commerce-kit 0.36.11 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/feedback-toolbar.js +2 -2
- package/dist/feedback-toolbar.js.map +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feedback-toolbar.tsx","../src/sandbox-inspectors.ts"],"sourcesContent":["/**\n * Feedback session toolbar — side-effect entry.\n *\n * Importing `commerce-kit/feedback-toolbar` (or `commerce-kit/browser` for the\n * combined entry) mounts a floating toolbar onto the page that lets reviewers\n * leave click-anchored comments. Comments persist via YNS API endpoints,\n * authenticated with the `better-auth` session cookie sent through\n * `credentials: \"include\"`.\n *\n * Gated on `process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\"` — only Vercel\n * preview deploys get the toolbar. Sandbox dev (env undefined) and production\n * (env === \"production\") skip it.\n */\n\nimport { type CSSProperties, type FormEvent, useEffect, useRef, useState } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nconst MOUNT_NODE_ID = \"yns-feedback-toolbar-root\";\n\ninterface FeedbackAttachment {\n\turl: string;\n\tcontentType: string;\n\twidth?: number;\n\theight?: number;\n}\n\ninterface FeedbackComment {\n\tid: string;\n\tpagePath: string;\n\tcssSelector: string;\n\tcontent: string;\n\tstatus: \"todo\" | \"done\";\n\toffsetXRatio: number;\n\toffsetYRatio: number;\n\tattachments: FeedbackAttachment[];\n}\n\ntype SessionStatus = \"created\" | \"in_progress\" | \"processing\" | \"in_review\" | \"done\";\n\ninterface ReviewProgress {\n\tfillPct: number;\n\tlabel: string;\n}\n\ninterface ActiveSession {\n\tfeedbackSessionId: string;\n\tcomments: FeedbackComment[];\n\tcanComment: boolean;\n\tsessionStatus: SessionStatus;\n\tcommentTotal: number;\n\tcommentDone: number;\n\teta: string;\n\tprogress: ReviewProgress;\n}\n\ninterface PendingPin {\n\tcssSelector: string;\n\tpagePath: string;\n\tsurroundingHtml: string;\n\trect: { top: number; left: number; width: number; height: number };\n\tclickX: number;\n\tclickY: number;\n\toffsetXRatio: number;\n\toffsetYRatio: number;\n}\n\nconst buildApiBase = (): string | null => {\n\tif (typeof window === \"undefined\") return null;\n\tconst override = (process.env.NEXT_PUBLIC_YNS_API_BASE ?? \"\").trim();\n\tif (override) return override.replace(/\\/$/, \"\");\n\n\t// Toolbar runs on a per-store preview deploy (mystore-preview.yns.{store|cx})\n\t// served by the merchant's Vercel project — that host has no YNS API. Aim\n\t// at the apex `yns.store` / `yns.cx`, which yns-app serves and where the\n\t// API lives. Cookies scoped to `.yns.store` / `.yns.cx` travel along.\n\tconst host = window.location.hostname;\n\tconst protocol = window.location.protocol;\n\tif (host.endsWith(\".yns.store\")) return `${protocol}//yns.store`;\n\tif (host.endsWith(\".yns.cx\")) return `${protocol}//yns.cx`;\n\treturn window.location.origin;\n};\n\nconst computeCssSelector = (el: Element): string => {\n\tif (el.id) return `#${CSS.escape(el.id)}`;\n\tconst path: string[] = [];\n\tlet node: Element | null = el;\n\twhile (node && node.nodeType === Node.ELEMENT_NODE && path.length < 6) {\n\t\tlet part = node.tagName.toLowerCase();\n\t\tconst className = node.getAttribute(\"class\");\n\t\tif (className) {\n\t\t\tconst classes = className\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.slice(0, 2)\n\t\t\t\t.map((c) => `.${CSS.escape(c)}`)\n\t\t\t\t.join(\"\");\n\t\t\tpart += classes;\n\t\t}\n\t\tconst parent: Element | null = node.parentElement;\n\t\tconst tag = node.tagName;\n\t\tif (parent) {\n\t\t\tconst siblings: Element[] = Array.from(parent.children).filter((c) => c.tagName === tag);\n\t\t\tif (siblings.length > 1) {\n\t\t\t\tconst idx = siblings.indexOf(node) + 1;\n\t\t\t\tpart += `:nth-of-type(${idx})`;\n\t\t\t}\n\t\t}\n\t\tpath.unshift(part);\n\t\tnode = parent;\n\t}\n\treturn path.join(\" > \");\n};\n\nconst ATTRS_OF_INTEREST = [\"id\", \"class\", \"data-testid\", \"aria-label\", \"role\", \"name\", \"href\", \"src\"];\n\nconst formatAttrs = (el: Element): string => {\n\tconst parts: string[] = [];\n\tfor (const attr of ATTRS_OF_INTEREST) {\n\t\tconst v = el.getAttribute(attr);\n\t\tif (!v) continue;\n\t\tconst trimmed = v.length > 80 ? `${v.slice(0, 80)}…` : v;\n\t\tparts.push(` ${attr}=\"${trimmed.replace(/\"/g, \""\")}\"`);\n\t}\n\treturn parts.join(\"\");\n};\n\nconst formatTextContent = (el: Element): string => {\n\tconst text = (el.textContent ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (!text) return \"\";\n\treturn text.length > 100 ? `${text.slice(0, 100)}…` : text;\n};\n\nconst buildSurroundingHtml = (target: Element): string => {\n\tconst ancestors: Element[] = [];\n\tlet cur: Element | null = target;\n\twhile (cur && cur !== document.documentElement && ancestors.length < 5) {\n\t\tconst parent: Element | null = cur.parentElement;\n\t\tif (!parent) break;\n\t\tancestors.unshift(parent);\n\t\tcur = parent;\n\t}\n\n\tconst lines: string[] = [];\n\tlet depth = 0;\n\tfor (const ancestor of ancestors) {\n\t\tconst indent = \" \".repeat(depth);\n\t\tlines.push(`${indent}<${ancestor.tagName.toLowerCase()}${formatAttrs(ancestor)}>`);\n\t\tdepth++;\n\t}\n\n\tconst targetIndent = \" \".repeat(depth);\n\tconst targetTag = target.tagName.toLowerCase();\n\tconst targetText = formatTextContent(target);\n\tlines.push(\n\t\t`${targetIndent}<${targetTag}${formatAttrs(target)}>${\n\t\t\ttargetText ? `${targetText}</${targetTag}>` : \"\"\n\t\t} ← TARGET`,\n\t);\n\n\tif (!targetText) {\n\t\tconst childIndent = \" \".repeat(depth + 1);\n\t\tconst children = Array.from(target.children).slice(0, 6);\n\t\tfor (const child of children) {\n\t\t\tconst childText = formatTextContent(child);\n\t\t\tlines.push(\n\t\t\t\t`${childIndent}<${child.tagName.toLowerCase()}${formatAttrs(child)}>${\n\t\t\t\t\tchildText ? `${childText}</${child.tagName.toLowerCase()}>` : \"\"\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (target.children.length > 6) {\n\t\t\tlines.push(`${childIndent}… (${target.children.length - 6} more children)`);\n\t\t}\n\t\tlines.push(`${targetIndent}</${targetTag}>`);\n\t}\n\n\tfor (let i = ancestors.length - 1; i >= 0; i--) {\n\t\tconst indent = \" \".repeat(i);\n\t\tconst ancestor = ancestors[i];\n\t\tif (!ancestor) continue;\n\t\tlines.push(`${indent}</${ancestor.tagName.toLowerCase()}>`);\n\t}\n\n\treturn lines.join(\"\\n\");\n};\n\nconst isInsideToolbar = (el: Element | null): boolean => {\n\tlet node = el;\n\twhile (node) {\n\t\tif (node instanceof HTMLElement && node.dataset.ynsFeedbackUi === \"true\") return true;\n\t\tnode = node.parentElement;\n\t}\n\treturn false;\n};\n\nconst IGNORED_TAGS = new Set([\"HTML\", \"HEAD\", \"SCRIPT\", \"STYLE\", \"NOSCRIPT\"]);\n\nconst POLL_INTERVAL_MS = 10_000;\n\n// Format a server-computed ETA as remaining + absolute label. The deadline\n// math itself lives in yns-app's `lib/feedback-comments-api.ts` so the toolbar\n// and YNS lock screen stay in sync.\nconst formatEta = (etaIso: string): string => {\n\tconst eta = new Date(etaIso);\n\tconst remainingMs = eta.getTime() - Date.now();\n\tconst dateLabel = eta.toLocaleString(undefined, {\n\t\tweekday: \"short\",\n\t\tmonth: \"short\",\n\t\tday: \"numeric\",\n\t\thour: \"numeric\",\n\t\tminute: \"2-digit\",\n\t});\n\n\tif (remainingMs <= 0) return `Any moment now (estimated by ${dateLabel})`;\n\tconst remainingMin = Math.ceil(remainingMs / 60_000);\n\tif (remainingMin < 60) return `~${remainingMin} minutes (by ${dateLabel})`;\n\tconst remainingHours = Math.round(remainingMs / 3_600_000);\n\tif (remainingHours < 24) {\n\t\treturn `~${remainingHours} ${remainingHours === 1 ? \"hour\" : \"hours\"} (by ${dateLabel})`;\n\t}\n\tconst remainingDays = Math.round(remainingMs / 86_400_000);\n\treturn `~${remainingDays} ${remainingDays === 1 ? \"day\" : \"days\"} (by ${dateLabel})`;\n};\n\nfunction FeedbackToolbar() {\n\tconst [session, setSession] = useState<ActiveSession | null>(null);\n\tconst [loading, setLoading] = useState(true);\n\tconst [pinMode, setPinMode] = useState(false);\n\tconst [pending, setPending] = useState<PendingPin | null>(null);\n\tconst [editingId, setEditingId] = useState<string | null>(null);\n\tconst [sidebarOpen, setSidebarOpen] = useState(false);\n\tconst [finalizing, setFinalizing] = useState(false);\n\tconst apiBase = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\tapiBase.current = buildApiBase();\n\t\tif (!apiBase.current) {\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\tlet cancelled = false;\n\t\tconst controller = new AbortController();\n\n\t\tconst fetchOnce = async () => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\n\t\t\t\t\t`${apiBase.current}/api/feedback-comments?host=${encodeURIComponent(window.location.host)}`,\n\t\t\t\t\t{ credentials: \"include\", signal: controller.signal },\n\t\t\t\t);\n\t\t\t\tif (cancelled) return;\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tsetSession(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst data = (await res.json()) as ActiveSession;\n\t\t\t\tif (cancelled) return;\n\t\t\t\tsetSession(data);\n\t\t\t\t// Hard-refresh once the AI run lands and the preview is up to date.\n\t\t\t\t// Out of scope to diff anything smarter — the new deploy replaces\n\t\t\t\t// the page entirely so a full reload is appropriate here.\n\t\t\t\tif (data.sessionStatus === \"done\") {\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tif (!cancelled) setSession(null);\n\t\t\t} finally {\n\t\t\t\tif (!cancelled) setLoading(false);\n\t\t\t}\n\t\t};\n\n\t\tvoid fetchOnce();\n\t\tconst interval = window.setInterval(fetchOnce, POLL_INTERVAL_MS);\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t\tcontroller.abort();\n\t\t\twindow.clearInterval(interval);\n\t\t};\n\t}, []);\n\n\t// When the session stops accepting comments (finalized → in_review, or\n\t// closed), tear down any in-flight UI so the hover overlay/popover/sidebar\n\t// don't linger after the toolbar's main render returns null.\n\tuseEffect(() => {\n\t\tif (!session || session.canComment) return;\n\t\tsetPinMode(false);\n\t\tsetPending(null);\n\t\tsetSidebarOpen(false);\n\t\tsetEditingId(null);\n\t}, [session]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\t\tdocument.body.style.cursor = \"crosshair\";\n\t\treturn () => {\n\t\t\tdocument.body.style.cursor = \"\";\n\t\t};\n\t}, [pinMode]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\n\t\tconst overlay = document.createElement(\"div\");\n\t\toverlay.dataset.ynsFeedbackUi = \"true\";\n\t\toverlay.style.cssText = [\n\t\t\t\"position: fixed\",\n\t\t\t\"pointer-events: none\",\n\t\t\t\"z-index: 2147483644\",\n\t\t\t\"border: 2px dashed #10b981\",\n\t\t\t\"background: rgba(16, 185, 129, 0.08)\",\n\t\t\t\"border-radius: 3px\",\n\t\t\t\"display: none\",\n\t\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t\t].join(\";\");\n\n\t\tconst label = document.createElement(\"div\");\n\t\tlabel.dataset.ynsFeedbackUi = \"true\";\n\t\tlabel.textContent = \"Click to comment\";\n\t\tlabel.style.cssText = [\n\t\t\t\"position: fixed\",\n\t\t\t\"pointer-events: none\",\n\t\t\t\"z-index: 2147483645\",\n\t\t\t\"background: #059669\",\n\t\t\t\"color: #fff\",\n\t\t\t\"font-size: 11px\",\n\t\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\t\"padding: 3px 8px\",\n\t\t\t\"border-radius: 4px\",\n\t\t\t\"white-space: nowrap\",\n\t\t\t\"display: none\",\n\t\t\t\"box-shadow: 0 2px 6px rgba(0,0,0,0.15)\",\n\t\t].join(\";\");\n\n\t\tdocument.documentElement.appendChild(overlay);\n\t\tdocument.documentElement.appendChild(label);\n\n\t\tlet hovered: Element | null = null;\n\t\tconst handleMove = (e: MouseEvent) => {\n\t\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\t\tif (!el || IGNORED_TAGS.has(el.tagName) || isInsideToolbar(el)) {\n\t\t\t\toverlay.style.display = \"none\";\n\t\t\t\tlabel.style.display = \"none\";\n\t\t\t\thovered = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thovered = el;\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (hovered !== el) return;\n\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\toverlay.style.top = `${rect.top}px`;\n\t\t\t\toverlay.style.left = `${rect.left}px`;\n\t\t\t\toverlay.style.width = `${rect.width}px`;\n\t\t\t\toverlay.style.height = `${rect.height}px`;\n\t\t\t\toverlay.style.display = \"block\";\n\t\t\t\tlabel.style.left = `${e.clientX + 14}px`;\n\t\t\t\tlabel.style.top = `${e.clientY + 14}px`;\n\t\t\t\tlabel.style.display = \"block\";\n\t\t\t});\n\t\t};\n\n\t\tconst handleLeave = () => {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tlabel.style.display = \"none\";\n\t\t\thovered = null;\n\t\t};\n\n\t\tdocument.addEventListener(\"mousemove\", handleMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleLeave);\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"mousemove\", handleMove, true);\n\t\t\tdocument.removeEventListener(\"mouseleave\", handleLeave);\n\t\t\toverlay.remove();\n\t\t\tlabel.remove();\n\t\t};\n\t}, [pinMode]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\t\tconst handleClick = (event: MouseEvent) => {\n\t\t\tconst target = event.target;\n\t\t\tif (!(target instanceof Element)) return;\n\t\t\tif (isInsideToolbar(target)) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tconst rect = target.getBoundingClientRect();\n\t\t\tconst offsetXRatio = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0.5;\n\t\t\tconst offsetYRatio = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0.5;\n\t\t\tsetPending({\n\t\t\t\tcssSelector: computeCssSelector(target),\n\t\t\t\tpagePath: window.location.pathname,\n\t\t\t\tsurroundingHtml: buildSurroundingHtml(target),\n\t\t\t\trect: {\n\t\t\t\t\ttop: rect.top + window.scrollY,\n\t\t\t\t\tleft: rect.left + window.scrollX,\n\t\t\t\t\twidth: rect.width,\n\t\t\t\t\theight: rect.height,\n\t\t\t\t},\n\t\t\t\tclickX: event.clientX + window.scrollX,\n\t\t\t\tclickY: event.clientY + window.scrollY,\n\t\t\t\toffsetXRatio: Math.min(1, Math.max(0, offsetXRatio)),\n\t\t\t\toffsetYRatio: Math.min(1, Math.max(0, offsetYRatio)),\n\t\t\t});\n\t\t\tsetPinMode(false);\n\t\t};\n\t\tdocument.addEventListener(\"click\", handleClick, { capture: true });\n\t\treturn () => document.removeEventListener(\"click\", handleClick, { capture: true });\n\t}, [pinMode]);\n\n\tconst refreshComments = async () => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(\n\t\t\t`${apiBase.current}/api/feedback-comments?host=${encodeURIComponent(window.location.host)}`,\n\t\t\t{ credentials: \"include\" },\n\t\t);\n\t\tif (!res.ok) return;\n\t\tconst data = (await res.json()) as ActiveSession;\n\t\tsetSession(data);\n\t};\n\n\tconst submitNewComment = async (content: string, attachments: FeedbackAttachment[]) => {\n\t\tif (!apiBase.current || !session || !pending) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments`, {\n\t\t\tmethod: \"POST\",\n\t\t\tcredentials: \"include\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tfeedbackSessionId: session.feedbackSessionId,\n\t\t\t\tcontent,\n\t\t\t\tpagePath: pending.pagePath,\n\t\t\t\tcssSelector: pending.cssSelector,\n\t\t\t\tsurroundingHtml: pending.surroundingHtml,\n\t\t\t\toffsetXRatio: pending.offsetXRatio,\n\t\t\t\toffsetYRatio: pending.offsetYRatio,\n\t\t\t\t...(attachments.length > 0 ? { attachments } : {}),\n\t\t\t}),\n\t\t});\n\t\tif (!res.ok) return;\n\t\tsetPending(null);\n\t\tsetPinMode(true);\n\t\tawait refreshComments();\n\t};\n\n\tconst updateComment = async (id: string, content: string, attachments: FeedbackAttachment[]) => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments/${id}`, {\n\t\t\tmethod: \"PATCH\",\n\t\t\tcredentials: \"include\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ content, attachments }),\n\t\t});\n\t\tif (!res.ok) return;\n\t\tsetEditingId(null);\n\t\tawait refreshComments();\n\t};\n\n\tconst removeComment = async (id: string) => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments/${id}`, {\n\t\t\tmethod: \"DELETE\",\n\t\t\tcredentials: \"include\",\n\t\t});\n\t\tif (!res.ok) return;\n\t\tawait refreshComments();\n\t};\n\n\tconst finalizeSession = async () => {\n\t\tif (!apiBase.current || !session) return;\n\t\tif (!window.confirm(\"Finalize this feedback session? You won't be able to add more comments.\")) return;\n\t\tsetFinalizing(true);\n\t\ttry {\n\t\t\tconst res = await fetch(\n\t\t\t\t`${apiBase.current}/api/feedback-sessions/${session.feedbackSessionId}/finalize`,\n\t\t\t\t{ method: \"POST\", credentials: \"include\" },\n\t\t\t);\n\t\t\tif (!res.ok) return;\n\t\t\t// Flip BOTH canComment and sessionStatus locally. Without the status\n\t\t\t// flip, the render guard sees `canComment=false` + `status=in_progress`\n\t\t\t// (a state the SubmittedPanel branch returns null for) and the toolbar\n\t\t\t// disappears for the ~10s gap until the next poll catches up.\n\t\t\tconst body = (await res.json().catch(() => null)) as { status?: SessionStatus } | null;\n\t\t\tconst nextStatus: SessionStatus = body?.status ?? \"processing\";\n\t\t\tsetSession((prev) => (prev ? { ...prev, canComment: false, sessionStatus: nextStatus } : prev));\n\t\t} finally {\n\t\t\tsetFinalizing(false);\n\t\t}\n\t};\n\n\tconst scrollToComment = (comment: FeedbackComment) => {\n\t\tif (comment.pagePath !== window.location.pathname) {\n\t\t\twindow.location.assign(comment.pagePath);\n\t\t\treturn;\n\t\t}\n\t\tlet el: Element | null = null;\n\t\ttry {\n\t\t\tel = document.querySelector(comment.cssSelector);\n\t\t} catch {\n\t\t\tel = null;\n\t\t}\n\t\tif (!el) return;\n\t\tel.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\tsetEditingId(comment.id);\n\t};\n\n\tif (loading || !session) return null;\n\n\t// Session has been finalized for AI review. Show a small status panel with\n\t// the same progress + ETA shown in YNS, but no commenting controls. Polling\n\t// continues in the background; on `done` we hard-reload to pick up the\n\t// fresh deploy.\n\tif (!session.canComment) {\n\t\tif (session.sessionStatus !== \"processing\" && session.sessionStatus !== \"in_review\") return null;\n\t\treturn (\n\t\t\t<div data-yns-feedback-ui=\"true\">\n\t\t\t\t<SubmittedPanel progress={session.progress} eta={session.eta} status={session.sessionStatus} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst visiblePins = session.comments.filter(\n\t\t(c) => c.pagePath === window.location.pathname && c.status !== \"done\",\n\t);\n\n\treturn (\n\t\t<div data-yns-feedback-ui=\"true\">\n\t\t\t{visiblePins.map((pin, idx) => (\n\t\t\t\t<PinOverlay\n\t\t\t\t\tkey={pin.id}\n\t\t\t\t\tpin={pin}\n\t\t\t\t\tnumber={idx + 1}\n\t\t\t\t\tediting={editingId === pin.id}\n\t\t\t\t\tfeedbackSessionId={session.feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase.current}\n\t\t\t\t\tonStartEdit={() => setEditingId(pin.id)}\n\t\t\t\t\tonCancelEdit={() => setEditingId(null)}\n\t\t\t\t\tonSave={(content, attachments) => updateComment(pin.id, content, attachments)}\n\t\t\t\t\tonRemove={() => removeComment(pin.id)}\n\t\t\t\t/>\n\t\t\t))}\n\n\t\t\t{pending && (\n\t\t\t\t<PendingCommentPopover\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tfeedbackSessionId={session.feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase.current}\n\t\t\t\t\tonCancel={() => {\n\t\t\t\t\t\tsetPending(null);\n\t\t\t\t\t\tsetPinMode(true);\n\t\t\t\t\t}}\n\t\t\t\t\tonSave={(content, attachments) => submitNewComment(content, attachments)}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{sidebarOpen && (\n\t\t\t\t<CommentsSidebar\n\t\t\t\t\tcomments={session.comments}\n\t\t\t\t\tcurrentPath={window.location.pathname}\n\t\t\t\t\tonClose={() => setSidebarOpen(false)}\n\t\t\t\t\tonSelect={scrollToComment}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<div style={toolbarStyle}>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={() => setPinMode((v) => !v)}\n\t\t\t\t\tstyle={pinMode ? toolbarButtonActiveStyle : toolbarButtonStyle}\n\t\t\t\t>\n\t\t\t\t\t{pinMode ? \"Cancel\" : \"Add comment\"}\n\t\t\t\t</button>\n\t\t\t\t<button type=\"button\" onClick={() => setSidebarOpen((v) => !v)} style={toolbarButtonGhostStyle}>\n\t\t\t\t\t{sidebarOpen ? \"Hide list\" : `List (${session.comments.length})`}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={finalizeSession}\n\t\t\t\t\tdisabled={finalizing}\n\t\t\t\t\tstyle={toolbarButtonFinalizeStyle}\n\t\t\t\t>\n\t\t\t\t\t{finalizing ? \"Finalizing…\" : \"Finalize\"}\n\t\t\t\t</button>\n\t\t\t\t<span style={toolbarHintStyle}>\n\t\t\t\t\t{pinMode ? \"Click any element to comment\" : `${visiblePins.length} on this page`}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction SubmittedPanel({\n\tprogress,\n\teta: etaIso,\n\tstatus,\n}: {\n\tprogress: ReviewProgress;\n\teta: string;\n\tstatus: SessionStatus;\n}) {\n\t// Re-render every minute so the relative ETA label stays fresh between\n\t// the 10s data polls (which only re-render when the API payload changes).\n\tconst [, setTick] = useState(0);\n\tuseEffect(() => {\n\t\tconst id = window.setInterval(() => setTick((t) => t + 1), 60_000);\n\t\treturn () => window.clearInterval(id);\n\t}, []);\n\n\tconst eta = formatEta(etaIso);\n\tconst isInReview = status === \"in_review\";\n\tconst headline = isInReview ? \"Feedback under review\" : \"Applying feedback\";\n\n\treturn (\n\t\t<div style={submittedPanelStyle}>\n\t\t\t<style>{spinnerKeyframes}</style>\n\t\t\t<div style={submittedHeaderStyle}>\n\t\t\t\t<Spinner />\n\t\t\t\t<span style={submittedBadgeStyle}>Submitted</span>\n\t\t\t\t<strong style={{ fontSize: 13 }}>{headline}</strong>\n\t\t\t</div>\n\t\t\t<div style={submittedProgressLabelStyle}>\n\t\t\t\t<span>Review progress</span>\n\t\t\t\t<span style={{ opacity: 0.7 }}>{progress.label}</span>\n\t\t\t</div>\n\t\t\t<div style={submittedProgressTrackStyle}>\n\t\t\t\t<div style={{ ...submittedProgressFillStyle, width: `${progress.fillPct}%` }} />\n\t\t\t</div>\n\t\t\t<p style={submittedEtaStyle}>\n\t\t\t\tEstimated delivery: <span style={{ fontWeight: 600 }}>{eta}</span>\n\t\t\t</p>\n\t\t</div>\n\t);\n}\n\n// Inline keyframes — toolbar avoids relying on a global stylesheet.\nconst spinnerKeyframes = `@keyframes yns-feedback-spin { to { transform: rotate(360deg); } }`;\n\nfunction Spinner({ size = 14 }: { size?: number }) {\n\treturn (\n\t\t<span\n\t\t\taria-hidden\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"inline-block\",\n\t\t\t\twidth: size,\n\t\t\t\theight: size,\n\t\t\t\tborder: \"2px solid rgba(16, 185, 129, 0.25)\",\n\t\t\t\tborderTopColor: \"#10b981\",\n\t\t\t\tborderRadius: 999,\n\t\t\t\tanimation: \"yns-feedback-spin 0.9s linear infinite\",\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction PinOverlay({\n\tpin,\n\tnumber,\n\tediting,\n\tfeedbackSessionId,\n\tapiBase,\n\tonStartEdit,\n\tonCancelEdit,\n\tonSave,\n\tonRemove,\n}: {\n\tpin: FeedbackComment;\n\tnumber: number;\n\tediting: boolean;\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonStartEdit: () => void;\n\tonCancelEdit: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n\tonRemove: () => Promise<void>;\n}) {\n\tconst target = useTargetPosition(pin.cssSelector, pin.offsetXRatio, pin.offsetYRatio);\n\tif (!target) return null;\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tposition: \"absolute\",\n\t\t\t\ttop: target.top,\n\t\t\t\tleft: target.left,\n\t\t\t\tzIndex: 2147483600,\n\t\t\t\tpointerEvents: \"auto\",\n\t\t\t}}\n\t\t>\n\t\t\t<button type=\"button\" onClick={onStartEdit} style={pinDotStyle} title={pin.content}>\n\t\t\t\t{number}\n\t\t\t</button>\n\t\t\t{editing && (\n\t\t\t\t<EditPopover\n\t\t\t\t\tinitial={pin.content}\n\t\t\t\t\tinitialAttachments={pin.attachments}\n\t\t\t\t\tfeedbackSessionId={feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase}\n\t\t\t\t\tonCancel={onCancelEdit}\n\t\t\t\t\tonSave={onSave}\n\t\t\t\t\tonRemove={onRemove}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction PendingCommentPopover({\n\tpending,\n\tfeedbackSessionId,\n\tapiBase,\n\tonCancel,\n\tonSave,\n}: {\n\tpending: PendingPin;\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonCancel: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n}) {\n\treturn (\n\t\t<>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: pending.rect.top + pending.rect.height * pending.offsetYRatio - 12,\n\t\t\t\t\tleft: pending.rect.left + pending.rect.width * pending.offsetXRatio - 12,\n\t\t\t\t\tzIndex: 2147483600,\n\t\t\t\t\tpointerEvents: \"none\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div style={pinDotStyle}>•</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: pending.clickY + 10,\n\t\t\t\t\tleft: pending.clickX + 10,\n\t\t\t\t\tzIndex: 2147483647,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<EditPopover\n\t\t\t\t\tinitial=\"\"\n\t\t\t\t\tinitialAttachments={[]}\n\t\t\t\t\tfeedbackSessionId={feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase}\n\t\t\t\t\tonCancel={onCancel}\n\t\t\t\t\tonSave={onSave}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\nfunction CommentsSidebar({\n\tcomments,\n\tcurrentPath,\n\tonClose,\n\tonSelect,\n}: {\n\tcomments: FeedbackComment[];\n\tcurrentPath: string;\n\tonClose: () => void;\n\tonSelect: (comment: FeedbackComment) => void;\n}) {\n\tconst groups = new Map<string, FeedbackComment[]>();\n\tfor (const c of comments) {\n\t\tconst list = groups.get(c.pagePath) ?? [];\n\t\tlist.push(c);\n\t\tgroups.set(c.pagePath, list);\n\t}\n\tconst paths = Array.from(groups.keys()).sort((a, b) => {\n\t\tif (a === currentPath) return -1;\n\t\tif (b === currentPath) return 1;\n\t\treturn a.localeCompare(b);\n\t});\n\n\treturn (\n\t\t<div style={sidebarStyle}>\n\t\t\t<div style={sidebarHeaderStyle}>\n\t\t\t\t<strong style={{ fontSize: 14 }}>Comments ({comments.length})</strong>\n\t\t\t\t<button type=\"button\" onClick={onClose} style={ghostButtonStyle}>\n\t\t\t\t\tClose\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div style={sidebarScrollStyle}>\n\t\t\t\t{comments.length === 0 ? (\n\t\t\t\t\t<div style={sidebarEmptyStyle}>No comments yet. Click “Add comment” to leave one.</div>\n\t\t\t\t) : (\n\t\t\t\t\tpaths.map((path) => (\n\t\t\t\t\t\t<div key={path} style={{ marginBottom: 12 }}>\n\t\t\t\t\t\t\t<div style={sidebarPathStyle}>{path === currentPath ? `${path} · current` : path}</div>\n\t\t\t\t\t\t\t{(groups.get(path) ?? []).map((c, idx) => (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tkey={c.id}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tonClick={() => onSelect(c)}\n\t\t\t\t\t\t\t\t\tstyle={sidebarItemStyle}\n\t\t\t\t\t\t\t\t\tdisabled={c.status === \"done\" && false}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span style={sidebarItemIndexStyle}>{idx + 1}</span>\n\t\t\t\t\t\t\t\t\t<span style={sidebarItemTextStyle}>\n\t\t\t\t\t\t\t\t\t\t{c.content.length > 140 ? `${c.content.slice(0, 140)}…` : c.content}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{c.status === \"done\" && <span style={sidebarItemDoneStyle}>done</span>}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nconst MAX_ATTACHMENTS = 5;\nconst MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;\n\nconst readImageDimensions = (file: File): Promise<{ width: number; height: number } | null> =>\n\tnew Promise((resolve) => {\n\t\tconst url = URL.createObjectURL(file);\n\t\tconst img = new window.Image();\n\t\timg.onload = () => {\n\t\t\tURL.revokeObjectURL(url);\n\t\t\tresolve({ width: img.naturalWidth, height: img.naturalHeight });\n\t\t};\n\t\timg.onerror = () => {\n\t\t\tURL.revokeObjectURL(url);\n\t\t\tresolve(null);\n\t\t};\n\t\timg.src = url;\n\t});\n\nfunction EditPopover({\n\tinitial,\n\tinitialAttachments,\n\tfeedbackSessionId,\n\tapiBase,\n\tonCancel,\n\tonSave,\n\tonRemove,\n}: {\n\tinitial: string;\n\tinitialAttachments: FeedbackAttachment[];\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonCancel: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n\tonRemove?: () => Promise<void>;\n}) {\n\tconst [value, setValue] = useState(initial);\n\tconst [attachments, setAttachments] = useState<FeedbackAttachment[]>(initialAttachments);\n\tconst [saving, setSaving] = useState(false);\n\tconst [uploading, setUploading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\tconst fileInputRef = useRef<HTMLInputElement | null>(null);\n\n\tuseEffect(() => {\n\t\tconst el = textareaRef.current;\n\t\tif (!el) return;\n\t\tel.focus();\n\t\tconst len = el.value.length;\n\t\tel.setSelectionRange(len, len);\n\t}, []);\n\n\tconst handleSubmit = async (e: FormEvent) => {\n\t\te.preventDefault();\n\t\tconst content = value.trim();\n\t\tif (!content) return;\n\t\tsetSaving(true);\n\t\ttry {\n\t\t\tawait onSave(content, attachments);\n\t\t} finally {\n\t\t\tsetSaving(false);\n\t\t}\n\t};\n\n\tconst handleFiles = async (files: FileList | null) => {\n\t\tif (!files || files.length === 0 || !apiBase) return;\n\t\tsetError(null);\n\t\tconst slots = MAX_ATTACHMENTS - attachments.length;\n\t\tif (slots <= 0) {\n\t\t\tsetError(`Max ${MAX_ATTACHMENTS} images per comment`);\n\t\t\treturn;\n\t\t}\n\t\tconst picked = Array.from(files).slice(0, slots);\n\t\tfor (const f of picked) {\n\t\t\tif (!f.type.startsWith(\"image/\")) {\n\t\t\t\tsetError(`\"${f.name}\" is not an image`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (f.size > MAX_ATTACHMENT_BYTES) {\n\t\t\t\tsetError(`\"${f.name}\" exceeds 5 MB`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tsetUploading(true);\n\t\ttry {\n\t\t\tconst dims = await Promise.all(picked.map(readImageDimensions));\n\t\t\tconst fd = new FormData();\n\t\t\tpicked.forEach((file, i) => {\n\t\t\t\tfd.append(\"file\", file);\n\t\t\t\tfd.append(\"width\", dims[i]?.width ? String(dims[i]?.width) : \"\");\n\t\t\t\tfd.append(\"height\", dims[i]?.height ? String(dims[i]?.height) : \"\");\n\t\t\t});\n\t\t\tconst res = await fetch(\n\t\t\t\t`${apiBase}/api/feedback-comments/uploads?feedbackSessionId=${encodeURIComponent(feedbackSessionId)}`,\n\t\t\t\t{ method: \"POST\", credentials: \"include\", body: fd },\n\t\t\t);\n\t\t\tif (!res.ok) {\n\t\t\t\tconst body = (await res.json().catch(() => null)) as { error?: string } | null;\n\t\t\t\tsetError(body?.error ?? \"Upload failed\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst body = (await res.json()) as { uploads: FeedbackAttachment[] };\n\t\t\tsetAttachments((prev) => [...prev, ...body.uploads]);\n\t\t} catch {\n\t\t\tsetError(\"Upload failed\");\n\t\t} finally {\n\t\t\tsetUploading(false);\n\t\t\tif (fileInputRef.current) fileInputRef.current.value = \"\";\n\t\t}\n\t};\n\n\tconst removeAttachment = (url: string) => {\n\t\tsetAttachments((prev) => prev.filter((a) => a.url !== url));\n\t};\n\n\treturn (\n\t\t<form onSubmit={handleSubmit} style={popoverStyle}>\n\t\t\t<textarea\n\t\t\t\tref={textareaRef}\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => setValue(e.target.value)}\n\t\t\t\tplaceholder=\"Leave a comment…\"\n\t\t\t\tstyle={textareaStyle}\n\t\t\t\trows={3}\n\t\t\t/>\n\t\t\t{attachments.length > 0 && (\n\t\t\t\t<div style={attachmentRowStyle}>\n\t\t\t\t\t{attachments.map((att) => (\n\t\t\t\t\t\t<div key={att.url} style={attachmentThumbWrapStyle}>\n\t\t\t\t\t\t\t<img src={att.url} alt=\"\" style={attachmentThumbStyle} />\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => removeAttachment(att.url)}\n\t\t\t\t\t\t\t\tstyle={attachmentRemoveStyle}\n\t\t\t\t\t\t\t\tdisabled={saving || uploading}\n\t\t\t\t\t\t\t\taria-label=\"Remove attachment\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t×\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{error && <div style={errorTextStyle}>{error}</div>}\n\t\t\t<input\n\t\t\t\tref={fileInputRef}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept=\"image/*\"\n\t\t\t\tmultiple\n\t\t\t\tonChange={(e) => void handleFiles(e.target.files)}\n\t\t\t\tstyle={{ display: \"none\" }}\n\t\t\t/>\n\t\t\t<div style={popoverActionsStyle}>\n\t\t\t\t{onRemove && (\n\t\t\t\t\t<button type=\"button\" onClick={() => onRemove()} style={dangerButtonStyle} disabled={saving}>\n\t\t\t\t\t\tDelete\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={() => fileInputRef.current?.click()}\n\t\t\t\t\tstyle={ghostButtonStyle}\n\t\t\t\t\tdisabled={saving || uploading || attachments.length >= MAX_ATTACHMENTS}\n\t\t\t\t>\n\t\t\t\t\t{uploading\n\t\t\t\t\t\t? \"Uploading…\"\n\t\t\t\t\t\t: `Attach image${attachments.length > 0 ? ` (${attachments.length})` : \"\"}`}\n\t\t\t\t</button>\n\t\t\t\t<div style={{ flex: 1 }} />\n\t\t\t\t<button type=\"button\" onClick={onCancel} style={ghostButtonStyle} disabled={saving}>\n\t\t\t\t\tCancel\n\t\t\t\t</button>\n\t\t\t\t<button type=\"submit\" style={primaryButtonStyle} disabled={saving || uploading || !value.trim()}>\n\t\t\t\t\t{saving ? \"Saving…\" : \"Save\"}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</form>\n\t);\n}\n\nfunction useTargetPosition(selector: string, offsetXRatio: number, offsetYRatio: number) {\n\tconst [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n\tuseEffect(() => {\n\t\tconst update = () => {\n\t\t\tlet el: Element | null = null;\n\t\t\ttry {\n\t\t\t\tel = document.querySelector(selector);\n\t\t\t} catch {\n\t\t\t\tel = null;\n\t\t\t}\n\t\t\tif (!el) {\n\t\t\t\tsetPos(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst r = el.getBoundingClientRect();\n\t\t\tsetPos({\n\t\t\t\ttop: r.top + window.scrollY + r.height * offsetYRatio - 12,\n\t\t\t\tleft: r.left + window.scrollX + r.width * offsetXRatio - 12,\n\t\t\t});\n\t\t};\n\n\t\tupdate();\n\t\tconst ro = new ResizeObserver(update);\n\t\ttry {\n\t\t\tconst el = document.querySelector(selector);\n\t\t\tif (el) ro.observe(el);\n\t\t} catch {\n\t\t\t// swallow invalid selector\n\t\t}\n\t\twindow.addEventListener(\"scroll\", update, true);\n\t\twindow.addEventListener(\"resize\", update);\n\t\treturn () => {\n\t\t\tro.disconnect();\n\t\t\twindow.removeEventListener(\"scroll\", update, true);\n\t\t\twindow.removeEventListener(\"resize\", update);\n\t\t};\n\t}, [selector, offsetXRatio, offsetYRatio]);\n\n\treturn pos;\n}\n\n// Inline styles — toolbar is injected into arbitrary stores, so we avoid relying\n// on any CSS framework being present.\nconst toolbarStyle: CSSProperties = {\n\tposition: \"fixed\",\n\tbottom: 16,\n\tleft: \"50%\",\n\ttransform: \"translateX(-50%)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 8,\n\tpadding: \"8px 12px\",\n\tbackground: \"rgba(17, 17, 17, 0.92)\",\n\tcolor: \"white\",\n\tborderRadius: 999,\n\tboxShadow: \"0 8px 24px rgba(0,0,0,0.25)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tfontSize: 14,\n\tpointerEvents: \"auto\",\n};\n\nconst toolbarButtonStyle: CSSProperties = {\n\tborder: \"none\",\n\tbackground: \"white\",\n\tcolor: \"#111\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 600,\n\tfontSize: 13,\n};\n\nconst toolbarButtonActiveStyle: CSSProperties = {\n\t...toolbarButtonStyle,\n\tbackground: \"#ef4444\",\n\tcolor: \"white\",\n};\n\nconst toolbarButtonGhostStyle: CSSProperties = {\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"transparent\",\n\tcolor: \"white\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 500,\n\tfontSize: 13,\n};\n\nconst toolbarButtonFinalizeStyle: CSSProperties = {\n\tborder: \"none\",\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 600,\n\tfontSize: 13,\n};\n\nconst toolbarHintStyle: CSSProperties = {\n\topacity: 0.8,\n\tfontSize: 12,\n};\n\nconst pinDotStyle: CSSProperties = {\n\twidth: 24,\n\theight: 24,\n\tborderRadius: 999,\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tborder: \"2px solid white\",\n\tcursor: \"pointer\",\n\tfontSize: 12,\n\tfontWeight: 700,\n\tboxShadow: \"0 2px 6px rgba(0,0,0,0.3)\",\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\tpadding: 0,\n};\n\nconst popoverStyle: CSSProperties = {\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 8,\n\tpadding: 12,\n\twidth: 280,\n\tboxShadow: \"0 12px 32px rgba(0,0,0,0.18)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: 8,\n\tcolor: \"#111\",\n};\n\nconst textareaStyle: CSSProperties = {\n\twidth: \"100%\",\n\tborder: \"1px solid #d1d5db\",\n\tborderRadius: 6,\n\tpadding: 8,\n\tfontSize: 14,\n\tresize: \"vertical\",\n\tfontFamily: \"inherit\",\n\tcolor: \"#111\",\n\tbackground: \"white\",\n\tboxSizing: \"border-box\",\n};\n\nconst popoverActionsStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 6,\n};\n\nconst baseButton: CSSProperties = {\n\tborder: \"1px solid transparent\",\n\tborderRadius: 6,\n\tpadding: \"6px 10px\",\n\tfontSize: 13,\n\tcursor: \"pointer\",\n\tfontWeight: 500,\n};\n\nconst primaryButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"#111\",\n\tcolor: \"white\",\n};\n\nconst ghostButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"transparent\",\n\tcolor: \"#374151\",\n\tborderColor: \"#d1d5db\",\n};\n\nconst dangerButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"transparent\",\n\tcolor: \"#b91c1c\",\n\tborderColor: \"#fecaca\",\n};\n\nconst attachmentRowStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\tflexWrap: \"wrap\",\n\tgap: 6,\n};\n\nconst attachmentThumbWrapStyle: CSSProperties = {\n\tposition: \"relative\",\n\twidth: 56,\n\theight: 56,\n\tborderRadius: 6,\n\toverflow: \"hidden\",\n\tborder: \"1px solid #e5e7eb\",\n\tbackground: \"#f9fafb\",\n};\n\nconst attachmentThumbStyle: CSSProperties = {\n\twidth: \"100%\",\n\theight: \"100%\",\n\tobjectFit: \"cover\",\n\tdisplay: \"block\",\n};\n\nconst attachmentRemoveStyle: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 2,\n\tright: 2,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"none\",\n\tbackground: \"rgba(17, 17, 17, 0.85)\",\n\tcolor: \"white\",\n\tfontSize: 13,\n\tlineHeight: \"16px\",\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nconst errorTextStyle: CSSProperties = {\n\tcolor: \"#b91c1c\",\n\tfontSize: 12,\n\tmargin: 0,\n};\n\nconst sidebarStyle: CSSProperties = {\n\tposition: \"fixed\",\n\ttop: 0,\n\tright: 0,\n\tbottom: 0,\n\twidth: 360,\n\tmaxWidth: \"92vw\",\n\tbackground: \"white\",\n\tborderLeft: \"1px solid #e5e7eb\",\n\tboxShadow: \"-12px 0 32px rgba(0,0,0,0.12)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tcolor: \"#111\",\n};\n\nconst sidebarHeaderStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"space-between\",\n\tpadding: \"12px 16px\",\n\tborderBottom: \"1px solid #e5e7eb\",\n};\n\nconst sidebarScrollStyle: CSSProperties = {\n\tflex: 1,\n\toverflow: \"auto\",\n\tpadding: \"12px 12px 24px\",\n};\n\nconst sidebarEmptyStyle: CSSProperties = {\n\tcolor: \"#6b7280\",\n\tfontSize: 13,\n\tpadding: \"24px 8px\",\n\ttextAlign: \"center\",\n};\n\nconst sidebarPathStyle: CSSProperties = {\n\tfontSize: 11,\n\ttextTransform: \"uppercase\",\n\tletterSpacing: 0.5,\n\tcolor: \"#6b7280\",\n\tpadding: \"4px 4px 6px\",\n\twordBreak: \"break-all\",\n};\n\nconst sidebarItemStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"flex-start\",\n\tgap: 8,\n\twidth: \"100%\",\n\ttextAlign: \"left\",\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 6,\n\tpadding: \"8px 10px\",\n\tcursor: \"pointer\",\n\tfontSize: 13,\n\tmarginBottom: 6,\n\tcolor: \"#111\",\n};\n\nconst sidebarItemIndexStyle: CSSProperties = {\n\tflexShrink: 0,\n\twidth: 22,\n\theight: 22,\n\tborderRadius: 999,\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tfontWeight: 700,\n\tfontSize: 11,\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nconst sidebarItemTextStyle: CSSProperties = {\n\tflex: 1,\n\twhiteSpace: \"pre-wrap\",\n\twordBreak: \"break-word\",\n};\n\nconst sidebarItemDoneStyle: CSSProperties = {\n\tflexShrink: 0,\n\tbackground: \"#d1fae5\",\n\tcolor: \"#065f46\",\n\tfontSize: 11,\n\tfontWeight: 600,\n\tpadding: \"2px 6px\",\n\tborderRadius: 4,\n\talignSelf: \"center\",\n};\n\nconst submittedPanelStyle: CSSProperties = {\n\tposition: \"fixed\",\n\tbottom: 16,\n\tleft: \"50%\",\n\ttransform: \"translateX(-50%)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: 8,\n\tpadding: \"12px 16px\",\n\twidth: \"min(420px, calc(100vw - 32px))\",\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 12,\n\tboxShadow: \"0 12px 32px rgba(0,0,0,0.18)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tcolor: \"#111\",\n\tpointerEvents: \"auto\",\n};\n\nconst submittedHeaderStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 8,\n};\n\nconst submittedBadgeStyle: CSSProperties = {\n\tbackground: \"#d1fae5\",\n\tcolor: \"#065f46\",\n\tfontSize: 11,\n\tfontWeight: 700,\n\tpadding: \"2px 8px\",\n\tborderRadius: 999,\n\ttextTransform: \"uppercase\",\n\tletterSpacing: 0.5,\n};\n\nconst submittedProgressLabelStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\tjustifyContent: \"space-between\",\n\tfontSize: 12,\n};\n\nconst submittedProgressTrackStyle: CSSProperties = {\n\twidth: \"100%\",\n\theight: 6,\n\tbackground: \"#f3f4f6\",\n\tborderRadius: 999,\n\toverflow: \"hidden\",\n};\n\nconst submittedProgressFillStyle: CSSProperties = {\n\theight: \"100%\",\n\tbackground: \"#10b981\",\n\tborderRadius: 999,\n\ttransition: \"width 500ms\",\n};\n\nconst submittedEtaStyle: CSSProperties = {\n\tmargin: 0,\n\tfontSize: 12,\n\tcolor: \"#6b7280\",\n};\n\nexport function mountFeedbackToolbar(): { unmount: () => void } | null {\n\tconsole.log(\"[YNS Feedback Toolbar] mountFeedbackToolbar() called\", {\n\t\tisWindow: typeof window !== \"undefined\",\n\t\tvercelEnv: process.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\talreadyMounted: typeof document !== \"undefined\" && Boolean(document.getElementById(MOUNT_NODE_ID)),\n\t});\n\tif (typeof window === \"undefined\") return null;\n\tif (process.env.NEXT_PUBLIC_VERCEL_ENV !== \"preview\") {\n\t\tconsole.log(\n\t\t\t\"[YNS Feedback Toolbar] gate failed — NEXT_PUBLIC_VERCEL_ENV is\",\n\t\t\tprocess.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\t);\n\t\treturn null;\n\t}\n\tif (document.getElementById(MOUNT_NODE_ID)) return null;\n\n\tconst container = document.createElement(\"div\");\n\tcontainer.id = MOUNT_NODE_ID;\n\tcontainer.dataset.ynsFeedbackUi = \"true\";\n\tdocument.body.appendChild(container);\n\n\tconst root = createRoot(container);\n\troot.render(<FeedbackToolbar />);\n\n\treturn {\n\t\tunmount: () => {\n\t\t\troot.unmount();\n\t\t\tcontainer.remove();\n\t\t},\n\t};\n}\n\n// Auto-mount on import. Wait for DOM ready.\nif (typeof window !== \"undefined\") {\n\tconsole.log(\"[YNS Feedback Toolbar] module evaluated\", {\n\t\tvercelEnv: process.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\treadyState: document.readyState,\n\t\twillAutoMount: process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\",\n\t});\n}\nif (typeof window !== \"undefined\" && process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\") {\n\tif (document.readyState === \"loading\") {\n\t\tdocument.addEventListener(\"DOMContentLoaded\", () => {\n\t\t\tmountFeedbackToolbar();\n\t\t});\n\t} else {\n\t\tmountFeedbackToolbar();\n\t}\n}\n","/**\n * Sandbox Inspectors — side-effect entry.\n *\n * Auto-mounts the design-mode + comment-mode inspectors inside per-store\n * storefronts running under the AI Builder sandbox dev server. Communicates\n * with the parent /design iframe via postMessage.\n *\n * Always-on: inspectors are passive postMessage listeners and don't affect the\n * page until the AI Builder iframe sends a `*-mode-toggle` message. Gating on\n * NODE_ENV is wrong (always \"production\" on Vercel) and any build-time gate\n * gets folded out by the commerce-kit bundle, leaving an empty file.\n */\n\n/**\n * Exported so `browser.tsx` can `export { startSandboxInspectors }` — the\n * named binding anchors this module against esbuild tree-shaking when\n * commerce-kit is bundled. Without it, an `export * from \"./sandbox-inspectors\"`\n * re-exports an empty binding set and esbuild DCEs the whole file.\n */\nexport function startSandboxInspectors(): void {\n\tif (typeof window === \"undefined\") return;\n\tconsole.log(\"[YNS Sandbox Inspectors] module evaluated\");\n\tinitDesignModeInspector();\n\tinitCommentModeInspector();\n}\n\n// Auto-start on import.\nstartSandboxInspectors();\n\ninterface ElementInfo {\n\ttag: string;\n\tid: string | undefined;\n\tclasses: string[];\n\ttextContent: string;\n\tcssSelector: string;\n\tboundingRect: { top: number; left: number; width: number; height: number };\n\tcomputedStyles: Partial<{\n\t\tcolor: string;\n\t\tbackgroundColor: string;\n\t\tfontSize: string;\n\t\tfontFamily: string;\n\t\tpadding: string;\n\t\tmargin: string;\n\t}>;\n}\n\nconst IGNORED_TAGS = new Set([\"HEAD\", \"SCRIPT\", \"STYLE\", \"NOSCRIPT\", \"HTML\"]);\n\nfunction generateCssSelector(el: Element): string {\n\tif (el.id) return `${el.tagName.toLowerCase()}#${CSS.escape(el.id)}`;\n\n\tconst parts: string[] = [];\n\tlet current: Element | null = el;\n\twhile (current && current !== document.body && current !== document.documentElement) {\n\t\tlet selector = current.tagName.toLowerCase();\n\n\t\tif (current.id) {\n\t\t\tparts.unshift(`${selector}#${CSS.escape(current.id)}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst classes = Array.from(current.classList).filter((c) => !c.startsWith(\"data-yns-\"));\n\t\tif (classes.length > 0) {\n\t\t\tselector += `.${classes.map((c) => CSS.escape(c)).join(\".\")}`;\n\t\t}\n\n\t\tconst parent: Element | null = current.parentElement;\n\t\tconst tag = current.tagName;\n\t\tif (parent) {\n\t\t\tconst siblings = Array.from(parent.children).filter(\n\t\t\t\t(s) => s.tagName === tag && (classes.length === 0 || classes.every((c) => s.classList.contains(c))),\n\t\t\t);\n\t\t\tif (siblings.length > 1) {\n\t\t\t\tconst index = Array.from(parent.children).indexOf(current) + 1;\n\t\t\t\tselector += `:nth-child(${index})`;\n\t\t\t}\n\t\t}\n\n\t\tparts.unshift(selector);\n\t\tcurrent = current.parentElement;\n\t}\n\treturn parts.join(\" > \");\n}\n\nfunction buildElementInfo(el: Element, textLimit: number): ElementInfo {\n\tconst rect = el.getBoundingClientRect();\n\tconst computed = window.getComputedStyle(el);\n\tconst text = (el.textContent ?? \"\").trim();\n\treturn {\n\t\ttag: el.tagName.toLowerCase(),\n\t\tid: el.id || undefined,\n\t\tclasses: Array.from(el.classList).filter((c) => !c.startsWith(\"data-yns-\")),\n\t\ttextContent: text.length > textLimit ? `${text.slice(0, textLimit)}…` : text,\n\t\tcssSelector: generateCssSelector(el),\n\t\tboundingRect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },\n\t\tcomputedStyles: {\n\t\t\tcolor: computed.color,\n\t\t\tbackgroundColor: computed.backgroundColor,\n\t\t\tfontSize: computed.fontSize,\n\t\t\tfontFamily: computed.fontFamily,\n\t\t\tpadding: computed.padding,\n\t\t\tmargin: computed.margin,\n\t\t},\n\t};\n}\n\nfunction shouldIgnore(el: Element | null, overlayAttrs: string[]): el is null {\n\tif (!el || !el.tagName) return true;\n\tif (IGNORED_TAGS.has(el.tagName)) return true;\n\tfor (const attr of overlayAttrs) {\n\t\tif (el.hasAttribute?.(attr)) return true;\n\t}\n\treturn false;\n}\n\nfunction initDesignModeInspector() {\n\tlet enabled = false;\n\tlet hoveredElement: Element | null = null;\n\tlet selectedElement: { el: Element; cssSelector: string } | null = null;\n\n\tconst overlay = document.createElement(\"div\");\n\toverlay.setAttribute(\"data-yns-design-overlay\", \"hover\");\n\toverlay.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483646\",\n\t\t\"border: 2px solid #3b82f6\",\n\t\t\"background: rgba(59, 130, 246, 0.08)\",\n\t\t\"border-radius: 3px\",\n\t\t\"display: none\",\n\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t].join(\";\");\n\n\tconst label = document.createElement(\"div\");\n\tlabel.setAttribute(\"data-yns-design-overlay\", \"label\");\n\tlabel.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483647\",\n\t\t\"background: #3b82f6\",\n\t\t\"color: #fff\",\n\t\t\"font-size: 11px\",\n\t\t\"font-family: ui-monospace, monospace\",\n\t\t\"padding: 2px 6px\",\n\t\t\"border-radius: 3px\",\n\t\t\"white-space: nowrap\",\n\t\t\"display: none\",\n\t].join(\";\");\n\n\tdocument.documentElement.appendChild(overlay);\n\tdocument.documentElement.appendChild(label);\n\n\tconst style = document.createElement(\"style\");\n\tstyle.setAttribute(\"data-yns-design-overlay\", \"style\");\n\tstyle.textContent = \"[data-yns-selected] { outline: 2px solid #3b82f6 !important; outline-offset: 1px; }\";\n\tdocument.head.appendChild(style);\n\n\tfunction positionOverlay(el: Element) {\n\t\tconst rect = el.getBoundingClientRect();\n\t\toverlay.style.top = `${rect.top}px`;\n\t\toverlay.style.left = `${rect.left}px`;\n\t\toverlay.style.width = `${rect.width}px`;\n\t\toverlay.style.height = `${rect.height}px`;\n\t\toverlay.style.display = \"block\";\n\n\t\tconst classes = Array.from(el.classList).filter((c) => !c.startsWith(\"data-yns-\"));\n\t\tconst labelText = el.tagName.toLowerCase() + (classes.length ? `.${classes[0]}` : \"\");\n\t\tlabel.textContent = labelText;\n\t\tlabel.style.left = `${rect.left}px`;\n\t\tlabel.style.top = `${Math.max(0, rect.top - 22)}px`;\n\t\tlabel.style.display = \"block\";\n\t}\n\n\tconst handleMouseMove = (e: MouseEvent) => {\n\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\tif (shouldIgnore(el, [\"data-yns-design-overlay\"])) {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tlabel.style.display = \"none\";\n\t\t\thoveredElement = null;\n\t\t\treturn;\n\t\t}\n\t\thoveredElement = el;\n\t\trequestAnimationFrame(() => {\n\t\t\tif (hoveredElement === el && enabled && el) {\n\t\t\t\tpositionOverlay(el);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst handleMouseLeave = () => {\n\t\toverlay.style.display = \"none\";\n\t\tlabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t};\n\n\tconst handleClick = (e: MouseEvent) => {\n\t\tif (!enabled || !hoveredElement) return;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\te.stopImmediatePropagation();\n\n\t\tconst el = hoveredElement;\n\t\tif (shouldIgnore(el, [\"data-yns-design-overlay\"])) return;\n\n\t\tconst info = buildElementInfo(el, 120);\n\t\tconst selector = info.cssSelector;\n\n\t\tif (selectedElement) {\n\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t}\n\n\t\tif (selectedElement && selectedElement.cssSelector === selector) {\n\t\t\tselectedElement = null;\n\t\t\twindow.parent.postMessage({ type: \"element-deselected\", data: info }, \"*\");\n\t\t} else {\n\t\t\tselectedElement = { el, cssSelector: selector };\n\t\t\tel.setAttribute(\"data-yns-selected\", \"\");\n\t\t\twindow.parent.postMessage({ type: \"element-selected\", data: info }, \"*\");\n\t\t}\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key === \"Escape\" && enabled) {\n\t\t\tdisableDesignMode();\n\t\t\twindow.parent.postMessage({ type: \"design-mode-cleared\" }, \"*\");\n\t\t}\n\t};\n\n\tfunction enableDesignMode() {\n\t\tenabled = true;\n\t\tdocument.addEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.addEventListener(\"click\", handleClick, true);\n\t\tdocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t}\n\n\tfunction disableDesignMode() {\n\t\tenabled = false;\n\t\tdocument.removeEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.removeEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.removeEventListener(\"click\", handleClick, true);\n\t\tdocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\n\t\toverlay.style.display = \"none\";\n\t\tlabel.style.display = \"none\";\n\t\thoveredElement = null;\n\n\t\tif (selectedElement) {\n\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t\tselectedElement = null;\n\t\t}\n\t}\n\n\twindow.addEventListener(\"message\", (event) => {\n\t\tconst msg = event.data;\n\t\tif (!msg || typeof msg !== \"object\") return;\n\n\t\tif (msg.type === \"design-mode-toggle\") {\n\t\t\tif (msg.enabled) {\n\t\t\t\tenableDesignMode();\n\t\t\t} else {\n\t\t\t\tdisableDesignMode();\n\t\t\t\twindow.parent.postMessage({ type: \"design-mode-cleared\" }, \"*\");\n\t\t\t}\n\t\t}\n\n\t\tif (msg.type === \"design-mode-deselect\") {\n\t\t\tif (selectedElement) {\n\t\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t\t\tselectedElement = null;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction initCommentModeInspector() {\n\tlet enabled = false;\n\tlet hoveredElement: Element | null = null;\n\tlet pins: Array<{ id: string; selector: string; number: number }> = [];\n\n\tconst overlay = document.createElement(\"div\");\n\toverlay.setAttribute(\"data-yns-comment-overlay\", \"hover\");\n\toverlay.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483644\",\n\t\t\"border: 2px dashed #10b981\",\n\t\t\"background: rgba(16, 185, 129, 0.06)\",\n\t\t\"border-radius: 3px\",\n\t\t\"display: none\",\n\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t].join(\";\");\n\n\tconst cursorLabel = document.createElement(\"div\");\n\tcursorLabel.setAttribute(\"data-yns-comment-overlay\", \"cursor-label\");\n\tcursorLabel.textContent = \"Click to comment\";\n\tcursorLabel.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483645\",\n\t\t\"background: #059669\",\n\t\t\"color: #fff\",\n\t\t\"font-size: 11px\",\n\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\"padding: 3px 8px\",\n\t\t\"border-radius: 4px\",\n\t\t\"white-space: nowrap\",\n\t\t\"display: none\",\n\t\t\"box-shadow: 0 2px 6px rgba(0,0,0,0.15)\",\n\t].join(\";\");\n\n\tconst pinContainer = document.createElement(\"div\");\n\tpinContainer.setAttribute(\"data-yns-comment-overlay\", \"pins\");\n\tpinContainer.style.cssText =\n\t\t\"position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2147483643;\";\n\n\tdocument.documentElement.appendChild(overlay);\n\tdocument.documentElement.appendChild(cursorLabel);\n\tdocument.documentElement.appendChild(pinContainer);\n\n\tfunction renderPins() {\n\t\tpinContainer.innerHTML = \"\";\n\t\tfor (const pin of pins) {\n\t\t\tlet el: Element | null = null;\n\t\t\ttry {\n\t\t\t\tel = document.querySelector(pin.selector);\n\t\t\t} catch {\n\t\t\t\tel = null;\n\t\t\t}\n\t\t\tif (!el) continue;\n\n\t\t\tconst r = el.getBoundingClientRect();\n\t\t\tconst pinEl = document.createElement(\"div\");\n\t\t\tpinEl.style.cssText = [\n\t\t\t\t\"position: fixed\",\n\t\t\t\t`top: ${r.top - 12}px`,\n\t\t\t\t`left: ${r.left + r.width / 2 - 12}px`,\n\t\t\t\t\"width: 24px\",\n\t\t\t\t\"height: 24px\",\n\t\t\t\t\"border-radius: 50%\",\n\t\t\t\t\"background: #059669\",\n\t\t\t\t\"color: #fff\",\n\t\t\t\t\"display: flex\",\n\t\t\t\t\"align-items: center\",\n\t\t\t\t\"justify-content: center\",\n\t\t\t\t\"font-size: 12px\",\n\t\t\t\t\"font-weight: 600\",\n\t\t\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\t\t\"box-shadow: 0 2px 8px rgba(0,0,0,0.2)\",\n\t\t\t\t\"pointer-events: none\",\n\t\t\t].join(\";\");\n\t\t\tpinEl.textContent = String(pin.number);\n\t\t\tpinContainer.appendChild(pinEl);\n\t\t}\n\t}\n\n\tconst handleMouseMove = (e: MouseEvent) => {\n\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\tif (shouldIgnore(el, [\"data-yns-comment-overlay\", \"data-yns-design-overlay\"])) {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tcursorLabel.style.display = \"none\";\n\t\t\thoveredElement = null;\n\t\t\treturn;\n\t\t}\n\t\thoveredElement = el;\n\t\trequestAnimationFrame(() => {\n\t\t\tif (hoveredElement === el && enabled && el) {\n\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\toverlay.style.top = `${rect.top}px`;\n\t\t\t\toverlay.style.left = `${rect.left}px`;\n\t\t\t\toverlay.style.width = `${rect.width}px`;\n\t\t\t\toverlay.style.height = `${rect.height}px`;\n\t\t\t\toverlay.style.display = \"block\";\n\n\t\t\t\tcursorLabel.style.left = `${e.clientX + 14}px`;\n\t\t\t\tcursorLabel.style.top = `${e.clientY + 14}px`;\n\t\t\t\tcursorLabel.style.display = \"block\";\n\t\t\t}\n\t\t});\n\t};\n\n\tconst handleMouseLeave = () => {\n\t\toverlay.style.display = \"none\";\n\t\tcursorLabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t};\n\n\tconst handleClick = (e: MouseEvent) => {\n\t\tif (!enabled || !hoveredElement) return;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\te.stopImmediatePropagation();\n\n\t\tconst el = hoveredElement;\n\t\tif (shouldIgnore(el, [\"data-yns-comment-overlay\", \"data-yns-design-overlay\"])) return;\n\n\t\tconst info = buildElementInfo(el, 200);\n\t\tconst rect = el.getBoundingClientRect();\n\n\t\twindow.parent.postMessage(\n\t\t\t{\n\t\t\t\ttype: \"comment-click\",\n\t\t\t\tdata: {\n\t\t\t\t\telement: info,\n\t\t\t\t\tclickPosition: { x: e.clientX, y: e.clientY },\n\t\t\t\t\telementRect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },\n\t\t\t\t\tpagePath: window.location.pathname,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"*\",\n\t\t);\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key === \"Escape\" && enabled) {\n\t\t\tdisableCommentMode();\n\t\t\twindow.parent.postMessage({ type: \"comment-mode-cleared\" }, \"*\");\n\t\t}\n\t};\n\n\tfunction enableCommentMode() {\n\t\tenabled = true;\n\t\tdocument.body.style.cursor = \"crosshair\";\n\t\tdocument.addEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.addEventListener(\"click\", handleClick, true);\n\t\tdocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t}\n\n\tfunction disableCommentMode() {\n\t\tenabled = false;\n\t\tdocument.body.style.cursor = \"\";\n\t\tdocument.removeEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.removeEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.removeEventListener(\"click\", handleClick, true);\n\t\tdocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\n\t\toverlay.style.display = \"none\";\n\t\tcursorLabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t}\n\n\tlet rafPending = false;\n\tconst scheduleRender = () => {\n\t\tif (rafPending) return;\n\t\trafPending = true;\n\t\trequestAnimationFrame(() => {\n\t\t\trafPending = false;\n\t\t\trenderPins();\n\t\t});\n\t};\n\twindow.addEventListener(\"scroll\", scheduleRender, { passive: true });\n\twindow.addEventListener(\"resize\", scheduleRender, { passive: true });\n\n\twindow.addEventListener(\"message\", (event) => {\n\t\tconst msg = event.data;\n\t\tif (!msg || typeof msg !== \"object\") return;\n\n\t\tif (msg.type === \"comment-mode-toggle\") {\n\t\t\tif (msg.enabled) enableCommentMode();\n\t\t\telse disableCommentMode();\n\t\t}\n\n\t\tif (msg.type === \"comment-pins-update\") {\n\t\t\tpins = msg.pins ?? [];\n\t\t\trenderPins();\n\t\t}\n\n\t\tif (msg.type === \"comment-pin-remove\") {\n\t\t\tpins = pins.filter((p) => p.id !== msg.pinId);\n\t\t\trenderPins();\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","createRoot","Fragment","jsx","jsxs","MOUNT_NODE_ID","buildApiBase","override","host","protocol","computeCssSelector","el","path","node","part","className","classes","parent","tag","siblings","idx","ATTRS_OF_INTEREST","formatAttrs","parts","attr","v","trimmed","formatTextContent","text","buildSurroundingHtml","target","ancestors","cur","lines","depth","ancestor","indent","targetIndent","targetTag","targetText","childIndent","children","child","childText","i","isInsideToolbar","IGNORED_TAGS","POLL_INTERVAL_MS","formatEta","etaIso","eta","remainingMs","dateLabel","remainingMin","remainingHours","remainingDays","FeedbackToolbar","session","setSession","loading","setLoading","pinMode","setPinMode","pending","setPending","editingId","setEditingId","sidebarOpen","setSidebarOpen","finalizing","setFinalizing","apiBase","cancelled","controller","fetchOnce","res","data","interval","overlay","label","hovered","handleMove","e","rect","handleLeave","handleClick","event","offsetXRatio","offsetYRatio","refreshComments","submitNewComment","content","attachments","updateComment","id","removeComment","finalizeSession","nextStatus","prev","scrollToComment","comment","SubmittedPanel","visiblePins","c","pin","PinOverlay","PendingCommentPopover","CommentsSidebar","toolbarStyle","toolbarButtonActiveStyle","toolbarButtonStyle","toolbarButtonGhostStyle","toolbarButtonFinalizeStyle","toolbarHintStyle","progress","status","setTick","t","submittedPanelStyle","spinnerKeyframes","submittedHeaderStyle","Spinner","submittedBadgeStyle","submittedProgressLabelStyle","submittedProgressTrackStyle","submittedProgressFillStyle","submittedEtaStyle","size","number","editing","feedbackSessionId","onStartEdit","onCancelEdit","onSave","onRemove","useTargetPosition","pinDotStyle","EditPopover","onCancel","comments","currentPath","onClose","onSelect","groups","list","paths","a","b","sidebarStyle","sidebarHeaderStyle","ghostButtonStyle","sidebarScrollStyle","sidebarEmptyStyle","sidebarPathStyle","sidebarItemStyle","sidebarItemIndexStyle","sidebarItemTextStyle","sidebarItemDoneStyle","MAX_ATTACHMENTS","MAX_ATTACHMENT_BYTES","readImageDimensions","file","resolve","url","img","initial","initialAttachments","value","setValue","setAttachments","saving","setSaving","uploading","setUploading","error","setError","textareaRef","fileInputRef","len","handleSubmit","handleFiles","files","slots","picked","dims","fd","body","removeAttachment","popoverStyle","textareaStyle","attachmentRowStyle","att","attachmentThumbWrapStyle","attachmentThumbStyle","attachmentRemoveStyle","errorTextStyle","popoverActionsStyle","dangerButtonStyle","primaryButtonStyle","selector","pos","setPos","update","r","ro","baseButton","mountFeedbackToolbar","container","root","startSandboxInspectors","initDesignModeInspector","initCommentModeInspector","IGNORED_TAGS","generateCssSelector","el","parts","current","selector","classes","c","parent","tag","s","index","buildElementInfo","textLimit","rect","computed","text","shouldIgnore","overlayAttrs","attr","enabled","hoveredElement","selectedElement","overlay","label","style","positionOverlay","labelText","handleMouseMove","e","handleMouseLeave","handleClick","info","handleKeyDown","disableDesignMode","enableDesignMode","event","msg","pins","cursorLabel","pinContainer","renderPins","pin","r","pinEl","disableCommentMode","enableCommentMode","rafPending","scheduleRender","p"]}
|
|
1
|
+
{"version":3,"sources":["../src/feedback-toolbar.tsx","../src/sandbox-inspectors.ts"],"sourcesContent":["/**\n * Feedback session toolbar — side-effect entry.\n *\n * Importing `commerce-kit/feedback-toolbar` (or `commerce-kit/browser` for the\n * combined entry) mounts a floating toolbar onto the page that lets reviewers\n * leave click-anchored comments. Comments persist via YNS API endpoints,\n * authenticated with the `better-auth` session cookie sent through\n * `credentials: \"include\"`.\n *\n * Gated on `process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\"` — only Vercel\n * preview deploys get the toolbar. Sandbox dev (env undefined) and production\n * (env === \"production\") skip it.\n */\n\nimport { type CSSProperties, type FormEvent, useEffect, useRef, useState } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nconst MOUNT_NODE_ID = \"yns-feedback-toolbar-root\";\n\ninterface FeedbackAttachment {\n\turl: string;\n\tcontentType: string;\n\twidth?: number;\n\theight?: number;\n}\n\ninterface FeedbackComment {\n\tid: string;\n\tpagePath: string;\n\tcssSelector: string;\n\tcontent: string;\n\tstatus: \"todo\" | \"done\";\n\toffsetXRatio: number;\n\toffsetYRatio: number;\n\tattachments: FeedbackAttachment[];\n}\n\ntype SessionStatus = \"created\" | \"in_progress\" | \"processing\" | \"in_review\" | \"done\";\n\ninterface ReviewProgress {\n\tfillPct: number;\n\tlabel: string;\n}\n\ninterface ActiveSession {\n\tfeedbackSessionId: string;\n\tcomments: FeedbackComment[];\n\tcanComment: boolean;\n\tsessionStatus: SessionStatus;\n\tcommentTotal: number;\n\tcommentDone: number;\n\teta: string;\n\tprogress: ReviewProgress;\n}\n\ninterface PendingPin {\n\tcssSelector: string;\n\tpagePath: string;\n\tsurroundingHtml: string;\n\trect: { top: number; left: number; width: number; height: number };\n\tclickX: number;\n\tclickY: number;\n\toffsetXRatio: number;\n\toffsetYRatio: number;\n}\n\nconst buildApiBase = (): string | null => {\n\tif (typeof window === \"undefined\") return null;\n\tconst override = (process.env.NEXT_PUBLIC_YNS_API_BASE ?? \"\").trim();\n\tif (override) return override.replace(/\\/$/, \"\");\n\n\t// Toolbar runs on a per-store preview deploy (mystore-preview.yns.{store|cx})\n\t// served by the merchant's Vercel project — that host has no YNS API. Aim\n\t// at the apex `yns.store` / `yns.cx`, which yns-app serves and where the\n\t// API lives. Cookies scoped to `.yns.store` / `.yns.cx` travel along.\n\tconst host = window.location.hostname;\n\tconst protocol = window.location.protocol;\n\tif (host.endsWith(\".yns.store\")) return `${protocol}//yns.store`;\n\tif (host.endsWith(\".yns.cx\")) return `${protocol}//yns.cx`;\n\treturn window.location.origin;\n};\n\nconst computeCssSelector = (el: Element): string => {\n\tif (el.id) return `#${CSS.escape(el.id)}`;\n\tconst path: string[] = [];\n\tlet node: Element | null = el;\n\twhile (node && node.nodeType === Node.ELEMENT_NODE && path.length < 6) {\n\t\tlet part = node.tagName.toLowerCase();\n\t\tconst className = node.getAttribute(\"class\");\n\t\tif (className) {\n\t\t\tconst classes = className\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.slice(0, 2)\n\t\t\t\t.map((c) => `.${CSS.escape(c)}`)\n\t\t\t\t.join(\"\");\n\t\t\tpart += classes;\n\t\t}\n\t\tconst parent: Element | null = node.parentElement;\n\t\tconst tag = node.tagName;\n\t\tif (parent) {\n\t\t\tconst siblings: Element[] = Array.from(parent.children).filter((c) => c.tagName === tag);\n\t\t\tif (siblings.length > 1) {\n\t\t\t\tconst idx = siblings.indexOf(node) + 1;\n\t\t\t\tpart += `:nth-of-type(${idx})`;\n\t\t\t}\n\t\t}\n\t\tpath.unshift(part);\n\t\tnode = parent;\n\t}\n\treturn path.join(\" > \");\n};\n\nconst ATTRS_OF_INTEREST = [\"id\", \"class\", \"data-testid\", \"aria-label\", \"role\", \"name\", \"href\", \"src\"];\n\nconst formatAttrs = (el: Element): string => {\n\tconst parts: string[] = [];\n\tfor (const attr of ATTRS_OF_INTEREST) {\n\t\tconst v = el.getAttribute(attr);\n\t\tif (!v) continue;\n\t\tconst trimmed = v.length > 80 ? `${v.slice(0, 80)}…` : v;\n\t\tparts.push(` ${attr}=\"${trimmed.replace(/\"/g, \""\")}\"`);\n\t}\n\treturn parts.join(\"\");\n};\n\nconst formatTextContent = (el: Element): string => {\n\tconst text = (el.textContent ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (!text) return \"\";\n\treturn text.length > 100 ? `${text.slice(0, 100)}…` : text;\n};\n\nconst buildSurroundingHtml = (target: Element): string => {\n\tconst ancestors: Element[] = [];\n\tlet cur: Element | null = target;\n\twhile (cur && cur !== document.documentElement && ancestors.length < 5) {\n\t\tconst parent: Element | null = cur.parentElement;\n\t\tif (!parent) break;\n\t\tancestors.unshift(parent);\n\t\tcur = parent;\n\t}\n\n\tconst lines: string[] = [];\n\tlet depth = 0;\n\tfor (const ancestor of ancestors) {\n\t\tconst indent = \" \".repeat(depth);\n\t\tlines.push(`${indent}<${ancestor.tagName.toLowerCase()}${formatAttrs(ancestor)}>`);\n\t\tdepth++;\n\t}\n\n\tconst targetIndent = \" \".repeat(depth);\n\tconst targetTag = target.tagName.toLowerCase();\n\tconst targetText = formatTextContent(target);\n\tlines.push(\n\t\t`${targetIndent}<${targetTag}${formatAttrs(target)}>${\n\t\t\ttargetText ? `${targetText}</${targetTag}>` : \"\"\n\t\t} ← TARGET`,\n\t);\n\n\tif (!targetText) {\n\t\tconst childIndent = \" \".repeat(depth + 1);\n\t\tconst children = Array.from(target.children).slice(0, 6);\n\t\tfor (const child of children) {\n\t\t\tconst childText = formatTextContent(child);\n\t\t\tlines.push(\n\t\t\t\t`${childIndent}<${child.tagName.toLowerCase()}${formatAttrs(child)}>${\n\t\t\t\t\tchildText ? `${childText}</${child.tagName.toLowerCase()}>` : \"\"\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (target.children.length > 6) {\n\t\t\tlines.push(`${childIndent}… (${target.children.length - 6} more children)`);\n\t\t}\n\t\tlines.push(`${targetIndent}</${targetTag}>`);\n\t}\n\n\tfor (let i = ancestors.length - 1; i >= 0; i--) {\n\t\tconst indent = \" \".repeat(i);\n\t\tconst ancestor = ancestors[i];\n\t\tif (!ancestor) continue;\n\t\tlines.push(`${indent}</${ancestor.tagName.toLowerCase()}>`);\n\t}\n\n\treturn lines.join(\"\\n\");\n};\n\nconst isInsideToolbar = (el: Element | null): boolean => {\n\tlet node = el;\n\twhile (node) {\n\t\tif (node instanceof HTMLElement && node.dataset.ynsFeedbackUi === \"true\") return true;\n\t\tnode = node.parentElement;\n\t}\n\treturn false;\n};\n\nconst IGNORED_TAGS = new Set([\"HTML\", \"HEAD\", \"SCRIPT\", \"STYLE\", \"NOSCRIPT\"]);\n\nconst POLL_INTERVAL_MS = 10_000;\n\n// Format a server-computed ETA as remaining + absolute label. The deadline\n// math itself lives in yns-app's `lib/feedback-comments-api.ts` so the toolbar\n// and YNS lock screen stay in sync.\nconst formatEta = (etaIso: string): string => {\n\tconst eta = new Date(etaIso);\n\tconst remainingMs = eta.getTime() - Date.now();\n\tconst dateLabel = eta.toLocaleString(undefined, {\n\t\tweekday: \"short\",\n\t\tmonth: \"short\",\n\t\tday: \"numeric\",\n\t\thour: \"numeric\",\n\t\tminute: \"2-digit\",\n\t});\n\n\tif (remainingMs <= 0) return `Any moment now (estimated by ${dateLabel})`;\n\tconst remainingMin = Math.ceil(remainingMs / 60_000);\n\tif (remainingMin < 60) return `~${remainingMin} minutes (by ${dateLabel})`;\n\tconst remainingHours = Math.round(remainingMs / 3_600_000);\n\tif (remainingHours < 24) {\n\t\treturn `~${remainingHours} ${remainingHours === 1 ? \"hour\" : \"hours\"} (by ${dateLabel})`;\n\t}\n\tconst remainingDays = Math.round(remainingMs / 86_400_000);\n\treturn `~${remainingDays} ${remainingDays === 1 ? \"day\" : \"days\"} (by ${dateLabel})`;\n};\n\nfunction FeedbackToolbar() {\n\tconst [session, setSession] = useState<ActiveSession | null>(null);\n\tconst [loading, setLoading] = useState(true);\n\tconst [pinMode, setPinMode] = useState(false);\n\tconst [pending, setPending] = useState<PendingPin | null>(null);\n\tconst [editingId, setEditingId] = useState<string | null>(null);\n\tconst [sidebarOpen, setSidebarOpen] = useState(false);\n\tconst [finalizing, setFinalizing] = useState(false);\n\tconst apiBase = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\tapiBase.current = buildApiBase();\n\t\tif (!apiBase.current) {\n\t\t\tsetLoading(false);\n\t\t\treturn;\n\t\t}\n\n\t\tlet cancelled = false;\n\t\tconst controller = new AbortController();\n\n\t\tconst fetchOnce = async () => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\n\t\t\t\t\t`${apiBase.current}/api/feedback-comments?host=${encodeURIComponent(window.location.host)}`,\n\t\t\t\t\t{ credentials: \"include\", signal: controller.signal },\n\t\t\t\t);\n\t\t\t\tif (cancelled) return;\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tsetSession(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst data = (await res.json()) as ActiveSession;\n\t\t\t\tif (cancelled) return;\n\t\t\t\tsetSession(data);\n\t\t\t\t// Hard-refresh once the AI run lands and the preview is up to date.\n\t\t\t\t// Out of scope to diff anything smarter — the new deploy replaces\n\t\t\t\t// the page entirely so a full reload is appropriate here.\n\t\t\t\tif (data.sessionStatus === \"done\") {\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tif (!cancelled) setSession(null);\n\t\t\t} finally {\n\t\t\t\tif (!cancelled) setLoading(false);\n\t\t\t}\n\t\t};\n\n\t\tvoid fetchOnce();\n\t\tconst interval = window.setInterval(fetchOnce, POLL_INTERVAL_MS);\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t\tcontroller.abort();\n\t\t\twindow.clearInterval(interval);\n\t\t};\n\t}, []);\n\n\t// When the session stops accepting comments (finalized → in_review, or\n\t// closed), tear down any in-flight UI so the hover overlay/popover/sidebar\n\t// don't linger after the toolbar's main render returns null.\n\tuseEffect(() => {\n\t\tif (!session || session.canComment) return;\n\t\tsetPinMode(false);\n\t\tsetPending(null);\n\t\tsetSidebarOpen(false);\n\t\tsetEditingId(null);\n\t}, [session]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\t\tdocument.body.style.cursor = \"crosshair\";\n\t\treturn () => {\n\t\t\tdocument.body.style.cursor = \"\";\n\t\t};\n\t}, [pinMode]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\n\t\tconst overlay = document.createElement(\"div\");\n\t\toverlay.dataset.ynsFeedbackUi = \"true\";\n\t\toverlay.style.cssText = [\n\t\t\t\"position: fixed\",\n\t\t\t\"pointer-events: none\",\n\t\t\t\"z-index: 2147483644\",\n\t\t\t\"border: 2px dashed #10b981\",\n\t\t\t\"background: rgba(16, 185, 129, 0.08)\",\n\t\t\t\"border-radius: 3px\",\n\t\t\t\"display: none\",\n\t\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t\t].join(\";\");\n\n\t\tconst label = document.createElement(\"div\");\n\t\tlabel.dataset.ynsFeedbackUi = \"true\";\n\t\tlabel.textContent = \"Click to comment\";\n\t\tlabel.style.cssText = [\n\t\t\t\"position: fixed\",\n\t\t\t\"pointer-events: none\",\n\t\t\t\"z-index: 2147483645\",\n\t\t\t\"background: #059669\",\n\t\t\t\"color: #fff\",\n\t\t\t\"font-size: 11px\",\n\t\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\t\"padding: 3px 8px\",\n\t\t\t\"border-radius: 4px\",\n\t\t\t\"white-space: nowrap\",\n\t\t\t\"display: none\",\n\t\t\t\"box-shadow: 0 2px 6px rgba(0,0,0,0.15)\",\n\t\t].join(\";\");\n\n\t\tdocument.documentElement.appendChild(overlay);\n\t\tdocument.documentElement.appendChild(label);\n\n\t\tlet hovered: Element | null = null;\n\t\tconst handleMove = (e: MouseEvent) => {\n\t\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\t\tif (!el || IGNORED_TAGS.has(el.tagName) || isInsideToolbar(el)) {\n\t\t\t\toverlay.style.display = \"none\";\n\t\t\t\tlabel.style.display = \"none\";\n\t\t\t\thovered = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thovered = el;\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (hovered !== el) return;\n\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\toverlay.style.top = `${rect.top}px`;\n\t\t\t\toverlay.style.left = `${rect.left}px`;\n\t\t\t\toverlay.style.width = `${rect.width}px`;\n\t\t\t\toverlay.style.height = `${rect.height}px`;\n\t\t\t\toverlay.style.display = \"block\";\n\t\t\t\tlabel.style.left = `${e.clientX + 14}px`;\n\t\t\t\tlabel.style.top = `${e.clientY + 14}px`;\n\t\t\t\tlabel.style.display = \"block\";\n\t\t\t});\n\t\t};\n\n\t\tconst handleLeave = () => {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tlabel.style.display = \"none\";\n\t\t\thovered = null;\n\t\t};\n\n\t\tdocument.addEventListener(\"mousemove\", handleMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleLeave);\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"mousemove\", handleMove, true);\n\t\t\tdocument.removeEventListener(\"mouseleave\", handleLeave);\n\t\t\toverlay.remove();\n\t\t\tlabel.remove();\n\t\t};\n\t}, [pinMode]);\n\n\tuseEffect(() => {\n\t\tif (!pinMode) return;\n\t\tconst handleClick = (event: MouseEvent) => {\n\t\t\tconst target = event.target;\n\t\t\tif (!(target instanceof Element)) return;\n\t\t\tif (isInsideToolbar(target)) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tconst rect = target.getBoundingClientRect();\n\t\t\tconst offsetXRatio = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0.5;\n\t\t\tconst offsetYRatio = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0.5;\n\t\t\tsetPending({\n\t\t\t\tcssSelector: computeCssSelector(target),\n\t\t\t\tpagePath: window.location.pathname,\n\t\t\t\tsurroundingHtml: buildSurroundingHtml(target),\n\t\t\t\trect: {\n\t\t\t\t\ttop: rect.top + window.scrollY,\n\t\t\t\t\tleft: rect.left + window.scrollX,\n\t\t\t\t\twidth: rect.width,\n\t\t\t\t\theight: rect.height,\n\t\t\t\t},\n\t\t\t\tclickX: event.clientX + window.scrollX,\n\t\t\t\tclickY: event.clientY + window.scrollY,\n\t\t\t\toffsetXRatio: Math.min(1, Math.max(0, offsetXRatio)),\n\t\t\t\toffsetYRatio: Math.min(1, Math.max(0, offsetYRatio)),\n\t\t\t});\n\t\t\tsetPinMode(false);\n\t\t};\n\t\tdocument.addEventListener(\"click\", handleClick, { capture: true });\n\t\treturn () => document.removeEventListener(\"click\", handleClick, { capture: true });\n\t}, [pinMode]);\n\n\tconst refreshComments = async () => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(\n\t\t\t`${apiBase.current}/api/feedback-comments?host=${encodeURIComponent(window.location.host)}`,\n\t\t\t{ credentials: \"include\" },\n\t\t);\n\t\tif (!res.ok) return;\n\t\tconst data = (await res.json()) as ActiveSession;\n\t\tsetSession(data);\n\t};\n\n\tconst submitNewComment = async (content: string, attachments: FeedbackAttachment[]) => {\n\t\tif (!apiBase.current || !session || !pending) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments`, {\n\t\t\tmethod: \"POST\",\n\t\t\tcredentials: \"include\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tfeedbackSessionId: session.feedbackSessionId,\n\t\t\t\tcontent,\n\t\t\t\tpagePath: pending.pagePath,\n\t\t\t\tcssSelector: pending.cssSelector,\n\t\t\t\tsurroundingHtml: pending.surroundingHtml,\n\t\t\t\toffsetXRatio: pending.offsetXRatio,\n\t\t\t\toffsetYRatio: pending.offsetYRatio,\n\t\t\t\t...(attachments.length > 0 ? { attachments } : {}),\n\t\t\t}),\n\t\t});\n\t\tif (!res.ok) return;\n\t\tsetPending(null);\n\t\tsetPinMode(true);\n\t\tawait refreshComments();\n\t};\n\n\tconst updateComment = async (id: string, content: string, attachments: FeedbackAttachment[]) => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments/${id}`, {\n\t\t\tmethod: \"PATCH\",\n\t\t\tcredentials: \"include\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ content, attachments }),\n\t\t});\n\t\tif (!res.ok) return;\n\t\tsetEditingId(null);\n\t\tawait refreshComments();\n\t};\n\n\tconst removeComment = async (id: string) => {\n\t\tif (!apiBase.current) return;\n\t\tconst res = await fetch(`${apiBase.current}/api/feedback-comments/${id}`, {\n\t\t\tmethod: \"DELETE\",\n\t\t\tcredentials: \"include\",\n\t\t});\n\t\tif (!res.ok) return;\n\t\tawait refreshComments();\n\t};\n\n\tconst finalizeSession = async () => {\n\t\tif (!apiBase.current || !session) return;\n\t\tif (!window.confirm(\"Finalize this feedback session? You won't be able to add more comments.\")) return;\n\t\tsetFinalizing(true);\n\t\ttry {\n\t\t\tconst res = await fetch(\n\t\t\t\t`${apiBase.current}/api/feedback-sessions/${session.feedbackSessionId}/finalize`,\n\t\t\t\t{ method: \"POST\", credentials: \"include\" },\n\t\t\t);\n\t\t\tif (!res.ok) return;\n\t\t\t// Flip BOTH canComment and sessionStatus locally. Without the status\n\t\t\t// flip, the render guard sees `canComment=false` + `status=in_progress`\n\t\t\t// (a state the SubmittedPanel branch returns null for) and the toolbar\n\t\t\t// disappears for the ~10s gap until the next poll catches up.\n\t\t\tconst body = (await res.json().catch(() => null)) as { status?: SessionStatus } | null;\n\t\t\tconst nextStatus: SessionStatus = body?.status ?? \"processing\";\n\t\t\tsetSession((prev) => (prev ? { ...prev, canComment: false, sessionStatus: nextStatus } : prev));\n\t\t} finally {\n\t\t\tsetFinalizing(false);\n\t\t}\n\t};\n\n\tconst scrollToComment = (comment: FeedbackComment) => {\n\t\tif (comment.pagePath !== window.location.pathname) {\n\t\t\twindow.location.assign(comment.pagePath);\n\t\t\treturn;\n\t\t}\n\t\tlet el: Element | null = null;\n\t\ttry {\n\t\t\tel = document.querySelector(comment.cssSelector);\n\t\t} catch {\n\t\t\tel = null;\n\t\t}\n\t\tif (!el) return;\n\t\tel.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\tsetEditingId(comment.id);\n\t};\n\n\tif (loading || !session) return null;\n\n\t// Session has been finalized for AI review. Show a small status panel with\n\t// the same progress + ETA shown in YNS, but no commenting controls. Polling\n\t// continues in the background; on `done` we hard-reload to pick up the\n\t// fresh deploy.\n\tif (!session.canComment) {\n\t\tif (session.sessionStatus !== \"processing\" && session.sessionStatus !== \"in_review\") return null;\n\t\treturn (\n\t\t\t<div data-yns-feedback-ui=\"true\">\n\t\t\t\t<SubmittedPanel progress={session.progress} eta={session.eta} status={session.sessionStatus} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst visiblePins = session.comments.filter(\n\t\t(c) => c.pagePath === window.location.pathname && c.status !== \"done\",\n\t);\n\n\treturn (\n\t\t<div data-yns-feedback-ui=\"true\">\n\t\t\t{visiblePins.map((pin, idx) => (\n\t\t\t\t<PinOverlay\n\t\t\t\t\tkey={pin.id}\n\t\t\t\t\tpin={pin}\n\t\t\t\t\tnumber={idx + 1}\n\t\t\t\t\tediting={editingId === pin.id}\n\t\t\t\t\tfeedbackSessionId={session.feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase.current}\n\t\t\t\t\tonStartEdit={() => setEditingId(pin.id)}\n\t\t\t\t\tonCancelEdit={() => setEditingId(null)}\n\t\t\t\t\tonSave={(content, attachments) => updateComment(pin.id, content, attachments)}\n\t\t\t\t\tonRemove={() => removeComment(pin.id)}\n\t\t\t\t/>\n\t\t\t))}\n\n\t\t\t{pending && (\n\t\t\t\t<PendingCommentPopover\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tfeedbackSessionId={session.feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase.current}\n\t\t\t\t\tonCancel={() => {\n\t\t\t\t\t\tsetPending(null);\n\t\t\t\t\t\tsetPinMode(true);\n\t\t\t\t\t}}\n\t\t\t\t\tonSave={(content, attachments) => submitNewComment(content, attachments)}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{sidebarOpen && (\n\t\t\t\t<CommentsSidebar\n\t\t\t\t\tcomments={session.comments}\n\t\t\t\t\tcurrentPath={window.location.pathname}\n\t\t\t\t\tonClose={() => setSidebarOpen(false)}\n\t\t\t\t\tonSelect={scrollToComment}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<div style={toolbarStyle}>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={() => setPinMode((v) => !v)}\n\t\t\t\t\tstyle={pinMode ? toolbarButtonActiveStyle : toolbarButtonStyle}\n\t\t\t\t>\n\t\t\t\t\t{pinMode ? \"Cancel\" : \"Add comment\"}\n\t\t\t\t</button>\n\t\t\t\t<button type=\"button\" onClick={() => setSidebarOpen((v) => !v)} style={toolbarButtonGhostStyle}>\n\t\t\t\t\t{sidebarOpen ? \"Hide list\" : `List (${session.comments.length})`}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={finalizeSession}\n\t\t\t\t\tdisabled={finalizing}\n\t\t\t\t\tstyle={toolbarButtonFinalizeStyle}\n\t\t\t\t>\n\t\t\t\t\t{finalizing ? \"Finalizing…\" : \"Finalize\"}\n\t\t\t\t</button>\n\t\t\t\t<span style={toolbarHintStyle}>\n\t\t\t\t\t{pinMode ? \"Click any element to comment\" : `${visiblePins.length} on this page`}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction SubmittedPanel({\n\tprogress,\n\teta: etaIso,\n\tstatus,\n}: {\n\tprogress: ReviewProgress;\n\teta: string;\n\tstatus: SessionStatus;\n}) {\n\t// Re-render every minute so the relative ETA label stays fresh between\n\t// the 10s data polls (which only re-render when the API payload changes).\n\tconst [, setTick] = useState(0);\n\tuseEffect(() => {\n\t\tconst id = window.setInterval(() => setTick((t) => t + 1), 60_000);\n\t\treturn () => window.clearInterval(id);\n\t}, []);\n\n\tconst eta = formatEta(etaIso);\n\tconst isInReview = status === \"in_review\";\n\tconst headline = isInReview ? \"Feedback under review\" : \"Applying feedback\";\n\n\treturn (\n\t\t<div style={submittedPanelStyle}>\n\t\t\t<style>{spinnerKeyframes}</style>\n\t\t\t<div style={submittedHeaderStyle}>\n\t\t\t\t<Spinner />\n\t\t\t\t<span style={submittedBadgeStyle}>Submitted</span>\n\t\t\t\t<strong style={{ fontSize: 13 }}>{headline}</strong>\n\t\t\t</div>\n\t\t\t<div style={submittedProgressLabelStyle}>\n\t\t\t\t<span>Review progress</span>\n\t\t\t\t<span style={{ opacity: 0.7 }}>{progress.label}</span>\n\t\t\t</div>\n\t\t\t<div style={submittedProgressTrackStyle}>\n\t\t\t\t<div style={{ ...submittedProgressFillStyle, width: `${progress.fillPct}%` }} />\n\t\t\t</div>\n\t\t\t<p style={submittedEtaStyle}>\n\t\t\t\tEstimated delivery: <span style={{ fontWeight: 600 }}>{eta}</span>\n\t\t\t</p>\n\t\t</div>\n\t);\n}\n\n// Inline keyframes — toolbar avoids relying on a global stylesheet.\nconst spinnerKeyframes = `@keyframes yns-feedback-spin { to { transform: rotate(360deg); } }`;\n\nfunction Spinner({ size = 14 }: { size?: number }) {\n\treturn (\n\t\t<span\n\t\t\taria-hidden\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"inline-block\",\n\t\t\t\twidth: size,\n\t\t\t\theight: size,\n\t\t\t\tborder: \"2px solid rgba(16, 185, 129, 0.25)\",\n\t\t\t\tborderTopColor: \"#10b981\",\n\t\t\t\tborderRadius: 999,\n\t\t\t\tanimation: \"yns-feedback-spin 0.9s linear infinite\",\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction PinOverlay({\n\tpin,\n\tnumber,\n\tediting,\n\tfeedbackSessionId,\n\tapiBase,\n\tonStartEdit,\n\tonCancelEdit,\n\tonSave,\n\tonRemove,\n}: {\n\tpin: FeedbackComment;\n\tnumber: number;\n\tediting: boolean;\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonStartEdit: () => void;\n\tonCancelEdit: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n\tonRemove: () => Promise<void>;\n}) {\n\tconst target = useTargetPosition(pin.cssSelector, pin.offsetXRatio, pin.offsetYRatio);\n\tif (!target) return null;\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tposition: \"absolute\",\n\t\t\t\ttop: target.top,\n\t\t\t\tleft: target.left,\n\t\t\t\tzIndex: 2147483600,\n\t\t\t\tpointerEvents: \"auto\",\n\t\t\t}}\n\t\t>\n\t\t\t<button type=\"button\" onClick={onStartEdit} style={pinDotStyle} title={pin.content}>\n\t\t\t\t{number}\n\t\t\t</button>\n\t\t\t{editing && (\n\t\t\t\t<EditPopover\n\t\t\t\t\tinitial={pin.content}\n\t\t\t\t\tinitialAttachments={pin.attachments}\n\t\t\t\t\tfeedbackSessionId={feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase}\n\t\t\t\t\tonCancel={onCancelEdit}\n\t\t\t\t\tonSave={onSave}\n\t\t\t\t\tonRemove={onRemove}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction PendingCommentPopover({\n\tpending,\n\tfeedbackSessionId,\n\tapiBase,\n\tonCancel,\n\tonSave,\n}: {\n\tpending: PendingPin;\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonCancel: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n}) {\n\treturn (\n\t\t<>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: pending.rect.top + pending.rect.height * pending.offsetYRatio - 12,\n\t\t\t\t\tleft: pending.rect.left + pending.rect.width * pending.offsetXRatio - 12,\n\t\t\t\t\tzIndex: 2147483600,\n\t\t\t\t\tpointerEvents: \"none\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div style={pinDotStyle}>•</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: pending.clickY + 10,\n\t\t\t\t\tleft: pending.clickX + 10,\n\t\t\t\t\tzIndex: 2147483647,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<EditPopover\n\t\t\t\t\tinitial=\"\"\n\t\t\t\t\tinitialAttachments={[]}\n\t\t\t\t\tfeedbackSessionId={feedbackSessionId}\n\t\t\t\t\tapiBase={apiBase}\n\t\t\t\t\tonCancel={onCancel}\n\t\t\t\t\tonSave={onSave}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\nfunction CommentsSidebar({\n\tcomments,\n\tcurrentPath,\n\tonClose,\n\tonSelect,\n}: {\n\tcomments: FeedbackComment[];\n\tcurrentPath: string;\n\tonClose: () => void;\n\tonSelect: (comment: FeedbackComment) => void;\n}) {\n\tconst groups = new Map<string, FeedbackComment[]>();\n\tfor (const c of comments) {\n\t\tconst list = groups.get(c.pagePath) ?? [];\n\t\tlist.push(c);\n\t\tgroups.set(c.pagePath, list);\n\t}\n\tconst paths = Array.from(groups.keys()).sort((a, b) => {\n\t\tif (a === currentPath) return -1;\n\t\tif (b === currentPath) return 1;\n\t\treturn a.localeCompare(b);\n\t});\n\n\treturn (\n\t\t<div style={sidebarStyle}>\n\t\t\t<div style={sidebarHeaderStyle}>\n\t\t\t\t<strong style={{ fontSize: 14 }}>Comments ({comments.length})</strong>\n\t\t\t\t<button type=\"button\" onClick={onClose} style={ghostButtonStyle}>\n\t\t\t\t\tClose\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div style={sidebarScrollStyle}>\n\t\t\t\t{comments.length === 0 ? (\n\t\t\t\t\t<div style={sidebarEmptyStyle}>No comments yet. Click “Add comment” to leave one.</div>\n\t\t\t\t) : (\n\t\t\t\t\tpaths.map((path) => (\n\t\t\t\t\t\t<div key={path} style={{ marginBottom: 12 }}>\n\t\t\t\t\t\t\t<div style={sidebarPathStyle}>{path === currentPath ? `${path} · current` : path}</div>\n\t\t\t\t\t\t\t{(groups.get(path) ?? []).map((c, idx) => (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tkey={c.id}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tonClick={() => onSelect(c)}\n\t\t\t\t\t\t\t\t\tstyle={sidebarItemStyle}\n\t\t\t\t\t\t\t\t\tdisabled={c.status === \"done\" && false}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span style={sidebarItemIndexStyle}>{idx + 1}</span>\n\t\t\t\t\t\t\t\t\t<span style={sidebarItemTextStyle}>\n\t\t\t\t\t\t\t\t\t\t{c.content.length > 140 ? `${c.content.slice(0, 140)}…` : c.content}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{c.status === \"done\" && <span style={sidebarItemDoneStyle}>done</span>}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nconst MAX_ATTACHMENTS = 5;\nconst MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;\n\nconst readImageDimensions = (file: File): Promise<{ width: number; height: number } | null> =>\n\tnew Promise((resolve) => {\n\t\tconst url = URL.createObjectURL(file);\n\t\tconst img = new window.Image();\n\t\timg.onload = () => {\n\t\t\tURL.revokeObjectURL(url);\n\t\t\tresolve({ width: img.naturalWidth, height: img.naturalHeight });\n\t\t};\n\t\timg.onerror = () => {\n\t\t\tURL.revokeObjectURL(url);\n\t\t\tresolve(null);\n\t\t};\n\t\timg.src = url;\n\t});\n\nfunction EditPopover({\n\tinitial,\n\tinitialAttachments,\n\tfeedbackSessionId,\n\tapiBase,\n\tonCancel,\n\tonSave,\n\tonRemove,\n}: {\n\tinitial: string;\n\tinitialAttachments: FeedbackAttachment[];\n\tfeedbackSessionId: string;\n\tapiBase: string | null;\n\tonCancel: () => void;\n\tonSave: (content: string, attachments: FeedbackAttachment[]) => Promise<void>;\n\tonRemove?: () => Promise<void>;\n}) {\n\tconst [value, setValue] = useState(initial);\n\tconst [attachments, setAttachments] = useState<FeedbackAttachment[]>(initialAttachments);\n\tconst [saving, setSaving] = useState(false);\n\tconst [uploading, setUploading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\tconst fileInputRef = useRef<HTMLInputElement | null>(null);\n\n\tuseEffect(() => {\n\t\tconst el = textareaRef.current;\n\t\tif (!el) return;\n\t\tel.focus();\n\t\tconst len = el.value.length;\n\t\tel.setSelectionRange(len, len);\n\t}, []);\n\n\tconst handleSubmit = async (e: FormEvent) => {\n\t\te.preventDefault();\n\t\tconst content = value.trim();\n\t\tif (!content) return;\n\t\tsetSaving(true);\n\t\ttry {\n\t\t\tawait onSave(content, attachments);\n\t\t} finally {\n\t\t\tsetSaving(false);\n\t\t}\n\t};\n\n\tconst handleFiles = async (files: FileList | null) => {\n\t\tif (!files || files.length === 0 || !apiBase) return;\n\t\tsetError(null);\n\t\tconst slots = MAX_ATTACHMENTS - attachments.length;\n\t\tif (slots <= 0) {\n\t\t\tsetError(`Max ${MAX_ATTACHMENTS} images per comment`);\n\t\t\treturn;\n\t\t}\n\t\tconst picked = Array.from(files).slice(0, slots);\n\t\tfor (const f of picked) {\n\t\t\tif (!f.type.startsWith(\"image/\")) {\n\t\t\t\tsetError(`\"${f.name}\" is not an image`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (f.size > MAX_ATTACHMENT_BYTES) {\n\t\t\t\tsetError(`\"${f.name}\" exceeds 5 MB`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tsetUploading(true);\n\t\ttry {\n\t\t\tconst dims = await Promise.all(picked.map(readImageDimensions));\n\t\t\tconst fd = new FormData();\n\t\t\tpicked.forEach((file, i) => {\n\t\t\t\tfd.append(\"file\", file);\n\t\t\t\tfd.append(\"width\", dims[i]?.width ? String(dims[i]?.width) : \"\");\n\t\t\t\tfd.append(\"height\", dims[i]?.height ? String(dims[i]?.height) : \"\");\n\t\t\t});\n\t\t\tconst res = await fetch(\n\t\t\t\t`${apiBase}/api/feedback-comments/uploads?feedbackSessionId=${encodeURIComponent(feedbackSessionId)}`,\n\t\t\t\t{ method: \"POST\", credentials: \"include\", body: fd },\n\t\t\t);\n\t\t\tif (!res.ok) {\n\t\t\t\tconst body = (await res.json().catch(() => null)) as { error?: string } | null;\n\t\t\t\tsetError(body?.error ?? \"Upload failed\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst body = (await res.json()) as { uploads: FeedbackAttachment[] };\n\t\t\tsetAttachments((prev) => [...prev, ...body.uploads]);\n\t\t} catch {\n\t\t\tsetError(\"Upload failed\");\n\t\t} finally {\n\t\t\tsetUploading(false);\n\t\t\tif (fileInputRef.current) fileInputRef.current.value = \"\";\n\t\t}\n\t};\n\n\tconst removeAttachment = (url: string) => {\n\t\tsetAttachments((prev) => prev.filter((a) => a.url !== url));\n\t};\n\n\treturn (\n\t\t<form onSubmit={handleSubmit} style={popoverStyle}>\n\t\t\t<textarea\n\t\t\t\tref={textareaRef}\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => setValue(e.target.value)}\n\t\t\t\tplaceholder=\"Leave a comment…\"\n\t\t\t\tstyle={textareaStyle}\n\t\t\t\trows={3}\n\t\t\t/>\n\t\t\t{attachments.length > 0 && (\n\t\t\t\t<div style={attachmentRowStyle}>\n\t\t\t\t\t{attachments.map((att) => (\n\t\t\t\t\t\t<div key={att.url} style={attachmentThumbWrapStyle}>\n\t\t\t\t\t\t\t<img src={att.url} alt=\"\" style={attachmentThumbStyle} />\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => removeAttachment(att.url)}\n\t\t\t\t\t\t\t\tstyle={attachmentRemoveStyle}\n\t\t\t\t\t\t\t\tdisabled={saving || uploading}\n\t\t\t\t\t\t\t\taria-label=\"Remove attachment\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t×\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t{error && <div style={errorTextStyle}>{error}</div>}\n\t\t\t<input\n\t\t\t\tref={fileInputRef}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept=\"image/*\"\n\t\t\t\tmultiple\n\t\t\t\tonChange={(e) => void handleFiles(e.target.files)}\n\t\t\t\tstyle={{ display: \"none\" }}\n\t\t\t/>\n\t\t\t<div style={popoverActionsStyle}>\n\t\t\t\t{onRemove && (\n\t\t\t\t\t<button type=\"button\" onClick={() => onRemove()} style={dangerButtonStyle} disabled={saving}>\n\t\t\t\t\t\tDelete\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonClick={() => fileInputRef.current?.click()}\n\t\t\t\t\tstyle={attachIconButtonStyle}\n\t\t\t\t\tdisabled={saving || uploading || attachments.length >= MAX_ATTACHMENTS}\n\t\t\t\t\taria-label={uploading ? \"Uploading…\" : \"Attach image\"}\n\t\t\t\t\ttitle={uploading ? \"Uploading…\" : \"Attach image\"}\n\t\t\t\t>\n\t\t\t\t\t{uploading ? <SpinnerGlyph /> : <PaperclipGlyph />}\n\t\t\t\t</button>\n\t\t\t\t<div style={{ flex: 1 }} />\n\t\t\t\t<button type=\"button\" onClick={onCancel} style={ghostButtonStyle} disabled={saving}>\n\t\t\t\t\tCancel\n\t\t\t\t</button>\n\t\t\t\t<button type=\"submit\" style={primaryButtonStyle} disabled={saving || uploading || !value.trim()}>\n\t\t\t\t\t{saving ? \"Saving…\" : \"Save\"}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</form>\n\t);\n}\n\nfunction useTargetPosition(selector: string, offsetXRatio: number, offsetYRatio: number) {\n\tconst [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n\tuseEffect(() => {\n\t\tconst update = () => {\n\t\t\tlet el: Element | null = null;\n\t\t\ttry {\n\t\t\t\tel = document.querySelector(selector);\n\t\t\t} catch {\n\t\t\t\tel = null;\n\t\t\t}\n\t\t\tif (!el) {\n\t\t\t\tsetPos(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst r = el.getBoundingClientRect();\n\t\t\tsetPos({\n\t\t\t\ttop: r.top + window.scrollY + r.height * offsetYRatio - 12,\n\t\t\t\tleft: r.left + window.scrollX + r.width * offsetXRatio - 12,\n\t\t\t});\n\t\t};\n\n\t\tupdate();\n\t\tconst ro = new ResizeObserver(update);\n\t\ttry {\n\t\t\tconst el = document.querySelector(selector);\n\t\t\tif (el) ro.observe(el);\n\t\t} catch {\n\t\t\t// swallow invalid selector\n\t\t}\n\t\twindow.addEventListener(\"scroll\", update, true);\n\t\twindow.addEventListener(\"resize\", update);\n\t\treturn () => {\n\t\t\tro.disconnect();\n\t\t\twindow.removeEventListener(\"scroll\", update, true);\n\t\t\twindow.removeEventListener(\"resize\", update);\n\t\t};\n\t}, [selector, offsetXRatio, offsetYRatio]);\n\n\treturn pos;\n}\n\n// Inline styles — toolbar is injected into arbitrary stores, so we avoid relying\n// on any CSS framework being present.\nconst toolbarStyle: CSSProperties = {\n\tposition: \"fixed\",\n\tbottom: 16,\n\tleft: \"50%\",\n\ttransform: \"translateX(-50%)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 8,\n\tpadding: \"8px 12px\",\n\tbackground: \"rgba(17, 17, 17, 0.92)\",\n\tcolor: \"white\",\n\tborderRadius: 999,\n\tboxShadow: \"0 8px 24px rgba(0,0,0,0.25)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tfontSize: 14,\n\tpointerEvents: \"auto\",\n};\n\nconst toolbarButtonStyle: CSSProperties = {\n\tborder: \"none\",\n\tbackground: \"white\",\n\tcolor: \"#111\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 600,\n\tfontSize: 13,\n};\n\nconst toolbarButtonActiveStyle: CSSProperties = {\n\t...toolbarButtonStyle,\n\tbackground: \"#ef4444\",\n\tcolor: \"white\",\n};\n\nconst toolbarButtonGhostStyle: CSSProperties = {\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"transparent\",\n\tcolor: \"white\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 500,\n\tfontSize: 13,\n};\n\nconst toolbarButtonFinalizeStyle: CSSProperties = {\n\tborder: \"none\",\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tpadding: \"6px 12px\",\n\tborderRadius: 999,\n\tcursor: \"pointer\",\n\tfontWeight: 600,\n\tfontSize: 13,\n};\n\nconst toolbarHintStyle: CSSProperties = {\n\topacity: 0.8,\n\tfontSize: 12,\n};\n\nconst pinDotStyle: CSSProperties = {\n\twidth: 24,\n\theight: 24,\n\tborderRadius: 999,\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tborder: \"2px solid white\",\n\tcursor: \"pointer\",\n\tfontSize: 12,\n\tfontWeight: 700,\n\tboxShadow: \"0 2px 6px rgba(0,0,0,0.3)\",\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\tpadding: 0,\n};\n\nconst popoverStyle: CSSProperties = {\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 8,\n\tpadding: 12,\n\twidth: 280,\n\tboxShadow: \"0 12px 32px rgba(0,0,0,0.18)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: 8,\n\tcolor: \"#111\",\n};\n\nconst textareaStyle: CSSProperties = {\n\twidth: \"100%\",\n\tborder: \"1px solid #d1d5db\",\n\tborderRadius: 6,\n\tpadding: 8,\n\tfontSize: 14,\n\tresize: \"vertical\",\n\tfontFamily: \"inherit\",\n\tcolor: \"#111\",\n\tbackground: \"white\",\n\tboxSizing: \"border-box\",\n};\n\nconst popoverActionsStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 6,\n};\n\nconst baseButton: CSSProperties = {\n\tborder: \"1px solid transparent\",\n\tborderRadius: 6,\n\tpadding: \"6px 10px\",\n\tfontSize: 13,\n\tcursor: \"pointer\",\n\tfontWeight: 500,\n};\n\nconst primaryButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"#111\",\n\tcolor: \"white\",\n};\n\nconst ghostButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"transparent\",\n\tcolor: \"#374151\",\n\tborderColor: \"#d1d5db\",\n};\n\nconst dangerButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"transparent\",\n\tcolor: \"#b91c1c\",\n\tborderColor: \"#fecaca\",\n};\n\nconst attachmentRowStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\tflexWrap: \"wrap\",\n\tgap: 6,\n};\n\nconst attachmentThumbWrapStyle: CSSProperties = {\n\tposition: \"relative\",\n\twidth: 56,\n\theight: 56,\n\tborderRadius: 6,\n\toverflow: \"hidden\",\n\tborder: \"1px solid #e5e7eb\",\n\tbackground: \"#f9fafb\",\n};\n\nconst attachmentThumbStyle: CSSProperties = {\n\twidth: \"100%\",\n\theight: \"100%\",\n\tobjectFit: \"cover\",\n\tdisplay: \"block\",\n};\n\nconst attachmentRemoveStyle: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 2,\n\tright: 2,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"none\",\n\tbackground: \"rgba(17, 17, 17, 0.85)\",\n\tcolor: \"white\",\n\tfontSize: 13,\n\tlineHeight: \"16px\",\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nconst errorTextStyle: CSSProperties = {\n\tcolor: \"#b91c1c\",\n\tfontSize: 12,\n\tmargin: 0,\n};\n\nconst attachIconButtonStyle: CSSProperties = {\n\t...baseButton,\n\tbackground: \"transparent\",\n\tcolor: \"#374151\",\n\tborderColor: \"#d1d5db\",\n\twidth: 30,\n\theight: 30,\n\tpadding: 0,\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\tflexShrink: 0,\n};\n\nfunction PaperclipGlyph() {\n\treturn (\n\t\t<svg\n\t\t\trole=\"img\"\n\t\t\taria-label=\"Attach image\"\n\t\t\twidth=\"14\"\n\t\t\theight=\"14\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<title>Attach image</title>\n\t\t\t<path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 17.93 8.83l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\n\t\t</svg>\n\t);\n}\n\nfunction SpinnerGlyph() {\n\treturn (\n\t\t<>\n\t\t\t<style>{`@keyframes yns-attach-spin { to { transform: rotate(360deg); } }`}</style>\n\t\t\t<span\n\t\t\t\taria-hidden\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"inline-block\",\n\t\t\t\t\twidth: 12,\n\t\t\t\t\theight: 12,\n\t\t\t\t\tborder: \"2px solid rgba(55, 65, 81, 0.25)\",\n\t\t\t\t\tborderTopColor: \"#374151\",\n\t\t\t\t\tborderRadius: 999,\n\t\t\t\t\tanimation: \"yns-attach-spin 0.9s linear infinite\",\n\t\t\t\t}}\n\t\t\t/>\n\t\t</>\n\t);\n}\n\nconst sidebarStyle: CSSProperties = {\n\tposition: \"fixed\",\n\ttop: 0,\n\tright: 0,\n\tbottom: 0,\n\twidth: 360,\n\tmaxWidth: \"92vw\",\n\tbackground: \"white\",\n\tborderLeft: \"1px solid #e5e7eb\",\n\tboxShadow: \"-12px 0 32px rgba(0,0,0,0.12)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tcolor: \"#111\",\n};\n\nconst sidebarHeaderStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"space-between\",\n\tpadding: \"12px 16px\",\n\tborderBottom: \"1px solid #e5e7eb\",\n};\n\nconst sidebarScrollStyle: CSSProperties = {\n\tflex: 1,\n\toverflow: \"auto\",\n\tpadding: \"12px 12px 24px\",\n};\n\nconst sidebarEmptyStyle: CSSProperties = {\n\tcolor: \"#6b7280\",\n\tfontSize: 13,\n\tpadding: \"24px 8px\",\n\ttextAlign: \"center\",\n};\n\nconst sidebarPathStyle: CSSProperties = {\n\tfontSize: 11,\n\ttextTransform: \"uppercase\",\n\tletterSpacing: 0.5,\n\tcolor: \"#6b7280\",\n\tpadding: \"4px 4px 6px\",\n\twordBreak: \"break-all\",\n};\n\nconst sidebarItemStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"flex-start\",\n\tgap: 8,\n\twidth: \"100%\",\n\ttextAlign: \"left\",\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 6,\n\tpadding: \"8px 10px\",\n\tcursor: \"pointer\",\n\tfontSize: 13,\n\tmarginBottom: 6,\n\tcolor: \"#111\",\n};\n\nconst sidebarItemIndexStyle: CSSProperties = {\n\tflexShrink: 0,\n\twidth: 22,\n\theight: 22,\n\tborderRadius: 999,\n\tbackground: \"#10b981\",\n\tcolor: \"white\",\n\tfontWeight: 700,\n\tfontSize: 11,\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nconst sidebarItemTextStyle: CSSProperties = {\n\tflex: 1,\n\twhiteSpace: \"pre-wrap\",\n\twordBreak: \"break-word\",\n};\n\nconst sidebarItemDoneStyle: CSSProperties = {\n\tflexShrink: 0,\n\tbackground: \"#d1fae5\",\n\tcolor: \"#065f46\",\n\tfontSize: 11,\n\tfontWeight: 600,\n\tpadding: \"2px 6px\",\n\tborderRadius: 4,\n\talignSelf: \"center\",\n};\n\nconst submittedPanelStyle: CSSProperties = {\n\tposition: \"fixed\",\n\tbottom: 16,\n\tleft: \"50%\",\n\ttransform: \"translateX(-50%)\",\n\tzIndex: 2147483646,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: 8,\n\tpadding: \"12px 16px\",\n\twidth: \"min(420px, calc(100vw - 32px))\",\n\tbackground: \"white\",\n\tborder: \"1px solid #e5e7eb\",\n\tborderRadius: 12,\n\tboxShadow: \"0 12px 32px rgba(0,0,0,0.18)\",\n\tfontFamily:\n\t\t'-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n\tcolor: \"#111\",\n\tpointerEvents: \"auto\",\n};\n\nconst submittedHeaderStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tgap: 8,\n};\n\nconst submittedBadgeStyle: CSSProperties = {\n\tbackground: \"#d1fae5\",\n\tcolor: \"#065f46\",\n\tfontSize: 11,\n\tfontWeight: 700,\n\tpadding: \"2px 8px\",\n\tborderRadius: 999,\n\ttextTransform: \"uppercase\",\n\tletterSpacing: 0.5,\n};\n\nconst submittedProgressLabelStyle: CSSProperties = {\n\tdisplay: \"flex\",\n\tjustifyContent: \"space-between\",\n\tfontSize: 12,\n};\n\nconst submittedProgressTrackStyle: CSSProperties = {\n\twidth: \"100%\",\n\theight: 6,\n\tbackground: \"#f3f4f6\",\n\tborderRadius: 999,\n\toverflow: \"hidden\",\n};\n\nconst submittedProgressFillStyle: CSSProperties = {\n\theight: \"100%\",\n\tbackground: \"#10b981\",\n\tborderRadius: 999,\n\ttransition: \"width 500ms\",\n};\n\nconst submittedEtaStyle: CSSProperties = {\n\tmargin: 0,\n\tfontSize: 12,\n\tcolor: \"#6b7280\",\n};\n\nexport function mountFeedbackToolbar(): { unmount: () => void } | null {\n\tconsole.log(\"[YNS Feedback Toolbar] mountFeedbackToolbar() called\", {\n\t\tisWindow: typeof window !== \"undefined\",\n\t\tvercelEnv: process.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\talreadyMounted: typeof document !== \"undefined\" && Boolean(document.getElementById(MOUNT_NODE_ID)),\n\t});\n\tif (typeof window === \"undefined\") return null;\n\tif (process.env.NEXT_PUBLIC_VERCEL_ENV !== \"preview\") {\n\t\tconsole.log(\n\t\t\t\"[YNS Feedback Toolbar] gate failed — NEXT_PUBLIC_VERCEL_ENV is\",\n\t\t\tprocess.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\t);\n\t\treturn null;\n\t}\n\tif (document.getElementById(MOUNT_NODE_ID)) return null;\n\n\tconst container = document.createElement(\"div\");\n\tcontainer.id = MOUNT_NODE_ID;\n\tcontainer.dataset.ynsFeedbackUi = \"true\";\n\tdocument.body.appendChild(container);\n\n\tconst root = createRoot(container);\n\troot.render(<FeedbackToolbar />);\n\n\treturn {\n\t\tunmount: () => {\n\t\t\troot.unmount();\n\t\t\tcontainer.remove();\n\t\t},\n\t};\n}\n\n// Auto-mount on import. Wait for DOM ready.\nif (typeof window !== \"undefined\") {\n\tconsole.log(\"[YNS Feedback Toolbar] module evaluated\", {\n\t\tvercelEnv: process.env.NEXT_PUBLIC_VERCEL_ENV,\n\t\treadyState: document.readyState,\n\t\twillAutoMount: process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\",\n\t});\n}\nif (typeof window !== \"undefined\" && process.env.NEXT_PUBLIC_VERCEL_ENV === \"preview\") {\n\tif (document.readyState === \"loading\") {\n\t\tdocument.addEventListener(\"DOMContentLoaded\", () => {\n\t\t\tmountFeedbackToolbar();\n\t\t});\n\t} else {\n\t\tmountFeedbackToolbar();\n\t}\n}\n","/**\n * Sandbox Inspectors — side-effect entry.\n *\n * Auto-mounts the design-mode + comment-mode inspectors inside per-store\n * storefronts running under the AI Builder sandbox dev server. Communicates\n * with the parent /design iframe via postMessage.\n *\n * Always-on: inspectors are passive postMessage listeners and don't affect the\n * page until the AI Builder iframe sends a `*-mode-toggle` message. Gating on\n * NODE_ENV is wrong (always \"production\" on Vercel) and any build-time gate\n * gets folded out by the commerce-kit bundle, leaving an empty file.\n */\n\n/**\n * Exported so `browser.tsx` can `export { startSandboxInspectors }` — the\n * named binding anchors this module against esbuild tree-shaking when\n * commerce-kit is bundled. Without it, an `export * from \"./sandbox-inspectors\"`\n * re-exports an empty binding set and esbuild DCEs the whole file.\n */\nexport function startSandboxInspectors(): void {\n\tif (typeof window === \"undefined\") return;\n\tconsole.log(\"[YNS Sandbox Inspectors] module evaluated\");\n\tinitDesignModeInspector();\n\tinitCommentModeInspector();\n}\n\n// Auto-start on import.\nstartSandboxInspectors();\n\ninterface ElementInfo {\n\ttag: string;\n\tid: string | undefined;\n\tclasses: string[];\n\ttextContent: string;\n\tcssSelector: string;\n\tboundingRect: { top: number; left: number; width: number; height: number };\n\tcomputedStyles: Partial<{\n\t\tcolor: string;\n\t\tbackgroundColor: string;\n\t\tfontSize: string;\n\t\tfontFamily: string;\n\t\tpadding: string;\n\t\tmargin: string;\n\t}>;\n}\n\nconst IGNORED_TAGS = new Set([\"HEAD\", \"SCRIPT\", \"STYLE\", \"NOSCRIPT\", \"HTML\"]);\n\nfunction generateCssSelector(el: Element): string {\n\tif (el.id) return `${el.tagName.toLowerCase()}#${CSS.escape(el.id)}`;\n\n\tconst parts: string[] = [];\n\tlet current: Element | null = el;\n\twhile (current && current !== document.body && current !== document.documentElement) {\n\t\tlet selector = current.tagName.toLowerCase();\n\n\t\tif (current.id) {\n\t\t\tparts.unshift(`${selector}#${CSS.escape(current.id)}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst classes = Array.from(current.classList).filter((c) => !c.startsWith(\"data-yns-\"));\n\t\tif (classes.length > 0) {\n\t\t\tselector += `.${classes.map((c) => CSS.escape(c)).join(\".\")}`;\n\t\t}\n\n\t\tconst parent: Element | null = current.parentElement;\n\t\tconst tag = current.tagName;\n\t\tif (parent) {\n\t\t\tconst siblings = Array.from(parent.children).filter(\n\t\t\t\t(s) => s.tagName === tag && (classes.length === 0 || classes.every((c) => s.classList.contains(c))),\n\t\t\t);\n\t\t\tif (siblings.length > 1) {\n\t\t\t\tconst index = Array.from(parent.children).indexOf(current) + 1;\n\t\t\t\tselector += `:nth-child(${index})`;\n\t\t\t}\n\t\t}\n\n\t\tparts.unshift(selector);\n\t\tcurrent = current.parentElement;\n\t}\n\treturn parts.join(\" > \");\n}\n\nfunction buildElementInfo(el: Element, textLimit: number): ElementInfo {\n\tconst rect = el.getBoundingClientRect();\n\tconst computed = window.getComputedStyle(el);\n\tconst text = (el.textContent ?? \"\").trim();\n\treturn {\n\t\ttag: el.tagName.toLowerCase(),\n\t\tid: el.id || undefined,\n\t\tclasses: Array.from(el.classList).filter((c) => !c.startsWith(\"data-yns-\")),\n\t\ttextContent: text.length > textLimit ? `${text.slice(0, textLimit)}…` : text,\n\t\tcssSelector: generateCssSelector(el),\n\t\tboundingRect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },\n\t\tcomputedStyles: {\n\t\t\tcolor: computed.color,\n\t\t\tbackgroundColor: computed.backgroundColor,\n\t\t\tfontSize: computed.fontSize,\n\t\t\tfontFamily: computed.fontFamily,\n\t\t\tpadding: computed.padding,\n\t\t\tmargin: computed.margin,\n\t\t},\n\t};\n}\n\nfunction shouldIgnore(el: Element | null, overlayAttrs: string[]): el is null {\n\tif (!el || !el.tagName) return true;\n\tif (IGNORED_TAGS.has(el.tagName)) return true;\n\tfor (const attr of overlayAttrs) {\n\t\tif (el.hasAttribute?.(attr)) return true;\n\t}\n\treturn false;\n}\n\nfunction initDesignModeInspector() {\n\tlet enabled = false;\n\tlet hoveredElement: Element | null = null;\n\tlet selectedElement: { el: Element; cssSelector: string } | null = null;\n\n\tconst overlay = document.createElement(\"div\");\n\toverlay.setAttribute(\"data-yns-design-overlay\", \"hover\");\n\toverlay.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483646\",\n\t\t\"border: 2px solid #3b82f6\",\n\t\t\"background: rgba(59, 130, 246, 0.08)\",\n\t\t\"border-radius: 3px\",\n\t\t\"display: none\",\n\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t].join(\";\");\n\n\tconst label = document.createElement(\"div\");\n\tlabel.setAttribute(\"data-yns-design-overlay\", \"label\");\n\tlabel.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483647\",\n\t\t\"background: #3b82f6\",\n\t\t\"color: #fff\",\n\t\t\"font-size: 11px\",\n\t\t\"font-family: ui-monospace, monospace\",\n\t\t\"padding: 2px 6px\",\n\t\t\"border-radius: 3px\",\n\t\t\"white-space: nowrap\",\n\t\t\"display: none\",\n\t].join(\";\");\n\n\tdocument.documentElement.appendChild(overlay);\n\tdocument.documentElement.appendChild(label);\n\n\tconst style = document.createElement(\"style\");\n\tstyle.setAttribute(\"data-yns-design-overlay\", \"style\");\n\tstyle.textContent = \"[data-yns-selected] { outline: 2px solid #3b82f6 !important; outline-offset: 1px; }\";\n\tdocument.head.appendChild(style);\n\n\tfunction positionOverlay(el: Element) {\n\t\tconst rect = el.getBoundingClientRect();\n\t\toverlay.style.top = `${rect.top}px`;\n\t\toverlay.style.left = `${rect.left}px`;\n\t\toverlay.style.width = `${rect.width}px`;\n\t\toverlay.style.height = `${rect.height}px`;\n\t\toverlay.style.display = \"block\";\n\n\t\tconst classes = Array.from(el.classList).filter((c) => !c.startsWith(\"data-yns-\"));\n\t\tconst labelText = el.tagName.toLowerCase() + (classes.length ? `.${classes[0]}` : \"\");\n\t\tlabel.textContent = labelText;\n\t\tlabel.style.left = `${rect.left}px`;\n\t\tlabel.style.top = `${Math.max(0, rect.top - 22)}px`;\n\t\tlabel.style.display = \"block\";\n\t}\n\n\tconst handleMouseMove = (e: MouseEvent) => {\n\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\tif (shouldIgnore(el, [\"data-yns-design-overlay\"])) {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tlabel.style.display = \"none\";\n\t\t\thoveredElement = null;\n\t\t\treturn;\n\t\t}\n\t\thoveredElement = el;\n\t\trequestAnimationFrame(() => {\n\t\t\tif (hoveredElement === el && enabled && el) {\n\t\t\t\tpositionOverlay(el);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst handleMouseLeave = () => {\n\t\toverlay.style.display = \"none\";\n\t\tlabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t};\n\n\tconst handleClick = (e: MouseEvent) => {\n\t\tif (!enabled || !hoveredElement) return;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\te.stopImmediatePropagation();\n\n\t\tconst el = hoveredElement;\n\t\tif (shouldIgnore(el, [\"data-yns-design-overlay\"])) return;\n\n\t\tconst info = buildElementInfo(el, 120);\n\t\tconst selector = info.cssSelector;\n\n\t\tif (selectedElement) {\n\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t}\n\n\t\tif (selectedElement && selectedElement.cssSelector === selector) {\n\t\t\tselectedElement = null;\n\t\t\twindow.parent.postMessage({ type: \"element-deselected\", data: info }, \"*\");\n\t\t} else {\n\t\t\tselectedElement = { el, cssSelector: selector };\n\t\t\tel.setAttribute(\"data-yns-selected\", \"\");\n\t\t\twindow.parent.postMessage({ type: \"element-selected\", data: info }, \"*\");\n\t\t}\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key === \"Escape\" && enabled) {\n\t\t\tdisableDesignMode();\n\t\t\twindow.parent.postMessage({ type: \"design-mode-cleared\" }, \"*\");\n\t\t}\n\t};\n\n\tfunction enableDesignMode() {\n\t\tenabled = true;\n\t\tdocument.addEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.addEventListener(\"click\", handleClick, true);\n\t\tdocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t}\n\n\tfunction disableDesignMode() {\n\t\tenabled = false;\n\t\tdocument.removeEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.removeEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.removeEventListener(\"click\", handleClick, true);\n\t\tdocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\n\t\toverlay.style.display = \"none\";\n\t\tlabel.style.display = \"none\";\n\t\thoveredElement = null;\n\n\t\tif (selectedElement) {\n\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t\tselectedElement = null;\n\t\t}\n\t}\n\n\twindow.addEventListener(\"message\", (event) => {\n\t\tconst msg = event.data;\n\t\tif (!msg || typeof msg !== \"object\") return;\n\n\t\tif (msg.type === \"design-mode-toggle\") {\n\t\t\tif (msg.enabled) {\n\t\t\t\tenableDesignMode();\n\t\t\t} else {\n\t\t\t\tdisableDesignMode();\n\t\t\t\twindow.parent.postMessage({ type: \"design-mode-cleared\" }, \"*\");\n\t\t\t}\n\t\t}\n\n\t\tif (msg.type === \"design-mode-deselect\") {\n\t\t\tif (selectedElement) {\n\t\t\t\tselectedElement.el.removeAttribute(\"data-yns-selected\");\n\t\t\t\tselectedElement = null;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction initCommentModeInspector() {\n\tlet enabled = false;\n\tlet hoveredElement: Element | null = null;\n\tlet pins: Array<{ id: string; selector: string; number: number }> = [];\n\n\tconst overlay = document.createElement(\"div\");\n\toverlay.setAttribute(\"data-yns-comment-overlay\", \"hover\");\n\toverlay.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483644\",\n\t\t\"border: 2px dashed #10b981\",\n\t\t\"background: rgba(16, 185, 129, 0.06)\",\n\t\t\"border-radius: 3px\",\n\t\t\"display: none\",\n\t\t\"transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s\",\n\t].join(\";\");\n\n\tconst cursorLabel = document.createElement(\"div\");\n\tcursorLabel.setAttribute(\"data-yns-comment-overlay\", \"cursor-label\");\n\tcursorLabel.textContent = \"Click to comment\";\n\tcursorLabel.style.cssText = [\n\t\t\"position: fixed\",\n\t\t\"pointer-events: none\",\n\t\t\"z-index: 2147483645\",\n\t\t\"background: #059669\",\n\t\t\"color: #fff\",\n\t\t\"font-size: 11px\",\n\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\"padding: 3px 8px\",\n\t\t\"border-radius: 4px\",\n\t\t\"white-space: nowrap\",\n\t\t\"display: none\",\n\t\t\"box-shadow: 0 2px 6px rgba(0,0,0,0.15)\",\n\t].join(\";\");\n\n\tconst pinContainer = document.createElement(\"div\");\n\tpinContainer.setAttribute(\"data-yns-comment-overlay\", \"pins\");\n\tpinContainer.style.cssText =\n\t\t\"position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2147483643;\";\n\n\tdocument.documentElement.appendChild(overlay);\n\tdocument.documentElement.appendChild(cursorLabel);\n\tdocument.documentElement.appendChild(pinContainer);\n\n\tfunction renderPins() {\n\t\tpinContainer.innerHTML = \"\";\n\t\tfor (const pin of pins) {\n\t\t\tlet el: Element | null = null;\n\t\t\ttry {\n\t\t\t\tel = document.querySelector(pin.selector);\n\t\t\t} catch {\n\t\t\t\tel = null;\n\t\t\t}\n\t\t\tif (!el) continue;\n\n\t\t\tconst r = el.getBoundingClientRect();\n\t\t\tconst pinEl = document.createElement(\"div\");\n\t\t\tpinEl.style.cssText = [\n\t\t\t\t\"position: fixed\",\n\t\t\t\t`top: ${r.top - 12}px`,\n\t\t\t\t`left: ${r.left + r.width / 2 - 12}px`,\n\t\t\t\t\"width: 24px\",\n\t\t\t\t\"height: 24px\",\n\t\t\t\t\"border-radius: 50%\",\n\t\t\t\t\"background: #059669\",\n\t\t\t\t\"color: #fff\",\n\t\t\t\t\"display: flex\",\n\t\t\t\t\"align-items: center\",\n\t\t\t\t\"justify-content: center\",\n\t\t\t\t\"font-size: 12px\",\n\t\t\t\t\"font-weight: 600\",\n\t\t\t\t\"font-family: ui-sans-serif, system-ui, sans-serif\",\n\t\t\t\t\"box-shadow: 0 2px 8px rgba(0,0,0,0.2)\",\n\t\t\t\t\"pointer-events: none\",\n\t\t\t].join(\";\");\n\t\t\tpinEl.textContent = String(pin.number);\n\t\t\tpinContainer.appendChild(pinEl);\n\t\t}\n\t}\n\n\tconst handleMouseMove = (e: MouseEvent) => {\n\t\tconst el = document.elementFromPoint(e.clientX, e.clientY);\n\t\tif (shouldIgnore(el, [\"data-yns-comment-overlay\", \"data-yns-design-overlay\"])) {\n\t\t\toverlay.style.display = \"none\";\n\t\t\tcursorLabel.style.display = \"none\";\n\t\t\thoveredElement = null;\n\t\t\treturn;\n\t\t}\n\t\thoveredElement = el;\n\t\trequestAnimationFrame(() => {\n\t\t\tif (hoveredElement === el && enabled && el) {\n\t\t\t\tconst rect = el.getBoundingClientRect();\n\t\t\t\toverlay.style.top = `${rect.top}px`;\n\t\t\t\toverlay.style.left = `${rect.left}px`;\n\t\t\t\toverlay.style.width = `${rect.width}px`;\n\t\t\t\toverlay.style.height = `${rect.height}px`;\n\t\t\t\toverlay.style.display = \"block\";\n\n\t\t\t\tcursorLabel.style.left = `${e.clientX + 14}px`;\n\t\t\t\tcursorLabel.style.top = `${e.clientY + 14}px`;\n\t\t\t\tcursorLabel.style.display = \"block\";\n\t\t\t}\n\t\t});\n\t};\n\n\tconst handleMouseLeave = () => {\n\t\toverlay.style.display = \"none\";\n\t\tcursorLabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t};\n\n\tconst handleClick = (e: MouseEvent) => {\n\t\tif (!enabled || !hoveredElement) return;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\te.stopImmediatePropagation();\n\n\t\tconst el = hoveredElement;\n\t\tif (shouldIgnore(el, [\"data-yns-comment-overlay\", \"data-yns-design-overlay\"])) return;\n\n\t\tconst info = buildElementInfo(el, 200);\n\t\tconst rect = el.getBoundingClientRect();\n\n\t\twindow.parent.postMessage(\n\t\t\t{\n\t\t\t\ttype: \"comment-click\",\n\t\t\t\tdata: {\n\t\t\t\t\telement: info,\n\t\t\t\t\tclickPosition: { x: e.clientX, y: e.clientY },\n\t\t\t\t\telementRect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },\n\t\t\t\t\tpagePath: window.location.pathname,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"*\",\n\t\t);\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key === \"Escape\" && enabled) {\n\t\t\tdisableCommentMode();\n\t\t\twindow.parent.postMessage({ type: \"comment-mode-cleared\" }, \"*\");\n\t\t}\n\t};\n\n\tfunction enableCommentMode() {\n\t\tenabled = true;\n\t\tdocument.body.style.cursor = \"crosshair\";\n\t\tdocument.addEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.addEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.addEventListener(\"click\", handleClick, true);\n\t\tdocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t}\n\n\tfunction disableCommentMode() {\n\t\tenabled = false;\n\t\tdocument.body.style.cursor = \"\";\n\t\tdocument.removeEventListener(\"mousemove\", handleMouseMove, true);\n\t\tdocument.removeEventListener(\"mouseleave\", handleMouseLeave);\n\t\tdocument.removeEventListener(\"click\", handleClick, true);\n\t\tdocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\n\t\toverlay.style.display = \"none\";\n\t\tcursorLabel.style.display = \"none\";\n\t\thoveredElement = null;\n\t}\n\n\tlet rafPending = false;\n\tconst scheduleRender = () => {\n\t\tif (rafPending) return;\n\t\trafPending = true;\n\t\trequestAnimationFrame(() => {\n\t\t\trafPending = false;\n\t\t\trenderPins();\n\t\t});\n\t};\n\twindow.addEventListener(\"scroll\", scheduleRender, { passive: true });\n\twindow.addEventListener(\"resize\", scheduleRender, { passive: true });\n\n\twindow.addEventListener(\"message\", (event) => {\n\t\tconst msg = event.data;\n\t\tif (!msg || typeof msg !== \"object\") return;\n\n\t\tif (msg.type === \"comment-mode-toggle\") {\n\t\t\tif (msg.enabled) enableCommentMode();\n\t\t\telse disableCommentMode();\n\t\t}\n\n\t\tif (msg.type === \"comment-pins-update\") {\n\t\t\tpins = msg.pins ?? [];\n\t\t\trenderPins();\n\t\t}\n\n\t\tif (msg.type === \"comment-pin-remove\") {\n\t\t\tpins = pins.filter((p) => p.id !== msg.pinId);\n\t\t\trenderPins();\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","createRoot","Fragment","jsx","jsxs","MOUNT_NODE_ID","buildApiBase","override","host","protocol","computeCssSelector","el","path","node","part","className","classes","c","parent","tag","siblings","idx","ATTRS_OF_INTEREST","formatAttrs","parts","attr","v","trimmed","formatTextContent","text","buildSurroundingHtml","target","ancestors","cur","lines","depth","ancestor","indent","targetIndent","targetTag","targetText","childIndent","children","child","childText","i","isInsideToolbar","IGNORED_TAGS","POLL_INTERVAL_MS","formatEta","etaIso","eta","remainingMs","dateLabel","remainingMin","remainingHours","remainingDays","FeedbackToolbar","session","setSession","loading","setLoading","pinMode","setPinMode","pending","setPending","editingId","setEditingId","sidebarOpen","setSidebarOpen","finalizing","setFinalizing","apiBase","cancelled","controller","fetchOnce","res","data","interval","overlay","label","hovered","handleMove","e","rect","handleLeave","handleClick","event","offsetXRatio","offsetYRatio","refreshComments","submitNewComment","content","attachments","updateComment","id","removeComment","finalizeSession","nextStatus","prev","scrollToComment","comment","SubmittedPanel","visiblePins","pin","PinOverlay","PendingCommentPopover","CommentsSidebar","toolbarStyle","toolbarButtonActiveStyle","toolbarButtonStyle","toolbarButtonGhostStyle","toolbarButtonFinalizeStyle","toolbarHintStyle","progress","status","setTick","t","submittedPanelStyle","spinnerKeyframes","submittedHeaderStyle","Spinner","submittedBadgeStyle","submittedProgressLabelStyle","submittedProgressTrackStyle","submittedProgressFillStyle","submittedEtaStyle","size","number","editing","feedbackSessionId","onStartEdit","onCancelEdit","onSave","onRemove","useTargetPosition","pinDotStyle","EditPopover","onCancel","comments","currentPath","onClose","onSelect","groups","list","paths","a","b","sidebarStyle","sidebarHeaderStyle","ghostButtonStyle","sidebarScrollStyle","sidebarEmptyStyle","sidebarPathStyle","sidebarItemStyle","sidebarItemIndexStyle","sidebarItemTextStyle","sidebarItemDoneStyle","MAX_ATTACHMENTS","MAX_ATTACHMENT_BYTES","readImageDimensions","file","resolve","url","img","initial","initialAttachments","value","setValue","setAttachments","saving","setSaving","uploading","setUploading","error","setError","textareaRef","fileInputRef","len","handleSubmit","handleFiles","files","slots","picked","dims","fd","body","removeAttachment","popoverStyle","textareaStyle","attachmentRowStyle","att","attachmentThumbWrapStyle","attachmentThumbStyle","attachmentRemoveStyle","errorTextStyle","popoverActionsStyle","dangerButtonStyle","attachIconButtonStyle","SpinnerGlyph","PaperclipGlyph","primaryButtonStyle","selector","pos","setPos","update","r","ro","baseButton","mountFeedbackToolbar","container","root","startSandboxInspectors","initDesignModeInspector","initCommentModeInspector","IGNORED_TAGS","generateCssSelector","el","parts","current","selector","classes","c","parent","tag","s","index","buildElementInfo","textLimit","rect","computed","text","shouldIgnore","overlayAttrs","attr","enabled","hoveredElement","selectedElement","overlay","label","style","positionOverlay","labelText","handleMouseMove","e","handleMouseLeave","handleClick","info","handleKeyDown","disableDesignMode","enableDesignMode","event","msg","pins","cursorLabel","pinContainer","renderPins","pin","r","pinEl","disableCommentMode","enableCommentMode","rafPending","scheduleRender","p"]}
|