@popgrids/embed 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["getComputedStyle","t"],"sources":["../src/lib/popup-auth.ts","../src/store/auth-store.ts","../src/store/registry.ts","../src/store/grid-store.ts","../src/styles/base.css?inline","../src/styles/buttons.css?inline","../src/styles/masks.css?inline","../src/helpers/theme.ts","../src/components/base-element.ts","../src/components/pop-auth-panel.ts","../src/assets/popgrids-letter-p.png?inline","../src/helpers/color.ts","../src/components/pop-comment-avatar.ts","../src/helpers/author.ts","../src/components/pop-comment-bar.ts","../src/components/pop-comment-icon.ts","../src/components/pop-comment-input.ts","../src/components/pop-comment-thread.ts","../src/helpers/time.ts","../src/components/pop-comment.ts","../src/components/pop-feed.ts","../node_modules/.pnpm/@floating-ui+utils@0.2.11/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs","../node_modules/.pnpm/composed-offset-position@0.0.6_@floating-ui+utils@0.2.11/node_modules/composed-offset-position/dist/composed-offset-position.browser.min.mjs","../src/components/pop-grid.ts","../src/components/pop-widget.ts","../src/index.ts"],"sourcesContent":["import type { AuthUser } from \"../types/models.js\";\n\nexport const EMBED_AUTH_SOURCE = \"popgrids-embed\";\nexport const EMBED_AUTH_SUCCESS = \"popgrids:auth:success\";\nexport const EMBED_AUTH_ERROR = \"popgrids:auth:error\";\n\nexport const EMBED_AUTH_LOGIN_PATH = \"/embed/auth/login\";\nexport const POPUP_NAME = \"popgrids-auth\";\nexport const POPUP_FEATURES = \"popup,width=480,height=640\";\nexport const AUTH_TIMEOUT_MS = 5 * 60 * 1000;\n\nconst POPUP_CLOSE_GRACE_MS = 250;\n\nexport class PopupAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PopupAuthError\";\n }\n}\n\nexport const buildEmbedLoginUrl = (\n apiUrl: string,\n publicKey: string,\n returnOrigin: string,\n) => {\n const url = new URL(EMBED_AUTH_LOGIN_PATH, apiUrl);\n url.searchParams.set(\"publicKey\", publicKey);\n url.searchParams.set(\"returnOrigin\", returnOrigin);\n return url.toString();\n};\n\nexport const openPopgridsLoginPopup = (apiUrl: string, publicKey: string) => {\n const popup = window.open(\n buildEmbedLoginUrl(apiUrl, publicKey, window.location.origin),\n POPUP_NAME,\n POPUP_FEATURES,\n );\n\n if (!popup) {\n throw new PopupAuthError(\"Popup blocked. Allow popups for this site and try again.\");\n }\n\n return popup;\n};\n\nconst isAuthMessage = (data: unknown, type: string) =>\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n \"source\" in data &&\n (data as { type: string; source: string }).type === type &&\n (data as { type: string; source: string }).source === EMBED_AUTH_SOURCE;\n\nconst readAuthUser = (data: unknown): AuthUser | null => {\n if (typeof data !== \"object\" || data === null || !(\"user\" in data)) {\n return null;\n }\n\n const user = (data as { user?: unknown }).user;\n if (typeof user !== \"object\" || user === null || !(\"id\" in user)) {\n return null;\n }\n\n const record = user as {\n id?: unknown;\n name?: unknown;\n email?: unknown;\n image?: unknown;\n };\n\n if (typeof record.id !== \"string\") {\n return null;\n }\n\n return {\n id: record.id,\n name: typeof record.name === \"string\" ? record.name : \"\",\n email: typeof record.email === \"string\" ? record.email : \"\",\n image: typeof record.image === \"string\" ? record.image : null,\n };\n};\n\nexport const waitForPopgridsAuth = (\n apiUrl: string,\n popup: Window,\n options?: {\n onAuthUser?: (user: AuthUser) => void;\n verifySignedIn?: () => Promise<boolean>;\n },\n) =>\n new Promise<void>((resolve, reject) => {\n const expectedOrigin = new URL(apiUrl).origin;\n let settled = false;\n let authMessageReceived = false;\n let closeCheckStarted = false;\n\n const settle = (result: \"resolve\" | \"reject\", error?: PopupAuthError) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n if (result === \"resolve\") {\n resolve();\n return;\n }\n reject(error ?? new PopupAuthError(\"Sign-in failed\"));\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) {\n return;\n }\n\n if (isAuthMessage(event.data, EMBED_AUTH_SUCCESS)) {\n authMessageReceived = true;\n const user = readAuthUser(event.data);\n if (user) {\n options?.onAuthUser?.(user);\n }\n settle(\"resolve\");\n return;\n }\n\n if (isAuthMessage(event.data, EMBED_AUTH_ERROR)) {\n authMessageReceived = true;\n const message =\n typeof event.data === \"object\" &&\n event.data !== null &&\n \"error\" in event.data &&\n typeof (event.data as { error?: unknown }).error === \"string\"\n ? (event.data as { error: string }).error\n : \"Sign-in failed\";\n settle(\"reject\", new PopupAuthError(message));\n }\n };\n\n const interval = window.setInterval(() => {\n if (!popup.closed) {\n return;\n }\n\n if (closeCheckStarted) {\n return;\n }\n\n closeCheckStarted = true;\n\n void (async () => {\n await new Promise((resolveDelay) => window.setTimeout(resolveDelay, POPUP_CLOSE_GRACE_MS));\n\n if (authMessageReceived || settled) {\n return;\n }\n\n if (options?.verifySignedIn && (await options.verifySignedIn())) {\n settle(\"resolve\");\n return;\n }\n\n settle(\"reject\", new PopupAuthError(\"Sign-in was cancelled\"));\n })();\n }, 300);\n\n const timeout = window.setTimeout(() => {\n try {\n popup.close();\n } catch {\n // ignore\n }\n settle(\"reject\", new PopupAuthError(\"Sign-in timed out\"));\n }, AUTH_TIMEOUT_MS);\n\n const cleanup = () => {\n window.removeEventListener(\"message\", onMessage);\n clearInterval(interval);\n clearTimeout(timeout);\n };\n\n window.addEventListener(\"message\", onMessage);\n });\n\nexport const signInWithPopup = async (\n apiUrl: string,\n publicKey: string,\n options?: {\n onAuthUser?: (user: AuthUser) => void;\n verifySignedIn?: () => Promise<boolean>;\n },\n) => {\n const popup = openPopgridsLoginPopup(apiUrl, publicKey);\n await waitForPopgridsAuth(apiUrl, popup, options);\n};\n","import { signal } from \"@preact/signals-core\";\nimport { signInWithPopup } from \"../lib/popup-auth.js\";\nimport type { AuthUser } from \"../types/models.js\";\n\nexport const currentUser = signal<AuthUser | null>(null);\nexport const authError = signal<string | null>(null);\nexport const authPending = signal(false);\n\nconst SESSION_RETRY_DELAYS_MS = [0, 150, 400];\nconst POST_AUTH_SESSION_DELAYS_MS = [0, 100, 200, 400, 800, 1500, 2500, 4000];\n\nexport async function checkSession(\n apiUrl: string,\n publicKey: string,\n delays: number[] = SESSION_RETRY_DELAYS_MS,\n): Promise<boolean> {\n if (!apiUrl || !publicKey) {\n currentUser.value = null;\n return false;\n }\n\n const sessionUrl = new URL(\n `/api/v1/embed/grids/${publicKey}/session`,\n apiUrl,\n );\n sessionUrl.searchParams.set(\"pageUrl\", window.location.href);\n\n for (let attempt = 0; attempt < delays.length; attempt++) {\n const delay = delays[attempt] ?? 0;\n if (delay > 0) {\n await new Promise((resolve) => window.setTimeout(resolve, delay));\n }\n\n try {\n const res = await fetch(sessionUrl, { credentials: \"include\" });\n\n if (!res.ok) {\n continue;\n }\n\n const data = (await res.json()) as { user: AuthUser | null };\n currentUser.value = data.user ?? null;\n\n if (currentUser.value !== null) {\n return true;\n }\n } catch {\n // retry\n }\n }\n\n currentUser.value = null;\n return false;\n}\n\nexport async function requestSignIn(\n apiUrl: string,\n publicKey: string,\n): Promise<boolean> {\n authError.value = null;\n authPending.value = true;\n\n try {\n await signInWithPopup(apiUrl, publicKey, {\n onAuthUser: (user) => {\n currentUser.value = user;\n },\n verifySignedIn: () =>\n checkSession(apiUrl, publicKey, POST_AUTH_SESSION_DELAYS_MS),\n });\n\n if (currentUser.value) {\n return true;\n }\n\n return await checkSession(apiUrl, publicKey, POST_AUTH_SESSION_DELAYS_MS);\n } catch (error) {\n authError.value = error instanceof Error ? error.message : \"Sign-in failed\";\n return false;\n } finally {\n authPending.value = false;\n }\n}\n\nexport function clearAuthError(): void {\n authError.value = null;\n}\n","const _registry = new WeakMap<Element, Map<any, any>>();\n\nexport const registerStore = (el: Element, store: any, key: any = store.constructor): void => {\n let stores = _registry.get(el);\n if (!stores) {\n stores = new Map();\n _registry.set(el, stores);\n }\n stores.set(key, store);\n};\n\nexport const unregisterStore = (el: Element): void => {\n _registry.delete(el);\n};\n\nexport const resolveStore = <T>(el: Element, key: any): T | null => {\n let node: Element | null = el;\n while (node) {\n const stores = _registry.get(node);\n const store = stores?.get(key);\n if (store) return store as T;\n\n const root = node.getRootNode();\n if (!(root instanceof ShadowRoot)) break;\n node = root.host;\n }\n return null;\n};\n\nexport function consume(storeKey: any) {\n return function (target: any, propertyKey: string) {\n const cacheKey = Symbol(\"context_\" + (storeKey.name || \"store\"));\n Object.defineProperty(target, propertyKey, {\n get(this: any) {\n if (this[cacheKey]) return this[cacheKey];\n const resolved = resolveStore(this, storeKey);\n if (!resolved) {\n console.error(`[Context] resolveStore failed! isConnected: ${this.isConnected}`, this);\n throw new Error(\n `[Context] Store for key \"${storeKey.name || storeKey}\" not resolved on <${this.localName}>.`\n );\n }\n this[cacheKey] = resolved;\n return resolved;\n },\n enumerable: true,\n configurable: true,\n });\n };\n}\n\n","import { computed, signal } from \"@preact/signals-core\";\nimport type { Comment, CommentAuthor, Grid } from \"../types/models.js\";\nimport { currentUser, requestSignIn } from \"./auth-store.js\";\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst DEFAULT_PREVIEW_COUNT = 3;\n\nconst commentRecency = (comment: Comment) => {\n const createdAt =\n typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt));\n\n return Number.isFinite(createdAt) ? createdAt : 0;\n};\n\nconst resolvePreviewCount = (grid: Grid | null, fallback: number) => {\n const value = grid?.previewCount ?? fallback;\n\n return value > 0 ? value : DEFAULT_PREVIEW_COUNT;\n};\n\nexport class GridStore {\n readonly apiUrl: string;\n readonly publicKey: string;\n readonly pageUrl: string;\n readonly externalId: string | null;\n readonly previewCount = DEFAULT_PREVIEW_COUNT;\n\n grid = signal<Grid | null>(null);\n comments = signal<Comment[]>([]);\n loading = signal(true);\n error = signal<string | null>(null);\n open = signal(false);\n replyingTo = signal<string | null>(null);\n editingCommentId = signal<string | null>(null);\n scrollingCommentId = signal<string | null>(null);\n\n private socket: WebSocket | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n\n topLevelComments = computed(() =>\n this.comments.value\n .filter((c) => c.parentCommentId === null)\n .sort((a, b) => String(a.sortKey).localeCompare(String(b.sortKey))),\n );\n\n replyingToComment = computed(() => {\n const id = this.replyingTo.value;\n if (!id) return null;\n return this.comments.value.find((c) => c.id === id) ?? null;\n });\n\n editingComment = computed(() => {\n const id = this.editingCommentId.value;\n if (!id) return null;\n return this.comments.value.find((c) => c.id === id) ?? null;\n });\n\n previewComments = computed(() =>\n this.topLevelComments.value.slice(0, resolvePreviewCount(this.grid.value, this.previewCount)),\n );\n\n previewAvatars = computed((): CommentAuthor[] => {\n const limit = resolvePreviewCount(this.grid.value, this.previewCount);\n const seen = new Set<string>();\n const uniqueNewestFirst: CommentAuthor[] = [];\n\n const sorted = [...this.comments.value].sort((a, b) => commentRecency(b) - commentRecency(a));\n\n for (const comment of sorted) {\n const author = comment.author;\n\n if (!author?.id || seen.has(author.id)) {\n continue;\n }\n\n seen.add(author.id);\n uniqueNewestFirst.push(author);\n\n if (uniqueNewestFirst.length >= limit) {\n break;\n }\n }\n\n return uniqueNewestFirst.reverse();\n });\n\n constructor(opts: {\n apiUrl: string;\n publicKey: string;\n pageUrl: string;\n externalId?: string | null;\n }) {\n this.apiUrl = opts.apiUrl;\n this.publicKey = opts.publicKey;\n this.pageUrl = opts.pageUrl;\n this.externalId = opts.externalId?.trim() || null;\n }\n\n /** pageUrl + optional externalId — the params that identify the discussion. */\n private identityParams(): string {\n const params = new URLSearchParams({ pageUrl: this.pageUrl });\n if (this.externalId) {\n params.set(\"externalId\", this.externalId);\n }\n return params.toString();\n }\n\n repliesFor(parentId: string): Comment[] {\n const parent = this.comments.value.find((c) => c.id === parentId);\n if (!parent) return [];\n return this.comments.value\n .filter(\n (c) =>\n c.id !== parentId &&\n (c.sortKey === parent.sortKey || c.sortKey.startsWith(parent.sortKey + \"/\")),\n )\n .sort((a, b) => String(a.sortKey).localeCompare(String(b.sortKey)));\n }\n\n async load(): Promise<boolean> {\n this.loading.value = true;\n this.error.value = null;\n try {\n const gridRes = await fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}`, {\n credentials: \"include\",\n });\n\n if (!gridRes.ok) {\n this.error.value = \"There was a problem loading the PopGrid\";\n return false;\n }\n\n const data = (await gridRes.json()) as { grid: Grid };\n this.grid.value = data.grid;\n this.connectRealtime();\n\n const commentsRes = await fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments?${this.identityParams()}`,\n { credentials: \"include\" },\n );\n\n if (commentsRes.ok) {\n const commentsData = (await commentsRes.json()) as { comments: Comment[] };\n this.comments.value = commentsData.comments;\n }\n\n return true;\n } catch {\n console.error(\"Failed to load PopGrid\");\n this.error.value = \"There was a problem loading the PopGrid\";\n return false;\n } finally {\n this.loading.value = false;\n }\n }\n\n async postComment(body: string, parentCommentId?: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments`, {\n method: \"POST\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n body,\n pageUrl: this.pageUrl,\n externalId: this.externalId ?? undefined,\n parentCommentId,\n }),\n });\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.upsertComment(data.comment);\n\n if (data.comment.author && !currentUser.value) {\n currentUser.value = {\n id: data.comment.author.id,\n name: data.comment.author.name ?? \"\",\n email: \"\",\n image: data.comment.author.image,\n };\n }\n\n return data.comment;\n }\n\n destroy(): void {\n this.disposed = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.socket) {\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.close();\n this.socket = null;\n }\n }\n\n private connectRealtime(): void {\n const connectUrl = this.grid.value?.connectUrl;\n\n if (!connectUrl || this.disposed) {\n return;\n }\n\n if (this.socket) {\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.close();\n this.socket = null;\n }\n\n const wsUrl = new URL(connectUrl, this.apiUrl);\n wsUrl.protocol = wsUrl.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n wsUrl.searchParams.set(\"pageUrl\", this.pageUrl);\n if (this.externalId) {\n wsUrl.searchParams.set(\"externalId\", this.externalId);\n }\n\n const socket = new WebSocket(wsUrl.toString());\n this.socket = socket;\n\n socket.onopen = () => {\n this.reconnectAttempt = 0;\n };\n\n socket.onmessage = (event) => {\n try {\n const payload = JSON.parse(String(event.data)) as {\n type?: string;\n comment?: Comment;\n };\n\n if (payload.type === \"comment.created\" && payload.comment) {\n this.upsertComment(payload.comment);\n } else if (payload.type === \"comment.updated\" && payload.comment) {\n this.updateCommentInList(payload.comment);\n }\n } catch {\n // Ignore malformed realtime payloads.\n }\n };\n\n socket.onclose = () => {\n if (this.disposed) {\n return;\n }\n\n this.scheduleReconnect();\n };\n\n socket.onerror = () => {\n socket.close();\n };\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || this.reconnectTimer) {\n return;\n }\n\n const delay = Math.min(1000 * 2 ** this.reconnectAttempt, MAX_RECONNECT_DELAY_MS);\n this.reconnectAttempt += 1;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connectRealtime();\n }, delay);\n }\n\n private upsertComment(comment: Comment): void {\n const existing = this.comments.value.some((entry) => entry.id === comment.id);\n\n if (existing) {\n return;\n }\n\n this.comments.value = [...this.comments.value, comment];\n }\n\n async editComment(commentId: string, body: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}`, {\n method: \"PATCH\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n body,\n pageUrl: this.pageUrl,\n externalId: this.externalId ?? undefined,\n }),\n });\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.updateCommentInList(data.comment);\n return data.comment;\n }\n\n async deleteComment(commentId: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}?${this.identityParams()}`,\n {\n method: \"DELETE\",\n credentials: \"include\",\n },\n );\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.updateCommentInList(data.comment);\n return data.comment;\n }\n\n async flagComment(commentId: string): Promise<boolean> {\n const attempt = async () =>\n fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}/flag?${this.identityParams()}`,\n {\n method: \"POST\",\n credentials: \"include\",\n },\n );\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return false;\n }\n res = await attempt();\n }\n\n return res.ok;\n }\n\n private updateCommentInList(comment: Comment): void {\n this.comments.value = this.comments.value.map((c) => (c.id === comment.id ? comment : c));\n }\n}\n","@layer base {\n :host {\n box-sizing: border-box;\n font-family: \"Inter\", sans-serif;\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Color: Brand */\n --pop-color-brand-midnight-100: oklch(0.9658 0.0161 262.75);\n --pop-color-brand-midnight-900: oklch(0.15 0.03 255.43);\n --pop-color-brand-midnight-800: oklch(0.19 0.05 255.43);\n --pop-color-brand-ocean-400: oklch(0.63 0.19 255.43);\n --pop-color-brand-ocean-100: oklch(0.91 0.05 255.43);\n --pop-color-brand-forest-900: oklch(0.3866 0.0698 180.75);\n --pop-color-brand-forest-700: oklch(0.45 0.15 165.43);\n --pop-color-brand-forest-100: oklch(0.97 0.04 165.43);\n --pop-color-brand-highlight-400: oklch(0.88 0.25 105.43);\n --pop-color-brand-pumpkin-500: oklch(0.62 0.18 45.43);\n --pop-color-brand-pumpkin-200: oklch(0.89 0.08 45.43);\n --pop-color-brand-lemon-300: oklch(0.91 0.12 85.43);\n --pop-color-brand-lemon-100: oklch(0.97 0.04 85.43);\n\n /* Durations */\n --pop-duration-bouncy: 1s;\n --pop-duration-card-highlight: 0.6s;\n --pop-duration-gentle: 0.833s;\n --pop-duration-menu: 0.4s;\n --pop-duration-pop-hover: 0.6s;\n --pop-duration-pop-text: 0.3s;\n --pop-duration-quick: 0.833s;\n --pop-duration-slow: 1.167s;\n\n /* Easing */\n /* prettier-ignore */\n --pop-ease-bouncy: linear(0, 0.011, 0.045 1.3%, 0.184 2.7%, 0.911 7.4%, 1.153 9.4%, 1.301 11.2%, 1.342, 1.362 13%, 1.363, 1.355 14.4%, 1.306 16%, 1.028 21%, 0.939 23%, 0.89 24.7%, 0.876, 0.868 26.4%, 0.869, 0.882 29%, 0.907 30.5%, 1.014 35.9%, 1.038, 1.048 39.8% 41.1%, 1.043 42.5%, 0.995 49.3%, 0.987, 0.983 53.2%, 0.984 55.9%, 1.002 62.7%, 1.006 66.4%, 0.998 79.7%, 1);\n /* prettier-ignore */\n --pop-ease-card-highlight: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-gentle: linear(0, 0.007, 0.026, 0.059 4.5%, 0.106 6.3%, 0.209 9.5%, 0.558 19.3%, 0.658, 0.742, 0.812, 0.87, 0.918, 0.957, 0.986 41.6%, 1.007 45.3%, 1.021 49.4%, 1.027 54% 60.9%, 1.007 83.2%, 1);\n /* prettier-ignore */\n --pop-ease-menu: linear(0, 0.0034 0.81%, 0.0278 2.42%, 0.097 4.84%, 0.5361 15.32%, 0.655 18.55%, 0.7314, 0.7964 23.39%, 0.8662, 0.9185, 0.9561, 0.9818, 0.9984, 1.0083 42.74%, 1.014 46.77%, 1.0145 53.22%, 1.0053 68.55%, 1.0019 77.42%, 0.9998 100%);\n /* prettier-ignore */\n --pop-ease-pop-hover: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-pop-text: linear(0, 0.0051 0.99%, 0.0261, 0.0607 3.61%, 0.1192 5.26%, 0.2531 8.21%, 0.6509 16.1%, 0.7652 18.73%, 0.8512, 0.9232 23.33%, 0.9881 25.96%, 1.0305 28.26%, 1.0642 30.88%, 1.0782 32.53%, 1.089, 1.094 36.47%, 1.0942, 1.0896 41.07%, 1.0804 43.7%, 1.0354 53.23%, 1.0181 57.5%, 1.0061 61.44%, 0.9974 65.71%, 0.9925 70.31%, 0.991 75.9%, 0.9996 99.88%);\n /* prettier-ignore */\n --pop-ease-quick: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-slow: linear(0, 0.005, 0.02 2%, 0.081 4.5%, 0.469 15.2%, 0.567, 0.65, 0.722 24.4%, 0.784, 0.835 31.1%, 0.878 34.9%, 0.914 39.1%, 0.942 43.8%, 0.964 49.1%, 0.979 55.4%, 0.989 62.4%, 0.995 71.1%, 1);\n\n /* Box-Shadow */\n --pop-shadow-xs: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);\n --pop-shadow-sm: 0px 1px 3px 0px rgba(16, 24, 40, 0.1), 0px 1px 2px 0px rgba(16, 24, 40, 0.06);\n --pop-shadow-md:\n 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);\n --pop-shadow-lg:\n 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);\n --pop-shadow-xl:\n 0px 20px 24px -4px rgba(16, 24, 40, 0.08), 0px 8px 8px -4px rgba(16, 24, 40, 0.03);\n --pop-shadow-2xl: 0px 24px 48px -12px rgba(16, 24, 40, 0.18);\n --pop-shadow-3xl: 0px 32px 48px -12px rgba(16, 24, 40, 0.32);\n --pop-shadow-4xl: 0px 24px 32px -12px rgba(16, 24, 40, 0.28);\n\n --pop-radius-none: 0; /* 0px */\n --pop-radius-xxs: 0.125rem; /* 2px */\n --pop-radius-xs: 0.25rem; /* 4px */\n --pop-radius-sm: 0.375rem; /* 6px */\n --pop-radius-md: 0.5rem; /* 8px */\n --pop-radius-lg: 0.625rem; /* 10px */\n --pop-radius-xl: 0.75rem; /* 12px */\n --pop-radius-2xl: 1rem; /* 16px */\n --pop-radius-3xl: 1.25rem; /* 20px */\n --pop-radius-4xl: 1.5rem; /* 24px */\n --pop-radius-full: 9999px; /* Creates a circle or oval */\n\n --pop-radius: 0.625rem;\n --pop-background: oklch(1 0 0);\n --pop-foreground: oklch(0 0 0);\n --pop-card: oklch(1 0 0);\n --pop-card-foreground: oklch(0.145 0 0);\n --pop-popover: oklch(1 0 0);\n --pop-popover-foreground: oklch(0 0 0);\n --pop-primary: oklch(0.205 0 0);\n --pop-primary-foreground: oklch(0.985 0 0);\n --pop-secondary: oklch(0.97 0 0);\n --pop-secondary-foreground: oklch(0.205 0 0);\n --pop-muted: oklch(0.97 0 0);\n --pop-muted-foreground: oklch(0.7152 0.0233 256.76);\n --pop-accent: oklch(0.97 0 0);\n --pop-accent-foreground: oklch(0.205 0 0);\n --pop-destructive: var(--color-error-600);\n --pop-border: oklch(0.1101 0.0763 264.05 / 10.2%);\n --pop-input: oklch(0.922 0 0);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.646 0.222 41.116);\n --pop-chart-2: oklch(0.6 0.118 184.704);\n --pop-chart-3: oklch(0.398 0.07 227.392);\n --pop-chart-4: oklch(0.828 0.189 84.429);\n --pop-chart-5: oklch(0.769 0.188 70.08);\n --pop-sidebar: oklch(0.985 0 0);\n --pop-sidebar-foreground: oklch(0.145 0 0);\n --pop-sidebar-primary: oklch(0.205 0 0);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.97 0 0);\n --pop-sidebar-accent-foreground: oklch(0.205 0 0);\n --pop-sidebar-border: oklch(0.922 0 0);\n --pop-sidebar-ring: oklch(0.708 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-background: oklch(0.15 0.03 255.43);\n --pop-foreground: oklch(0.66 0.006 255.43);\n --pop-card: oklch(0.205 0 0);\n --pop-card-foreground: oklch(0.985 0 0);\n --pop-popover: oklch(0.15 0.03 255.43);\n --pop-popover-foreground: oklch(0.66 0.006 255.43);\n --pop-primary: oklch(0.922 0 0);\n --pop-primary-foreground: oklch(0.205 0 0);\n --pop-secondary: oklch(0.269 0 0);\n --pop-secondary-foreground: oklch(0.985 0 0);\n --pop-muted: oklch(0.269 0 0);\n --pop-muted-foreground: oklch(0.66 0.006 255.43);\n --pop-accent: oklch(0.269 0 0);\n --pop-accent-foreground: oklch(0.985 0 0);\n --pop-destructive: var(--color-error-400);\n --pop-border: oklch(1 0 0 / 10%);\n --pop-input: oklch(1 0 0 / 15%);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.488 0.243 264.376);\n --pop-chart-2: oklch(0.696 0.17 162.48);\n --pop-chart-3: oklch(0.769 0.188 70.08);\n --pop-chart-4: oklch(0.627 0.265 303.9);\n --pop-chart-5: oklch(0.645 0.246 16.439);\n --pop-sidebar: oklch(0.205 0 0);\n --pop-sidebar-foreground: oklch(0.985 0 0);\n --pop-sidebar-primary: oklch(0.488 0.243 264.376);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.269 0 0);\n --pop-sidebar-accent-foreground: oklch(0.985 0 0);\n --pop-sidebar-border: oklch(1 0 0 / 10%);\n --pop-sidebar-ring: oklch(0.556 0 0);\n }\n }\n\n :host(.dark) {\n --pop-background: oklch(0.15 0.03 255.43);\n --pop-foreground: oklch(0.66 0.006 255.43);\n --pop-card: oklch(0.205 0 0);\n --pop-card-foreground: oklch(0.985 0 0);\n --pop-popover: oklch(0.15 0.03 255.43);\n --pop-popover-foreground: oklch(0.66 0.006 255.43);\n --pop-primary: oklch(0.922 0 0);\n --pop-primary-foreground: oklch(0.205 0 0);\n --pop-secondary: oklch(0.269 0 0);\n --pop-secondary-foreground: oklch(0.985 0 0);\n --pop-muted: oklch(0.269 0 0);\n --pop-muted-foreground: oklch(0.66 0.006 255.43);\n --pop-accent: oklch(0.269 0 0);\n --pop-accent-foreground: oklch(0.985 0 0);\n --pop-destructive: var(--color-error-400);\n --pop-border: oklch(1 0 0 / 10%);\n --pop-input: oklch(1 0 0 / 15%);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.488 0.243 264.376);\n --pop-chart-2: oklch(0.696 0.17 162.48);\n --pop-chart-3: oklch(0.769 0.188 70.08);\n --pop-chart-4: oklch(0.627 0.265 303.9);\n --pop-chart-5: oklch(0.645 0.246 16.439);\n --pop-sidebar: oklch(0.205 0 0);\n --pop-sidebar-foreground: oklch(0.985 0 0);\n --pop-sidebar-primary: oklch(0.488 0.243 264.376);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.269 0 0);\n --pop-sidebar-accent-foreground: oklch(0.985 0 0);\n --pop-sidebar-border: oklch(1 0 0 / 10%);\n --pop-sidebar-ring: oklch(0.556 0 0);\n }\n\n *,\n *::before,\n *::after {\n box-sizing: inherit;\n }\n\n html,\n body {\n padding: 0;\n margin: 0;\n }\n\n svg {\n display: block;\n }\n\n p {\n margin: 0;\n padding: 0;\n }\n\n button {\n margin: 0;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n cursor: pointer;\n }\n}\n","@layer components {\n .btn {\n display: flex;\n height: auto;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n border-radius: 4px;\n border: 0;\n padding: 0.625rem 1.25rem;\n text-align: center;\n cursor: pointer;\n transition:\n background-color 0.2s,\n color 0.2s;\n }\n\n .btn-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n border-radius: var(--pop-radius-xs, 4px);\n border-style: solid;\n border-color: transparent;\n cursor: pointer;\n background-color: transparent;\n text-decoration: none;\n font-weight: 500;\n transition:\n background-color 0.2s,\n border-color 0.2s,\n color 0.2s;\n }\n\n /* Sizes */\n .btn-link--size-sm {\n font-size: 13px;\n line-height: 18px;\n letter-spacing: -0.08px;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 2px;\n border-right-width: 2px;\n }\n\n .btn-link--size-md {\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 3px;\n border-right-width: 3px;\n }\n\n .btn-link--size-lg {\n font-size: 16px;\n line-height: 24px;\n letter-spacing: 0;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 4px;\n border-right-width: 4px;\n }\n\n /* Themes */\n .btn-link--theme-default {\n color: color-mix(in srgb, var(--pop-foreground) 50%, transparent);\n }\n\n .btn-link--theme-default.btn-link--primary {\n color: var(--pop-foreground);\n }\n\n .btn-link--theme-white {\n color: white;\n }\n\n .btn-link--theme-black {\n color: black;\n }\n\n /* Hover State */\n .btn-link--theme-default:hover,\n .btn-link--theme-black:hover {\n background-color: color-mix(in srgb, var(--pop-foreground) 10%, transparent);\n border-color: color-mix(in srgb, var(--pop-foreground) 10%, transparent);\n }\n\n .btn-link--theme-default:not(.btn-link--primary):hover {\n color: var(--pop-foreground);\n }\n\n .btn-link--theme-white:hover {\n background-color: color-mix(in srgb, white 16%, transparent);\n border-color: color-mix(in srgb, white 16%, transparent);\n }\n\n /* Active (Pressed) State */\n .btn-link:active {\n background-color: transparent;\n border-color: transparent;\n }\n\n .btn-link--theme-default:not(.btn-link--primary):active {\n color: color-mix(in srgb, var(--pop-foreground) 50%, transparent);\n }\n\n /* Focus State */\n .btn-link:focus-visible {\n background-color: var(--pop-ring, #155eef);\n border-color: var(--pop-ring, #155eef);\n color: white !important;\n outline: none;\n }\n\n /* Disabled State */\n .btn-link:disabled,\n .btn-link.is-disabled {\n color: color-mix(in srgb, var(--pop-foreground) 35%, transparent) !important;\n background-color: transparent !important;\n border-color: transparent !important;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .btn:focus-visible {\n outline: 2px solid currentColor; /* focus-visible */\n outline-offset: 2px;\n }\n}\n","@layer components {\n .mask {\n -webkit-mask-size: contain;\n mask-size: contain;\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-position: center;\n mask-position: center;\n }\n\n .mask-squircle {\n -webkit-mask-image: url(\"data:image/svg+xml,%3csvg width='160' height='160' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M 0 80 C 0 14.12 14.12 0 80 0 C 145.88 0 160 14.12 160 80 C 160 145.88 145.88 160 80 160 C 14.12 160 0 145.88 0 80 Z'/%3e%3c/svg%3e\");\n mask-image: url(\"data:image/svg+xml,%3csvg width='160' height='160' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M 0 80 C 0 14.12 14.12 0 80 0 C 145.88 0 160 14.12 160 80 C 160 145.88 145.88 160 80 160 C 14.12 160 0 145.88 0 80 Z'/%3e%3c/svg%3e\");\n }\n}\n","let isGlobalDark = false;\nconst activeElements = new Set<HTMLElement>();\nlet globalObserver: MutationObserver | null = null;\nlet mediaQuery: MediaQueryList | null = null;\n\nfunction checkGlobalDark(): boolean {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return false;\n\n const hasDarkClass =\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\");\n const hasLightClass =\n document.documentElement.classList.contains(\"light\") ||\n document.body.classList.contains(\"light\");\n\n if (hasDarkClass) return true;\n if (hasLightClass) return false;\n\n if (!mediaQuery) {\n mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n }\n return mediaQuery.matches;\n}\n\nfunction updateGlobalDark() {\n const newDark = checkGlobalDark();\n if (newDark !== isGlobalDark) {\n isGlobalDark = newDark;\n activeElements.forEach((el) => {\n const isDark = isGlobalDark || !!el.closest(\".dark\");\n el.classList.toggle(\"dark\", isDark);\n });\n }\n}\n\nconst mediaListener = () => {\n updateGlobalDark();\n};\n\nexport function registerThemeObserver(el: HTMLElement) {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n if (activeElements.size === 0) {\n isGlobalDark = checkGlobalDark();\n globalObserver = new MutationObserver(() => {\n updateGlobalDark();\n });\n globalObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n globalObserver.observe(document.body, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mediaQuery.addEventListener(\"change\", mediaListener);\n }\n\n activeElements.add(el);\n\n const isDark = isGlobalDark || !!el.closest(\".dark\");\n el.classList.toggle(\"dark\", isDark);\n}\n\nexport function unregisterThemeObserver(el: HTMLElement) {\n activeElements.delete(el);\n if (activeElements.size === 0) {\n if (globalObserver) {\n globalObserver.disconnect();\n globalObserver = null;\n }\n if (mediaQuery) {\n mediaQuery.removeEventListener(\"change\", mediaListener);\n mediaQuery = null;\n }\n }\n}\n","import baseStyles from \"../styles/base.css?inline\";\nimport btnStyles from \"../styles/buttons.css?inline\";\nimport masksStyles from \"../styles/masks.css?inline\";\n\nimport { effect, untracked } from \"@preact/signals-core\";\n\nexport function createSheet(cssText: string): CSSStyleSheet {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(cssText);\n return sheet;\n}\n\nexport const sharedBaseSheet = createSheet(baseStyles);\nexport const btnSheet = createSheet(btnStyles);\nexport const masksSheet = createSheet(masksStyles);\n\nimport { registerThemeObserver, unregisterThemeObserver } from \"../helpers/theme.js\";\n\nexport abstract class BaseElement extends HTMLElement implements EventListenerObject {\n protected baseStyleSheets: CSSStyleSheet[] = [sharedBaseSheet, btnSheet, masksSheet];\n protected get styleSheets(): CSSStyleSheet[] {\n return [];\n }\n\n private _hasRendered = false;\n\n private _disposables: Array<() => void> = [];\n\n constructor() {\n super();\n this.attachShadow({ mode: \"open\" });\n if (this.shadowRoot) {\n this.shadowRoot.adoptedStyleSheets = this.styles;\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n if (oldValue === newValue) return;\n\n const pascalName = name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n const methodName = `on${pascalName}Changed`;\n\n if (typeof (this as any)[methodName] === \"function\") {\n (this as any)[methodName](newValue, oldValue);\n }\n }\n\n /**\n * Use this instead of calling effect() directly to ensure\n * automatic cleanup when the component disconnects.\n */\n protected addEffect(callback: () => void) {\n this._disposables.push(effect(callback));\n }\n\n connectedCallback() {\n registerThemeObserver(this);\n untracked(() => {\n this.render();\n this._bindEvents();\n this.setupEffects();\n });\n }\n\n disconnectedCallback() {\n unregisterThemeObserver(this);\n // Kill all active subscriptions\n this._disposables.forEach((dispose) => dispose());\n this._disposables = [];\n }\n\n protected events: Record<string, string> = {};\n\n private _bindEvents() {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) {\n return;\n }\n Object.keys(this.events).forEach((key) => {\n shadowRoot.addEventListener(key, this);\n });\n }\n\n handleEvent(event: Event): void {\n const methodName = this.events[event.type];\n\n if (methodName && typeof (this as any)[methodName] === \"function\") {\n (this as any)[methodName](event);\n }\n }\n\n protected emit<T = unknown>(eventName: string, options: CustomEventInit<T> = {}) {\n this.dispatchEvent(\n new CustomEvent<T>(eventName, {\n bubbles: true,\n composed: true,\n ...options,\n }),\n );\n }\n\n // --- Abstract & Overrideable Methods ---\n protected abstract getTemplate(): string;\n\n protected get styles(): CSSStyleSheet[] {\n return [...this.baseStyleSheets, ...this.styleSheets];\n }\n\n protected setupEffects(): void {}\n\n protected render() {\n if (!this.shadowRoot) return;\n this.shadowRoot.innerHTML = this.getTemplate();\n this._hasRendered = true;\n }\n\n protected hideElement(selector: string, shouldHide: boolean, useDisplayNone = true) {\n if (!this.shadowRoot || !this._hasRendered) {\n return;\n }\n\n const el = this.shadowRoot.querySelector(selector);\n if (!el) {\n console.warn(`Element not found for selector: ${selector}`);\n return;\n }\n\n if (useDisplayNone) {\n el.classList.toggle(\"hidden\", shouldHide);\n } else {\n el.classList.toggle(\"invisible\", shouldHide);\n }\n }\n\n protected setText(selector: string, text: string | number) {\n const el = this.shadowRoot?.querySelector(selector);\n if (el && el.textContent !== String(text)) {\n el.textContent = String(text);\n }\n }\n\n protected setAttr(selector: string, attr: string, value: string | null) {\n const el = this.shadowRoot?.querySelector(selector);\n if (!el) return;\n\n if (value === null) {\n el.removeAttribute(attr);\n } else if (el.getAttribute(attr) !== value) {\n el.setAttribute(attr, value);\n }\n }\n\n protected toggleClass(selector: string, className: string, force?: boolean) {\n const el = this.shadowRoot?.querySelector(selector);\n if (!el) return;\n\n el.classList.toggle(className, force);\n }\n\n protected getElement<T extends Element = HTMLElement>(selector: string): T | null {\n return this.shadowRoot?.querySelector(selector) ?? null;\n }\n}\n","import {\n authError,\n authPending,\n clearAuthError,\n requestSignIn,\n} from \"../store/auth-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n position: relative;\n\n --pop-auth-border: var(--pop-border, rgba(0, 0, 32, 0.04));\n --pop-auth-watermark: rgba(0, 0, 32, 0.4);\n --pop-auth-btn: #000000;\n --pop-auth-logo: rgba(0, 0, 32, 0.35);\n --pop-auth-error: #dc2626;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-auth-border: var(--pop-border, rgba(255, 255, 255, 0.1));\n --pop-auth-watermark: rgba(255, 255, 255, 0.4);\n --pop-auth-btn: #ffffff;\n --pop-auth-logo: rgba(255, 255, 255, 0.35);\n --pop-auth-error: var(--pop-destructive, #f87171);\n }\n }\n\n :host(.dark) {\n --pop-auth-border: var(--pop-border, rgba(255, 255, 255, 0.1));\n --pop-auth-watermark: rgba(255, 255, 255, 0.4);\n --pop-auth-btn: #ffffff;\n --pop-auth-logo: rgba(255, 255, 255, 0.35);\n --pop-auth-error: var(--pop-destructive, #f87171);\n }\n\n .panel {\n position: relative;\n border-top: 1px solid var(--pop-auth-border);\n }\n\n .watermark {\n position: absolute;\n top: -16px;\n left: 8px;\n font-family: Inter, sans-serif;\n font-size: 8px;\n font-weight: 700;\n letter-spacing: 1px;\n color: var(--pop-auth-watermark);\n text-transform: uppercase;\n backdrop-filter: blur(4px);\n border-radius: 9999px;\n padding: 2px 6px;\n pointer-events: none;\n }\n\n .actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n }\n\n .join-btn {\n font-family: Inter, sans-serif;\n font-size: 13px;\n font-weight: 600;\n color: var(--pop-auth-btn);\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n letter-spacing: -0.08px;\n line-height: 18px;\n }\n\n .join-btn:disabled {\n opacity: 0.6;\n cursor: default;\n }\n\n .logo {\n font-family: Inter, sans-serif;\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 1.5px;\n color: var(--pop-auth-logo);\n text-transform: uppercase;\n }\n\n .error {\n padding: 0 16px 12px;\n font-family: Inter, sans-serif;\n font-size: 12px;\n line-height: 16px;\n color: var(--pop-auth-error);\n text-align: center;\n }\n`);\n\nexport class PopAuthPanel extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".join-btn\")) return;\n void this.handleJoin();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const pending = authPending.value;\n const error = authError.value;\n\n const joinBtn = this.getElement<HTMLButtonElement>(\".join-btn\");\n if (joinBtn) {\n joinBtn.disabled = pending;\n joinBtn.textContent = pending ? \"Signing in…\" : \"Join the Conversation\";\n }\n\n const errorEl = this.getElement<HTMLDivElement>(\".error\");\n if (errorEl) {\n if (error) {\n errorEl.hidden = false;\n errorEl.textContent = error;\n } else {\n errorEl.hidden = true;\n errorEl.textContent = \"\";\n }\n }\n });\n }\n\n private async handleJoin(): Promise<void> {\n clearAuthError();\n await requestSignIn(this.gridStore.apiUrl, this.gridStore.publicKey);\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"panel\">\n <div class=\"watermark\">Popgrids</div>\n <div class=\"actions\">\n <button class=\"join-btn\" type=\"button\">Join the Conversation</button>\n <span class=\"logo\">POPGRIDS</span>\n </div>\n <div class=\"error\" hidden></div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-auth-panel\")) {\n customElements.define(\"pop-auth-panel\", PopAuthPanel);\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD8AAABMCAYAAADa6W+wAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAUuSURBVHgB5ZyBceIwEEX3bq4AOsAdQAdxKggl+Co4rgKcCkgqgFRAUgGkAqACOxVAKvDpg+VRHEmWQSubuTezg8Ega7UrebWS+UG8jIXEQoZCovI9lcd1ciHHUnZCPsrXXflZ7xkISYSshByEFJ5kLWRO54bsHRGdK+dTYZNkQhbUg4aI6FyRoiNBQyQUGLj3jMJYuleNMC4v1gel67Ig/WCq5Qe144+QlM6Wb2QwGNB4PD7JaDQ6veIzKZLj8XiSPM9Pr/v9nna73UnwWUtyIb+FbMgjM3K0QBzHxXq9Lg6HQ3Et2+22WCwWpzJdr1/KjDzRqLiwZDGbzbwobCLLslNDRFEUrAEmTReBVVCxkLRohIsbICLLiA5roxJdAm9zaIAJXUBmKhCtHtraJjAuNHjBgVrcBcDsFhSXoD4NDbB2VTyyFNI7xSUODTB1UX5hKmA+nxd9Bl0AYxGZ3X9wkdWTJCluARjIYv2ULrG6T3eHhabT6SkY4sASFB1aWx23FJ+IULcqm6MBUKbF+rFO+ZQCje6qa6J8jsjQYv2FTvmMAvb1yWRSXePp6anwzWq1cnb9MQXo6yqwthyZ0Q04y9e5/k9F+VjnCpiGCrckDjCtFV51OpZTWN/lo/4Gxqryd7pvCNckTkS/rI7f39/JN5b6j1TltU10d3dHnKjl+7Y8sHhtpS+iHm3f4JyfS2RIytHvMV4ZdMt+1lvhS9OUaSdu5DUuSFk5l60hksoPWv7QK9I1kb/zjU2HRsuHIFQj17FanusWV4fD4i5I5Ye6k8PhkELAqbxlHDn2os9L5Tm6mUX5vBfKy/s7x/U+Pz9Np7q3/GazqY7VaI+j/Br7zpV/e3urjjmiSUvUWJ3QRkHcqAlHzL58g+iUzAmNLxOboGAgur+/rwYkjgnU6+ur6VROXVpezbLA6hw5A9dMTnDlZRoLinPk8CwTmm85vE76PCdIvRn0ympdQL8YGWI6y0GD1atVGzngaePLrmLua8FAaqEaBTsb7bl4fHy0hbTPdB7pv7AmjYtwraZw0eDu6OuRqrTV7T8+PuhWkHGDhUeqWV0qr43+b6XPI4RVAyYNGyHL+odS+Vz3i1tQ/vn5uUlxnPitO/FL+cL3XzEkFAFmWsjRY28eZnKXTKBQBgY3y6xN8pcM+km0O66wlhZiUMJ1lstlY1yB8y335KU2peUOTKRQtvWTyOGJypJv4FGwmlD42zl4Aq6rZnQhFyxnYYBLXb4YEemXpjlx2ENziSBaTaglncT3nhtgTS23nEkyXYEhdl417KJwtfaUrkCrPPbOhEDdqNBS6ZQcd4HbWOkugN0NIWhhfRhpQR4eM/mlHGujPEvq1ysNOXu4tHzaKidPqLO6XPcFrkCnDgIdy/IYUryYiubkEVV5bSwbSnlgW04mBhqVDxnfh16tVZXXhk8hLW9bVCQGemV5y7VyCkAnUR5APEHmezkL9RxeZ4Oey5qab5yUVxcTuXh5eTGd2lMgnkjjepg/c9JmdYWT2FQJjo3BEsusLqPAbHUV4VpMTNPUZvUFBSYxVMT7vvsGxWH1iDpgTYbbDjzg2i6AXBweMSH77C2hjsAUy/psPLwASce2OD4GuqIA2B4hxzRyrrzHbfBb8I2ZGJKODw8PVeJRxujysXDcw/FYOBKWDhFjLuSeAkV1NlJqn125RjLqqJ+bSOk/VVwSEe9fRSzJQx6Om4T8NgLKiunGSMh8O3QR/Damjmn7hyF14KpxKSM6d49IOa/7u6dX6snfPf0DiVL6IWhCmZ4AAAAASUVORK5CYII=\"","export const colors = [\n \"#DDD0BE\",\n \"#E9DCBB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#C6D0CB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#E9DCBB\",\n \"#DFC2C0\",\n \"#CFD4C6\",\n \"#D7E3E8\",\n \"#CFD4C6\",\n \"#D6B3B3\",\n \"#E9DCBB\",\n \"#CFCBDC\",\n \"#BFD6D7\",\n \"#E3D2C6\",\n \"#D1E2E7\",\n \"#D6B3B3\",\n \"#BFD6D7\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#DFC2C0\",\n \"#D1E2E7\",\n \"#CFD4C6\",\n \"#E9DCBB\",\n \"#D7E3E8\",\n \"#CFD4C6\",\n \"#C6D0CB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#E9DCBB\",\n \"#CFCBDC\",\n \"#E3D2C6\",\n \"#E9DCBB\",\n];\n\nexport const sampleColor = (index?: number) => {\n if (typeof index === \"number\") {\n return colors[index % colors.length] ?? \"#e5e7eb\";\n }\n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n/** 32-bit FNV-1a over UTF-8 bytes — deterministic, no lookup table. */\nexport function fnv1a32(data: string): number {\n const bytes = new TextEncoder().encode(data);\n let h = 0x811c9dc5;\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i] ?? 0;\n h ^= byte;\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/** Deterministic background color from a stable string (e.g. user id, org id, slug). */\nexport function backgroundColor(id: string): string {\n return colors[fnv1a32(id) % colors.length] ?? \"#e5e7eb\";\n}\n\n","import deletedUserMarkSrc from \"../assets/popgrids-letter-p.png?inline\";\nimport { backgroundColor, sampleColor } from \"../helpers/color.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n\n --comment-avatar-border-size: 1px;\n --comment-avatar-border-color: var(--color-background, #fff);\n --comment-avatar-size: 32px;\n }\n\n .comment-avatar {\n align-items: center;\n display: flex;\n flex-shrink: 0;\n isolation: isolate;\n justify-content: center;\n position: relative;\n width: calc(var(--comment-avatar-size) + calc(var(--comment-avatar-border-size) * 2));\n height: calc(var(--comment-avatar-size) + calc(var(--comment-avatar-border-size) * 2));\n }\n\n .comment-avatar--size-xs {\n --comment-avatar-size: 32px;\n }\n\n .comment-avatar--size-sm {\n --comment-avatar-size: 56px;\n }\n\n .comment-avatar--size-md {\n --comment-avatar-size: 80px;\n }\n\n .comment-avatar--size-lg {\n --comment-avatar-size: 120px;\n }\n\n .comment-avatar--size-xl {\n --comment-avatar-size: 140px;\n }\n\n .comment-avatar__background {\n background-color: var(--comment-avatar-border-color);\n position: absolute;\n top: 0;\n left: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n }\n\n /**\n * Content\n */\n\n .comment-avatar__content {\n align-items: center;\n background-color: var(--color-surface-bg-default);\n display: flex;\n justify-content: center;\n overflow: hidden;\n position: relative;\n height: var(--comment-avatar-size);\n width: var(--comment-avatar-size);\n z-index: 20;\n\n /* Initials styling */\n font-family: Inter, sans-serif;\n font-weight: 600;\n color: #374151;\n font-size: calc(var(--comment-avatar-size) * 0.35);\n line-height: 1;\n }\n\n .comment-avatar__content::slotted(img) {\n -webkit-user-drag: none;\n align-self: stretch;\n flex: 1 0 0;\n height: var(--comment-avatar-size);\n object-fit: cover;\n pointer-events: none;\n position: absolute;\n user-select: none;\n width: var(--comment-avatar-size);\n }\n\n .comment-avatar__deleted-mark {\n -webkit-user-drag: none;\n bottom: -3px;\n height: auto;\n left: 0;\n object-fit: cover;\n pointer-events: none;\n position: absolute;\n user-select: none;\n width: 100%;\n transform: scale(0.57);\n }\n`);\n\nexport class PopCommentAvatar extends BaseElement {\n private _backgroundColor: string;\n\n constructor() {\n super();\n this._backgroundColor = sampleColor() ?? \"#e5e7eb\";\n }\n\n static get observedAttributes() {\n return [\"size\", \"data-color-key\", \"deleted\"];\n }\n\n onSizeChanged() {\n this.render();\n }\n\n onDataColorKeyChanged() {\n this.render();\n }\n\n onDeletedChanged() {\n this.render();\n }\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n get size(): string {\n return this.getAttribute(\"size\") || \"md\";\n }\n\n set size(value: string) {\n this.setAttribute(\"size\", value);\n }\n\n get deleted(): boolean {\n return this.hasAttribute(\"deleted\");\n }\n\n set deleted(value: boolean) {\n if (value) {\n this.setAttribute(\"deleted\", \"\");\n } else {\n this.removeAttribute(\"deleted\");\n }\n }\n\n protected getTemplate(): string {\n const size = this.size;\n const deleted = this.deleted;\n const key = this.getAttribute(\"data-color-key\");\n const bg = deleted\n ? \"var(--pop-muted-foreground, #e5e7eb)\"\n : key\n ? backgroundColor(key)\n : this._backgroundColor;\n\n const content = deleted\n ? `<div\n class=\"comment-avatar__content mask mask-squircle\"\n part=\"content\"\n style=\"background-color: ${bg}; opacity: 0.15\"\n ><img class=\"comment-avatar__deleted-mark\" src=\"${deletedUserMarkSrc}\" alt=\"Deleted user\" /></div>`\n : `<slot\n class=\"comment-avatar__content mask mask-squircle\"\n part=\"content\"\n style=\"background-color: ${bg};\"\n ></slot>`;\n\n return /* html */ `\n <div class=\"comment-avatar comment-avatar--size-${size}\" part=\"base\">\n <div class=\"comment-avatar__background mask mask-squircle\" part=\"background\"></div>\n ${content}\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-avatar\")) {\n customElements.define(\"pop-comment-avatar\", PopCommentAvatar);\n}\n","export function getInitials(name: string | null | undefined): string {\n if (!name) return \"?\";\n return name\n .split(\" \")\n .map((p) => p[0] ?? \"\")\n .join(\"\")\n .toUpperCase()\n .slice(0, 2);\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { currentUser } from \"../store/auth-store.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\nimport type { PopCommentInput } from \"./pop-comment-input.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n background: var(--pop-background);\n border-top: 1px solid var(--pop-bar-input-bg);\n display: block;\n padding: 6px;\n position: relative;\n\n --pop-bar-avatar-bg: #e5e7eb;\n --pop-bar-avatar-color: #374151;\n --pop-bar-avatar-border: #ffffff;\n --pop-bar-input-bg: rgba(0, 0, 32, 0.04);\n --pop-bar-send-hover: rgba(0, 0, 32, 0.06);\n --pop-bar-send-color: #000000;\n --pop-bar-watermark: rgba(0, 0, 32, 0.1);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-bar-avatar-bg: #1f2937;\n --pop-bar-avatar-color: #d1d5db;\n --pop-bar-avatar-border: var(--pop-popover, #151d2a);\n --pop-bar-input-bg: rgba(255, 255, 255, 0.05);\n --pop-bar-send-hover: rgba(255, 255, 255, 0.08);\n --pop-bar-send-color: #ffffff;\n --pop-bar-watermark: rgba(255, 255, 255, 0.1);\n }\n }\n\n :host(.dark) {\n --pop-bar-avatar-bg: #1f2937;\n --pop-bar-avatar-color: #d1d5db;\n --pop-bar-avatar-border: var(--pop-popover, #151d2a);\n --pop-bar-input-bg: rgba(255, 255, 255, 0.05);\n --pop-bar-send-hover: rgba(255, 255, 255, 0.08);\n --pop-bar-send-color: #ffffff;\n --pop-bar-watermark: rgba(255, 255, 255, 0.1);\n }\n\n .bar {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .bar__user {\n display: flex;\n align-items: center;\n align-self: flex-start;\n flex-shrink: 0;\n padding-top: 2px;\n }\n\n .bar__avatar {\n flex-shrink: 0;\n --comment-avatar-border-size: 0px;\n }\n\n .bar__avatar--reply {\n margin-right: -4px;\n z-index: 1;\n }\n\n .bar__avatar--user {\n z-index: 2;\n }\n\n .bar__user.has-reply .bar__avatar--user {\n --comment-avatar-border-size: 2px;\n --comment-avatar-border-color: var(--pop-bar-avatar-border);\n }\n\n .bar__input-wrap {\n flex: 1;\n min-width: 0;\n background: var(--pop-bar-input-bg);\n border-radius: 18px;\n overflow: hidden;\n display: flex;\n align-items: flex-end;\n padding: 4px 8px 4px 12px;\n max-height: 280px;\n }\n\n .bar__send {\n align-items: center;\n align-self: flex-end;\n background: none;\n border: none;\n cursor: pointer;\n display: flex;\n justify-content: center;\n padding-bottom: 2px;\n }\n\n .logo-watermark {\n position: absolute;\n top: -16px;\n left: 8px;\n font-family: Inter, sans-serif;\n font-size: 8px;\n font-weight: 700;\n letter-spacing: 1px;\n color: var(--pop-bar-watermark);\n text-transform: uppercase;\n border-radius: 9999px;\n padding: 2px 6px;\n pointer-events: none;\n user-select: none;\n }\n`);\n\nconst LOGO_WATERMARK_SVG = `<svg width=\"64\" height=\"11\" viewBox=\"0 0 64 11\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3.91111 0C0.892839 0 0 2.11357 0 4.77714C0 5.76321 0.0987654 6.73357 0.213333 7.70786C0.25679 8.08893 0.240988 8.50929 0.312099 8.89036C0.497778 9.89214 1.44593 10.3557 2.36642 10.3557C3.62667 10.3557 4.4642 9.56607 4.4642 8.30107C4.4642 7.57036 4.22321 7.09107 3.5279 6.80821C3.48444 6.7925 3.44099 6.78071 3.44099 6.72179C3.44099 6.62357 3.59901 6.55286 3.69778 6.55286C4.03753 6.55286 4.57481 6.89071 5.04494 6.89071C6.88593 6.89071 7.90519 5.13071 7.90519 3.48071C7.90519 1.08429 6.13136 0 3.91111 0ZM3.89531 5.18179C3.78074 5.18179 3.68198 5.08357 3.68198 4.96964C3.68198 4.81643 3.89531 4.7025 3.96642 4.57679C4.12049 4.29393 4.16395 3.81464 4.16395 3.4925C4.16395 3.11143 4.06519 2.40821 3.8242 2.12536C3.75309 2.04286 3.65432 1.99964 3.65432 1.88571C3.65432 1.77179 3.76889 1.67357 3.87951 1.67357C4.36148 1.67357 4.60247 3.08393 4.60247 3.44929C4.60247 3.84214 4.47605 5.18179 3.89531 5.18179Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M12.7368 0.239637C9.73433 0.239637 7.93285 2.35321 7.93285 5.25249C7.93285 8.15178 9.73038 10.2654 12.7368 10.2654C15.7432 10.2654 17.5249 8.12428 17.5249 5.25249C17.5249 2.38071 15.7116 0.239637 12.7368 0.239637ZM12.8672 8.83142C12.8198 8.89035 12.7249 9.00035 12.6104 9.00035C12.4958 9.00035 12.3852 8.90214 12.3852 8.78821C12.3852 8.74499 12.7526 8.19499 12.8119 8.02607C13.037 7.36214 13.0805 6.64321 13.0805 5.93999C13.0805 4.99714 12.9106 3.78321 12.3299 3.00928C12.2153 2.86785 11.8637 2.60071 11.8637 2.44749C11.8637 2.33357 11.9625 2.23535 12.077 2.23535C12.1758 2.23535 12.2746 2.32178 12.3457 2.37678C13.2504 3.12321 13.523 4.82821 13.523 5.93999C13.523 6.81214 13.4874 8.08499 12.8711 8.82749L12.8672 8.83142Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M21.6533 0C18.6351 0 17.7422 2.11357 17.7422 4.77714C17.7422 5.76321 17.841 6.73357 17.9555 7.70786C17.999 8.08893 17.9832 8.50929 18.0543 8.89036C18.24 9.89214 19.1881 10.3557 20.1086 10.3557C21.3689 10.3557 22.2064 9.56607 22.2064 8.30107C22.2064 7.57036 21.9654 7.09107 21.2701 6.80821C21.2267 6.7925 21.1832 6.78071 21.1832 6.72179C21.1832 6.62357 21.3412 6.55286 21.44 6.55286C21.7797 6.55286 22.317 6.89071 22.7871 6.89071C24.6281 6.89071 25.6474 5.13071 25.6474 3.48071C25.6474 1.08429 23.8775 0 21.6533 0ZM21.6415 5.18179C21.5269 5.18179 21.4281 5.08357 21.4281 4.96964C21.4281 4.81643 21.6415 4.7025 21.7126 4.57679C21.8667 4.29393 21.9101 3.81464 21.9101 3.4925C21.9101 3.11143 21.8113 2.40821 21.5704 2.12536C21.4992 2.04286 21.4005 1.99964 21.4005 1.88571C21.4005 1.77179 21.5151 1.67357 21.6257 1.67357C22.1076 1.67357 22.3486 3.08393 22.3486 3.44929C22.3486 3.84214 22.2222 5.18179 21.6415 5.18179Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M31.9012 4.16822C30.882 4.16822 29.4637 4.6318 29.4637 5.84572C29.4637 6.53715 29.9733 7.56251 30.7832 7.56251C31.2929 7.56251 31.6208 7.16965 31.7906 7.16965C31.8341 7.16965 31.8736 7.19715 31.8736 7.24037C31.8736 7.64894 31.0795 7.83358 30.7674 7.83358C29.677 7.83358 29.0963 6.90251 29.0963 5.91644C29.0963 4.70644 30.242 3.77537 31.4035 3.77537C31.7432 3.77537 32.0988 3.87358 32.4385 3.87358C33.4459 3.87358 34.165 2.97394 34.165 2.01537C34.165 0.424295 32.2687 0.0589382 31.0045 0.0589382C27.6464 0.0589382 25.6909 2.22751 25.6909 5.52358C25.6909 8.56822 27.279 10.5089 30.4237 10.5089C32.4622 10.5089 34.6864 9.6368 34.6864 7.26787C34.6864 5.6493 33.6237 4.16822 31.8973 4.16822H31.9012Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M41.2681 6.56464C41.0113 6.56464 40.802 6.66286 40.5886 6.66286C40.5452 6.66286 40.5333 6.61964 40.5333 6.59214C40.5333 6.49393 40.5768 6.45071 40.6479 6.42321C40.8889 6.34071 41.1457 6.28179 41.3827 6.16786C42.4612 5.66107 43.0973 4.7575 43.0973 3.56321C43.0973 1.40643 41.2405 0.0982143 39.202 0.0982143C38.4632 0.0982143 37.7442 0.310357 37.12 0.648214C35.4212 1.56357 35.0933 2.87571 34.9946 4.66321C34.9511 5.36643 34.9511 6.07357 34.9511 6.77679V8.48179C34.9511 9.55036 35.6583 10.4107 36.7763 10.4107C37.5822 10.4107 38.3052 9.83321 38.4909 9.07107C38.5896 8.61929 38.5343 8.085 38.5343 7.64893C38.5343 7.60571 38.5501 7.59393 38.5896 7.59393C38.6291 7.59393 38.6765 7.62143 38.7042 7.63714C39.202 8.83536 39.8815 10.3557 41.4222 10.3557C42.4849 10.3557 43.362 9.60929 43.362 8.525C43.362 7.44071 42.3427 6.56857 41.2642 6.56857L41.2681 6.56464ZM38.961 5.18179C38.8464 5.18179 38.7476 5.08357 38.7476 4.96964C38.7476 4.81643 38.961 4.7025 39.0321 4.57679C39.1862 4.29393 39.2296 3.81464 39.2296 3.4925C39.2296 3.11143 39.1309 2.40821 38.8899 2.12536C38.8188 2.04286 38.7358 1.99964 38.7358 1.88571C38.7358 1.77179 38.8346 1.67357 38.9491 1.67357C39.4311 1.67357 39.6721 3.08393 39.6721 3.44929C39.6721 3.84214 39.5575 5.18179 38.9649 5.18179H38.961Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M46.7674 0.549991C46.4277 0.326063 45.9457 0.212134 45.5348 0.212134C44.642 0.212134 43.8756 0.915349 43.7768 1.79142C43.7491 2.04678 43.761 2.28642 43.761 2.55356V4.94606L43.7175 7.46821V8.72142C43.7175 9.70749 44.5669 10.4814 45.5467 10.4814C46.2696 10.4814 47.0637 10.0296 47.3324 9.35392C47.4864 8.97285 47.5022 8.43856 47.5022 8.02999V6.92999L47.518 4.73392V2.53785C47.518 1.72071 47.5022 1.07249 46.7674 0.549991Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M50.2993 0.125713C48.8533 0.125713 48.1304 0.801428 48.1304 2.25107V2.82857L48.1462 3.96786V4.54536C48.1462 4.98143 48.1462 5.39 48.1304 5.82607C48.1027 6.34857 48.0316 6.86714 48.0316 7.40536C48.0316 9.3775 49.0509 10.3361 51.0222 10.3361C54.0523 10.3361 56.1067 9.03964 56.1067 5.81429C56.1067 1.925 54.2222 0.121785 50.2993 0.121785V0.125713ZM51.6583 7.91607C51.5437 7.91607 51.4449 7.81786 51.4449 7.70393C51.4449 7.66071 51.4608 7.83352 51.4884 7.59C51.8558 6.985 51.9546 6.14036 51.9546 5.44893C51.9546 4.80071 51.8835 3.84214 51.4726 3.33536C51.4015 3.22143 51.2593 3.13893 51.2593 2.9975C51.2593 2.88357 51.358 2.78536 51.4726 2.78536C51.6859 2.78536 51.9822 3.31964 52.0691 3.50428C52.3378 4.125 52.3812 4.80071 52.3812 5.46071C52.3812 5.86928 52.1679 7.91214 51.6583 7.91214V7.91607Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M62.7239 5.1268C61.9022 5.05608 60.7249 4.77322 60.0889 4.23894C60.0059 4.16822 59.8637 4.07001 59.8637 3.9443C59.8637 3.90108 59.8795 3.83037 59.9348 3.83037C60.0889 3.83037 61.0805 4.62001 61.9338 4.62001C63.0123 4.62001 64 3.78715 64 2.69108C64 0.887867 61.5941 0.157152 60.1324 0.157152C57.9635 0.157152 56.3516 1.5518 56.3516 3.76358C56.3516 4.24287 56.4227 4.90287 56.7783 5.27215C56.9482 5.4568 57.2326 5.4568 57.4578 5.4568C58.3072 5.4568 59.3857 5.72394 59.836 6.49787C59.8795 6.56858 59.919 6.68251 59.919 6.76501C59.919 6.79251 59.919 6.83572 59.8914 6.82001C59.8084 6.79251 59.7373 6.7218 59.678 6.6668C59.1802 6.18751 58.5007 5.70822 57.7817 5.70822C56.7032 5.70822 56.324 6.73751 56.324 7.63715C56.324 9.45215 57.9674 10.4539 59.6385 10.4539C61.6217 10.4539 64 9.15751 64 6.94572C64 6.12858 63.6444 5.21322 62.7239 5.13072V5.1268Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n</svg>`;\n\nexport class PopCommentBar extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".bar__send\")) return;\n void this.handleSend();\n }\n\n protected setupEffects() {\n let lastReplyingTo: string | null = null;\n let lastEditingCommentId: string | null = null;\n\n this.addEffect(() => {\n const parentCommentId = this.gridStore.replyingTo.value;\n\n if (parentCommentId && parentCommentId !== lastReplyingTo) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n setTimeout(() => input.focus(), 0);\n }\n }\n lastReplyingTo = parentCommentId;\n });\n\n this.addEffect(() => {\n const editingComment = this.gridStore.editingComment.value;\n if (editingComment && editingComment.id !== lastEditingCommentId) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n input.setValue(editingComment.body);\n setTimeout(() => input.focus(), 0);\n }\n } else if (!editingComment && lastEditingCommentId) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n input.clear();\n }\n }\n lastEditingCommentId = editingComment?.id ?? null;\n });\n\n this.addEffect(() => {\n const user = currentUser.value;\n const barUser = this.getElement<HTMLDivElement>(\".bar__user\");\n if (!barUser) return;\n\n const parentComment = this.gridStore.replyingToComment.value;\n const parentAuthor = parentComment?.author;\n const editingComment = this.gridStore.editingComment.value;\n\n if (editingComment) {\n barUser.classList.remove(\"has-reply\");\n const userColorKey = user?.id ?? user?.name ?? \"\";\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n barUser.innerHTML = userAvatarHtml;\n } else if (parentAuthor) {\n barUser.classList.add(\"has-reply\");\n\n const parentColorKey = parentAuthor.id ?? parentAuthor.name ?? \"\";\n const userColorKey = user?.id ?? user?.name ?? \"\";\n\n const parentAvatarHtml = parentAuthor.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--reply\" data-color-key=\"${parentColorKey}\"><img src=\"${parentAuthor.image}\" alt=\"${parentAuthor.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--reply\" data-color-key=\"${parentColorKey}\">${getInitials(parentAuthor.name)}</pop-comment-avatar>`;\n\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n\n barUser.innerHTML = parentAvatarHtml + userAvatarHtml;\n } else {\n barUser.classList.remove(\"has-reply\");\n\n const userColorKey = user?.id ?? user?.name ?? \"\";\n\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n\n barUser.innerHTML = userAvatarHtml;\n }\n });\n }\n\n private async handleSend(): Promise<void> {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (!input) return;\n\n const body = input.getValue().trim();\n if (!body) return;\n\n const editingId = this.gridStore.editingCommentId.value;\n if (editingId) {\n input.clear();\n this.gridStore.editingCommentId.value = null;\n await this.gridStore.editComment(editingId, body);\n } else {\n input.clear();\n const comment = await this.gridStore.postComment(\n body,\n this.gridStore.replyingTo.value ?? undefined,\n );\n this.gridStore.replyingTo.value = null;\n\n if (comment) {\n this.gridStore.scrollingCommentId.value = comment.id;\n }\n }\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"logo-watermark\">${LOGO_WATERMARK_SVG}</div>\n <div class=\"bar\">\n <div class=\"bar__user\">\n <pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\">?</pop-comment-avatar>\n </div>\n <div class=\"bar__input-wrap\">\n <pop-comment-input></pop-comment-input>\n </div>\n <button class=\"bar__send\" type=\"button\" aria-label=\"Send comment\">\n <pop-comment-icon theme=\"neutral\" variant=\"send\"></pop-comment-icon>\n </button>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-bar\")) {\n customElements.define(\"pop-comment-bar\", PopCommentBar);\n}\n","import { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n /* Mode-level theme colors (defaults for light mode) */\n --pop-comment-color-black: #000000;\n --pop-comment-color-white: #ffffff;\n --pop-comment-color-default: #000000;\n --pop-comment-color-reversed: #ffffff;\n --pop-comment-bg-singular-resting: #121926;\n --pop-comment-bg-singular-hover: rgba(0, 0, 32, 0.08);\n --pop-comment-bg-reversed: #121926;\n --pop-comment-bg-blank-resting: #ffffff;\n\n display: flex;\n\n --pop-comment-icon-scale: 1;\n --pop-comment-icon-scale-hover: 1.1875;\n --pop-comment-icon-scale-active: 0.9375;\n --pop-comment-icon-size: 32px;\n --pop-comment-icon-color: var(--pop-foreground, #000000);\n --pop-comment-icon-color-hover: var(--pop-foreground, #000000);\n --pop-comment-icon-color-active: var(--pop-foreground, #000000);\n --pop-comment-icon-color-focused: var(--pop-foreground, #000000);\n --pop-comment-icon-background: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-hover: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-active: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-focused: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n /* Overrides for dark mode */\n --pop-comment-color-black: #ffffff;\n --pop-comment-color-white: #000000;\n --pop-comment-color-default: #ffffff;\n --pop-comment-color-reversed: #000000;\n --pop-comment-bg-singular-resting: #ffffff;\n --pop-comment-bg-singular-hover: rgba(255, 255, 255, 0.15);\n --pop-comment-bg-reversed: #ffffff;\n --pop-comment-bg-blank-resting: #121926;\n }\n }\n\n :host(.dark) {\n /* Overrides for dark mode (.dark class on host) */\n --pop-comment-color-black: #ffffff;\n --pop-comment-color-white: #000000;\n --pop-comment-color-default: #ffffff;\n --pop-comment-color-reversed: #000000;\n --pop-comment-bg-singular-resting: #ffffff;\n --pop-comment-bg-singular-hover: rgba(255, 255, 255, 0.15);\n --pop-comment-bg-reversed: #ffffff;\n --pop-comment-bg-blank-resting: #121926;\n }\n\n .comment-icon {\n align-items: center;\n background: transparent;\n border: none;\n display: inline-flex;\n height: var(--pop-comment-icon-size);\n justify-content: center;\n padding: 0;\n position: relative;\n transform-origin: center;\n width: var(--pop-comment-icon-size);\n }\n\n .comment-icon--size-sm {\n --pop-comment-icon-size: 24px;\n }\n\n .comment-icon:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .comment-icon__focus-indicator {\n display: none;\n height: calc(100% + 3px);\n inset: -1.5px;\n transform-origin: center;\n transform: scale(var(--pop-comment-icon-scale));\n transition: all 200ms ease-out;\n width: calc(100% + 3px);\n }\n\n .comment-icon:focus-visible .comment-icon__focus-indicator {\n display: flex;\n }\n\n .comment-icon:focus-visible {\n outline: none;\n }\n\n .comment-icon__inner {\n align-items: center;\n background: var(--pop-comment-icon-background);\n color: var(--pop-comment-icon-color);\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n height: var(--pop-comment-icon-size);\n justify-content: center;\n position: absolute;\n transform-origin: center;\n transition: all 200ms ease-out;\n transform: scale(var(--pop-comment-icon-scale));\n width: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon-container {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n transition: transform ease-out 150ms;\n width: 100%;\n }\n\n .comment-icon__icon-container svg {\n width: calc(var(--pop-comment-icon-size) * 0.6875);\n height: calc(var(--pop-comment-icon-size) * 0.6875);\n }\n\n .comment-icon--variant-close.comment-icon--theme-neutral .comment-icon__icon-container svg {\n width: var(--pop-comment-icon-size);\n height: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon-image {\n display: flex;\n width: var(--pop-comment-icon-size);\n height: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon {\n display: flex;\n }\n\n .comment-icon__icon-image + .comment-icon__icon {\n display: none;\n }\n\n @media (hover: hover) and (pointer: fine) {\n .comment-icon:hover .comment-icon__inner {\n background: var(--pop-comment-icon-background-hover);\n color: var(--pop-comment-icon-color-hover);\n transition: transform var(--pop-ease-pop-hover) var(--pop-duration-pop-hover);\n transform: scale(var(--pop-comment-icon-scale-hover));\n }\n\n .comment-icon:hover .comment-icon__icon-image {\n display: none;\n }\n\n .comment-icon:hover .comment-icon__icon-image + .comment-icon__icon {\n display: flex;\n }\n }\n\n .comment-icon:active .comment-icon__inner {\n background: var(--pop-comment-icon-background-active);\n color: var(--pop-comment-icon-color-active);\n transform: scale(var(--pop-comment-icon-scale-active));\n transition-duration: 100ms;\n }\n\n .comment-icon:is(:focus-visible) .comment-icon__inner {\n background: var(--pop-comment-icon-background-focused);\n color: var(--pop-comment-icon-color-focused);\n }\n\n /* Brand / Add */\n .comment-icon--theme-brand.comment-icon--variant-add {\n --pop-comment-icon-color: var(--pop-comment-color-black);\n --pop-comment-icon-color-hover: var(--pop-comment-color-black);\n --pop-comment-icon-color-active: var(--pop-comment-color-black);\n --pop-comment-icon-color-focused: var(--pop-comment-color-black);\n --pop-comment-icon-background: transparent;\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-focused: transparent;\n }\n\n /* Brand / Close */\n .comment-icon--theme-brand.comment-icon--variant-close {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-white);\n --pop-comment-icon-color-active: var(--pop-comment-color-white);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Add */\n .comment-icon--theme-neutral.comment-icon--variant-add {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-black);\n --pop-comment-icon-color-active: var(--pop-comment-color-black);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Close */\n .comment-icon--theme-neutral.comment-icon--variant-close {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-white);\n --pop-comment-icon-color-active: var(--pop-comment-color-white);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Send */\n .comment-icon--theme-neutral.comment-icon--variant-send {\n --pop-comment-icon-color: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-hover: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-active: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-focused: var(--pop-comment-color-reversed);\n --pop-comment-icon-background: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-active: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-reversed);\n }\n\n /* Neutral / More */\n .comment-icon--theme-neutral.comment-icon--variant-more {\n --pop-comment-icon-color: var(--pop-comment-color-default);\n --pop-comment-icon-color-hover: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-active: var(--pop-comment-color-default);\n --pop-comment-icon-color-focused: var(--pop-comment-color-default);\n --pop-comment-icon-background: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-active: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-blank-resting);\n }\n\n /* Neutral / Cancel */\n .comment-icon--theme-neutral.comment-icon--variant-cancel {\n --pop-comment-icon-color: var(--pop-comment-color-default);\n --pop-comment-icon-color-hover: var(--pop-comment-color-default);\n --pop-comment-icon-color-active: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-focused: var(--pop-comment-color-default);\n --pop-comment-icon-background: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-blank-resting);\n }\n`);\n\nexport class PopCommentIcon extends BaseElement {\n protected get styleSheets() {\n return [localSheet];\n }\n\n static get observedAttributes() {\n return [\"counter\", \"icon-url\", \"size\", \"theme\", \"variant\", \"type\", \"disabled\"];\n }\n\n onCounterChanged() {\n this.render();\n }\n\n onIconUrlChanged() {\n this.render();\n }\n\n onSizeChanged() {\n this.render();\n }\n\n onThemeChanged() {\n this.render();\n }\n\n onVariantChanged() {\n this.render();\n }\n\n onTypeChanged() {\n this.render();\n }\n\n onDisabledChanged() {\n this.render();\n }\n\n get counter(): number {\n return Number(this.getAttribute(\"counter\") || \"0\");\n }\n\n set counter(value: number) {\n this.setAttribute(\"counter\", String(value));\n }\n\n get iconUrl(): string | undefined {\n return this.getAttribute(\"icon-url\") || undefined;\n }\n\n set iconUrl(value: string | undefined) {\n if (value === undefined) {\n this.removeAttribute(\"icon-url\");\n } else {\n this.setAttribute(\"icon-url\", value);\n }\n }\n\n get size(): string {\n return this.getAttribute(\"size\") || \"md\";\n }\n\n set size(value: string) {\n this.setAttribute(\"size\", value);\n }\n\n get theme(): \"brand\" | \"neutral\" {\n return (this.getAttribute(\"theme\") as \"brand\" | \"neutral\") || \"brand\";\n }\n\n set theme(value: \"brand\" | \"neutral\") {\n this.setAttribute(\"theme\", value);\n }\n\n get variant(): \"add\" | \"close\" | \"filter\" | \"more\" | \"send\" | \"cancel\" {\n return (this.getAttribute(\"variant\") as any) || \"add\";\n }\n\n set variant(value: \"add\" | \"close\" | \"filter\" | \"more\" | \"send\" | \"cancel\") {\n this.setAttribute(\"variant\", value);\n }\n\n get type(): \"button\" | \"submit\" | \"reset\" | \"menu\" {\n return (this.getAttribute(\"type\") as any) || \"button\";\n }\n\n set type(value: \"button\" | \"submit\" | \"reset\" | \"menu\") {\n this.setAttribute(\"type\", value);\n }\n\n get disabled(): boolean {\n return this.hasAttribute(\"disabled\");\n }\n\n set disabled(value: boolean) {\n if (value) {\n this.setAttribute(\"disabled\", \"\");\n } else {\n this.removeAttribute(\"disabled\");\n }\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: Event) {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n this.emit(\"pop-click\");\n }\n\n get icon(): string {\n let icon = \"\";\n\n if (this.theme === \"brand\") {\n if (this.variant === \"add\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11 4.58331V17.4166M4.58333 11H17.4167\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"close\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M16.5 5.5L5.5 16.5M5.5 5.5L16.5 16.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n } else if (this.theme === \"neutral\") {\n if (this.variant === \"add\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.0002 4.58301V17.4163M4.5835 10.9997H17.4168\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"close\") {\n icon = `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.4628 11.4627L20.5373 20.5373M11.4628 20.5373L20.5373 11.4627\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"more\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12.8335 16.5L7.3335 11L12.8335 5.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"send\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M18.0394 3.68048C18.2139 3.61601 18.3837 3.78583 18.3193 3.96036L12.3858 20.0241C12.314 20.2185 12.0369 20.2123 11.9739 20.0149L9.89172 13.4908C9.86908 13.4199 9.88424 13.3423 9.93191 13.2851L14.4838 7.82287C14.6536 7.61906 14.3807 7.34616 14.1769 7.516L8.71467 12.0678C8.65746 12.1155 8.57987 12.1307 8.50893 12.108L1.98489 10.0259C1.78743 9.96287 1.78121 9.68575 1.97565 9.61393L18.0394 3.68048Z\"\n fill=\"currentColor\"\n />\n </svg>\n `;\n } else if (this.variant === \"cancel\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M16.5 5.5L5.5 16.5M5.5 5.5L16.5 16.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n }\n return icon;\n }\n\n protected getTemplate(): string {\n const disabledAttr = this.disabled ? \"disabled\" : \"\";\n const classes = [\n \"comment-icon\",\n this.size ? `comment-icon--size-${this.size}` : \"\",\n this.theme ? `comment-icon--theme-${this.theme}` : \"\",\n this.variant ? `comment-icon--variant-${this.variant}` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n const iconHtml = this.iconUrl\n ? `<img src=\"${this.iconUrl}\" alt=\"\" class=\"comment-icon__icon-image\" />\n <slot class=\"comment-icon__icon\" name=\"icon\">${this.icon}</slot>`\n : `<slot class=\"comment-icon__icon\" name=\"icon\">${this.icon}</slot>`;\n\n return /* html */ `\n <button\n class=\"${classes}\"\n part=\"base\"\n type=\"${this.type}\"\n ${disabledAttr}\n >\n <pop-focus-indicator class=\"comment-icon__focus-indicator\"></pop-focus-indicator>\n <div class=\"comment-icon__inner mask mask-squircle\">\n <div class=\"comment-icon__icon-container\" part=\"icon\">${iconHtml}</div>\n </div>\n </button>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-icon\")) {\n customElements.define(\"pop-comment-icon\", PopCommentIcon);\n}\n","import { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: flex;\n flex: 1;\n min-width: 0;\n align-items: flex-end;\n }\n\n textarea {\n flex: 1;\n min-width: 0;\n background: none;\n border: none;\n outline: none;\n resize: none;\n font-family: Inter, sans-serif;\n font-size: 13px;\n color: black;\n line-height: 18px;\n padding: 5px 0;\n max-height: 200px;\n overflow-y: auto;\n width: 100%;\n letter-spacing: -0.08px;\n }\n\n textarea::placeholder {\n color: #697586;\n }\n`);\n\nexport class PopCommentInput extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n input: \"onInput\",\n keydown: \"onKeyDown\",\n };\n\n protected onInput(event: Event) {\n const textarea = event.target as HTMLTextAreaElement;\n textarea.style.height = \"auto\";\n textarea.style.height = `${textarea.scrollHeight}px`;\n }\n\n protected onKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n if (this.gridStore.editingCommentId.value || this.gridStore.replyingTo.value) {\n event.stopPropagation();\n this.gridStore.editingCommentId.value = null;\n this.gridStore.replyingTo.value = null;\n }\n }\n }\n\n getValue(): string {\n return this.getElement<HTMLTextAreaElement>(\"textarea\")?.value ?? \"\";\n }\n\n setValue(val: string): void {\n const textarea = this.getElement<HTMLTextAreaElement>(\"textarea\");\n if (!textarea) return;\n\n textarea.value = val;\n textarea.style.height = \"auto\";\n textarea.style.height = `${textarea.scrollHeight}px`;\n }\n\n clear(): void {\n const textarea = this.getElement<HTMLTextAreaElement>(\"textarea\");\n if (!textarea) return;\n\n textarea.value = \"\";\n textarea.style.height = \"auto\";\n }\n\n focus(): void {\n this.getElement<HTMLTextAreaElement>(\"textarea\")?.focus();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const parent = this.gridStore.replyingToComment.value;\n const editing = this.gridStore.editingComment.value;\n\n let placeholder = \"Comment\";\n if (editing) {\n placeholder = \"Edit comment...\";\n } else if (parent?.author?.name) {\n placeholder = `Reply to ${parent.author.name}`;\n }\n\n this.setAttr(\"textarea\", \"placeholder\", placeholder);\n });\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <textarea rows=\"1\" placeholder=\"Comment\"></textarea>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-input\")) {\n customElements.define(\"pop-comment-input\", PopCommentInput);\n}\n","import { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n\n --pop-thread-link: rgba(0, 0, 32, 0.5);\n --pop-thread-link-hover: rgba(0, 0, 32, 0.8);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-thread-link: rgba(255, 255, 255, 0.5);\n --pop-thread-link-hover: rgba(255, 255, 255, 0.8);\n }\n }\n\n :host(.dark) {\n --pop-thread-link: rgba(255, 255, 255, 0.5);\n --pop-thread-link-hover: rgba(255, 255, 255, 0.8);\n }\n\n .thread {\n align-items: stretch;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .thread__replies {\n align-items: center;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-left: 24px;\n }\n\n .thread__more {\n display: flex;\n align-items: center;\n font-size: 13px;\n gap: 6px;\n padding-left: 30px;\n transition: opacity 0.15s ease;\n width: 100%;\n }\n\n .thread__more:hover {\n opacity: 1;\n }\n\n .thread__more-dot {\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--pop-muted-foreground);\n flex-shrink: 0;\n opacity: 0.1;\n }\n`);\n\nconst COLLAPSED_REPLY_LIMIT = 2;\n\nexport class PopCommentThread extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n private _showAll = false;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".thread__more-btn\")) return;\n this._showAll = true;\n this.render();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const commentId = this.getAttribute(\"comment-id\");\n const targetId = this.gridStore.scrollingCommentId.value;\n if (commentId && targetId) {\n const replies = this.gridStore.repliesFor(commentId);\n if (replies.some((r) => r.id === targetId)) {\n this._showAll = true;\n }\n }\n\n this.gridStore.comments.value;\n this.render();\n });\n }\n\n protected getTemplate(): string {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return \"\";\n\n const replies = this.gridStore.repliesFor(commentId);\n const visibleReplies =\n this._showAll || replies.length <= COLLAPSED_REPLY_LIMIT\n ? replies\n : replies.slice(0, COLLAPSED_REPLY_LIMIT);\n const hiddenCount = replies.length - visibleReplies.length;\n\n const moreHtml =\n hiddenCount > 0\n ? `<div class=\"thread__more\">\n <div class=\"thread__more-dot\"></div>\n <button class=\"thread__more-btn btn-link btn-link--size-sm btn-link--theme-default\" type=\"button\">\n Show ${hiddenCount} more ${hiddenCount === 1 ? \"reply\" : \"replies\"}\n </button>\n </div>`\n : \"\";\n\n const repliesHtml =\n replies.length > 0\n ? `<div class=\"thread__replies\">\n ${visibleReplies\n .map((reply) => `<pop-comment comment-id=\"${reply.id}\"></pop-comment>`)\n .join(\"\")}\n ${moreHtml}\n </div>`\n : \"\";\n\n return /* html */ `\n <div class=\"thread\">\n <pop-comment comment-id=\"${commentId}\"></pop-comment>\n ${repliesHtml}\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-thread\")) {\n customElements.define(\"pop-comment-thread\", PopCommentThread);\n}\n","export function timeAgo(date: Date | string | number): string {\n const d = date instanceof Date ? date : new Date(date);\n const seconds = (Date.now() - d.getTime()) / 1000;\n\n if (seconds < 1) return \"now\";\n if (seconds < 60) return `${Math.floor(seconds)}s`;\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;\n if (seconds < 604800) return `${Math.floor(seconds / 86400)}d`;\n return `${Math.floor(seconds / 604800)}w`;\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { timeAgo } from \"../helpers/time.js\";\nimport { currentUser } from \"../store/auth-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\nimport { computePosition, autoUpdate, flip, offset, shift } from \"@floating-ui/dom\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n width: 100%;\n --pop-comment-hover: rgba(0, 0, 32, 0.04);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-comment-hover: rgba(255, 255, 255, 0.04);\n }\n }\n\n .comment {\n display: flex;\n width: 100%;\n gap: 8px;\n align-items: center;\n background-color: transparent;\n border: none;\n padding: 0;\n border-radius: var(--pop-radius-md);\n outline: 6px solid transparent;\n text-align: left;\n transition:\n background-color 150ms ease,\n outline-color 150ms ease;\n }\n\n :host([data-size=\"sm\"]) .comment,\n :host:not([data-size]) .comment {\n --avatar-size: 32px;\n --width: 32px;\n gap: 8px;\n }\n\n :host([data-size=\"lg\"]) .comment {\n --avatar-size: 56px;\n --width: 56px;\n gap: 12px;\n }\n\n .comment--is-selected {\n background-color: var(--pop-muted);\n outline-color: var(--pop-muted);\n }\n\n :host(.is-signed-in) .comment {\n cursor: pointer;\n }\n\n @media (hover: hover) and (pointer: fine) {\n .comment:hover .comment__avatar {\n --avatar-translate-x: 2px;\n }\n\n .comment__avatar:hover {\n /* --avatar-scale: 1.06; */\n }\n\n .comment .comment__menu {\n display: none;\n }\n\n .comment:hover .comment__menu {\n display: flex;\n }\n }\n\n .comment--is-selected .comment__avatar {\n --avatar-translate-x: 2px;\n }\n\n .comment__avatar {\n --comment-avatar-border-size: 0;\n --avatar-translate-x: 0px;\n --avatar-scale: 1;\n width: var(--avatar-size);\n height: var(--avatar-size);\n transform: translateX(var(--avatar-translate-x)) scale(var(--avatar-scale));\n transition: transform var(--pop-duration-quick) var(--pop-ease-quick);\n }\n\n .comment__user {\n display: flex;\n width: var(--width);\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n align-self: stretch;\n }\n\n .comment__content {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 0 0;\n align-self: stretch;\n }\n\n .comment__info {\n display: flex;\n align-items: flex-start;\n align-self: stretch;\n }\n\n .comment__menu {\n display: flex;\n justify-self: flex-end;\n }\n\n .comment__menu-trigger {\n background: none;\n border: none;\n cursor: pointer;\n border-radius: 9999px;\n aspect-ratio: 1;\n position: relative;\n }\n\n .comment__menu-trigger:before {\n content: \"\";\n height: 40px;\n left: 50%;\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n }\n\n .comment__user-meta {\n display: flex;\n align-items: flex-start;\n gap: 4px;\n flex-shrink: 0;\n align-self: stretch;\n flex-grow: 1;\n }\n\n .comment__user-name {\n color: var(--pop-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: var(--text-widget-base, 13px);\n font-style: normal;\n font-weight: 500;\n line-height: var(--text-widget-base--line-height, 18px);\n letter-spacing: -0.08px;\n }\n\n .comment__timestamp {\n color: var(--pop-muted-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: var(--text-widget-base, 13px);\n font-style: normal;\n font-weight: 400;\n line-height: var(--text-widget-base--line-height, 18px);\n letter-spacing: -0.08px;\n opacity: 0.5;\n }\n\n .comment__text {\n align-self: stretch;\n color: var(--pop-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: 13px;\n font-style: normal;\n font-weight: 400;\n line-height: 18px;\n letter-spacing: -0.08px;\n text-align: left;\n\n /* Clamping when not expanded */\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .comment__text.expanded,\n .comment--is-selected .comment__text {\n -webkit-line-clamp: initial;\n display: block;\n }\n\n .comment__mention {\n color: #155eef;\n font-weight: 500;\n }\n\n .comment__menu {\n position: relative;\n }\n\n .comment__dropdown {\n background-color: var(--pop-background);\n border-radius: 6px;\n box-shadow: var(--pop-shadow-xl);\n display: none;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n pointer-events: auto;\n position: fixed;\n width: 120px;\n z-index: 1000;\n }\n\n .comment__dropdown.is-open {\n display: flex;\n }\n\n .comment__dropdown-item {\n align-items: center;\n background: none;\n border-radius: 4px;\n border: none;\n color: var(--pop-foreground);\n cursor: pointer;\n display: flex;\n flex: 1 0 0;\n font-family: Inter, sans-serif;\n font-size: 14px;\n font-weight: 500;\n justify-content: center;\n min-height: 40px;\n padding: 0 12px;\n text-align: left;\n transition: background-color 100ms ease;\n width: 100%;\n }\n\n .comment__dropdown-item:hover {\n background-color: var(--pop-comment-hover, rgba(0, 0, 0, 0.04));\n }\n\n .comment__dropdown-item--danger {\n color: #ef4444;\n }\n\n .comment__edit-form {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: 8px;\n margin-top: 4px;\n }\n\n .comment__edit-input {\n width: 100%;\n background: var(--pop-background, #ffffff);\n color: var(--pop-foreground, #000000);\n border: 1px solid var(--pop-border, #e4e4e7);\n border-radius: var(--pop-radius-sm, 4px);\n padding: 6px 8px;\n font-family: Inter, sans-serif;\n font-size: 13px;\n line-height: 18px;\n resize: vertical;\n outline: none;\n }\n\n .comment__edit-input:focus {\n border-color: var(--pop-ring, #000020);\n }\n\n .comment__edit-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .comment__edit-save,\n .comment__edit-cancel {\n font-size: 12px;\n padding: 4px 8px;\n cursor: pointer;\n }\n\n .comment--deleted .comment__text {\n color: var(--pop-muted-foreground, #697586);\n font-style: italic;\n opacity: 0.8;\n }\n`);\n\nexport class PopComment extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n static get observedAttributes() {\n return [\"data-size\", \"comment-id\"];\n }\n\n onDataSizeChanged() {\n this.render();\n }\n\n onCommentIdChanged() {\n this.render();\n }\n\n get size(): \"sm\" | \"lg\" {\n return (this.getAttribute(\"data-size\") as \"sm\" | \"lg\") || \"sm\";\n }\n\n get commentAvatarSize(): \"xs\" | \"sm\" {\n return this.size === \"sm\" ? \"xs\" : \"sm\";\n }\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n private _expanded = false;\n private _dropdownOpen = false;\n private _floatingCleanup?: () => void;\n\n private _onOutsideClick = (event: MouseEvent) => {\n const path = event.composedPath();\n const dropdown = this.getElement(\".comment__dropdown\");\n const trigger = this.getElement(\".comment__menu-trigger\");\n\n if (dropdown && trigger && !path.includes(dropdown) && !path.includes(trigger)) {\n this.closeDropdown();\n }\n };\n\n private toggleDropdown() {\n if (this._dropdownOpen) {\n this.closeDropdown();\n } else {\n this.openDropdown();\n }\n }\n\n private openDropdown() {\n this._dropdownOpen = true;\n const dropdown = this.getElement<HTMLElement>(\".comment__dropdown\");\n const trigger = this.getElement<HTMLElement>(\".comment__menu-trigger\");\n\n if (dropdown && trigger) {\n dropdown.classList.add(\"is-open\");\n\n const update = () => {\n computePosition(trigger, dropdown, {\n placement: \"bottom-end\",\n middleware: [offset(4), flip(), shift({ padding: 8 })],\n strategy: \"fixed\",\n }).then(({ x, y }) => {\n Object.assign(dropdown.style, {\n left: `${x}px`,\n top: `${y}px`,\n position: \"fixed\",\n });\n });\n };\n\n this._floatingCleanup = autoUpdate(trigger, dropdown, update);\n document.addEventListener(\"mousedown\", this._onOutsideClick);\n }\n }\n\n private closeDropdown() {\n this._dropdownOpen = false;\n const dropdown = this.getElement(\".comment__dropdown\");\n if (dropdown) {\n dropdown.classList.remove(\"is-open\");\n }\n if (this._floatingCleanup) {\n this._floatingCleanup();\n this._floatingCleanup = undefined;\n }\n document.removeEventListener(\"mousedown\", this._onOutsideClick);\n }\n\n private async deleteComment() {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n if (confirm(\"Are you sure you want to delete this comment?\")) {\n await this.gridStore.deleteComment(commentId);\n }\n }\n\n private async flagComment() {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const success = await this.gridStore.flagComment(commentId);\n if (success) {\n alert(\"Comment flagged successfully.\");\n } else {\n alert(\"Failed to flag comment.\");\n }\n }\n\n protected onClick(event: Event) {\n const target = event.target as HTMLElement;\n\n // Handle menu trigger click\n if (target.closest(\".comment__menu-trigger\")) {\n event.stopPropagation();\n this.toggleDropdown();\n return;\n }\n\n // Handle dropdown item click\n const dropdownItem = target.closest(\".comment__dropdown-item\") as HTMLElement;\n if (dropdownItem) {\n event.stopPropagation();\n const action = dropdownItem.getAttribute(\"data-action\");\n const commentId = this.getAttribute(\"comment-id\");\n if (action === \"edit\" && commentId) {\n this.gridStore.replyingTo.value = null;\n this.gridStore.editingCommentId.value = commentId;\n } else if (action === \"delete\") {\n this.deleteComment();\n } else if (action === \"flag\") {\n this.flagComment();\n }\n this.closeDropdown();\n return;\n }\n\n // Don't trigger reply if clicking inside the dropdown\n if (target.closest(\".comment__dropdown\")) {\n event.stopPropagation();\n return;\n }\n\n // Default reply action\n if (!currentUser.value) return;\n\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (comment?.status === \"deleted\") return;\n\n if (this.gridStore.replyingTo.value === commentId) {\n this.gridStore.replyingTo.value = null;\n } else {\n this.gridStore.replyingTo.value = commentId;\n }\n\n this.expandText();\n }\n\n private expandText() {\n const textEl = this.getElement<HTMLElement>(\".comment__text\");\n if (!this._expanded && textEl) {\n const startHeight = textEl.offsetHeight;\n this._expanded = true;\n this.render();\n\n const newTextEl = this.getElement<HTMLElement>(\".comment__text\");\n if (newTextEl) {\n const endHeight = newTextEl.scrollHeight;\n\n newTextEl.style.height = `${startHeight}px`;\n newTextEl.style.overflow = \"hidden\";\n\n // Force a reflow\n void newTextEl.offsetHeight;\n\n newTextEl.style.transition = \"height var(--pop-duration-quick) var(--pop-ease-quick)\";\n newTextEl.style.height = `${endHeight}px`;\n\n setTimeout(() => {\n newTextEl.style.height = \"\";\n newTextEl.style.overflow = \"\";\n }, 300);\n }\n }\n }\n\n private _timeUpdateTimer: ReturnType<typeof setTimeout> | null = null;\n\n disconnectedCallback() {\n this.closeDropdown();\n this.stopTimeUpdates();\n super.disconnectedCallback();\n }\n\n private startTimeUpdates() {\n this.stopTimeUpdates();\n\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (!comment) return;\n\n const update = () => {\n const timeSpan = this.getElement<HTMLSpanElement>(\".comment__timestamp\");\n if (timeSpan) {\n timeSpan.textContent = timeAgo(comment.createdAt);\n }\n\n const ageMs =\n Date.now() -\n (typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt)));\n let delay = 60000;\n\n if (ageMs < 60000) {\n delay = 5000;\n } else if (ageMs < 3600000) {\n delay = 60000;\n } else {\n delay = 1800000;\n }\n\n this._timeUpdateTimer = setTimeout(update, delay);\n };\n\n const ageMs =\n Date.now() -\n (typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt)));\n const initialDelay = ageMs < 60000 ? 5000 : 60000;\n this._timeUpdateTimer = setTimeout(update, initialDelay);\n }\n\n private stopTimeUpdates() {\n if (this._timeUpdateTimer) {\n clearTimeout(this._timeUpdateTimer);\n this._timeUpdateTimer = null;\n }\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const commentId = this.getAttribute(\"comment-id\");\n const user = currentUser.value;\n const replyingToId = this.gridStore.replyingTo.value;\n const editingId = this.gridStore.editingCommentId.value;\n const targetId = this.gridStore.scrollingCommentId.value;\n\n this.classList.toggle(\"is-signed-in\", user !== null);\n this.classList.toggle(\"is-replying\", commentId !== null && replyingToId === commentId);\n this.classList.toggle(\"is-editing\", commentId !== null && editingId === commentId);\n\n this.gridStore.comments.value;\n this.render();\n this.startTimeUpdates();\n\n if (commentId && targetId === commentId) {\n setTimeout(() => {\n const innerComment = this.shadowRoot?.querySelector(`#comment-${commentId}`);\n if (innerComment) {\n innerComment.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n } else {\n this.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n }\n this.gridStore.scrollingCommentId.value = null;\n }, 50);\n }\n });\n }\n\n protected getTemplate(): string {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return \"\";\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (!comment) return \"\";\n\n const isDeleted = comment.status === \"deleted\";\n const isAuthorDeleted = comment.authorDeleted === true;\n const showDeletedAvatar = isDeleted || isAuthorDeleted;\n\n const avatarContent = showDeletedAvatar\n ? \"\"\n : comment.author?.image\n ? `<img src=\"${comment.author.image}\" alt=\"${comment.author.name ?? \"User avatar\"}\" />`\n : getInitials(comment.author?.name);\n\n const replyingToId = this.gridStore.replyingTo.value;\n const isReplying = commentId !== null && replyingToId === commentId;\n const size = this.size;\n\n // Determine if signed-in user is the author\n const isAuthor =\n currentUser.value && comment.author && currentUser.value.id === comment.author.id;\n\n // Dropdown HTML (only if signed in and comment is not deleted)\n const menuHtml =\n currentUser.value && !isDeleted\n ? `<div class=\"comment__menu\">\n <button class=\"comment__menu-trigger\" type=\"button\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 9.5C9.27614 9.5 9.5 9.27614 9.5 9C9.5 8.72386 9.27614 8.5 9 8.5C8.72386 8.5 8.5 8.72386 8.5 9C8.5 9.27614 8.72386 9.5 9 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M12.5 9.5C12.7761 9.5 13 9.27614 13 9C13 8.72386 12.7761 8.5 12.5 8.5C12.2239 8.5 12 8.72386 12 9C12 9.27614 12.2239 9.5 12.5 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M5.5 9.5C5.77614 9.5 6 9.27614 6 9C6 8.72386 5.77614 8.5 5.5 8.5C5.22386 8.5 5 8.72386 5 9C5 9.27614 5.22386 9.5 5.5 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M9 9.5C9.27614 9.5 9.5 9.27614 9.5 9C9.5 8.72386 9.27614 8.5 9 8.5C8.72386 8.5 8.5 8.72386 8.5 9C8.5 9.27614 8.72386 9.5 9 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M12.5 9.5C12.7761 9.5 13 9.27614 13 9C13 8.72386 12.7761 8.5 12.5 8.5C12.2239 8.5 12 8.72386 12 9C12 9.27614 12.2239 9.5 12.5 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M5.5 9.5C5.77614 9.5 6 9.27614 6 9C6 8.72386 5.77614 8.5 5.5 8.5C5.22386 8.5 5 8.72386 5 9C5 9.27614 5.22386 9.5 5.5 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n <div class=\"comment__dropdown\">\n ${\n isAuthor\n ? `<button class=\"comment__dropdown-item\" type=\"button\" data-action=\"edit\">Edit</button>\n <button class=\"comment__dropdown-item comment__dropdown-item--danger\" type=\"button\" data-action=\"delete\">Delete</button>`\n : \"\"\n }\n <button class=\"comment__dropdown-item\" type=\"button\" data-action=\"flag\">Flag</button>\n </div>\n </div>`\n : \"\";\n\n return /* html */ `\n <div\n class=\"comment comment--size-${size}${isReplying ? \" comment--is-selected\" : \"\"}${isDeleted\n ? \" comment--deleted\"\n : \"\"}\"\n id=\"comment-${commentId}\"\n >\n <div class=\"comment__user\">\n <pop-comment-avatar\n class=\"comment__avatar\"\n size=\"${this.commentAvatarSize}\"\n data-color-key=\"${comment.author?.id ?? comment.author?.name ?? \"\"}\"\n ${showDeletedAvatar ? \"deleted\" : \"\"}\n >\n ${avatarContent}\n </pop-comment-avatar>\n </div>\n <div class=\"comment__content\">\n <div class=\"comment__info\">\n <div class=\"comment__user-meta\">\n <div class=\"comment__user-name\">\n ${isDeleted ? \"[Deleted]\" : isAuthorDeleted ? \"[Deleted user]\" : (comment.author?.name ?? \"\")}\n </div>\n <div class=\"comment__timestamp\">${timeAgo(comment.createdAt)}</div>\n </div>\n ${menuHtml}\n </div>\n <div class=\"comment__text${this._expanded ? \" expanded\" : \"\"}\">${comment.body}</div>\n </div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment\")) {\n customElements.define(\"pop-comment\", PopComment);\n}\n","import { checkSession, currentUser } from \"../store/auth-store.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: flex;\n background: var(--pop-background);\n border-radius: var(--pop-radius-2xl);\n border: 1px solid var(--pop-background);\n box-shadow: var(--pop-shadow-3xl);\n display: block;\n left: 0;\n max-height: 400px;\n max-width: 400px;\n min-width: 343px;\n opacity: 0;\n overflow: hidden;\n padding: 0 4px 0 0;\n pointer-events: none;\n position: fixed;\n top: 0;\n width: 100%;\n z-index: 9999;\n transform: scale(0.94);\n transition:\n opacity var(--pop-duration-quick) var(--pop-ease-quick),\n transform var(--pop-duration-quick) var(--pop-ease-quick),\n display var(--pop-duration-quick) allow-discrete;\n }\n\n :host([data-current-placement=\"top-start\"]) {\n transform-origin: left bottom;\n }\n\n :host([data-current-placement=\"bottom-start\"]) {\n transform-origin: left top;\n }\n\n :host([data-current-placement=\"top-end\"]) {\n transform-origin: right bottom;\n }\n\n :host([data-current-placement=\"bottom-end\"]) {\n transform-origin: right top;\n }\n\n :host([data-current-placement=\"top\"]) {\n transform-origin: bottom;\n }\n\n :host([data-current-placement=\"bottom\"]) {\n transform-origin: top;\n }\n\n :host([open]) {\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n\n @starting-style {\n display: flex;\n opacity: 0;\n transform: scale(0.94);\n }\n }\n\n .feed {\n display: grid;\n grid-template-rows: 1fr 50px;\n }\n\n .feed__content {\n align-items: flex-start;\n align-self: stretch;\n display: flex;\n gap: 8px;\n min-height: 80px;\n max-height: 290px;\n }\n\n .feed__empty {\n padding: 24px 16px 24px 8px;\n text-align: center;\n font-family: Inter, sans-serif;\n font-size: 13px;\n color: var(--pop-muted-foreground);\n line-height: 18px;\n }\n\n .feed__footer {\n position: absolute;\n bottom: 0;\n min-height: 50px;\n width: 100%;\n }\n\n .feed__main {\n align-items: stretch;\n align-self: stretch;\n display: flex;\n flex-direction: column;\n flex: 1 0 0;\n gap: 16px;\n min-height: 100%;\n overflow: hidden auto;\n padding: 8px 10px 8px 8px;\n }\n\n .feed__main::-webkit-scrollbar {\n width: 4px;\n }\n\n .feed__main::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .feed__main::-webkit-scrollbar-thumb {\n background: var(--pop-border);\n border-radius: 100px;\n }\n`);\n\nexport class PopFeed extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n private _footerChild: string | null = null;\n private _wasOpen = false;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n connectedCallback() {\n super.connectedCallback();\n document.addEventListener(\"mousedown\", this);\n document.addEventListener(\"keydown\", this);\n }\n\n disconnectedCallback() {\n document.removeEventListener(\"mousedown\", this);\n document.removeEventListener(\"keydown\", this);\n super.disconnectedCallback();\n }\n\n handleEvent(event: Event): void {\n if (event.type === \"mousedown\") {\n this.onOutsideClick(event as MouseEvent);\n return;\n }\n\n if (event.type === \"keydown\") {\n this.onKeyDown(event as KeyboardEvent);\n return;\n }\n\n super.handleEvent(event);\n }\n\n private onOutsideClick(event: MouseEvent) {\n if (!this.gridStore.open.value) return;\n\n const path = event.composedPath();\n const root = this.getRootNode();\n const host = root instanceof ShadowRoot ? root.host : null;\n if (!path.includes(this) && (!host || !path.includes(host))) {\n this.gridStore.open.value = false;\n }\n }\n\n private onKeyDown(event: KeyboardEvent) {\n if (event.key !== \"Escape\") return;\n this.gridStore.open.value = false;\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const open = this.gridStore.open.value;\n\n if (open && !this._wasOpen && this.gridStore.grid.value) {\n void checkSession(this.gridStore.apiUrl, this.gridStore.publicKey);\n }\n\n this._wasOpen = open;\n this.update();\n });\n }\n\n private update(): void {\n if (this.gridStore.open.value) {\n this.setAttribute(\"open\", \"\");\n } else {\n this.removeAttribute(\"open\");\n }\n\n const content = this.getElement<HTMLDivElement>(\".feed__main\");\n if (content) {\n const threads = this.gridStore.topLevelComments.value;\n\n if (threads.length === 0) {\n const isEmpty = content.querySelector(\".feed__empty\");\n if (!isEmpty) {\n content.innerHTML = `<div class=\"feed__empty\">Waiting for your thoughts…</div>`;\n }\n } else {\n const existingIds = Array.from(content.querySelectorAll(\"pop-comment-thread\")).map((el) =>\n el.getAttribute(\"comment-id\"),\n );\n\n const newIds = threads.map((c) => c.id);\n const needsRebuild =\n existingIds.length !== newIds.length || existingIds.some((id, i) => id !== newIds[i]);\n\n if (needsRebuild) {\n content.innerHTML = threads\n .map(\n (comment) => `<pop-comment-thread comment-id=\"${comment.id}\"></pop-comment-thread>`,\n )\n .join(\"\");\n }\n }\n }\n\n const footer = this.getElement<HTMLDivElement>(\".feed__footer\");\n if (footer) {\n const authed = currentUser.value !== null;\n const desired = authed ? \"pop-comment-bar\" : \"pop-auth-panel\";\n if (this._footerChild !== desired) {\n this._footerChild = desired;\n footer.innerHTML = `<${desired}></${desired}>`;\n }\n }\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"feed\">\n <div class=\"feed__content\">\n <div class=\"feed__main\"></div>\n </div>\n <div class=\"feed__footer\"></div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-feed\")) {\n customElements.define(\"pop-feed\", PopFeed);\n}\n","function hasWindow() {\n return typeof window !== 'undefined';\n}\nfunction getNodeName(node) {\n if (isNode(node)) {\n return (node.nodeName || '').toLowerCase();\n }\n // Mocked nodes in testing environments may not be instances of Node. By\n // returning `#document` an infinite loop won't occur.\n // https://github.com/floating-ui/floating-ui/issues/2317\n return '#document';\n}\nfunction getWindow(node) {\n var _node$ownerDocument;\n return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;\n}\nfunction getDocumentElement(node) {\n var _ref;\n return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;\n}\nfunction isNode(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Node || value instanceof getWindow(value).Node;\n}\nfunction isElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Element || value instanceof getWindow(value).Element;\n}\nfunction isHTMLElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;\n}\nfunction isShadowRoot(value) {\n if (!hasWindow() || typeof ShadowRoot === 'undefined') {\n return false;\n }\n return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;\n}\nfunction isOverflowElement(element) {\n const {\n overflow,\n overflowX,\n overflowY,\n display\n } = getComputedStyle(element);\n return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';\n}\nfunction isTableElement(element) {\n return /^(table|td|th)$/.test(getNodeName(element));\n}\nfunction isTopLayer(element) {\n try {\n if (element.matches(':popover-open')) {\n return true;\n }\n } catch (_e) {\n // no-op\n }\n try {\n return element.matches(':modal');\n } catch (_e) {\n return false;\n }\n}\nconst willChangeRe = /transform|translate|scale|rotate|perspective|filter/;\nconst containRe = /paint|layout|strict|content/;\nconst isNotNone = value => !!value && value !== 'none';\nlet isWebKitValue;\nfunction isContainingBlock(elementOrCss) {\n const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n // https://drafts.csswg.org/css-transforms-2/#individual-transforms\n return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');\n}\nfunction getContainingBlock(element) {\n let currentNode = getParentNode(element);\n while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {\n if (isContainingBlock(currentNode)) {\n return currentNode;\n } else if (isTopLayer(currentNode)) {\n return null;\n }\n currentNode = getParentNode(currentNode);\n }\n return null;\n}\nfunction isWebKit() {\n if (isWebKitValue == null) {\n isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');\n }\n return isWebKitValue;\n}\nfunction isLastTraversableNode(node) {\n return /^(html|body|#document)$/.test(getNodeName(node));\n}\nfunction getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\nfunction getNodeScroll(element) {\n if (isElement(element)) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n }\n return {\n scrollLeft: element.scrollX,\n scrollTop: element.scrollY\n };\n}\nfunction getParentNode(node) {\n if (getNodeName(node) === 'html') {\n return node;\n }\n const result =\n // Step into the shadow DOM of the parent of a slotted node.\n node.assignedSlot ||\n // DOM Element detected.\n node.parentNode ||\n // ShadowRoot detected.\n isShadowRoot(node) && node.host ||\n // Fallback.\n getDocumentElement(node);\n return isShadowRoot(result) ? result.host : result;\n}\nfunction getNearestOverflowAncestor(node) {\n const parentNode = getParentNode(node);\n if (isLastTraversableNode(parentNode)) {\n return node.ownerDocument ? node.ownerDocument.body : node.body;\n }\n if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {\n return parentNode;\n }\n return getNearestOverflowAncestor(parentNode);\n}\nfunction getOverflowAncestors(node, list, traverseIframes) {\n var _node$ownerDocument2;\n if (list === void 0) {\n list = [];\n }\n if (traverseIframes === void 0) {\n traverseIframes = true;\n }\n const scrollableAncestor = getNearestOverflowAncestor(node);\n const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);\n const win = getWindow(scrollableAncestor);\n if (isBody) {\n const frameElement = getFrameElement(win);\n return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);\n } else {\n return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));\n }\n}\nfunction getFrameElement(win) {\n return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;\n}\n\nexport { getComputedStyle, getContainingBlock, getDocumentElement, getFrameElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isTopLayer, isWebKit };\n","import{isContainingBlock as t}from\"@floating-ui/utils/dom\";function e(t){return i(t)}function n(t){return f(t,\"offsetTop\")}function o(t){return f(t,\"offsetLeft\")}function r(t){return t.assignedSlot?t.assignedSlot:t.parentNode instanceof ShadowRoot?t.parentNode.host:t.parentNode}function i(e){for(let t=e;t;t=r(t))if(t instanceof Element&&\"none\"===getComputedStyle(t).display)return null;for(let n=r(e);n;n=r(n)){if(!(n instanceof Element))continue;const e=getComputedStyle(n);if(\"contents\"!==e.display){if(\"static\"!==e.position||t(e))return n;if(\"BODY\"===n.tagName)return n}}return null}function f(t,e){let n=t[e],o=i(t);const r=function(t){const e=new Set;let n=t.getRootNode();for(;n;)e.add(n),n=n.parentNode?n.parentNode.getRootNode():null;return e}(t);for(;o&&!r.has(o.getRootNode());)n-=o[e],o=i(o);return n}export{o as offsetLeft,e as offsetParent,n as offsetTop};\n","import {\n type Middleware,\n autoUpdate,\n computePosition,\n flip,\n offset,\n platform,\n} from \"@floating-ui/dom\";\nimport { offsetParent } from \"composed-offset-position\";\nimport { checkSession } from \"../store/auth-store.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { registerStore, unregisterStore } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst DEFAULT_API_URL = \"https://www.popgrids.io\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n position: relative;\n }\n\n .grid {\n display: flex;\n height: 100%;\n position: relative;\n width: 100%;\n }\n\n .grid--align-start {\n justify-content: flex-start;\n }\n\n .grid--align-center {\n justify-content: center;\n }\n\n .grid--align-end {\n justify-content: flex-end;\n }\n`);\n\nexport class PopGrid extends BaseElement {\n private _initialized = false;\n private _floatingCleanup?: () => void;\n private _store!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n connectedCallback() {\n if (this._initialized) return;\n this._initialized = true;\n\n const publicKey = this.getAttribute(\"data-key\") ?? this.getAttribute(\"public-key\") ?? \"\";\n\n const apiUrl =\n this.getAttribute(\"data-api-url\") ??\n this.getAttribute(\"api-url\") ??\n DEFAULT_API_URL;\n\n const pageUrl =\n this.getAttribute(\"data-page-url\") ?? this.getAttribute(\"page-url\") ?? location.href;\n\n // Names the discussion thread (Disqus-style identifier): embeds sharing a\n // data-id share one thread across pages; without it the thread is keyed\n // by the page's canonical URL.\n const externalId = this.getAttribute(\"data-id\");\n\n this._store = new GridStore({\n apiUrl,\n publicKey,\n pageUrl,\n externalId,\n });\n registerStore(this, this._store);\n\n super.connectedCallback();\n\n void this._store.load().then((loaded) => {\n if (loaded) {\n void checkSession(apiUrl, publicKey);\n }\n });\n }\n\n disconnectedCallback() {\n this._floatingCleanup?.();\n this._store.destroy();\n unregisterStore(this);\n super.disconnectedCallback();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const grid = this._store.grid.value;\n const gridEl = this.getElement(\".grid\");\n if (!gridEl) return;\n\n // Remove any existing grid-- classes\n const toRemove = Array.from(gridEl.classList).filter((cls) => cls.startsWith(\"grid--\"));\n if (toRemove.length > 0) {\n gridEl.classList.remove(...toRemove);\n }\n\n if (grid) {\n if (grid.align) gridEl.classList.add(`grid--align-${grid.align}`);\n if (grid.appearance) gridEl.classList.add(`grid--appearance-${grid.appearance}`);\n if (grid.icon) gridEl.classList.add(`grid--icon-${grid.icon}`);\n if (grid.layout) gridEl.classList.add(`grid--layout-${grid.layout}`);\n if (grid.position) gridEl.classList.add(`grid--position-${grid.position}`);\n\n const previewVal = grid.previewCount ?? this._store.previewCount;\n gridEl.classList.add(`grid--preview-${previewVal}`);\n }\n });\n\n this.addEffect(() => {\n const open = this._store.open.value;\n\n if (this._floatingCleanup) {\n this._floatingCleanup();\n this._floatingCleanup = undefined;\n }\n\n if (!open) return;\n\n const widget = this.getElement(\"pop-widget\");\n const feed = this.getElement(\"pop-feed\");\n if (!widget || !feed) return;\n\n const grid = this._store.grid.value;\n if (!grid) return;\n\n // Offset\n let middleware: Middleware[] = [];\n\n middleware = [\n offset({\n mainAxis: grid.position === \"down\" ? -16 : -54,\n crossAxis: -18,\n }),\n ];\n\n // Flip\n if (!grid.position || grid.position === \"auto\") {\n middleware.push(\n flip({\n fallbackPlacements: [\"bottom-start\", \"top-start\"],\n fallbackStrategy: \"bestFit\",\n padding: 16,\n }),\n );\n }\n\n const getOffsetParent = (element: Element) => platform.getOffsetParent(element, offsetParent);\n\n const update = () => {\n void computePosition(widget, feed, {\n placement: grid.position === \"down\" ? \"bottom-start\" : \"top-start\",\n middleware,\n strategy: \"fixed\",\n platform: {\n ...platform,\n getOffsetParent,\n },\n }).then(({ x, y, placement }) => {\n feed.setAttribute(\"data-current-placement\", placement);\n\n Object.assign(feed.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n });\n };\n\n this._floatingCleanup = autoUpdate(widget, feed, update);\n });\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"grid\">\n <pop-widget></pop-widget>\n <pop-feed></pop-feed>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-grid\")) {\n customElements.define(\"pop-grid\", PopGrid);\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n --error-badge-bg: #fef2f2;\n --error-badge-text: #991b1b;\n --error-badge-border: #fecaca;\n\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --error-badge-bg: #450a0a;\n --error-badge-text: #fca5a5;\n --error-badge-border: #7f1d1d;\n }\n }\n\n :host(.dark) {\n --error-badge-bg: #450a0a;\n --error-badge-text: #fca5a5;\n --error-badge-border: #7f1d1d;\n }\n\n :host([data-error]) {\n cursor: default;\n }\n\n .error-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: var(--pop-radius-full);\n border: 1px solid var(--error-badge-border);\n background: var(--error-badge-bg);\n color: var(--error-badge-text);\n font-size: 12px;\n font-weight: 500;\n line-height: 16px;\n white-space: nowrap;\n }\n\n .widget {\n display: inline-flex;\n align-items: flex-start;\n }\n\n .widget > :not([hidden]) ~ :not([hidden]) {\n margin-left: -6px;\n }\n\n .skeleton {\n width: 32px;\n height: 32px;\n background: var(--pop-muted);\n animation: pulse 1.5s ease-in-out infinite;\n }\n\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n }\n\n .count {\n --count-size: calc(32px + var(--count-border-size));\n --count-background: var(--pop-background);\n --count-border-color: rgba(0 0 32 / 16%);\n --count-border-size: 1px;\n --count-color: var(--pop-foreground);\n\n align-items: center;\n background-color: var(--pop-background);\n display: flex;\n flex-shrink: 0;\n justify-content: center;\n padding: calc(var(--count-border-size) / 2);\n position: relative;\n z-index: 10;\n\n width: calc(var(--count-size) + (calc(var(--count-border-size))));\n height: calc(var(--count-size) + (calc(var(--count-border-size))));\n }\n\n .count__background {\n background-color: var(--count-border-color);\n position: absolute;\n top: 0;\n left: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n }\n\n .count__content {\n align-items: center;\n background: var(--count-background);\n display: flex;\n justify-content: center;\n overflow: hidden;\n height: var(--count-size);\n width: var(--count-size);\n }\n\n .count__label {\n color: var(--count-color);\n font-size: 16px;\n font-style: normal;\n font-weight: 500;\n letter-spacing: -0.96px;\n line-height: 28px;\n text-align: center;\n user-select: none;\n }\n\n .count__label-container {\n align-items: center;\n background: var(--pop-background);\n display: flex;\n height: calc(100% - calc(var(--count-border-size) * 2));\n justify-content: center;\n position: relative;\n text-indent: calc(calc(var(--count-border-size) * 2) * -1);\n width: calc(100% - calc(var(--count-border-size) * 2));\n z-index: 20;\n }\n`);\n\nexport class PopWidget extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick() {\n if (this.gridStore.error.value) {\n return;\n }\n\n this.gridStore.open.value = !this.gridStore.open.value;\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n this.gridStore.loading.value;\n this.gridStore.error.value;\n this.gridStore.previewAvatars.value;\n this.gridStore.comments.value;\n this.gridStore.grid.value;\n\n const hasError = Boolean(this.gridStore.error.value);\n this.toggleAttribute(\"data-error\", hasError);\n\n if (hasError && this.gridStore.open.value) {\n this.gridStore.open.value = false;\n }\n\n this.render();\n });\n }\n\n protected getTemplate(): string {\n if (this.gridStore.loading.value) {\n return `<div class=\"widget\"><div class=\"skeleton mask mask-squircle\"></div></div>`;\n }\n\n if (this.gridStore.error.value) {\n return `<div class=\"error-badge\">Error: there was a problem loading the PopGrid</div>`;\n }\n\n const avatars = this.gridStore.previewAvatars.value;\n const totalCount = this.gridStore.comments.value.length;\n\n const avatarsHtml = avatars\n .map((author, idx) => {\n const zIndex = avatars.length + idx;\n const colorKey = author?.id ?? author?.name ?? \"\";\n\n if (author?.image) {\n return `<pop-comment-avatar size=\"xs\" style=\"z-index: ${zIndex}\" data-color-key=\"${colorKey}\">\n <img src=\"${author.image}\" alt=\"${author.name ?? \"User\"}\" />\n </pop-comment-avatar>`;\n }\n\n return `<pop-comment-avatar size=\"xs\" style=\"z-index: ${zIndex}\" data-color-key=\"${colorKey}\">\n ${getInitials(author?.name)}\n </pop-comment-avatar>`;\n })\n .join(\"\");\n\n return /* html */ `\n <div class=\"widget\">\n ${avatarsHtml}\n <div class=\"count mask mask-squircle\">\n <span class=\"count__content mask mask-squircle\">\n <div class=\"count__background mask mask-squircle\"></div>\n <div class=\"count__label-container mask mask-squircle\">\n <div class=\"count__label\">${totalCount}</div>\n </div>\n </span>\n </div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-widget\")) {\n customElements.define(\"pop-widget\", PopWidget);\n}\n","if (typeof document !== \"undefined\") {\n const fontUrl = \"https://rsms.me/inter/inter.css\";\n if (!document.querySelector(`link[href=\"${fontUrl}\"]`)) {\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = fontUrl;\n document.head.appendChild(link);\n }\n}\n\nimport \"./components/pop-auth-panel.js\";\nimport \"./components/pop-comment-avatar.js\";\nimport \"./components/pop-comment-bar.js\";\nimport \"./components/pop-comment-icon.js\";\nimport \"./components/pop-comment-input.js\";\nimport \"./components/pop-comment-thread.js\";\nimport \"./components/pop-comment.js\";\nimport \"./components/pop-feed.js\";\nimport \"./components/pop-grid.js\";\nimport \"./components/pop-widget.js\";\n\nexport type { AuthUser, Comment, CommentAuthor, Grid } from \"./types/models.js\";\n"],"x_google_ignoreList":[21,22],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["getComputedStyle","t"],"sources":["../src/lib/popup-auth.ts","../src/store/auth-store.ts","../src/store/registry.ts","../src/store/grid-store.ts","../src/styles/base.css?inline","../src/styles/buttons.css?inline","../src/styles/masks.css?inline","../src/helpers/theme.ts","../src/components/base-element.ts","../src/components/pop-auth-panel.ts","../src/assets/popgrids-letter-p.png?inline","../src/helpers/color.ts","../src/components/pop-comment-avatar.ts","../src/helpers/author.ts","../src/components/pop-comment-bar.ts","../src/components/pop-comment-icon.ts","../src/components/pop-comment-input.ts","../src/components/pop-comment-thread.ts","../src/helpers/time.ts","../src/components/pop-comment.ts","../src/components/pop-feed.ts","../node_modules/.pnpm/@floating-ui+utils@0.2.11/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs","../node_modules/.pnpm/composed-offset-position@0.0.6_@floating-ui+utils@0.2.11/node_modules/composed-offset-position/dist/composed-offset-position.browser.min.mjs","../src/components/pop-grid.ts","../src/components/pop-widget.ts","../src/index.ts"],"sourcesContent":["import type { AuthUser } from \"../types/models.js\";\n\nexport const EMBED_AUTH_SOURCE = \"popgrids-embed\";\nexport const EMBED_AUTH_SUCCESS = \"popgrids:auth:success\";\nexport const EMBED_AUTH_ERROR = \"popgrids:auth:error\";\n\nexport const EMBED_AUTH_LOGIN_PATH = \"/embed/auth/login\";\nexport const POPUP_NAME = \"popgrids-auth\";\nexport const POPUP_FEATURES = \"popup,width=480,height=640\";\nexport const AUTH_TIMEOUT_MS = 5 * 60 * 1000;\n\nconst POPUP_CLOSE_GRACE_MS = 250;\n\nexport class PopupAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PopupAuthError\";\n }\n}\n\nexport const buildEmbedLoginUrl = (\n apiUrl: string,\n publicKey: string,\n returnOrigin: string,\n) => {\n const url = new URL(EMBED_AUTH_LOGIN_PATH, apiUrl);\n url.searchParams.set(\"publicKey\", publicKey);\n url.searchParams.set(\"returnOrigin\", returnOrigin);\n return url.toString();\n};\n\nexport const openPopgridsLoginPopup = (apiUrl: string, publicKey: string) => {\n const popup = window.open(\n buildEmbedLoginUrl(apiUrl, publicKey, window.location.origin),\n POPUP_NAME,\n POPUP_FEATURES,\n );\n\n if (!popup) {\n throw new PopupAuthError(\"Popup blocked. Allow popups for this site and try again.\");\n }\n\n return popup;\n};\n\nconst isAuthMessage = (data: unknown, type: string) =>\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n \"source\" in data &&\n (data as { type: string; source: string }).type === type &&\n (data as { type: string; source: string }).source === EMBED_AUTH_SOURCE;\n\nconst readAuthUser = (data: unknown): AuthUser | null => {\n if (typeof data !== \"object\" || data === null || !(\"user\" in data)) {\n return null;\n }\n\n const user = (data as { user?: unknown }).user;\n if (typeof user !== \"object\" || user === null || !(\"id\" in user)) {\n return null;\n }\n\n const record = user as {\n id?: unknown;\n name?: unknown;\n email?: unknown;\n image?: unknown;\n };\n\n if (typeof record.id !== \"string\") {\n return null;\n }\n\n return {\n id: record.id,\n name: typeof record.name === \"string\" ? record.name : \"\",\n email: typeof record.email === \"string\" ? record.email : \"\",\n image: typeof record.image === \"string\" ? record.image : null,\n };\n};\n\nexport const waitForPopgridsAuth = (\n apiUrl: string,\n popup: Window,\n options?: {\n onAuthUser?: (user: AuthUser) => void;\n verifySignedIn?: () => Promise<boolean>;\n },\n) =>\n new Promise<void>((resolve, reject) => {\n const expectedOrigin = new URL(apiUrl).origin;\n let settled = false;\n let authMessageReceived = false;\n let closeCheckStarted = false;\n\n const settle = (result: \"resolve\" | \"reject\", error?: PopupAuthError) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n if (result === \"resolve\") {\n resolve();\n return;\n }\n reject(error ?? new PopupAuthError(\"Sign-in failed\"));\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) {\n return;\n }\n\n if (isAuthMessage(event.data, EMBED_AUTH_SUCCESS)) {\n authMessageReceived = true;\n const user = readAuthUser(event.data);\n if (user) {\n options?.onAuthUser?.(user);\n }\n settle(\"resolve\");\n return;\n }\n\n if (isAuthMessage(event.data, EMBED_AUTH_ERROR)) {\n authMessageReceived = true;\n const message =\n typeof event.data === \"object\" &&\n event.data !== null &&\n \"error\" in event.data &&\n typeof (event.data as { error?: unknown }).error === \"string\"\n ? (event.data as { error: string }).error\n : \"Sign-in failed\";\n settle(\"reject\", new PopupAuthError(message));\n }\n };\n\n const interval = window.setInterval(() => {\n if (!popup.closed) {\n return;\n }\n\n if (closeCheckStarted) {\n return;\n }\n\n closeCheckStarted = true;\n\n void (async () => {\n await new Promise((resolveDelay) => window.setTimeout(resolveDelay, POPUP_CLOSE_GRACE_MS));\n\n if (authMessageReceived || settled) {\n return;\n }\n\n if (options?.verifySignedIn && (await options.verifySignedIn())) {\n settle(\"resolve\");\n return;\n }\n\n settle(\"reject\", new PopupAuthError(\"Sign-in was cancelled\"));\n })();\n }, 300);\n\n const timeout = window.setTimeout(() => {\n try {\n popup.close();\n } catch {\n // ignore\n }\n settle(\"reject\", new PopupAuthError(\"Sign-in timed out\"));\n }, AUTH_TIMEOUT_MS);\n\n const cleanup = () => {\n window.removeEventListener(\"message\", onMessage);\n clearInterval(interval);\n clearTimeout(timeout);\n };\n\n window.addEventListener(\"message\", onMessage);\n });\n\nexport const signInWithPopup = async (\n apiUrl: string,\n publicKey: string,\n options?: {\n onAuthUser?: (user: AuthUser) => void;\n verifySignedIn?: () => Promise<boolean>;\n },\n) => {\n const popup = openPopgridsLoginPopup(apiUrl, publicKey);\n await waitForPopgridsAuth(apiUrl, popup, options);\n};\n","import { signal } from \"@preact/signals-core\";\nimport { signInWithPopup } from \"../lib/popup-auth.js\";\nimport type { AuthUser } from \"../types/models.js\";\n\nexport const currentUser = signal<AuthUser | null>(null);\nexport const authError = signal<string | null>(null);\nexport const authPending = signal(false);\n\nconst SESSION_RETRY_DELAYS_MS = [0, 150, 400];\nconst POST_AUTH_SESSION_DELAYS_MS = [0, 100, 200, 400, 800, 1500, 2500, 4000];\n\nexport async function checkSession(\n apiUrl: string,\n publicKey: string,\n delays: number[] = SESSION_RETRY_DELAYS_MS,\n): Promise<boolean> {\n if (!apiUrl || !publicKey) {\n currentUser.value = null;\n return false;\n }\n\n const sessionUrl = new URL(\n `/api/v1/embed/grids/${publicKey}/session`,\n apiUrl,\n );\n sessionUrl.searchParams.set(\"pageUrl\", window.location.href);\n\n for (let attempt = 0; attempt < delays.length; attempt++) {\n const delay = delays[attempt] ?? 0;\n if (delay > 0) {\n await new Promise((resolve) => window.setTimeout(resolve, delay));\n }\n\n try {\n const res = await fetch(sessionUrl, { credentials: \"include\" });\n\n if (!res.ok) {\n continue;\n }\n\n const data = (await res.json()) as { user: AuthUser | null };\n currentUser.value = data.user ?? null;\n\n if (currentUser.value !== null) {\n return true;\n }\n } catch {\n // retry\n }\n }\n\n currentUser.value = null;\n return false;\n}\n\nexport async function requestSignIn(\n apiUrl: string,\n publicKey: string,\n): Promise<boolean> {\n authError.value = null;\n authPending.value = true;\n\n try {\n await signInWithPopup(apiUrl, publicKey, {\n onAuthUser: (user) => {\n currentUser.value = user;\n },\n verifySignedIn: () =>\n checkSession(apiUrl, publicKey, POST_AUTH_SESSION_DELAYS_MS),\n });\n\n if (currentUser.value) {\n return true;\n }\n\n return await checkSession(apiUrl, publicKey, POST_AUTH_SESSION_DELAYS_MS);\n } catch (error) {\n authError.value = error instanceof Error ? error.message : \"Sign-in failed\";\n return false;\n } finally {\n authPending.value = false;\n }\n}\n\nexport function clearAuthError(): void {\n authError.value = null;\n}\n","const _registry = new WeakMap<Element, Map<any, any>>();\n\nexport const registerStore = (el: Element, store: any, key: any = store.constructor): void => {\n let stores = _registry.get(el);\n if (!stores) {\n stores = new Map();\n _registry.set(el, stores);\n }\n stores.set(key, store);\n};\n\nexport const unregisterStore = (el: Element): void => {\n _registry.delete(el);\n};\n\nexport const resolveStore = <T>(el: Element, key: any): T | null => {\n let node: Element | null = el;\n while (node) {\n const stores = _registry.get(node);\n const store = stores?.get(key);\n if (store) return store as T;\n\n const root = node.getRootNode();\n if (!(root instanceof ShadowRoot)) break;\n node = root.host;\n }\n return null;\n};\n\nexport function consume(storeKey: any) {\n return function (target: any, propertyKey: string) {\n const cacheKey = Symbol(\"context_\" + (storeKey.name || \"store\"));\n Object.defineProperty(target, propertyKey, {\n get(this: any) {\n if (this[cacheKey]) return this[cacheKey];\n const resolved = resolveStore(this, storeKey);\n if (!resolved) {\n console.error(`[Context] resolveStore failed! isConnected: ${this.isConnected}`, this);\n throw new Error(\n `[Context] Store for key \"${storeKey.name || storeKey}\" not resolved on <${this.localName}>.`\n );\n }\n this[cacheKey] = resolved;\n return resolved;\n },\n enumerable: true,\n configurable: true,\n });\n };\n}\n\n","import { computed, signal } from \"@preact/signals-core\";\nimport type { Comment, CommentAuthor, Grid } from \"../types/models.js\";\nimport { currentUser, requestSignIn } from \"./auth-store.js\";\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst DEFAULT_PREVIEW_COUNT = 3;\n\nconst commentRecency = (comment: Comment) => {\n const createdAt =\n typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt));\n\n return Number.isFinite(createdAt) ? createdAt : 0;\n};\n\nconst resolvePreviewCount = (grid: Grid | null, fallback: number) => {\n const value = grid?.previewCount ?? fallback;\n\n return value > 0 ? value : DEFAULT_PREVIEW_COUNT;\n};\n\n/**\n * The five visual settings a `<pop-grid>` can override live via\n * `data-align`/`data-layout`/`data-position`/`data-icon`/`data-preview-count`\n * — see pop-grid.ts's observedAttributes. Never includes `undefined`-valued\n * keys: an absent/invalid attribute is simply omitted, not set to\n * `undefined`, so `mergeOverrides` can fall back to the fetched grid's value\n * for that field with a plain spread.\n */\nexport type GridOverrides = Partial<\n Pick<Grid, \"align\" | \"layout\" | \"position\" | \"icon\" | \"previewCount\">\n>;\n\nconst mergeOverrides = (fetched: Grid | null, overrides: GridOverrides): Grid | null => {\n if (!fetched) {\n return fetched;\n }\n\n return { ...fetched, ...overrides };\n};\n\nexport class GridStore {\n readonly apiUrl: string;\n readonly publicKey: string;\n readonly pageUrl: string;\n readonly externalId: string | null;\n readonly previewCount = DEFAULT_PREVIEW_COUNT;\n\n /** The grid last fetched from the API — never read directly outside this\n * class; `grid` (below) is the override-aware value every consumer uses. */\n private _fetchedGrid = signal<Grid | null>(null);\n /** The override attributes currently set on the `<pop-grid>` element. */\n private _overrides = signal<GridOverrides>({});\n\n /** Fetched grid config with any live override attributes layered on top.\n * Read-only from the outside — set via `load()` (fetched) or\n * `setOverrides()` (overrides). */\n grid = computed(() => mergeOverrides(this._fetchedGrid.value, this._overrides.value));\n comments = signal<Comment[]>([]);\n loading = signal(true);\n error = signal<string | null>(null);\n open = signal(false);\n replyingTo = signal<string | null>(null);\n editingCommentId = signal<string | null>(null);\n scrollingCommentId = signal<string | null>(null);\n\n private socket: WebSocket | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n\n topLevelComments = computed(() =>\n this.comments.value\n .filter((c) => c.parentCommentId === null)\n .sort((a, b) => String(a.sortKey).localeCompare(String(b.sortKey))),\n );\n\n replyingToComment = computed(() => {\n const id = this.replyingTo.value;\n if (!id) return null;\n return this.comments.value.find((c) => c.id === id) ?? null;\n });\n\n editingComment = computed(() => {\n const id = this.editingCommentId.value;\n if (!id) return null;\n return this.comments.value.find((c) => c.id === id) ?? null;\n });\n\n previewComments = computed(() =>\n this.topLevelComments.value.slice(0, resolvePreviewCount(this.grid.value, this.previewCount)),\n );\n\n previewAvatars = computed((): CommentAuthor[] => {\n const limit = resolvePreviewCount(this.grid.value, this.previewCount);\n const seen = new Set<string>();\n const uniqueNewestFirst: CommentAuthor[] = [];\n\n const sorted = [...this.comments.value].sort((a, b) => commentRecency(b) - commentRecency(a));\n\n for (const comment of sorted) {\n const author = comment.author;\n\n if (!author?.id || seen.has(author.id)) {\n continue;\n }\n\n seen.add(author.id);\n uniqueNewestFirst.push(author);\n\n if (uniqueNewestFirst.length >= limit) {\n break;\n }\n }\n\n return uniqueNewestFirst.reverse();\n });\n\n constructor(opts: {\n apiUrl: string;\n publicKey: string;\n pageUrl: string;\n externalId?: string | null;\n }) {\n this.apiUrl = opts.apiUrl;\n this.publicKey = opts.publicKey;\n this.pageUrl = opts.pageUrl;\n this.externalId = opts.externalId?.trim() || null;\n }\n\n /** Replaces the current override set wholesale (not a per-key merge) —\n * called with every override attribute `<pop-grid>` currently has set, so\n * removing an attribute correctly falls back to the fetched grid's value\n * for that field instead of leaving a stale override in place. */\n setOverrides(overrides: GridOverrides): void {\n this._overrides.value = overrides;\n }\n\n /** pageUrl + optional externalId — the params that identify the discussion. */\n private identityParams(): string {\n const params = new URLSearchParams({ pageUrl: this.pageUrl });\n if (this.externalId) {\n params.set(\"externalId\", this.externalId);\n }\n return params.toString();\n }\n\n repliesFor(parentId: string): Comment[] {\n const parent = this.comments.value.find((c) => c.id === parentId);\n if (!parent) return [];\n return this.comments.value\n .filter(\n (c) =>\n c.id !== parentId &&\n (c.sortKey === parent.sortKey || c.sortKey.startsWith(parent.sortKey + \"/\")),\n )\n .sort((a, b) => String(a.sortKey).localeCompare(String(b.sortKey)));\n }\n\n async load(): Promise<boolean> {\n this.loading.value = true;\n this.error.value = null;\n try {\n const gridRes = await fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}`, {\n credentials: \"include\",\n });\n\n if (!gridRes.ok) {\n this.error.value = \"There was a problem loading the PopGrid\";\n return false;\n }\n\n const data = (await gridRes.json()) as { grid: Grid };\n this._fetchedGrid.value = data.grid;\n this.connectRealtime();\n\n const commentsRes = await fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments?${this.identityParams()}`,\n { credentials: \"include\" },\n );\n\n if (commentsRes.ok) {\n const commentsData = (await commentsRes.json()) as { comments: Comment[] };\n this.comments.value = commentsData.comments;\n }\n\n return true;\n } catch {\n console.error(\"Failed to load PopGrid\");\n this.error.value = \"There was a problem loading the PopGrid\";\n return false;\n } finally {\n this.loading.value = false;\n }\n }\n\n async postComment(body: string, parentCommentId?: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments`, {\n method: \"POST\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n body,\n pageUrl: this.pageUrl,\n externalId: this.externalId ?? undefined,\n parentCommentId,\n }),\n });\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.upsertComment(data.comment);\n\n if (data.comment.author && !currentUser.value) {\n currentUser.value = {\n id: data.comment.author.id,\n name: data.comment.author.name ?? \"\",\n email: \"\",\n image: data.comment.author.image,\n };\n }\n\n return data.comment;\n }\n\n destroy(): void {\n this.disposed = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.socket) {\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.close();\n this.socket = null;\n }\n }\n\n private connectRealtime(): void {\n const connectUrl = this.grid.value?.connectUrl;\n\n if (!connectUrl || this.disposed) {\n return;\n }\n\n if (this.socket) {\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.close();\n this.socket = null;\n }\n\n const wsUrl = new URL(connectUrl, this.apiUrl);\n wsUrl.protocol = wsUrl.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n wsUrl.searchParams.set(\"pageUrl\", this.pageUrl);\n if (this.externalId) {\n wsUrl.searchParams.set(\"externalId\", this.externalId);\n }\n\n const socket = new WebSocket(wsUrl.toString());\n this.socket = socket;\n\n socket.onopen = () => {\n this.reconnectAttempt = 0;\n };\n\n socket.onmessage = (event) => {\n try {\n const payload = JSON.parse(String(event.data)) as {\n type?: string;\n comment?: Comment;\n };\n\n if (payload.type === \"comment.created\" && payload.comment) {\n this.upsertComment(payload.comment);\n } else if (payload.type === \"comment.updated\" && payload.comment) {\n this.updateCommentInList(payload.comment);\n }\n } catch {\n // Ignore malformed realtime payloads.\n }\n };\n\n socket.onclose = () => {\n if (this.disposed) {\n return;\n }\n\n this.scheduleReconnect();\n };\n\n socket.onerror = () => {\n socket.close();\n };\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || this.reconnectTimer) {\n return;\n }\n\n const delay = Math.min(1000 * 2 ** this.reconnectAttempt, MAX_RECONNECT_DELAY_MS);\n this.reconnectAttempt += 1;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connectRealtime();\n }, delay);\n }\n\n private upsertComment(comment: Comment): void {\n const existing = this.comments.value.some((entry) => entry.id === comment.id);\n\n if (existing) {\n return;\n }\n\n this.comments.value = [...this.comments.value, comment];\n }\n\n async editComment(commentId: string, body: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(`${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}`, {\n method: \"PATCH\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n body,\n pageUrl: this.pageUrl,\n externalId: this.externalId ?? undefined,\n }),\n });\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.updateCommentInList(data.comment);\n return data.comment;\n }\n\n async deleteComment(commentId: string): Promise<Comment | null> {\n const attempt = async () =>\n fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}?${this.identityParams()}`,\n {\n method: \"DELETE\",\n credentials: \"include\",\n },\n );\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return null;\n }\n res = await attempt();\n }\n\n if (!res.ok) {\n return null;\n }\n\n const data = (await res.json()) as { comment: Comment };\n this.updateCommentInList(data.comment);\n return data.comment;\n }\n\n async flagComment(commentId: string): Promise<boolean> {\n const attempt = async () =>\n fetch(\n `${this.apiUrl}/api/v1/embed/grids/${this.publicKey}/comments/${commentId}/flag?${this.identityParams()}`,\n {\n method: \"POST\",\n credentials: \"include\",\n },\n );\n\n let res = await attempt();\n\n if (res.status === 401) {\n const signedIn = await requestSignIn(this.apiUrl, this.publicKey);\n if (!signedIn) {\n return false;\n }\n res = await attempt();\n }\n\n return res.ok;\n }\n\n private updateCommentInList(comment: Comment): void {\n this.comments.value = this.comments.value.map((c) => (c.id === comment.id ? comment : c));\n }\n}\n","@layer base {\n :host {\n box-sizing: border-box;\n font-family: \"Inter\", sans-serif;\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Color: Brand */\n --pop-color-brand-midnight-100: oklch(0.9658 0.0161 262.75);\n --pop-color-brand-midnight-900: oklch(0.15 0.03 255.43);\n --pop-color-brand-midnight-800: oklch(0.19 0.05 255.43);\n --pop-color-brand-ocean-400: oklch(0.63 0.19 255.43);\n --pop-color-brand-ocean-100: oklch(0.91 0.05 255.43);\n --pop-color-brand-forest-900: oklch(0.3866 0.0698 180.75);\n --pop-color-brand-forest-700: oklch(0.45 0.15 165.43);\n --pop-color-brand-forest-100: oklch(0.97 0.04 165.43);\n --pop-color-brand-highlight-400: oklch(0.88 0.25 105.43);\n --pop-color-brand-pumpkin-500: oklch(0.62 0.18 45.43);\n --pop-color-brand-pumpkin-200: oklch(0.89 0.08 45.43);\n --pop-color-brand-lemon-300: oklch(0.91 0.12 85.43);\n --pop-color-brand-lemon-100: oklch(0.97 0.04 85.43);\n\n /* Durations */\n --pop-duration-bouncy: 1s;\n --pop-duration-card-highlight: 0.6s;\n --pop-duration-gentle: 0.833s;\n --pop-duration-menu: 0.4s;\n --pop-duration-pop-hover: 0.6s;\n --pop-duration-pop-text: 0.3s;\n --pop-duration-quick: 0.833s;\n --pop-duration-slow: 1.167s;\n\n /* Easing */\n /* prettier-ignore */\n --pop-ease-bouncy: linear(0, 0.011, 0.045 1.3%, 0.184 2.7%, 0.911 7.4%, 1.153 9.4%, 1.301 11.2%, 1.342, 1.362 13%, 1.363, 1.355 14.4%, 1.306 16%, 1.028 21%, 0.939 23%, 0.89 24.7%, 0.876, 0.868 26.4%, 0.869, 0.882 29%, 0.907 30.5%, 1.014 35.9%, 1.038, 1.048 39.8% 41.1%, 1.043 42.5%, 0.995 49.3%, 0.987, 0.983 53.2%, 0.984 55.9%, 1.002 62.7%, 1.006 66.4%, 0.998 79.7%, 1);\n /* prettier-ignore */\n --pop-ease-card-highlight: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-gentle: linear(0, 0.007, 0.026, 0.059 4.5%, 0.106 6.3%, 0.209 9.5%, 0.558 19.3%, 0.658, 0.742, 0.812, 0.87, 0.918, 0.957, 0.986 41.6%, 1.007 45.3%, 1.021 49.4%, 1.027 54% 60.9%, 1.007 83.2%, 1);\n /* prettier-ignore */\n --pop-ease-menu: linear(0, 0.0034 0.81%, 0.0278 2.42%, 0.097 4.84%, 0.5361 15.32%, 0.655 18.55%, 0.7314, 0.7964 23.39%, 0.8662, 0.9185, 0.9561, 0.9818, 0.9984, 1.0083 42.74%, 1.014 46.77%, 1.0145 53.22%, 1.0053 68.55%, 1.0019 77.42%, 0.9998 100%);\n /* prettier-ignore */\n --pop-ease-pop-hover: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-pop-text: linear(0, 0.0051 0.99%, 0.0261, 0.0607 3.61%, 0.1192 5.26%, 0.2531 8.21%, 0.6509 16.1%, 0.7652 18.73%, 0.8512, 0.9232 23.33%, 0.9881 25.96%, 1.0305 28.26%, 1.0642 30.88%, 1.0782 32.53%, 1.089, 1.094 36.47%, 1.0942, 1.0896 41.07%, 1.0804 43.7%, 1.0354 53.23%, 1.0181 57.5%, 1.0061 61.44%, 0.9974 65.71%, 0.9925 70.31%, 0.991 75.9%, 0.9996 99.88%);\n /* prettier-ignore */\n --pop-ease-quick: linear(0, 0.008, 0.031 1.8%, 0.127 3.9%, 0.671 11.8%, 0.881 15.5%, 0.959, 1.02 19.2%, 1.064, 1.093 23.2%, 1.102, 1.108, 1.108, 1.104 28.7%, 1.089 31.4%, 1.038 38.1%, 1.016 41.5%, 0.999 45.4%, 0.99 49.6%, 0.989 55.3%, 1.001 74.9%, 1);\n /* prettier-ignore */\n --pop-ease-slow: linear(0, 0.005, 0.02 2%, 0.081 4.5%, 0.469 15.2%, 0.567, 0.65, 0.722 24.4%, 0.784, 0.835 31.1%, 0.878 34.9%, 0.914 39.1%, 0.942 43.8%, 0.964 49.1%, 0.979 55.4%, 0.989 62.4%, 0.995 71.1%, 1);\n\n /* Box-Shadow */\n --pop-shadow-xs: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);\n --pop-shadow-sm: 0px 1px 3px 0px rgba(16, 24, 40, 0.1), 0px 1px 2px 0px rgba(16, 24, 40, 0.06);\n --pop-shadow-md:\n 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);\n --pop-shadow-lg:\n 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);\n --pop-shadow-xl:\n 0px 20px 24px -4px rgba(16, 24, 40, 0.08), 0px 8px 8px -4px rgba(16, 24, 40, 0.03);\n --pop-shadow-2xl: 0px 24px 48px -12px rgba(16, 24, 40, 0.18);\n --pop-shadow-3xl: 0px 32px 48px -12px rgba(16, 24, 40, 0.32);\n --pop-shadow-4xl: 0px 24px 32px -12px rgba(16, 24, 40, 0.28);\n\n --pop-radius-none: 0; /* 0px */\n --pop-radius-xxs: 0.125rem; /* 2px */\n --pop-radius-xs: 0.25rem; /* 4px */\n --pop-radius-sm: 0.375rem; /* 6px */\n --pop-radius-md: 0.5rem; /* 8px */\n --pop-radius-lg: 0.625rem; /* 10px */\n --pop-radius-xl: 0.75rem; /* 12px */\n --pop-radius-2xl: 1rem; /* 16px */\n --pop-radius-3xl: 1.25rem; /* 20px */\n --pop-radius-4xl: 1.5rem; /* 24px */\n --pop-radius-full: 9999px; /* Creates a circle or oval */\n\n --pop-radius: 0.625rem;\n --pop-background: oklch(1 0 0);\n --pop-foreground: oklch(0 0 0);\n --pop-card: oklch(1 0 0);\n --pop-card-foreground: oklch(0.145 0 0);\n --pop-popover: oklch(1 0 0);\n --pop-popover-foreground: oklch(0 0 0);\n --pop-primary: oklch(0.205 0 0);\n --pop-primary-foreground: oklch(0.985 0 0);\n --pop-secondary: oklch(0.97 0 0);\n --pop-secondary-foreground: oklch(0.205 0 0);\n --pop-muted: oklch(0.97 0 0);\n --pop-muted-foreground: oklch(0.7152 0.0233 256.76);\n --pop-accent: oklch(0.97 0 0);\n --pop-accent-foreground: oklch(0.205 0 0);\n --pop-destructive: var(--color-error-600);\n --pop-border: oklch(0.1101 0.0763 264.05 / 10.2%);\n --pop-input: oklch(0.922 0 0);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.646 0.222 41.116);\n --pop-chart-2: oklch(0.6 0.118 184.704);\n --pop-chart-3: oklch(0.398 0.07 227.392);\n --pop-chart-4: oklch(0.828 0.189 84.429);\n --pop-chart-5: oklch(0.769 0.188 70.08);\n --pop-sidebar: oklch(0.985 0 0);\n --pop-sidebar-foreground: oklch(0.145 0 0);\n --pop-sidebar-primary: oklch(0.205 0 0);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.97 0 0);\n --pop-sidebar-accent-foreground: oklch(0.205 0 0);\n --pop-sidebar-border: oklch(0.922 0 0);\n --pop-sidebar-ring: oklch(0.708 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-background: oklch(0.15 0.03 255.43);\n --pop-foreground: oklch(0.66 0.006 255.43);\n --pop-card: oklch(0.205 0 0);\n --pop-card-foreground: oklch(0.985 0 0);\n --pop-popover: oklch(0.15 0.03 255.43);\n --pop-popover-foreground: oklch(0.66 0.006 255.43);\n --pop-primary: oklch(0.922 0 0);\n --pop-primary-foreground: oklch(0.205 0 0);\n --pop-secondary: oklch(0.269 0 0);\n --pop-secondary-foreground: oklch(0.985 0 0);\n --pop-muted: oklch(0.269 0 0);\n --pop-muted-foreground: oklch(0.66 0.006 255.43);\n --pop-accent: oklch(0.269 0 0);\n --pop-accent-foreground: oklch(0.985 0 0);\n --pop-destructive: var(--color-error-400);\n --pop-border: oklch(1 0 0 / 10%);\n --pop-input: oklch(1 0 0 / 15%);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.488 0.243 264.376);\n --pop-chart-2: oklch(0.696 0.17 162.48);\n --pop-chart-3: oklch(0.769 0.188 70.08);\n --pop-chart-4: oklch(0.627 0.265 303.9);\n --pop-chart-5: oklch(0.645 0.246 16.439);\n --pop-sidebar: oklch(0.205 0 0);\n --pop-sidebar-foreground: oklch(0.985 0 0);\n --pop-sidebar-primary: oklch(0.488 0.243 264.376);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.269 0 0);\n --pop-sidebar-accent-foreground: oklch(0.985 0 0);\n --pop-sidebar-border: oklch(1 0 0 / 10%);\n --pop-sidebar-ring: oklch(0.556 0 0);\n }\n }\n\n :host(.dark) {\n --pop-background: oklch(0.15 0.03 255.43);\n --pop-foreground: oklch(0.66 0.006 255.43);\n --pop-card: oklch(0.205 0 0);\n --pop-card-foreground: oklch(0.985 0 0);\n --pop-popover: oklch(0.15 0.03 255.43);\n --pop-popover-foreground: oklch(0.66 0.006 255.43);\n --pop-primary: oklch(0.922 0 0);\n --pop-primary-foreground: oklch(0.205 0 0);\n --pop-secondary: oklch(0.269 0 0);\n --pop-secondary-foreground: oklch(0.985 0 0);\n --pop-muted: oklch(0.269 0 0);\n --pop-muted-foreground: oklch(0.66 0.006 255.43);\n --pop-accent: oklch(0.269 0 0);\n --pop-accent-foreground: oklch(0.985 0 0);\n --pop-destructive: var(--color-error-400);\n --pop-border: oklch(1 0 0 / 10%);\n --pop-input: oklch(1 0 0 / 15%);\n --pop-ring: oklch(62.3% 0.214 259.815);\n --pop-chart-1: oklch(0.488 0.243 264.376);\n --pop-chart-2: oklch(0.696 0.17 162.48);\n --pop-chart-3: oklch(0.769 0.188 70.08);\n --pop-chart-4: oklch(0.627 0.265 303.9);\n --pop-chart-5: oklch(0.645 0.246 16.439);\n --pop-sidebar: oklch(0.205 0 0);\n --pop-sidebar-foreground: oklch(0.985 0 0);\n --pop-sidebar-primary: oklch(0.488 0.243 264.376);\n --pop-sidebar-primary-foreground: oklch(0.985 0 0);\n --pop-sidebar-accent: oklch(0.269 0 0);\n --pop-sidebar-accent-foreground: oklch(0.985 0 0);\n --pop-sidebar-border: oklch(1 0 0 / 10%);\n --pop-sidebar-ring: oklch(0.556 0 0);\n }\n\n *,\n *::before,\n *::after {\n box-sizing: inherit;\n }\n\n html,\n body {\n padding: 0;\n margin: 0;\n }\n\n svg {\n display: block;\n }\n\n p {\n margin: 0;\n padding: 0;\n }\n\n button {\n margin: 0;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n cursor: pointer;\n }\n}\n","@layer components {\n .btn {\n display: flex;\n height: auto;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n border-radius: 4px;\n border: 0;\n padding: 0.625rem 1.25rem;\n text-align: center;\n cursor: pointer;\n transition:\n background-color 0.2s,\n color 0.2s;\n }\n\n .btn-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n border-radius: var(--pop-radius-xs, 4px);\n border-style: solid;\n border-color: transparent;\n cursor: pointer;\n background-color: transparent;\n text-decoration: none;\n font-weight: 500;\n transition:\n background-color 0.2s,\n border-color 0.2s,\n color 0.2s;\n }\n\n /* Sizes */\n .btn-link--size-sm {\n font-size: 13px;\n line-height: 18px;\n letter-spacing: -0.08px;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 2px;\n border-right-width: 2px;\n }\n\n .btn-link--size-md {\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 3px;\n border-right-width: 3px;\n }\n\n .btn-link--size-lg {\n font-size: 16px;\n line-height: 24px;\n letter-spacing: 0;\n border-top-width: 1px;\n border-bottom-width: 1px;\n border-left-width: 4px;\n border-right-width: 4px;\n }\n\n /* Themes */\n .btn-link--theme-default {\n color: color-mix(in srgb, var(--pop-foreground) 50%, transparent);\n }\n\n .btn-link--theme-default.btn-link--primary {\n color: var(--pop-foreground);\n }\n\n .btn-link--theme-white {\n color: white;\n }\n\n .btn-link--theme-black {\n color: black;\n }\n\n /* Hover State */\n .btn-link--theme-default:hover,\n .btn-link--theme-black:hover {\n background-color: color-mix(in srgb, var(--pop-foreground) 10%, transparent);\n border-color: color-mix(in srgb, var(--pop-foreground) 10%, transparent);\n }\n\n .btn-link--theme-default:not(.btn-link--primary):hover {\n color: var(--pop-foreground);\n }\n\n .btn-link--theme-white:hover {\n background-color: color-mix(in srgb, white 16%, transparent);\n border-color: color-mix(in srgb, white 16%, transparent);\n }\n\n /* Active (Pressed) State */\n .btn-link:active {\n background-color: transparent;\n border-color: transparent;\n }\n\n .btn-link--theme-default:not(.btn-link--primary):active {\n color: color-mix(in srgb, var(--pop-foreground) 50%, transparent);\n }\n\n /* Focus State */\n .btn-link:focus-visible {\n background-color: var(--pop-ring, #155eef);\n border-color: var(--pop-ring, #155eef);\n color: white !important;\n outline: none;\n }\n\n /* Disabled State */\n .btn-link:disabled,\n .btn-link.is-disabled {\n color: color-mix(in srgb, var(--pop-foreground) 35%, transparent) !important;\n background-color: transparent !important;\n border-color: transparent !important;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .btn:focus-visible {\n outline: 2px solid currentColor; /* focus-visible */\n outline-offset: 2px;\n }\n}\n","@layer components {\n .mask {\n -webkit-mask-size: contain;\n mask-size: contain;\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-position: center;\n mask-position: center;\n }\n\n .mask-squircle {\n -webkit-mask-image: url(\"data:image/svg+xml,%3csvg width='160' height='160' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M 0 80 C 0 14.12 14.12 0 80 0 C 145.88 0 160 14.12 160 80 C 160 145.88 145.88 160 80 160 C 14.12 160 0 145.88 0 80 Z'/%3e%3c/svg%3e\");\n mask-image: url(\"data:image/svg+xml,%3csvg width='160' height='160' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M 0 80 C 0 14.12 14.12 0 80 0 C 145.88 0 160 14.12 160 80 C 160 145.88 145.88 160 80 160 C 14.12 160 0 145.88 0 80 Z'/%3e%3c/svg%3e\");\n }\n}\n","let isGlobalDark = false;\nconst activeElements = new Set<HTMLElement>();\nlet globalObserver: MutationObserver | null = null;\nlet mediaQuery: MediaQueryList | null = null;\n\nfunction checkGlobalDark(): boolean {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return false;\n\n const hasDarkClass =\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\");\n const hasLightClass =\n document.documentElement.classList.contains(\"light\") ||\n document.body.classList.contains(\"light\");\n\n if (hasDarkClass) return true;\n if (hasLightClass) return false;\n\n if (!mediaQuery) {\n mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n }\n return mediaQuery.matches;\n}\n\nfunction updateGlobalDark() {\n const newDark = checkGlobalDark();\n if (newDark !== isGlobalDark) {\n isGlobalDark = newDark;\n activeElements.forEach((el) => {\n const isDark = isGlobalDark || !!el.closest(\".dark\");\n el.classList.toggle(\"dark\", isDark);\n });\n }\n}\n\nconst mediaListener = () => {\n updateGlobalDark();\n};\n\nexport function registerThemeObserver(el: HTMLElement) {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n if (activeElements.size === 0) {\n isGlobalDark = checkGlobalDark();\n globalObserver = new MutationObserver(() => {\n updateGlobalDark();\n });\n globalObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n globalObserver.observe(document.body, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mediaQuery.addEventListener(\"change\", mediaListener);\n }\n\n activeElements.add(el);\n\n const isDark = isGlobalDark || !!el.closest(\".dark\");\n el.classList.toggle(\"dark\", isDark);\n}\n\nexport function unregisterThemeObserver(el: HTMLElement) {\n activeElements.delete(el);\n if (activeElements.size === 0) {\n if (globalObserver) {\n globalObserver.disconnect();\n globalObserver = null;\n }\n if (mediaQuery) {\n mediaQuery.removeEventListener(\"change\", mediaListener);\n mediaQuery = null;\n }\n }\n}\n","import baseStyles from \"../styles/base.css?inline\";\nimport btnStyles from \"../styles/buttons.css?inline\";\nimport masksStyles from \"../styles/masks.css?inline\";\n\nimport { effect, untracked } from \"@preact/signals-core\";\n\nexport function createSheet(cssText: string): CSSStyleSheet {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(cssText);\n return sheet;\n}\n\nexport const sharedBaseSheet = createSheet(baseStyles);\nexport const btnSheet = createSheet(btnStyles);\nexport const masksSheet = createSheet(masksStyles);\n\nimport { registerThemeObserver, unregisterThemeObserver } from \"../helpers/theme.js\";\n\nexport abstract class BaseElement extends HTMLElement implements EventListenerObject {\n protected baseStyleSheets: CSSStyleSheet[] = [sharedBaseSheet, btnSheet, masksSheet];\n protected get styleSheets(): CSSStyleSheet[] {\n return [];\n }\n\n private _hasRendered = false;\n\n private _disposables: Array<() => void> = [];\n\n constructor() {\n super();\n this.attachShadow({ mode: \"open\" });\n if (this.shadowRoot) {\n this.shadowRoot.adoptedStyleSheets = this.styles;\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n if (oldValue === newValue) return;\n\n const pascalName = name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n const methodName = `on${pascalName}Changed`;\n\n if (typeof (this as any)[methodName] === \"function\") {\n (this as any)[methodName](newValue, oldValue);\n }\n }\n\n /**\n * Use this instead of calling effect() directly to ensure\n * automatic cleanup when the component disconnects.\n */\n protected addEffect(callback: () => void) {\n this._disposables.push(effect(callback));\n }\n\n connectedCallback() {\n registerThemeObserver(this);\n untracked(() => {\n this.render();\n this._bindEvents();\n this.setupEffects();\n });\n }\n\n disconnectedCallback() {\n unregisterThemeObserver(this);\n // Kill all active subscriptions\n this._disposables.forEach((dispose) => dispose());\n this._disposables = [];\n }\n\n protected events: Record<string, string> = {};\n\n private _bindEvents() {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) {\n return;\n }\n Object.keys(this.events).forEach((key) => {\n shadowRoot.addEventListener(key, this);\n });\n }\n\n handleEvent(event: Event): void {\n const methodName = this.events[event.type];\n\n if (methodName && typeof (this as any)[methodName] === \"function\") {\n (this as any)[methodName](event);\n }\n }\n\n protected emit<T = unknown>(eventName: string, options: CustomEventInit<T> = {}) {\n this.dispatchEvent(\n new CustomEvent<T>(eventName, {\n bubbles: true,\n composed: true,\n ...options,\n }),\n );\n }\n\n // --- Abstract & Overrideable Methods ---\n protected abstract getTemplate(): string;\n\n protected get styles(): CSSStyleSheet[] {\n return [...this.baseStyleSheets, ...this.styleSheets];\n }\n\n protected setupEffects(): void {}\n\n protected render() {\n if (!this.shadowRoot) return;\n this.shadowRoot.innerHTML = this.getTemplate();\n this._hasRendered = true;\n }\n\n protected hideElement(selector: string, shouldHide: boolean, useDisplayNone = true) {\n if (!this.shadowRoot || !this._hasRendered) {\n return;\n }\n\n const el = this.shadowRoot.querySelector(selector);\n if (!el) {\n console.warn(`Element not found for selector: ${selector}`);\n return;\n }\n\n if (useDisplayNone) {\n el.classList.toggle(\"hidden\", shouldHide);\n } else {\n el.classList.toggle(\"invisible\", shouldHide);\n }\n }\n\n protected setText(selector: string, text: string | number) {\n const el = this.shadowRoot?.querySelector(selector);\n if (el && el.textContent !== String(text)) {\n el.textContent = String(text);\n }\n }\n\n protected setAttr(selector: string, attr: string, value: string | null) {\n const el = this.shadowRoot?.querySelector(selector);\n if (!el) return;\n\n if (value === null) {\n el.removeAttribute(attr);\n } else if (el.getAttribute(attr) !== value) {\n el.setAttribute(attr, value);\n }\n }\n\n protected toggleClass(selector: string, className: string, force?: boolean) {\n const el = this.shadowRoot?.querySelector(selector);\n if (!el) return;\n\n el.classList.toggle(className, force);\n }\n\n protected getElement<T extends Element = HTMLElement>(selector: string): T | null {\n return this.shadowRoot?.querySelector(selector) ?? null;\n }\n}\n","import {\n authError,\n authPending,\n clearAuthError,\n requestSignIn,\n} from \"../store/auth-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n position: relative;\n\n --pop-auth-border: var(--pop-border, rgba(0, 0, 32, 0.04));\n --pop-auth-watermark: rgba(0, 0, 32, 0.4);\n --pop-auth-btn: #000000;\n --pop-auth-logo: rgba(0, 0, 32, 0.35);\n --pop-auth-error: #dc2626;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-auth-border: var(--pop-border, rgba(255, 255, 255, 0.1));\n --pop-auth-watermark: rgba(255, 255, 255, 0.4);\n --pop-auth-btn: #ffffff;\n --pop-auth-logo: rgba(255, 255, 255, 0.35);\n --pop-auth-error: var(--pop-destructive, #f87171);\n }\n }\n\n :host(.dark) {\n --pop-auth-border: var(--pop-border, rgba(255, 255, 255, 0.1));\n --pop-auth-watermark: rgba(255, 255, 255, 0.4);\n --pop-auth-btn: #ffffff;\n --pop-auth-logo: rgba(255, 255, 255, 0.35);\n --pop-auth-error: var(--pop-destructive, #f87171);\n }\n\n .panel {\n position: relative;\n border-top: 1px solid var(--pop-auth-border);\n }\n\n .watermark {\n position: absolute;\n top: -16px;\n left: 8px;\n font-family: Inter, sans-serif;\n font-size: 8px;\n font-weight: 700;\n letter-spacing: 1px;\n color: var(--pop-auth-watermark);\n text-transform: uppercase;\n backdrop-filter: blur(4px);\n border-radius: 9999px;\n padding: 2px 6px;\n pointer-events: none;\n }\n\n .actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n }\n\n .join-btn {\n font-family: Inter, sans-serif;\n font-size: 13px;\n font-weight: 600;\n color: var(--pop-auth-btn);\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n letter-spacing: -0.08px;\n line-height: 18px;\n }\n\n .join-btn:disabled {\n opacity: 0.6;\n cursor: default;\n }\n\n .logo {\n font-family: Inter, sans-serif;\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 1.5px;\n color: var(--pop-auth-logo);\n text-transform: uppercase;\n }\n\n .error {\n padding: 0 16px 12px;\n font-family: Inter, sans-serif;\n font-size: 12px;\n line-height: 16px;\n color: var(--pop-auth-error);\n text-align: center;\n }\n`);\n\nexport class PopAuthPanel extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".join-btn\")) return;\n void this.handleJoin();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const pending = authPending.value;\n const error = authError.value;\n\n const joinBtn = this.getElement<HTMLButtonElement>(\".join-btn\");\n if (joinBtn) {\n joinBtn.disabled = pending;\n joinBtn.textContent = pending ? \"Signing in…\" : \"Join the Conversation\";\n }\n\n const errorEl = this.getElement<HTMLDivElement>(\".error\");\n if (errorEl) {\n if (error) {\n errorEl.hidden = false;\n errorEl.textContent = error;\n } else {\n errorEl.hidden = true;\n errorEl.textContent = \"\";\n }\n }\n });\n }\n\n private async handleJoin(): Promise<void> {\n clearAuthError();\n await requestSignIn(this.gridStore.apiUrl, this.gridStore.publicKey);\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"panel\">\n <div class=\"watermark\">Popgrids</div>\n <div class=\"actions\">\n <button class=\"join-btn\" type=\"button\">Join the Conversation</button>\n <span class=\"logo\">POPGRIDS</span>\n </div>\n <div class=\"error\" hidden></div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-auth-panel\")) {\n customElements.define(\"pop-auth-panel\", PopAuthPanel);\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD8AAABMCAYAAADa6W+wAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAUuSURBVHgB5ZyBceIwEEX3bq4AOsAdQAdxKggl+Co4rgKcCkgqgFRAUgGkAqACOxVAKvDpg+VRHEmWQSubuTezg8Ega7UrebWS+UG8jIXEQoZCovI9lcd1ciHHUnZCPsrXXflZ7xkISYSshByEFJ5kLWRO54bsHRGdK+dTYZNkQhbUg4aI6FyRoiNBQyQUGLj3jMJYuleNMC4v1gel67Ig/WCq5Qe144+QlM6Wb2QwGNB4PD7JaDQ6veIzKZLj8XiSPM9Pr/v9nna73UnwWUtyIb+FbMgjM3K0QBzHxXq9Lg6HQ3Et2+22WCwWpzJdr1/KjDzRqLiwZDGbzbwobCLLslNDRFEUrAEmTReBVVCxkLRohIsbICLLiA5roxJdAm9zaIAJXUBmKhCtHtraJjAuNHjBgVrcBcDsFhSXoD4NDbB2VTyyFNI7xSUODTB1UX5hKmA+nxd9Bl0AYxGZ3X9wkdWTJCluARjIYv2ULrG6T3eHhabT6SkY4sASFB1aWx23FJ+IULcqm6MBUKbF+rFO+ZQCje6qa6J8jsjQYv2FTvmMAvb1yWRSXePp6anwzWq1cnb9MQXo6yqwthyZ0Q04y9e5/k9F+VjnCpiGCrckDjCtFV51OpZTWN/lo/4Gxqryd7pvCNckTkS/rI7f39/JN5b6j1TltU10d3dHnKjl+7Y8sHhtpS+iHm3f4JyfS2RIytHvMV4ZdMt+1lvhS9OUaSdu5DUuSFk5l60hksoPWv7QK9I1kb/zjU2HRsuHIFQj17FanusWV4fD4i5I5Ye6k8PhkELAqbxlHDn2os9L5Tm6mUX5vBfKy/s7x/U+Pz9Np7q3/GazqY7VaI+j/Br7zpV/e3urjjmiSUvUWJ3QRkHcqAlHzL58g+iUzAmNLxOboGAgur+/rwYkjgnU6+ur6VROXVpezbLA6hw5A9dMTnDlZRoLinPk8CwTmm85vE76PCdIvRn0ympdQL8YGWI6y0GD1atVGzngaePLrmLua8FAaqEaBTsb7bl4fHy0hbTPdB7pv7AmjYtwraZw0eDu6OuRqrTV7T8+PuhWkHGDhUeqWV0qr43+b6XPI4RVAyYNGyHL+odS+Vz3i1tQ/vn5uUlxnPitO/FL+cL3XzEkFAFmWsjRY28eZnKXTKBQBgY3y6xN8pcM+km0O66wlhZiUMJ1lstlY1yB8y335KU2peUOTKRQtvWTyOGJypJv4FGwmlD42zl4Aq6rZnQhFyxnYYBLXb4YEemXpjlx2ENziSBaTaglncT3nhtgTS23nEkyXYEhdl417KJwtfaUrkCrPPbOhEDdqNBS6ZQcd4HbWOkugN0NIWhhfRhpQR4eM/mlHGujPEvq1ysNOXu4tHzaKidPqLO6XPcFrkCnDgIdy/IYUryYiubkEVV5bSwbSnlgW04mBhqVDxnfh16tVZXXhk8hLW9bVCQGemV5y7VyCkAnUR5APEHmezkL9RxeZ4Oey5qab5yUVxcTuXh5eTGd2lMgnkjjepg/c9JmdYWT2FQJjo3BEsusLqPAbHUV4VpMTNPUZvUFBSYxVMT7vvsGxWH1iDpgTYbbDjzg2i6AXBweMSH77C2hjsAUy/psPLwASce2OD4GuqIA2B4hxzRyrrzHbfBb8I2ZGJKODw8PVeJRxujysXDcw/FYOBKWDhFjLuSeAkV1NlJqn125RjLqqJ+bSOk/VVwSEe9fRSzJQx6Om4T8NgLKiunGSMh8O3QR/Damjmn7hyF14KpxKSM6d49IOa/7u6dX6snfPf0DiVL6IWhCmZ4AAAAASUVORK5CYII=\"","export const colors = [\n \"#DDD0BE\",\n \"#E9DCBB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#C6D0CB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#E9DCBB\",\n \"#DFC2C0\",\n \"#CFD4C6\",\n \"#D7E3E8\",\n \"#CFD4C6\",\n \"#D6B3B3\",\n \"#E9DCBB\",\n \"#CFCBDC\",\n \"#BFD6D7\",\n \"#E3D2C6\",\n \"#D1E2E7\",\n \"#D6B3B3\",\n \"#BFD6D7\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#DFC2C0\",\n \"#D1E2E7\",\n \"#CFD4C6\",\n \"#E9DCBB\",\n \"#D7E3E8\",\n \"#CFD4C6\",\n \"#C6D0CB\",\n \"#E9DCBB\",\n \"#C7D1B0\",\n \"#E9DCBB\",\n \"#CFCBDC\",\n \"#E3D2C6\",\n \"#E9DCBB\",\n];\n\nexport const sampleColor = (index?: number) => {\n if (typeof index === \"number\") {\n return colors[index % colors.length] ?? \"#e5e7eb\";\n }\n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n/** 32-bit FNV-1a over UTF-8 bytes — deterministic, no lookup table. */\nexport function fnv1a32(data: string): number {\n const bytes = new TextEncoder().encode(data);\n let h = 0x811c9dc5;\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i] ?? 0;\n h ^= byte;\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/** Deterministic background color from a stable string (e.g. user id, org id, slug). */\nexport function backgroundColor(id: string): string {\n return colors[fnv1a32(id) % colors.length] ?? \"#e5e7eb\";\n}\n\n","import deletedUserMarkSrc from \"../assets/popgrids-letter-p.png?inline\";\nimport { backgroundColor, sampleColor } from \"../helpers/color.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n\n --comment-avatar-border-size: 1px;\n --comment-avatar-border-color: var(--color-background, #fff);\n --comment-avatar-size: 32px;\n }\n\n .comment-avatar {\n align-items: center;\n display: flex;\n flex-shrink: 0;\n isolation: isolate;\n justify-content: center;\n position: relative;\n width: calc(var(--comment-avatar-size) + calc(var(--comment-avatar-border-size) * 2));\n height: calc(var(--comment-avatar-size) + calc(var(--comment-avatar-border-size) * 2));\n }\n\n .comment-avatar--size-xs {\n --comment-avatar-size: 32px;\n }\n\n .comment-avatar--size-sm {\n --comment-avatar-size: 56px;\n }\n\n .comment-avatar--size-md {\n --comment-avatar-size: 80px;\n }\n\n .comment-avatar--size-lg {\n --comment-avatar-size: 120px;\n }\n\n .comment-avatar--size-xl {\n --comment-avatar-size: 140px;\n }\n\n .comment-avatar__background {\n background-color: var(--comment-avatar-border-color);\n position: absolute;\n top: 0;\n left: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n }\n\n /**\n * Content\n */\n\n .comment-avatar__content {\n align-items: center;\n background-color: var(--color-surface-bg-default);\n display: flex;\n justify-content: center;\n overflow: hidden;\n position: relative;\n height: var(--comment-avatar-size);\n width: var(--comment-avatar-size);\n z-index: 20;\n\n /* Initials styling */\n font-family: Inter, sans-serif;\n font-weight: 600;\n color: #374151;\n font-size: calc(var(--comment-avatar-size) * 0.35);\n line-height: 1;\n }\n\n .comment-avatar__content::slotted(img) {\n -webkit-user-drag: none;\n align-self: stretch;\n flex: 1 0 0;\n height: var(--comment-avatar-size);\n object-fit: cover;\n pointer-events: none;\n position: absolute;\n user-select: none;\n width: var(--comment-avatar-size);\n }\n\n .comment-avatar__deleted-mark {\n -webkit-user-drag: none;\n bottom: -3px;\n height: auto;\n left: 0;\n object-fit: cover;\n pointer-events: none;\n position: absolute;\n user-select: none;\n width: 100%;\n transform: scale(0.57);\n }\n`);\n\nexport class PopCommentAvatar extends BaseElement {\n private _backgroundColor: string;\n\n constructor() {\n super();\n this._backgroundColor = sampleColor() ?? \"#e5e7eb\";\n }\n\n static get observedAttributes() {\n return [\"size\", \"data-color-key\", \"deleted\"];\n }\n\n onSizeChanged() {\n this.render();\n }\n\n onDataColorKeyChanged() {\n this.render();\n }\n\n onDeletedChanged() {\n this.render();\n }\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n get size(): string {\n return this.getAttribute(\"size\") || \"md\";\n }\n\n set size(value: string) {\n this.setAttribute(\"size\", value);\n }\n\n get deleted(): boolean {\n return this.hasAttribute(\"deleted\");\n }\n\n set deleted(value: boolean) {\n if (value) {\n this.setAttribute(\"deleted\", \"\");\n } else {\n this.removeAttribute(\"deleted\");\n }\n }\n\n protected getTemplate(): string {\n const size = this.size;\n const deleted = this.deleted;\n const key = this.getAttribute(\"data-color-key\");\n const bg = deleted\n ? \"var(--pop-muted-foreground, #e5e7eb)\"\n : key\n ? backgroundColor(key)\n : this._backgroundColor;\n\n const content = deleted\n ? `<div\n class=\"comment-avatar__content mask mask-squircle\"\n part=\"content\"\n style=\"background-color: ${bg}; opacity: 0.15\"\n ><img class=\"comment-avatar__deleted-mark\" src=\"${deletedUserMarkSrc}\" alt=\"Deleted user\" /></div>`\n : `<slot\n class=\"comment-avatar__content mask mask-squircle\"\n part=\"content\"\n style=\"background-color: ${bg};\"\n ></slot>`;\n\n return /* html */ `\n <div class=\"comment-avatar comment-avatar--size-${size}\" part=\"base\">\n <div class=\"comment-avatar__background mask mask-squircle\" part=\"background\"></div>\n ${content}\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-avatar\")) {\n customElements.define(\"pop-comment-avatar\", PopCommentAvatar);\n}\n","export function getInitials(name: string | null | undefined): string {\n if (!name) return \"?\";\n return name\n .split(\" \")\n .map((p) => p[0] ?? \"\")\n .join(\"\")\n .toUpperCase()\n .slice(0, 2);\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { currentUser } from \"../store/auth-store.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\nimport type { PopCommentInput } from \"./pop-comment-input.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n background: var(--pop-background);\n border-top: 1px solid var(--pop-bar-input-bg);\n display: block;\n padding: 6px;\n position: relative;\n\n --pop-bar-avatar-bg: #e5e7eb;\n --pop-bar-avatar-color: #374151;\n --pop-bar-avatar-border: #ffffff;\n --pop-bar-input-bg: rgba(0, 0, 32, 0.04);\n --pop-bar-send-hover: rgba(0, 0, 32, 0.06);\n --pop-bar-send-color: #000000;\n --pop-bar-watermark: rgba(0, 0, 32, 0.1);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-bar-avatar-bg: #1f2937;\n --pop-bar-avatar-color: #d1d5db;\n --pop-bar-avatar-border: var(--pop-popover, #151d2a);\n --pop-bar-input-bg: rgba(255, 255, 255, 0.05);\n --pop-bar-send-hover: rgba(255, 255, 255, 0.08);\n --pop-bar-send-color: #ffffff;\n --pop-bar-watermark: rgba(255, 255, 255, 0.1);\n }\n }\n\n :host(.dark) {\n --pop-bar-avatar-bg: #1f2937;\n --pop-bar-avatar-color: #d1d5db;\n --pop-bar-avatar-border: var(--pop-popover, #151d2a);\n --pop-bar-input-bg: rgba(255, 255, 255, 0.05);\n --pop-bar-send-hover: rgba(255, 255, 255, 0.08);\n --pop-bar-send-color: #ffffff;\n --pop-bar-watermark: rgba(255, 255, 255, 0.1);\n }\n\n .bar {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .bar__user {\n display: flex;\n align-items: center;\n align-self: flex-start;\n flex-shrink: 0;\n padding-top: 2px;\n }\n\n .bar__avatar {\n flex-shrink: 0;\n --comment-avatar-border-size: 0px;\n }\n\n .bar__avatar--reply {\n margin-right: -4px;\n z-index: 1;\n }\n\n .bar__avatar--user {\n z-index: 2;\n }\n\n .bar__user.has-reply .bar__avatar--user {\n --comment-avatar-border-size: 2px;\n --comment-avatar-border-color: var(--pop-bar-avatar-border);\n }\n\n .bar__input-wrap {\n flex: 1;\n min-width: 0;\n background: var(--pop-bar-input-bg);\n border-radius: 18px;\n overflow: hidden;\n display: flex;\n align-items: flex-end;\n padding: 4px 8px 4px 12px;\n max-height: 280px;\n }\n\n .bar__send {\n align-items: center;\n align-self: flex-end;\n background: none;\n border: none;\n cursor: pointer;\n display: flex;\n justify-content: center;\n padding-bottom: 2px;\n }\n\n .logo-watermark {\n position: absolute;\n top: -16px;\n left: 8px;\n font-family: Inter, sans-serif;\n font-size: 8px;\n font-weight: 700;\n letter-spacing: 1px;\n color: var(--pop-bar-watermark);\n text-transform: uppercase;\n border-radius: 9999px;\n padding: 2px 6px;\n pointer-events: none;\n user-select: none;\n }\n`);\n\nconst LOGO_WATERMARK_SVG = `<svg width=\"64\" height=\"11\" viewBox=\"0 0 64 11\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3.91111 0C0.892839 0 0 2.11357 0 4.77714C0 5.76321 0.0987654 6.73357 0.213333 7.70786C0.25679 8.08893 0.240988 8.50929 0.312099 8.89036C0.497778 9.89214 1.44593 10.3557 2.36642 10.3557C3.62667 10.3557 4.4642 9.56607 4.4642 8.30107C4.4642 7.57036 4.22321 7.09107 3.5279 6.80821C3.48444 6.7925 3.44099 6.78071 3.44099 6.72179C3.44099 6.62357 3.59901 6.55286 3.69778 6.55286C4.03753 6.55286 4.57481 6.89071 5.04494 6.89071C6.88593 6.89071 7.90519 5.13071 7.90519 3.48071C7.90519 1.08429 6.13136 0 3.91111 0ZM3.89531 5.18179C3.78074 5.18179 3.68198 5.08357 3.68198 4.96964C3.68198 4.81643 3.89531 4.7025 3.96642 4.57679C4.12049 4.29393 4.16395 3.81464 4.16395 3.4925C4.16395 3.11143 4.06519 2.40821 3.8242 2.12536C3.75309 2.04286 3.65432 1.99964 3.65432 1.88571C3.65432 1.77179 3.76889 1.67357 3.87951 1.67357C4.36148 1.67357 4.60247 3.08393 4.60247 3.44929C4.60247 3.84214 4.47605 5.18179 3.89531 5.18179Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M12.7368 0.239637C9.73433 0.239637 7.93285 2.35321 7.93285 5.25249C7.93285 8.15178 9.73038 10.2654 12.7368 10.2654C15.7432 10.2654 17.5249 8.12428 17.5249 5.25249C17.5249 2.38071 15.7116 0.239637 12.7368 0.239637ZM12.8672 8.83142C12.8198 8.89035 12.7249 9.00035 12.6104 9.00035C12.4958 9.00035 12.3852 8.90214 12.3852 8.78821C12.3852 8.74499 12.7526 8.19499 12.8119 8.02607C13.037 7.36214 13.0805 6.64321 13.0805 5.93999C13.0805 4.99714 12.9106 3.78321 12.3299 3.00928C12.2153 2.86785 11.8637 2.60071 11.8637 2.44749C11.8637 2.33357 11.9625 2.23535 12.077 2.23535C12.1758 2.23535 12.2746 2.32178 12.3457 2.37678C13.2504 3.12321 13.523 4.82821 13.523 5.93999C13.523 6.81214 13.4874 8.08499 12.8711 8.82749L12.8672 8.83142Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M21.6533 0C18.6351 0 17.7422 2.11357 17.7422 4.77714C17.7422 5.76321 17.841 6.73357 17.9555 7.70786C17.999 8.08893 17.9832 8.50929 18.0543 8.89036C18.24 9.89214 19.1881 10.3557 20.1086 10.3557C21.3689 10.3557 22.2064 9.56607 22.2064 8.30107C22.2064 7.57036 21.9654 7.09107 21.2701 6.80821C21.2267 6.7925 21.1832 6.78071 21.1832 6.72179C21.1832 6.62357 21.3412 6.55286 21.44 6.55286C21.7797 6.55286 22.317 6.89071 22.7871 6.89071C24.6281 6.89071 25.6474 5.13071 25.6474 3.48071C25.6474 1.08429 23.8775 0 21.6533 0ZM21.6415 5.18179C21.5269 5.18179 21.4281 5.08357 21.4281 4.96964C21.4281 4.81643 21.6415 4.7025 21.7126 4.57679C21.8667 4.29393 21.9101 3.81464 21.9101 3.4925C21.9101 3.11143 21.8113 2.40821 21.5704 2.12536C21.4992 2.04286 21.4005 1.99964 21.4005 1.88571C21.4005 1.77179 21.5151 1.67357 21.6257 1.67357C22.1076 1.67357 22.3486 3.08393 22.3486 3.44929C22.3486 3.84214 22.2222 5.18179 21.6415 5.18179Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M31.9012 4.16822C30.882 4.16822 29.4637 4.6318 29.4637 5.84572C29.4637 6.53715 29.9733 7.56251 30.7832 7.56251C31.2929 7.56251 31.6208 7.16965 31.7906 7.16965C31.8341 7.16965 31.8736 7.19715 31.8736 7.24037C31.8736 7.64894 31.0795 7.83358 30.7674 7.83358C29.677 7.83358 29.0963 6.90251 29.0963 5.91644C29.0963 4.70644 30.242 3.77537 31.4035 3.77537C31.7432 3.77537 32.0988 3.87358 32.4385 3.87358C33.4459 3.87358 34.165 2.97394 34.165 2.01537C34.165 0.424295 32.2687 0.0589382 31.0045 0.0589382C27.6464 0.0589382 25.6909 2.22751 25.6909 5.52358C25.6909 8.56822 27.279 10.5089 30.4237 10.5089C32.4622 10.5089 34.6864 9.6368 34.6864 7.26787C34.6864 5.6493 33.6237 4.16822 31.8973 4.16822H31.9012Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M41.2681 6.56464C41.0113 6.56464 40.802 6.66286 40.5886 6.66286C40.5452 6.66286 40.5333 6.61964 40.5333 6.59214C40.5333 6.49393 40.5768 6.45071 40.6479 6.42321C40.8889 6.34071 41.1457 6.28179 41.3827 6.16786C42.4612 5.66107 43.0973 4.7575 43.0973 3.56321C43.0973 1.40643 41.2405 0.0982143 39.202 0.0982143C38.4632 0.0982143 37.7442 0.310357 37.12 0.648214C35.4212 1.56357 35.0933 2.87571 34.9946 4.66321C34.9511 5.36643 34.9511 6.07357 34.9511 6.77679V8.48179C34.9511 9.55036 35.6583 10.4107 36.7763 10.4107C37.5822 10.4107 38.3052 9.83321 38.4909 9.07107C38.5896 8.61929 38.5343 8.085 38.5343 7.64893C38.5343 7.60571 38.5501 7.59393 38.5896 7.59393C38.6291 7.59393 38.6765 7.62143 38.7042 7.63714C39.202 8.83536 39.8815 10.3557 41.4222 10.3557C42.4849 10.3557 43.362 9.60929 43.362 8.525C43.362 7.44071 42.3427 6.56857 41.2642 6.56857L41.2681 6.56464ZM38.961 5.18179C38.8464 5.18179 38.7476 5.08357 38.7476 4.96964C38.7476 4.81643 38.961 4.7025 39.0321 4.57679C39.1862 4.29393 39.2296 3.81464 39.2296 3.4925C39.2296 3.11143 39.1309 2.40821 38.8899 2.12536C38.8188 2.04286 38.7358 1.99964 38.7358 1.88571C38.7358 1.77179 38.8346 1.67357 38.9491 1.67357C39.4311 1.67357 39.6721 3.08393 39.6721 3.44929C39.6721 3.84214 39.5575 5.18179 38.9649 5.18179H38.961Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M46.7674 0.549991C46.4277 0.326063 45.9457 0.212134 45.5348 0.212134C44.642 0.212134 43.8756 0.915349 43.7768 1.79142C43.7491 2.04678 43.761 2.28642 43.761 2.55356V4.94606L43.7175 7.46821V8.72142C43.7175 9.70749 44.5669 10.4814 45.5467 10.4814C46.2696 10.4814 47.0637 10.0296 47.3324 9.35392C47.4864 8.97285 47.5022 8.43856 47.5022 8.02999V6.92999L47.518 4.73392V2.53785C47.518 1.72071 47.5022 1.07249 46.7674 0.549991Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M50.2993 0.125713C48.8533 0.125713 48.1304 0.801428 48.1304 2.25107V2.82857L48.1462 3.96786V4.54536C48.1462 4.98143 48.1462 5.39 48.1304 5.82607C48.1027 6.34857 48.0316 6.86714 48.0316 7.40536C48.0316 9.3775 49.0509 10.3361 51.0222 10.3361C54.0523 10.3361 56.1067 9.03964 56.1067 5.81429C56.1067 1.925 54.2222 0.121785 50.2993 0.121785V0.125713ZM51.6583 7.91607C51.5437 7.91607 51.4449 7.81786 51.4449 7.70393C51.4449 7.66071 51.4608 7.83352 51.4884 7.59C51.8558 6.985 51.9546 6.14036 51.9546 5.44893C51.9546 4.80071 51.8835 3.84214 51.4726 3.33536C51.4015 3.22143 51.2593 3.13893 51.2593 2.9975C51.2593 2.88357 51.358 2.78536 51.4726 2.78536C51.6859 2.78536 51.9822 3.31964 52.0691 3.50428C52.3378 4.125 52.3812 4.80071 52.3812 5.46071C52.3812 5.86928 52.1679 7.91214 51.6583 7.91214V7.91607Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n<path d=\"M62.7239 5.1268C61.9022 5.05608 60.7249 4.77322 60.0889 4.23894C60.0059 4.16822 59.8637 4.07001 59.8637 3.9443C59.8637 3.90108 59.8795 3.83037 59.9348 3.83037C60.0889 3.83037 61.0805 4.62001 61.9338 4.62001C63.0123 4.62001 64 3.78715 64 2.69108C64 0.887867 61.5941 0.157152 60.1324 0.157152C57.9635 0.157152 56.3516 1.5518 56.3516 3.76358C56.3516 4.24287 56.4227 4.90287 56.7783 5.27215C56.9482 5.4568 57.2326 5.4568 57.4578 5.4568C58.3072 5.4568 59.3857 5.72394 59.836 6.49787C59.8795 6.56858 59.919 6.68251 59.919 6.76501C59.919 6.79251 59.919 6.83572 59.8914 6.82001C59.8084 6.79251 59.7373 6.7218 59.678 6.6668C59.1802 6.18751 58.5007 5.70822 57.7817 5.70822C56.7032 5.70822 56.324 6.73751 56.324 7.63715C56.324 9.45215 57.9674 10.4539 59.6385 10.4539C61.6217 10.4539 64 9.15751 64 6.94572C64 6.12858 63.6444 5.21322 62.7239 5.13072V5.1268Z\" fill=\"#000020\" fill-opacity=\"0.1\"/>\n</svg>`;\n\nexport class PopCommentBar extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".bar__send\")) return;\n void this.handleSend();\n }\n\n protected setupEffects() {\n let lastReplyingTo: string | null = null;\n let lastEditingCommentId: string | null = null;\n\n this.addEffect(() => {\n const parentCommentId = this.gridStore.replyingTo.value;\n\n if (parentCommentId && parentCommentId !== lastReplyingTo) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n setTimeout(() => input.focus(), 0);\n }\n }\n lastReplyingTo = parentCommentId;\n });\n\n this.addEffect(() => {\n const editingComment = this.gridStore.editingComment.value;\n if (editingComment && editingComment.id !== lastEditingCommentId) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n input.setValue(editingComment.body);\n setTimeout(() => input.focus(), 0);\n }\n } else if (!editingComment && lastEditingCommentId) {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (input) {\n input.clear();\n }\n }\n lastEditingCommentId = editingComment?.id ?? null;\n });\n\n this.addEffect(() => {\n const user = currentUser.value;\n const barUser = this.getElement<HTMLDivElement>(\".bar__user\");\n if (!barUser) return;\n\n const parentComment = this.gridStore.replyingToComment.value;\n const parentAuthor = parentComment?.author;\n const editingComment = this.gridStore.editingComment.value;\n\n if (editingComment) {\n barUser.classList.remove(\"has-reply\");\n const userColorKey = user?.id ?? user?.name ?? \"\";\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n barUser.innerHTML = userAvatarHtml;\n } else if (parentAuthor) {\n barUser.classList.add(\"has-reply\");\n\n const parentColorKey = parentAuthor.id ?? parentAuthor.name ?? \"\";\n const userColorKey = user?.id ?? user?.name ?? \"\";\n\n const parentAvatarHtml = parentAuthor.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--reply\" data-color-key=\"${parentColorKey}\"><img src=\"${parentAuthor.image}\" alt=\"${parentAuthor.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--reply\" data-color-key=\"${parentColorKey}\">${getInitials(parentAuthor.name)}</pop-comment-avatar>`;\n\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n\n barUser.innerHTML = parentAvatarHtml + userAvatarHtml;\n } else {\n barUser.classList.remove(\"has-reply\");\n\n const userColorKey = user?.id ?? user?.name ?? \"\";\n\n const userAvatarHtml = user?.image\n ? `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\"><img src=\"${user.image}\" alt=\"${user.name ?? \"User\"}'s avatar\"></pop-comment-avatar>`\n : `<pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\" data-color-key=\"${userColorKey}\">${getInitials(user?.name)}</pop-comment-avatar>`;\n\n barUser.innerHTML = userAvatarHtml;\n }\n });\n }\n\n private async handleSend(): Promise<void> {\n const input = this.getElement<PopCommentInput>(\"pop-comment-input\");\n if (!input) return;\n\n const body = input.getValue().trim();\n if (!body) return;\n\n const editingId = this.gridStore.editingCommentId.value;\n if (editingId) {\n input.clear();\n this.gridStore.editingCommentId.value = null;\n await this.gridStore.editComment(editingId, body);\n } else {\n input.clear();\n const comment = await this.gridStore.postComment(\n body,\n this.gridStore.replyingTo.value ?? undefined,\n );\n this.gridStore.replyingTo.value = null;\n\n if (comment) {\n this.gridStore.scrollingCommentId.value = comment.id;\n }\n }\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"logo-watermark\">${LOGO_WATERMARK_SVG}</div>\n <div class=\"bar\">\n <div class=\"bar__user\">\n <pop-comment-avatar size=\"xs\" class=\"bar__avatar bar__avatar--user\">?</pop-comment-avatar>\n </div>\n <div class=\"bar__input-wrap\">\n <pop-comment-input></pop-comment-input>\n </div>\n <pop-comment-icon\n class=\"bar__send\"\n theme=\"neutral\"\n variant=\"send\"\n aria-label=\"Send comment\"\n ></pop-comment-icon>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-bar\")) {\n customElements.define(\"pop-comment-bar\", PopCommentBar);\n}\n","import { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n /* Mode-level theme colors (defaults for light mode) */\n --pop-comment-color-black: #000000;\n --pop-comment-color-white: #ffffff;\n --pop-comment-color-default: #000000;\n --pop-comment-color-reversed: #ffffff;\n --pop-comment-bg-singular-resting: #121926;\n --pop-comment-bg-singular-hover: rgba(0, 0, 32, 0.08);\n --pop-comment-bg-reversed: #121926;\n --pop-comment-bg-blank-resting: #ffffff;\n\n display: flex;\n\n --pop-comment-icon-scale: 1;\n --pop-comment-icon-scale-hover: 1.1875;\n --pop-comment-icon-scale-active: 0.9375;\n --pop-comment-icon-size: 32px;\n --pop-comment-icon-color: var(--pop-foreground, #000000);\n --pop-comment-icon-color-hover: var(--pop-foreground, #000000);\n --pop-comment-icon-color-active: var(--pop-foreground, #000000);\n --pop-comment-icon-color-focused: var(--pop-foreground, #000000);\n --pop-comment-icon-background: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-hover: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-active: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n --pop-comment-icon-background-focused: var(\n --color-surface-buttons-singular-bg-launch-icon-hover,\n rgba(0, 0, 32, 0.08)\n );\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n /* Overrides for dark mode */\n --pop-comment-color-black: #ffffff;\n --pop-comment-color-white: #000000;\n --pop-comment-color-default: #ffffff;\n --pop-comment-color-reversed: #000000;\n --pop-comment-bg-singular-resting: #ffffff;\n --pop-comment-bg-singular-hover: rgba(255, 255, 255, 0.15);\n --pop-comment-bg-reversed: #ffffff;\n --pop-comment-bg-blank-resting: #121926;\n }\n }\n\n :host(.dark) {\n /* Overrides for dark mode (.dark class on host) */\n --pop-comment-color-black: #ffffff;\n --pop-comment-color-white: #000000;\n --pop-comment-color-default: #ffffff;\n --pop-comment-color-reversed: #000000;\n --pop-comment-bg-singular-resting: #ffffff;\n --pop-comment-bg-singular-hover: rgba(255, 255, 255, 0.15);\n --pop-comment-bg-reversed: #ffffff;\n --pop-comment-bg-blank-resting: #121926;\n }\n\n .comment-icon {\n align-items: center;\n background: transparent;\n border: none;\n display: inline-flex;\n height: var(--pop-comment-icon-size);\n justify-content: center;\n padding: 0;\n position: relative;\n transform-origin: center;\n width: var(--pop-comment-icon-size);\n }\n\n .comment-icon--size-sm {\n --pop-comment-icon-size: 24px;\n }\n\n .comment-icon:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .comment-icon__focus-indicator {\n background-color: var(--pop-ring);\n display: none;\n position: absolute;\n inset: -3px;\n pointer-events: none;\n transform-origin: center;\n transform: scale(var(--pop-comment-icon-scale));\n transition: all 200ms ease-out;\n width: calc(100% + 6px);\n }\n\n .comment-icon:focus-visible .comment-icon__focus-indicator {\n display: flex;\n }\n\n .comment-icon:focus-visible {\n outline: none;\n }\n\n .comment-icon__inner {\n align-items: center;\n background: var(--pop-comment-icon-background);\n color: var(--pop-comment-icon-color);\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n height: var(--pop-comment-icon-size);\n justify-content: center;\n position: absolute;\n transform-origin: center;\n transition: all 200ms ease-out;\n transform: scale(var(--pop-comment-icon-scale));\n width: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon-container {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n transition: transform ease-out 150ms;\n width: 100%;\n }\n\n .comment-icon__icon-container svg {\n width: calc(var(--pop-comment-icon-size) * 0.6875);\n height: calc(var(--pop-comment-icon-size) * 0.6875);\n }\n\n .comment-icon--variant-close.comment-icon--theme-neutral .comment-icon__icon-container svg {\n width: var(--pop-comment-icon-size);\n height: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon-image {\n display: flex;\n width: var(--pop-comment-icon-size);\n height: var(--pop-comment-icon-size);\n }\n\n .comment-icon__icon {\n display: flex;\n }\n\n .comment-icon__icon-image + .comment-icon__icon {\n display: none;\n }\n\n .comment-icon .comment-icon__inner {\n transition: transform var(--pop-ease-pop-hover) var(--pop-duration-pop-hover);\n }\n\n @media (hover: hover) and (pointer: fine) {\n .comment-icon:hover .comment-icon__inner {\n background: var(--pop-comment-icon-background-hover);\n color: var(--pop-comment-icon-color-hover);\n transform: scale(var(--pop-comment-icon-scale-hover));\n }\n\n .comment-icon:hover .comment-icon__icon-image {\n display: none;\n }\n\n .comment-icon:hover .comment-icon__icon-image + .comment-icon__icon {\n display: flex;\n }\n }\n\n .comment-icon:active .comment-icon__inner {\n background: var(--pop-comment-icon-background-active);\n color: var(--pop-comment-icon-color-active);\n transform: scale(var(--pop-comment-icon-scale-active));\n transition-duration: 200ms;\n }\n\n .comment-icon:is(:focus-visible) .comment-icon__inner {\n background: var(--pop-comment-icon-background-focused);\n color: var(--pop-comment-icon-color-focused);\n }\n\n /* Brand / Add */\n .comment-icon--theme-brand.comment-icon--variant-add {\n --pop-comment-icon-color: var(--pop-comment-color-black);\n --pop-comment-icon-color-hover: var(--pop-comment-color-black);\n --pop-comment-icon-color-active: var(--pop-comment-color-black);\n --pop-comment-icon-color-focused: var(--pop-comment-color-black);\n --pop-comment-icon-background: transparent;\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-hover);\n --pop-comment-icon-background-focused: transparent;\n }\n\n /* Brand / Close */\n .comment-icon--theme-brand.comment-icon--variant-close {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-white);\n --pop-comment-icon-color-active: var(--pop-comment-color-white);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Add */\n .comment-icon--theme-neutral.comment-icon--variant-add {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-white);\n --pop-comment-icon-color-active: var(--pop-comment-color-white);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Close */\n .comment-icon--theme-neutral.comment-icon--variant-close {\n --pop-comment-icon-color: var(--pop-comment-color-white);\n --pop-comment-icon-color-hover: var(--pop-comment-color-white);\n --pop-comment-icon-color-active: var(--pop-comment-color-white);\n --pop-comment-icon-color-focused: var(--pop-comment-color-white);\n --pop-comment-icon-background: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-singular-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-singular-resting);\n }\n\n /* Neutral / Send */\n .comment-icon--theme-neutral.comment-icon--variant-send {\n --pop-comment-icon-color: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-hover: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-active: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-focused: var(--pop-comment-color-reversed);\n --pop-comment-icon-background: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-active: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-reversed);\n }\n\n /* Neutral / More */\n .comment-icon--theme-neutral.comment-icon--variant-more {\n --pop-comment-icon-color: var(--pop-comment-color-default);\n --pop-comment-icon-color-hover: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-active: var(--pop-comment-color-default);\n --pop-comment-icon-color-focused: var(--pop-comment-color-default);\n --pop-comment-icon-background: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-active: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-blank-resting);\n }\n\n /* Neutral / Cancel */\n .comment-icon--theme-neutral.comment-icon--variant-cancel {\n --pop-comment-icon-color: var(--pop-comment-color-default);\n --pop-comment-icon-color-hover: var(--pop-comment-color-default);\n --pop-comment-icon-color-active: var(--pop-comment-color-reversed);\n --pop-comment-icon-color-focused: var(--pop-comment-color-default);\n --pop-comment-icon-background: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-hover: var(--pop-comment-bg-blank-resting);\n --pop-comment-icon-background-active: var(--pop-comment-bg-reversed);\n --pop-comment-icon-background-focused: var(--pop-comment-bg-blank-resting);\n }\n`);\n\nexport class PopCommentIcon extends BaseElement {\n protected get styleSheets() {\n return [localSheet];\n }\n\n static get observedAttributes() {\n return [\"counter\", \"icon-url\", \"size\", \"theme\", \"variant\", \"type\", \"disabled\", \"aria-label\"];\n }\n\n onAriaLabelChanged() {\n this.render();\n }\n\n onCounterChanged() {\n this.render();\n }\n\n onIconUrlChanged() {\n this.render();\n }\n\n onSizeChanged() {\n this.render();\n }\n\n onThemeChanged() {\n this.render();\n }\n\n onVariantChanged() {\n this.render();\n }\n\n onTypeChanged() {\n this.render();\n }\n\n onDisabledChanged() {\n this.render();\n }\n\n get counter(): number {\n return Number(this.getAttribute(\"counter\") || \"0\");\n }\n\n set counter(value: number) {\n this.setAttribute(\"counter\", String(value));\n }\n\n get iconUrl(): string | undefined {\n return this.getAttribute(\"icon-url\") || undefined;\n }\n\n set iconUrl(value: string | undefined) {\n if (value === undefined) {\n this.removeAttribute(\"icon-url\");\n } else {\n this.setAttribute(\"icon-url\", value);\n }\n }\n\n get size(): string {\n return this.getAttribute(\"size\") || \"md\";\n }\n\n set size(value: string) {\n this.setAttribute(\"size\", value);\n }\n\n get theme(): \"brand\" | \"neutral\" {\n return (this.getAttribute(\"theme\") as \"brand\" | \"neutral\") || \"brand\";\n }\n\n set theme(value: \"brand\" | \"neutral\") {\n this.setAttribute(\"theme\", value);\n }\n\n get variant(): \"add\" | \"close\" | \"filter\" | \"more\" | \"send\" | \"cancel\" {\n return (this.getAttribute(\"variant\") as any) || \"add\";\n }\n\n set variant(value: \"add\" | \"close\" | \"filter\" | \"more\" | \"send\" | \"cancel\") {\n this.setAttribute(\"variant\", value);\n }\n\n get type(): \"button\" | \"submit\" | \"reset\" | \"menu\" {\n return (this.getAttribute(\"type\") as any) || \"button\";\n }\n\n set type(value: \"button\" | \"submit\" | \"reset\" | \"menu\") {\n this.setAttribute(\"type\", value);\n }\n\n get disabled(): boolean {\n return this.hasAttribute(\"disabled\");\n }\n\n set disabled(value: boolean) {\n if (value) {\n this.setAttribute(\"disabled\", \"\");\n } else {\n this.removeAttribute(\"disabled\");\n }\n }\n\n get ariaLabel(): string | null {\n return this.getAttribute(\"aria-label\");\n }\n\n set ariaLabel(value: string | null) {\n if (value === null) {\n this.removeAttribute(\"aria-label\");\n } else {\n this.setAttribute(\"aria-label\", value);\n }\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: Event) {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n this.emit(\"pop-click\");\n }\n\n get icon(): string {\n let icon = \"\";\n\n if (this.theme === \"brand\") {\n if (this.variant === \"add\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11 4.58331V17.4166M4.58333 11H17.4167\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"close\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M16.5 5.5L5.5 16.5M5.5 5.5L16.5 16.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n } else if (this.theme === \"neutral\") {\n if (this.variant === \"add\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.0002 4.58301V17.4163M4.5835 10.9997H17.4168\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"close\") {\n icon = `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.4628 11.4627L20.5373 20.5373M11.4628 20.5373L20.5373 11.4627\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"more\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12.8335 16.5L7.3335 11L12.8335 5.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n } else if (this.variant === \"send\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M18.0394 3.68048C18.2139 3.61601 18.3837 3.78583 18.3193 3.96036L12.3858 20.0241C12.314 20.2185 12.0369 20.2123 11.9739 20.0149L9.89172 13.4908C9.86908 13.4199 9.88424 13.3423 9.93191 13.2851L14.4838 7.82287C14.6536 7.61906 14.3807 7.34616 14.1769 7.516L8.71467 12.0678C8.65746 12.1155 8.57987 12.1307 8.50893 12.108L1.98489 10.0259C1.78743 9.96287 1.78121 9.68575 1.97565 9.61393L18.0394 3.68048Z\"\n fill=\"currentColor\"\n />\n </svg>\n `;\n } else if (this.variant === \"cancel\") {\n icon = `\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M16.5 5.5L5.5 16.5M5.5 5.5L16.5 16.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n }\n return icon;\n }\n\n protected getTemplate(): string {\n const disabledAttr = this.disabled ? \"disabled\" : \"\";\n const classes = [\n \"comment-icon\",\n this.size ? `comment-icon--size-${this.size}` : \"\",\n this.theme ? `comment-icon--theme-${this.theme}` : \"\",\n this.variant ? `comment-icon--variant-${this.variant}` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n const iconHtml = this.iconUrl\n ? `<img src=\"${this.iconUrl}\" alt=\"\" class=\"comment-icon__icon-image\" />\n <slot class=\"comment-icon__icon\" name=\"icon\">${this.icon}</slot>`\n : `<slot class=\"comment-icon__icon\" name=\"icon\">${this.icon}</slot>`;\n\n const ariaLabelAttr = this.ariaLabel ? `aria-label=\"${this.ariaLabel}\"` : \"\";\n\n return /* html */ `\n <button\n class=\"${classes}\"\n part=\"base\"\n type=\"${this.type}\"\n ${disabledAttr}\n ${ariaLabelAttr}\n >\n <pop-focus-indicator\n class=\"comment-icon__focus-indicator mask mask-squircle\"\n ></pop-focus-indicator>\n <div class=\"comment-icon__inner mask mask-squircle\">\n <div class=\"comment-icon__icon-container\" part=\"icon\">${iconHtml}</div>\n </div>\n </button>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-icon\")) {\n customElements.define(\"pop-comment-icon\", PopCommentIcon);\n}\n","import { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: flex;\n flex: 1;\n min-width: 0;\n align-items: flex-end;\n }\n\n textarea {\n flex: 1;\n min-width: 0;\n background: none;\n border: none;\n outline: none;\n resize: none;\n font-family: Inter, sans-serif;\n font-size: 13px;\n color: black;\n line-height: 18px;\n padding: 5px 0;\n max-height: 200px;\n overflow-y: auto;\n width: 100%;\n letter-spacing: -0.08px;\n }\n\n textarea::placeholder {\n color: #697586;\n }\n`);\n\nexport class PopCommentInput extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n input: \"onInput\",\n keydown: \"onKeyDown\",\n };\n\n protected onInput(event: Event) {\n const textarea = event.target as HTMLTextAreaElement;\n textarea.style.height = \"auto\";\n textarea.style.height = `${textarea.scrollHeight}px`;\n }\n\n protected onKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n if (this.gridStore.editingCommentId.value || this.gridStore.replyingTo.value) {\n event.stopPropagation();\n this.gridStore.editingCommentId.value = null;\n this.gridStore.replyingTo.value = null;\n }\n }\n }\n\n getValue(): string {\n return this.getElement<HTMLTextAreaElement>(\"textarea\")?.value ?? \"\";\n }\n\n setValue(val: string): void {\n const textarea = this.getElement<HTMLTextAreaElement>(\"textarea\");\n if (!textarea) return;\n\n textarea.value = val;\n textarea.style.height = \"auto\";\n textarea.style.height = `${textarea.scrollHeight}px`;\n }\n\n clear(): void {\n const textarea = this.getElement<HTMLTextAreaElement>(\"textarea\");\n if (!textarea) return;\n\n textarea.value = \"\";\n textarea.style.height = \"auto\";\n }\n\n focus(): void {\n this.getElement<HTMLTextAreaElement>(\"textarea\")?.focus();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const parent = this.gridStore.replyingToComment.value;\n const editing = this.gridStore.editingComment.value;\n\n let placeholder = \"Comment\";\n if (editing) {\n placeholder = \"Edit comment...\";\n } else if (parent?.author?.name) {\n placeholder = `Reply to ${parent.author.name}`;\n }\n\n this.setAttr(\"textarea\", \"placeholder\", placeholder);\n });\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <textarea rows=\"1\" placeholder=\"Comment\"></textarea>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-input\")) {\n customElements.define(\"pop-comment-input\", PopCommentInput);\n}\n","import { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n\n --pop-thread-link: rgba(0, 0, 32, 0.5);\n --pop-thread-link-hover: rgba(0, 0, 32, 0.8);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-thread-link: rgba(255, 255, 255, 0.5);\n --pop-thread-link-hover: rgba(255, 255, 255, 0.8);\n }\n }\n\n :host(.dark) {\n --pop-thread-link: rgba(255, 255, 255, 0.5);\n --pop-thread-link-hover: rgba(255, 255, 255, 0.8);\n }\n\n .thread {\n align-items: stretch;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .thread__replies {\n align-items: center;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-left: 24px;\n }\n\n .thread__more {\n display: flex;\n align-items: center;\n font-size: 13px;\n gap: 6px;\n padding-left: 30px;\n transition: opacity 0.15s ease;\n width: 100%;\n }\n\n .thread__more:hover {\n opacity: 1;\n }\n\n .thread__more-dot {\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: var(--pop-muted-foreground);\n flex-shrink: 0;\n opacity: 0.1;\n }\n`);\n\nconst COLLAPSED_REPLY_LIMIT = 2;\n\nexport class PopCommentThread extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n private _showAll = false;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest(\".thread__more-btn\")) return;\n this._showAll = true;\n this.render();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const commentId = this.getAttribute(\"comment-id\");\n const targetId = this.gridStore.scrollingCommentId.value;\n if (commentId && targetId) {\n const replies = this.gridStore.repliesFor(commentId);\n if (replies.some((r) => r.id === targetId)) {\n this._showAll = true;\n }\n }\n\n this.gridStore.comments.value;\n this.render();\n });\n }\n\n protected getTemplate(): string {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return \"\";\n\n const replies = this.gridStore.repliesFor(commentId);\n const visibleReplies =\n this._showAll || replies.length <= COLLAPSED_REPLY_LIMIT\n ? replies\n : replies.slice(0, COLLAPSED_REPLY_LIMIT);\n const hiddenCount = replies.length - visibleReplies.length;\n\n const moreHtml =\n hiddenCount > 0\n ? `<div class=\"thread__more\">\n <div class=\"thread__more-dot\"></div>\n <button class=\"thread__more-btn btn-link btn-link--size-sm btn-link--theme-default\" type=\"button\">\n Show ${hiddenCount} more ${hiddenCount === 1 ? \"reply\" : \"replies\"}\n </button>\n </div>`\n : \"\";\n\n const repliesHtml =\n replies.length > 0\n ? `<div class=\"thread__replies\">\n ${visibleReplies\n .map((reply) => `<pop-comment comment-id=\"${reply.id}\"></pop-comment>`)\n .join(\"\")}\n ${moreHtml}\n </div>`\n : \"\";\n\n return /* html */ `\n <div class=\"thread\">\n <pop-comment comment-id=\"${commentId}\"></pop-comment>\n ${repliesHtml}\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment-thread\")) {\n customElements.define(\"pop-comment-thread\", PopCommentThread);\n}\n","export function timeAgo(date: Date | string | number): string {\n const d = date instanceof Date ? date : new Date(date);\n const seconds = (Date.now() - d.getTime()) / 1000;\n\n if (seconds < 1) return \"now\";\n if (seconds < 60) return `${Math.floor(seconds)}s`;\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;\n if (seconds < 604800) return `${Math.floor(seconds / 86400)}d`;\n return `${Math.floor(seconds / 604800)}w`;\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { timeAgo } from \"../helpers/time.js\";\nimport { currentUser } from \"../store/auth-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\nimport { computePosition, autoUpdate, flip, offset, shift } from \"@floating-ui/dom\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n width: 100%;\n --pop-comment-hover: rgba(0, 0, 32, 0.04);\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --pop-comment-hover: rgba(255, 255, 255, 0.04);\n }\n }\n\n .comment {\n display: flex;\n width: 100%;\n gap: 8px;\n align-items: center;\n background-color: transparent;\n border: none;\n padding: 0;\n border-radius: var(--pop-radius-md);\n outline: 6px solid transparent;\n text-align: left;\n transition:\n background-color 150ms ease,\n outline-color 150ms ease;\n }\n\n :host([data-size=\"sm\"]) .comment,\n :host:not([data-size]) .comment {\n --avatar-size: 32px;\n --width: 32px;\n gap: 8px;\n }\n\n :host([data-size=\"lg\"]) .comment {\n --avatar-size: 56px;\n --width: 56px;\n gap: 12px;\n }\n\n .comment--is-selected {\n background-color: var(--pop-muted);\n outline-color: var(--pop-muted);\n }\n\n :host(.is-signed-in) .comment {\n cursor: pointer;\n }\n\n @media (hover: hover) and (pointer: fine) {\n .comment:hover .comment__avatar {\n --avatar-translate-x: 2px;\n }\n\n .comment__avatar:hover {\n /* --avatar-scale: 1.06; */\n }\n\n .comment .comment__menu {\n display: none;\n }\n\n .comment:hover .comment__menu {\n display: flex;\n }\n }\n\n .comment--is-selected .comment__avatar {\n --avatar-translate-x: 2px;\n }\n\n .comment__avatar {\n --comment-avatar-border-size: 0;\n --avatar-translate-x: 0px;\n --avatar-scale: 1;\n width: var(--avatar-size);\n height: var(--avatar-size);\n transform: translateX(var(--avatar-translate-x)) scale(var(--avatar-scale));\n transition: transform var(--pop-duration-quick) var(--pop-ease-quick);\n }\n\n .comment__user {\n display: flex;\n width: var(--width);\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n align-self: stretch;\n }\n\n .comment__content {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 0 0;\n align-self: stretch;\n }\n\n .comment__info {\n display: flex;\n align-items: flex-start;\n align-self: stretch;\n }\n\n .comment__menu {\n display: flex;\n justify-self: flex-end;\n }\n\n .comment__menu-trigger {\n background: none;\n border: none;\n cursor: pointer;\n border-radius: 9999px;\n aspect-ratio: 1;\n position: relative;\n }\n\n .comment__menu-trigger:before {\n content: \"\";\n height: 40px;\n left: 50%;\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n }\n\n .comment__user-meta {\n display: flex;\n align-items: flex-start;\n gap: 4px;\n flex-shrink: 0;\n align-self: stretch;\n flex-grow: 1;\n }\n\n .comment__user-name {\n color: var(--pop-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: var(--text-widget-base, 13px);\n font-style: normal;\n font-weight: 500;\n line-height: var(--text-widget-base--line-height, 18px);\n letter-spacing: -0.08px;\n }\n\n .comment__timestamp {\n color: var(--pop-muted-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: var(--text-widget-base, 13px);\n font-style: normal;\n font-weight: 400;\n line-height: var(--text-widget-base--line-height, 18px);\n letter-spacing: -0.08px;\n opacity: 0.5;\n }\n\n .comment__text {\n align-self: stretch;\n color: var(--pop-foreground);\n font-feature-settings:\n \"liga\" off,\n \"clig\" off;\n font-family: Inter, sans-serif;\n font-size: 13px;\n font-style: normal;\n font-weight: 400;\n line-height: 18px;\n letter-spacing: -0.08px;\n text-align: left;\n\n /* Clamping when not expanded */\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .comment__text.expanded,\n .comment--is-selected .comment__text {\n -webkit-line-clamp: initial;\n display: block;\n }\n\n .comment__mention {\n color: #155eef;\n font-weight: 500;\n }\n\n .comment__menu {\n position: relative;\n }\n\n .comment__dropdown {\n background-color: var(--pop-background);\n border-radius: 6px;\n box-shadow: var(--pop-shadow-xl);\n display: none;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n pointer-events: auto;\n position: fixed;\n width: 120px;\n z-index: 1000;\n }\n\n .comment__dropdown.is-open {\n display: flex;\n }\n\n .comment__dropdown-item {\n align-items: center;\n background: none;\n border-radius: 4px;\n border: none;\n color: var(--pop-foreground);\n cursor: pointer;\n display: flex;\n flex: 1 0 0;\n font-family: Inter, sans-serif;\n font-size: 14px;\n font-weight: 500;\n justify-content: center;\n min-height: 40px;\n padding: 0 12px;\n text-align: left;\n transition: background-color 100ms ease;\n width: 100%;\n }\n\n .comment__dropdown-item:hover {\n background-color: var(--pop-comment-hover, rgba(0, 0, 0, 0.04));\n }\n\n .comment__dropdown-item--danger {\n color: #ef4444;\n }\n\n .comment__edit-form {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: 8px;\n margin-top: 4px;\n }\n\n .comment__edit-input {\n width: 100%;\n background: var(--pop-background, #ffffff);\n color: var(--pop-foreground, #000000);\n border: 1px solid var(--pop-border, #e4e4e7);\n border-radius: var(--pop-radius-sm, 4px);\n padding: 6px 8px;\n font-family: Inter, sans-serif;\n font-size: 13px;\n line-height: 18px;\n resize: vertical;\n outline: none;\n }\n\n .comment__edit-input:focus {\n border-color: var(--pop-ring, #000020);\n }\n\n .comment__edit-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .comment__edit-save,\n .comment__edit-cancel {\n font-size: 12px;\n padding: 4px 8px;\n cursor: pointer;\n }\n\n .comment--deleted .comment__text {\n color: var(--pop-muted-foreground, #697586);\n font-style: italic;\n opacity: 0.8;\n }\n`);\n\nexport class PopComment extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n static get observedAttributes() {\n return [\"data-size\", \"comment-id\"];\n }\n\n onDataSizeChanged() {\n this.render();\n }\n\n onCommentIdChanged() {\n this.render();\n }\n\n get size(): \"sm\" | \"lg\" {\n return (this.getAttribute(\"data-size\") as \"sm\" | \"lg\") || \"sm\";\n }\n\n get commentAvatarSize(): \"xs\" | \"sm\" {\n return this.size === \"sm\" ? \"xs\" : \"sm\";\n }\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n private _expanded = false;\n private _dropdownOpen = false;\n private _floatingCleanup?: () => void;\n\n private _onOutsideClick = (event: MouseEvent) => {\n const path = event.composedPath();\n const dropdown = this.getElement(\".comment__dropdown\");\n const trigger = this.getElement(\".comment__menu-trigger\");\n\n if (dropdown && trigger && !path.includes(dropdown) && !path.includes(trigger)) {\n this.closeDropdown();\n }\n };\n\n private toggleDropdown() {\n if (this._dropdownOpen) {\n this.closeDropdown();\n } else {\n this.openDropdown();\n }\n }\n\n private openDropdown() {\n this._dropdownOpen = true;\n const dropdown = this.getElement<HTMLElement>(\".comment__dropdown\");\n const trigger = this.getElement<HTMLElement>(\".comment__menu-trigger\");\n\n if (dropdown && trigger) {\n dropdown.classList.add(\"is-open\");\n\n const update = () => {\n computePosition(trigger, dropdown, {\n placement: \"bottom-end\",\n middleware: [offset(4), flip(), shift({ padding: 8 })],\n strategy: \"fixed\",\n }).then(({ x, y }) => {\n Object.assign(dropdown.style, {\n left: `${x}px`,\n top: `${y}px`,\n position: \"fixed\",\n });\n });\n };\n\n this._floatingCleanup = autoUpdate(trigger, dropdown, update);\n document.addEventListener(\"mousedown\", this._onOutsideClick);\n }\n }\n\n private closeDropdown() {\n this._dropdownOpen = false;\n const dropdown = this.getElement(\".comment__dropdown\");\n if (dropdown) {\n dropdown.classList.remove(\"is-open\");\n }\n if (this._floatingCleanup) {\n this._floatingCleanup();\n this._floatingCleanup = undefined;\n }\n document.removeEventListener(\"mousedown\", this._onOutsideClick);\n }\n\n private async deleteComment() {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n if (confirm(\"Are you sure you want to delete this comment?\")) {\n await this.gridStore.deleteComment(commentId);\n }\n }\n\n private async flagComment() {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const success = await this.gridStore.flagComment(commentId);\n if (success) {\n alert(\"Comment flagged successfully.\");\n } else {\n alert(\"Failed to flag comment.\");\n }\n }\n\n protected onClick(event: Event) {\n const target = event.target as HTMLElement;\n\n // Handle menu trigger click\n if (target.closest(\".comment__menu-trigger\")) {\n event.stopPropagation();\n this.toggleDropdown();\n return;\n }\n\n // Handle dropdown item click\n const dropdownItem = target.closest(\".comment__dropdown-item\") as HTMLElement;\n if (dropdownItem) {\n event.stopPropagation();\n const action = dropdownItem.getAttribute(\"data-action\");\n const commentId = this.getAttribute(\"comment-id\");\n if (action === \"edit\" && commentId) {\n this.gridStore.replyingTo.value = null;\n this.gridStore.editingCommentId.value = commentId;\n } else if (action === \"delete\") {\n this.deleteComment();\n } else if (action === \"flag\") {\n this.flagComment();\n }\n this.closeDropdown();\n return;\n }\n\n // Don't trigger reply if clicking inside the dropdown\n if (target.closest(\".comment__dropdown\")) {\n event.stopPropagation();\n return;\n }\n\n // Default reply action\n if (!currentUser.value) return;\n\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (comment?.status === \"deleted\") return;\n\n if (this.gridStore.replyingTo.value === commentId) {\n this.gridStore.replyingTo.value = null;\n } else {\n this.gridStore.replyingTo.value = commentId;\n }\n\n this.expandText();\n }\n\n private expandText() {\n const textEl = this.getElement<HTMLElement>(\".comment__text\");\n if (!this._expanded && textEl) {\n const startHeight = textEl.offsetHeight;\n this._expanded = true;\n this.render();\n\n const newTextEl = this.getElement<HTMLElement>(\".comment__text\");\n if (newTextEl) {\n const endHeight = newTextEl.scrollHeight;\n\n newTextEl.style.height = `${startHeight}px`;\n newTextEl.style.overflow = \"hidden\";\n\n // Force a reflow\n void newTextEl.offsetHeight;\n\n newTextEl.style.transition = \"height var(--pop-duration-quick) var(--pop-ease-quick)\";\n newTextEl.style.height = `${endHeight}px`;\n\n setTimeout(() => {\n newTextEl.style.height = \"\";\n newTextEl.style.overflow = \"\";\n }, 300);\n }\n }\n }\n\n private _timeUpdateTimer: ReturnType<typeof setTimeout> | null = null;\n\n disconnectedCallback() {\n this.closeDropdown();\n this.stopTimeUpdates();\n super.disconnectedCallback();\n }\n\n private startTimeUpdates() {\n this.stopTimeUpdates();\n\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return;\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (!comment) return;\n\n const update = () => {\n const timeSpan = this.getElement<HTMLSpanElement>(\".comment__timestamp\");\n if (timeSpan) {\n timeSpan.textContent = timeAgo(comment.createdAt);\n }\n\n const ageMs =\n Date.now() -\n (typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt)));\n let delay = 60000;\n\n if (ageMs < 60000) {\n delay = 5000;\n } else if (ageMs < 3600000) {\n delay = 60000;\n } else {\n delay = 1800000;\n }\n\n this._timeUpdateTimer = setTimeout(update, delay);\n };\n\n const ageMs =\n Date.now() -\n (typeof comment.createdAt === \"number\"\n ? comment.createdAt\n : Date.parse(String(comment.createdAt)));\n const initialDelay = ageMs < 60000 ? 5000 : 60000;\n this._timeUpdateTimer = setTimeout(update, initialDelay);\n }\n\n private stopTimeUpdates() {\n if (this._timeUpdateTimer) {\n clearTimeout(this._timeUpdateTimer);\n this._timeUpdateTimer = null;\n }\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const commentId = this.getAttribute(\"comment-id\");\n const user = currentUser.value;\n const replyingToId = this.gridStore.replyingTo.value;\n const editingId = this.gridStore.editingCommentId.value;\n const targetId = this.gridStore.scrollingCommentId.value;\n\n this.classList.toggle(\"is-signed-in\", user !== null);\n this.classList.toggle(\"is-replying\", commentId !== null && replyingToId === commentId);\n this.classList.toggle(\"is-editing\", commentId !== null && editingId === commentId);\n\n this.gridStore.comments.value;\n this.render();\n this.startTimeUpdates();\n\n if (commentId && targetId === commentId) {\n setTimeout(() => {\n const innerComment = this.shadowRoot?.querySelector(`#comment-${commentId}`);\n if (innerComment) {\n innerComment.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n } else {\n this.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n }\n this.gridStore.scrollingCommentId.value = null;\n }, 50);\n }\n });\n }\n\n protected getTemplate(): string {\n const commentId = this.getAttribute(\"comment-id\");\n if (!commentId) return \"\";\n\n const comment = this.gridStore.comments.value.find((c) => c.id === commentId);\n if (!comment) return \"\";\n\n const isDeleted = comment.status === \"deleted\";\n const isAuthorDeleted = comment.authorDeleted === true;\n const showDeletedAvatar = isDeleted || isAuthorDeleted;\n\n const avatarContent = showDeletedAvatar\n ? \"\"\n : comment.author?.image\n ? `<img src=\"${comment.author.image}\" alt=\"${comment.author.name ?? \"User avatar\"}\" />`\n : getInitials(comment.author?.name);\n\n const replyingToId = this.gridStore.replyingTo.value;\n const isReplying = commentId !== null && replyingToId === commentId;\n const size = this.size;\n\n // Determine if signed-in user is the author\n const isAuthor =\n currentUser.value && comment.author && currentUser.value.id === comment.author.id;\n\n // Dropdown HTML (only if signed in and comment is not deleted)\n const menuHtml =\n currentUser.value && !isDeleted\n ? `<div class=\"comment__menu\">\n <button class=\"comment__menu-trigger\" type=\"button\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 9.5C9.27614 9.5 9.5 9.27614 9.5 9C9.5 8.72386 9.27614 8.5 9 8.5C8.72386 8.5 8.5 8.72386 8.5 9C8.5 9.27614 8.72386 9.5 9 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M12.5 9.5C12.7761 9.5 13 9.27614 13 9C13 8.72386 12.7761 8.5 12.5 8.5C12.2239 8.5 12 8.72386 12 9C12 9.27614 12.2239 9.5 12.5 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M5.5 9.5C5.77614 9.5 6 9.27614 6 9C6 8.72386 5.77614 8.5 5.5 8.5C5.22386 8.5 5 8.72386 5 9C5 9.27614 5.22386 9.5 5.5 9.5Z\"\n fill=\"white\"\n />\n <path\n d=\"M9 9.5C9.27614 9.5 9.5 9.27614 9.5 9C9.5 8.72386 9.27614 8.5 9 8.5C8.72386 8.5 8.5 8.72386 8.5 9C8.5 9.27614 8.72386 9.5 9 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M12.5 9.5C12.7761 9.5 13 9.27614 13 9C13 8.72386 12.7761 8.5 12.5 8.5C12.2239 8.5 12 8.72386 12 9C12 9.27614 12.2239 9.5 12.5 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M5.5 9.5C5.77614 9.5 6 9.27614 6 9C6 8.72386 5.77614 8.5 5.5 8.5C5.22386 8.5 5 8.72386 5 9C5 9.27614 5.22386 9.5 5.5 9.5Z\"\n stroke=\"#000020\"\n stroke-opacity=\"0.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n <div class=\"comment__dropdown\">\n ${\n isAuthor\n ? `<button class=\"comment__dropdown-item\" type=\"button\" data-action=\"edit\">Edit</button>\n <button class=\"comment__dropdown-item comment__dropdown-item--danger\" type=\"button\" data-action=\"delete\">Delete</button>`\n : \"\"\n }\n <button class=\"comment__dropdown-item\" type=\"button\" data-action=\"flag\">Flag</button>\n </div>\n </div>`\n : \"\";\n\n return /* html */ `\n <div\n class=\"comment comment--size-${size}${isReplying ? \" comment--is-selected\" : \"\"}${isDeleted\n ? \" comment--deleted\"\n : \"\"}\"\n id=\"comment-${commentId}\"\n >\n <div class=\"comment__user\">\n <pop-comment-avatar\n class=\"comment__avatar\"\n size=\"${this.commentAvatarSize}\"\n data-color-key=\"${comment.author?.id ?? comment.author?.name ?? \"\"}\"\n ${showDeletedAvatar ? \"deleted\" : \"\"}\n >\n ${avatarContent}\n </pop-comment-avatar>\n </div>\n <div class=\"comment__content\">\n <div class=\"comment__info\">\n <div class=\"comment__user-meta\">\n <div class=\"comment__user-name\">\n ${isDeleted ? \"[Deleted]\" : isAuthorDeleted ? \"[Deleted user]\" : (comment.author?.name ?? \"\")}\n </div>\n <div class=\"comment__timestamp\">${timeAgo(comment.createdAt)}</div>\n </div>\n ${menuHtml}\n </div>\n <div class=\"comment__text${this._expanded ? \" expanded\" : \"\"}\">${comment.body}</div>\n </div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-comment\")) {\n customElements.define(\"pop-comment\", PopComment);\n}\n","import { checkSession, currentUser } from \"../store/auth-store.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: flex;\n background: var(--pop-background);\n border-radius: var(--pop-radius-2xl);\n border: 1px solid var(--pop-background);\n box-shadow: var(--pop-shadow-3xl);\n display: block;\n left: 0;\n max-height: 400px;\n max-width: 400px;\n min-width: 343px;\n opacity: 0;\n overflow: hidden;\n padding: 0 4px 0 0;\n pointer-events: none;\n position: fixed;\n top: 0;\n width: 100%;\n z-index: 9999;\n transform: scale(0.94);\n transition:\n opacity var(--pop-duration-quick) var(--pop-ease-quick),\n transform var(--pop-duration-quick) var(--pop-ease-quick),\n display var(--pop-duration-quick) allow-discrete;\n }\n\n :host([data-current-placement=\"top-start\"]) {\n transform-origin: left bottom;\n }\n\n :host([data-current-placement=\"bottom-start\"]) {\n transform-origin: left top;\n }\n\n :host([data-current-placement=\"top-end\"]) {\n transform-origin: right bottom;\n }\n\n :host([data-current-placement=\"bottom-end\"]) {\n transform-origin: right top;\n }\n\n :host([data-current-placement=\"top\"]) {\n transform-origin: bottom;\n }\n\n :host([data-current-placement=\"bottom\"]) {\n transform-origin: top;\n }\n\n :host([open]) {\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n\n @starting-style {\n display: flex;\n opacity: 0;\n transform: scale(0.94);\n }\n }\n\n .feed {\n display: grid;\n grid-template-rows: 1fr 50px;\n }\n\n .feed__content {\n align-items: flex-start;\n align-self: stretch;\n display: flex;\n gap: 8px;\n min-height: 80px;\n max-height: 290px;\n }\n\n .feed__empty {\n padding: 24px 16px 24px 8px;\n text-align: center;\n font-family: Inter, sans-serif;\n font-size: 13px;\n color: var(--pop-muted-foreground);\n line-height: 18px;\n }\n\n .feed__footer {\n position: absolute;\n bottom: 0;\n min-height: 50px;\n width: 100%;\n }\n\n .feed__main {\n align-items: stretch;\n align-self: stretch;\n display: flex;\n flex-direction: column;\n flex: 1 0 0;\n gap: 16px;\n min-height: 100%;\n overflow: hidden auto;\n padding: 8px 10px 8px 8px;\n }\n\n .feed__main::-webkit-scrollbar {\n width: 4px;\n }\n\n .feed__main::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .feed__main::-webkit-scrollbar-thumb {\n background: var(--pop-border);\n border-radius: 100px;\n }\n`);\n\nexport class PopFeed extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n private _footerChild: string | null = null;\n private _wasOpen = false;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n connectedCallback() {\n super.connectedCallback();\n document.addEventListener(\"mousedown\", this);\n document.addEventListener(\"keydown\", this);\n }\n\n disconnectedCallback() {\n document.removeEventListener(\"mousedown\", this);\n document.removeEventListener(\"keydown\", this);\n super.disconnectedCallback();\n }\n\n handleEvent(event: Event): void {\n if (event.type === \"mousedown\") {\n this.onOutsideClick(event as MouseEvent);\n return;\n }\n\n if (event.type === \"keydown\") {\n this.onKeyDown(event as KeyboardEvent);\n return;\n }\n\n super.handleEvent(event);\n }\n\n private onOutsideClick(event: MouseEvent) {\n if (!this.gridStore.open.value) return;\n\n const path = event.composedPath();\n const root = this.getRootNode();\n const host = root instanceof ShadowRoot ? root.host : null;\n if (!path.includes(this) && (!host || !path.includes(host))) {\n this.gridStore.open.value = false;\n }\n }\n\n private onKeyDown(event: KeyboardEvent) {\n if (event.key !== \"Escape\") return;\n this.gridStore.open.value = false;\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const open = this.gridStore.open.value;\n\n if (open && !this._wasOpen && this.gridStore.grid.value) {\n void checkSession(this.gridStore.apiUrl, this.gridStore.publicKey);\n }\n\n this._wasOpen = open;\n this.update();\n });\n }\n\n private update(): void {\n if (this.gridStore.open.value) {\n this.setAttribute(\"open\", \"\");\n } else {\n this.removeAttribute(\"open\");\n }\n\n const content = this.getElement<HTMLDivElement>(\".feed__main\");\n if (content) {\n const threads = this.gridStore.topLevelComments.value;\n\n if (threads.length === 0) {\n const isEmpty = content.querySelector(\".feed__empty\");\n if (!isEmpty) {\n content.innerHTML = `<div class=\"feed__empty\">Waiting for your thoughts…</div>`;\n }\n } else {\n const existingIds = Array.from(content.querySelectorAll(\"pop-comment-thread\")).map((el) =>\n el.getAttribute(\"comment-id\"),\n );\n\n const newIds = threads.map((c) => c.id);\n const needsRebuild =\n existingIds.length !== newIds.length || existingIds.some((id, i) => id !== newIds[i]);\n\n if (needsRebuild) {\n content.innerHTML = threads\n .map(\n (comment) => `<pop-comment-thread comment-id=\"${comment.id}\"></pop-comment-thread>`,\n )\n .join(\"\");\n }\n }\n }\n\n const footer = this.getElement<HTMLDivElement>(\".feed__footer\");\n if (footer) {\n const authed = currentUser.value !== null;\n const desired = authed ? \"pop-comment-bar\" : \"pop-auth-panel\";\n if (this._footerChild !== desired) {\n this._footerChild = desired;\n footer.innerHTML = `<${desired}></${desired}>`;\n }\n }\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"feed\">\n <div class=\"feed__content\">\n <div class=\"feed__main\"></div>\n </div>\n <div class=\"feed__footer\"></div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-feed\")) {\n customElements.define(\"pop-feed\", PopFeed);\n}\n","function hasWindow() {\n return typeof window !== 'undefined';\n}\nfunction getNodeName(node) {\n if (isNode(node)) {\n return (node.nodeName || '').toLowerCase();\n }\n // Mocked nodes in testing environments may not be instances of Node. By\n // returning `#document` an infinite loop won't occur.\n // https://github.com/floating-ui/floating-ui/issues/2317\n return '#document';\n}\nfunction getWindow(node) {\n var _node$ownerDocument;\n return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;\n}\nfunction getDocumentElement(node) {\n var _ref;\n return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;\n}\nfunction isNode(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Node || value instanceof getWindow(value).Node;\n}\nfunction isElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Element || value instanceof getWindow(value).Element;\n}\nfunction isHTMLElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;\n}\nfunction isShadowRoot(value) {\n if (!hasWindow() || typeof ShadowRoot === 'undefined') {\n return false;\n }\n return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;\n}\nfunction isOverflowElement(element) {\n const {\n overflow,\n overflowX,\n overflowY,\n display\n } = getComputedStyle(element);\n return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';\n}\nfunction isTableElement(element) {\n return /^(table|td|th)$/.test(getNodeName(element));\n}\nfunction isTopLayer(element) {\n try {\n if (element.matches(':popover-open')) {\n return true;\n }\n } catch (_e) {\n // no-op\n }\n try {\n return element.matches(':modal');\n } catch (_e) {\n return false;\n }\n}\nconst willChangeRe = /transform|translate|scale|rotate|perspective|filter/;\nconst containRe = /paint|layout|strict|content/;\nconst isNotNone = value => !!value && value !== 'none';\nlet isWebKitValue;\nfunction isContainingBlock(elementOrCss) {\n const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n // https://drafts.csswg.org/css-transforms-2/#individual-transforms\n return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');\n}\nfunction getContainingBlock(element) {\n let currentNode = getParentNode(element);\n while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {\n if (isContainingBlock(currentNode)) {\n return currentNode;\n } else if (isTopLayer(currentNode)) {\n return null;\n }\n currentNode = getParentNode(currentNode);\n }\n return null;\n}\nfunction isWebKit() {\n if (isWebKitValue == null) {\n isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');\n }\n return isWebKitValue;\n}\nfunction isLastTraversableNode(node) {\n return /^(html|body|#document)$/.test(getNodeName(node));\n}\nfunction getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\nfunction getNodeScroll(element) {\n if (isElement(element)) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n }\n return {\n scrollLeft: element.scrollX,\n scrollTop: element.scrollY\n };\n}\nfunction getParentNode(node) {\n if (getNodeName(node) === 'html') {\n return node;\n }\n const result =\n // Step into the shadow DOM of the parent of a slotted node.\n node.assignedSlot ||\n // DOM Element detected.\n node.parentNode ||\n // ShadowRoot detected.\n isShadowRoot(node) && node.host ||\n // Fallback.\n getDocumentElement(node);\n return isShadowRoot(result) ? result.host : result;\n}\nfunction getNearestOverflowAncestor(node) {\n const parentNode = getParentNode(node);\n if (isLastTraversableNode(parentNode)) {\n return node.ownerDocument ? node.ownerDocument.body : node.body;\n }\n if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {\n return parentNode;\n }\n return getNearestOverflowAncestor(parentNode);\n}\nfunction getOverflowAncestors(node, list, traverseIframes) {\n var _node$ownerDocument2;\n if (list === void 0) {\n list = [];\n }\n if (traverseIframes === void 0) {\n traverseIframes = true;\n }\n const scrollableAncestor = getNearestOverflowAncestor(node);\n const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);\n const win = getWindow(scrollableAncestor);\n if (isBody) {\n const frameElement = getFrameElement(win);\n return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);\n } else {\n return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));\n }\n}\nfunction getFrameElement(win) {\n return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;\n}\n\nexport { getComputedStyle, getContainingBlock, getDocumentElement, getFrameElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isTopLayer, isWebKit };\n","import{isContainingBlock as t}from\"@floating-ui/utils/dom\";function e(t){return i(t)}function n(t){return f(t,\"offsetTop\")}function o(t){return f(t,\"offsetLeft\")}function r(t){return t.assignedSlot?t.assignedSlot:t.parentNode instanceof ShadowRoot?t.parentNode.host:t.parentNode}function i(e){for(let t=e;t;t=r(t))if(t instanceof Element&&\"none\"===getComputedStyle(t).display)return null;for(let n=r(e);n;n=r(n)){if(!(n instanceof Element))continue;const e=getComputedStyle(n);if(\"contents\"!==e.display){if(\"static\"!==e.position||t(e))return n;if(\"BODY\"===n.tagName)return n}}return null}function f(t,e){let n=t[e],o=i(t);const r=function(t){const e=new Set;let n=t.getRootNode();for(;n;)e.add(n),n=n.parentNode?n.parentNode.getRootNode():null;return e}(t);for(;o&&!r.has(o.getRootNode());)n-=o[e],o=i(o);return n}export{o as offsetLeft,e as offsetParent,n as offsetTop};\n","import {\n type Middleware,\n autoUpdate,\n computePosition,\n flip,\n offset,\n platform,\n} from \"@floating-ui/dom\";\nimport { offsetParent } from \"composed-offset-position\";\nimport { checkSession } from \"../store/auth-store.js\";\nimport { GridStore, type GridOverrides } from \"../store/grid-store.js\";\nimport { registerStore, unregisterStore } from \"../store/registry.js\";\nimport type { Grid } from \"../types/models.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst DEFAULT_API_URL = \"https://www.popgrids.io\";\n\nconst ALIGN_VALUES = new Set<string>([\"start\", \"center\", \"end\"] satisfies Grid[\"align\"][]);\nconst LAYOUT_VALUES = new Set<string>([\"sm\", \"lg\"] satisfies Grid[\"layout\"][]);\nconst POSITION_VALUES = new Set<string>([\"auto\", \"up\", \"down\"] satisfies Grid[\"position\"][]);\n\nconst localSheet = createSheet(/* css */ `\n :host {\n display: block;\n position: relative;\n }\n\n .grid {\n display: flex;\n height: 100%;\n position: relative;\n width: 100%;\n }\n\n .grid--align-start {\n justify-content: flex-start;\n }\n\n .grid--align-center {\n justify-content: center;\n }\n\n .grid--align-end {\n justify-content: flex-end;\n }\n`);\n\nexport class PopGrid extends BaseElement {\n private _initialized = false;\n private _floatingCleanup?: () => void;\n private _store!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n // Only the five visual-override attributes are observed/reactive.\n // data-key/data-api-url/data-page-url/data-id stay connect-once — changing\n // them would mean tearing down and re-establishing the fetch/websocket,\n // which is out of scope here.\n static get observedAttributes() {\n return [\"data-align\", \"data-layout\", \"data-position\", \"data-icon\", \"data-preview-count\"];\n }\n\n connectedCallback() {\n if (this._initialized) return;\n this._initialized = true;\n\n const publicKey = this.getAttribute(\"data-key\") ?? this.getAttribute(\"public-key\") ?? \"\";\n\n const apiUrl =\n this.getAttribute(\"data-api-url\") ??\n this.getAttribute(\"api-url\") ??\n DEFAULT_API_URL;\n\n const pageUrl =\n this.getAttribute(\"data-page-url\") ?? this.getAttribute(\"page-url\") ?? location.href;\n\n // Names the discussion thread (Disqus-style identifier): embeds sharing a\n // data-id share one thread across pages; without it the thread is keyed\n // by the page's canonical URL.\n const externalId = this.getAttribute(\"data-id\");\n\n this._store = new GridStore({\n apiUrl,\n publicKey,\n pageUrl,\n externalId,\n });\n registerStore(this, this._store);\n\n super.connectedCallback();\n\n // Picks up any override attributes already present at connect time —\n // attributeChangedCallback can fire for these before _store exists (the\n // browser calls it for observed attributes present at upgrade, ahead of\n // connectedCallback), so each onData*Changed handler below no-ops until\n // this runs.\n this._store.setOverrides(this._readOverridesFromAttributes());\n\n void this._store.load().then((loaded) => {\n if (loaded) {\n void checkSession(apiUrl, publicKey);\n }\n });\n }\n\n private _readOverridesFromAttributes(): GridOverrides {\n const overrides: GridOverrides = {};\n\n const align = this.getAttribute(\"data-align\");\n if (align && ALIGN_VALUES.has(align)) {\n overrides.align = align as Grid[\"align\"];\n }\n\n const layout = this.getAttribute(\"data-layout\");\n if (layout && LAYOUT_VALUES.has(layout)) {\n overrides.layout = layout as Grid[\"layout\"];\n }\n\n const position = this.getAttribute(\"data-position\");\n if (position && POSITION_VALUES.has(position)) {\n overrides.position = position as Grid[\"position\"];\n }\n\n const icon = this.getAttribute(\"data-icon\");\n if (icon) {\n overrides.icon = icon;\n }\n\n const previewCountAttr = this.getAttribute(\"data-preview-count\");\n if (previewCountAttr !== null) {\n const previewCount = Number(previewCountAttr);\n if (Number.isInteger(previewCount) && previewCount > 0) {\n overrides.previewCount = previewCount;\n }\n }\n\n return overrides;\n }\n\n private _applyOverridesFromAttributes(): void {\n // Attributes present at upgrade can trigger this before connectedCallback\n // constructs _store — connectedCallback re-reads everything once it does.\n if (!this._store) return;\n this._store.setOverrides(this._readOverridesFromAttributes());\n }\n\n onDataAlignChanged() {\n this._applyOverridesFromAttributes();\n }\n\n onDataLayoutChanged() {\n this._applyOverridesFromAttributes();\n }\n\n onDataPositionChanged() {\n this._applyOverridesFromAttributes();\n }\n\n onDataIconChanged() {\n this._applyOverridesFromAttributes();\n }\n\n onDataPreviewCountChanged() {\n this._applyOverridesFromAttributes();\n }\n\n disconnectedCallback() {\n this._floatingCleanup?.();\n this._store.destroy();\n unregisterStore(this);\n super.disconnectedCallback();\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n const grid = this._store.grid.value;\n const gridEl = this.getElement(\".grid\");\n if (!gridEl) return;\n\n // Remove any existing grid-- classes\n const toRemove = Array.from(gridEl.classList).filter((cls) => cls.startsWith(\"grid--\"));\n if (toRemove.length > 0) {\n gridEl.classList.remove(...toRemove);\n }\n\n if (grid) {\n if (grid.align) gridEl.classList.add(`grid--align-${grid.align}`);\n if (grid.appearance) gridEl.classList.add(`grid--appearance-${grid.appearance}`);\n if (grid.icon) gridEl.classList.add(`grid--icon-${grid.icon}`);\n if (grid.layout) gridEl.classList.add(`grid--layout-${grid.layout}`);\n if (grid.position) gridEl.classList.add(`grid--position-${grid.position}`);\n\n const previewVal = grid.previewCount ?? this._store.previewCount;\n gridEl.classList.add(`grid--preview-${previewVal}`);\n }\n });\n\n this.addEffect(() => {\n const open = this._store.open.value;\n\n if (this._floatingCleanup) {\n this._floatingCleanup();\n this._floatingCleanup = undefined;\n }\n\n if (!open) return;\n\n const widget = this.getElement(\"pop-widget\");\n const feed = this.getElement(\"pop-feed\");\n if (!widget || !feed) return;\n\n const grid = this._store.grid.value;\n if (!grid) return;\n\n // Offset\n let middleware: Middleware[] = [];\n\n middleware = [\n offset({\n mainAxis: grid.position === \"down\" ? -16 : -54,\n crossAxis: -18,\n }),\n ];\n\n // Flip\n if (!grid.position || grid.position === \"auto\") {\n middleware.push(\n flip({\n fallbackPlacements: [\"bottom-start\", \"top-start\"],\n fallbackStrategy: \"bestFit\",\n padding: 16,\n }),\n );\n }\n\n const getOffsetParent = (element: Element) => platform.getOffsetParent(element, offsetParent);\n\n const update = () => {\n void computePosition(widget, feed, {\n placement: grid.position === \"down\" ? \"bottom-start\" : \"top-start\",\n middleware,\n strategy: \"fixed\",\n platform: {\n ...platform,\n getOffsetParent,\n },\n }).then(({ x, y, placement }) => {\n feed.setAttribute(\"data-current-placement\", placement);\n\n Object.assign(feed.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n });\n };\n\n this._floatingCleanup = autoUpdate(widget, feed, update);\n });\n }\n\n protected getTemplate(): string {\n return /* html */ `\n <div class=\"grid\">\n <pop-widget></pop-widget>\n <pop-feed></pop-feed>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-grid\")) {\n customElements.define(\"pop-grid\", PopGrid);\n}\n","import { getInitials } from \"../helpers/author.js\";\nimport { GridStore } from \"../store/grid-store.js\";\nimport { consume } from \"../store/registry.js\";\nimport { BaseElement, createSheet } from \"./base-element.js\";\n\nconst localSheet = createSheet(/* css */ `\n :host {\n --error-badge-bg: #fef2f2;\n --error-badge-text: #991b1b;\n --error-badge-border: #fecaca;\n\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --error-badge-bg: #450a0a;\n --error-badge-text: #fca5a5;\n --error-badge-border: #7f1d1d;\n }\n }\n\n :host(.dark) {\n --error-badge-bg: #450a0a;\n --error-badge-text: #fca5a5;\n --error-badge-border: #7f1d1d;\n }\n\n :host([data-error]) {\n cursor: default;\n }\n\n .error-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: var(--pop-radius-full);\n border: 1px solid var(--error-badge-border);\n background: var(--error-badge-bg);\n color: var(--error-badge-text);\n font-size: 12px;\n font-weight: 500;\n line-height: 16px;\n white-space: nowrap;\n }\n\n .widget {\n display: inline-flex;\n align-items: flex-start;\n }\n\n .widget > :not([hidden]) ~ :not([hidden]) {\n margin-left: -6px;\n }\n\n .skeleton {\n width: 32px;\n height: 32px;\n background: var(--pop-muted);\n animation: pulse 1.5s ease-in-out infinite;\n }\n\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n }\n\n .count {\n --count-size: calc(32px + var(--count-border-size));\n --count-background: var(--pop-background);\n --count-border-color: rgba(0 0 32 / 16%);\n --count-border-size: 1px;\n --count-color: var(--pop-foreground);\n\n align-items: center;\n background-color: var(--pop-background);\n display: flex;\n flex-shrink: 0;\n justify-content: center;\n padding: calc(var(--count-border-size) / 2);\n position: relative;\n z-index: 10;\n\n width: calc(var(--count-size) + (calc(var(--count-border-size))));\n height: calc(var(--count-size) + (calc(var(--count-border-size))));\n }\n\n .count__background {\n background-color: var(--count-border-color);\n position: absolute;\n top: 0;\n left: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n }\n\n .count__content {\n align-items: center;\n background: var(--count-background);\n display: flex;\n justify-content: center;\n overflow: hidden;\n height: var(--count-size);\n width: var(--count-size);\n }\n\n .count__label {\n color: var(--count-color);\n font-size: 16px;\n font-style: normal;\n font-weight: 500;\n letter-spacing: -0.96px;\n line-height: 28px;\n text-align: center;\n user-select: none;\n }\n\n .count__label-container {\n align-items: center;\n background: var(--pop-background);\n display: flex;\n height: calc(100% - calc(var(--count-border-size) * 2));\n justify-content: center;\n position: relative;\n text-indent: calc(calc(var(--count-border-size) * 2) * -1);\n width: calc(100% - calc(var(--count-border-size) * 2));\n z-index: 20;\n }\n\n /* Above .count (z-index: 10) — otherwise it paints underneath despite\n * coming later in the widget's facepile, since z-index only applies to\n * positioned elements and this one had neither. */\n .widget pop-comment-icon {\n position: relative;\n z-index: 20;\n top: 1px;\n }\n`);\n\nexport class PopWidget extends BaseElement {\n @consume(GridStore) gridStore!: GridStore;\n\n protected get styleSheets() {\n return [localSheet];\n }\n\n protected events = {\n click: \"onClick\",\n };\n\n protected onClick() {\n if (this.gridStore.error.value) {\n return;\n }\n\n this.gridStore.open.value = !this.gridStore.open.value;\n }\n\n protected setupEffects() {\n this.addEffect(() => {\n this.gridStore.loading.value;\n this.gridStore.error.value;\n this.gridStore.previewAvatars.value;\n this.gridStore.comments.value;\n this.gridStore.grid.value;\n\n const hasError = Boolean(this.gridStore.error.value);\n this.toggleAttribute(\"data-error\", hasError);\n\n if (hasError && this.gridStore.open.value) {\n this.gridStore.open.value = false;\n }\n\n this.render();\n });\n }\n\n protected getTemplate(): string {\n if (this.gridStore.loading.value) {\n return `<div class=\"widget\"><div class=\"skeleton mask mask-squircle\"></div></div>`;\n }\n\n if (this.gridStore.error.value) {\n return `<div class=\"error-badge\">Error: there was a problem loading the PopGrid</div>`;\n }\n\n const avatars = this.gridStore.previewAvatars.value;\n const totalCount = this.gridStore.comments.value.length;\n const grid = this.gridStore.grid.value;\n\n // \"sm\"/null -&gt; today's default (32px); \"lg\" -&gt; a clearly larger step (80px).\n const avatarSize = grid?.layout === \"lg\" ? \"md\" : \"xs\";\n const iconTheme = grid?.icon === \"brand\" ? \"brand\" : \"neutral\";\n\n const avatarsHtml = avatars\n .map((author, idx) => {\n const zIndex = avatars.length + idx;\n const colorKey = author?.id ?? author?.name ?? \"\";\n\n if (author?.image) {\n return `<pop-comment-avatar size=\"${avatarSize}\" style=\"z-index: ${zIndex}\" data-color-key=\"${colorKey}\">\n <img src=\"${author.image}\" alt=\"${author.name ?? \"User\"}\" />\n </pop-comment-avatar>`;\n }\n\n return `<pop-comment-avatar size=\"${avatarSize}\" style=\"z-index: ${zIndex}\" data-color-key=\"${colorKey}\">\n ${getInitials(author?.name)}\n </pop-comment-avatar>`;\n })\n .join(\"\");\n\n return /* html */ `\n <div class=\"widget\">\n ${avatarsHtml}\n <div class=\"count mask mask-squircle\">\n <span class=\"count__content mask mask-squircle\">\n <div class=\"count__background mask mask-squircle\"></div>\n <div class=\"count__label-container mask mask-squircle\">\n <div class=\"count__label\">${totalCount}</div>\n </div>\n </span>\n </div>\n <pop-comment-icon variant=\"add\" theme=\"${iconTheme}\" size=\"xs\"></pop-comment-icon>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"pop-widget\")) {\n customElements.define(\"pop-widget\", PopWidget);\n}\n","if (typeof document !== \"undefined\") {\n const fontUrl = \"https://rsms.me/inter/inter.css\";\n if (!document.querySelector(`link[href=\"${fontUrl}\"]`)) {\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = fontUrl;\n document.head.appendChild(link);\n }\n}\n\nimport \"./components/pop-auth-panel.js\";\nimport \"./components/pop-comment-avatar.js\";\nimport \"./components/pop-comment-bar.js\";\nimport \"./components/pop-comment-icon.js\";\nimport \"./components/pop-comment-input.js\";\nimport \"./components/pop-comment-thread.js\";\nimport \"./components/pop-comment.js\";\nimport \"./components/pop-feed.js\";\nimport \"./components/pop-grid.js\";\nimport \"./components/pop-widget.js\";\n\nexport type { AuthUser, Comment, CommentAuthor, Grid } from \"./types/models.js\";\n"],"x_google_ignoreList":[21,22],"mappings":"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"}