@crvouga/mockingbird-notifications 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +304 -2
- package/dist/chunk-GRGR3QZM.js +1066 -0
- package/dist/chunk-GRGR3QZM.js.map +7 -0
- package/dist/chunk-JQ6KPT2C.js +202 -0
- package/dist/chunk-JQ6KPT2C.js.map +7 -0
- package/dist/chunk-LM7R7AR7.js +183 -0
- package/dist/chunk-LM7R7AR7.js.map +7 -0
- package/dist/chunk-QE3TRUI6.js +444 -0
- package/dist/chunk-QE3TRUI6.js.map +7 -0
- package/dist/cli.js +104 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +411 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +7 -0
- package/dist/server.d.ts +177 -0
- package/dist/server.js +13 -0
- package/dist/server.js.map +7 -0
- package/dist/ui.d.ts +445 -0
- package/dist/ui.js +1923 -0
- package/dist/ui.js.map +7 -0
- package/package.json +88 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/model.ts", "../src/mime.ts", "../src/discovery.ts", "../src/generated/browser.ts", "../src/sources.ts", "../src/ui/page.ts", "../src/harness.ts"],
|
|
4
|
+
"sourcesContent": ["/** The three kinds of device a notification lands on. */\nexport type Channel = \"sms\" | \"email\" | \"push\"\n\n/** Emulators the harness knows how to read. */\nexport type ServiceKind = \"twilio\" | \"resend\" | \"fcm\" | \"ses\" | \"sns\" | \"customerio\" | \"mailosaur\"\n\nexport const SERVICE_KINDS: readonly ServiceKind[] = [\n \"twilio\",\n \"resend\",\n \"fcm\",\n \"ses\",\n \"sns\",\n \"customerio\",\n \"mailosaur\",\n]\n\nexport const SERVICE_LABELS: Record<ServiceKind, string> = {\n twilio: \"Twilio\",\n resend: \"Resend\",\n fcm: \"Firebase Cloud Messaging\",\n ses: \"Amazon SES\",\n sns: \"Amazon SNS\",\n customerio: \"Customer.io\",\n mailosaur: \"Mailosaur\",\n}\n\nexport type Address = { name: string | null; address: string }\n\nexport type SmsContent = {\n body: string\n /** One-time code the sender included (Twilio Verify), when known. */\n code: string | null\n media: string[]\n}\n\nexport type EmailAttachment = { filename: string; contentType: string | null; size: number | null }\n\nexport type EmailContent = {\n subject: string\n html: string | null\n text: string | null\n cc: string[]\n bcc: string[]\n replyTo: string[]\n attachments: EmailAttachment[]\n headers: Record<string, string>\n}\n\nexport type PushPlatform = \"android\" | \"ios\" | \"web\" | \"unknown\"\n\nexport type PushContent = {\n title: string | null\n body: string | null\n imageUrl: string | null\n /** The app the notification belongs to (the FCM project, for example). */\n app: string\n platform: PushPlatform\n data: Record<string, string>\n badge: number | null\n sound: string | null\n}\n\n/** One message as a recipient would receive it, normalized across emulators. */\nexport type Notification = {\n /** Stable across polls: `<service entry>:<namespace>:<provider id>`. */\n id: string\n /** The provider's own id (Twilio SID, Resend id, FCM message name, \u2026). */\n providerId: string\n channel: Channel\n /** The fleet entry name (`twilio`, or an alias such as `push`). */\n source: string\n service: ServiceKind\n namespace: string\n /** Phone number, email address, or push registration token. */\n to: string\n from: Address\n /** ISO-8601, on the emulator's clock. */\n createdAt: string\n /** Short plain-text preview. */\n preview: string\n /** Provider delivery state when it reports one (`queued`, `delivered`, `suppressed`, \u2026). */\n status: string | null\n sms: SmsContent | null\n email: EmailContent | null\n push: PushContent | null\n /** The record exactly as the emulator reported it. */\n raw: unknown\n}\n\nexport type NotificationFilter = {\n channel?: Channel | undefined\n service?: ServiceKind | undefined\n source?: string | undefined\n namespace?: string | undefined\n /** Exact recipient (case-insensitive for email). */\n to?: string | undefined\n /** Case-insensitive text search across sender, subject, title and body. */\n contains?: string | undefined\n /** Only notifications created at or after this instant (ISO-8601 or epoch ms). */\n since?: string | number | undefined\n}\n\nexport type SourceStatus = {\n name: string\n service: ServiceKind | null\n url: string\n ok: boolean\n error: string | null\n count: number\n lastSyncAt: string | null\n}\n\nconst toMs = (value: string | number): number =>\n typeof value === \"number\" ? value : /^\\d+$/.test(value) ? Number(value) : Date.parse(value)\n\nconst searchable = (n: Notification): string =>\n [\n n.to,\n n.from.address,\n n.from.name ?? \"\",\n n.preview,\n n.sms?.body ?? \"\",\n n.email?.subject ?? \"\",\n n.email?.text ?? \"\",\n n.push?.title ?? \"\",\n n.push?.body ?? \"\",\n ]\n .join(\"\\n\")\n .toLowerCase()\n\nexport const matches = (n: Notification, filter: NotificationFilter): boolean => {\n if (filter.channel && n.channel !== filter.channel) return false\n if (filter.service && n.service !== filter.service) return false\n if (filter.source && n.source !== filter.source) return false\n if (filter.namespace && n.namespace !== filter.namespace) return false\n if (filter.to && n.to.toLowerCase() !== filter.to.toLowerCase()) return false\n if (filter.contains && !searchable(n).includes(filter.contains.toLowerCase())) return false\n if (filter.since !== undefined && Date.parse(n.createdAt) < toMs(filter.since)) return false\n return true\n}\n\n/** Parse `?channel=&service=&to=\u2026` into a filter. Unknown values are rejected. */\nexport const filterFromSearch = (params: URLSearchParams): NotificationFilter => {\n const filter: NotificationFilter = {}\n const channel = params.get(\"channel\")\n if (channel) {\n if (channel !== \"sms\" && channel !== \"email\" && channel !== \"push\")\n throw new Error(`channel: expected sms, email or push, got ${JSON.stringify(channel)}`)\n filter.channel = channel\n }\n const service = params.get(\"service\")\n if (service) {\n if (!(SERVICE_KINDS as readonly string[]).includes(service))\n throw new Error(`service: expected one of ${SERVICE_KINDS.join(\", \")}`)\n filter.service = service as ServiceKind\n }\n for (const key of [\"source\", \"namespace\", \"to\", \"contains\"] as const) {\n const value = params.get(key)\n if (value) filter[key] = value\n }\n const since = params.get(\"since\")\n if (since) {\n if (Number.isNaN(toMs(since))) throw new Error(\"since: expected ISO-8601 or epoch milliseconds\")\n filter.since = since\n }\n return filter\n}\n\nexport const filterToSearch = (filter: NotificationFilter): URLSearchParams => {\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined && value !== \"\") params.set(key, String(value))\n return params\n}\n", "/**\n * A small MIME reader for the raw messages SES `SendRawEmail` receives. It covers what mail\n * libraries produce (nodemailer, the AWS samples): folded headers, RFC 2047 encoded words,\n * nested multiparts, base64 and quoted-printable bodies. Everything is decoded as UTF-8.\n */\nimport type { EmailAttachment } from \"./model.js\"\n\nexport type ParsedMime = {\n headers: Record<string, string>\n subject: string\n from: string | null\n to: string[]\n cc: string[]\n html: string | null\n text: string | null\n attachments: EmailAttachment[]\n}\n\ntype Part = { headers: Record<string, string>; body: string }\n\nconst utf8 = new TextDecoder()\n\nconst base64Bytes = (value: string): Uint8Array => {\n const binary = atob(value.replace(/[^A-Za-z0-9+/=]/g, \"\"))\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n return bytes\n}\n\nconst quotedPrintableBytes = (value: string, underscoreSpace = false): Uint8Array => {\n const source = value.replace(/=\\r?\\n/g, \"\")\n const out: number[] = []\n for (let i = 0; i < source.length; i++) {\n const ch = source[i] ?? \"\"\n const hex = source.slice(i + 1, i + 3)\n if (ch === \"=\" && /^[0-9A-Fa-f]{2}$/.test(hex)) {\n out.push(Number.parseInt(hex, 16))\n i += 2\n } else if (underscoreSpace && ch === \"_\") out.push(32)\n else for (const byte of new TextEncoder().encode(ch)) out.push(byte)\n }\n return new Uint8Array(out)\n}\n\n/** `=?utf-8?B?\u2026?=` and `=?utf-8?Q?\u2026?=` words in a header value. */\nexport const decodeWords = (value: string): string =>\n value\n .replace(/\\?=\\s+=\\?/g, \"?==?\")\n .replace(\n /=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?=/g,\n (_, _charset: string, kind: string, text: string) =>\n utf8.decode(\n kind.toUpperCase() === \"B\" ? base64Bytes(text) : quotedPrintableBytes(text, true),\n ),\n )\n\nconst splitHead = (raw: string): Part => {\n const normalized = raw.replace(/\\r\\n/g, \"\\n\")\n const end = normalized.indexOf(\"\\n\\n\")\n const head = end < 0 ? normalized : normalized.slice(0, end)\n const body = end < 0 ? \"\" : normalized.slice(end + 2)\n const headers: Record<string, string> = {}\n for (const line of head.replace(/\\n[ \\t]+/g, \" \").split(\"\\n\")) {\n const colon = line.indexOf(\":\")\n if (colon <= 0) continue\n const name = line.slice(0, colon).trim().toLowerCase()\n const value = decodeWords(line.slice(colon + 1).trim())\n headers[name] = headers[name] ? `${headers[name]}, ${value}` : value\n }\n return { headers, body }\n}\n\nconst param = (header: string | undefined, name: string): string | null => {\n if (!header) return null\n const match = new RegExp(`${name}\\\\*?=(?:\"([^\"]*)\"|([^;\\\\s]+))`, \"i\").exec(header)\n return match ? (match[1] ?? match[2] ?? null) : null\n}\n\nconst decodeBody = (part: Part): Uint8Array => {\n const encoding = (part.headers[\"content-transfer-encoding\"] ?? \"\").toLowerCase()\n if (encoding === \"base64\") return base64Bytes(part.body)\n if (encoding === \"quoted-printable\") return quotedPrintableBytes(part.body)\n return new TextEncoder().encode(part.body)\n}\n\nconst walk = (part: Part, out: ParsedMime): void => {\n const type = (part.headers[\"content-type\"] ?? \"text/plain\").toLowerCase()\n const boundary = param(part.headers[\"content-type\"], \"boundary\")\n if (type.startsWith(\"multipart/\") && boundary) {\n const sections = part.body.split(`--${boundary}`)\n for (const section of sections.slice(1)) {\n if (section.startsWith(\"--\")) break\n walk(splitHead(section.replace(/^\\n/, \"\")), out)\n }\n return\n }\n const disposition = part.headers[\"content-disposition\"] ?? \"\"\n const filename = param(disposition, \"filename\") ?? param(part.headers[\"content-type\"], \"name\")\n if (/^attachment/i.test(disposition) || (filename && !type.startsWith(\"text/\"))) {\n out.attachments.push({\n filename: filename ?? \"attachment\",\n contentType: type.split(\";\")[0]?.trim() ?? null,\n size: decodeBody(part).byteLength,\n })\n return\n }\n const text = utf8.decode(decodeBody(part)).replace(/\\n$/, \"\")\n if (type.startsWith(\"text/html\") && out.html === null) out.html = text\n else if (type.startsWith(\"text/plain\") && out.text === null) out.text = text\n}\n\n/** Split an address list header (`\"A, B\" <a@x>, b@y`) into its addresses. */\nexport const addressList = (value: string | undefined): string[] =>\n (value ?? \"\")\n .split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/)\n .map((item) => item.trim())\n .filter(Boolean)\n\nexport const parseMime = (raw: string): ParsedMime => {\n const root = splitHead(raw)\n const out: ParsedMime = {\n headers: root.headers,\n subject: root.headers.subject ?? \"\",\n from: root.headers.from ?? null,\n to: addressList(root.headers.to),\n cc: addressList(root.headers.cc),\n html: null,\n text: null,\n attachments: [],\n }\n walk(root, out)\n return out\n}\n\n/** Raw message bytes arrive base64 encoded in `RawMessage.Data`; fall back to plain text. */\nexport const decodeRawMessage = (data: string): string => {\n const compact = data.replace(/\\s+/g, \"\")\n if (/^[A-Za-z0-9+/]+=*$/.test(compact) && compact.length % 4 === 0) {\n const decoded = utf8.decode(base64Bytes(compact))\n if (/^[\\x20-\\x7e]+:/m.test(decoded)) return decoded\n }\n return data\n}\n", "/**\n * Where the emulators are. The harness reads the same fleet the application uses: the live fleet\n * controller (`adminBase`), the fleet's ready manifest, or explicit URLs and in-process runtimes.\n */\nimport { SERVICE_KINDS, type ServiceKind } from \"./model.js\"\n\nexport type FetchLike = (request: Request) => Response | Promise<Response>\n\n/** A service emulator: its base URL, an `{ url, adminUrl?, service? }` entry, or an in-process runtime. */\nexport type ServiceInput =\n | string\n | { url: string; adminUrl?: string; service?: ServiceKind }\n | { fetch: FetchLike; service?: ServiceKind; adminPrefix?: string }\n\n/** The subset of a fleet ready manifest (`--ready-file`) the harness reads. */\nexport type FleetManifest = {\n adminBase?: string\n services: Record<\n string,\n { protocol?: string; url?: string; adminUrl?: string; target?: string } | undefined\n >\n}\n\nexport type Endpoint = {\n /** The fleet entry name, e.g. `twilio`, or an alias such as `push`. */\n name: string\n /** Null until the emulator's health route has told us what it is. */\n service: ServiceKind | null\n /** Absolute admin prefix, e.g. `http://127.0.0.1:8798/__admin`. */\n adminUrl: string\n fetch: FetchLike\n}\n\nexport const asServiceKind = (value: unknown): ServiceKind | null =>\n typeof value === \"string\" && (SERVICE_KINDS as readonly string[]).includes(value)\n ? (value as ServiceKind)\n : null\n\nconst trimSlash = (url: string) => url.replace(/\\/+$/, \"\")\n\nexport const endpointsFromServices = (\n services: Record<string, ServiceInput>,\n fetchImpl: FetchLike,\n): Endpoint[] =>\n Object.entries(services).map(([name, input]) => {\n if (typeof input === \"string\")\n return {\n name,\n service: asServiceKind(name),\n adminUrl: `${trimSlash(input)}/__admin`,\n fetch: fetchImpl,\n }\n if (\"fetch\" in input)\n return {\n name,\n service: input.service ?? asServiceKind(name),\n adminUrl: `http://${name}.mockingbird.local${input.adminPrefix ?? \"/__admin\"}`,\n fetch: input.fetch,\n }\n return {\n name,\n service: input.service ?? asServiceKind(name),\n adminUrl: input.adminUrl ? trimSlash(input.adminUrl) : `${trimSlash(input.url)}/__admin`,\n fetch: fetchImpl,\n }\n })\n\nexport const endpointsFromManifest = (\n manifest: FleetManifest,\n fetchImpl: FetchLike,\n targets: Record<string, string | undefined> = {},\n): Endpoint[] =>\n Object.entries(manifest.services ?? {}).flatMap(([name, entry]): Endpoint[] => {\n if (!entry || (entry.protocol && entry.protocol !== \"http\") || !entry.url) return []\n const service = asServiceKind(targets[name] ?? entry.target ?? name)\n // A target the fleet named that the harness cannot read (stripe, postgres, \u2026) is skipped.\n if (!service && (targets[name] ?? entry.target)) return []\n return [\n {\n name,\n service,\n adminUrl: entry.adminUrl ? trimSlash(entry.adminUrl) : `${trimSlash(entry.url)}/__admin`,\n fetch: fetchImpl,\n },\n ]\n })\n\nexport type FleetDiscovery = {\n endpoints: Endpoint[]\n namespaces: string[]\n}\n\n/** Ask a running fleet controller for its manifest, each entry's target, and its namespaces. */\nexport const discoverFleet = async (\n adminBase: string,\n fetchImpl: FetchLike,\n headers: Record<string, string>,\n): Promise<FleetDiscovery> => {\n const base = trimSlash(adminBase)\n const get = async (path: string) => {\n const response = await fetchImpl(new Request(`${base}${path}`, { headers }))\n if (!response.ok) throw new Error(`fleet ${base}${path}: HTTP ${response.status}`)\n return (await response.json()) as Record<string, unknown>\n }\n const [root, namespaces] = await Promise.all([\n get(\"\"),\n get(\"/namespaces\").catch((): Record<string, unknown> => ({})),\n ])\n const manifest = root.manifest as FleetManifest | undefined\n if (!manifest?.services) throw new Error(`fleet ${base}: discovery has no manifest`)\n const described = (root.services ?? {}) as Record<string, { target?: string } | undefined>\n const targets = Object.fromEntries(\n Object.entries(described).map(([name, entry]) => [name, entry?.target]),\n )\n const names = Array.isArray(namespaces.namespaces)\n ? (namespaces.namespaces as { namespace?: unknown }[])\n .map((n) => n.namespace)\n .filter((n): n is string => typeof n === \"string\")\n : []\n return { endpoints: endpointsFromManifest(manifest, fetchImpl, targets), namespaces: names }\n}\n", "// Generated by scripts/build-ui.ts from src/ui/browser.ts. Do not edit.\nexport const BROWSER_JS: string = \"var r={app:\\\"notifications-app\\\",topbar:\\\"topbar\\\",namespace:\\\"namespace\\\",search:\\\"search\\\",viewDevices:\\\"view-devices\\\",viewTimeline:\\\"view-timeline\\\",follow:\\\"follow\\\",sound:\\\"sound-toggle\\\",connection:\\\"connection\\\",source:\\\"source\\\",notice:\\\"notice\\\",toast:\\\"toast\\\",toastUndo:\\\"toast-undo\\\",smsDevice:\\\"sms-device\\\",smsRecipient:\\\"sms-recipient\\\",smsUnreadCount:\\\"sms-unread-count\\\",smsThread:\\\"sms-thread\\\",smsThreadName:\\\"sms-thread-name\\\",smsThreadPreview:\\\"sms-thread-preview\\\",smsThreadTime:\\\"sms-thread-time\\\",smsThreadUnread:\\\"sms-thread-unread\\\",smsThreadDelete:\\\"sms-thread-delete\\\",smsThreadMute:\\\"sms-thread-mute\\\",smsThreadPin:\\\"sms-thread-pin\\\",smsThreadToggleUnread:\\\"sms-thread-toggle-unread\\\",smsEmpty:\\\"sms-empty\\\",smsConversation:\\\"sms-conversation\\\",smsConversationTitle:\\\"sms-conversation-title\\\",smsBack:\\\"sms-back\\\",smsBubble:\\\"sms-bubble\\\",smsBubbleMedia:\\\"sms-bubble-media\\\",smsBubbleTime:\\\"sms-bubble-time\\\",smsTapback:\\\"sms-tapback\\\",smsTimestamp:\\\"sms-timestamp\\\",smsCode:\\\"sms-code\\\",smsMenu:\\\"sms-menu\\\",smsMenuCopy:\\\"sms-menu-copy\\\",smsMenuTapback:\\\"sms-menu-tapback\\\",pushDevice:\\\"push-device\\\",pushRecipient:\\\"push-recipient\\\",pushSkin:\\\"push-skin\\\",pushUnreadCount:\\\"push-unread-count\\\",pushNotification:\\\"push-notification\\\",pushNotificationApp:\\\"push-notification-app\\\",pushNotificationTitle:\\\"push-notification-title\\\",pushNotificationBody:\\\"push-notification-body\\\",pushNotificationTime:\\\"push-notification-time\\\",pushNotificationImage:\\\"push-notification-image\\\",pushNotificationData:\\\"push-notification-data\\\",pushNotificationMeta:\\\"push-notification-meta\\\",pushGroup:\\\"push-group\\\",pushGroupMore:\\\"push-group-more\\\",pushGroupCollapse:\\\"push-group-collapse\\\",pushClear:\\\"push-clear\\\",pushOptions:\\\"push-options\\\",pushPreview:\\\"push-preview\\\",pushSettings:\\\"push-settings\\\",pushClearAll:\\\"push-clear-all\\\",pushEmpty:\\\"push-empty\\\",emailDevice:\\\"email-device\\\",emailRecipient:\\\"email-recipient\\\",emailUnreadCount:\\\"email-unread-count\\\",emailRow:\\\"email-row\\\",emailRowFrom:\\\"email-row-from\\\",emailRowSubject:\\\"email-row-subject\\\",emailRowSnippet:\\\"email-row-snippet\\\",emailRowDate:\\\"email-row-date\\\",emailRowService:\\\"email-row-service\\\",emailRowAttachment:\\\"email-row-attachment\\\",emailRowStar:\\\"email-row-star\\\",emailRowArchive:\\\"email-row-archive\\\",emailRowDelete:\\\"email-row-delete\\\",emailRowToggleRead:\\\"email-row-toggle-read\\\",emailRefresh:\\\"email-refresh\\\",emailEmpty:\\\"email-empty\\\",emailOpen:\\\"email-open\\\",emailBack:\\\"email-back\\\",emailArchive:\\\"email-archive\\\",emailDelete:\\\"email-delete\\\",emailMarkUnread:\\\"email-mark-unread\\\",emailSubject:\\\"email-subject\\\",emailFromName:\\\"email-from-name\\\",emailFromAddress:\\\"email-from-address\\\",emailTo:\\\"email-to\\\",emailDate:\\\"email-date\\\",emailDetails:\\\"email-details\\\",emailDetail:\\\"email-detail\\\",emailBody:\\\"email-body\\\",emailText:\\\"email-text\\\",emailAttachments:\\\"email-attachments\\\",emailAttachment:\\\"email-attachment\\\",timeline:\\\"timeline\\\",timelineRow:\\\"timeline-row\\\",timelineEmpty:\\\"timeline-empty\\\",inspector:\\\"inspector\\\",inspectorTitle:\\\"inspector-title\\\",inspectorClose:\\\"inspector-close\\\",inspectorShowOnDevice:\\\"inspector-show-on-device\\\",inspectorField:\\\"inspector-field\\\",inspectorJson:\\\"inspector-json\\\"};var V=(d,p,h,k=\\\"\\\")=>`<svg width=\\\"${d}\\\" height=\\\"${p}\\\" viewBox=\\\"0 0 ${d} ${p}\\\" fill=\\\"none\\\" aria-hidden=\\\"true\\\" ${k}>${h}</svg>`,v=(d,p=20)=>`<svg width=\\\"${p}\\\" height=\\\"${p}\\\" viewBox=\\\"0 0 24 24\\\" fill=\\\"currentColor\\\" aria-hidden=\\\"true\\\"><path d=\\\"${d}\\\"/></svg>`,c={signal:(d=\\\"currentColor\\\")=>V(18,12,`<rect x=\\\"0\\\" y=\\\"8\\\" width=\\\"3\\\" height=\\\"4\\\" rx=\\\"1\\\" fill=\\\"${d}\\\"/><rect x=\\\"5\\\" y=\\\"5.5\\\" width=\\\"3\\\" height=\\\"6.5\\\" rx=\\\"1\\\" fill=\\\"${d}\\\"/><rect x=\\\"10\\\" y=\\\"3\\\" width=\\\"3\\\" height=\\\"9\\\" rx=\\\"1\\\" fill=\\\"${d}\\\"/><rect x=\\\"15\\\" y=\\\"0\\\" width=\\\"3\\\" height=\\\"12\\\" rx=\\\"1\\\" fill=\\\"${d}\\\"/>`),wifi:(d=\\\"currentColor\\\")=>V(16,12,`<path d=\\\"M8 2.6c2.3 0 4.4.9 6 2.4l1.1-1.1A10 10 0 0 0 8 1 10 10 0 0 0 .9 3.9L2 5c1.6-1.5 3.7-2.4 6-2.4Z\\\" fill=\\\"${d}\\\"/><path d=\\\"M8 5.9c1.4 0 2.6.5 3.6 1.4l1.1-1.1A6.7 6.7 0 0 0 8 4.3c-1.8 0-3.5.7-4.7 1.9l1.1 1.1c1-.9 2.2-1.4 3.6-1.4Z\\\" fill=\\\"${d}\\\"/><path d=\\\"M10.3 8.6 8 11 5.7 8.6A3.3 3.3 0 0 1 8 7.6c.9 0 1.7.4 2.3 1Z\\\" fill=\\\"${d}\\\"/>`),battery:(d=\\\"currentColor\\\")=>V(27,13,`<rect x=\\\".5\\\" y=\\\".5\\\" width=\\\"23\\\" height=\\\"12\\\" rx=\\\"3.8\\\" stroke=\\\"${d}\\\" stroke-opacity=\\\".4\\\"/><rect x=\\\"2\\\" y=\\\"2\\\" width=\\\"20\\\" height=\\\"9\\\" rx=\\\"2.5\\\" fill=\\\"${d}\\\"/><path d=\\\"M25 4.5v4c.8-.3 1.3-1.1 1.3-2s-.5-1.7-1.3-2Z\\\" fill=\\\"${d}\\\" fill-opacity=\\\".45\\\"/>`),compose:()=>V(24,24,'<path d=\\\"M19 13v6.5a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 3 19.5v-13A1.5 1.5 0 0 1 4.5 5H11\\\" stroke=\\\"#007aff\\\" stroke-width=\\\"1.8\\\" stroke-linecap=\\\"round\\\"/><path d=\\\"m9.5 14.5.6-3.1 8.8-8.8a1.5 1.5 0 0 1 2.1 0l.9.9a1.5 1.5 0 0 1 0 2.1l-8.8 8.8-3.6.1Z\\\" stroke=\\\"#007aff\\\" stroke-width=\\\"1.8\\\" stroke-linejoin=\\\"round\\\"/>'),search:(d=\\\"currentColor\\\",p=16)=>V(p,p,`<circle cx=\\\"${p*.43}\\\" cy=\\\"${p*.43}\\\" r=\\\"${p*.3}\\\" stroke=\\\"${d}\\\" stroke-width=\\\"${p/9}\\\"/><path d=\\\"m${p*.65} ${p*.65} ${p*.27} ${p*.27}\\\" stroke=\\\"${d}\\\" stroke-width=\\\"${p/9}\\\" stroke-linecap=\\\"round\\\"/>`),mic:(d=\\\"#8e8e93\\\")=>V(14,20,`<rect x=\\\"4\\\" y=\\\"1\\\" width=\\\"6\\\" height=\\\"11\\\" rx=\\\"3\\\" fill=\\\"${d}\\\"/><path d=\\\"M1.5 9a5.5 5.5 0 0 0 11 0M7 14.5V18\\\" stroke=\\\"${d}\\\" stroke-width=\\\"1.6\\\" stroke-linecap=\\\"round\\\"/>`),chevronRight:(d=\\\"#c4c4c6\\\")=>V(8,13,`<path d=\\\"m1.5 1.5 5 5-5 5\\\" stroke=\\\"${d}\\\" stroke-width=\\\"2\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\"/>`),chevronBack:()=>V(13,21,'<path d=\\\"M11 2 2.5 10.5 11 19\\\" stroke=\\\"#007aff\\\" stroke-width=\\\"3\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\"/>'),plus:()=>V(16,16,'<path d=\\\"M8 2v12M2 8h12\\\" stroke=\\\"#8e8e93\\\" stroke-width=\\\"2.2\\\" stroke-linecap=\\\"round\\\"/>'),person:()=>V(26,26,'<circle cx=\\\"13\\\" cy=\\\"9\\\" r=\\\"5\\\" fill=\\\"#fff\\\"/><path d=\\\"M3 24c0-5.5 4.5-9 10-9s10 3.5 10 9\\\" fill=\\\"#fff\\\"/>'),padlock:()=>V(16,21,'<rect x=\\\"1\\\" y=\\\"9\\\" width=\\\"14\\\" height=\\\"11\\\" rx=\\\"2.5\\\" fill=\\\"#fff\\\"/><path d=\\\"M4 9V6a4 4 0 0 1 8 0v3\\\" stroke=\\\"#fff\\\" stroke-width=\\\"2\\\"/>'),flashlight:()=>V(14,22,'<path d=\\\"M2 1h10v4L9.5 9v11a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V9L2 5V1Z\\\" fill=\\\"#fff\\\"/>'),camera:()=>V(22,18,'<path d=\\\"M2 5.5A1.5 1.5 0 0 1 3.5 4h3l1.6-2.2h5.8L15.5 4h3A1.5 1.5 0 0 1 20 5.5v10a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 2 15.5v-10Z\\\" fill=\\\"#fff\\\"/><circle cx=\\\"11\\\" cy=\\\"10.3\\\" r=\\\"3.6\\\" fill=\\\"#555\\\"/>'),bell:()=>v(\\\"M12 22a2 2 0 0 0 2-2h-4a2 2 0 0 0 2 2Zm6-6V11a6 6 0 0 0-5-5.9V4a1 1 0 0 0-2 0v1.1A6 6 0 0 0 6 11v5l-2 2v1h16v-1l-2-2Z\\\",18),expand:()=>v(\\\"M7.4 8.6 12 13.2l4.6-4.6L18 10l-6 6-6-6z\\\",16),collapse:()=>v(\\\"M7.4 15.4 12 10.8l4.6 4.6L18 14l-6-6-6 6z\\\",16),androidWifi:()=>v(\\\"M12 21 23.6 6.5A17.6 17.6 0 0 0 12 2.5 17.6 17.6 0 0 0 .4 6.5Z\\\",15),androidSignal:()=>v(\\\"M2 22h20V2Z\\\",14),androidBattery:()=>v(\\\"M16 4h-2V2h-4v2H8a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1Z\\\",15),menu:()=>v(\\\"M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z\\\",24),tune:()=>v(\\\"M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z\\\",24),help:()=>v(\\\"M11 18h2v-2h-2v2zm1-16a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm0-14a4 4 0 0 0-4 4h2a2 2 0 1 1 4 0c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5a4 4 0 0 0-4-4z\\\",24),gear:()=>v(\\\"M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58a.49.49 0 0 0 .12-.61l-1.92-3.32a.49.49 0 0 0-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54a.48.48 0 0 0-.48-.41h-3.84a.48.48 0 0 0-.48.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96a.48.48 0 0 0-.59.22L2.74 8.87a.47.47 0 0 0 .12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58a.49.49 0 0 0-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32a.47.47 0 0 0-.12-.61l-2.01-1.58zM12 15.6A3.6 3.6 0 1 1 12 8.4a3.6 3.6 0 0 1 0 7.2z\\\",24),apps:()=>v(\\\"M6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm6 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-6 0a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm6 0a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4-8a2 2 0 1 0 4 0 2 2 0 0 0-4 0zm-4 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm6 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\\\",24),pencil:()=>v(\\\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 0 0 0-1.41l-2.34-2.34a1 1 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\\\",24),inbox:()=>v(\\\"M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 12h-4a3 3 0 0 1-6 0H5V5h14v10z\\\",20),star:()=>v(\\\"M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z\\\",20),clock:()=>v(\\\"M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z\\\",20),send:()=>v(\\\"M3.4 20.4l17.45-7.48a1 1 0 0 0 0-1.84L3.4 3.6a.99.99 0 0 0-1.39.91L2 9.12c0 .5.37.93.87.99L17 12 2.87 13.88c-.5.07-.87.5-.87 1l.01 4.61c0 .71.73 1.2 1.39.91z\\\",20),draft:()=>v(\\\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zM6 20V4h7v5h5v11H6z\\\",20),more:()=>v(\\\"M12 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 1 0 0 4 2 2 0 0 0 0-4z\\\",20),refresh:()=>v(\\\"M17.65 6.35A7.96 7.96 0 0 0 12 4a8 8 0 1 0 7.73 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\\\",20),checkbox:()=>v(\\\"M19 5v14H5V5h14m0-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z\\\",18),back:()=>v(\\\"M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z\\\",20),archive:()=>v(\\\"M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5 6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z\\\",20),report:()=>v(\\\"M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15.73 3zM19 14.9 14.9 19H9.1L5 14.9V9.1L9.1 5h5.8L19 9.1v5.8zM11 7h2v6h-2zm0 8h2v2h-2z\\\",20),trash:()=>v(\\\"M15 4V3H9v1H4v2h1v13a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6h1V4h-5zm2 15H7V6h10v13zM9 8h2v9H9zm4 0h2v9h-2z\\\",20),reply:()=>v(\\\"M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z\\\",20),forward:()=>v(\\\"M14 9V5l7 7-7 7v-4.1c-5 0-8.5 1.6-11 5.1 1-5 4-10 11-11z\\\",20),clip:()=>v(\\\"M16.5 6v11.5a4 4 0 0 1-8 0V5a2.5 2.5 0 0 1 5 0v10.5a1 1 0 0 1-2 0V6H10v9.5a2.5 2.5 0 0 0 5 0V5a4 4 0 0 0-8 0v12.5a5.5 5.5 0 0 0 11 0V6h-1.5z\\\",16),file:()=>v(\\\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm4 18H6V4h7v5h5v11z\\\",28),dropdown:()=>v(\\\"M7 10l5 5 5-5z\\\",18),lock:()=>v(\\\"M18 8h-1V6A5 5 0 0 0 7 6v2H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2zM9 6a3 3 0 0 1 6 0v2H9V6z\\\",14),envelope:()=>V(30,24,'<path d=\\\"M3 4h24v16a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4Z\\\" fill=\\\"#e8eaed\\\"/><path d=\\\"M3 4l12 9 12-9\\\" stroke=\\\"#5f6368\\\" stroke-width=\\\"2.2\\\" stroke-linejoin=\\\"round\\\"/><path d=\\\"M3 4h24\\\" stroke=\\\"#5f6368\\\" stroke-width=\\\"2.2\\\"/>'),pin:(d=16)=>v(\\\"M16 9V4h1c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1h1v5c0 1.66-1.34 3-3 3v2h5.97v7l1 1 1-1v-7H19v-2c-1.66 0-3-1.34-3-3z\\\",d),bellSlash:(d=16)=>v(\\\"M20 18.69 7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11-.23.09-.46.2-.68.31L18 14.68z\\\",d),volumeOn:(d=16)=>v(\\\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\\\",d),volumeOff:(d=16)=>v(\\\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3 3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4 9.91 6.09 12 8.18V4z\\\",d),markUnread:(d=20)=>v(\\\"M22 8.98V18c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2h10.1c-.06.32-.1.66-.1 1 0 1.48.65 2.79 1.67 3.71L12 11 4 6v2l8 5 5.3-3.32c.54.2 1.1.32 1.7.32 1.13 0 2.16-.39 3-1.02zM16 5c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z\\\",d),markRead:(d=20)=>v(\\\"M21.99 8c0-.72-.37-1.35-.94-1.7L12 1 2.95 6.3C2.38 6.65 2 7.28 2 8v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zM12 13 3.74 7.84 12 3l8.26 4.84L12 13z\\\",d),close:(d=16)=>v(\\\"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\\\",d),starFilled:(d=20)=>v(\\\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\\\",d)};var Q=(d,p,h,k,T,z=1)=>{for(let[$,N]of[[1,1],[2.76,.18],[5.4,.06]]){let A=d.createOscillator(),D=d.createGain();A.type=\\\"sine\\\",A.frequency.value=k*$,D.gain.setValueAtTime(0,h),D.gain.linearRampToValueAtTime(.32*N*z,h+.006),D.gain.exponentialRampToValueAtTime(1e-4,h+T/$**.35),A.connect(D).connect(p),A.start(h),A.stop(h+T+.05)}},Ge=(d,p,h,k,T)=>{let z=d.createOscillator(),$=d.createBiquadFilter(),N=d.createGain();z.type=\\\"triangle\\\",z.frequency.value=k,$.type=\\\"lowpass\\\",$.frequency.setValueAtTime(k*6,h),$.frequency.exponentialRampToValueAtTime(k*1.5,h+T),N.gain.setValueAtTime(0,h),N.gain.linearRampToValueAtTime(.42,h+.004),N.gain.exponentialRampToValueAtTime(1e-4,h+T),z.connect($).connect(N).connect(p),z.start(h),z.stop(h+T+.05)},sa={sms:(d,p,h)=>{Q(d,p,h,1318.5,.5),Q(d,p,h+.12,1661.2,.5),Q(d,p,h+.24,1975.5,.8)},\\\"push-ios\\\":(d,p,h)=>{Q(d,p,h,1760,.35,.8),Q(d,p,h+.09,2349.3,.9,.9)},\\\"push-android\\\":(d,p,h)=>{Ge(d,p,h,1046.5,.22),Ge(d,p,h+.1,1568,.22),Ge(d,p,h+.2,2093,.45)},email:(d,p,h)=>{Q(d,p,h,987.8,.45,.7),Q(d,p,h+.16,1318.5,.9,.7)}},oa={sms:[180,90,180],\\\"push-ios\\\":[120],\\\"push-android\\\":[60,80,60]},zt=(d=!1)=>{let p=null,h=null,k=new Map,T=()=>{if(p)return p;let $=globalThis.AudioContext??globalThis.webkitAudioContext;if(!$)return null;try{p=new $,h=p.createGain(),h.gain.value=.6,h.connect(p.destination)}catch{p=null}return p},z={enabled:d,unlock(){if(!z.enabled)return;let $=T();$?.state===\\\"suspended\\\"&&$.resume().catch(()=>{})},play($){if(!z.enabled)return;let N=Date.now();if(N-(k.get($)??0)<600)return;k.set($,N);let A=oa[$];if(A)try{navigator.vibrate?.(A)}catch{}let D=T();!D||!h||(D.state===\\\"suspended\\\"&&D.resume().catch(()=>{}),sa[$](D,h,D.currentTime+.02))},close(){p?.close().catch(()=>{}),p=null}};return z};var Ke=(d,p)=>{let h=d.replace(/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g,\\\"\\\"),k=\\\"\\\",T=0;for(;T<h.length;){let z=h.indexOf(\\\"{\\\",T);if(z<0)break;let $=h.slice(T,z).trim(),N=1,A=z+1;for(;A<h.length&&N>0;)h[A]===\\\"{\\\"?N++:h[A]===\\\"}\\\"&&N--,A++;let D=h.slice(z+1,A-1);/^@(media|container|supports|layer)\\\\b/.test($)?k+=`${$} {\\n${Ke(D,p)}}\\n`:$.startsWith(\\\"@\\\")?k+=`${$} {${D}}\\n`:k+=`${na($,p)} {${D}}\\n`,T=A}return k},na=(d,p)=>ra(d).map(h=>{let k=h.trim();return k===\\\":root\\\"||k===\\\"html\\\"||k===\\\"body\\\"?p:k.startsWith(\\\":root\\\")?`${p}${k.slice(5)}`:k.startsWith(\\\"&\\\")?`${p}${k.slice(1)}`:`${p} ${k}`}).join(\\\", \\\"),ra=d=>{let p=[],h=0,k=0;for(let T=0;T<d.length;T++){let z=d[T];z===\\\"(\\\"?h++:z===\\\")\\\"?h--:z===\\\",\\\"&&h===0&&(p.push(d.slice(k,T)),k=T+1)}return p.push(d.slice(k)),p};var Te=\\\"mb-notifications\\\",la=`\\n:root {\\n --bg: #0e1015; --panel: #161920; --panel-2: #1d212a; --line: #2a2f3a; --text: #e8eaf0;\\n --muted: #9aa1b1; --accent: #0a84ff; --ok: #30d158; --bad: #ff453a; --warn: #ffd60a;\\n --ios: -apple-system, BlinkMacSystemFont, \\\"SF Pro Text\\\", \\\"SF Pro Display\\\", \\\"Helvetica Neue\\\", Helvetica, Arial, sans-serif;\\n --android: \\\"Google Sans Text\\\", \\\"Google Sans\\\", Roboto, \\\"Segoe UI\\\", system-ui, sans-serif;\\n --mail: \\\"Google Sans\\\", Roboto, RobotoDraft, Helvetica, Arial, sans-serif;\\n --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\\n}\\n:root { display: block; position: relative; box-sizing: border-box; min-height: 100%; background: var(--bg); color: var(--text);\\n font: 14px/1.4 system-ui, -apple-system, \\\"Segoe UI\\\", Roboto, sans-serif; -webkit-tap-highlight-color: transparent; }\\n*, *::before, *::after { box-sizing: border-box; }\\nbutton, input, select { font: inherit; color: inherit; }\\nbutton { cursor: pointer; }\\n[hidden] { display: none !important; }\\n&[data-motion=\\\"reduce\\\"] *, &[data-motion=\\\"reduce\\\"] *::before, &[data-motion=\\\"reduce\\\"] *::after { animation: none !important; transition: none !important; }\\n&.embedded { height: 100%; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\\n&.embedded .mbn-scroll { flex: 1; min-height: 0; overflow: auto; }\\n&.embedded .inspector { position: absolute; }\\n[data-gesture]:focus-visible, [role=\\\"button\\\"]:focus-visible, .icon-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\\n.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\\n\\n/* \\\\u2500\\\\u2500 Harness chrome \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.topbar { position: sticky; top: 0; z-index: 20; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;\\n padding: 10px 18px; background: rgba(14,16,21,.86); backdrop-filter: blur(14px); border-bottom: 1px solid var(--line); }\\n.brand { display: flex; align-items: center; gap: 10px; font-weight: 650; letter-spacing: -.01em; margin-right: 6px; }\\n.brand-mark { width: 26px; height: 26px; border-radius: 7px; background: linear-gradient(135deg,#0a84ff,#5e5ce6); display: grid; place-items: center; }\\n.brand small { color: var(--muted); font-weight: 500; }\\n.field { display: flex; align-items: center; gap: 6px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px; padding: 0 8px; height: 32px; }\\n.field label { color: var(--muted); font-size: 12px; }\\n.field select, .field input { background: transparent; border: 0; outline: 0; height: 30px; min-width: 0; }\\n.field select option { background: var(--panel-2); }\\n.field.search { flex: 1 1 220px; max-width: 360px; }\\n.field.search input { width: 100%; }\\n.tabs { display: flex; background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px; padding: 2px; }\\n.tabs button { background: none; border: 0; padding: 5px 12px; border-radius: 6px; color: var(--muted); font-weight: 550; }\\n.tabs button[aria-pressed=\\\"true\\\"] { background: #2c3240; color: var(--text); }\\n.toggle { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; user-select: none; }\\n.toggle input { accent-color: var(--accent); }\\n.sources { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }\\n.pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line); background: var(--panel); font-size: 12px; color: var(--muted); white-space: nowrap; }\\n.pill b { color: var(--text); font-weight: 600; }\\n.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); }\\n.dot.ok { background: var(--ok); box-shadow: 0 0 0 3px rgba(48,209,88,.15); }\\n.dot.bad { background: var(--bad); box-shadow: 0 0 0 3px rgba(255,69,58,.15); }\\n.live { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }\\n.notice { margin: 14px 18px 0; padding: 10px 14px; border: 1px solid #5a2b2b; background: #2a1517; color: #ffb4ab; border-radius: 10px; font-size: 13px; }\\n\\n.devices { display: flex; flex-wrap: wrap; gap: 28px; padding: 22px 18px 40px; align-items: flex-start; justify-content: center; }\\n.devices.solo .device-col.wide { max-width: 1280px; }\\n.device-col { display: flex; flex-direction: column; gap: 12px; align-items: center; width: 362px; flex: none; }\\n.device-col.wide { flex: 1 1 720px; width: auto; min-width: 0; max-width: 1180px; align-items: stretch; }\\n.device-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; width: 100%; justify-content: space-between; min-height: 32px; }\\n.device-head .controls { display: flex; gap: 6px; align-items: center; min-width: 0; }\\n.device-head h2 { margin: 0; font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 650; display: flex; align-items: center; gap: 8px; }\\n.device-head h2 .count { background: var(--accent); color: #fff; border-radius: 999px; padding: 0 7px; font-size: 11px; letter-spacing: 0; line-height: 18px; }\\n.device-head .field { height: 30px; max-width: 250px; min-width: 0; }\\n.device-head .field select { max-width: 190px; text-overflow: ellipsis; }\\n.seg { display: flex; background: var(--panel-2); border: 1px solid var(--line); border-radius: 7px; padding: 2px; }\\n.seg button { border: 0; background: none; color: var(--muted); padding: 2px 9px; border-radius: 5px; font-size: 12px; }\\n.seg button[aria-pressed=\\\"true\\\"] { background: #2c3240; color: var(--text); }\\n\\n/* \\\\u2500\\\\u2500 Phone hardware \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.iphone { position: relative; width: 362px; height: 760px; border-radius: 58px; padding: 12px; background: #0b0b0c;\\n box-shadow: 0 0 0 2px #3a3a3c, 0 0 0 6px #1c1c1e, 0 0 0 7px #4a4a4e, 0 40px 80px rgba(0,0,0,.55); }\\n.iphone::before, .iphone::after { content: \\\"\\\"; position: absolute; left: -9px; width: 4px; border-radius: 2px; background: #2c2c2e; }\\n.iphone::before { top: 150px; height: 60px; }\\n.iphone::after { top: 225px; height: 60px; }\\n.iphone .screen { position: relative; width: 100%; height: 100%; border-radius: 47px; overflow: hidden; background: #fff; font-family: var(--ios); color: #000; -webkit-font-smoothing: antialiased; }\\n.island { position: absolute; z-index: 30; top: 11px; left: 50%; transform: translateX(-50%); width: 112px; height: 33px; border-radius: 20px; background: #000; }\\n.statusbar { position: absolute; z-index: 25; top: 0; left: 0; right: 0; height: 54px; display: flex; align-items: center; justify-content: space-between; padding: 6px 32px 0 40px; font: 600 16px/1 var(--ios); letter-spacing: -.01em; }\\n.statusbar .icons { display: flex; gap: 6px; align-items: center; }\\n.statusbar.light { color: #fff; }\\n.home-indicator { position: absolute; z-index: 30; bottom: 8px; left: 50%; transform: translateX(-50%); width: 134px; height: 5px; border-radius: 3px; background: #000; }\\n.home-indicator.light { background: rgba(255,255,255,.9); }\\n\\n.pixel { position: relative; width: 352px; height: 760px; border-radius: 44px; padding: 10px; background: #111;\\n box-shadow: 0 0 0 2px #2b2b2f, 0 0 0 5px #3c3c41, 0 40px 80px rgba(0,0,0,.55); }\\n.pixel::after { content: \\\"\\\"; position: absolute; right: -7px; top: 170px; width: 4px; height: 90px; border-radius: 2px; background: #2c2c2e; }\\n.pixel .screen { position: relative; width: 100%; height: 100%; border-radius: 35px; overflow: hidden; font-family: var(--android); }\\n.punch { position: absolute; z-index: 30; top: 12px; left: 50%; width: 13px; height: 13px; margin-left: -6px; border-radius: 50%; background: #050505; box-shadow: inset 0 0 0 2px #1a1a1a; }\\n\\n/* \\\\u2500\\\\u2500 Messages (iOS) \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.msgs { position: absolute; inset: 0; display: flex; flex-direction: column; background: #fff; }\\n.msgs-nav { padding: 54px 16px 0; }\\n.msgs-nav .row { display: flex; justify-content: space-between; align-items: center; height: 44px; color: #007aff; font-size: 17px; }\\n.msgs-nav h1 { margin: 2px 0 8px; font: 700 34px/41px var(--ios); letter-spacing: .01em; }\\n.ios-search { display: flex; align-items: center; gap: 6px; height: 36px; border-radius: 10px; background: rgba(118,118,128,.12); color: rgba(60,60,67,.6); padding: 0 8px; font-size: 17px; margin-bottom: 8px; }\\n.ios-search span { flex: 1; }\\n.threads { flex: 1; overflow-y: auto; }\\n.thread { position: relative; display: flex; gap: 12px; padding: 10px 16px 0 26px; cursor: pointer; }\\n.thread:active { background: #e5e5ea; }\\n.thread .unread { position: absolute; left: 8px; top: 30px; width: 10px; height: 10px; border-radius: 50%; background: #007aff; }\\n.avatar { flex: none; width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; color: #fff; font: 600 18px var(--ios); background: linear-gradient(180deg,#a5abb8,#858994); }\\n.thread .text { flex: 1; min-width: 0; border-bottom: .5px solid #c6c6c8; padding-bottom: 10px; }\\n.thread .top { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }\\n.thread .name { font: 600 17px/22px var(--ios); letter-spacing: -.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.thread .when { flex: none; color: rgba(60,60,67,.6); font-size: 15px; display: flex; align-items: center; gap: 6px; }\\n.thread .preview { color: rgba(60,60,67,.6); font-size: 15px; line-height: 20px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; letter-spacing: -.01em; }\\n.empty-ios { flex: 1; display: grid; place-items: center; color: rgba(60,60,67,.6); font-size: 17px; text-align: center; padding: 40px; }\\n\\n.convo { position: absolute; inset: 0; display: flex; flex-direction: column; background: #fff; }\\n.convo-nav { position: relative; z-index: 5; padding-top: 50px; background: rgba(249,249,249,.94); backdrop-filter: blur(20px); border-bottom: .5px solid rgba(0,0,0,.18); }\\n.convo-nav .bar { position: relative; height: 96px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; }\\n.convo-nav .back { position: absolute; left: 8px; top: 8px; display: flex; align-items: center; color: #007aff; font-size: 17px; background: none; border: 0; padding: 4px; }\\n.convo-nav .back .badge { background: #007aff; color: #fff; border-radius: 10px; font-size: 13px; min-width: 20px; padding: 0 6px; line-height: 20px; margin-left: 2px; }\\n.convo-nav .avatar { width: 54px; height: 54px; font-size: 22px; }\\n.convo-nav .who { font-size: 12px; display: flex; align-items: center; gap: 2px; }\\n.convo-body { flex: 1; overflow-y: auto; padding: 8px 0 12px; }\\n.stamp { text-align: center; color: rgba(60,60,67,.6); font-size: 12px; margin: 14px 0 6px; }\\n.stamp b { font-weight: 600; }\\n.bubble-row { display: flex; padding: 0 14px; margin-top: 2px; }\\n.bubble-row.gap { margin-top: 10px; }\\n.bubble { position: relative; max-width: 74%; padding: 7px 12px 8px; border-radius: 18px; background: #e9e9eb; color: #000; font-size: 17px; line-height: 22px; letter-spacing: -.02em; white-space: pre-wrap; overflow-wrap: anywhere; }\\n.bubble.tail::before { content: \\\"\\\"; position: absolute; bottom: 0; left: -7px; width: 20px; height: 20px; background: #e9e9eb; border-bottom-right-radius: 15px; }\\n.bubble.tail::after { content: \\\"\\\"; position: absolute; bottom: 0; left: -10px; width: 10px; height: 20px; background: #fff; border-bottom-right-radius: 10px; }\\n.bubble a, .bubble .code { color: inherit; text-decoration: underline; text-underline-offset: 2px; }\\n.bubble .media { display: block; max-width: 100%; border-radius: 12px; margin: 2px 0 4px; }\\n.bubble.arrive { animation: mbn-pop .35s cubic-bezier(.2,.9,.3,1.3); }\\n.delivered-note { padding: 2px 16px 0 26px; color: rgba(60,60,67,.6); font-size: 11px; }\\n.convo-input { display: flex; align-items: flex-end; gap: 8px; padding: 6px 10px 32px; background: #fff; }\\n.convo-input .plus { width: 34px; height: 34px; border-radius: 50%; background: #e9e9eb; display: grid; place-items: center; flex: none; }\\n.convo-input .field-ios { flex: 1; height: 36px; border: 1px solid #c6c6c8; border-radius: 18px; display: flex; align-items: center; justify-content: space-between; padding: 0 6px 0 14px; color: #c4c4c6; font-size: 17px; }\\n.qt { margin: 0 10px 6px; padding: 8px 12px; border-radius: 10px; background: #d1d3d9; text-align: center; font-size: 15px; color: #000; }\\n.qt small { display: block; font-size: 12px; color: #3c3c43; }\\n\\n/* \\\\u2500\\\\u2500 Lock screen (iOS) \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.lock { position: absolute; inset: 0; color: #fff; overflow: hidden;\\n background: radial-gradient(120% 70% at 20% 10%, #6f86ff 0%, transparent 55%), radial-gradient(90% 60% at 90% 30%, #ff7eb3 0%, transparent 60%), radial-gradient(120% 80% at 50% 100%, #1d1b4a 0%, transparent 70%), linear-gradient(180deg,#3a3f9f,#141433); }\\n.lock .padlock { position: absolute; top: 56px; left: 50%; transform: translateX(-50%); opacity: .95; }\\n.lock .date { position: absolute; top: 84px; width: 100%; text-align: center; font: 600 19px var(--ios); letter-spacing: .01em; opacity: .92; }\\n.lock .clock { position: absolute; top: 102px; width: 100%; text-align: center; font: 700 92px/1 \\\"SF Pro Rounded\\\", var(--ios); letter-spacing: -.02em; color: rgba(255,255,255,.93); }\\n.lock-stack { position: absolute; left: 10px; right: 10px; top: 236px; bottom: 112px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; scrollbar-width: none; }\\n.lock-stack::-webkit-scrollbar { display: none; }\\n.lock-stack .center-label { text-align: center; font: 600 15px var(--ios); opacity: .85; padding: 4px 0; }\\n.ios-note { position: relative; display: flex; gap: 10px; padding: 11px 12px 12px 11px; border-radius: 22px; color: #000; background: rgba(246,246,246,.66); backdrop-filter: blur(28px) saturate(180%); -webkit-backdrop-filter: blur(28px) saturate(180%); cursor: pointer; box-shadow: 0 1px 0 rgba(255,255,255,.25) inset; }\\n.ios-note.arrive { animation: mbn-drop .45s cubic-bezier(.2,.9,.3,1.15); }\\n.ios-note .app-icon { flex: none; width: 38px; height: 38px; border-radius: 9px; display: grid; place-items: center; color: #fff; font: 700 18px var(--ios); box-shadow: 0 0 0 .5px rgba(0,0,0,.08); }\\n.ios-note .content { flex: 1; min-width: 0; }\\n.ios-note .line1 { display: flex; justify-content: space-between; gap: 8px; }\\n.ios-note .title { font: 600 15px/20px var(--ios); letter-spacing: -.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ios-note .time { flex: none; font-size: 13px; color: rgba(60,60,67,.62); }\\n.ios-note .body { font: 400 15px/20px var(--ios); letter-spacing: -.02em; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }\\n.ios-note .thumb { flex: none; width: 38px; height: 38px; border-radius: 7px; object-fit: cover; align-self: center; }\\n.ios-note.expanded .body { -webkit-line-clamp: unset; }\\n.ios-note .hero { width: 100%; border-radius: 12px; margin-top: 8px; display: block; }\\n.note-data { margin-top: 8px; font: 12px/1.45 var(--mono); background: rgba(255,255,255,.55); border-radius: 10px; padding: 8px 10px; white-space: pre-wrap; overflow-wrap: anywhere; color: #1c1c1e; }\\n.note-meta { margin-top: 6px; font-size: 12px; color: rgba(60,60,67,.7); }\\n.ios-stack-more { position: relative; height: 18px; margin: -14px 14px 0; border-radius: 0 0 18px 18px; background: rgba(246,246,246,.42); backdrop-filter: blur(20px); }\\n.ios-stack-more + .ios-stack-more { margin: -10px 26px 0; background: rgba(246,246,246,.28); }\\n.lock-buttons { position: absolute; bottom: 46px; left: 46px; right: 46px; display: flex; justify-content: space-between; }\\n.lock-buttons span { width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center; background: rgba(0,0,0,.28); backdrop-filter: blur(20px); }\\n.lock-empty { text-align: center; font: 500 15px var(--ios); opacity: .7; margin-top: 30px; }\\n\\n/* \\\\u2500\\\\u2500 Notification shade (Android) \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.shade { position: absolute; inset: 0; color: #e6e1e5; background: linear-gradient(180deg, rgba(20,18,24,.94), rgba(20,18,24,.98)), radial-gradient(100% 60% at 30% 0%, #4b3f72, #141218); overflow: hidden; }\\n.shade .sb { position: absolute; top: 0; left: 0; right: 0; height: 40px; display: flex; align-items: center; justify-content: space-between; padding: 6px 24px 0; font: 500 14px var(--android); color: #e6e1e5; }\\n.shade .sb .icons { display: flex; gap: 5px; align-items: center; }\\n.shade .qs-head { position: absolute; top: 46px; left: 22px; right: 22px; display: flex; justify-content: space-between; align-items: center; font: 400 15px var(--android); color: #cac4d0; }\\n.qs { position: absolute; top: 80px; left: 14px; right: 14px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }\\n.qs .tile { height: 60px; border-radius: 20px; background: #36343b; display: flex; align-items: center; gap: 10px; padding: 0 14px; font: 500 14px var(--android); color: #e6e1e5; min-width: 0; }\\n.qs .tile > div { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.qs .tile svg { flex: none; }\\n.qs .tile.on { background: #d0bcff; color: #381e72; }\\n.qs .tile small { display: block; font-weight: 400; font-size: 12px; opacity: .8; }\\n.qs-bright { position: absolute; top: 216px; left: 14px; right: 14px; height: 44px; border-radius: 22px; background: #36343b; overflow: hidden; }\\n.qs-bright::before { content: \\\"\\\"; position: absolute; inset: 0 44% 0 0; background: #d0bcff; border-radius: 22px; }\\n.shade-list { position: absolute; top: 276px; left: 10px; right: 10px; bottom: 92px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; scrollbar-width: none; }\\n.shade-list::-webkit-scrollbar { display: none; }\\n.a-note { background: #2b2930; border-radius: 6px; padding: 14px 16px 14px 14px; cursor: pointer; display: flex; gap: 12px; }\\n.a-note:first-child { border-top-left-radius: 26px; border-top-right-radius: 26px; }\\n.a-note:last-child { border-bottom-left-radius: 26px; border-bottom-right-radius: 26px; }\\n.a-note.arrive { animation: mbn-headsup .5s cubic-bezier(.2,.9,.3,1.12); }\\n.a-note .a-icon { flex: none; width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; color: #fff; font: 600 15px var(--android); }\\n.a-note .a-main { flex: 1; min-width: 0; }\\n.a-note .a-head { display: flex; align-items: center; gap: 6px; font: 400 12px var(--android); color: #cac4d0; }\\n.a-note .a-head .chev { margin-left: auto; width: 26px; height: 20px; border-radius: 10px; background: #49454f; display: grid; place-items: center; }\\n.a-note .a-title { font: 500 15px/20px var(--android); color: #e6e1e5; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.a-note .a-body { font: 400 14px/20px var(--android); color: #cac4d0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }\\n.a-note.expanded .a-body { -webkit-line-clamp: unset; }\\n.a-note .large-icon { flex: none; width: 40px; height: 40px; border-radius: 8px; object-fit: cover; align-self: center; }\\n.a-note .big-picture { display: block; width: 100%; border-radius: 14px; margin-top: 10px; }\\n.a-note .note-data { background: #1d1b20; color: #e6e1e5; }\\n.a-note .note-meta { color: #938f99; }\\n.shade-actions { position: absolute; bottom: 44px; left: 14px; right: 14px; display: flex; justify-content: space-between; }\\n.shade-actions span { padding: 8px 16px; border-radius: 18px; background: #36343b; font: 500 14px var(--android); color: #e6e1e5; }\\n.shade-empty { text-align: center; color: #938f99; font: 400 14px var(--android); margin-top: 26px; }\\n.gesture { position: absolute; bottom: 12px; left: 50%; width: 110px; height: 4px; margin-left: -55px; border-radius: 2px; background: rgba(255,255,255,.75); }\\n\\n/* \\\\u2500\\\\u2500 Mail (web client) \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.window { position: relative; container-type: inline-size; border-radius: 12px; overflow: hidden; background: #f8fafd; box-shadow: 0 0 0 1px #2c313c, 0 30px 70px rgba(0,0,0,.5); height: 760px; display: flex; flex-direction: column; font-family: var(--mail); color: #1f1f1f; }\\n.chrome { flex: none; height: 38px; background: #dfe3e9; display: flex; align-items: center; gap: 12px; padding: 0 12px; }\\n.lights { display: flex; gap: 7px; }\\n.lights i { width: 12px; height: 12px; border-radius: 50%; display: block; }\\n.lights i:nth-child(1) { background: #ff5f57; } .lights i:nth-child(2) { background: #febc2e; } .lights i:nth-child(3) { background: #28c840; }\\n.omnibox { flex: 1; max-width: 560px; margin: 0 auto; height: 26px; border-radius: 13px; background: #fff; display: flex; align-items: center; gap: 8px; padding: 0 12px; color: #5f6368; font: 13px system-ui; }\\n.mail-top { flex: none; height: 64px; display: flex; align-items: center; gap: 8px; padding: 8px 16px 8px 12px; }\\n.icon-btn { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; color: #444746; border: 0; background: none; flex: none; }\\n.icon-btn:hover { background: rgba(68,71,70,.08); }\\n.mail-logo { display: flex; align-items: center; gap: 6px; width: 194px; font: 400 22px var(--mail); color: #444746; letter-spacing: -.01em; }\\n.mail-search { flex: 1; min-width: 0; max-width: 720px; height: 48px; border-radius: 24px; background: #e9eef6; display: flex; align-items: center; gap: 4px; padding: 0 4px; color: #444746; font-size: 16px; }\\n.mail-search .placeholder { flex: 1; padding-left: 4px; }\\n.mail-top .right { margin-left: auto; display: flex; align-items: center; gap: 2px; }\\n.mail-avatar { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; color: #fff; font: 500 15px var(--mail); margin-left: 8px; }\\n.mail-body { flex: 1; min-height: 0; display: flex; }\\n.mail-nav { flex: none; width: 236px; padding: 8px 8px 0 0; overflow: hidden; }\\n.compose { display: inline-flex; align-items: center; gap: 12px; height: 56px; padding: 0 22px 0 16px; margin: 0 0 16px 8px; border-radius: 16px; background: #c2e7ff; color: #001d35; font: 500 14px var(--mail); border: 0; box-shadow: none; }\\n.nav-item { display: flex; align-items: center; gap: 18px; height: 32px; padding: 0 12px 0 26px; border-radius: 0 16px 16px 0; color: #202124; font: 400 14px var(--mail); }\\n.nav-item.active { background: #d3e3fd; font-weight: 700; color: #001d35; }\\n.nav-item .n { margin-left: auto; font-size: 12px; }\\n.mail-main { flex: 1; min-width: 0; margin: 0 16px 16px 0; background: #fff; border-radius: 16px; display: flex; flex-direction: column; overflow: hidden; }\\n.mail-toolbar { flex: none; height: 48px; display: flex; align-items: center; gap: 4px; padding: 0 12px 0 14px; color: #444746; }\\n.mail-toolbar .range { margin-left: auto; font-size: 12px; color: #444746; }\\n.cat-tabs { flex: none; display: flex; border-bottom: 1px solid #f1f3f4; }\\n.cat-tabs div { flex: 0 1 250px; min-width: 0; height: 54px; display: flex; align-items: center; gap: 16px; padding: 0 16px; color: #444746; font: 500 14px var(--mail); position: relative; }\\n.cat-tabs div.on { color: #0b57d0; }\\n.cat-tabs div.on::after { content: \\\"\\\"; position: absolute; left: 8px; right: 8px; bottom: 0; height: 3px; border-radius: 3px 3px 0 0; background: #0b57d0; }\\n.mail-list { flex: 1; overflow-y: auto; }\\n.mrow { display: flex; align-items: center; height: 40px; padding: 0 16px 0 12px; border-bottom: 1px solid #f1f3f4; cursor: pointer; font-size: 14px; color: #202124; background: #f2f6fc; }\\n.mrow.unread { background: #fff; font-weight: 700; }\\n.mrow:hover { box-shadow: inset 1px 0 0 #dadce0, inset -1px 0 0 #dadce0, 0 1px 2px 0 rgba(60,64,67,.3), 0 1px 3px 1px rgba(60,64,67,.15); position: relative; z-index: 1; }\\n.mrow.arrive { animation: mbn-rowflash 1.6s ease-out; }\\n.mrow .chk, .mrow .star { flex: none; width: 20px; height: 20px; margin-right: 10px; color: #c4c7c5; display: grid; place-items: center; }\\n.mrow .from { flex: none; width: 168px; padding-right: 24px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.mrow .subj { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.mrow .snippet { color: #5f6368; font-weight: 400; }\\n.mrow .clip { color: #5f6368; margin-left: 8px; flex: none; }\\n.mrow .date { flex: none; width: 78px; text-align: right; font-size: 12px; }\\n.mrow .svc { flex: none; font: 500 10px var(--mail); color: #5f6368; border: 1px solid #dadce0; border-radius: 4px; padding: 0 4px; margin-left: 8px; font-weight: 500; text-transform: uppercase; letter-spacing: .03em; }\\n.mail-empty { padding: 60px 20px; text-align: center; color: #5f6368; font: 400 14px var(--mail); }\\n.mail-empty b { display: block; font: 400 22px var(--mail); color: #1f1f1f; margin: 12px 0 4px; }\\n.reader { flex: 1; overflow-y: auto; padding: 0 0 24px; }\\n.reader .subject-row { display: flex; align-items: center; gap: 10px; padding: 18px 16px 8px 72px; }\\n.reader h1 { margin: 0; font: 400 22px/28px var(--mail); color: #1f1f1f; }\\n.label-chip { font: 400 12px var(--mail); background: #ddd; border-radius: 4px; padding: 0 6px; color: #444746; display: inline-flex; gap: 4px; align-items: center; }\\n.sender-row { display: flex; gap: 14px; padding: 12px 16px 0 16px; }\\n.sender-row .mail-avatar { width: 40px; height: 40px; font-size: 18px; margin: 0; }\\n.sender-row .who { flex: 1; min-width: 0; }\\n.sender-row .who b { font: 700 14px var(--mail); color: #1f1f1f; }\\n.sender-row .who .addr { font: 400 12px var(--mail); color: #5e5e5e; }\\n.sender-row .who .to { font: 400 12px var(--mail); color: #5e5e5e; display: flex; align-items: center; gap: 2px; margin-top: 2px; }\\n.sender-row .meta { display: flex; align-items: center; gap: 4px; color: #5e5e5e; font: 400 12px var(--mail); white-space: nowrap; }\\n.details { margin: 8px 16px 0 70px; padding: 10px 14px; border: 1px solid #dadce0; border-radius: 8px; font: 12px/1.6 var(--mail); color: #5e5e5e; display: grid; grid-template-columns: max-content 1fr; gap: 0 12px; }\\n.details span:nth-child(odd) { text-align: right; }\\n.details span:nth-child(even) { color: #1f1f1f; overflow-wrap: anywhere; }\\n.mail-frame { display: block; width: calc(100% - 86px); margin: 16px 16px 0 70px; border: 0; min-height: 120px; background: #fff; }\\n.mail-text { margin: 16px 16px 0 70px; white-space: pre-wrap; font: 400 14px/1.55 Arial, sans-serif; color: #222; overflow-wrap: anywhere; }\\n.mail-text a { color: #1155cc; }\\n.attachments { margin: 18px 16px 0 70px; border-top: 1px solid #e0e0e0; padding-top: 14px; }\\n.attachments h3 { margin: 0 0 10px; font: 500 14px var(--mail); color: #1f1f1f; }\\n.att-grid { display: flex; flex-wrap: wrap; gap: 12px; }\\n.att { width: 180px; height: 104px; border: 1px solid #dadce0; border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }\\n.att .att-top { flex: 1; background: #f1f3f4; display: grid; place-items: center; color: #d93025; }\\n.att .att-name { height: 36px; display: flex; align-items: center; gap: 8px; padding: 0 10px; font: 500 12px var(--mail); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.reply-row { display: flex; gap: 10px; margin: 24px 16px 0 70px; }\\n.reply-row span { display: inline-flex; align-items: center; gap: 8px; padding: 0 22px 0 16px; height: 36px; border: 1px solid #747775; border-radius: 18px; font: 500 14px var(--mail); color: #444746; }\\n\\n/* \\\\u2500\\\\u2500 Timeline + inspector \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.timeline { padding: 18px; overflow-x: auto; }\\n.tl td.mono:first-child { white-space: nowrap; }\\n.tl { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }\\n.tl th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 600; padding: 10px 12px; background: var(--panel-2); border-bottom: 1px solid var(--line); }\\n.tl td { padding: 9px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }\\n.tl tr:last-child td { border-bottom: 0; }\\n.tl tbody tr { cursor: pointer; }\\n.tl tbody tr:hover { background: #1b1f28; }\\n.tl .content { max-width: 520px; color: var(--muted); }\\n.tl .content b { color: var(--text); font-weight: 600; }\\n.tl .mono { font-family: var(--mono); font-size: 12px; }\\n.chan { display: inline-flex; align-items: center; gap: 6px; padding: 2px 8px; border-radius: 6px; font-size: 12px; font-weight: 600; }\\n.chan.sms { background: rgba(48,209,88,.14); color: #6ee38a; }\\n.chan.email { background: rgba(10,132,255,.16); color: #69b0ff; }\\n.chan.push { background: rgba(255,159,10,.15); color: #ffc15e; }\\n.svc-tag { font-size: 12px; color: var(--muted); }\\n.empty-tl { padding: 60px; text-align: center; color: var(--muted); }\\n.inspector { position: fixed; z-index: 40; top: 0; right: 0; bottom: 0; width: min(560px, 100vw); background: var(--panel); border-left: 1px solid var(--line); box-shadow: -20px 0 50px rgba(0,0,0,.4); display: flex; flex-direction: column; }\\n.inspector header { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line); }\\n.inspector header h3 { margin: 0; font-size: 15px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.inspector .btn { background: var(--panel-2); border: 1px solid var(--line); border-radius: 7px; padding: 4px 10px; font-size: 13px; }\\n.inspector pre { margin: 0; flex: 1; overflow: auto; padding: 14px 16px; font: 12px/1.55 var(--mono); color: #cdd3df; white-space: pre-wrap; overflow-wrap: anywhere; }\\n.inspector .kv { display: grid; grid-template-columns: 110px 1fr; gap: 6px 12px; padding: 14px 16px; border-bottom: 1px solid var(--line); font-size: 13px; }\\n.inspector .kv span:nth-child(odd) { color: var(--muted); }\\n.inspector .kv span:nth-child(even) { overflow-wrap: anywhere; font-family: var(--mono); font-size: 12px; }\\n\\n\\n/* \\\\u2500\\\\u2500 Sound toggle \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.icon-toggle { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel-2); color: var(--muted); font-size: 13px; }\\n.icon-toggle[aria-pressed=\\\"true\\\"] { color: var(--text); border-color: #3d4a66; }\\n\\n/* \\\\u2500\\\\u2500 Swipe gestures \\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500\\\\u2500 */\\n.swipe { position: relative; touch-action: pan-y; }\\n.swipe > .swipe-card { position: relative; z-index: 1; will-change: transform; }\\n.swipe.settling > .swipe-card, .settling.a-note { transition: transform .32s cubic-bezier(.2,.9,.25,1), opacity .32s ease; }\\n.swipe-actions { position: absolute; inset: 0; display: flex; justify-content: flex-end; align-items: stretch; visibility: hidden; }\\n.swipe.swiping > .swipe-actions, .swipe.open > .swipe-actions { visibility: visible; }\\n.collapsing { overflow: hidden; transition: height .26s ease, margin .26s ease, padding .26s ease, opacity .2s ease !important; }\\n\\n/* iOS lock screen: Options / Clear behind a card */\\n.ios-swipe .swipe-actions { gap: 8px; }\\n.ios-swipe .swipe-actions button { width: 72px; border: 0; border-radius: 20px; background: rgba(246,246,246,.6); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); color: #000; font: 500 14px var(--ios); }\\n.push-group { display: flex; flex-direction: column; gap: 8px; }\\n.group-head { display: flex; align-items: center; gap: 8px; padding: 0 2px; animation: mbn-fadein .25s ease; }\\n.group-head h3 { flex: 1; margin: 0; font: 700 20px/1.2 var(--ios); color: #fff; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.group-head button { border: 0; border-radius: 15px; background: rgba(246,246,246,.6); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); color: #000; font: 500 13px var(--ios); padding: 6px 12px; }\\n.group-head button.x { width: 30px; height: 30px; padding: 0; display: grid; place-items: center; border-radius: 50%; }\\n.push-group[data-open=\\\"true\\\"] .ios-swipe { animation: mbn-unstack .38s cubic-bezier(.2,.9,.3,1.1) backwards; }\\n.push-group[data-open=\\\"true\\\"] .ios-swipe:nth-child(3) { animation-delay: .03s; } .push-group[data-open=\\\"true\\\"] .ios-swipe:nth-child(4) { animation-delay: .06s; }\\n.stack-layers { cursor: pointer; border: 0; padding: 0; background: none; display: block; width: 100%; }\\n.stack-layers .ios-stack-more:first-child { margin-top: -14px; }\\n.lock.wake { animation: mbn-wake 1.1s ease-out; }\\n.ios-overlay { position: absolute; inset: 0; z-index: 40; display: flex; flex-direction: column; justify-content: center; gap: 10px; padding: 0 14px; background: rgba(255,255,255,.28); backdrop-filter: blur(18px) saturate(140%); -webkit-backdrop-filter: blur(18px) saturate(140%); animation: mbn-fadein .2s ease; }\\n.ios-overlay.dark { background: rgba(0,0,0,.28); }\\n.ios-overlay .ios-note { animation: mbn-lift .3s cubic-bezier(.2,.9,.3,1.2); box-shadow: 0 20px 40px rgba(0,0,0,.25); }\\n.ios-menu { align-self: flex-start; width: 250px; border-radius: 14px; overflow: hidden; background: rgba(237,237,237,.86); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); box-shadow: 0 10px 40px rgba(0,0,0,.2); animation: mbn-lift .28s cubic-bezier(.2,.9,.3,1.2); }\\n.ios-menu button { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 11px 16px; border: 0; border-bottom: .5px solid rgba(60,60,67,.29); background: none; color: #000; font: 400 17px var(--ios); letter-spacing: -.02em; text-align: left; }\\n.ios-menu button:last-child { border-bottom: 0; }\\n.ios-menu button:active { background: rgba(0,0,0,.08); }\\n.ios-overlay.dark .ios-menu { align-self: stretch; width: auto; }\\n\\n/* Android shade */\\n.a-note { touch-action: pan-y; position: relative; }\\n.a-settings { margin-top: 8px; display: grid; gap: 8px; animation: mbn-fadein .2s ease; }\\n.a-settings .opt { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 16px; border: 1px solid #49454f; font: 500 14px var(--android); color: #e6e1e5; background: none; text-align: left; }\\n.a-settings .opt[aria-pressed=\\\"true\\\"] { background: #4a4458; border-color: #d0bcff; }\\n.a-settings .opt small { display: block; font-weight: 400; color: #cac4d0; font-size: 12px; }\\n.a-settings .row { display: flex; justify-content: space-between; }\\n.a-settings .row button { border: 0; background: none; color: #d0bcff; font: 500 14px var(--android); padding: 6px 4px; }\\n.shade-actions button { padding: 8px 16px; border: 0; border-radius: 18px; background: #36343b; font: 500 14px var(--android); color: #e6e1e5; }\\n\\n/* Messages: thread swipe actions, page transitions, bubble times, tapbacks */\\n.thread-swipe .swipe-actions { justify-content: space-between; }\\n.thread-swipe .swipe-actions .side { display: flex; }\\n.thread-swipe .swipe-actions button { width: 74px; border: 0; color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; font: 400 13px var(--ios); }\\n.act-unread { background: #007aff; } .act-pin { background: #ffcc00; } .act-mute { background: #5856d6; } .act-delete { background: #ff3b30; }\\n.thread-swipe .thread { background: #fff; }\\n.thread .name-line { display: flex; align-items: center; gap: 4px; min-width: 0; }\\n.thread .flag { flex: none; color: rgba(60,60,67,.6); display: inline-flex; }\\n.msgs.enter { animation: mbn-back .38s cubic-bezier(.2,.9,.25,1); }\\n.convo.enter { animation: mbn-push .4s cubic-bezier(.2,.9,.25,1); box-shadow: -10px 0 30px rgba(0,0,0,.12); }\\n.convo-body { --reveal: 0px; overflow-x: hidden; touch-action: pan-y; }\\n.convo-body .bubble-row, .convo-body .stamp { transform: translateX(calc(-1 * var(--reveal))); }\\n.convo-body.settling .bubble-row, .convo-body.settling .stamp { transition: transform .3s cubic-bezier(.2,.9,.25,1); }\\n.bubble-row { position: relative; }\\n.bubble-time { position: absolute; right: -66px; top: 50%; transform: translateY(-50%); width: 58px; color: rgba(60,60,67,.6); font-size: 12px; white-space: nowrap; }\\n.bubble { touch-action: pan-y; -webkit-user-select: text; user-select: text; }\\n.tapback { position: absolute; z-index: 2; top: -16px; right: -12px; min-width: 30px; height: 30px; padding: 0 4px; border-radius: 15px; background: #007aff; color: #fff; display: grid; place-items: center; font: 700 13px/1 var(--ios); box-shadow: 0 0 0 2.5px #fff; animation: mbn-pop .35s cubic-bezier(.2,.9,.3,1.4); }\\n.tapback-bar { align-self: flex-start; display: flex; gap: 4px; padding: 6px 8px; border-radius: 26px; background: rgba(233,233,235,.96); box-shadow: 0 8px 30px rgba(0,0,0,.18); animation: mbn-lift .28s cubic-bezier(.2,.9,.3,1.3); }\\n.tapback-bar button { width: 38px; height: 38px; border-radius: 50%; border: 0; background: none; color: #8e8e93; font: 700 16px/1 var(--ios); display: grid; place-items: center; }\\n.tapback-bar button[aria-pressed=\\\"true\\\"] { background: #007aff; color: #fff; }\\n.ios-overlay .bubble { align-self: flex-start; max-width: 80%; animation: mbn-lift .28s cubic-bezier(.2,.9,.3,1.2); }\\n\\n/* Mail: hover actions, row swipe, toast */\\n.mrow .hover-actions { display: none; flex: none; align-items: center; gap: 2px; margin-left: 8px; }\\n.mrow .hover-actions .icon-btn { width: 32px; height: 32px; }\\n.mrow:hover .hover-actions, .mrow:focus-within .hover-actions { display: flex; }\\n.mrow:hover .date, .mrow:focus-within .date { display: none; }\\n.mrow .star { cursor: pointer; }\\n.mrow .star[aria-pressed=\\\"true\\\"] { color: #f4b400; }\\n.mrow-swipe { background: #188038; }\\n.mrow-swipe .swipe-actions { justify-content: space-between; align-items: center; padding: 0 22px; color: #fff; }\\n.toast { position: absolute; z-index: 20; left: 24px; bottom: 24px; display: flex; align-items: center; gap: 24px; min-width: 288px; max-width: calc(100% - 48px); padding: 14px 16px 14px 24px; border-radius: 4px; background: #303030; color: #f2f2f2; font: 400 14px var(--mail); box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px rgba(0,0,0,.14); animation: mbn-toast .25s cubic-bezier(0,0,.2,1); }\\n.toast button { margin-left: auto; border: 0; background: none; color: #a8c7fa; font: 500 14px var(--mail); padding: 4px 8px; }\\n.reader.enter, .mail-list.enter { animation: mbn-fadein .18s ease; }\\n\\n@keyframes mbn-fadein { from { opacity: 0; } to { opacity: 1; } }\\n@keyframes mbn-headsup { from { opacity: 0; transform: translateY(-70px) scale(.98); } to { opacity: 1; transform: none; } }\\n@keyframes mbn-unstack { from { opacity: 0; transform: translateY(-40px) scale(.94); } to { opacity: 1; transform: none; } }\\n@keyframes mbn-wake { from { filter: brightness(.25); } to { filter: none; } }\\n@keyframes mbn-lift { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: none; } }\\n@keyframes mbn-push { from { transform: translateX(100%); } to { transform: none; } }\\n@keyframes mbn-back { from { transform: translateX(-28%); filter: brightness(.92); } to { transform: none; filter: none; } }\\n@keyframes mbn-toast { from { opacity: 0; transform: translateY(16px) scale(.96); } to { opacity: 1; transform: none; } }\\n@keyframes mbn-pop { from { transform: scale(.6) translateY(12px); opacity: 0; } to { transform: none; opacity: 1; } }\\n@keyframes mbn-drop { from { transform: translateY(-30px) scale(.96); opacity: 0; } to { transform: none; opacity: 1; } }\\n@keyframes mbn-fade { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }\\n@keyframes mbn-rowflash { from { background: #fef7e0; } to { background: #fff; } }\\n@container (max-width: 980px) { .mail-nav { width: 72px; } .mail-nav .lbl, .mail-nav .n, .compose .lbl { display: none; } .mail-logo { width: auto; } .compose { padding: 0 16px; } .mrow .svc { display: none; } }\\n@container (max-width: 640px) { .mail-nav, .mail-search, .cat-tabs, .mail-logo .lbl, .mail-toolbar .range { display: none; } .mail-main { margin-left: 8px; } .mrow .from { width: 110px; } .reader .subject-row, .sender-row { padding-left: 16px; } .mail-frame, .mail-text, .attachments, .reply-row, .details { margin-left: 16px; } .mail-frame { width: calc(100% - 32px); } .sender-row { flex-wrap: wrap; } .sender-row .who { flex-basis: calc(100% - 54px); } .sender-row .meta { flex-basis: 100%; padding-left: 54px; white-space: normal; } .reader h1 { font-size: 19px; line-height: 24px; } }\\n@media (max-width: 760px) { .devices { padding: 16px 8px; } .device-col.wide { flex-basis: 100%; } }\\n`,ha=Ke(la,`.${Te}`);var Lt=[{id:\\\"heart\\\",glyph:\\\"\\\\u2665\\\",label:\\\"Heart\\\"},{id:\\\"like\\\",glyph:\\\"\\\\u{1F44D}\\\",label:\\\"Like\\\"},{id:\\\"dislike\\\",glyph:\\\"\\\\u{1F44E}\\\",label:\\\"Dislike\\\"},{id:\\\"laugh\\\",glyph:\\\"HA<br>HA\\\",label:\\\"Laugh\\\"},{id:\\\"emphasize\\\",glyph:\\\"\\\\u203C\\\",label:\\\"Emphasize\\\"},{id:\\\"question\\\",glyph:\\\"?\\\",label:\\\"Question\\\"}],fe=[\\\"sms\\\",\\\"push\\\",\\\"email\\\"];function At(d,p={}){let h=p.live??!0,k=p.syncUrl??(h&&!p.fetch&&!p.baseUrl),T=p.storage??h,z=p.now,$=()=>z??Date.now(),N=p.baseUrl??(p.fetch||typeof location>\\\"u\\\"?\\\"http://harness.local/\\\":location.href),A=(e,t)=>{let s=new Request(new URL(e,N),t);return p.fetch?p.fetch(s):fetch(s)},D=new AbortController,P=(e,t,s=!1)=>d.addEventListener(e,t,{signal:D.signal,capture:s}),he=new Set,G=(e,t)=>{let s=setTimeout(()=>{he.delete(s),t()},e);he.add(s)},ne=!1,Y=new URLSearchParams(p.search??(k&&typeof location<\\\"u\\\"?location.search:\\\"\\\")),ee=Y.get(\\\"view\\\"),j=p.initial??{},a={namespace:Y.get(\\\"namespace\\\")??p.namespace??\\\"default\\\",namespaces:[],items:[],sources:[],discoveryError:null,version:0,view:ee===\\\"timeline\\\"?\\\"timeline\\\":\\\"devices\\\",only:ee===\\\"sms\\\"||ee===\\\"email\\\"||ee===\\\"push\\\"?ee:null,search:\\\"\\\",follow:Y.get(\\\"follow\\\")!==\\\"0\\\",connected:!1,sms:{to:null,thread:null,menu:null,transition:null},push:{to:null,skin:\\\"auto\\\",expanded:null,preview:null,settings:null,wake:!1},email:{to:null,open:null,transition:!1},inspect:null,toast:null,arrived:new Set(p.arrived??[])};Object.assign(a,{...j,sms:{...a.sms,...j.sms},push:{...a.push,...j.push},email:{...a.email,...j.email},toast:j.toast?{text:j.toast}:null}),ee===\\\"timeline\\\"&&(a.view=\\\"timeline\\\"),delete a.local,delete a.push.openGroups;let w={dismissed:new Set(j.local?.dismissed??[]),pinned:new Set(j.local?.pinned??[]),muted:new Set(j.local?.muted??[]),starred:new Set(j.local?.starred??[]),silent:new Set(j.local?.silent??[]),checked:new Set,tapbacks:new Map(Object.entries(j.local?.tapbacks??{})),openGroups:new Set(j.push?.openGroups??[])},re=j.mailDetailsOpen??!1,Ye=Y.get(\\\"to\\\"),Ht=Y.get(\\\"from\\\"),_e=Y.get(\\\"id\\\"),O=Ye&&a.only?{channel:a.only,to:Ye}:null;Y.get(\\\"follow\\\")===null&&O&&(a.follow=!1);let Ct=()=>typeof matchMedia==\\\"function\\\"&&matchMedia(\\\"(prefers-reduced-motion: reduce)\\\").matches,We=()=>(p.motion??\\\"auto\\\")===\\\"auto\\\"?Ct()?\\\"reduce\\\":\\\"full\\\":p.motion,W=()=>We()===\\\"full\\\",Ze=\\\"mockingbird-notifications:sound\\\",Dt=()=>{if(!T)return null;try{let e=localStorage.getItem(Ze);return e===null?null:e===\\\"1\\\"}catch{return null}},K=zt(Y.get(\\\"sound\\\")!==null?Y.get(\\\"sound\\\")===\\\"1\\\":Dt()??p.sound??!1),Xe=()=>`mockingbird-notifications:seen:${a.namespace}`,H=new Set(p.seen??[]),Je=()=>{if(T)try{H=new Set(JSON.parse(localStorage.getItem(Xe())??\\\"[]\\\"))}catch{H=new Set}},Qe=()=>{if(T)try{localStorage.setItem(Xe(),JSON.stringify([...H].slice(-5e3)))}catch{}},le=e=>{let t=!1;for(let s of e)H.has(s)||(H.add(s),t=!0);t&&Qe()},ze=e=>{for(let t of e)H.delete(t);Qe()},o=e=>String(e??\\\"\\\").replace(/[&<>\\\"']/g,t=>`&#${t.charCodeAt(0)};`),l=e=>`data-testid=\\\"${e}\\\"`,te=e=>`data-notification-id=\\\"${o(e.id)}\\\" data-channel=\\\"${e.channel}\\\" data-service=\\\"${o(e.service)}\\\" data-source=\\\"${o(e.source)}\\\" data-to=\\\"${o(e.to)}\\\" data-from=\\\"${o(e.from.address)}\\\" data-status=\\\"${o(e.status??\\\"\\\")}\\\" data-created-at=\\\"${o(e.createdAt)}\\\" data-unread=\\\"${!H.has(e.id)}\\\"`,et=e=>e.replace(/\\\\bhttps?:\\\\/\\\\/[^\\\\s<]+[^\\\\s<.,;:!?)'\\\"]/g,t=>`<a href=\\\"${t}\\\" target=\\\"_blank\\\" rel=\\\"noreferrer\\\">${t}</a>`),Le=e=>{let t=/^\\\\+1(\\\\d{3})(\\\\d{3})(\\\\d{4})$/.exec(e);return t?`+1 (${t[1]}) ${t[2]}-${t[3]}`:e},tt=e=>/^\\\\+?\\\\d[\\\\d\\\\s()-]{5,}$/.test(e),be=e=>e.from.name??(tt(e.from.address)?Le(e.from.address):e.from.address),ge=e=>{let t=e.replace(/[^\\\\p{L}\\\\p{N}\\\\s]/gu,\\\" \\\").trim().split(/\\\\s+/).filter(Boolean);return t.length?((t[0]?.[0]??\\\"\\\")+(t[1]?.[0]??\\\"\\\")).toUpperCase():\\\"?\\\"},Nt=[\\\"#1a73e8\\\",\\\"#e8710a\\\",\\\"#188038\\\",\\\"#d93025\\\",\\\"#9334e6\\\",\\\"#12b5cb\\\",\\\"#e52592\\\",\\\"#f9ab00\\\",\\\"#5f6368\\\",\\\"#a142f4\\\"],at=[\\\"#ff9500\\\",\\\"#34c759\\\",\\\"#5856d6\\\",\\\"#ff2d55\\\",\\\"#007aff\\\",\\\"#af52de\\\",\\\"#ff3b30\\\",\\\"#30b0c7\\\"],Et=e=>[...e].reduce((t,s)=>t*31+s.charCodeAt(0)>>>0,7),xe=(e,t=Nt)=>t[Et(e)%t.length]??\\\"#5f6368\\\",de=(e,t)=>e.toDateString()===t.toDateString(),Z=e=>e.toLocaleTimeString([],{hour:\\\"numeric\\\",minute:\\\"2-digit\\\"}),Rt=e=>{let t=new Date(e),s=new Date($());if(de(t,s))return Z(t);let n=new Date(s);return n.setDate(s.getDate()-1),de(t,n)?\\\"Yesterday\\\":s.getTime()-t.getTime()<6*864e5?t.toLocaleDateString([],{weekday:\\\"long\\\"}):t.toLocaleDateString([],{year:\\\"2-digit\\\",month:\\\"numeric\\\",day:\\\"numeric\\\"})},jt=e=>{let t=new Date(e),s=new Date($());return de(t,s)?`<b>Today</b> ${Z(t)}`:`<b>${o(t.toLocaleDateString([],{weekday:\\\"short\\\",month:\\\"short\\\",day:\\\"numeric\\\"}))}</b> at ${Z(t)}`},Ae=e=>{let t=Math.max(0,($()-Date.parse(e))/1e3);return t<60?\\\"now\\\":t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:`${Math.floor(t/86400)}d ago`},Vt=e=>{let t=Math.max(0,($()-Date.parse(e))/1e3);return t<60?\\\"now\\\":t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`},It=e=>{let t=new Date(e);return de(t,new Date($()))?t.toLocaleTimeString():t.toLocaleString([],{month:\\\"short\\\",day:\\\"numeric\\\",hour:\\\"numeric\\\",minute:\\\"2-digit\\\",...t.getFullYear()===new Date($()).getFullYear()?{}:{year:\\\"numeric\\\"}})},Pt=e=>{let t=new Date(e),s=new Date($());return de(t,s)?Z(t):t.getFullYear()===s.getFullYear()?t.toLocaleDateString([],{month:\\\"short\\\",day:\\\"numeric\\\"}):t.toLocaleDateString([],{year:\\\"2-digit\\\",month:\\\"numeric\\\",day:\\\"numeric\\\"})},Ot=e=>`${new Date(e).toLocaleString([],{weekday:\\\"short\\\",month:\\\"short\\\",day:\\\"numeric\\\",year:\\\"numeric\\\",hour:\\\"numeric\\\",minute:\\\"2-digit\\\"})} (${Ae(e)===\\\"now\\\"?\\\"0 minutes ago\\\":Ae(e)})`,ae={twilio:\\\"Twilio\\\",resend:\\\"Resend\\\",fcm:\\\"FCM\\\",ses:\\\"SES\\\",sns:\\\"SNS\\\",customerio:\\\"Customer.io\\\",mailosaur:\\\"Mailosaur\\\"},Ut=e=>{let t=a.search.trim().toLowerCase();return t?[e.to,e.from.address,e.from.name??\\\"\\\",e.preview,e.email?.subject??\\\"\\\",e.push?.title??\\\"\\\",e.source,e.service].join(`\\n`).toLowerCase().includes(t):!0},it=()=>a.items.filter(Ut),U=e=>it().filter(t=>t.channel===e&&!w.dismissed.has(t.id)),He=e=>{let t=new Map;for(let s of U(e)){let n=t.get(s.to)??{to:s.to,count:0,unread:0,latest:s.createdAt};n.count++,H.has(s.id)||n.unread++,s.createdAt>n.latest&&(n.latest=s.createdAt),s.push&&(n.platform=s.push.platform),t.set(s.to,n)}return[...t.values()].sort((s,n)=>s.latest<n.latest?1:-1)},Ce=()=>{for(let e of fe){let t=He(e),s=a[e];if(O?.channel===e){s.to=O.to;continue}(!s.to||!t.some(n=>n.to===s.to))&&(s.to=t[0]?.to??null)}},De=async e=>{let t=await A(e);if(!t.ok)throw new Error(`${e}: HTTP ${t.status}`);return await t.json()},ve=async()=>{let e=new URLSearchParams({namespace:a.namespace,order:\\\"newest\\\"}),t=await De(`./api/notifications?${e}`);ne||(a.items=t.notifications,a.version=t.version??a.version,Ce(),F())},st=async()=>{try{let e=await De(\\\"./api/sources\\\");a.sources=e.sources,a.discoveryError=e.discoveryError;let t=await De(\\\"./api/namespaces\\\");a.namespaces=t.namespaces,ne||X()}catch{}},ie=(e,t)=>`${e}|${t}`,Ne=(e,t)=>`${e}|${t}`,Bt=e=>{if(e.channel===\\\"sms\\\")return w.muted.has(ie(e.to,e.from.address))?null:\\\"sms\\\";if(e.channel===\\\"email\\\")return\\\"email\\\";let t=a.push.skin===\\\"auto\\\"?e.push?.platform===\\\"android\\\"?\\\"android\\\":\\\"ios\\\":a.push.skin;return t===\\\"android\\\"&&w.silent.has(e.push?.app??\\\"App\\\")?null:t===\\\"android\\\"?\\\"push-android\\\":\\\"push-ios\\\"},qt=e=>{for(let n of e)a.arrived.add(n.id);let t=[...e].sort((n,i)=>n.createdAt<i.createdAt?1:-1);for(let n of fe){let i=t.filter(b=>b.channel===n),u=O?.channel===n?i.find(b=>b.to===O.to):i[0];u&&(O?.channel===n?n===\\\"sms\\\"&&!a.sms.thread&&(a.sms.thread=u.from.address):a.follow&&(a[n].to=u.to,n===\\\"sms\\\"&&a.sms.thread!==null&&(a.sms.thread=u.from.address)),n===\\\"push\\\"&&a.push.to===u.to&&(a.push.wake=!0))}let s=new Set(e.map(Bt).filter(n=>n!==null));for(let n of s)K.play(n);p.onArrive?.(e),G(1800,()=>{for(let n of e)a.arrived.delete(n.id)})},Ee=null,ot=()=>{Ee?.abort();let e=new AbortController;Ee=e;let t=a.namespace,s=(i,u)=>{if(!e.signal.aborted){if(i===\\\"sources\\\")a.sources=JSON.parse(u),X();else if(i===\\\"change\\\"){let{added:b,version:f}=JSON.parse(u);a.version=f,qt(b),ve().catch(()=>{})}}};(async()=>{for(;!e.signal.aborted;){try{let i=await A(`./api/events?namespace=${encodeURIComponent(t)}`,{signal:e.signal,headers:{accept:\\\"text/event-stream\\\"}});if(!i.ok||!i.body)throw new Error(`events: HTTP ${i.status}`);a.connected=!0,X();let u=i.body.pipeThrough(new TextDecoderStream).getReader(),b=\\\"\\\";for(;;){let{value:f,done:y}=await u.read();if(y)break;b+=f.replace(/\\\\r\\\\n/g,`\\n`);let g=b.indexOf(`\\n\\n`);for(;g>=0;){let m=b.slice(0,g);b=b.slice(g+2);let x=\\\"message\\\",L=[];for(let S of m.split(`\\n`))S.startsWith(\\\"event:\\\")?x=S.slice(6).trim():S.startsWith(\\\"data:\\\")&&L.push(S.slice(5).trimStart());L.length&&s(x,L.join(`\\n`)),g=b.indexOf(`\\n\\n`)}}}catch{}if(e.signal.aborted)return;a.connected=!1,X(),await new Promise(i=>G(1e3,()=>i(null)))}})()};d.classList.add(Te),p.embedded&&d.classList.add(\\\"embedded\\\"),d.dataset.testid=r.app,d.dataset.ready=\\\"false\\\",d.innerHTML=`\\n<header class=\\\"topbar\\\" data-region=\\\"topbar\\\" ${l(r.topbar)}></header>\\n<div data-region=\\\"notice\\\"></div>\\n<div class=\\\"mbn-scroll\\\" data-region=\\\"scroll\\\">\\n<section class=\\\"devices\\\" data-region=\\\"devices\\\">\\n <div class=\\\"device-col\\\" data-region=\\\"col-sms\\\"></div>\\n <div class=\\\"device-col\\\" data-region=\\\"col-push\\\"></div>\\n <div class=\\\"device-col wide\\\" data-region=\\\"col-email\\\"></div>\\n</section>\\n<section class=\\\"timeline\\\" data-region=\\\"timeline\\\" hidden></section>\\n</div>\\n<aside class=\\\"inspector\\\" data-region=\\\"inspector\\\" ${l(r.inspector)} hidden></aside>`;let B=e=>d.querySelector(`[data-region=\\\"${e}\\\"]`),nt=e=>d.querySelector(`[data-testid=\\\"${e}\\\"]`),rt=()=>p.title??d.dataset.title??\\\"Notifications\\\",Ft=()=>{Object.assign(d.dataset,{view:a.view,namespace:a.namespace,count:String(a.items.length),version:String(a.version),connected:String(a.connected),sound:String(K.enabled),motion:We()})},X=()=>{Ft();let e=B(\\\"topbar\\\");if(e.hidden=p.chrome===!1,p.chrome===!1)return;let t=[...new Set([...a.namespaces,a.namespace])].sort(),s=document.activeElement===nt(r.search);if(e.innerHTML=`\\n <div class=\\\"brand\\\"><span class=\\\"brand-mark\\\">${c.bell()}</span><span>${o(rt())} <small>Mockingbird</small></span></div>\\n <label class=\\\"field\\\">Namespace <select data-action=\\\"namespace\\\" ${l(r.namespace)} aria-label=\\\"Namespace\\\">${t.map(i=>`<option ${i===a.namespace?\\\"selected\\\":\\\"\\\"}>${o(i)}</option>`).join(\\\"\\\")}</select></label>\\n <div class=\\\"field search\\\">${c.search(\\\"#9aa1b1\\\",14)}<input type=\\\"search\\\" data-action=\\\"search\\\" ${l(r.search)} aria-label=\\\"Filter notifications\\\" placeholder=\\\"Filter by recipient, sender, text\\\\u2026\\\" value=\\\"${o(a.search)}\\\"></div>\\n <div class=\\\"tabs\\\" role=\\\"group\\\" aria-label=\\\"View\\\">\\n <button data-action=\\\"view\\\" data-value=\\\"devices\\\" ${l(r.viewDevices)} aria-pressed=\\\"${a.view===\\\"devices\\\"}\\\">Devices</button>\\n <button data-action=\\\"view\\\" data-value=\\\"timeline\\\" ${l(r.viewTimeline)} aria-pressed=\\\"${a.view===\\\"timeline\\\"}\\\">Timeline <span style=\\\"opacity:.6\\\">${a.items.length}</span></button>\\n </div>\\n <label class=\\\"toggle\\\" title=\\\"Jump each device to the newest arrival\\\"><input type=\\\"checkbox\\\" data-action=\\\"follow\\\" ${l(r.follow)} ${a.follow?\\\"checked\\\":\\\"\\\"}> Follow new</label>\\n <button class=\\\"icon-toggle\\\" data-action=\\\"sound\\\" ${l(r.sound)} aria-pressed=\\\"${K.enabled}\\\" title=\\\"Play alert sounds on arrivals\\\">${K.enabled?c.volumeOn():c.volumeOff()}<span>Sound</span></button>\\n <span class=\\\"live\\\" ${l(r.connection)} data-state=\\\"${a.connected?\\\"live\\\":\\\"reconnecting\\\"}\\\" role=\\\"status\\\"><span class=\\\"dot ${a.connected?\\\"ok\\\":\\\"bad\\\"}\\\"></span>${a.connected?\\\"Live\\\":\\\"Reconnecting\\\"}</span>\\n <div class=\\\"sources\\\">${a.sources.map(i=>`<span class=\\\"pill\\\" title=\\\"${o(i.error??i.url)}\\\" ${l(r.source)} data-name=\\\"${o(i.name)}\\\" data-service=\\\"${o(i.service??\\\"\\\")}\\\" data-ok=\\\"${i.ok}\\\" data-count=\\\"${i.count}\\\"><span class=\\\"dot ${i.ok?\\\"ok\\\":i.error?\\\"bad\\\":\\\"\\\"}\\\"></span>${o(i.service&&i.name!==i.service?`${i.name} \\\\xB7 ${ae[i.service]??i.service}`:ae[i.name]??i.name)} <b>${i.count}</b></span>`).join(\\\"\\\")}</div>`,s){let i=nt(r.search);i?.focus(),i?.setSelectionRange(i.value.length,i.value.length)}let n=a.sources.filter(i=>i.error);B(\\\"notice\\\").innerHTML=a.discoveryError||n.length?`<div class=\\\"notice\\\" ${l(r.notice)} data-kind=\\\"error\\\" role=\\\"alert\\\">${a.discoveryError?`Fleet discovery failed: ${o(a.discoveryError)}. `:\\\"\\\"}${n.map(i=>`<b>${o(i.name)}</b>: ${o(i.error)}`).join(\\\" \\\\xB7 \\\")}</div>`:a.sources.length?\\\"\\\":`<div class=\\\"notice\\\" ${l(r.notice)} data-kind=\\\"empty\\\" style=\\\"border-color:#3a3f4b;background:#171a21;color:#9aa1b1\\\">No messaging emulators found yet. Start the fleet with twilio, resend, fcm, ses, sns, customerio or mailosaur.</div>`},Re=(e,t,s,n)=>{let i=He(e),u=a[e].to;return`<label class=\\\"field\\\">${t}<select data-action=\\\"recipient\\\" data-channel=\\\"${e}\\\" ${l(s)} aria-label=\\\"${t}\\\" ${i.length?\\\"\\\":\\\"disabled\\\"}>${i.length?i.map(b=>`<option value=\\\"${o(b.to)}\\\" ${b.to===u?\\\"selected\\\":\\\"\\\"}>${b.unread?\\\"\\\\u25CF \\\":\\\"\\\"}${o(n(b.to))} \\\\xB7 ${b.count}</option>`).join(\\\"\\\"):\\\"<option>No recipients yet</option>\\\"}</select></label>`},je=(e,t)=>e?`<span class=\\\"count\\\" ${l(t)} data-count=\\\"${e}\\\">${e}</span>`:\\\"\\\",lt=(e=!1)=>`\\n <div class=\\\"statusbar ${e?\\\"light\\\":\\\"\\\"}\\\"><span>${Z(new Date($())).replace(/\\\\s?[AP]M$/i,\\\"\\\")}</span>\\n <span class=\\\"icons\\\">${c.signal()}${c.wifi()}${c.battery()}</span></div>`,Ve=(e,t)=>{if(!W()||typeof e.animate!=\\\"function\\\")return t();let s=new Map;for(let n of e.querySelectorAll(\\\"[data-flip]\\\"))s.set(n.dataset.flip??\\\"\\\",n.getBoundingClientRect().top);t();for(let n of e.querySelectorAll(\\\"[data-flip]\\\")){let i=s.get(n.dataset.flip??\\\"\\\");if(i===void 0)continue;let u=i-n.getBoundingClientRect().top;Math.abs(u)<1||n.animate([{transform:`translateY(${u}px)`},{transform:\\\"none\\\"}],{duration:380,easing:\\\"cubic-bezier(.2,.9,.25,1)\\\"})}},Ie=e=>{let t=new Map;for(let s of U(\\\"sms\\\").filter(n=>n.to===e)){let n=s.from.address;t.set(n,[...t.get(n)??[],s])}return[...t.entries()].map(([s,n])=>({from:s,items:n.sort((i,u)=>i.createdAt<u.createdAt?-1:1),pinned:w.pinned.has(ie(e,s))})).sort((s,n)=>s.pinned!==n.pinned?s.pinned?-1:1:(s.items.at(-1)?.createdAt??\\\"\\\")<(n.items.at(-1)?.createdAt??\\\"\\\")?1:-1)},dt=e=>{let t=e?be(e):\\\"\\\";return tt(e?.from.address??\\\"\\\")&&!e?.from.name?c.person():o(ge(t))},Pe=e=>e.sms?.code??(/\\\\b(code|otp|passcode|pin|verif)/i.test(e.sms?.body??\\\"\\\")?/\\\\b(\\\\d{4,8})\\\\b/.exec(e.sms?.body??\\\"\\\")?.[1]??null:null),Gt=(e,t)=>t?e.replace(new RegExp(`\\\\\\\\b${t}\\\\\\\\b`),`<span class=\\\"code\\\">${t}</span>`):e,Kt=e=>{let t=w.tapbacks.get(e),s=Lt.find(n=>n.id===t);return s?`<span class=\\\"tapback\\\" ${l(r.smsTapback)} data-tapback=\\\"${s.id}\\\" aria-label=\\\"${s.label}\\\">${s.glyph}</span>`:\\\"\\\"},ct=e=>{let t=Gt(et(o(e.sms?.body??\\\"\\\")),Pe(e));return(e.sms?.media??[]).map(n=>`<img class=\\\"media\\\" src=\\\"${o(n)}\\\" alt=\\\"\\\" ${l(r.smsBubbleMedia)}>`).join(\\\"\\\")+t},q=()=>{let e=a.sms.to,t=e?Ie(e):[],s=U(\\\"sms\\\").filter(g=>!H.has(g.id)).length,n,i=t.find(g=>g.from===a.sms.thread),u=a.sms.transition;if(a.sms.transition=null,i&&e){le(i.items.map(R=>R.id));let g=i.items[0],m=t.filter(R=>R!==i).reduce((R,se)=>R+se.items.filter(oe=>!H.has(oe.id)).length,0),x=0,L=!0,S=i.items.map((R,se)=>{let oe=Date.parse(R.createdAt),kt=se===0||oe-x>15*6e4?`<div class=\\\"stamp\\\" ${l(r.smsTimestamp)}>${se===0?\\\"Text Message<br>\\\":\\\"\\\"}${jt(R.createdAt)}</div>`:\\\"\\\",Mt=i.items[se+1],St=!Mt||Date.parse(Mt.createdAt)-oe>6e4,ia=!kt&&L&&se>0;x=oe,L=St;let Tt=Pe(R);return`${kt}<div class=\\\"bubble-row ${ia?\\\"gap\\\":\\\"\\\"}\\\"><div class=\\\"bubble ${St?\\\"tail\\\":\\\"\\\"} ${a.arrived.has(R.id)?\\\"arrive\\\":\\\"\\\"}\\\" ${te(R)} ${l(r.smsBubble)} ${Tt?`data-code=\\\"${o(Tt)}\\\"`:\\\"\\\"} data-longpress=\\\"sms-bubble\\\" tabindex=\\\"0\\\" aria-haspopup=\\\"menu\\\">${ct(R)}${Kt(R.id)}</div><span class=\\\"bubble-time\\\" ${l(r.smsBubbleTime)} aria-hidden=\\\"true\\\">${o(Z(new Date(oe)))}</span></div>`}).join(\\\"\\\"),C=i.items.at(-1),J=C?Pe(C):null,Se=a.sms.menu?i.items.find(R=>R.id===a.sms.menu):null,aa=w.muted.has(ie(e,i.from));n=`<div class=\\\"convo ${u===\\\"push\\\"&&W()?\\\"enter\\\":\\\"\\\"}\\\" ${l(r.smsConversation)} data-from=\\\"${o(i.from)}\\\">\\n <div class=\\\"convo-nav\\\"><div class=\\\"bar\\\">\\n <button class=\\\"back\\\" data-action=\\\"sms-back\\\" ${l(r.smsBack)} aria-label=\\\"Back to Messages\\\">${c.chevronBack()}${m?`<span class=\\\"badge\\\">${m}</span>`:\\\"\\\"}</button>\\n <div class=\\\"avatar\\\">${dt(g)}</div>\\n <div class=\\\"who\\\" ${l(r.smsConversationTitle)}>${o(g?be(g):i.from)}${aa?` <span class=\\\"flag\\\">${c.bellSlash(12)}</span>`:\\\"\\\"} ${c.chevronRight(\\\"#8e8e93\\\")}</div>\\n </div></div>\\n <div class=\\\"convo-body\\\" data-swipe=\\\"sms-convo\\\">${S}</div>\\n ${J&&C&&$()-Date.parse(C.createdAt)<10*6e4?`<button class=\\\"qt\\\" data-action=\\\"sms-copy-code\\\" data-code=\\\"${o(J)}\\\" ${l(r.smsCode)}><small>From Messages</small>${o(J)}</button>`:\\\"\\\"}\\n <div class=\\\"convo-input\\\"><span class=\\\"plus\\\">${c.plus()}</span><span class=\\\"field-ios\\\">Text Message<span>${c.mic()}</span></span></div>\\n ${Se?Yt(Se):\\\"\\\"}\\n </div>`}else a.sms.thread=null,a.sms.menu=null,n=`<div class=\\\"msgs ${u===\\\"back\\\"&&W()?\\\"enter\\\":\\\"\\\"}\\\">\\n <div class=\\\"msgs-nav\\\"><div class=\\\"row\\\"><span>Edit</span>${c.compose()}</div><h1>Messages</h1>\\n <div class=\\\"ios-search\\\">${c.search(\\\"rgba(60,60,67,.6)\\\",15)}<span>Search</span>${c.mic(\\\"rgba(60,60,67,.6)\\\")}</div></div>\\n ${t.length&&e?`<div class=\\\"threads\\\" role=\\\"list\\\">${t.map(g=>{let m=g.items.at(-1),x=g.items.some(J=>!H.has(J.id)),L=ie(e,g.from),S=w.muted.has(L),C=m?be(m):g.from;return`<div class=\\\"swipe thread-swipe\\\" data-swipe=\\\"sms-thread\\\" data-from=\\\"${o(g.from)}\\\" data-flip=\\\"thread:${o(g.from)}\\\" role=\\\"listitem\\\">\\n <div class=\\\"swipe-actions\\\">\\n <div class=\\\"side\\\"><button class=\\\"act-unread\\\" data-action=\\\"thread-unread\\\" data-from=\\\"${o(g.from)}\\\" ${l(r.smsThreadToggleUnread)}>${x?c.markRead(22):c.markUnread(22)}${x?\\\"Read\\\":\\\"Unread\\\"}</button><button class=\\\"act-pin\\\" data-action=\\\"thread-pin\\\" data-from=\\\"${o(g.from)}\\\" ${l(r.smsThreadPin)}>${c.pin(22)}${g.pinned?\\\"Unpin\\\":\\\"Pin\\\"}</button></div>\\n <div class=\\\"side\\\"><button class=\\\"act-mute\\\" data-action=\\\"thread-mute\\\" data-from=\\\"${o(g.from)}\\\" ${l(r.smsThreadMute)}>${c.bellSlash(22)}${S?\\\"Show Alerts\\\":\\\"Hide Alerts\\\"}</button><button class=\\\"act-delete\\\" data-action=\\\"thread-delete\\\" data-from=\\\"${o(g.from)}\\\" ${l(r.smsThreadDelete)}>${c.trash()}Delete</button></div>\\n </div>\\n <div class=\\\"thread swipe-card\\\" data-action=\\\"sms-open\\\" data-from=\\\"${o(g.from)}\\\" ${l(r.smsThread)} ${m?te(m):\\\"\\\"} data-unread=\\\"${x}\\\" data-pinned=\\\"${g.pinned}\\\" data-muted=\\\"${S}\\\" role=\\\"button\\\" tabindex=\\\"0\\\" aria-label=\\\"${o(C)}${x?\\\", unread\\\":\\\"\\\"}\\\">\\n ${x?`<span class=\\\"unread\\\" ${l(r.smsThreadUnread)}></span>`:\\\"\\\"}<div class=\\\"avatar\\\">${dt(m)}</div>\\n <div class=\\\"text\\\"><div class=\\\"top\\\"><span class=\\\"name-line\\\"><span class=\\\"name\\\" ${l(r.smsThreadName)}>${o(C)}</span>${g.pinned?`<span class=\\\"flag\\\">${c.pin(13)}</span>`:\\\"\\\"}${S?`<span class=\\\"flag\\\">${c.bellSlash(13)}</span>`:\\\"\\\"}</span><span class=\\\"when\\\" ${l(r.smsThreadTime)}>${o(Rt(m?.createdAt??\\\"\\\"))} ${c.chevronRight()}</span></div>\\n <div class=\\\"preview\\\" ${l(r.smsThreadPreview)}>${o(m?.sms?.body??\\\"\\\")}</div></div></div></div>`}).join(\\\"\\\")}</div>`:`<div class=\\\"empty-ios\\\" ${l(r.smsEmpty)}>${e?\\\"No Messages\\\":\\\"No text messages yet.<br><br>SMS sent through Twilio, SNS, Customer.io or Mailosaur shows up here.\\\"}</div>`}\\n </div>`;let b=B(\\\"col-sms\\\");Ve(b,()=>{b.innerHTML=`\\n <div class=\\\"device-head\\\"><h2>Text messages ${je(s,r.smsUnreadCount)}</h2>${Re(\\\"sms\\\",\\\"Phone\\\",r.smsRecipient,Le)}</div>\\n <div class=\\\"iphone\\\" ${l(r.smsDevice)} data-screen=\\\"${i?\\\"conversation\\\":\\\"threads\\\"}\\\" data-recipient=\\\"${o(e??\\\"\\\")}\\\" data-thread=\\\"${o(i?.from??\\\"\\\")}\\\"><div class=\\\"screen\\\"><div class=\\\"island\\\"></div>${lt()}${n}<div class=\\\"home-indicator\\\"></div></div></div>`});let f=b.querySelector(\\\".convo-body\\\"),y=()=>{f&&(f.scrollTop=f.scrollHeight)};y(),requestAnimationFrame(y)},Yt=e=>{let t=w.tapbacks.get(e.id);return`<div class=\\\"ios-overlay\\\" data-action=\\\"close-overlay\\\" ${l(r.smsMenu)} data-notification-id=\\\"${o(e.id)}\\\" role=\\\"dialog\\\" aria-label=\\\"Message actions\\\">\\n <div class=\\\"tapback-bar\\\" role=\\\"toolbar\\\" aria-label=\\\"Tapback\\\">${Lt.map(s=>`<button data-action=\\\"tapback\\\" data-id=\\\"${o(e.id)}\\\" data-value=\\\"${s.id}\\\" ${l(r.smsMenuTapback)} data-tapback=\\\"${s.id}\\\" aria-label=\\\"${s.label}\\\" aria-pressed=\\\"${t===s.id}\\\">${s.glyph}</button>`).join(\\\"\\\")}</div>\\n <div class=\\\"bubble tail\\\">${ct(e)}</div>\\n <div class=\\\"ios-menu\\\" role=\\\"menu\\\">\\n <button role=\\\"menuitem\\\" data-action=\\\"close-overlay\\\">Reply</button>\\n <button role=\\\"menuitem\\\" data-action=\\\"sms-copy\\\" data-id=\\\"${o(e.id)}\\\" ${l(r.smsMenuCopy)}>Copy</button>\\n <button role=\\\"menuitem\\\" data-action=\\\"close-overlay\\\">Translate</button>\\n <button role=\\\"menuitem\\\" data-action=\\\"close-overlay\\\">More\\\\u2026</button>\\n </div></div>`},pt=e=>{let t=e.push?.data??{};return Object.keys(t).length?`<div class=\\\"note-data\\\" ${l(r.pushNotificationData)}>${o(JSON.stringify(t,null,2))}</div>`:\\\"\\\"},mt=e=>`<div class=\\\"note-meta\\\" ${l(r.pushNotificationMeta)}>${o(ae[e.service]??e.service)} \\\\xB7 ${o(e.status??\\\"accepted\\\")}${e.push?.badge!==null&&e.push?.badge!==void 0?` \\\\xB7 badge ${e.push.badge}`:\\\"\\\"}${e.push?.sound?` \\\\xB7 sound ${o(e.push.sound)}`:\\\"\\\"}</div>`,ut=(e,t={})=>`${te(e)} ${l(r.pushNotification)} data-platform=\\\"${o(e.push?.platform??\\\"unknown\\\")}\\\" data-app=\\\"${o(e.push?.app??\\\"App\\\")}\\\" ${Object.entries(t).map(([s,n])=>`data-${s}=\\\"${o(n)}\\\"`).join(\\\" \\\")}`,ft=(e,t)=>{let s=e.push,n=s?.app??\\\"App\\\",i=t.expanded;return`<div class=\\\"ios-note swipe-card ${i?\\\"expanded\\\":\\\"\\\"} ${a.arrived.has(e.id)?\\\"arrive\\\":\\\"\\\"}\\\" data-action=\\\"push-toggle\\\" data-id=\\\"${o(e.id)}\\\" ${ut(e,{expanded:i,stacked:t.stacked??!1})} ${t.extra??\\\"\\\"} role=\\\"button\\\" tabindex=\\\"0\\\" aria-expanded=\\\"${i}\\\" data-longpress=\\\"ios-note\\\">\\n <span class=\\\"app-icon\\\" style=\\\"background:${xe(n,at)}\\\" ${l(r.pushNotificationApp)} aria-label=\\\"${o(n)}\\\">${o(ge(n).slice(0,1))}</span>\\n <div class=\\\"content\\\">\\n <div class=\\\"line1\\\"><span class=\\\"title\\\" ${l(r.pushNotificationTitle)}>${o(s?.title??n)}</span><span class=\\\"time\\\" ${l(r.pushNotificationTime)}>${o(Ae(e.createdAt))}</span></div>\\n <div class=\\\"body\\\" ${l(r.pushNotificationBody)}>${o(s?.body??\\\"\\\")}</div>\\n ${i&&s?.imageUrl?`<img class=\\\"hero\\\" src=\\\"${o(s.imageUrl)}\\\" alt=\\\"\\\" ${l(r.pushNotificationImage)}>`:\\\"\\\"}\\n ${i?pt(e)+mt(e):\\\"\\\"}\\n </div>\\n ${!i&&s?.imageUrl?`<img class=\\\"thumb\\\" src=\\\"${o(s.imageUrl)}\\\" alt=\\\"\\\" ${l(r.pushNotificationImage)}>`:\\\"\\\"}\\n </div>`},we=(e,t={})=>`<div class=\\\"swipe ios-swipe\\\" data-swipe=\\\"ios-note\\\" data-id=\\\"${o(e.id)}\\\" data-flip=\\\"note:${o(e.id)}\\\" ${t.hidden?\\\"hidden\\\":\\\"\\\"}>\\n <div class=\\\"swipe-actions\\\"><button data-action=\\\"push-options\\\" data-id=\\\"${o(e.id)}\\\" ${l(r.pushOptions)}>Options</button><button data-action=\\\"push-clear\\\" data-id=\\\"${o(e.id)}\\\" ${l(r.pushClear)}>Clear</button></div>\\n ${ft(e,{expanded:a.push.expanded===e.id,stacked:t.stacked??!1,extra:t.top?'data-group-top=\\\"true\\\"':\\\"\\\"})}\\n </div>`,_t=e=>{let t=e.push,s=a.push.expanded===e.id,n=t?.app??\\\"App\\\",i=a.push.settings===e.id,u=w.silent.has(n);return`<div class=\\\"a-note ${s?\\\"expanded\\\":\\\"\\\"} ${a.arrived.has(e.id)?\\\"arrive\\\":\\\"\\\"}\\\" data-action=\\\"push-toggle\\\" data-id=\\\"${o(e.id)}\\\" ${ut(e,{expanded:s})} data-swipe=\\\"a-note\\\" data-longpress=\\\"a-note\\\" data-flip=\\\"note:${o(e.id)}\\\" role=\\\"button\\\" tabindex=\\\"0\\\" aria-expanded=\\\"${s}\\\">\\n <span class=\\\"a-icon\\\" style=\\\"background:${xe(n,at)}\\\" aria-hidden=\\\"true\\\">${o(ge(n).slice(0,1))}</span>\\n <div class=\\\"a-main\\\">\\n <div class=\\\"a-head\\\"><span ${l(r.pushNotificationApp)}>${o(n)}</span><span>\\\\u2022</span><span ${l(r.pushNotificationTime)}>${o(Vt(e.createdAt))}</span>${u?`<span>${c.bellSlash(12)}</span>`:\\\"\\\"}<span class=\\\"chev\\\">${s?c.collapse():c.expand()}</span></div>\\n ${t?.title?`<div class=\\\"a-title\\\" ${l(r.pushNotificationTitle)}>${o(t.title)}</div>`:\\\"\\\"}\\n <div class=\\\"a-body\\\" ${l(r.pushNotificationBody)}>${o(t?.body??\\\"\\\")}</div>\\n ${s&&t?.imageUrl?`<img class=\\\"big-picture\\\" src=\\\"${o(t.imageUrl)}\\\" alt=\\\"\\\" ${l(r.pushNotificationImage)}>`:\\\"\\\"}\\n ${s?pt(e)+mt(e):\\\"\\\"}\\n ${i?`<div class=\\\"a-settings\\\" ${l(r.pushSettings)} data-app=\\\"${o(n)}\\\">\\n <button class=\\\"opt\\\" data-action=\\\"push-alerting\\\" data-app=\\\"${o(n)}\\\" data-value=\\\"alerting\\\" aria-pressed=\\\"${!u}\\\">${c.bell()}<span>Default<small>May ring or vibrate based on device settings</small></span></button>\\n <button class=\\\"opt\\\" data-action=\\\"push-alerting\\\" data-app=\\\"${o(n)}\\\" data-value=\\\"silent\\\" aria-pressed=\\\"${u}\\\">${c.bellSlash(18)}<span>Silent<small>No sound or vibration</small></span></button>\\n <div class=\\\"row\\\"><button data-action=\\\"close-overlay\\\">Turn off notifications</button><button data-action=\\\"close-overlay\\\">Done</button></div></div>`:\\\"\\\"}\\n </div>\\n ${!s&&t?.imageUrl?`<img class=\\\"large-icon\\\" src=\\\"${o(t.imageUrl)}\\\" alt=\\\"\\\" ${l(r.pushNotificationImage)}>`:\\\"\\\"}\\n </div>`},Wt=(e,t)=>{let s=[],n=new Map;for(let i of t){let u=i.push?.app??\\\"App\\\";n.has(u)||s.push(u),n.set(u,[...n.get(u)??[],i])}return s.map(i=>{let u=n.get(i)??[],b=u[0];if(!b)return\\\"\\\";if(u.length===1)return we(b);let f=Ne(e,i),y=w.openGroups.has(f),g=u.length-1;return y?`<div class=\\\"push-group\\\" ${l(r.pushGroup)} data-app=\\\"${o(i)}\\\" data-count=\\\"${u.length}\\\" data-open=\\\"true\\\" data-flip=\\\"group:${o(i)}\\\">\\n <div class=\\\"group-head\\\"><h3>${o(i)}</h3><button data-action=\\\"group-collapse\\\" data-key=\\\"${o(f)}\\\" ${l(r.pushGroupCollapse)}>Show less</button><button class=\\\"x\\\" data-action=\\\"group-clear\\\" data-key=\\\"${o(f)}\\\" data-app=\\\"${o(i)}\\\" aria-label=\\\"Clear ${o(i)} notifications\\\">${c.close(14)}</button></div>\\n ${u.map(m=>we(m)).join(\\\"\\\")}</div>`:`<div class=\\\"push-group\\\" ${l(r.pushGroup)} data-app=\\\"${o(i)}\\\" data-count=\\\"${u.length}\\\" data-open=\\\"false\\\" data-flip=\\\"group:${o(i)}\\\">\\n ${we(b,{top:!0})}\\n <button class=\\\"stack-layers\\\" data-action=\\\"group-open\\\" data-key=\\\"${o(f)}\\\" ${l(r.pushGroupMore)} data-count=\\\"${g}\\\" aria-label=\\\"Show ${g} more notification${g===1?\\\"\\\":\\\"s\\\"}\\\"><div class=\\\"ios-stack-more\\\"></div>${g>1?'<div class=\\\"ios-stack-more\\\"></div>':\\\"\\\"}<div class=\\\"center-label\\\" style=\\\"font-size:13px;margin-top:6px\\\">${g} more notification${g===1?\\\"\\\":\\\"s\\\"}</div></button>\\n ${u.slice(1).map(m=>we(m,{stacked:!0,hidden:!0})).join(\\\"\\\")}</div>`}).join(\\\"\\\")},E=()=>{let e=a.push.to,t=e?U(\\\"push\\\").filter(x=>x.to===e):[];le(t.map(x=>x.id));let s=t[0]?.push?.platform??\\\"unknown\\\",n=a.push.skin===\\\"auto\\\"?s===\\\"android\\\"?\\\"android\\\":\\\"ios\\\":a.push.skin,i=new Date($()),u=U(\\\"push\\\").filter(x=>!H.has(x.id)).length,b=a.push.wake&&W();a.push.wake=!1;let f,y=`${l(r.pushDevice)} data-skin=\\\"${n}\\\" data-recipient=\\\"${o(e??\\\"\\\")}\\\" data-platform=\\\"${o(s)}\\\"`;if(n===\\\"android\\\")f=`<div class=\\\"pixel\\\" ${y}><div class=\\\"screen\\\"><div class=\\\"punch\\\"></div><div class=\\\"shade\\\">\\n <div class=\\\"sb\\\"><span>${Z(i).replace(/\\\\s?[AP]M$/i,\\\"\\\")}</span><span class=\\\"icons\\\">${c.androidWifi()}${c.androidSignal()}${c.androidBattery()}</span></div>\\n <div class=\\\"qs-head\\\"><span>${o(i.toLocaleDateString([],{weekday:\\\"short\\\",month:\\\"short\\\",day:\\\"numeric\\\"}))}</span>${c.gear()}</div>\\n <div class=\\\"qs\\\"><div class=\\\"tile on\\\">${c.androidWifi()}<div>Internet<small>Mockingbird</small></div></div><div class=\\\"tile\\\">${c.bell()}<div>Do Not Disturb<small>Off</small></div></div>\\n <div class=\\\"tile\\\">${c.androidBattery()}<div>Battery Saver<small>Off</small></div></div><div class=\\\"tile\\\">${c.lock()}<div>Screen lock<small>On</small></div></div></div>\\n <div class=\\\"qs-bright\\\"></div>\\n <div class=\\\"shade-list\\\" role=\\\"list\\\">${t.length?t.map(_t).join(\\\"\\\"):`<div class=\\\"shade-empty\\\" ${l(r.pushEmpty)}>No notifications</div>`}</div>\\n ${t.length?`<div class=\\\"shade-actions\\\"><button data-action=\\\"close-overlay\\\">Manage</button><button data-action=\\\"push-clear-all\\\" ${l(r.pushClearAll)}>Clear all</button></div>`:\\\"\\\"}\\n <div class=\\\"gesture\\\"></div></div></div></div>`;else{let x=a.push.preview?t.find(L=>L.id===a.push.preview):null;f=`<div class=\\\"iphone\\\" ${y}><div class=\\\"screen\\\"><div class=\\\"island\\\"></div>${lt(!0)}<div class=\\\"lock ${b?\\\"wake\\\":\\\"\\\"}\\\">\\n <div class=\\\"padlock\\\">${c.padlock()}</div>\\n <div class=\\\"date\\\">${o(i.toLocaleDateString([],{weekday:\\\"long\\\",month:\\\"long\\\",day:\\\"numeric\\\"}))}</div>\\n <div class=\\\"clock\\\">${o(Z(i).replace(/\\\\s?[AP]M$/i,\\\"\\\"))}</div>\\n <div class=\\\"lock-stack\\\" role=\\\"list\\\">${t.length&&e?`<div class=\\\"center-label\\\">Notification Center</div>${Wt(e,t)}`:`<div class=\\\"lock-empty\\\" ${l(r.pushEmpty)}>${e?\\\"No Older Notifications\\\":\\\"No push notifications yet\\\"}</div>`}</div>\\n <div class=\\\"lock-buttons\\\"><span>${c.flashlight()}</span><span>${c.camera()}</span></div>\\n ${x?`<div class=\\\"ios-overlay dark\\\" data-action=\\\"close-overlay\\\" ${l(r.pushPreview)} data-notification-id=\\\"${o(x.id)}\\\" role=\\\"dialog\\\" aria-label=\\\"Notification preview\\\">${ft(x,{expanded:!0})}\\n <div class=\\\"ios-menu\\\" role=\\\"menu\\\"><button role=\\\"menuitem\\\" data-action=\\\"push-clear\\\" data-id=\\\"${o(x.id)}\\\">Clear</button><button role=\\\"menuitem\\\" data-action=\\\"close-overlay\\\">Options</button></div></div>`:\\\"\\\"}\\n </div><div class=\\\"home-indicator light\\\"></div></div></div>`}let g=x=>{let L=He(\\\"push\\\").find(C=>C.to===x);return`${x.length>22?`${x.slice(0,10)}\\\\u2026${x.slice(-8)}`:x}${L?.platform&&L.platform!==\\\"unknown\\\"?` \\\\xB7 ${L.platform}`:\\\"\\\"}`},m=B(\\\"col-push\\\");Ve(m,()=>{m.innerHTML=`\\n <div class=\\\"device-head\\\"><h2>Push ${je(u,r.pushUnreadCount)}</h2>\\n <div class=\\\"controls\\\">${Re(\\\"push\\\",\\\"Device\\\",r.pushRecipient,g)}\\n <div class=\\\"seg\\\" role=\\\"group\\\" aria-label=\\\"Phone\\\">${[\\\"auto\\\",\\\"ios\\\",\\\"android\\\"].map(x=>`<button data-action=\\\"skin\\\" data-value=\\\"${x}\\\" ${l(r.pushSkin)} aria-pressed=\\\"${a.push.skin===x}\\\">${x===\\\"auto\\\"?\\\"Auto\\\":x===\\\"ios\\\"?\\\"iOS\\\":\\\"Android\\\"}</button>`).join(\\\"\\\")}</div></div></div>${f}`})},Zt=e=>`<!doctype html><html><head><meta charset=\\\"utf-8\\\"><base target=\\\"_blank\\\"><style>body{margin:0;font:14px/1.5 Arial,Helvetica,sans-serif;color:#222;overflow-wrap:anywhere}img{max-width:100%;height:auto}</style></head><body>${e.email?.html??\\\"\\\"}</body></html>`,Xt=(e,t)=>{a.toast=t?{text:e,undo:t}:{text:e},I();let s=a.toast;G(6e3,()=>{a.toast===s&&(a.toast=null,I())})},ht=(e,t)=>{w.dismissed.add(e),a.email.open===e&&(a.email.open=null,a.email.transition=!0),Xt(t===\\\"archived\\\"?\\\"Conversation archived.\\\":\\\"Conversation moved to Trash.\\\",()=>{w.dismissed.delete(e),a.toast=null,I()})},I=()=>{let e=a.email.to,t=e?U(\\\"email\\\").filter(m=>m.to===e):[],s=t.filter(m=>!H.has(m.id)).length,n=U(\\\"email\\\").filter(m=>!H.has(m.id)).length,i=t.find(m=>m.id===a.email.open);i||(a.email.open=null);let u=a.email.transition&&W();a.email.transition=!1;let b=e??\\\"you@example.test\\\",f;if(i){le([i.id]);let m=i.email,x=i.from.name??i.from.address,L=i.to.toLowerCase()===b.toLowerCase()?\\\"me\\\":i.to,S=(C,J,Se)=>`<span>${J}:</span><span ${l(r.emailDetail)} data-field=\\\"${C}\\\">${o(Se)}</span>`;f=`<div class=\\\"mail-toolbar\\\">\\n <button class=\\\"icon-btn\\\" data-action=\\\"mail-back\\\" ${l(r.emailBack)} title=\\\"Back to Inbox\\\" aria-label=\\\"Back to Inbox\\\">${c.back()}</button>\\n <button class=\\\"icon-btn\\\" data-action=\\\"mail-archive\\\" data-id=\\\"${o(i.id)}\\\" ${l(r.emailArchive)} title=\\\"Archive\\\" aria-label=\\\"Archive\\\">${c.archive()}</button><span class=\\\"icon-btn\\\">${c.report()}</span><button class=\\\"icon-btn\\\" data-action=\\\"mail-delete\\\" data-id=\\\"${o(i.id)}\\\" ${l(r.emailDelete)} title=\\\"Delete\\\" aria-label=\\\"Delete\\\">${c.trash()}</button>\\n <button class=\\\"icon-btn\\\" data-action=\\\"mail-unread\\\" data-id=\\\"${o(i.id)}\\\" ${l(r.emailMarkUnread)} title=\\\"Mark as unread\\\" aria-label=\\\"Mark as unread\\\">${c.markUnread()}</button><span class=\\\"icon-btn\\\">${c.clock()}</span><span class=\\\"icon-btn\\\">${c.more()}</span>\\n <span class=\\\"range\\\">${t.indexOf(i)+1} of ${t.length}</span></div>\\n <div class=\\\"reader ${u?\\\"enter\\\":\\\"\\\"}\\\" ${te(i)} ${l(r.emailOpen)}>\\n <div class=\\\"subject-row\\\"><h1 ${l(r.emailSubject)}>${o(m?.subject||\\\"(no subject)\\\")}</h1><span class=\\\"label-chip\\\">Inbox</span></div>\\n <div class=\\\"sender-row\\\">\\n <span class=\\\"mail-avatar\\\" style=\\\"background:${xe(i.from.address)}\\\">${o(ge(x).slice(0,1))}</span>\\n <div class=\\\"who\\\"><b ${l(r.emailFromName)}>${o(x)}</b> <span class=\\\"addr\\\"><<span ${l(r.emailFromAddress)}>${o(i.from.address)}</span>></span>\\n <div class=\\\"to\\\" data-action=\\\"mail-details\\\" ${l(r.emailTo)} role=\\\"button\\\" tabindex=\\\"0\\\" aria-expanded=\\\"${re}\\\">to ${o(L)}${m?.cc.length?`, ${o(m.cc.join(\\\", \\\"))}`:\\\"\\\"} ${c.dropdown()}</div></div>\\n <div class=\\\"meta\\\"><span ${l(r.emailDate)}>${o(Ot(i.createdAt))}</span> <span class=\\\"icon-btn\\\">${c.star()}</span><span class=\\\"icon-btn\\\">${c.reply()}</span><span class=\\\"icon-btn\\\">${c.more()}</span></div>\\n </div>\\n ${re?`<div class=\\\"details\\\" ${l(r.emailDetails)}>\\n ${S(\\\"from\\\",\\\"from\\\",i.from.name?`${i.from.name} <${i.from.address}>`:i.from.address)}\\n ${S(\\\"to\\\",\\\"to\\\",i.to)}\\n ${m?.cc.length?S(\\\"cc\\\",\\\"cc\\\",m.cc.join(\\\", \\\")):\\\"\\\"}\\n ${m?.bcc.length?S(\\\"bcc\\\",\\\"bcc\\\",m.bcc.join(\\\", \\\")):\\\"\\\"}\\n ${m?.replyTo.length?S(\\\"reply-to\\\",\\\"reply-to\\\",m.replyTo.join(\\\", \\\")):\\\"\\\"}\\n ${S(\\\"date\\\",\\\"date\\\",new Date(i.createdAt).toLocaleString())}\\n ${S(\\\"subject\\\",\\\"subject\\\",m?.subject??\\\"\\\")}\\n ${S(\\\"mailed-by\\\",\\\"mailed-by\\\",`${ae[i.service]??i.service} (${i.source})`)}\\n ${S(\\\"message-id\\\",\\\"message id\\\",i.providerId)}\\n </div>`:\\\"\\\"}\\n ${m?.html?`<iframe class=\\\"mail-frame\\\" name=\\\"email-body\\\" ${l(r.emailBody)} data-format=\\\"html\\\" sandbox=\\\"allow-same-origin allow-popups allow-popups-to-escape-sandbox\\\" title=\\\"Email body\\\"></iframe>`:`<div class=\\\"mail-text\\\" ${l(r.emailText)} data-format=\\\"text\\\">${et(o(m?.text??\\\"\\\"))}</div>`}\\n ${m?.attachments.length?`<div class=\\\"attachments\\\" ${l(r.emailAttachments)} data-count=\\\"${m.attachments.length}\\\"><h3>${m.attachments.length} attachment${m.attachments.length===1?\\\"\\\":\\\"s\\\"}</h3><div class=\\\"att-grid\\\">${m.attachments.map(C=>`<div class=\\\"att\\\" ${l(r.emailAttachment)} data-filename=\\\"${o(C.filename)}\\\" data-content-type=\\\"${o(C.contentType??\\\"\\\")}\\\" data-size=\\\"${C.size??\\\"\\\"}\\\"><div class=\\\"att-top\\\">${c.file()}</div><div class=\\\"att-name\\\">${c.clip()} ${o(C.filename)}${C.size?` <span style=\\\"color:#5f6368;font-weight:400\\\">${Math.max(1,Math.round(C.size/1024))} KB</span>`:\\\"\\\"}</div></div>`).join(\\\"\\\")}</div></div>`:\\\"\\\"}\\n <div class=\\\"reply-row\\\"><span>${c.reply()} Reply</span><span>${c.forward()} Forward</span></div>\\n </div>`}else f=`<div class=\\\"mail-toolbar\\\"><span class=\\\"icon-btn\\\">${c.checkbox()}</span><button class=\\\"icon-btn\\\" data-action=\\\"refresh\\\" ${l(r.emailRefresh)} title=\\\"Refresh\\\" aria-label=\\\"Refresh\\\">${c.refresh()}</button><span class=\\\"icon-btn\\\">${c.more()}</span>\\n <span class=\\\"range\\\">${t.length?`1\\\\u2013${t.length} of ${t.length}`:\\\"\\\"}</span></div>\\n <div class=\\\"cat-tabs\\\"><div class=\\\"on\\\">${c.inbox()} Primary</div><div>${c.star()} Promotions</div><div>${c.send()} Updates</div></div>\\n <div class=\\\"mail-list ${u?\\\"enter\\\":\\\"\\\"}\\\" role=\\\"list\\\">${t.length?t.map(m=>{let x=!H.has(m.id),L=m.from.name??m.from.address,S=w.starred.has(m.id);return`<div class=\\\"swipe mrow-swipe\\\" data-swipe=\\\"mrow\\\" data-id=\\\"${o(m.id)}\\\" data-flip=\\\"row:${o(m.id)}\\\" role=\\\"listitem\\\">\\n <div class=\\\"swipe-actions\\\">${c.archive()}${c.archive()}</div>\\n <div class=\\\"mrow swipe-card ${x?\\\"unread\\\":\\\"\\\"} ${a.arrived.has(m.id)?\\\"arrive\\\":\\\"\\\"}\\\" data-action=\\\"mail-open\\\" data-id=\\\"${o(m.id)}\\\" ${te(m)} ${l(r.emailRow)} data-starred=\\\"${S}\\\" role=\\\"button\\\" tabindex=\\\"0\\\">\\n <span class=\\\"chk\\\" data-action=\\\"mail-check\\\" data-id=\\\"${o(m.id)}\\\" role=\\\"checkbox\\\" aria-checked=\\\"${w.checked.has(m.id)}\\\" aria-label=\\\"Select\\\">${c.checkbox()}</span><span class=\\\"star\\\" data-action=\\\"mail-star\\\" data-id=\\\"${o(m.id)}\\\" ${l(r.emailRowStar)} role=\\\"button\\\" aria-pressed=\\\"${S}\\\" aria-label=\\\"${S?\\\"Starred\\\":\\\"Not starred\\\"}\\\">${S?c.starFilled():c.star()}</span>\\n <span class=\\\"from\\\" ${l(r.emailRowFrom)}>${o(L)}</span>\\n <span class=\\\"subj\\\"><span ${l(r.emailRowSubject)}>${o(m.email?.subject||\\\"(no subject)\\\")}</span> <span class=\\\"snippet\\\">- <span ${l(r.emailRowSnippet)}>${o(m.preview)}</span></span></span>\\n ${m.email?.attachments.length?`<span class=\\\"clip\\\" ${l(r.emailRowAttachment)}>${c.clip()}</span>`:\\\"\\\"}<span class=\\\"svc\\\" ${l(r.emailRowService)}>${o(ae[m.service]??m.service)}</span>\\n <span class=\\\"date\\\" ${l(r.emailRowDate)}>${o(Pt(m.createdAt))}</span>\\n <span class=\\\"hover-actions\\\"><button class=\\\"icon-btn\\\" data-action=\\\"mail-archive\\\" data-id=\\\"${o(m.id)}\\\" ${l(r.emailRowArchive)} title=\\\"Archive\\\" aria-label=\\\"Archive\\\">${c.archive()}</button><button class=\\\"icon-btn\\\" data-action=\\\"mail-delete\\\" data-id=\\\"${o(m.id)}\\\" ${l(r.emailRowDelete)} title=\\\"Delete\\\" aria-label=\\\"Delete\\\">${c.trash()}</button><button class=\\\"icon-btn\\\" data-action=\\\"mail-toggle-read\\\" data-id=\\\"${o(m.id)}\\\" ${l(r.emailRowToggleRead)} title=\\\"${x?\\\"Mark as read\\\":\\\"Mark as unread\\\"}\\\" aria-label=\\\"${x?\\\"Mark as read\\\":\\\"Mark as unread\\\"}\\\">${x?c.markRead():c.markUnread()}</button><span class=\\\"icon-btn\\\">${c.clock()}</span></span></div></div>`}).join(\\\"\\\"):`<div class=\\\"mail-empty\\\" ${l(r.emailEmpty)}>${c.envelope()}<b>${e?\\\"Your Primary tab is empty.\\\":\\\"No email yet\\\"}</b>${e?\\\"\\\":\\\"Email sent through Resend, SES, SNS, Customer.io or Mailosaur lands here.\\\"}</div>`}</div>`;let y=B(\\\"col-email\\\");Ve(y,()=>{y.innerHTML=`\\n <div class=\\\"device-head\\\"><h2>Email ${je(n,r.emailUnreadCount)}</h2>${Re(\\\"email\\\",\\\"Mailbox\\\",r.emailRecipient,m=>m)}</div>\\n <div class=\\\"window\\\" ${l(r.emailDevice)} data-screen=\\\"${i?\\\"message\\\":\\\"inbox\\\"}\\\" data-recipient=\\\"${o(e??\\\"\\\")}\\\">\\n <div class=\\\"chrome\\\"><span class=\\\"lights\\\"><i></i><i></i><i></i></span><span class=\\\"omnibox\\\">${c.lock()} mail.example.test/#inbox${i?`/${o(i.providerId)}`:\\\"\\\"}</span></div>\\n <div class=\\\"mail-top\\\"><span class=\\\"icon-btn\\\">${c.menu()}</span><span class=\\\"mail-logo\\\">${c.envelope()}<span class=\\\"lbl\\\">Mail</span></span>\\n <div class=\\\"mail-search\\\"><span class=\\\"icon-btn\\\">${c.search(\\\"#444746\\\",20)}</span><span class=\\\"placeholder\\\">Search mail</span><span class=\\\"icon-btn\\\">${c.tune()}</span></div>\\n <div class=\\\"right\\\"><span class=\\\"icon-btn\\\">${c.help()}</span><span class=\\\"icon-btn\\\">${c.gear()}</span><span class=\\\"icon-btn\\\">${c.apps()}</span>\\n <span class=\\\"mail-avatar\\\" title=\\\"${o(b)}\\\" style=\\\"background:${xe(b)}\\\">${o(b.slice(0,1).toUpperCase())}</span></div></div>\\n <div class=\\\"mail-body\\\">\\n <nav class=\\\"mail-nav\\\"><button class=\\\"compose\\\">${c.pencil()}<span class=\\\"lbl\\\">Compose</span></button>\\n <div class=\\\"nav-item active\\\">${c.inbox()}<span class=\\\"lbl\\\">Inbox</span><span class=\\\"n\\\">${s||\\\"\\\"}</span></div>\\n <div class=\\\"nav-item\\\">${c.star()}<span class=\\\"lbl\\\">Starred</span></div>\\n <div class=\\\"nav-item\\\">${c.clock()}<span class=\\\"lbl\\\">Snoozed</span></div>\\n <div class=\\\"nav-item\\\">${c.send()}<span class=\\\"lbl\\\">Sent</span></div>\\n <div class=\\\"nav-item\\\">${c.draft()}<span class=\\\"lbl\\\">Drafts</span></div>\\n <div class=\\\"nav-item\\\">${c.expand()}<span class=\\\"lbl\\\">More</span></div></nav>\\n <main class=\\\"mail-main\\\">${f}</main>\\n </div>\\n ${a.toast?`<div class=\\\"toast\\\" ${l(r.toast)} role=\\\"status\\\"><span>${o(a.toast.text)}</span>${a.toast.undo?`<button data-action=\\\"toast-undo\\\" ${l(r.toastUndo)}>Undo</button>`:\\\"\\\"}<button data-action=\\\"toast-close\\\" aria-label=\\\"Dismiss\\\">${c.close(16)}</button></div>`:\\\"\\\"}\\n </div>`});let g=y.querySelector(\\\".mail-frame\\\");if(g&&i&&(g.addEventListener(\\\"load\\\",()=>{let m=g.contentDocument;m&&(g.style.height=`${Math.max(120,m.documentElement.scrollHeight+8)}px`)}),g.srcdoc=Zt(i)),k&&h){let m=fe.reduce((x,L)=>x+U(L).filter(S=>!H.has(S.id)).length,0);document.title=`${m?`(${m}) `:\\\"\\\"}${rt()} \\\\xB7 Mockingbird`}},Jt=()=>{let e=it();B(\\\"timeline\\\").innerHTML=e.length?`<table class=\\\"tl\\\" ${l(r.timeline)}><thead><tr><th>Time</th><th>Channel</th><th>Source</th><th>To</th><th>From</th><th>Content</th><th>Status</th></tr></thead><tbody>${e.map(t=>`<tr data-action=\\\"inspect\\\" data-id=\\\"${o(t.id)}\\\" ${te(t)} ${l(r.timelineRow)} tabindex=\\\"0\\\">\\n <td class=\\\"mono\\\" data-col=\\\"time\\\">${o(It(t.createdAt))}</td>\\n <td data-col=\\\"channel\\\"><span class=\\\"chan ${t.channel}\\\">${t.channel===\\\"sms\\\"?\\\"SMS\\\":t.channel===\\\"email\\\"?\\\"Email\\\":\\\"Push\\\"}</span></td>\\n <td data-col=\\\"source\\\"><span class=\\\"svc-tag\\\">${o(ae[t.service]??t.service)}${t.source!==t.service?` \\\\xB7 ${o(t.source)}`:\\\"\\\"}</span></td>\\n <td class=\\\"mono\\\" data-col=\\\"to\\\">${o(t.channel===\\\"sms\\\"?Le(t.to):t.to.length>28?`${t.to.slice(0,26)}\\\\u2026`:t.to)}</td>\\n <td data-col=\\\"from\\\">${o(be(t))}</td>\\n <td class=\\\"content\\\" data-col=\\\"content\\\">${t.email?`<b>${o(t.email.subject)}</b> \\\\u2014 `:t.push?.title?`<b>${o(t.push.title)}</b> \\\\u2014 `:\\\"\\\"}${o(t.channel===\\\"email\\\"?t.preview.slice(0,120):t.sms?.body??t.push?.body??t.preview)}</td>\\n <td class=\\\"svc-tag\\\" data-col=\\\"status\\\">${o(t.status??\\\"\\\")}</td></tr>`).join(\\\"\\\")}</tbody></table>`:`<div class=\\\"empty-tl\\\" ${l(r.timelineEmpty)}>Nothing sent in namespace <b>${o(a.namespace)}</b> yet.</div>`},ce=()=>{let e=a.items.find(u=>u.id===a.inspect),t=B(\\\"inspector\\\");if(!e){t.hidden=!0,t.innerHTML=\\\"\\\";for(let u of Object.keys(t.dataset))u!==\\\"region\\\"&&u!==\\\"testid\\\"&&delete t.dataset[u];return}t.hidden=!1,Object.assign(t.dataset,{notificationId:e.id,channel:e.channel,service:e.service,source:e.source,to:e.to,from:e.from.address,status:e.status??\\\"\\\",createdAt:e.createdAt});let{raw:s,...n}=e,i=(u,b,f)=>`<span>${b}</span><span ${l(r.inspectorField)} data-field=\\\"${u}\\\">${o(f)}</span>`;t.innerHTML=`<header><h3 ${l(r.inspectorTitle)}>${o(e.channel.toUpperCase())} \\\\xB7 ${o(e.email?.subject??e.push?.title??e.preview.slice(0,60))}</h3>\\n <button class=\\\"btn\\\" data-action=\\\"show-on-device\\\" data-id=\\\"${o(e.id)}\\\" ${l(r.inspectorShowOnDevice)}>Show on device</button><button class=\\\"btn\\\" data-action=\\\"close-inspector\\\" ${l(r.inspectorClose)}>Close</button></header>\\n <div class=\\\"kv\\\">${i(\\\"id\\\",\\\"Id\\\",e.id)}${i(\\\"providerId\\\",\\\"Provider id\\\",e.providerId)}${i(\\\"service\\\",\\\"Service\\\",`${e.service} (${e.source})`)}\\n ${i(\\\"namespace\\\",\\\"Namespace\\\",e.namespace)}${i(\\\"to\\\",\\\"To\\\",e.to)}${i(\\\"from\\\",\\\"From\\\",e.from.name?`${e.from.name} <${e.from.address}>`:e.from.address)}\\n ${i(\\\"createdAt\\\",\\\"Created\\\",e.createdAt)}${i(\\\"status\\\",\\\"Status\\\",e.status??\\\"\\\\u2014\\\")}</div>\\n <pre ${l(r.inspectorJson)}>${o(JSON.stringify({...n,raw:s},null,2))}</pre>`},pe=e=>(a.only===null||a.only===e)&&(p.channels===void 0||p.channels.includes(e)),F=()=>{if(!ne){X(),B(\\\"devices\\\").hidden=a.view!==\\\"devices\\\",B(\\\"timeline\\\").hidden=a.view!==\\\"timeline\\\";for(let e of fe)B(`col-${e}`).hidden=!pe(e);B(\\\"devices\\\").classList.toggle(\\\"solo\\\",fe.filter(pe).length===1),a.view===\\\"devices\\\"?(pe(\\\"sms\\\")&&q(),pe(\\\"push\\\")&&E(),pe(\\\"email\\\")&&I()):Jt(),ce()}},Oe=e=>{a.view=\\\"devices\\\",a[e.channel].to=e.to,e.channel===\\\"sms\\\"&&(a.sms.thread=e.from.address),e.channel===\\\"email\\\"&&(a.email.open=e.id),e.channel===\\\"push\\\"&&(a.push.expanded=e.id,w.openGroups.add(Ne(e.to,e.push?.app??\\\"App\\\"))),w.dismissed.delete(e.id),a.inspect=null,F(),d.querySelector(`.devices [data-notification-id=\\\"${CSS.escape(e.id)}\\\"]`)?.scrollIntoView({block:\\\"nearest\\\"})},Qt=(e,t)=>{if(!W())return t();e.style.height=`${e.offsetHeight}px`,e.classList.add(\\\"collapsing\\\"),e.offsetHeight,Object.assign(e.style,{height:\\\"0px\\\",marginTop:\\\"0px\\\",marginBottom:\\\"0px\\\",paddingTop:\\\"0px\\\",paddingBottom:\\\"0px\\\",opacity:\\\"0\\\"}),G(270,t)},Ue=(e,t,s,n)=>{if(!W())return n();e.classList.add(\\\"settling\\\"),t.classList.add(\\\"settling\\\"),t.style.transform=`translateX(${s*(e.offsetWidth+40)}px)`,t.style.opacity=\\\"0\\\",G(230,()=>Qt(e,n))},$e=e=>d.querySelector(e),me=e=>e.querySelector(\\\".swipe-card\\\")??e,ye=(e,t=-1)=>{let s=$e(`.ios-swipe[data-id=\\\"${CSS.escape(e)}\\\"]`)??$e(`.a-note[data-id=\\\"${CSS.escape(e)}\\\"]`),n=()=>{w.dismissed.add(e),a.push.preview===e&&(a.push.preview=null),E()};if(!s)return n();Ue(s,me(s),t,n)},Be=e=>{let t=a.sms.to;if(!t)return;let s=U(\\\"sms\\\").filter(u=>u.to===t&&u.from.address===e).map(u=>u.id),n=$e(`.thread-swipe[data-from=\\\"${CSS.escape(e)}\\\"]`),i=()=>{for(let u of s)w.dismissed.add(u);q()};if(!n)return i();Ue(n,me(n),-1,i)},ke=(e,t,s=-1)=>{let n=$e(`.mrow-swipe[data-id=\\\"${CSS.escape(e)}\\\"]`);if(!n)return ht(e,t);Ue(n,me(n),s,()=>ht(e,t))},M=null,ue=!1,ea=160,bt=148,gt=(e,t)=>{let s=me(e);s.style.transform=t?`translateX(${t}px)`:\\\"\\\",e.dataset.swipe===\\\"a-note\\\"&&(s.style.opacity=String(1-Math.min(.9,Math.abs(t)/e.offsetWidth)))},_=(e,t,s)=>{e.classList.add(\\\"settling\\\"),e.classList.toggle(\\\"open\\\",s),e.dataset.swipe===\\\"a-note\\\"&&e.classList.add(\\\"settling\\\"),gt(e,t),G(340,()=>{e.classList.remove(\\\"settling\\\",\\\"swiping\\\"),e.dataset.offset=String(t)})},qe=e=>{let t=e.dataset.longpress,s=e.dataset.notificationId??e.dataset.id??\\\"\\\";if(t===\\\"sms-bubble\\\"){a.sms.menu=s,q();try{navigator.vibrate?.(10)}catch{}}else t===\\\"ios-note\\\"?(a.push.preview=s,E()):t===\\\"a-note\\\"&&(a.push.settings=a.push.settings===s?null:s,E())};P(\\\"pointerdown\\\",e=>{if(K.unlock(),ue=!1,e.button!==0||!e.isPrimary)return;let t=e.target;if(t.closest(\\\"select, input, .swipe-actions button, .ios-overlay\\\"))return;let s=t.closest(\\\"[data-swipe]\\\"),n=t.closest(\\\"[data-longpress]\\\");if(!(!s&&!n)&&(M={pointerId:e.pointerId,x0:e.clientX,y0:e.clientY,t0:performance.now(),dx:0,axis:null,swipe:s,press:n,base:Number(s?.dataset.offset??0),timer:null},n)){let i=M;i.timer=setTimeout(()=>{M!==i||i.axis||(ue=!0,M=null,qe(n))},480)}}),P(\\\"pointermove\\\",e=>{if(!M||e.pointerId!==M.pointerId)return;let t=e.clientX-M.x0,s=e.clientY-M.y0;if(!M.axis){if(Math.hypot(t,s)<8)return;if(M.axis=Math.abs(t)>Math.abs(s)?\\\"x\\\":\\\"y\\\",M.timer&&clearTimeout(M.timer),M.axis===\\\"x\\\"&&M.swipe){M.swipe.classList.add(\\\"swiping\\\"),M.swipe.classList.remove(\\\"settling\\\"),me(M.swipe).classList.remove(\\\"settling\\\");try{M.swipe.setPointerCapture(e.pointerId)}catch{}}}if(M.axis!==\\\"x\\\"||!M.swipe)return;e.preventDefault(),M.dx=t;let n=M.swipe.dataset.swipe,i=M.base+t;if(n===\\\"sms-convo\\\"){let u=Math.max(0,Math.min(72,-t));M.swipe.style.setProperty(\\\"--reveal\\\",`${u}px`);return}n===\\\"ios-note\\\"&&i>0&&(i=i*.35),(n===\\\"mrow\\\"||n===\\\"a-note\\\")&&(i=t),gt(M.swipe,i)});let xt=e=>{if(!M||e.pointerId!==M.pointerId)return;let t=M;if(M=null,t.timer&&clearTimeout(t.timer),t.axis!==\\\"x\\\"||!t.swipe)return;ue=!0;let s=t.swipe,n=s.dataset.swipe,i=s.offsetWidth||1,u=t.dx/Math.max(1,performance.now()-t.t0),b=t.base+t.dx;if(n===\\\"sms-convo\\\")s.classList.add(\\\"settling\\\"),s.style.setProperty(\\\"--reveal\\\",\\\"0px\\\"),G(320,()=>s.classList.remove(\\\"settling\\\"));else if(n===\\\"ios-note\\\"){let f=s.dataset.id??\\\"\\\";b<-i*.7||u<-1.1&&b<-60?ye(f):b<-60?_(s,-ea,!0):b>70?(_(s,0,!1),a.push.expanded=f,E()):_(s,0,!1)}else if(n===\\\"a-note\\\")Math.abs(b)>i*.4||Math.abs(u)>.7?ye(s.dataset.id??\\\"\\\",Math.sign(b)||1):_(s,0,!1);else if(n===\\\"sms-thread\\\"){let f=s.dataset.from??\\\"\\\";b<-i*.6?Be(f):b<-50?_(s,-bt,!0):b>50?_(s,bt,!0):_(s,0,!1)}else n===\\\"mrow\\\"&&(Math.abs(b)>i*.35||Math.abs(u)>.8?ke(s.dataset.id??\\\"\\\",\\\"archived\\\",Math.sign(b)||1):_(s,0,!1))};P(\\\"pointerup\\\",xt),P(\\\"pointercancel\\\",xt),P(\\\"contextmenu\\\",e=>{let t=e.target.closest(\\\"[data-longpress]\\\");t&&(e.preventDefault(),qe(t))}),P(\\\"click\\\",e=>{ue&&(ue=!1,e.stopPropagation(),e.preventDefault())},!0);let vt=()=>{let e=a.sms.menu||a.push.preview||a.push.settings;return a.sms.menu=null,a.push.preview=null,a.push.settings=null,e&&(q(),E()),!!e},wt=e=>{try{navigator.clipboard?.writeText(e).catch(()=>{})}catch{}};P(\\\"click\\\",e=>{let t=e.target.closest(\\\"[data-action]\\\");if(!t)return;let s=t.closest(\\\".swipe.open\\\");if(s&&t.classList.contains(\\\"swipe-card\\\")){_(s,0,!1);return}let n=t.dataset.action,i=t.dataset.id??\\\"\\\",u=t.dataset.from??\\\"\\\",b=a.sms.to??\\\"\\\";switch(n){case\\\"view\\\":a.view=t.dataset.value===\\\"timeline\\\"?\\\"timeline\\\":\\\"devices\\\",F();break;case\\\"sound\\\":Me.setSound(!K.enabled);break;case\\\"sms-open\\\":a.sms.thread=u||null,a.sms.transition=\\\"push\\\",q();break;case\\\"sms-back\\\":a.sms.thread=null,a.sms.transition=\\\"back\\\",q();break;case\\\"thread-delete\\\":Be(u);break;case\\\"thread-pin\\\":{let f=ie(b,u);w.pinned.delete(f)||w.pinned.add(f),q();break}case\\\"thread-mute\\\":{let f=ie(b,u);w.muted.delete(f)||w.muted.add(f),q();break}case\\\"thread-unread\\\":{let f=U(\\\"sms\\\").filter(y=>y.to===b&&y.from.address===u);if(f.some(y=>!H.has(y.id)))le(f.map(y=>y.id));else{let y=f.at(-1);y&&ze([y.id])}q();break}case\\\"tapback\\\":{let f=t.dataset.value;w.tapbacks.get(i)===f?w.tapbacks.delete(i):w.tapbacks.set(i,f),a.sms.menu=null,q();break}case\\\"sms-copy\\\":{let f=a.items.find(y=>y.id===i);f&&wt(f.sms?.body??\\\"\\\"),a.sms.menu=null,q();break}case\\\"sms-copy-code\\\":wt(t.dataset.code??\\\"\\\");break;case\\\"close-overlay\\\":vt();break;case\\\"push-toggle\\\":{if(t.dataset.groupTop===\\\"true\\\"){let f=a.items.find(y=>y.id===i);f&&(w.openGroups.add(Ne(f.to,f.push?.app??\\\"App\\\")),E());break}a.push.expanded=a.push.expanded===i?null:i,E();break}case\\\"push-clear\\\":a.push.preview=null,ye(i);break;case\\\"push-options\\\":a.push.preview=i,E();break;case\\\"push-alerting\\\":{let f=t.dataset.app??\\\"App\\\";t.dataset.value===\\\"silent\\\"?w.silent.add(f):w.silent.delete(f),E();break}case\\\"push-clear-all\\\":{let f=[...d.querySelectorAll(\\\".shade-list .a-note\\\")],y=f.map(m=>m.dataset.id??\\\"\\\"),g=()=>{for(let m of y)w.dismissed.add(m);E()};if(!W())return g();f.forEach((m,x)=>{G(x*60,()=>{m.classList.add(\\\"settling\\\"),m.style.transform=`translateX(${m.offsetWidth+40}px)`,m.style.opacity=\\\"0\\\"})}),G(f.length*60+300,g);break}case\\\"group-open\\\":w.openGroups.add(t.dataset.key??\\\"\\\"),E();break;case\\\"group-collapse\\\":w.openGroups.delete(t.dataset.key??\\\"\\\"),E();break;case\\\"group-clear\\\":{let f=t.dataset.app??\\\"App\\\";for(let y of U(\\\"push\\\"))y.to===a.push.to&&(y.push?.app??\\\"App\\\")===f&&w.dismissed.add(y.id);w.openGroups.delete(t.dataset.key??\\\"\\\"),E();break}case\\\"skin\\\":a.push.skin=t.dataset.value??\\\"auto\\\",E();break;case\\\"mail-open\\\":a.email.open=i,a.email.transition=!0,re=!1,I();break;case\\\"mail-back\\\":a.email.open=null,a.email.transition=!0,I();break;case\\\"mail-details\\\":re=!re,I();break;case\\\"mail-archive\\\":ke(i,\\\"archived\\\");break;case\\\"mail-delete\\\":ke(i,\\\"deleted\\\");break;case\\\"mail-unread\\\":ze([i]),a.email.open=null,a.email.transition=!0,I();break;case\\\"mail-toggle-read\\\":H.has(i)?ze([i]):le([i]),I();break;case\\\"mail-star\\\":w.starred.delete(i)||w.starred.add(i),I();break;case\\\"mail-check\\\":w.checked.delete(i)||w.checked.add(i),I();break;case\\\"toast-undo\\\":a.toast?.undo?.();break;case\\\"toast-close\\\":a.toast=null,I();break;case\\\"refresh\\\":ve().catch(()=>{});break;case\\\"inspect\\\":a.inspect=i,ce();break;case\\\"close-inspector\\\":a.inspect=null,ce();break;case\\\"show-on-device\\\":{let f=a.items.find(y=>y.id===i);f&&Oe(f);break}}}),P(\\\"dblclick\\\",e=>{let t=e.target.closest(\\\"[data-notification-id]\\\");!t||t.closest(\\\"[data-region=inspector]\\\")||(a.inspect=t.dataset.notificationId??null,ce())}),P(\\\"change\\\",e=>{let t=e.target,s=t.dataset.action;if(s===\\\"namespace\\\")Me.setNamespace(t.value);else if(s===\\\"follow\\\")a.follow=t.checked;else if(s===\\\"recipient\\\"){let n=t.dataset.channel;a[n].to=t.value,n===\\\"sms\\\"&&(a.sms.thread=null),n===\\\"email\\\"&&(a.email.open=null),F()}}),P(\\\"input\\\",e=>{let t=e.target;t.dataset.action===\\\"search\\\"&&(a.search=t.value,Ce(),F())}),P(\\\"keydown\\\",e=>{K.unlock();let t=e.target;if(e.key===\\\"Escape\\\"){if(vt())return;a.inspect&&(a.inspect=null,ce());return}if(!t.matches(\\\"input, select, textarea\\\")){if(e.key===\\\"ContextMenu\\\"||e.shiftKey&&e.key===\\\"F10\\\"){let s=t.closest(\\\"[data-longpress]\\\");s&&(e.preventDefault(),qe(s));return}if(e.key===\\\"Delete\\\"||e.key===\\\"Backspace\\\"||e.key===\\\"#\\\"||e.key===\\\"e\\\"){let s=t.dataset.id??\\\"\\\";t.matches(\\\"[data-testid=push-notification]\\\")&&e.key!==\\\"e\\\"?(e.preventDefault(),ye(s)):t.matches(\\\"[data-testid=sms-thread]\\\")&&e.key!==\\\"e\\\"?(e.preventDefault(),Be(t.dataset.from??\\\"\\\")):t.matches(\\\"[data-testid=email-row]\\\")&&(e.preventDefault(),ke(s,e.key===\\\"e\\\"?\\\"archived\\\":\\\"deleted\\\"));return}(e.key===\\\"Enter\\\"||e.key===\\\" \\\")&&t.matches(\\\"[role=button]:not(button)\\\")&&(e.preventDefault(),t.click())}});let $t=()=>{if(O&&(a[O.channel].to=O.to,O.channel===\\\"sms\\\"&&(a.sms.thread=Ht??Ie(O.to)[0]?.from??null)),_e){let e=a.items.find(t=>t.id===_e);if(e)return Oe(e)}F()},Fe=()=>{},ta=new Promise(e=>{Fe=()=>{d.dataset.ready=\\\"true\\\",e()}}),Me={render:F,state:a,ready:ta,show(e){let t=e.id?a.items.find(s=>s.id===e.id):void 0;if(t)return Oe(t);e.channel&&(a.view=\\\"devices\\\",e.to&&(a[e.channel].to=e.to),e.channel===\\\"sms\\\"&&e.to&&(a.sms.thread=Ie(e.to)[0]?.from??null),F())},setNamespace(e){if(e!==a.namespace){if(a.namespace=e,a.items=[],a.sms={...a.sms,to:null,thread:null,menu:null},a.email={...a.email,to:null,open:null},a.push.to=null,Je(),k){let t=new URL(location.href);t.searchParams.set(\\\"namespace\\\",e),history.replaceState(null,\\\"\\\",t)}h?(ot(),ve().catch(()=>{})):F()}},setSound(e){if(K.enabled=e,e&&K.unlock(),T)try{localStorage.setItem(Ze,e?\\\"1\\\":\\\"0\\\")}catch{}X()},destroy(){ne=!0,D.abort(),Ee?.abort();for(let e of he)clearTimeout(e);he.clear();for(let e of yt)clearInterval(e);K.close(),d.innerHTML=\\\"\\\",d.classList.remove(Te,\\\"embedded\\\")}},yt=[];return h?(yt.push(setInterval(()=>{M||a.sms.menu||a.push.preview||a.push.settings||(a.view===\\\"devices\\\"&&!d.querySelector(\\\".mail-frame\\\")?F():X())},3e4),setInterval(()=>{st()},5e3)),Je(),F(),ot(),st(),(async()=>{for(let e=0;!ne;e++)try{await ve(),$t(),Fe();return}catch{await new Promise(t=>G(Math.min(5e3,500*2**e),()=>t(null)))}})(),Me):(a.items=[...p.items??[]].sort((e,t)=>e.createdAt<t.createdAt?1:-1),a.sources=p.sources??[],a.namespaces=p.namespaces??[],a.discoveryError=p.discoveryError??null,a.connected=p.connected??!0,Ce(),$t(),Fe(),Me)}At(document.getElementById(\\\"app\\\"),{live:!0});\\n\"\n", "/**\n * One reader per emulator. Each turns that emulator's admin outbox (or stored state) into\n * notifications as the recipient would see them. Readers only GET admin routes, so they never\n * change emulator state.\n */\nimport { addressList, decodeRawMessage, parseMime } from \"./mime.js\"\nimport type {\n Address,\n Channel,\n EmailContent,\n Notification,\n PushContent,\n PushPlatform,\n ServiceKind,\n SmsContent,\n} from \"./model.js\"\n\n/** GET an admin path (relative to the emulator's admin prefix) in the reader's namespace. */\nexport type AdminRead = (path: string) => Promise<unknown>\n\nexport type ReadContext = { source: string; namespace: string; read: AdminRead }\n\nexport type Reader = (context: ReadContext) => Promise<Notification[]>\n\ntype Row = Record<string, unknown>\n\nconst isRow = (value: unknown): value is Row =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\nconst row = (value: unknown): Row => (isRow(value) ? value : {})\nconst str = (value: unknown): string | null =>\n typeof value === \"string\" ? value : typeof value === \"number\" ? String(value) : null\nconst strings = (value: unknown): string[] =>\n Array.isArray(value)\n ? value.map(str).filter((v): v is string => v !== null && v !== \"\")\n : typeof value === \"string\" && value !== \"\"\n ? [value]\n : []\nconst list = (value: unknown, key: string): Row[] => {\n const items = isRow(value) ? value[key] : value\n return Array.isArray(items) ? items.filter(isRow) : []\n}\nconst iso = (value: unknown): string => {\n if (typeof value === \"number\") return new Date(value < 1e11 ? value * 1000 : value).toISOString()\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value)))\n return new Date(value).toISOString()\n return new Date(0).toISOString()\n}\n\n/** `\"Acme\" <a@acme.test>` \u2192 `{ name: \"Acme\", address: \"a@acme.test\" }`. */\nexport const parseAddress = (value: string): Address => {\n const match = /^\\s*\"?([^\"<]*?)\"?\\s*<([^>]+)>\\s*$/.exec(value)\n if (match) return { name: match[1]?.trim() || null, address: (match[2] ?? \"\").trim() }\n return { name: null, address: value.trim() }\n}\n\nconst bare = (value: string): string => parseAddress(value).address.toLowerCase()\n\nconst stripHtml = (html: string): string =>\n html\n .replace(/<(style|script|head)[^>]*>[\\s\\S]*?<\\/\\1>/gi, \" \")\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \" \")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/[ \\t]+/g, \" \")\n .replace(/\\s*\\n\\s*/g, \"\\n\")\n .trim()\n\nconst preview = (text: string): string => text.replace(/\\s+/g, \" \").trim().slice(0, 240)\n\ntype Base = {\n context: ReadContext\n service: ServiceKind\n providerId: string\n to: string\n from: Address\n createdAt: string\n status?: string | null\n raw: unknown\n}\n\nconst base = (input: Base, channel: Channel) => ({\n id: `${input.context.source}:${input.context.namespace}:${input.providerId}${\n channel === \"email\" ? `#${input.to.toLowerCase()}` : \"\"\n }`,\n providerId: input.providerId,\n channel,\n source: input.context.source,\n service: input.service,\n namespace: input.context.namespace,\n to: input.to,\n from: input.from,\n createdAt: input.createdAt,\n status: input.status ?? null,\n raw: input.raw,\n})\n\nconst smsNotification = (\n input: Base,\n sms: Partial<SmsContent> & { body: string },\n): Notification => ({\n ...base(input, \"sms\"),\n preview: preview(sms.body),\n sms: { body: sms.body, code: sms.code ?? null, media: sms.media ?? [] },\n email: null,\n push: null,\n})\n\n/** One notification per mailbox: every `to`, `cc` and `bcc` recipient gets its own copy. */\nconst emailNotifications = (\n input: Omit<Base, \"to\">,\n recipients: string[],\n email: Partial<EmailContent> & { subject: string },\n): Notification[] => {\n const content: EmailContent = {\n subject: email.subject,\n html: email.html ?? null,\n text: email.text ?? null,\n cc: email.cc ?? [],\n bcc: email.bcc ?? [],\n replyTo: email.replyTo ?? [],\n attachments: email.attachments ?? [],\n headers: email.headers ?? {},\n }\n const body = content.text ?? (content.html ? stripHtml(content.html) : \"\")\n const seen = new Set<string>()\n return recipients.flatMap((recipient) => {\n const to = bare(recipient)\n if (!to || seen.has(to)) return []\n seen.add(to)\n return [\n {\n ...base({ ...input, to }, \"email\"),\n preview: preview(body),\n sms: null,\n email: content,\n push: null,\n },\n ]\n })\n}\n\nconst pushNotification = (input: Base, push: PushContent): Notification => ({\n ...base(input, \"push\"),\n preview: preview([push.title, push.body].filter(Boolean).join(\" \u2014 \")),\n sms: null,\n email: null,\n push,\n})\n\nconst twilio: Reader = async (context) => {\n const messages = list(await context.read(\"/outbox\"), \"messages\")\n return messages.flatMap((m): Notification[] => {\n const providerId = str(m.id) ?? str(m.sid) ?? \"\"\n const body = str(m.body) ?? \"\"\n const to = str(m.to) ?? \"\"\n const verify = m.kind === \"verify\"\n const sender = str(m.from) ?? str(m.messagingServiceSid) ?? (verify ? \"Verify\" : \"Twilio\")\n const common = {\n context,\n service: \"twilio\" as const,\n providerId,\n from: { name: verify && !m.from ? \"Verify\" : null, address: sender },\n createdAt: iso(m.createdAt),\n status: str(m.status),\n raw: m,\n }\n if (m.channel === \"email\")\n return emailNotifications(common, [to], {\n subject: \"Your verification code\",\n text: body,\n })\n return [smsNotification({ ...common, to }, { body, code: str(m.code) })]\n })\n}\n\nconst resend: Reader = async (context) =>\n list(await context.read(\"/outbox\"), \"messages\").flatMap((m) => {\n const cc = strings(m.cc)\n const bcc = strings(m.bcc)\n return emailNotifications(\n {\n context,\n service: \"resend\",\n providerId: str(m.id) ?? \"\",\n from: parseAddress(str(m.from) ?? \"\"),\n createdAt: iso(m.createdAt),\n status: m.scheduledAt ? \"scheduled\" : \"delivered\",\n raw: m,\n },\n [...strings(m.to), ...cc, ...bcc],\n {\n subject: str(m.subject) ?? \"\",\n html: str(m.html),\n text: str(m.text),\n cc,\n bcc,\n replyTo: strings(m.replyTo),\n headers: Object.fromEntries(Object.entries(row(m.headers)).map(([k, v]) => [k, String(v)])),\n attachments: list(m.attachments, \"\").map((a) => ({\n filename: str(a.filename) ?? \"attachment\",\n contentType: str(a.contentType),\n size: typeof a.size === \"number\" ? a.size : null,\n })),\n },\n )\n })\n\nconst platformOf = (value: unknown): PushPlatform =>\n value === \"android\" || value === \"ios\" || value === \"web\" ? value : \"unknown\"\n\nconst fcm: Reader = async (context) =>\n list(await context.read(\"/outbox\"), \"messages\").map((m) => {\n const wire = row(m.wire)\n const notification = row(m.notification ?? wire.notification)\n const android = row(row(m.android ?? wire.android).notification)\n const aps = row(row(row(m.apns ?? wire.apns).payload).aps)\n const alert = isRow(aps.alert) ? aps.alert : { body: aps.alert }\n const webpush = row(row(wire.webpush).notification)\n const platform = platformOf(m.platform)\n const pick = (key: \"title\" | \"body\") =>\n (platform === \"android\" ? str(android[key]) : null) ??\n (platform === \"ios\" ? str(alert[key]) : null) ??\n (platform === \"web\" ? str(webpush[key]) : null) ??\n str(notification[key])\n const image =\n (platform === \"android\" ? str(android.image) : null) ??\n str(row(row(m.apns ?? wire.apns).fcm_options).image) ??\n str(notification.image)\n const project = str(m.project) ?? \"app\"\n return pushNotification(\n {\n context,\n service: \"fcm\",\n providerId: str(m.id) ?? str(m.name) ?? \"\",\n to: str(m.token) ?? \"\",\n from: { name: project, address: str(m.name) ?? project },\n createdAt: iso(m.acceptedAt),\n status: str(m.state),\n raw: m,\n },\n {\n title: pick(\"title\"),\n body: pick(\"body\"),\n imageUrl: image,\n app: project,\n platform,\n data: Object.fromEntries(\n Object.entries(row(m.data ?? wire.data)).map(([k, v]) => [k, String(v)]),\n ),\n badge: typeof aps.badge === \"number\" ? aps.badge : null,\n sound: str(aps.sound) ?? str(android.sound),\n },\n )\n })\n\n/** Every record of a shared-runtime state collection, following `next` cursors. */\nconst stateRecords = async (read: AdminRead, collection: string): Promise<Row[]> => {\n const out: Row[] = []\n let after: unknown = null\n for (let page = 0; page < 100; page++) {\n const query = after === null ? \"\" : `&after=${encodeURIComponent(String(after))}`\n const result = row(await read(`/state/${collection}?limit=200&order=oldest${query}`))\n for (const record of list(result, \"records\")) out.push(record)\n if (result.next === null || result.next === undefined) break\n after = result.next\n }\n return out\n}\n\nconst ses: Reader = async (context) =>\n (await stateRecords(context.read, \"ses_messages\")).flatMap((record) => {\n const v = row(record.value)\n const destination = row(v.Destination)\n const common = {\n context,\n service: \"ses\" as const,\n providerId: str(v.MessageId) ?? str(record.id) ?? \"\",\n createdAt: iso(v.Timestamp),\n status: \"delivered\",\n raw: v,\n }\n const raw = row(v.RawMessage)\n if (raw.Data !== undefined) {\n const mime = parseMime(decodeRawMessage(str(raw.Data) ?? \"\"))\n const recipients = strings(v.Destinations)\n return emailNotifications(\n { ...common, from: parseAddress(str(v.Source) ?? mime.from ?? \"\") },\n recipients.length ? recipients : [...mime.to, ...mime.cc],\n {\n subject: mime.subject,\n html: mime.html,\n text: mime.text,\n cc: mime.cc,\n attachments: mime.attachments,\n headers: mime.headers,\n replyTo: addressList(mime.headers[\"reply-to\"]),\n },\n )\n }\n const message = row(v.Message)\n const body = row(message.Body)\n const cc = strings(destination.CcAddresses)\n const bcc = strings(destination.BccAddresses)\n return emailNotifications(\n { ...common, from: parseAddress(str(v.Source) ?? \"\") },\n [...strings(destination.ToAddresses), ...cc, ...bcc],\n {\n subject: str(row(message.Subject).Data) ?? \"\",\n html: str(row(body.Html).Data),\n text: str(row(body.Text).Data),\n cc,\n bcc,\n replyTo: strings(v.ReplyToAddresses),\n },\n )\n })\n\n/** SNS `MessageStructure: \"json\"` carries one body per protocol, with `default` as fallback. */\nconst snsBody = (v: Row, protocol: string): string => {\n const message = str(v.Message) ?? \"\"\n if (v.MessageStructure !== \"json\") return message\n try {\n const parsed = row(JSON.parse(message))\n return str(parsed[protocol]) ?? str(parsed.default) ?? message\n } catch {\n return message\n }\n}\n\nconst sns: Reader = async (context) => {\n const [messages, subscriptions] = await Promise.all([\n stateRecords(context.read, \"sns_messages\"),\n stateRecords(context.read, \"sns_subscriptions\"),\n ])\n return messages.flatMap((record): Notification[] => {\n const v = row(record.value)\n const providerId = str(v.MessageId) ?? str(record.id) ?? \"\"\n const common = { context, service: \"sns\" as const, createdAt: iso(v.Timestamp), raw: v }\n const phone = str(v.PhoneNumber)\n if (phone)\n return [\n smsNotification(\n {\n ...common,\n providerId,\n to: phone,\n from: { name: null, address: \"SNS\" },\n status: \"delivered\",\n },\n { body: snsBody(v, \"sms\") },\n ),\n ]\n const topicArn = str(v.TopicArn) ?? \"\"\n const topicName = topicArn.split(\":\").at(-1) ?? \"SNS\"\n return subscriptions.flatMap((sub): Notification[] => {\n const s = row(sub.value)\n if (s.TopicArn !== topicArn) return []\n const endpoint = str(s.Endpoint) ?? \"\"\n const subId = `${providerId}@${str(s.SubscriptionArn) ?? endpoint}`\n if (s.Protocol === \"sms\")\n return [\n smsNotification(\n {\n ...common,\n providerId: subId,\n to: endpoint,\n from: { name: topicName, address: topicName },\n status: \"delivered\",\n },\n { body: snsBody(v, \"sms\") },\n ),\n ]\n if (s.Protocol === \"email\" || s.Protocol === \"email-json\") {\n const text =\n s.Protocol === \"email-json\"\n ? JSON.stringify(\n {\n Type: \"Notification\",\n MessageId: providerId,\n TopicArn: topicArn,\n Subject: v.Subject ?? null,\n Message: snsBody(v, \"email-json\"),\n },\n null,\n 2,\n )\n : `${snsBody(v, \"email\")}\\n\\n--\\nIf you wish to stop receiving notifications from this topic, please unsubscribe.\\n\\nPlease do not reply directly to this email. If you have any questions or comments regarding this email, please contact us at https://aws.amazon.com/support`\n return emailNotifications(\n {\n ...common,\n providerId: subId,\n from: { name: \"AWS Notifications\", address: \"no-reply@sns.amazonaws.com\" },\n status: \"delivered\",\n },\n [endpoint],\n { subject: str(v.Subject) ?? \"AWS Notification Message\", text },\n )\n }\n return []\n })\n })\n}\n\nconst escapeHtml = (value: string): string =>\n value.replace(/[&<>\"']/g, (c) => `&#${c.charCodeAt(0)};`)\n\n/** Customer.io renders the template server side; the emulator keeps its id and data. */\nconst templatePreview = (m: Row): string => {\n const data = Object.entries(row(m.messageData))\n const rows = data\n .map(\n ([k, v]) =>\n `<tr><td style=\"padding:6px 12px;color:#6b7280;font:13px system-ui\">${escapeHtml(k)}</td><td style=\"padding:6px 12px;font:13px ui-monospace,monospace\">${escapeHtml(typeof v === \"string\" ? v : JSON.stringify(v))}</td></tr>`,\n )\n .join(\"\")\n const links = strings(m.links)\n .map(\n (href) =>\n `<p style=\"font:13px system-ui\"><a href=\"${escapeHtml(href)}\">${escapeHtml(href)}</a></p>`,\n )\n .join(\"\")\n return `<div style=\"font:14px system-ui;color:#111827;padding:8px\"><p style=\"margin:0 0 4px;color:#6b7280;font-size:12px\">Customer.io transactional message <b>${escapeHtml(str(m.transactionalMessageId) ?? \"\")}</b></p><p style=\"margin:0 0 12px;color:#6b7280;font-size:12px\">The template body is rendered by Customer.io; these are the <code>message_data</code> values it was sent with.</p>${rows ? `<table style=\"border-collapse:collapse;border:1px solid #e5e7eb;border-radius:8px\">${rows}</table>` : \"<p><i>No message_data.</i></p>\"}${links}</div>`\n}\n\nconst customerio: Reader = async (context) =>\n list(await context.read(\"/outbox\"), \"messages\").flatMap((m): Notification[] => {\n const identifiers = row(m.identifiers)\n const to = str(m.to) ?? str(identifiers.email) ?? str(identifiers.id) ?? \"\"\n const state = str(m.state)\n const common = {\n context,\n service: \"customerio\" as const,\n providerId: str(m.id) ?? \"\",\n createdAt: iso(m.createdAt),\n status: state,\n raw: m,\n }\n const templateId = str(m.transactionalMessageId) ?? \"message\"\n if (m.channel === \"sms\") {\n const data = row(m.messageData)\n const body =\n str(data.body) ??\n str(data.message) ??\n str(data.text) ??\n `[${templateId}] ${Object.entries(data)\n .map(([k, v]) => `${k}: ${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\", \")}`.trim()\n return [\n smsNotification(\n { ...common, to, from: { name: null, address: str(m.from) ?? \"Customer.io\" } },\n { body },\n ),\n ]\n }\n if (m.channel === \"email\")\n return emailNotifications(\n { ...common, from: parseAddress(str(m.from) ?? \"Customer.io <no-reply@customer.io>\") },\n [to],\n {\n subject: str(m.subject) ?? `Transactional message ${templateId}`,\n html: templatePreview(m),\n attachments: strings(m.attachments).map((filename) => ({\n filename,\n contentType: null,\n size: null,\n })),\n },\n )\n return []\n })\n\nconst mailosaurAddress = (value: unknown): string => {\n const a = row(value)\n return str(a.email) ?? str(a.phone) ?? str(a.phoneNumber) ?? \"\"\n}\n\nconst mailosaur: Reader = async (context) =>\n list(await context.read(\"/outbox\"), \"messages\").flatMap((entry): Notification[] => {\n const m = row(entry.message)\n const from = row(list(m.from, \"\")[0])\n const recipients = list(m.to, \"\").map(mailosaurAddress).filter(Boolean)\n const common = {\n context,\n service: \"mailosaur\" as const,\n providerId: str(entry.id) ?? str(m.id) ?? \"\",\n createdAt: iso(m.received ?? entry.createdAt),\n status: \"received\",\n raw: entry,\n }\n const html = str(row(m.html).body)\n const text = str(row(m.text).body)\n if (m.type === \"SMS\")\n return recipients.map((to) =>\n smsNotification(\n {\n ...common,\n to,\n from: { name: str(from.name) || null, address: mailosaurAddress(from) },\n },\n { body: text ?? (html ? stripHtml(html) : \"\") },\n ),\n )\n return emailNotifications(\n { ...common, from: { name: str(from.name) || null, address: mailosaurAddress(from) } },\n [...recipients, ...list(m.cc, \"\").map(mailosaurAddress)],\n {\n subject: str(m.subject) ?? \"\",\n html,\n text,\n cc: list(m.cc, \"\").map(mailosaurAddress),\n attachments: list(m.attachments, \"\").map((a) => ({\n filename: str(a.fileName) ?? str(a.filename) ?? \"attachment\",\n contentType: str(a.contentType),\n size: typeof a.length === \"number\" ? a.length : null,\n })),\n },\n )\n })\n\nexport const READERS: Record<ServiceKind, Reader> = {\n twilio,\n resend,\n fcm,\n ses,\n sns,\n customerio,\n mailosaur,\n}\n", "import { PAGE_STYLES, STYLES } from \"./styles.js\"\n\nconst escapeHtml = (value: string) => value.replace(/[&<>\"']/g, (c) => `&#${c.charCodeAt(0)};`)\n\n/** The harness shell. Everything inside `#app` is drawn by `/ui.js`. */\nexport const renderPage = ({ title }: { title: string }): string => `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"color-scheme\" content=\"dark\">\n<title>${escapeHtml(title)} \u00B7 Mockingbird</title>\n<link rel=\"icon\" href=\"data:image/svg+xml,${encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><rect width=\"32\" height=\"32\" rx=\"8\" fill=\"#0a84ff\"/><path d=\"M9 13a7 7 0 0 1 14 0v5l2 3H7l2-3z\" fill=\"#fff\"/><circle cx=\"16\" cy=\"24.5\" r=\"2.5\" fill=\"#fff\"/></svg>',\n)}\">\n<style>${PAGE_STYLES}${STYLES}</style>\n</head>\n<body>\n<div id=\"app\" data-title=\"${escapeHtml(title)}\"><div class=\"boot\">Loading notifications\u2026</div></div>\n<script type=\"module\" src=\"./ui.js\"></script>\n</body>\n</html>`\n", "import {\n asServiceKind,\n discoverFleet,\n type Endpoint,\n endpointsFromManifest,\n endpointsFromServices,\n type FetchLike,\n type FleetManifest,\n type ServiceInput,\n} from \"./discovery.js\"\nimport { BROWSER_JS } from \"./generated/browser.js\"\nimport {\n filterFromSearch,\n matches,\n type Notification,\n type NotificationFilter,\n SERVICE_KINDS,\n type SourceStatus,\n} from \"./model.js\"\nimport { READERS } from \"./sources.js\"\nimport { renderPage } from \"./ui/page.js\"\n\nexport type HarnessOptions = {\n /** A running fleet controller's `adminBase` (`http://127.0.0.1:9000/__admin/fleet`). */\n fleet?: string\n /** A fleet ready manifest, or a function that reads the current one (re-read on every sync). */\n manifest?: FleetManifest | (() => FleetManifest | Promise<FleetManifest>)\n /** Explicit emulators by name: base URLs, `{ url, adminUrl }`, or in-process runtimes. */\n services?: Record<string, ServiceInput>\n /**\n * Namespaces to watch in the background. `\"all\"` follows the fleet's namespace list.\n * Any namespace an API call or the UI asks for is watched from then on. Default `[\"default\"]`,\n * or `\"all\"` with `fleet`.\n */\n namespaces?: \"all\" | string[]\n /** Background polling interval. `0` turns it off; reads still sync on demand. Default 750 ms. */\n pollIntervalMs?: number\n /** Sent as `x-mockingbird-admin-key` to the fleet and every emulator. */\n adminKey?: string\n /** Transport for URL endpoints. Default: global `fetch`. */\n fetch?: FetchLike\n /** Page title. */\n title?: string\n}\n\nexport type WaitOptions = { timeoutMs?: number; count?: number }\n\nexport type NotificationHarness = {\n /** The harness UI and JSON API as a Fetch handler. */\n fetch(request: Request): Promise<Response>\n /** Read every emulator now. Resolves after a read that started after this call. */\n sync(namespace?: string): Promise<void>\n /** Notifications matching `filter`, oldest first, after a fresh sync. */\n list(filter?: NotificationFilter): Promise<Notification[]>\n /** Resolve once at least `count` (default 1) notifications match; reject after `timeoutMs`. */\n waitFor(filter: NotificationFilter, options?: WaitOptions): Promise<Notification[]>\n sources(): SourceStatus[]\n close(): void\n}\n\ntype Bucket = {\n notifications: Map<string, Notification>\n inFlight: Promise<void> | null\n queued: Promise<void> | null\n version: number\n}\n\nconst json = (status: number, body: unknown, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body, null, 2), {\n status,\n headers: { \"content-type\": \"application/json; charset=utf-8\", ...headers },\n })\n\nconst errorBody = (status: number, message: string) =>\n json(status, { error: { type: \"mockingbird_notifications\", message } })\n\nconst REDISCOVER_MS = 2_000\nconst DUPLICATE_WINDOW_MS = 10_000\n\n/** Mailosaur stores copies forwarded from Resend; show one message, not two. */\nconst fingerprint = (n: Notification) =>\n [\n n.channel,\n n.namespace,\n n.to.toLowerCase(),\n n.from.address.toLowerCase(),\n n.email?.subject ?? \"\",\n n.preview,\n ].join(\"\\u0000\")\n\nconst dedupe = (items: Notification[]): Notification[] => {\n const senders = new Map<string, number[]>()\n for (const n of items)\n if (n.service !== \"mailosaur\") {\n const key = fingerprint(n)\n senders.set(key, [...(senders.get(key) ?? []), Date.parse(n.createdAt)])\n }\n return items.filter((n) => {\n if (n.service !== \"mailosaur\") return true\n const at = Date.parse(n.createdAt)\n return !(senders.get(fingerprint(n)) ?? []).some((t) => Math.abs(t - at) <= DUPLICATE_WINDOW_MS)\n })\n}\n\nconst byTime = (a: Notification, b: Notification) =>\n a.createdAt === b.createdAt ? a.id.localeCompare(b.id) : a.createdAt < b.createdAt ? -1 : 1\n\nexport const createNotificationHarness = (options: HarnessOptions = {}): NotificationHarness => {\n if (!options.fleet && !options.manifest && !options.services)\n throw new Error(\"createNotificationHarness: pass fleet, manifest or services\")\n const fetchImpl: FetchLike = options.fetch ?? ((request) => fetch(request))\n const authHeaders: Record<string, string> = options.adminKey\n ? { \"x-mockingbird-admin-key\": options.adminKey }\n : {}\n const followAll = (options.namespaces ?? (options.fleet ? \"all\" : undefined)) === \"all\"\n const watched = new Set<string>(\n Array.isArray(options.namespaces) ? options.namespaces : [\"default\"],\n )\n const buckets = new Map<string, Bucket>()\n const statuses = new Map<string, SourceStatus>()\n const listeners = new Set<\n (event: { namespace: string; added: Notification[]; version: number }) => void\n >()\n const explicit = options.services ? endpointsFromServices(options.services, fetchImpl) : []\n let endpoints: Endpoint[] = explicit\n let discoveredAt = 0\n let discoveryError: string | null = null\n let discovering: Promise<void> | null = null\n /** Entries whose health route named a service the harness does not read (stripe, \u2026). */\n const rejected = new Set<string>()\n\n const rediscover = async (force = false) => {\n if (!options.fleet && !options.manifest) return\n if (!force && Date.now() - discoveredAt < REDISCOVER_MS) return\n discovering ??= (async () => {\n try {\n let found: Endpoint[] = []\n if (options.fleet) {\n const fleet = await discoverFleet(options.fleet, fetchImpl, authHeaders)\n found = fleet.endpoints\n if (followAll) for (const ns of fleet.namespaces) watched.add(ns)\n } else if (options.manifest) {\n const manifest =\n typeof options.manifest === \"function\" ? await options.manifest() : options.manifest\n found = endpointsFromManifest(manifest, fetchImpl)\n }\n // Keep what we learned from health probes across rediscovery.\n const known = new Map(endpoints.map((e) => [`${e.name}|${e.adminUrl}`, e.service]))\n endpoints = [\n ...explicit,\n ...found\n .filter(\n (e) =>\n !explicit.some((x) => x.name === e.name) &&\n !rejected.has(`${e.name}|${e.adminUrl}`),\n )\n .map((e) => ({\n ...e,\n service: e.service ?? known.get(`${e.name}|${e.adminUrl}`) ?? null,\n })),\n ]\n discoveryError = null\n } catch (error) {\n discoveryError = error instanceof Error ? error.message : String(error)\n } finally {\n discoveredAt = Date.now()\n discovering = null\n }\n })()\n await discovering\n }\n\n const adminGet = (endpoint: Endpoint, namespace: string) => async (path: string) => {\n const response = await endpoint.fetch(\n new Request(`${endpoint.adminUrl}${path}`, {\n headers: {\n ...authHeaders,\n \"x-mockingbird-namespace\": namespace,\n accept: \"application/json\",\n },\n }),\n )\n if (!response.ok) {\n const text = await response.text().catch(() => \"\")\n throw new Error(`GET ${path}: HTTP ${response.status} ${text.slice(0, 200)}`)\n }\n return response.json() as Promise<unknown>\n }\n\n /** Learn what an unnamed emulator is from its health route (`{ service: \"fcm\" }`). */\n const identify = async (endpoint: Endpoint): Promise<void> => {\n if (endpoint.service) return\n const health = (await adminGet(endpoint, \"default\")(\"/health\")) as { service?: unknown }\n endpoint.service = asServiceKind(health.service)\n if (!endpoint.service) throw new Error(`not a messaging emulator (${String(health.service)})`)\n }\n\n const bucket = (namespace: string): Bucket => {\n let b = buckets.get(namespace)\n if (!b) {\n b = { notifications: new Map(), inFlight: null, queued: null, version: 0 }\n buckets.set(namespace, b)\n }\n return b\n }\n\n const readAll = async (namespace: string) => {\n await rediscover()\n const results = await Promise.all(\n endpoints.map(async (endpoint) => {\n const key = endpoint.name\n const status: SourceStatus = statuses.get(key) ?? {\n name: endpoint.name,\n service: endpoint.service,\n url: endpoint.adminUrl,\n ok: false,\n error: null,\n count: 0,\n lastSyncAt: null,\n }\n statuses.set(key, status)\n try {\n await identify(endpoint)\n const service = endpoint.service\n if (!service) return { ok: false as const }\n const items = await READERS[service]({\n source: endpoint.name,\n namespace,\n read: adminGet(endpoint, namespace),\n })\n Object.assign(status, {\n service,\n url: endpoint.adminUrl,\n ok: true,\n error: null,\n lastSyncAt: new Date().toISOString(),\n })\n return { ok: true as const, items }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n // An emulator that answers but is not a messaging one is simply not shown.\n if (message.startsWith(\"not a messaging emulator\")) {\n statuses.delete(key)\n rejected.add(`${endpoint.name}|${endpoint.adminUrl}`)\n endpoints = endpoints.filter((e) => e !== endpoint)\n return { ok: false as const }\n }\n Object.assign(status, { url: endpoint.adminUrl, ok: false, error: message })\n discoveredAt = 0\n return { ok: false as const, source: endpoint.name }\n }\n }),\n )\n const b = bucket(namespace)\n const failed = new Set(results.flatMap((r) => (\"source\" in r && r.source ? [r.source] : [])))\n const fresh = dedupe(results.flatMap((r) => (r.ok ? r.items : [])))\n const next = new Map<string, Notification>()\n // A source that failed this round keeps what it last showed rather than blinking out.\n for (const n of b.notifications.values()) if (failed.has(n.source)) next.set(n.id, n)\n for (const n of fresh) next.set(n.id, n)\n const added = [...next.values()].filter((n) => !b.notifications.has(n.id)).sort(byTime)\n const removed = [...b.notifications.keys()].some((id) => !next.has(id))\n const changed =\n added.length > 0 ||\n removed ||\n [...next.values()].some((n) => b.notifications.get(n.id)?.status !== n.status)\n b.notifications = next\n for (const status of statuses.values())\n status.count = [...buckets.values()].reduce(\n (sum, bk) =>\n sum + [...bk.notifications.values()].filter((n) => n.source === status.name).length,\n 0,\n )\n if (changed) {\n b.version++\n for (const listener of listeners) listener({ namespace, added, version: b.version })\n }\n }\n\n const sync = (namespace = \"default\"): Promise<void> => {\n watched.add(namespace)\n const b = bucket(namespace)\n if (!b.inFlight) {\n b.inFlight = readAll(namespace).finally(() => {\n b.inFlight = null\n })\n return b.inFlight\n }\n // A read is running but may have started before the caller's send; queue one more.\n b.queued ??= b.inFlight.then(() => {\n b.queued = null\n return sync(namespace)\n })\n return b.queued\n }\n\n const list = async (filter: NotificationFilter = {}) => {\n const namespace = filter.namespace ?? \"default\"\n await sync(namespace)\n return [...bucket(namespace).notifications.values()]\n .filter((n) => matches(n, { ...filter, namespace }))\n .sort(byTime)\n }\n\n const waitFor = async (filter: NotificationFilter, wait: WaitOptions = {}) => {\n const timeoutMs = wait.timeoutMs ?? 10_000\n const count = wait.count ?? 1\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const found = await list(filter)\n if (found.length >= count) return found\n if (Date.now() >= deadline) {\n const error = new Error(\n `timed out after ${timeoutMs}ms waiting for ${count} notification(s) matching ${JSON.stringify(filter)}; found ${found.length}`,\n )\n Object.assign(error, { found })\n throw error\n }\n await new Promise((resolve) =>\n setTimeout(resolve, Math.min(100, Math.max(0, deadline - Date.now()))),\n )\n }\n }\n\n const interval = options.pollIntervalMs ?? 750\n const timer =\n interval > 0\n ? setInterval(() => {\n for (const namespace of watched) void sync(namespace).catch(() => {})\n }, interval)\n : null\n ;(timer as { unref?: () => void } | null)?.unref?.()\n\n const events = (namespace: string, signal: AbortSignal) => {\n watched.add(namespace)\n const encoder = new TextEncoder()\n let cleanup = () => {}\n return new ReadableStream<Uint8Array>({\n start(controller) {\n const send = (event: string, data: unknown) => {\n try {\n controller.enqueue(encoder.encode(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`))\n } catch {\n cleanup()\n }\n }\n const listener = (event: { namespace: string; added: Notification[]; version: number }) => {\n if (event.namespace === namespace) send(\"change\", event)\n }\n listeners.add(listener)\n const heartbeat = setInterval(() => send(\"sources\", [...statuses.values()]), 2_000)\n cleanup = () => {\n listeners.delete(listener)\n clearInterval(heartbeat)\n }\n signal.addEventListener(\"abort\", () => {\n cleanup()\n try {\n controller.close()\n } catch {}\n })\n send(\"hello\", { namespace, version: bucket(namespace).version })\n void sync(namespace).catch(() => {})\n },\n cancel() {\n cleanup()\n },\n })\n }\n\n const namespacesList = () => [...new Set([...watched, ...buckets.keys()])].sort()\n\n const handle = async (request: Request): Promise<Response> => {\n const url = new URL(request.url)\n const path = url.pathname.replace(/\\/+$/, \"\") || \"/\"\n if (request.method !== \"GET\" && request.method !== \"HEAD\")\n return errorBody(405, \"the notification harness is read-only\")\n if (path === \"/\" || path === \"/index.html\")\n return new Response(renderPage({ title: options.title ?? \"Notifications\" }), {\n headers: { \"content-type\": \"text/html; charset=utf-8\", \"cache-control\": \"no-store\" },\n })\n if (path === \"/ui.js\")\n return new Response(BROWSER_JS, {\n headers: { \"content-type\": \"text/javascript; charset=utf-8\", \"cache-control\": \"no-store\" },\n })\n if (path === \"/api/health\") return json(200, { status: \"ok\", sources: [...statuses.values()] })\n if (path === \"/api/sources\") {\n await rediscover()\n return json(200, {\n discoveryError,\n sources: endpoints.map(\n (e) =>\n statuses.get(e.name) ?? {\n name: e.name,\n service: e.service,\n url: e.adminUrl,\n ok: false,\n error: null,\n count: 0,\n lastSyncAt: null,\n },\n ),\n services: SERVICE_KINDS,\n })\n }\n if (path === \"/api/namespaces\") {\n await rediscover()\n return json(200, { namespaces: namespacesList() })\n }\n let filter: NotificationFilter\n try {\n filter = filterFromSearch(url.searchParams)\n } catch (error) {\n return errorBody(400, error instanceof Error ? error.message : String(error))\n }\n const namespace = filter.namespace ?? \"default\"\n if (path === \"/api/events\")\n return new Response(events(namespace, request.signal), {\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store\",\n connection: \"keep-alive\",\n },\n })\n if (path === \"/api/notifications\") {\n const found = await list(filter)\n if (url.searchParams.get(\"order\") === \"newest\") found.reverse()\n return json(200, { namespace, version: bucket(namespace).version, notifications: found })\n }\n if (path === \"/api/notifications/latest\") {\n const found = await list(filter)\n const latest = found.at(-1)\n return latest ? json(200, latest) : errorBody(404, \"no notification matches\")\n }\n if (path === \"/api/wait\") {\n const timeoutMs = Number(url.searchParams.get(\"timeoutMs\") ?? 10_000)\n const count = Number(url.searchParams.get(\"count\") ?? 1)\n if (!Number.isFinite(timeoutMs) || timeoutMs < 0 || timeoutMs > 120_000)\n return errorBody(400, \"timeoutMs: expected 0\u2013120000\")\n if (!Number.isInteger(count) || count < 1)\n return errorBody(400, \"count: expected a positive integer\")\n try {\n return json(200, { namespace, notifications: await waitFor(filter, { timeoutMs, count }) })\n } catch (error) {\n return json(408, {\n error: {\n type: \"mockingbird_notifications\",\n message: error instanceof Error ? error.message : String(error),\n },\n notifications: (error as { found?: unknown }).found ?? [],\n })\n }\n }\n const one = /^\\/api\\/notifications\\/(.+)$/.exec(path)\n if (one) {\n const id = decodeURIComponent(one[1] ?? \"\")\n const ns = id.split(\":\")[1] ?? namespace\n await sync(ns)\n const found = bucket(ns).notifications.get(id)\n return found ? json(200, found) : errorBody(404, `no notification ${id}`)\n }\n return errorBody(404, `no route ${path}`)\n }\n\n return {\n fetch: async (request) => {\n try {\n return await handle(request)\n } catch (error) {\n return errorBody(500, error instanceof Error ? error.message : String(error))\n }\n },\n sync,\n list,\n waitFor,\n sources: () => [...statuses.values()],\n close: () => {\n if (timer) clearInterval(timer)\n listeners.clear()\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["base", "escapeHtml", "list"]
|
|
7
|
+
}
|