@8ux-co/eelzap 0.10.1 → 0.10.2
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/CHANGELOG.md +17 -1
- package/dist/{chunk-7ZPXZZUT.js → chunk-4ET7VBJA.js} +60 -6
- package/dist/chunk-4ET7VBJA.js.map +1 -0
- package/dist/{chunk-7CXQK2PR.js → chunk-T6S3S5RH.js} +2 -2
- package/dist/{chunk-7CXQK2PR.js.map → chunk-T6S3S5RH.js.map} +1 -1
- package/dist/preview.js +6 -3
- package/dist/preview.js.map +1 -1
- package/dist/react.js +2 -2
- package/dist/react.js.map +1 -1
- package/dist/{signin-QT7YANBN.js → signin-XOGBCGBL.js} +4 -8
- package/dist/signin-XOGBCGBL.js.map +1 -0
- package/dist/{suggest-JZ63L3WP.js → suggest-KLS6B7AM.js} +467 -75
- package/dist/suggest-KLS6B7AM.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-7ZPXZZUT.js.map +0 -1
- package/dist/signin-QT7YANBN.js.map +0 -1
- package/dist/suggest-JZ63L3WP.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/preview/site/messages.ts","../src/preview/site/oauth.ts","../src/preview/site/ui.ts"],"sourcesContent":["/**\n * The site tools' own words («Editar» and «Comentar», zap-cms-v2 §3.4), Spanish and English (Spanish by default, as\n * the suite; `<html lang=\"en…\">` or `initZap({ locale: 'en' })` picks\n * English). Two objects, one per chunk, so each chunk carries only its own\n * copy. Plain strings and functions: the core has no i18n runtime, and these\n * never reach the server. Copy rules (`.docs/ui-patterns/copy.md`): no\n * ellipses, em dashes, middots or parentheses.\n */\n\ntype Locale = 'es' | 'en'\n\nconst plural = (count: number, one: string, other: string) =>\n (count === 1 ? one : other).replace('{n}', String(count))\n\nexport const SIGNIN_MESSAGES = {\n es: {\n launcher: 'Editar o comentar',\n hintBefore: 'Pulsa',\n hintAfter: 'para editar o comentar',\n title: 'Edita o comenta esta página',\n body: 'Escribe sobre el texto de la página o deja un comentario. Lo que edites queda en el borrador y se publica desde Zap.',\n signIn: 'Entrar con Eel',\n note: 'Solo para personas con Zap en este sitio. Los visitantes no ven nada de esto.',\n waiting: 'Esperando a Eel',\n waitingHelp: 'Termina en la ventana de Eel. Si la cerraste, vuelve a intentarlo.',\n retry: 'Intentar de nuevo',\n close: 'Cerrar',\n expired: 'Tu sesión terminó. Entra de nuevo para seguir.',\n failed: 'No pudimos completar la entrada. Intenta de nuevo.',\n },\n en: {\n launcher: 'Edit or comment',\n hintBefore: 'Press',\n hintAfter: 'to edit or comment',\n title: 'Edit or comment on this page',\n body: 'Type over the text on the page or leave a comment. What you edit goes to the draft and is published from Zap.',\n signIn: 'Sign in with Eel',\n note: 'Only for people with Zap on this site. Visitors see none of this.',\n waiting: 'Waiting for Eel',\n waitingHelp: 'Finish in the Eel window. If you closed it, try again.',\n retry: 'Try again',\n close: 'Close',\n expired: 'Your session ended. Sign in again to keep going.',\n failed: 'We could not finish signing you in. Try again.',\n },\n} satisfies Record<Locale, Record<string, string>>\n\nexport const SUGGEST_MESSAGES = {\n es: {\n toolbar: 'Zap en esta página',\n move: 'Mover la barra',\n moveTip: 'Arrastra para mover la barra',\n tools: 'Herramienta',\n navigate: 'Navegar',\n edit: 'Editar',\n comment: 'Comentar',\n editOff: 'Desactivado por un administrador',\n open: (n: number) => plural(n, '{n} abierto', '{n} abiertos'),\n openTitle: 'Comentarios abiertos en esta página',\n noneOpen: 'No hay comentarios abiertos en esta página.',\n changeRequest: 'Solicitud de cambio',\n exit: 'Salir',\n account: (name: string) => `${name}, cuenta`,\n accountMenu: 'Cuenta',\n openInZap: 'Abrir en Zap',\n signOut: 'Cerrar sesión en Zap',\n hide: 'Ocultar barra',\n show: 'Mostrar barra',\n showBar: (n: number) =>\n plural(n, 'Mostrar la barra de Zap, {n} abierto', 'Mostrar la barra de Zap, {n} abiertos'),\n paused: 'Vista previa pausada',\n pausedRunaway: 'La página no dejaba de crecer, así que dejamos de actualizarla.',\n pausedCap: 'La página tiene demasiados campos para seguirlos.',\n reload: 'Recargar',\n newComment: 'Nuevo comentario',\n commentTitle: 'Comentario',\n selected: (n: number) => plural(n, '{n} elemento seleccionado', '{n} elementos seleccionados'),\n clearSelection: 'Cancelar',\n commentLabel: 'Comentario',\n commentPlaceholder: 'Escribe tu comentario',\n requestChange: 'Solicitar cambio',\n requestHelp: 'Queda abierta hasta que alguien la resuelva o aplique el texto propuesto.',\n recipient: 'La recibe la persona responsable en Zap.',\n propose: 'Proponer texto',\n proposalFor: 'Texto propuesto para',\n removeProposal: 'Quitar texto propuesto',\n now: 'Ahora:',\n proposal: 'Texto propuesto',\n cancel: 'Cancelar',\n close: 'Cerrar',\n sending: 'Enviando',\n save: 'Guardar',\n sentComment: 'Comentario enviado',\n sentCommentBody: 'Tu equipo lo verá en Zap.',\n sentRequest: 'Solicitud de cambio enviada',\n sentRequestBody: (name: string | null, proposal: boolean) =>\n `${name ? `${name} la verá` : 'La persona responsable la verá'} en Zap${\n proposal ? ' con tu texto propuesto' : ''\n }. La página no cambia hasta que se publique.`,\n saving: 'Guardando',\n saved: 'Guardado en el borrador',\n notEditable: 'Esto no se edita aquí',\n notEditableBody: 'Usa Comentar para pedir el cambio.',\n inRecord: (name: string) => `en ${name}`,\n noFields: 'No hay campos para editar aquí',\n noFieldsBody:\n 'Esta página no marca sus campos. Ábrela desde la vista previa de Zap o usa Comentar.',\n editOffBody: 'Un administrador desactivó Editar en este sitio.',\n renewed: 'Sesión renovada',\n renewedAs: (name: string) => `Sigues como ${name}`,\n renewedBody: 'Sigues donde ibas.',\n dismiss: 'Cerrar aviso',\n someone: 'Alguien',\n refusedTitle: 'No puedes editar ni comentar en este sitio',\n refusedBody: 'Tu cuenta no tiene acceso a Zap aquí, o el sitio dejó de permitirlo.',\n rateLimited: (n: number) =>\n plural(\n n,\n 'Enviaste muchos seguidos. Intenta de nuevo en {n} segundo.',\n 'Enviaste muchos seguidos. Intenta de nuevo en {n} segundos.',\n ),\n failed: 'No se pudo enviar. Revisa el texto e intenta de nuevo.',\n saveFailed: 'No se pudo guardar. El texto volvió a como estaba.',\n noRecord: 'Esta parte de la página no es contenido de Zap.',\n invalidNumber: 'Escribe un número.',\n },\n en: {\n toolbar: 'Zap on this page',\n move: 'Move the bar',\n moveTip: 'Drag to move the bar',\n tools: 'Tool',\n navigate: 'Browse',\n edit: 'Edit',\n comment: 'Comment',\n editOff: 'Turned off by an administrator',\n open: (n: number) => plural(n, '{n} open', '{n} open'),\n openTitle: 'Open comments on this page',\n noneOpen: 'No open comments on this page.',\n changeRequest: 'Change request',\n exit: 'Sign out',\n account: (name: string) => `${name}, account`,\n accountMenu: 'Account',\n openInZap: 'Open in Zap',\n signOut: 'Sign out of Zap',\n hide: 'Hide the bar',\n show: 'Show the bar',\n showBar: (n: number) => plural(n, 'Show the Zap bar, {n} open', 'Show the Zap bar, {n} open'),\n paused: 'Preview paused',\n pausedRunaway: 'The page kept growing, so we stopped updating it.',\n pausedCap: 'The page has too many fields to follow.',\n reload: 'Reload',\n newComment: 'New comment',\n commentTitle: 'Comment',\n selected: (n: number) => plural(n, '{n} element selected', '{n} elements selected'),\n clearSelection: 'Cancel',\n commentLabel: 'Comment',\n commentPlaceholder: 'Write your comment',\n requestChange: 'Request a change',\n requestHelp: 'It stays open until someone resolves it or applies the proposed text.',\n recipient: 'The person responsible in Zap receives it.',\n propose: 'Propose text',\n proposalFor: 'Proposed text for',\n removeProposal: 'Remove proposed text',\n now: 'Now:',\n proposal: 'Proposed text',\n cancel: 'Cancel',\n close: 'Close',\n sending: 'Sending',\n save: 'Save',\n sentComment: 'Comment sent',\n sentCommentBody: 'Your team will see it in Zap.',\n sentRequest: 'Change request sent',\n sentRequestBody: (name: string | null, proposal: boolean) =>\n `${name ?? 'The person responsible'} will see it in Zap${\n proposal ? ' with your proposed text' : ''\n }. The page does not change until it is published.`,\n saving: 'Saving',\n saved: 'Saved to the draft',\n notEditable: 'This is not edited here',\n notEditableBody: 'Use Comment to ask for the change.',\n inRecord: (name: string) => `in ${name}`,\n noFields: 'Nothing to edit here',\n noFieldsBody:\n 'This page does not mark its fields. Open it from the Zap preview or use Comment.',\n editOffBody: 'An administrator turned off Edit for this site.',\n renewed: 'Session renewed',\n renewedAs: (name: string) => `You are still ${name}`,\n renewedBody: 'Pick up where you left off.',\n dismiss: 'Dismiss',\n someone: 'Someone',\n refusedTitle: 'You cannot edit or comment on this site',\n refusedBody: 'Your account has no Zap access here, or the site stopped allowing it.',\n rateLimited: (n: number) =>\n plural(\n n,\n 'You sent many in a row. Try again in {n} second.',\n 'You sent many in a row. Try again in {n} seconds.',\n ),\n failed: 'Could not send. Check the text and try again.',\n saveFailed: 'Could not save. The text is back to what it was.',\n noRecord: 'This part of the page is not Zap content.',\n invalidNumber: 'Enter a number.',\n },\n}\n\nexport type SuggestMessages = (typeof SUGGEST_MESSAGES)['es']\nexport type SigninMessages = (typeof SIGNIN_MESSAGES)['es']\n","import {\n PENDING_STORAGE_KEY,\n SITE_CLIENT_SCOPE,\n STATE_PREFIX,\n type CallbackParams,\n type SiteContext,\n} from './config'\nimport { REFRESH_LIFETIME_MS, type SiteToken } from './token'\n\n/**\n * The site client's side of OAuth 2.1 with Nest (ADR 024, ADR 041): a public\n * client, PKCE S256, `state`, and an `iss` check (RFC 9207). Pure functions\n * plus the one `fetch`, so every refusal is a unit spec.\n *\n * - `state` is `zap1.<128 random bits>` for the popup, and\n * `zap1.<random>.<return path>` for the full-page redirect (spec §3.4 step 4:\n * \"the return path in `state`\"). The callback must bring back EXACTLY the\n * state this tab minted; the return path is honoured only as a same-origin\n * path.\n * - `iss` must equal the compiled-in issuer exactly.\n * - The code is exchanged once, with the verifier only this tab holds, as a\n * form POST with no custom header (no preflight; Nest answers CORS to the\n * client's own redirect origins only) and no cookies.\n * - Nest answers an hour of access and, since ADR 041's amendment of\n * 2026-10-06, a short rotating refresh token (eight hours, redeemable only\n * inside the remembered consent and from this origin). Both are kept in\n * `sessionStorage` only (`token.ts`); `session.ts` spends the refresh.\n */\n\nexport interface PendingSignIn {\n state: string\n verifier: string\n mode: 'popup' | 'redirect'\n}\n\nexport type CallbackProblem = 'state' | 'iss' | 'code'\n\nfunction base64url(bytes: Uint8Array): string {\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction randomToken(win: Window, size: number): string {\n return base64url(win.crypto.getRandomValues(new Uint8Array(size)))\n}\n\n/** A 43-character verifier (32 random bytes), RFC 7636 §4.1. */\nexport function createVerifier(win: Window): string {\n return randomToken(win, 32)\n}\n\n/** `BASE64URL(SHA256(verifier))`, RFC 7636 §4.2. */\nexport async function challengeFor(win: Window, verifier: string): Promise<string> {\n const digest = await win.crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))\n return base64url(new Uint8Array(digest))\n}\n\n/** A same-origin path: one leading slash, no scheme, no `//host`, no backslash tricks. */\nexport function isReturnPath(value: string): boolean {\n return /^\\/(?![/\\\\])/.test(value) && !/[\\\\\\s]/.test(value) && value.length <= 2048\n}\n\nexport function createState(win: Window, returnPath?: string): string {\n const nonce = randomToken(win, 16)\n if (returnPath === undefined || !isReturnPath(returnPath)) return `${STATE_PREFIX}${nonce}`\n return `${STATE_PREFIX}${nonce}.${base64url(new TextEncoder().encode(returnPath))}`\n}\n\n/** The return path a redirect `state` carries, or null. */\nexport function returnPathOf(state: string): string | null {\n const encoded = state.slice(STATE_PREFIX.length).split('.')[1]\n if (!encoded) return null\n try {\n const binary = atob(encoded.replace(/-/g, '+').replace(/_/g, '/'))\n const path = new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))\n return isReturnPath(path) ? path : null\n } catch {\n return null\n }\n}\n\nexport function authorizeUrl(\n ctx: Pick<SiteContext, 'authOrigin' | 'clientId' | 'redirectUri'>,\n state: string,\n challenge: string,\n): string {\n const url = new URL('/oauth/authorize', ctx.authOrigin)\n url.search = new URLSearchParams({\n response_type: 'code',\n client_id: ctx.clientId,\n redirect_uri: ctx.redirectUri,\n code_challenge: challenge,\n code_challenge_method: 'S256',\n state,\n scope: SITE_CLIENT_SCOPE,\n }).toString()\n return url.toString()\n}\n\n/**\n * Null when the callback answers `pending`; otherwise what is wrong with it.\n * Exact comparisons only: a callback for another sign-in (another tab, an\n * attacker's code pushed at us) has another state; a code from another\n * issuer has another `iss`.\n */\nexport function checkCallback(\n callback: Partial<CallbackParams> | null | undefined,\n pending: PendingSignIn | null,\n authOrigin: string,\n): CallbackProblem | null {\n if (!pending || !callback || callback.state !== pending.state) return 'state'\n if (callback.iss !== authOrigin) return 'iss'\n if (typeof callback.code !== 'string' || !callback.code || callback.code.length > 512) {\n return 'code'\n }\n return null\n}\n\nexport class ExchangeError extends Error {\n constructor(readonly status: number) {\n super(`token exchange failed (${status})`)\n this.name = 'ExchangeError'\n }\n}\n\n/** Trade the code for the access token (and its refresh token). Never sends cookies. */\nexport async function exchangeCode(\n ctx: Pick<SiteContext, 'win' | 'authOrigin' | 'clientId' | 'redirectUri' | 'siteId'>,\n code: string,\n verifier: string,\n now = Date.now(),\n): Promise<SiteToken> {\n const response = await ctx.win.fetch(`${ctx.authOrigin}/api/oauth/token`, {\n method: 'POST',\n credentials: 'omit',\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n client_id: ctx.clientId,\n redirect_uri: ctx.redirectUri,\n code_verifier: verifier,\n }),\n })\n if (!response.ok) throw new ExchangeError(response.status)\n return readTokenAnswer(response, ctx.siteId, now)\n}\n\n/**\n * The token endpoint's answer, checked: an `eel_at_` token and its lifetime\n * (at most the hour the ADR promises, whatever the answer claims), and the\n * `eel_rt_` refresh token when there is one (eight hours at most).\n */\nexport async function readTokenAnswer(\n response: Response,\n siteId: string,\n now = Date.now(),\n): Promise<SiteToken> {\n const body = (await response.json().catch(() => null)) as {\n access_token?: unknown\n expires_in?: unknown\n refresh_token?: unknown\n } | null\n const token = body?.access_token\n const expiresIn = body?.expires_in\n if (\n typeof token !== 'string' ||\n !/^eel_at_[A-Za-z0-9_-]{8,200}$/.test(token) ||\n typeof expiresIn !== 'number' ||\n !(expiresIn > 0)\n ) {\n throw new ExchangeError(502)\n }\n const refresh = body?.refresh_token\n const withRefresh =\n typeof refresh === 'string' && /^eel_rt_[A-Za-z0-9_-]{8,200}$/.test(refresh)\n ? { refresh, rexp: now + REFRESH_LIFETIME_MS }\n : {}\n return { token, exp: now + Math.min(expiresIn, 3600) * 1000, site: siteId, ...withRefresh }\n}\n\n// ── The pending full-page sign-in (sessionStorage, this tab only) ───────────\n\nexport function savePending(win: Window, pending: PendingSignIn): void {\n try {\n win.sessionStorage.setItem(PENDING_STORAGE_KEY, JSON.stringify(pending))\n } catch {\n // Blocked storage: the redirect cannot be finished; the popup path still works.\n }\n}\n\n/** Read AND forget: a pending sign-in is good for one callback. */\nexport function takePending(win: Window): PendingSignIn | null {\n try {\n const raw = win.sessionStorage.getItem(PENDING_STORAGE_KEY)\n win.sessionStorage.removeItem(PENDING_STORAGE_KEY)\n const value = raw ? (JSON.parse(raw) as Partial<PendingSignIn>) : null\n if (\n value &&\n typeof value.state === 'string' &&\n typeof value.verifier === 'string' &&\n (value.mode === 'popup' || value.mode === 'redirect')\n ) {\n return { state: value.state, verifier: value.verifier, mode: value.mode }\n }\n } catch {\n // Nothing usable.\n }\n return null\n}\n","/**\n * The site tools' building blocks, shared by the `signin` and `suggest`\n * chunks (zap-cms-v2 §2.7, §7.3):\n *\n * - **A closed Shadow DOM** on a custom element appended to `<html>`, styled\n * `all: initial` with `!important` inline, so the site's CSS cannot restyle\n * it, it cannot restyle the site, and site scripts get no `shadowRoot`.\n * - **Eel tokens inlined** (`TOKENS`): the boards' colours, radii and Poppins\n * with system fallbacks; nothing is fetched.\n * - **Text only.** `el()` takes text as text: strings become text nodes, never\n * markup. The single `innerHTML` is `icon()`, which reads a constant SVG from\n * `ICONS` by name; no network string ever reaches it.\n */\n\nexport const SITE_HOST_TAG = 'eel-zap-site'\n\nconst ZAP_BOLT =\n '<svg viewBox=\"0 0 512 512\"><g transform=\"matrix(27.611111,0,0,24.833333,-74.833333,-42)\"><path d=\"M13,2L3,14L10.036,11.906L10,22L20.964,9.235L12.913,11.973L13,2Z\" fill=\"#F1A10D\" stroke=\"#F1A10D\" stroke-width=\"0.5\"/><path d=\"M13,2L6.518,12.953L10.036,11.906L12.913,11.973L13,2Z\" fill=\"#FFC03A\"/><path d=\"M10.036,11.906L10,22L20.964,9.235L12.913,11.973L10.036,11.906Z\" fill=\"#D98A05\"/><path d=\"M10,22L20.964,9.235L16.939,10.604L10,22Z\" fill=\"#BF7500\"/></g></svg>'\n\nconst EEL_MARK =\n '<svg viewBox=\"0 0 3000 3000\" fill=\"currentColor\"><g transform=\"matrix(1.01772,-0.122618,0.122163,1.013948,-241.899218,117.348723)\"><g transform=\"matrix(1.192409,0,0,1.144788,-367.077609,-248.030951)\"><path d=\"M2789.774,1920.921C2642.929,2454.806 2170.478,2846 1611,2846C934.352,2846 385,2273.795 385,1569C385,864.205 934.352,292 1611,292C1849.726,292 2072.607,363.224 2261.109,486.366C2132.562,436.833 1991.613,409.484 1843.83,409.484C1242.576,409.484 754.435,862.18 754.435,1419.774C754.435,1977.368 1242.576,2430.064 1843.83,2430.064C2248.492,2430.064 2601.918,2225.006 2789.774,1920.921Z\"/></g><g transform=\"matrix(1.434867,0,-0,0.933341,-1232.183743,68.591241)\"><path d=\"M2196.648,369.772C2557.019,431.746 2832,753.678 2832,1141C2832,1572.598 2490.559,1923 2070,1923C1813.847,1923 1587.045,1793.01 1448.867,1593.857C1561.131,1687.675 1700.963,1743.353 1852.482,1743.353C2222.082,1743.353 2522.15,1412.061 2522.15,1004.003C2522.15,734.845 2391.596,499.086 2196.648,369.772Z\"/></g></g></svg>'\n\nconst stroke = (paths: string) =>\n `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${paths}</svg>`\n\n/** Constant markup only. Adding an icon means adding a literal here. */\nexport const ICONS = {\n zap: ZAP_BOLT,\n eel: EEL_MARK,\n x: stroke('<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>'),\n lock: stroke(\n '<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>',\n ),\n pointer: stroke(\n '<path d=\"M12.586 12.586 19 19\"/><path d=\"M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z\"/>',\n ),\n pencil: stroke(\n '<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/>',\n ),\n commentPlus: stroke(\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/><path d=\"M12 7v6\"/><path d=\"M9 10h6\"/>',\n ),\n thread: stroke(\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/><path d=\"M13 8H7\"/><path d=\"M17 12H7\"/>',\n ),\n exit: stroke(\n '<path d=\"m16 17 5-5-5-5\"/><path d=\"M21 12H9\"/><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/>',\n ),\n check: stroke('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>'),\n alert: stroke('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 8v4\"/><path d=\"M12 16h.01\"/>'),\n field: stroke('<path d=\"M4 7V4h16v3\"/><path d=\"M9 20h6\"/><path d=\"M12 4v16\"/>'),\n chevron: stroke('<path d=\"m6 9 6 6 6-6\"/>'),\n /** Lucide `eye-off`, the suite's «Ocultar». */\n eyeOff: stroke(\n '<path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\"/><path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\"/><path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\"/><path d=\"m2 2 20 20\"/>',\n ),\n external: stroke(\n '<path d=\"M15 3h6v6\"/><path d=\"M10 14 21 3\"/><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/>',\n ),\n grip: stroke(\n '<circle cx=\"9\" cy=\"12\" r=\"1\"/><circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>',\n ),\n} as const\n\nexport type IconName = keyof typeof ICONS\n\nexport function icon(doc: Document, name: IconName, size = 15): HTMLElement {\n const span = doc.createElement('span')\n span.className = 'icon'\n span.style.width = `${size}px`\n span.style.height = `${size}px`\n span.setAttribute('aria-hidden', 'true')\n // A constant from ICONS, never network data (§7.3).\n span.innerHTML = ICONS[name]\n return span\n}\n\ntype Child = Node | string | number | null | undefined | false\n\nexport interface ElProps {\n class?: string\n attrs?: Record<string, string | null | undefined>\n text?: string\n on?: Partial<Record<string, (event: Event) => void>>\n}\n\n/** An element whose children are nodes or TEXT. Strings are never parsed as markup. */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: ElProps = {},\n children: Child[] = [],\n): HTMLElementTagNameMap[K] {\n const node = doc.createElement(tag)\n if (props.class) node.className = props.class\n for (const [name, value] of Object.entries(props.attrs ?? {})) {\n if (value !== null && value !== undefined) node.setAttribute(name, value)\n }\n if (props.text !== undefined) node.textContent = props.text\n for (const [type, handler] of Object.entries(props.on ?? {})) {\n if (handler) node.addEventListener(type, handler)\n }\n for (const child of children) {\n if (child === null || child === undefined || child === false) continue\n node.append(typeof child === 'string' || typeof child === 'number' ? String(child) : child)\n }\n return node\n}\n\nexport interface SiteHost {\n host: HTMLElement\n root: ShadowRoot\n destroy(): void\n}\n\n/** The closed shadow host, on `<html>` so a site that replaces `<body>` keeps it. */\nexport function mountHost(doc: Document, css: string): SiteHost {\n const host = doc.createElement(SITE_HOST_TAG)\n const style: Record<string, string> = {\n all: 'initial',\n position: 'fixed',\n inset: '0',\n 'pointer-events': 'none',\n 'z-index': '2147483647',\n display: 'block',\n }\n for (const [name, value] of Object.entries(style))\n host.style.setProperty(name, value, 'important')\n const root = host.attachShadow({ mode: 'closed' })\n const sheet = doc.createElement('style')\n sheet.textContent = BASE_CSS + css\n root.append(sheet)\n doc.documentElement.appendChild(host)\n return { host, root, destroy: () => host.remove() }\n}\n\n/** Initials for an avatar: first letters of the first two words. */\nexport function initials(name: string | null | undefined): string {\n const words = (name ?? '').trim().split(/\\s+/).filter(Boolean)\n return words\n .slice(0, 2)\n .map((word) => word.charAt(0).toUpperCase())\n .join('')\n}\n\n/** Eel tokens, inlined (boards SitioLanzador to SitioRenovacion). */\nexport const TOKENS = {\n fg: '#010313',\n muted: '#5A6C85',\n border: '#E2E8F0',\n bg: '#FFFFFF',\n subtle: '#EAEEF3',\n primary: '#287CCF',\n primaryBorder: '#4B97DE',\n dark: '#0F172B',\n gold: '#9A6200',\n goldTint: '#FDF3E1',\n goldText: '#7A4D00',\n danger: '#C62828',\n focus: 'rgba(144,161,185,0.5)',\n}\n\nconst T = TOKENS\nconst FONT = 'Poppins, ui-sans-serif, system-ui, sans-serif'\n\nconst BASE_CSS = `\n:host { all: initial; }\n* { box-sizing: border-box; }\n.layer { position: fixed; inset: 0; pointer-events: none; font-family: ${FONT}; color: ${T.fg};\n font-size: 13px; line-height: 1.45; -webkit-font-smoothing: antialiased; }\n.icon { display: inline-flex; flex-shrink: 0; }\n.icon svg { width: 100%; height: 100%; display: block; }\nbutton { font: 500 13px ${FONT}; color: inherit; cursor: pointer; border: 0; background: transparent;\n display: inline-flex; align-items: center; gap: 6px; padding: 0; margin: 0; }\nbutton:focus-visible, textarea:focus-visible, input:focus-visible { outline: none; box-shadow: 0 0 0 3px ${T.focus}; }\nbutton:disabled { opacity: .55; cursor: default; }\n.card { pointer-events: auto; position: fixed; background: ${T.bg}; border: 1px solid ${T.border};\n border-radius: 15px; box-shadow: 0 20px 25px -5px rgba(15,23,42,.12), 0 8px 10px -6px rgba(15,23,42,.08); }\n.muted { color: ${T.muted}; }\nh2 { margin: 0; font: 600 15px ${FONT}; color: ${T.fg}; display: flex; align-items: center; gap: 8px; }\np { margin: 0; }\n.iconbtn { width: 28px; height: 28px; justify-content: center; border-radius: 7px; color: ${T.muted}; }\n.iconbtn:hover { background: ${T.subtle}; }\n.btn { height: 34px; padding: 0 14px 0 11px; border-radius: 9px; white-space: nowrap; flex-shrink: 0;\n box-shadow: 0 1px 2px rgba(15,23,42,.05); }\n.btn-outline { border: 1px solid ${T.border}; background: ${T.bg}; color: ${T.fg}; }\n.btn-primary { border: 1px solid ${T.primaryBorder}; background: ${T.primary}; color: #FAFAFA; }\n.btn-dark { width: 100%; height: 38px; justify-content: center; gap: 8px; border-radius: 9px;\n background: ${T.dark}; color: #FFFFFF; }\n.error { color: ${T.danger}; font-size: 12px; }\n@media (max-width: 480px) { .card.sheet { left: 8px !important; right: 8px !important; width: auto !important; } }\n`\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/preview/site/signin.ts"],"sourcesContent":["import {\n SIGNIN_CHANNEL,\n type CallbackParams,\n type ChunkHandle,\n type SiteContext,\n type StartOptions,\n} from './config'\nimport { SIGNIN_MESSAGES } from './messages'\nimport {\n authorizeUrl,\n challengeFor,\n checkCallback,\n createState,\n createVerifier,\n exchangeCode,\n returnPathOf,\n savePending,\n takePending,\n type PendingSignIn,\n} from './oauth'\nimport { writeToken } from './token'\nimport { el, icon, mountHost, TOKENS as T } from './ui'\n\n/**\n * The `signin` chunk (zap-cms-v2 §3.4 steps 2 to 5, ADR 041; boards\n * SitioLanzador, SitioEntrar and SitioRenovacion): loaded only after the\n * opt-in trigger.\n *\n * The launcher «Editar o comentar», with the Shift Z hint above it, opens a\n * panel with «Entrar con Eel». All three sit at the bottom centre, the zone\n * the toolbar takes after sign-in (SitioBarra): sites keep the corners for\n * their own floating buttons (a WhatsApp button, a chat bubble). Signing in opens a popup on Nest's consent\n * screen (or, when the person consented to this site before and is signed in\n * to Eel, a popup Nest answers at once and closes, ADR 041 amendment\n * 2026-10-05); the popup lands back on\n * `{origin}/`, where the core hands the code over `BroadcastChannel('eel-zap')`\n * and closes it. This tab, which alone holds the PKCE verifier and the state,\n * checks both and the issuer, exchanges the code and opens `suggest`.\n *\n * A blocked popup turns into a full-page redirect: the verifier and state wait\n * in `sessionStorage` (`PENDING_STORAGE_KEY`), the state carries the return\n * path, and the callback page finishes here (`options.callback`) and goes back.\n */\n\nconst POPUP_NAME = 'eelzap-signin'\nconst POPUP_FEATURES = 'popup,width=480,height=720'\n\ntype Phase = 'closed' | 'open' | 'waiting' | 'error'\n\nexport function start(ctx: SiteContext, options: StartOptions = {}): ChunkHandle {\n const { win, doc } = ctx\n const m = SIGNIN_MESSAGES[ctx.locale]\n const host = mountHost(doc, CSS)\n const layer = el(doc, 'div', { class: 'layer' })\n host.root.append(layer)\n\n const renewing = options.reason === 'expired'\n let phase: Phase = renewing ? 'open' : 'closed'\n let notice: string | null = options.reason === 'expired' ? m.expired : null\n let pending: PendingSignIn | null = null\n let destroyed = false\n\n let channel: BroadcastChannel | null = null\n try {\n channel = new BroadcastChannel(SIGNIN_CHANNEL)\n channel.onmessage = (event: MessageEvent) => onCallback(event.data)\n } catch {\n // No BroadcastChannel: the popup cannot hand back; the redirect path still works.\n }\n\n function render(): void {\n if (destroyed) return\n const expanded = phase !== 'closed'\n const launcher = el(\n doc,\n 'button',\n {\n class: 'launcher',\n attrs: { type: 'button', 'aria-expanded': String(expanded) },\n on: { click: () => setPhase(expanded ? 'closed' : 'open') },\n },\n [icon(doc, 'zap', 18), m.launcher],\n )\n layer.replaceChildren(launcher, expanded ? panel() : hint())\n }\n\n /** «Pulsa Shift Z para editar o comentar», above the closed launcher (SitioLanzador). */\n function hint(): HTMLElement | string {\n const key = ctx.shortcut\n if (!key) return ''\n const kbd = (text: string) => el(doc, 'kbd', { text })\n return el(doc, 'span', { class: 'hint', attrs: { role: 'tooltip' } }, [\n `${m.hintBefore} `,\n kbd('Shift'),\n ' ',\n kbd(key.toUpperCase()),\n ` ${m.hintAfter}`,\n ])\n }\n\n function panel(): HTMLElement {\n const waiting = phase === 'waiting'\n return el(\n doc,\n 'div',\n {\n class: 'card panel sheet',\n attrs: { role: 'dialog', 'aria-labelledby': 'eelzap-signin-title' },\n },\n [\n el(doc, 'div', { class: 'head' }, [\n el(doc, 'h2', { attrs: { id: 'eelzap-signin-title' } }, [icon(doc, 'zap', 20), m.title]),\n el(\n doc,\n 'button',\n {\n class: 'iconbtn',\n attrs: { type: 'button', 'aria-label': m.close, title: m.close },\n on: { click: () => ctx.close() },\n },\n [icon(doc, 'x')],\n ),\n ]),\n el(doc, 'p', { class: 'muted body', text: waiting ? m.waitingHelp : m.body }),\n notice ? el(doc, 'p', { class: 'notice', attrs: { role: 'status' }, text: notice }) : null,\n el(\n doc,\n 'button',\n {\n class: 'btn-dark',\n attrs: { type: 'button', 'data-action': 'sign-in' },\n on: { click: () => void signIn() },\n },\n [icon(doc, 'eel', 18), waiting ? m.retry : m.signIn],\n ),\n waiting\n ? el(doc, 'p', { class: 'muted waiting', attrs: { role: 'status' }, text: m.waiting })\n : null,\n el(doc, 'p', { class: 'muted note' }, [\n icon(doc, 'lock', 13),\n el(doc, 'span', { text: m.note }),\n ]),\n ],\n )\n }\n\n function setPhase(next: Phase, message: string | null = null): void {\n phase = next\n notice = message\n render()\n }\n\n async function signIn(): Promise<void> {\n // A stale full-page attempt in this tab is abandoned.\n takePending(win)\n // The popup opens INSIDE the click, before any await, or the browser blocks it.\n const popup = win.open('', POPUP_NAME, POPUP_FEATURES)\n const verifier = createVerifier(win)\n try {\n const challenge = await challengeFor(win, verifier)\n if (popup) {\n const state = createState(win)\n pending = { state, verifier, mode: 'popup' }\n setPhase('waiting')\n popup.location.href = authorizeUrl(ctx, state, challenge)\n return\n }\n // Popup blocked: the whole tab goes to Nest and comes back to this path.\n const { pathname, search, hash } = win.location\n const state = createState(win, `${pathname}${search}${hash}`)\n savePending(win, { state, verifier, mode: 'redirect' })\n win.location.assign(authorizeUrl(ctx, state, challenge))\n } catch {\n popup?.close()\n setPhase('error', m.failed)\n }\n }\n\n function onCallback(data: unknown): void {\n if (!pending || !data || (data as { type?: unknown }).type !== 'eelzap:callback') return\n const callback = data as Partial<CallbackParams>\n const problem = checkCallback(callback, pending, ctx.authOrigin)\n // Another sign-in's callback (another tab of this site): not ours to judge.\n if (problem === 'state') return\n const used = pending\n pending = null\n if (problem) {\n setPhase('error', m.failed)\n return\n }\n void complete(callback.code!, used.verifier, null)\n }\n\n async function complete(code: string, verifier: string, returnPath: string | null) {\n try {\n const token = await exchangeCode(ctx, code, verifier)\n writeToken(win, token)\n if (destroyed) return\n if (returnPath && returnPath !== `${win.location.pathname}${win.location.search}`) {\n win.location.replace(returnPath)\n return\n }\n await ctx.open('suggest', renewing ? { reason: 'renewed' } : undefined)\n } catch {\n setPhase('error', m.failed)\n }\n }\n\n if (options.callback) {\n const stored = takePending(win)\n const problem =\n stored?.mode === 'redirect'\n ? checkCallback(options.callback, stored, ctx.authOrigin)\n : 'state'\n if (problem) {\n setPhase('error', m.failed)\n } else {\n render()\n void complete(options.callback.code, stored!.verifier, returnPathOf(options.callback.state))\n }\n } else {\n render()\n // «Volver a entrar»: one click already made, so the sign-in starts now.\n if (options.signIn) void signIn()\n }\n\n return {\n destroy() {\n destroyed = true\n pending = null\n channel?.close()\n host.destroy()\n },\n }\n}\n\nconst CSS = `\n.launcher { pointer-events: auto; position: fixed; left: 50%; transform: translateX(-50%); bottom: 24px; height: 42px; gap: 8px;\n padding: 0 16px 0 12px; border: 1px solid ${T.border}; border-radius: 999px; background: ${T.bg}; color: ${T.fg};\n box-shadow: 0 10px 15px -3px rgba(15,23,42,.10), 0 4px 6px -4px rgba(15,23,42,.08); }\n.hint { pointer-events: none; position: fixed; left: 50%; transform: translateX(-50%); bottom: 76px; display: flex; align-items: center; gap: 4px;\n padding: 6px 10px; border-radius: 9px; background: ${T.dark}; color: #FFFFFF; font-size: 12px; white-space: nowrap; }\nkbd { font: 600 11px Poppins, ui-sans-serif, system-ui, sans-serif; padding: 1px 5px; border-radius: 5px;\n background: rgba(255,255,255,.16); color: #FFFFFF; }\n.launcher[aria-expanded=\"true\"] { box-shadow: 0 10px 15px -3px rgba(15,23,42,.10), 0 0 0 3px ${T.focus}; }\n.panel { left: calc(50% - 160px); bottom: 78px; width: 320px; padding: 16px; }\n.head { display: flex; align-items: center; justify-content: space-between; }\n.body { margin: 8px 0 14px; }\n.notice { margin: 0 0 12px; padding: 8px 10px; border-radius: 9px; background: ${T.goldTint}; color: ${T.goldText}; font-size: 12px; }\n.waiting { margin-top: 8px; font-size: 12px; text-align: center; }\n.note { margin-top: 10px; display: flex; align-items: flex-start; gap: 6px; font-size: 12px; }\n.note .icon { margin-top: 2px; }\n`\n"],"mappings":"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","names":["state"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/preview/site/api.ts","../src/preview/site/drag.ts","../src/preview/site/draft-session.ts","../src/preview/site/suggestion.ts","../src/preview/site/session.ts","../src/preview/site/suggest.ts"],"sourcesContent":["import type { SiteContext } from './config'\n\n/**\n * The site tools' calls to Zap's public API with the site client's\n * bearer (ADR 041 §3 to §5). The browser sends `Origin`; Zap checks it\n * against the site's preview origins and answers CORS to that origin only.\n *\n * Every answer becomes one of a few outcomes the UI words:\n *\n * - `expired` (401): the hour is up or the token was revoked; sign in again.\n * - `refused`: a network error. A request Zap refuses for a wrong origin,\n * another site or Live mode off carries NO CORS headers, so the page sees a\n * network error, not a 403; the UI says «No puedes editar ni comentar en\n * este sitio».\n * - `forbidden` (a readable 403: no Zap seat, or «Editar» turned off for this\n * site on the save-to-draft route).\n * - `rate` (429) with `Retry-After` seconds.\n * - `invalid` for anything else.\n *\n * Creates are idempotent: the caller passes the `Idempotency-Key`, kept for\n * one payload so a retry after a 429 or a dropped answer cannot open two\n * threads.\n */\n\nexport type ApiFailure =\n | { ok: false; kind: 'expired' | 'refused' | 'forbidden' | 'invalid' }\n | { ok: false; kind: 'rate'; retryAfter: number }\n\nexport type ApiResult<T> = { ok: true; data: T } | ApiFailure\n\nexport interface FieldInfo {\n type: string\n label: string\n}\n\nexport interface OnPageAnchor {\n fieldKey: string | null\n tag: string | null\n selector: string | null\n rect: { x: number; y: number; w: number; h: number } | null\n /** A pin placed on a point of the page (fractions of the whole document). */\n spot: { x: number; y: number } | null\n}\n\nexport interface OnPageComment {\n id: string\n status: 'OPEN'\n isChangeRequest: boolean\n createdAt: string\n author: { name: string | null } | null\n excerpt: string | null\n anchors: OnPageAnchor[]\n}\n\nexport interface OnPage {\n /**\n * The caller's own name and email, and `editorUrl`: the absolute Zap editor\n * URL of the record this page is, or null (optional: older Zaps omit both).\n */\n viewer: { name: string | null; email?: string | null; editorUrl?: string | null }\n /** Whether «Editar» is on for this site (the ADMIN's `liveEditing` switch). */\n liveEditing: boolean\n fields: Record<string, Record<string, FieldInfo>>\n /**\n * The tagged records that are not the record this page is, by ref, to\n * their name: their fields read «… en Configuración» (optional: older\n * Zaps omit it).\n */\n records?: Record<string, string>\n comments: OnPageComment[]\n truncated: boolean\n}\n\n/** An element anchor (with its field when tagged), or a point of the page. */\nexport type ApiAnchor =\n | {\n field?: { key: string; locale?: string | null }\n dom: {\n tag?: string\n selector?: string\n textQuote?: { exact: string; prefix: string; suffix: string }\n rect: { x: number; y: number; w: number; h: number }\n viewport: { w: number; h: number }\n }\n }\n | { spot: { x: number; y: number }; viewport: { w: number; h: number } }\n\nexport interface CreateBody {\n collection?: string\n slug?: string\n document?: string\n /** «Solicitar cambio»: a change request, assigned by Zap to the record's Responsable. */\n isChangeRequest: boolean\n locale?: string\n /** The page the anchors were made on; element anchors need it. */\n pageUrl: string\n anchors: ApiAnchor[]\n body: string\n proposedValues?: Array<{ fieldKey: string; locale?: string; value: string | number | null }>\n}\n\n/** «Editar» saves to the draft: always a resolved change request, so no flag. */\nexport type DraftBody = Omit<CreateBody, 'isChangeRequest'>\n\nconst BASE = '/api/public/v1/comments'\n\nasync function call<T>(\n ctx: Pick<SiteContext, 'win' | 'zapOrigin'>,\n token: string,\n path: string,\n init: { method: 'GET' | 'POST'; body?: unknown; idempotencyKey?: string },\n): Promise<ApiResult<T>> {\n const headers: Record<string, string> = { Authorization: `Bearer ${token}` }\n if (init.body !== undefined) headers['Content-Type'] = 'application/json'\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey\n let response: Response\n try {\n response = await ctx.win.fetch(`${ctx.zapOrigin}${path}`, {\n method: init.method,\n headers,\n credentials: 'omit',\n body: init.body === undefined ? undefined : JSON.stringify(init.body),\n })\n } catch {\n return { ok: false, kind: 'refused' }\n }\n if (response.status === 401) return { ok: false, kind: 'expired' }\n if (response.status === 403) return { ok: false, kind: 'forbidden' }\n if (response.status === 429) {\n const seconds = Number.parseInt(response.headers.get('Retry-After') ?? '', 10)\n return { ok: false, kind: 'rate', retryAfter: seconds > 0 ? Math.min(seconds, 3600) : 30 }\n }\n if (!response.ok) return { ok: false, kind: 'invalid' }\n try {\n return { ok: true, data: (await response.json()) as T }\n } catch {\n return { ok: false, kind: 'invalid' }\n }\n}\n\nexport function fetchOnPage(\n ctx: Pick<SiteContext, 'win' | 'zapOrigin'>,\n token: string,\n pageUrl: string,\n refs: readonly string[],\n): Promise<ApiResult<OnPage>> {\n const query = new URLSearchParams({ url: pageUrl })\n if (refs.length > 0) query.set('refs', refs.slice(0, 20).join(','))\n return call<OnPage>(ctx, token, `${BASE}/on-page?${query.toString()}`, { method: 'GET' })\n}\n\n/** The part of the create answer the toast reads: who the request went to. */\nexport interface CreateAnswer {\n thread: { id: string; assignee?: { name: string | null } | null }\n}\n\nexport function createComment(\n ctx: Pick<SiteContext, 'win' | 'zapOrigin'>,\n token: string,\n body: CreateBody,\n idempotencyKey: string,\n): Promise<ApiResult<CreateAnswer>> {\n return call(ctx, token, BASE, { method: 'POST', body, idempotencyKey })\n}\n\nexport function saveToDraft(\n ctx: Pick<SiteContext, 'win' | 'zapOrigin'>,\n token: string,\n body: DraftBody,\n idempotencyKey: string,\n): Promise<ApiResult<{ thread: { id: string }; draftVersionId: string }>> {\n return call(ctx, token, `${BASE}/save-to-draft`, { method: 'POST', body, idempotencyKey })\n}\n\n/** A random Idempotency-Key (a v4-shaped UUID). */\nexport function newIdempotencyKey(win: Window): string {\n const native = (win.crypto as Crypto & { randomUUID?: () => string }).randomUUID\n if (typeof native === 'function') return native.call(win.crypto)\n const bytes = win.crypto.getRandomValues(new Uint8Array(16))\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n","import { el, icon, TOKENS as T } from './ui'\n\n/**\n * Moving the live site's toolbar (the `suggest` chunk's «Navegar», «Editar»,\n * «Comentar» pill) by a grip at its far left.\n *\n * - **Where it sits.** Nothing stored: the default bottom centre of the\n * `.bottom` stack, untouched (the zone sites leave free for it, signin.ts).\n * Once moved: the bar's top left, clamped to the viewport with a 16px\n * gutter on every layout, resize and orientation change.\n * - **What rides with it.** The cards stacked with the bar (the open\n * comments, the selection tray, the save status) open on the side with\n * more room, above or below, centred on the bar and kept inside the\n * viewport.\n * - **Remembered** per site origin in the page's `localStorage`, with\n * whether the bar is hidden (`{ x, y, hidden }`, every part optional);\n * every access may throw (private mode, blocked storage) and is caught. A\n * double click (or double tap) on the grip puts the bar back and forgets\n * the place.\n * - **Hidden** (SitioBarraEstados «Barra oculta»): the pill takes the bar's\n * place, the same stored point or the default bottom centre, under the same\n * clamp and resize rules. The pill itself is the grip (`grab`): a press\n * that moves 3px or more drags it and is not a click; the place it lands\n * is the bar's.\n * - **The account menu** rides in the stack too, right aligned under the\n * account chip, above the bar or below it as the cards are.\n * - **Pointer and keys.** Pointer events with capture and `touch-action:\n * none`; the arrow keys move it 16px (64px with Shift). Nothing the grip\n * receives reaches the site: its pointer, mouse, touch and click events\n * stop at the grip.\n */\n\nexport const BAR_STORAGE_KEY = 'eelzap:bar'\n\nconst GUTTER = 16\nconst STEP = 16\nconst BIG_STEP = 64\nconst GAP = 10\n/** A press that moves less than this is a click, not a drag. */\nconst SLOP = 3\nconst DOUBLE_MS = 400\n\ninterface Point {\n x: number\n y: number\n}\n\nexport interface BarDrag {\n /** The grip, one node for the bar's whole life: each render moves it into the new toolbar. */\n handle: HTMLButtonElement\n /** Whether the bar shows as the pill, remembered next to the place. */\n hidden(): boolean\n setHidden(value: boolean): void\n /** Make `node` (the pill) drag the stack too; its click after a drag is swallowed. */\n grab(node: HTMLElement): HTMLElement\n /** Lay out the stack again; call after every render of it. */\n place(): void\n destroy(): void\n}\n\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(Math.max(value, min), Math.max(min, max))\n\nfunction storage(win: Window): Storage | null {\n try {\n return win.localStorage\n } catch {\n return null\n }\n}\n\nfunction read(win: Window): { pos: Point | null; hidden: boolean } {\n try {\n const value = JSON.parse(storage(win)?.getItem(BAR_STORAGE_KEY) ?? 'null') as\n | (Partial<Point> & { hidden?: unknown })\n | null\n return {\n pos:\n value && Number.isFinite(value.x) && Number.isFinite(value.y)\n ? { x: value.x!, y: value.y! }\n : null,\n hidden: value?.hidden === true,\n }\n } catch {\n return { pos: null, hidden: false }\n }\n}\n\nfunction write(win: Window, point: Point | null, hidden: boolean): void {\n try {\n const store = storage(win)\n if (point || hidden)\n store?.setItem(BAR_STORAGE_KEY, JSON.stringify({ ...point, hidden: hidden || undefined }))\n else store?.removeItem(BAR_STORAGE_KEY)\n } catch {\n // Storage full or blocked: the bar still moves, it just is not remembered.\n }\n}\n\nexport function barDrag(\n win: Window,\n doc: Document,\n stack: HTMLElement,\n label: string,\n tip: string,\n): BarDrag {\n const saved = read(win)\n let pos = saved.pos\n let hidden = saved.hidden\n let drag: {\n id: number\n px: number\n py: number\n from: Point\n moved: boolean\n node: HTMLElement\n } | null = null\n /** The press that just ended was a drag: its click is not one. */\n let dragged = false\n let lastTap = 0\n\n const viewport = (): [number, number] => {\n const root = doc.documentElement\n return [root.clientWidth || win.innerWidth, root.clientHeight || win.innerHeight]\n }\n const bar = () => stack.querySelector<HTMLElement>('.toolbar, .pill')\n const rectOf = (node: HTMLElement): Point => {\n const rect = node.getBoundingClientRect()\n return { x: rect.left, y: rect.top }\n }\n\n function place(): void {\n const toolbar = bar()\n const cards = Array.from(stack.children) as HTMLElement[]\n const [vw, vh] = viewport()\n if (!pos || !toolbar) {\n stack.removeAttribute('style')\n stack.removeAttribute('data-below')\n for (const card of cards) {\n card.style.marginLeft = ''\n card.style.maxHeight = ''\n }\n placeMenu(toolbar, vw)\n return\n }\n const w = toolbar.offsetWidth\n const h = toolbar.offsetHeight\n const x = clamp(pos.x, GUTTER, vw - w - GUTTER)\n const y = clamp(pos.y, GUTTER, vh - h - GUTTER)\n // The cards open on the side with more room.\n const below = vh - y - h > y\n const room = (below ? vh - y - h : y) - GAP - GUTTER\n Object.assign(stack.style, {\n padding: '0',\n alignItems: 'flex-start',\n flexDirection: below ? 'column-reverse' : 'column',\n top: below ? `${y}px` : 'auto',\n bottom: below ? 'auto' : `${vh - y - h}px`,\n })\n stack.toggleAttribute('data-below', below)\n for (const card of cards) {\n if (card.classList.contains('toast') || card.classList.contains('menu')) continue\n if (card.classList.contains('list')) card.style.maxHeight = `min(50vh, ${room}px)`\n const cw = card.offsetWidth\n card.style.marginLeft = `${card === toolbar ? x : clamp(x + (w - cw) / 2, GUTTER / 2, vw - cw - GUTTER / 2)}px`\n }\n placeMenu(toolbar, vw)\n }\n\n /** The account menu's right edge under the account chip (35px in from the bar's right edge). */\n function placeMenu(toolbar: HTMLElement | null, vw: number): void {\n const menu = stack.querySelector<HTMLElement>('.menu')\n if (!menu || !toolbar) return\n const left =\n stack.getBoundingClientRect().left +\n (parseFloat(win.getComputedStyle(stack).paddingLeft) || 0)\n const mw = menu.offsetWidth\n menu.style.alignSelf = 'flex-start'\n menu.style.marginLeft = `${clamp(toolbar.getBoundingClientRect().right - 35 - mw, GUTTER / 2, vw - mw - GUTTER / 2) - left}px`\n }\n\n /** Move to `point`, clamped, and remember where the bar really landed. */\n function moveTo(point: Point, save: boolean): void {\n pos = point\n place()\n const toolbar = bar()\n if (toolbar) pos = rectOf(toolbar)\n if (save) write(win, pos, hidden)\n }\n\n function reset(): void {\n pos = null\n write(win, null, hidden)\n place()\n }\n\n const onMove = (event: PointerEvent) => {\n if (!drag || event.pointerId !== drag.id) return\n const dx = event.clientX - drag.px\n const dy = event.clientY - drag.py\n if (!drag.moved && Math.hypot(dx, dy) < SLOP) return\n drag.moved = true\n event.preventDefault()\n pos = { x: drag.from.x + dx, y: drag.from.y + dy }\n place()\n }\n const onUp = (event: PointerEvent) => {\n if (!drag || event.pointerId !== drag.id) return\n const { moved, node } = drag\n drag = null\n node.removeAttribute('data-dragging')\n if (moved && pos) {\n moveTo(pos, true)\n lastTap = 0\n // The click that follows this pointerup comes in the same task.\n dragged = true\n win.setTimeout(() => (dragged = false))\n } else if (node === handle && event.type === 'pointerup') {\n // Two presses in a row without moving: back to the default place.\n const now = Date.now()\n if (now - lastTap < DOUBLE_MS) {\n lastTap = 0\n reset()\n } else lastTap = now\n }\n }\n\n const stop = (event: Event) => event.stopPropagation()\n function begin(e: PointerEvent, node: HTMLElement): void {\n const toolbar = bar()\n if (e.button !== 0 || !toolbar) return\n drag = {\n id: e.pointerId,\n px: e.clientX,\n py: e.clientY,\n from: rectOf(toolbar),\n moved: false,\n node,\n }\n node.setAttribute('data-dragging', '')\n try {\n node.setPointerCapture(e.pointerId)\n } catch {\n // An inactive pointer: the window listeners still follow it.\n }\n }\n const handle = el(doc, 'button', {\n class: 'grip',\n attrs: { type: 'button', 'aria-label': label, title: tip },\n on: {\n pointerdown: (event) => {\n event.stopPropagation()\n begin(event as PointerEvent, handle)\n },\n keydown: (event) => {\n const e = event as KeyboardEvent\n const step = e.shiftKey ? BIG_STEP : STEP\n const delta: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n }\n const move = delta[e.key]\n const toolbar = bar()\n if (!move || !toolbar) return\n e.preventDefault()\n e.stopPropagation()\n const from = rectOf(toolbar)\n moveTo({ x: from.x + move[0], y: from.y + move[1] }, true)\n },\n },\n })\n for (const type of [\n 'pointerup',\n 'dblclick',\n 'mousedown',\n 'mouseup',\n 'click',\n 'touchstart',\n 'touchend',\n ]) {\n handle.addEventListener(type, stop)\n }\n handle.append(icon(doc, 'grip'))\n\n // Capture on the window: the grip stops its own events from bubbling, and a\n // render mid-drag may take it out of the page.\n const onResize = () => place()\n win.addEventListener('pointermove', onMove, true)\n win.addEventListener('pointerup', onUp, true)\n win.addEventListener('pointercancel', onUp, true)\n win.addEventListener('resize', onResize)\n win.addEventListener('orientationchange', onResize)\n\n return {\n handle,\n grab(node) {\n node.addEventListener('pointerdown', (event) => begin(event as PointerEvent, node))\n node.addEventListener(\n 'click',\n (event) => {\n if (dragged) event.stopImmediatePropagation()\n },\n true,\n )\n return node\n },\n place,\n hidden: () => hidden,\n setHidden(value) {\n hidden = value\n write(win, pos, hidden)\n },\n destroy() {\n win.removeEventListener('pointermove', onMove, true)\n win.removeEventListener('pointerup', onUp, true)\n win.removeEventListener('pointercancel', onUp, true)\n win.removeEventListener('resize', onResize)\n win.removeEventListener('orientationchange', onResize)\n },\n }\n}\n\n/** The grip's own styles; the bar's shared hover treatment lives with the bar (suggest.ts). */\nexport const DRAG_CSS = `\n.grip { width: 20px; height: 30px; justify-content: center; border-radius: 7px; color: ${T.muted};\n cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }\n.grip[data-dragging], .pill[data-dragging] { cursor: grabbing; }\n.pill { touch-action: none; user-select: none; -webkit-user-select: none; }\n.bottom[data-below] .seg[data-tip]:hover::after { bottom: auto; top: 34px; }\n`\n","import { isDraftRoutePath } from '../protocol'\nimport type { SiteContext } from './config'\n\n/**\n * «Editar» on the live site through a short draft-mode session (ADR 041\n * amendment 2026-10-06; zap-cms-v2 item 13, option a).\n *\n * A published page carries no tags: stega and `data-zap` are rendered only in\n * Next's draft mode, and only the browser holding the draft cookie gets them.\n * So when the person presses Editar on an untagged page, the bar:\n *\n * 1. asks Zap for a draft session (`POST /api/public/v1/preview/session`, the\n * site-client token in `Authorization`, the page's draft route and path in\n * the body, `credentials: 'omit'`);\n * 2. checks the answer is the site's own draft route on THIS origin (Zap built\n * it from the verified `Origin`; checked again so a confused answer cannot\n * send the tab elsewhere);\n * 3. remembers in `sessionStorage` that Editar should reopen on this path, and\n * until when this tab is in draft mode;\n * 4. navigates the tab there. The site's existing route validates the token\n * with Zap, sets the draft cookie and redirects back to the page, which\n * renders tagged; the bar comes back (the tab still holds its token) and\n * reopens Editar.\n *\n * A page already tagged needs none of this. A page still untagged while this\n * tab is in its draft session simply has no fields, and says so. Signing out\n * revokes the session's preview tokens at Zap and drops the draft cookie\n * through the site's exit route (`{draftRoute}/exit`, the SDK's\n * `createDraftModeExitRoute`), then reloads the page published.\n *\n * Comentar never needs draft mode: nothing here runs for it.\n */\n\nexport const DRAFT_SESSION_PATH = '/api/public/v1/preview/session'\n\n/** Editar should reopen after the reload, on this path, if it happens soon. */\nexport const EDIT_INTENT_KEY = 'eelzap:edit-intent'\n/** This tab entered draft mode through a session, until `exp`. */\nexport const DRAFT_SESSION_KEY = 'eelzap:draft-session'\n\n/** An intent older than this is stale (the navigation never landed). */\nconst INTENT_MAX_AGE_MS = 2 * 60_000\n\nexport const DRAFT_SESSION_MESSAGES = {\n es: {\n preparing: 'Preparando la edición…',\n noRoute:\n 'Este sitio no tiene la ruta de vista previa que Editar necesita. Usa Comentar o ábrelo desde Zap.',\n failed: 'No pudimos preparar la página para editar. Inténtalo de nuevo o usa Comentar.',\n rate: (seconds: number) =>\n `Demasiados intentos. Vuelve a intentarlo en ${seconds} ${seconds === 1 ? 'segundo' : 'segundos'}.`,\n },\n en: {\n preparing: 'Getting the page ready to edit…',\n noRoute:\n 'This site does not have the preview route Edit needs. Use Comment or open it from Zap.',\n failed: 'We could not get the page ready to edit. Try again or use Comment.',\n rate: (seconds: number) =>\n `Too many tries. Try again in ${seconds} ${seconds === 1 ? 'second' : 'seconds'}.`,\n },\n} as const\n\nexport type DraftSessionFailure =\n | { ok: false; reason: 'no-route' | 'expired' | 'refused' | 'failed' }\n | { ok: false; reason: 'rate'; retryAfter: number }\n\nexport type DraftSessionResult = { ok: true; url: string; expiresAt: number } | DraftSessionFailure\n\ntype Ctx = Pick<SiteContext, 'win' | 'zapOrigin' | 'draftRoute'>\n\nfunction storage(win: Window): Storage | null {\n try {\n return win.sessionStorage\n } catch {\n return null\n }\n}\n\nfunction readJson(win: Window, key: string): Record<string, unknown> | null {\n try {\n const raw = storage(win)?.getItem(key)\n if (!raw) return null\n const value = JSON.parse(raw) as unknown\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : null\n } catch {\n return null\n }\n}\n\nfunction write(win: Window, key: string, value: unknown): void {\n try {\n storage(win)?.setItem(key, JSON.stringify(value))\n } catch {\n // Blocked storage: Editar just does not reopen by itself after the reload.\n }\n}\n\nfunction remove(win: Window, key: string): void {\n try {\n storage(win)?.removeItem(key)\n } catch {\n // Nothing to clear.\n }\n}\n\n/** The page as the draft route should return to it: path, query and hash. */\nexport function currentPath(win: Window): string {\n const { pathname, search, hash } = win.location\n return `${pathname}${search}${hash}`\n}\n\n/** True while this tab is inside a draft session it entered (the cookie's life). */\nexport function inDraftSession(win: Window, now = Date.now()): boolean {\n const value = readJson(win, DRAFT_SESSION_KEY)\n return (\n !!value &&\n typeof value.exp === 'number' &&\n value.exp > now &&\n value.origin === win.location.origin\n )\n}\n\n/**\n * Whether Editar should reopen now: an intent left on this very path in the\n * last two minutes. Read once: the intent is removed either way.\n */\nexport function takeEditIntent(win: Window, now = Date.now()): boolean {\n const value = readJson(win, EDIT_INTENT_KEY)\n remove(win, EDIT_INTENT_KEY)\n return (\n !!value &&\n value.path === win.location.pathname &&\n typeof value.at === 'number' &&\n now - value.at >= 0 &&\n now - value.at < INTENT_MAX_AGE_MS\n )\n}\n\n/**\n * The URL Zap answered, accepted only when it is this page's own origin and\n * the announced draft route, carrying a token and a path: anything else is\n * a failure, never a navigation.\n */\nexport function acceptSessionUrl(raw: unknown, win: Window, draftRoute: string): string | null {\n if (typeof raw !== 'string') return null\n let url: URL\n try {\n url = new URL(raw)\n } catch {\n return null\n }\n if (url.origin !== win.location.origin || url.pathname !== draftRoute) return null\n if (!/^zpt_[A-Za-z0-9_-]{43}$/.test(url.searchParams.get('token') ?? '')) return null\n const path = url.searchParams.get('path') ?? ''\n if (!path.startsWith('/') || path.startsWith('//')) return null\n return url.toString()\n}\n\n/**\n * Ask Zap for a draft session for this page. On success the intent and the\n * session are remembered; the caller navigates (`win.location.assign`).\n */\nexport async function requestDraftSession(\n ctx: Ctx,\n token: string,\n now = Date.now,\n): Promise<DraftSessionResult> {\n const { win } = ctx\n const draftRoute = ctx.draftRoute\n if (!isDraftRoutePath(draftRoute)) return { ok: false, reason: 'no-route' }\n let response: Response\n try {\n response = await win.fetch(`${ctx.zapOrigin}${DRAFT_SESSION_PATH}`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n credentials: 'omit',\n body: JSON.stringify({ draftRoute, path: currentPath(win) }),\n })\n } catch {\n return { ok: false, reason: 'refused' }\n }\n if (response.status === 401) return { ok: false, reason: 'expired' }\n if (response.status === 429) {\n const seconds = Number.parseInt(response.headers.get('Retry-After') ?? '', 10)\n return { ok: false, reason: 'rate', retryAfter: seconds > 0 ? Math.min(seconds, 3600) : 30 }\n }\n if (!response.ok) return { ok: false, reason: 'failed' }\n let body: { url?: unknown; expiresAt?: unknown } | null\n try {\n body = (await response.json()) as typeof body\n } catch {\n return { ok: false, reason: 'failed' }\n }\n const url = acceptSessionUrl(body?.url, win, draftRoute)\n if (!url) return { ok: false, reason: 'failed' }\n const at = now()\n const parsed = typeof body?.expiresAt === 'string' ? Date.parse(body.expiresAt) : NaN\n const expiresAt = Number.isFinite(parsed) ? parsed : at + 10 * 60_000\n write(win, EDIT_INTENT_KEY, { path: win.location.pathname, at })\n write(win, DRAFT_SESSION_KEY, { exp: expiresAt, origin: win.location.origin })\n return { ok: true, url, expiresAt }\n}\n\n/** The site's draft-exit route by the SDK's convention: `{draftRoute}/exit`. */\nexport function draftExitUrl(win: Window, draftRoute: string): string {\n const url = new URL(`${draftRoute.replace(/\\/+$/, '')}/exit`, win.location.origin)\n url.searchParams.set('path', currentPath(win))\n return url.toString()\n}\n\n/**\n * Sign-out: revoke this token's draft sessions at Zap, then, when the page\n * is in draft mode (`tagged`, or this tab entered a session), drop the draft\n * cookie through the site's exit route and reload published. Resolves true\n * when it reloads. Never throws: signing out must work whatever answers.\n */\nexport async function leaveDraftSession(\n ctx: Ctx,\n token: string,\n tagged: boolean,\n): Promise<boolean> {\n const { win } = ctx\n const entered = inDraftSession(win)\n remove(win, EDIT_INTENT_KEY)\n remove(win, DRAFT_SESSION_KEY)\n if (!entered && !tagged) return false\n try {\n await win.fetch(`${ctx.zapOrigin}${DRAFT_SESSION_PATH}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}` },\n credentials: 'omit',\n })\n } catch {\n // The tokens die with their ten minutes anyway.\n }\n if (!isDraftRoutePath(ctx.draftRoute)) return false\n try {\n // Same origin, so the route's Set-Cookie (both cookies expired, partitioned)\n // applies; its 307 back to the page is not followed.\n const response = await win.fetch(draftExitUrl(win, ctx.draftRoute), {\n method: 'GET',\n credentials: 'same-origin',\n redirect: 'manual',\n cache: 'no-store',\n })\n if (response.type !== 'opaqueredirect' && !response.ok) return false\n } catch {\n return false\n }\n win.location.reload()\n return true\n}\n","import { cleanStega } from '../../stega'\nimport { findAnchorElement, normalizeText } from '../anchor'\nimport type { OverlayPin } from '../overlay'\nimport { isRecordRef, parseRecordRef, type DomAnchor, type PageAnchor } from '../protocol'\nimport type { TagIndex, TaggedElement } from '../tags'\nimport type { ApiAnchor, CreateBody, DraftBody, FieldInfo, OnPage, OnPageAnchor } from './api'\n\n/**\n * What «Editar» and «Comentar» send, decided in the page (zap-cms-v2 §3.3,\n * §3.4). Pure functions over the DOM and the `on-page` answer, so each rule is\n * a spec:\n *\n * - **What can be edited or proposed.** Only ONE tagged element whose field\n * is TEXT or LONG_TEXT (edited in place, `contenteditable`) or NUMBER or URL\n * (a small input), and never on `data-zap-html` (rich text). The field types\n * come from Zap's `on-page` read (the site's schema for the records tagged\n * on the page), never from the page's markup.\n * - **Which record** a thread lands on: the element's own tag, else the\n * nearest `data-zap-entry`, else the record the page tags most.\n * - **Anchors** are the package's own (`buildAnchor`), clamped to the request\n * schema's limits, with the `field` layer only for the target record; or a\n * point of the page (`spotAnchor`).\n * - **The payloads.** «Comentar»: a plain comment, or with «Solicitar cambio»\n * a change request, which alone may carry a proposed value. «Editar»: the\n * new value, saved to the draft. The page's address goes once, as `pageUrl`.\n * - **The pins**: the open threads made on this page with an element or a\n * point, oldest first, numbered from 1, as the editor's Comentarios list\n * numbers them (`numberPins` in Zap).\n */\n\nexport const SUGGESTIBLE_TYPES = ['TEXT', 'LONG_TEXT', 'NUMBER', 'URL'] as const\n\nexport type EditKind = 'text' | 'input'\n\n/** How a field can be edited in place, or null for comment only. */\nexport function editKindFor(\n tagged: TaggedElement | null,\n field: FieldInfo | null | undefined,\n): EditKind | null {\n if (!tagged || !field || tagged.html) return null\n if (field.type === 'TEXT' || field.type === 'LONG_TEXT') return 'text'\n if (field.type === 'NUMBER' || field.type === 'URL') return 'input'\n return null\n}\n\n/** The field of a tagged element, from the `on-page` schema. */\nexport function fieldOf(\n data: Pick<OnPage, 'fields'> | null,\n tagged: TaggedElement | null,\n): FieldInfo | null {\n if (!data || !tagged) return null\n const field = data.fields?.[tagged.recordRef]?.[tagged.fieldKey]\n return field && typeof field.type === 'string' ? field : null\n}\n\n/** The record a thread about `element` belongs to, or null when the page names none. */\nexport function recordFor(element: Element, index: TagIndex): string | null {\n const tagged = index.closest(element)\n if (tagged) return tagged.recordRef\n const entry = element.closest('[data-zap-entry]')?.getAttribute('data-zap-entry')?.trim()\n if (entry && isRecordRef(entry)) return entry\n const counts = new Map<string, number>()\n for (const row of index.summary()) {\n counts.set(row.recordRef, (counts.get(row.recordRef) ?? 0) + row.count)\n }\n let best: string | null = null\n let most = 0\n for (const [ref, count] of counts) {\n if (count > most) {\n best = ref\n most = count\n }\n }\n return best\n}\n\n/** The page's address for anchors and the `on-page` read: no hash, at most 2048 chars. */\nexport function currentPageUrl(win: Window): string {\n const { origin, pathname, search } = win.location\n return `${origin}${pathname}${search}`.slice(0, 2048)\n}\n\nconst unit = (value: number) => (Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 0)\nconst whole = (value: number, max: number) =>\n Number.isFinite(value) ? Math.min(max, Math.max(1, Math.round(value))) : 1\n\ntype ElementAnchor = Extract<ApiAnchor, { dom: unknown }>\n\n/** A page anchor as the public API takes it: keys, not ids; null layers left out. */\nexport function toApiAnchor(anchor: PageAnchor, recordRef: string): ElementAnchor {\n const dom = anchor.dom\n const out: ElementAnchor = {\n dom: {\n ...(dom.tag && dom.tag.length <= 500 ? { tag: dom.tag } : {}),\n ...(dom.selector ? { selector: dom.selector } : {}),\n ...(dom.textQuote\n ? {\n textQuote: {\n exact: dom.textQuote.exact.slice(0, 500),\n prefix: dom.textQuote.prefix.slice(-32),\n suffix: dom.textQuote.suffix.slice(0, 32),\n },\n }\n : {}),\n rect: { x: unit(dom.rect.x), y: unit(dom.rect.y), w: unit(dom.rect.w), h: unit(dom.rect.h) },\n viewport: { w: whole(dom.viewport.w, 100_000), h: whole(dom.viewport.h, 1_000_000) },\n },\n }\n if (anchor.field && anchor.field.recordRef === recordRef) {\n out.field = {\n key: anchor.field.key,\n ...(anchor.field.locale ? { locale: anchor.field.locale } : {}),\n }\n }\n return out\n}\n\nexport function recordKeys(\n recordRef: string,\n): Pick<CreateBody, 'collection' | 'slug' | 'document'> {\n const parsed = parseRecordRef(recordRef)\n if (!parsed) return {}\n return parsed.kind === 'document'\n ? { document: parsed.key }\n : { collection: parsed.collection, slug: parsed.slug }\n}\n\nexport interface Proposal {\n fieldKey: string\n locale: string | null\n value: string | number\n}\n\n/**\n * The «Comentar» body. A proposal goes only with a change request; the\n * comment (trimmed) is the body, or the proposed value's text when there is\n * no comment.\n */\nexport function buildCreateBody(input: {\n recordRef: string\n pageUrl: string\n anchors: ApiAnchor[]\n comment: string\n isChangeRequest: boolean\n proposal: Proposal | null\n}): CreateBody {\n const proposal = input.isChangeRequest ? input.proposal : null\n const comment = input.comment.trim()\n const body: CreateBody = {\n ...recordKeys(input.recordRef),\n isChangeRequest: input.isChangeRequest,\n pageUrl: input.pageUrl,\n anchors: input.anchors.slice(0, 20),\n body: (comment || (proposal ? String(proposal.value) : '')).slice(0, 10_000),\n }\n if (proposal) Object.assign(body, proposedPart(proposal))\n return body\n}\n\n/** The «Editar» body: the new value, saved to the record's draft. */\nexport function buildDraftBody(input: {\n recordRef: string\n pageUrl: string\n anchors: ApiAnchor[]\n proposal: Proposal\n}): DraftBody {\n return {\n ...recordKeys(input.recordRef),\n pageUrl: input.pageUrl,\n anchors: input.anchors.slice(0, 20),\n body: String(input.proposal.value).slice(0, 10_000) || ' ',\n ...proposedPart(input.proposal),\n }\n}\n\nfunction proposedPart(proposal: Proposal): Pick<CreateBody, 'locale' | 'proposedValues'> {\n const locale = proposal.locale\n return {\n ...(locale ? { locale } : {}),\n proposedValues: [\n { fieldKey: proposal.fieldKey, ...(locale ? { locale } : {}), value: proposal.value },\n ],\n }\n}\n\n/**\n * Two parsed values are the same edit: numbers by value, text without stega\n * markers and with whitespace collapsed (`normalizeText`), so a field left\n * as it was, read back from a preview page, never counts as a change.\n */\nexport function sameValue(a: string | number, b: string | number): boolean {\n if (typeof a === 'number' || typeof b === 'number') return a === b\n return normalizeText(a) === normalizeText(b)\n}\n\nconst LINE_BLOCKS = new Set(['div', 'p', 'li'])\n\n/**\n * The text an inline edit left in `element`, as typed: its text nodes, `<br>`\n * and a new block (what Enter makes in a contenteditable) as line breaks.\n * Never `innerText`: it applies CSS, so a field shown with `text-transform:\n * uppercase` read back in capitals and every edit of it looked like a change.\n */\nexport function editableText(element: Element): string {\n let out = ''\n const walk = (node: Node) => {\n for (let child = node.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === 3) {\n out += (child as Text).data\n } else if (child.nodeType === 1) {\n const name = (child as Element).localName\n if (name === 'br') {\n out += '\\n'\n continue\n }\n if (LINE_BLOCKS.has(name) && out !== '' && !out.endsWith('\\n')) out += '\\n'\n walk(child)\n }\n }\n }\n walk(element)\n return out\n}\n\n/** The value typed for `kind`, parsed for its field type; `invalid` when a number is not one. */\nexport function parseProposed(\n type: string,\n raw: string,\n): { ok: true; value: string | number } | { ok: false } {\n // Text read from the page in preview carries stega markers; never send one.\n raw = cleanStega(raw)\n if (type === 'NUMBER') {\n const text = raw.trim().replace(',', '.')\n const value = Number(text)\n return text !== '' && Number.isFinite(value) ? { ok: true, value } : { ok: false }\n }\n if (type === 'TEXT' || type === 'URL') return { ok: true, value: normalizeText(raw) }\n return { ok: true, value: raw.replace(/\\r\\n?/g, '\\n').trim() }\n}\n\n/** A point of the page, from a click at viewport `(x, y)`, as fractions of the whole document. */\nexport function spotAnchor(x: number, y: number, doc: Document, win: Window): ApiAnchor {\n const root = doc.documentElement\n const w = Math.max(root.scrollWidth, 1)\n const h = Math.max(root.scrollHeight, 1)\n return {\n spot: { x: unit((x + win.scrollX) / w), y: unit((y + win.scrollY) / h) },\n viewport: { w: whole(w, 100_000), h: whole(h, 1_000_000) },\n }\n}\n\n/** An anchor the page can show: a point, or an element (the editor's `onPageAnchor`). */\nfunction onPage(anchor: OnPageAnchor): boolean {\n return !!(anchor?.spot || anchor?.rect || anchor?.tag || anchor?.selector)\n}\n\n/**\n * The numbered pins of the page's open threads. Numbers go to every thread\n * with an on-page anchor, oldest first, so «2» here is «2» in Zap; a pin is\n * drawn at the thread's point, else at the first of its elements still on the\n * page (a thread whose element is gone keeps its number and draws nothing).\n * Never throws: stored selectors only reach `safeQueryAll`.\n */\nexport function pinsFor<R extends { id: string; createdAt: string; anchors: OnPageAnchor[] }>(\n threads: readonly R[],\n index: TagIndex,\n doc: Document,\n win: Window,\n): { pins: OverlayPin[]; numbers: Map<string, number> } {\n const numbers = new Map<string, number>()\n const pins: OverlayPin[] = []\n const numbered = threads\n .filter((thread) => Array.isArray(thread.anchors) && thread.anchors.some(onPage))\n .sort(\n (a, b) => String(a.createdAt).localeCompare(String(b.createdAt)) || a.id.localeCompare(b.id),\n )\n numbered.forEach((thread, i) => {\n const n = i + 1\n numbers.set(thread.id, n)\n const spot = thread.anchors.find((anchor) => anchor?.spot)?.spot\n if (spot && Number.isFinite(spot.x) && Number.isFinite(spot.y)) {\n pins.push({ id: thread.id, n, spot: { x: unit(spot.x), y: unit(spot.y) } })\n return\n }\n for (const anchor of thread.anchors) {\n if (!onPage(anchor) || anchor.spot) continue\n const element = findAnchorElement(asDomAnchor(anchor), index, doc, win)\n if (element && element !== doc.body && element !== doc.documentElement) {\n pins.push({ id: thread.id, n, element })\n return\n }\n }\n })\n return { pins: pins.slice(0, 50), numbers }\n}\n\n/** No rectangle fallback: a pin on a guessed element is worse than none. */\nconst NOWHERE = { x: -1, y: -1, w: 0, h: 0 }\n\nfunction asDomAnchor(anchor: OnPageAnchor): DomAnchor {\n const tag = typeof anchor?.tag === 'string' && anchor.tag.length <= 500 ? anchor.tag : null\n const selector =\n typeof anchor?.selector === 'string' && anchor.selector.length <= 1024 ? anchor.selector : null\n return { tag, selector, textQuote: null, rect: NOWHERE, viewport: { w: 1, h: 1 } }\n}\n","import type { ApiResult } from './api'\nimport type { SiteContext } from './config'\nimport { readTokenAnswer } from './oauth'\nimport {\n accessLive,\n clearToken,\n EXPIRY_MARGIN_MS,\n refreshLive,\n writeToken,\n type SiteToken,\n} from './token'\n\n/**\n * The site client's token lifecycle (ADR 041 amendment 2026-10-06; Zap item\n * 32): ONE place that knows whether the bar can still talk to Zap, shared by\n * the on-page read, comments, «Editar»'s saves and the draft-session\n * exchange.\n *\n * - **A valid token** for each call (`ensure`): the stored access token while\n * it has more than 30 seconds left, else a renewal first.\n * - **Renewal** (`refresh`) spends the refresh token at Nest\n * (`grant_type=refresh_token`, `client_id`, no cookies; Nest answers CORS to\n * this origin and rotates the refresh token). One renewal at a time: calls\n * that need it while one is running wait for the same answer.\n * - **A 401 retries once** (`call`): renew, then the same request with the\n * new token. A second 401, or a renewal that fails, is the expired state.\n * - **Ahead of time**: a timer renews two minutes before the hour ends, so a\n * person typing in a field never meets the wall; when the tab becomes\n * visible again (timers sleep with the tab) the same check runs at once.\n * Renewing touches nothing on the page: the bar keeps its state and an\n * inline edit in progress is not re-rendered.\n * - **Expired** (`onExpired`, once): the refresh is gone (no refresh token,\n * past its eight hours, consent revoked or past its 30 days, another\n * origin). The stored tokens are forgotten and the bar shows «Tu sesión de\n * Zap expiró» with «Volver a entrar». It is never «No puedes editar ni\n * comentar»: that card is for a 403 (no seat, or the site refused).\n */\n\n/** Renew this long before the access token's hour ends. */\nexport const REFRESH_LEAD_MS = 2 * 60_000\n\nexport interface TokenSession {\n /** The current access token (possibly near its end; prefer `call`). */\n token(): string\n /** True once renewal failed: the bar shows the expired state. */\n readonly expired: boolean\n /** A token good for the next call, renewing first when needed; null when expired. */\n ensure(): Promise<string | null>\n /** Renew now. Resolves true with a fresh token stored. Single flight. */\n refresh(): Promise<boolean>\n /**\n * Run `request` with a valid token; on a 401, renew and run it once more.\n * An expired session answers `{ ok: false, kind: 'expired' }` without\n * calling.\n */\n call<T>(request: (token: string) => Promise<ApiResult<T>>): Promise<ApiResult<T>>\n /** Stop the timers and the visibility listener. */\n destroy(): void\n}\n\nexport interface TokenSessionHooks {\n /** Renewal failed for good: show the expired state. Called once. */\n onExpired(): void\n}\n\nexport interface TokenSessionDeps {\n now?: () => number\n setTimeout?: (fn: () => void, ms: number) => unknown\n clearTimeout?: (handle: unknown) => void\n}\n\ntype Ctx = Pick<SiteContext, 'win' | 'doc' | 'authOrigin' | 'clientId' | 'siteId'>\n\nexport function createTokenSession(\n ctx: Ctx,\n stored: SiteToken,\n hooks: TokenSessionHooks,\n deps: TokenSessionDeps = {},\n): TokenSession {\n const { win, doc } = ctx\n const now = deps.now ?? (() => Date.now())\n const setT = deps.setTimeout ?? ((fn: () => void, ms: number) => win.setTimeout(fn, ms))\n const clearT = deps.clearTimeout ?? ((handle: unknown) => win.clearTimeout(handle as number))\n\n let current: SiteToken = stored\n let expired = false\n let destroyed = false\n let inflight: Promise<boolean> | null = null\n let timer: unknown = null\n\n function markExpired(): void {\n if (expired || destroyed) return\n expired = true\n stop()\n clearToken(win)\n hooks.onExpired()\n }\n\n async function renew(): Promise<boolean> {\n if (!refreshLive(current, now()) || !current.refresh) return false\n let response: Response\n try {\n response = await win.fetch(`${ctx.authOrigin}/api/oauth/token`, {\n method: 'POST',\n credentials: 'omit',\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: current.refresh,\n client_id: ctx.clientId,\n }),\n })\n } catch {\n return false\n }\n if (!response.ok) return false\n try {\n const next = await readTokenAnswer(response, ctx.siteId, now())\n // Rotation answers a new refresh token; without one, keep nothing stale.\n current = next\n writeToken(win, next)\n return true\n } catch {\n return false\n }\n }\n\n function refresh(): Promise<boolean> {\n if (expired || destroyed) return Promise.resolve(false)\n inflight ??= renew().finally(() => {\n inflight = null\n if (!destroyed && !expired) schedule()\n })\n return inflight\n }\n\n /** Renew if the hour is about to end (or has); expire if that fails past the margin. */\n async function check(): Promise<void> {\n if (expired || destroyed) return\n if (current.exp - REFRESH_LEAD_MS > now()) {\n schedule()\n return\n }\n const ok = await refresh()\n if (!ok && !accessLive(current, now())) markExpired()\n else if (!ok) {\n // Still a little hour left: try once more at the margin, then give up.\n stop()\n timer = setT(() => void lastTry(), Math.max(0, current.exp - EXPIRY_MARGIN_MS - now()))\n }\n }\n\n async function lastTry(): Promise<void> {\n if (!(await refresh())) markExpired()\n }\n\n function stop(): void {\n if (timer !== null) clearT(timer)\n timer = null\n }\n\n function schedule(): void {\n stop()\n if (expired || destroyed) return\n timer = setT(() => void check(), Math.max(0, current.exp - REFRESH_LEAD_MS - now()))\n }\n\n const onVisible = () => {\n if (doc.visibilityState === 'visible') void check()\n }\n doc.addEventListener('visibilitychange', onVisible)\n\n async function ensure(): Promise<string | null> {\n if (expired) return null\n if (accessLive(current, now())) return current.token\n if (await refresh()) return current.token\n markExpired()\n return null\n }\n\n async function call<T>(request: (token: string) => Promise<ApiResult<T>>): Promise<ApiResult<T>> {\n const token = await ensure()\n if (token === null) return { ok: false, kind: 'expired' }\n const first = await request(token)\n if (first.ok || first.kind !== 'expired') return first\n // A 401 with time left: revoked, or the clock disagrees. Renew and retry once.\n if (await refresh()) {\n const second = await request(current.token)\n if (!second.ok && second.kind === 'expired') markExpired()\n return second\n }\n markExpired()\n return first\n }\n\n // A session that arrives with its hour already spent renews at once.\n void check()\n\n return {\n token: () => current.token,\n get expired() {\n return expired\n },\n ensure,\n refresh,\n call,\n destroy() {\n destroyed = true\n stop()\n doc.removeEventListener('visibilitychange', onVisible)\n },\n }\n}\n\nexport const SESSION_MESSAGES = {\n es: {\n expiredTitle: 'Tu sesión de Zap expiró',\n expiredBody: 'Vuelve a entrar para seguir editando y comentando.',\n signInAgain: 'Volver a entrar',\n },\n en: {\n expiredTitle: 'Your Zap session expired',\n expiredBody: 'Sign in again to keep editing and commenting.',\n signInAgain: 'Sign in again',\n },\n} as const\n","import { buildAnchor, normalizeText } from '../anchor'\nimport { Overlay, OVERLAY_HOST_TAG, reveal as scrollTo, type OverlayPin } from '../overlay'\nimport type { OverlayMode } from '../protocol'\nimport { observeTags, tagGuard, TagIndex, type PauseReason, type TaggedElement } from '../tags'\nimport {\n createComment,\n fetchOnPage,\n newIdempotencyKey,\n saveToDraft,\n type ApiAnchor,\n type ApiFailure,\n type FieldInfo,\n type OnPage,\n type OnPageComment,\n} from './api'\nimport type { ChunkHandle, SiteContext, StartOptions } from './config'\nimport { barDrag, DRAG_CSS } from './drag'\nimport {\n DRAFT_SESSION_MESSAGES,\n inDraftSession,\n leaveDraftSession,\n requestDraftSession,\n takeEditIntent,\n} from './draft-session'\nimport { SUGGEST_MESSAGES } from './messages'\nimport { isShortcut } from './shortcut'\nimport {\n buildCreateBody,\n buildDraftBody,\n currentPageUrl,\n editableText,\n editKindFor,\n fieldOf,\n parseProposed,\n pinsFor,\n recordFor,\n sameValue,\n spotAnchor,\n toApiAnchor,\n type EditKind,\n type Proposal,\n} from './suggestion'\nimport { createTokenSession, SESSION_MESSAGES } from './session'\nimport { clearToken, readSession } from './token'\nimport { el, icon, initials, mountHost, TOKENS as T, type IconName } from './ui'\n\n/**\n * The `suggest` chunk: «Editar» and «Comentar» on the live site (zap-cms-v2\n * §3.4, owner 2026-10-05; boards SitioBarra, SitioEditar, SitioSugerencia,\n * SitioEnviado, SitioRenovacion), loaded only once this tab holds a site\n * client token. The file keeps its old name so the CDN chunk keeps its own.\n *\n * - **Toolbar** (SitioBarraEstados): the grip, Navegar, Editar and Comentar,\n * the page's open comments, the account chip and the hide arrow. Navegar\n * intercepts nothing and still shows the pins.\n * - **Account menu**: who you are, «Abrir en Zap» (the editor of the record\n * this page is, Zap's `viewer.editorUrl`, else Zap's home) and\n * «Cerrar sesión en Zap», which forgets the token as Salir did. A menu\n * button: arrows, Home and End move, Escape closes back to the chip, an\n * outside press or Tab closes it.\n * - **Paused** (the runaway guard, `tags.ts` `tagGuard`): a page over the\n * tagged cap at boot, or whose tagged count keeps growing on its own, stops\n * being followed: no more scans or pins, Editar and Comentar off, and a\n * quiet «Vista previa pausada» card over the bar with «Recargar» (the\n * pill says it in its label).\n * - **Hidden**: the hide arrow or Shift Z (the site's shortcut; never while\n * typing, editing or writing a comment) folds the bar into a pill with the\n * bolt and the open count, in the bar's place; a click or Shift Z brings it\n * back. Remembered per origin with the bar's place (`drag.ts`).\n * - **Editar** (only while the site's ADMIN leaves `liveEditing` on; off, the\n * tool shows disabled with «Desactivado por un administrador»): the overlay\n * outlines tagged fields; a click on a TEXT or LONG_TEXT field makes it\n * editable in place, a NUMBER or URL field opens a small input. Leaving the\n * field (or Enter) saves the new value straight to the record's draft\n * through Zap's save path and says «Guardado en el borrador»; Escape puts it\n * back. Nothing reaches the site's visitors until an ADMIN publishes in Zap.\n * - **Comentar**: the overlay outlines any element and consumes the click; a\n * click opens the composer anchored to that element, or to the point\n * clicked when the element is most of the page. Shift, Cmd or Ctrl click\n * gathers several elements for one comment. «Solicitar cambio» makes it a\n * change request, which Zap assigns to the record's Responsable; on a single\n * tagged text field it may carry «Proponer texto».\n * - **Pins**: the page's open comments (Zap's `on-page` read) as the\n * overlay's numbered gold pins, the same numbers as the editor's list; a\n * pin, or the count, opens the list.\n *\n * Everything renders in closed shadow roots as text (`ui.ts`, the overlay's\n * pins are `textContent` numbers). Excerpts, names and labels from Zap are\n * set with `textContent`; stored selectors only ever reach `safeQueryAll`.\n */\n\ntype Mode = 'navigate' | 'edit' | 'comment'\n\nconst OVERLAY_MODE: Record<Mode, OverlayMode> = {\n navigate: 'off',\n edit: 'inspect',\n comment: 'select',\n}\n\n/** The pin of the comment being written, never a thread id. */\nconst PENDING_PIN = 'eelzap:pending'\n\n/** An element taking at least this share of the viewport is commented as a point. */\nconst LARGE_SHARE = 0.5\n\nconst TOAST_MS = 8000\nconst SAVED_MS = 4000\n\ninterface Composer {\n elements: Element[]\n /** The point clicked, in viewport pixels, when the comment is on a point. */\n point: { x: number; y: number } | null\n pin: OverlayPin | null\n recordRef: string\n pageUrl: string\n anchors: ApiAnchor[]\n /** The one tagged text field a proposal may change, else null. */\n tagged: TaggedElement | null\n field: FieldInfo | null\n before: string\n card: HTMLElement\n textarea: HTMLTextAreaElement\n request: boolean\n proposing: boolean\n proposal: HTMLInputElement | HTMLTextAreaElement | null\n error: HTMLElement\n sendButton: HTMLButtonElement\n busy: boolean\n idempotency: { payload: string; key: string } | null\n}\n\ninterface Editing {\n element: HTMLElement\n tagged: TaggedElement\n field: FieldInfo\n kind: EditKind\n recordRef: string\n pageUrl: string\n anchors: ApiAnchor[]\n before: string\n /** Put the element back exactly as it was. */\n revert: () => void\n /** Stop editing, keeping what was typed. */\n keep: () => void\n card: HTMLElement | null\n input: HTMLInputElement | null\n done: boolean\n}\n\nexport function start(ctx: SiteContext, options: StartOptions = {}): ChunkHandle {\n const { win, doc } = ctx\n const stored = readSession(win, ctx.siteId)\n if (!stored) {\n void ctx.open('signin', { reason: 'expired' })\n return { destroy() {} }\n }\n // The token lifecycle (`session.ts`): every call gets a valid token, a 401\n // renews once and retries, and the hour is renewed ahead of time.\n const auth = createTokenSession(ctx, stored, { onExpired: () => expire() })\n const sm = SESSION_MESSAGES[ctx.locale]\n const m = SUGGEST_MESSAGES[ctx.locale]\n const dm = DRAFT_SESSION_MESSAGES[ctx.locale]\n // Editar asked for a draft session on this page and the tab came back in\n // draft mode: reopen Editar once the page read says it is allowed.\n let reopenEdit = takeEditIntent(win)\n\n const host = mountHost(doc, CSS + DRAG_CSS)\n const layer = el(doc, 'div', { class: 'layer' })\n const marks = el(doc, 'div', { class: 'marks' })\n const bottom = el(doc, 'div', { class: 'bottom' })\n // One tooltip for the bar's buttons, outside the toolbar: its horizontal scroll would clip it.\n const tip = el(doc, 'div', { class: 'tip', attrs: { role: 'tooltip' } })\n layer.append(marks, bottom, tip)\n const drag = barDrag(win, doc, bottom, m.move, m.moveTip)\n const key = ctx.shortcut ? ctx.shortcut.toUpperCase() : null\n host.root.append(layer)\n\n let mode: Mode = 'navigate'\n let selection: Element[] = []\n let data: OnPage | null = null\n let refused = false\n /** The session ran out and could not be renewed: «Volver a entrar». */\n let expired = false\n let composer: Composer | null = null\n let editing: Editing | null = null\n let list: OnPageComment[] | null = null\n let toast: { title: string; body: string; error?: boolean } | null = null\n let toastTimer: number | null = null\n let status: 'saving' | 'saved' | 'preparing' | null = null\n let statusTimer: number | null = null\n let frame: number | null = null\n let destroyed = false\n let pins: OverlayPin[] = []\n let numbers = new Map<string, number>()\n let lastClick = { x: 0, y: 0, additive: false }\n let menuOpen = false\n /** The `data-action` to focus after the next render. */\n let focusNext: string | null = null\n /** The next render shows the bar or the pill coming in (a toggle). */\n let entering = false\n let paused: PauseReason | null = null\n\n // Before the overlay installs its own capture listeners, so this one runs\n // first and still sees clicks the overlay consumes: where, and whether the\n // person was gathering elements.\n const onClickFirst = (event: MouseEvent) => {\n lastClick = {\n x: event.clientX,\n y: event.clientY,\n additive: event.shiftKey || event.metaKey || event.ctrlKey,\n }\n }\n win.addEventListener('click', onClickFirst, true)\n // A press anywhere on the page closes the account menu. Presses inside the\n // shadow root reach the window as the host; the layer sorts those out.\n const onPressFirst = (event: PointerEvent) => {\n if (menuOpen && event.target !== host.host) setMenu(false)\n }\n win.addEventListener('pointerdown', onPressFirst, true)\n layer.addEventListener('pointerdown', (event) => {\n if (!menuOpen) return\n const keep = Array.from(bottom.querySelectorAll('.menu, [data-action=\"account\"]'))\n if (!keep.some((node) => node.contains(event.target as Node))) setMenu(false)\n })\n\n const index = new TagIndex(doc)\n index.scan()\n const overlay = new Overlay({\n doc,\n win,\n index,\n pinsWhenOff: true,\n ignore: (target) => target === host.host,\n onInspect: (tagged) => beginEdit(tagged),\n onSelect: (elements) => onSelect(elements),\n onPin: ({ id }) => {\n if (id === PENDING_PIN) return\n const found = data?.comments.find((comment) => comment.id === id)\n if (!found) return\n list = [found]\n // A pin on the page while the bar is folded: the bar comes back with the thread.\n if (drag.hidden()) setHidden(false, false)\n else renderBottom()\n },\n })\n overlay.mount()\n // Both hosts sit at the top z-index, so document order decides: the bar\n // and its cards (this host) after the overlay's boxes, chips and pins.\n doc.documentElement.appendChild(host.host)\n\n // The runaway guard: a page over the cap is never observed; one that keeps\n // growing on its own stops being followed.\n const check = tagGuard()\n let stopObserving = () => {}\n const atBoot = check(index.elements.length, true)\n if (atBoot) {\n // Before the bar's first render, which shows it; the tools start on Navegar.\n paused = atBoot\n console.warn(`eelzap: preview paused (${atBoot})`)\n } else\n stopObserving = observeTags(\n doc.documentElement,\n (page) => {\n index.scan()\n const reason = check(index.elements.length, page)\n if (reason) pause(reason)\n else placePins()\n },\n {\n ignore: (node) => {\n const own = overlay.hostElement\n return node === host.host || (!!own && (node === own || own.contains(node)))\n },\n },\n )\n\n function pause(reason: PauseReason): void {\n if (paused) return\n paused = reason\n stopObserving()\n console.warn(`eelzap: preview paused (${reason})`)\n if (destroyed) return\n // Pins would drift on a page no longer followed: take them down.\n overlay.setPins([])\n setMode('navigate')\n }\n\n // ── Loading the page's context ──────────────────────────────────────────\n\n async function load(): Promise<void> {\n const refs = Array.from(new Set(index.elements.map((tagged) => tagged.recordRef)))\n const result = await auth.call((token) => fetchOnPage(ctx, token, currentPageUrl(win), refs))\n if (destroyed) return\n if (!result.ok) {\n onFailure(result)\n return\n }\n const first = data === null\n data = result.data\n // Labels by key for the page's own records; by tag, with «en …», for\n // fields of another record (a site-wide document in the header).\n const labels: Record<string, string> = {}\n const foreign: Record<string, [string, string]> = {}\n for (const [ref, fields] of Object.entries(data.fields ?? {})) {\n const name = data.records?.[ref]\n for (const [key, field] of Object.entries(fields)) {\n if (typeof field?.label !== 'string') continue\n if (name) foreign[`${ref}#${key}`] = [field.label, m.inRecord(name)]\n else labels[key] = field.label\n }\n }\n overlay.setLabels(labels, foreign)\n if (!data.liveEditing && mode === 'edit') setMode('navigate')\n if (reopenEdit) {\n reopenEdit = false\n if (canEdit()) setMode('edit')\n }\n if (first && options.reason === 'renewed') {\n const name = data.viewer?.name\n setToast({ title: m.renewed, body: name ? m.renewedAs(name) : m.renewedBody })\n }\n renderBottom()\n placePins()\n }\n\n function onFailure(failure: ApiFailure, during: 'read' | 'comment' | 'edit' = 'read'): void {\n if (failure.kind === 'expired') {\n expire()\n return\n }\n if (failure.kind === 'forbidden' && during === 'edit') {\n // «Editar» was turned off since the page read: the tool goes disabled.\n if (data) data.liveEditing = false\n setMode('navigate')\n setToast({ title: m.editOff, body: m.editOffBody, error: true })\n return\n }\n if (failure.kind === 'refused' || failure.kind === 'forbidden') {\n refused = true\n closeComposer()\n overlay.setMode('off')\n overlay.setPins([])\n renderBottom()\n return\n }\n const message = failure.kind === 'rate' ? m.rateLimited(failure.retryAfter) : m.failed\n if (during === 'comment' && composer) showError(message)\n else\n setToast({ title: during === 'edit' ? m.saveFailed : m.failed, body: message, error: true })\n }\n\n function expire(): void {\n clearToken(win)\n if (expired || destroyed) return\n // «Tu sesión de Zap expiró» with «Volver a entrar», not the refused card:\n // the person has access, their hour (and its renewal) ran out.\n expired = true\n closeComposer()\n overlay.setMode('off')\n renderBottom()\n }\n\n /** «Volver a entrar»: the sign-in starts inside this click, so the popup is allowed. */\n function signInAgain(): void {\n void ctx.open('signin', { reason: 'expired', signIn: true })\n }\n\n // ── Toolbar, tray, list, status, toast ──────────────────────────────────\n\n function canEdit(): boolean {\n return !!data?.liveEditing\n }\n\n function setMode(next: Mode): void {\n if ((next === 'edit' && !canEdit()) || (paused && next !== 'navigate')) return\n if (status === 'preparing') return\n // A page rendered outside draft mode carries no tags (no stega, empty\n // `attrs`): Editar first takes the tab through a draft session\n // (`draft-session.ts`), unless this tab is already in one.\n if (next === 'edit' && !index.elements.length && !inDraftSession(win)) {\n void prepareEdit()\n return\n }\n endEdit()\n closeComposer()\n mode = next\n selection = []\n overlay.clearSelection()\n overlay.setMode(OVERLAY_MODE[next])\n // In draft mode and still untagged: the page has no fields, so it says why.\n if (next === 'edit' && !index.elements.length)\n setToast({ title: m.noFields, body: m.noFieldsBody })\n renderBottom()\n }\n\n /**\n * Editar on an untagged page: exchange the site-client token for a draft\n * session and take the tab through the site's draft route; the page comes\n * back tagged and Editar reopens. On failure, the «no fields» empty state\n * with the reason.\n */\n async function prepareEdit(): Promise<void> {\n setStatus('preparing')\n const token = await auth.ensure()\n if (token === null || destroyed) return\n const result = await requestDraftSession(ctx, token)\n if (destroyed) return\n if (result.ok) {\n // Stays «Preparando la edición…» until the page unloads.\n win.location.assign(result.url)\n return\n }\n setStatus(null)\n if (result.reason === 'expired') {\n expire()\n return\n }\n const body =\n result.reason === 'no-route'\n ? dm.noRoute\n : result.reason === 'rate'\n ? dm.rate(result.retryAfter)\n : dm.failed\n setToast({ title: m.noFields, body, error: result.reason !== 'no-route' })\n }\n\n function renderBottom(): void {\n if (destroyed) return\n hideTip()\n // A render replaces the bar: keep focus on the same control.\n const active = host.root.activeElement?.getAttribute('data-action')\n const hidden = drag.hidden()\n const children: HTMLElement[] = []\n if (toast) children.push(toastCard(toast))\n if (expired) {\n children.push(expiredCard())\n bottom.replaceChildren(...children)\n drag.place()\n marks.replaceChildren()\n return\n }\n if (refused) {\n children.push(refusedCard())\n bottom.replaceChildren(...children)\n drag.place()\n marks.replaceChildren()\n return\n }\n if (paused && !hidden) children.push(pausedCard(paused))\n if (list && !hidden) children.push(listCard(list))\n if (selection.length > 0 && !composer && !hidden) children.push(trayCard())\n if (status) {\n children.push(\n el(doc, 'div', { class: 'card status', attrs: { role: 'status' } }, [\n status === 'saved' ? icon(doc, 'check', 14) : null,\n status === 'saved' ? m.saved : status === 'preparing' ? dm.preparing : m.saving,\n ]),\n )\n }\n if (menuOpen && !hidden) children.push(menuCard())\n const bar = hidden ? pill() : toolbar()\n if (entering) bar.setAttribute('data-enter', '')\n entering = false\n children.push(bar)\n bottom.replaceChildren(...children)\n drag.place()\n drawMarks()\n const want = focusNext ?? active\n focusNext = null\n if (want)\n bottom.querySelector<HTMLElement>(`[data-action=\"${want}\"]`)?.focus({ preventScroll: true })\n }\n\n function openCount(): [number, string] {\n const open = data?.comments.length ?? 0\n return [open, data?.truncated ? `${open}+` : String(open)]\n }\n\n function setMenu(open: boolean, focus: string | null = null): void {\n if (menuOpen === open && !focus) return\n menuOpen = open\n focusNext = focus\n renderBottom()\n }\n\n /** Bar to pill and back. `fromUi`: focus follows to the other control. */\n function setHidden(value: boolean, fromUi: boolean): void {\n if (refused || drag.hidden() === value) return\n if (value) {\n endEdit()\n closeComposer()\n selection = []\n overlay.clearSelection()\n list = null\n menuOpen = false\n }\n drag.setHidden(value)\n overlay.setMode(value ? 'off' : OVERLAY_MODE[mode])\n focusNext = fromUi ? (value ? 'show' : 'hide') : null\n entering = true\n renderBottom()\n }\n\n /** The bar's tooltip (SitioBarraEstados) with the shortcut's key chip, on hover and keyboard focus. */\n function withTip(target: HTMLElement, text: string, end: boolean): HTMLElement {\n const show = () => {\n tip.replaceChildren(text)\n if (key) tip.append(el(doc, 'span', { class: 'kbd', text: `Shift ${key}` }))\n tip.classList.add('on')\n const rect = target.getBoundingClientRect()\n const vw = doc.documentElement.clientWidth || win.innerWidth\n const w = tip.offsetWidth\n // Over the bar: 8px off its edge (the hide arrow sits 7px inside it), under it when the bar opens down.\n const gap = end ? 15 : 8\n const x = end ? rect.right + 7 - w : rect.left + (rect.width - w) / 2\n tip.style.left = `${Math.min(Math.max(x, 8), vw - w - 8)}px`\n tip.style.top = bottom.hasAttribute('data-below')\n ? `${rect.bottom + gap}px`\n : `${rect.top - gap - tip.offsetHeight}px`\n }\n const focus = () => {\n try {\n if (target.matches(':focus-visible')) show()\n } catch {\n show()\n }\n }\n for (const [type, handler] of [\n ['mouseenter', show],\n ['focus', focus],\n ['mouseleave', hideTip],\n ['blur', hideTip],\n ['pointerdown', hideTip],\n ] as const) {\n target.addEventListener(type, handler)\n }\n if (key) target.setAttribute('aria-keyshortcuts', `Shift+${key}`)\n return target\n }\n\n function hideTip(): void {\n tip.classList.remove('on')\n }\n\n function avatar(name: string | null, large = false): HTMLElement {\n return el(doc, 'span', {\n class: large ? 'avatar lg' : 'avatar',\n attrs: { 'aria-hidden': 'true' },\n text: initials(name),\n })\n }\n\n function menuCard(): HTMLElement {\n const name = data?.viewer?.name ?? null\n const email = data?.viewer?.email ?? null\n const item = (action: string, label: string, glyph: IconName, run: () => void) =>\n el(\n doc,\n 'button',\n {\n class: 'mi',\n attrs: { type: 'button', role: 'menuitem', tabindex: '-1', 'data-action': action },\n on: {\n click: run,\n pointerenter: (event) => (event.currentTarget as HTMLElement).focus(),\n },\n },\n [icon(doc, glyph), label],\n )\n return el(\n doc,\n 'div',\n {\n class: 'card menu',\n attrs: { role: 'menu', 'aria-label': m.accountMenu, tabindex: '-1', 'data-action': 'menu' },\n on: { keydown: onMenuKey },\n },\n [\n el(doc, 'div', { class: 'menu-head' }, [\n avatar(name, true),\n el(doc, 'div', { class: 'menu-who' }, [\n el(doc, 'span', { class: 'menu-name', text: name ?? m.someone }),\n email ? el(doc, 'span', { class: 'menu-mail', text: email }) : null,\n ]),\n ]),\n el(doc, 'div', { class: 'sep', attrs: { role: 'separator' } }),\n item('open-zap', m.openInZap, 'external', () => {\n setMenu(false, 'account')\n win.open(zapUrl(data?.viewer?.editorUrl, ctx.zapOrigin), '_blank', 'noopener')\n }),\n el(doc, 'div', { class: 'sep', attrs: { role: 'separator' } }),\n item('sign-out', m.signOut, 'exit', exit),\n ],\n )\n }\n\n function onMenuKey(event: Event): void {\n const e = event as KeyboardEvent\n if (e.key === 'Tab') {\n // Close, and let Tab move on from the chip.\n setMenu(false, 'account')\n return\n }\n const items = Array.from(bottom.querySelectorAll<HTMLElement>('.menu [role=\"menuitem\"]'))\n const at = items.indexOf(host.root.activeElement as HTMLElement)\n const to = (\n { ArrowDown: at + 1, ArrowUp: at < 0 ? -1 : at - 1, Home: 0, End: -1 } as Record<\n string,\n number\n >\n )[e.key]\n if (to === undefined) return\n e.preventDefault()\n items[(to + items.length) % items.length]?.focus()\n }\n\n function pill(): HTMLElement {\n const [open, shown] = openCount()\n // The pill drags like the grip (`drag.ts`); a press that did not move is the click.\n return withTip(\n drag.grab(\n el(\n doc,\n 'button',\n {\n class: 'card pill',\n attrs: {\n type: 'button',\n 'aria-label':\n m.showBar(open).replace(String(open), shown) + (paused ? `. ${m.paused}` : ''),\n 'data-action': 'show',\n },\n on: { click: () => setHidden(false, true) },\n },\n [\n icon(doc, 'zap', 20),\n el(doc, 'span', { class: 'pill-count' }, [icon(doc, 'thread', 14), shown]),\n ],\n ),\n ),\n m.show,\n false,\n )\n }\n\n function toolbar(): HTMLElement {\n const [open, shown] = openCount()\n const name = data?.viewer?.name ?? null\n const tool = (value: Mode, label: string, glyph: IconName) => {\n const off = (value === 'edit' && !canEdit()) || (!!paused && value !== 'navigate')\n // Disabled by the ADMIN: says so; still loading: just not yet.\n const why = paused && off ? m.paused : off && data ? m.editOff : null\n return el(\n doc,\n 'button',\n {\n class: 'seg',\n attrs: {\n type: 'button',\n 'aria-pressed': String(mode === value),\n 'aria-disabled': off ? 'true' : null,\n title: why,\n 'data-tip': why,\n 'data-mode': value,\n },\n on: { click: () => setMode(value) },\n },\n [icon(doc, glyph, 14), label],\n )\n }\n return el(\n doc,\n 'div',\n { class: 'card toolbar', attrs: { role: 'toolbar', 'aria-label': m.toolbar } },\n [\n drag.handle,\n el(doc, 'span', { class: 'divider', attrs: { 'aria-hidden': 'true' } }),\n icon(doc, 'zap', 20),\n el(doc, 'div', { class: 'segments', attrs: { role: 'group', 'aria-label': m.tools } }, [\n tool('navigate', m.navigate, 'pointer'),\n tool('edit', m.edit, 'pencil'),\n tool('comment', m.comment, 'commentPlus'),\n ]),\n el(doc, 'span', { class: 'divider', attrs: { 'aria-hidden': 'true' } }),\n el(\n doc,\n 'button',\n {\n class: 'tool strong',\n attrs: { type: 'button', 'aria-expanded': String(!!list), 'data-action': 'open-list' },\n on: {\n click: () => {\n list = list ? null : (data?.comments ?? [])\n renderBottom()\n },\n },\n },\n [icon(doc, 'thread'), m.open(open).replace(String(open), shown)],\n ),\n el(doc, 'span', { class: 'divider', attrs: { 'aria-hidden': 'true' } }),\n el(\n doc,\n 'button',\n {\n class: 'tool account',\n attrs: {\n type: 'button',\n 'aria-haspopup': 'menu',\n 'aria-expanded': String(menuOpen),\n 'aria-label': name ? m.account(name) : m.accountMenu,\n 'data-action': 'account',\n },\n on: {\n // A pointer opens onto the menu itself; Enter or Space onto its first item.\n click: (event) =>\n setMenu(\n !menuOpen,\n menuOpen ? 'account' : (event as MouseEvent).detail ? 'menu' : 'open-zap',\n ),\n keydown: (event) => {\n const k = (event as KeyboardEvent).key\n if (k !== 'ArrowDown' && k !== 'ArrowUp') return\n event.preventDefault()\n setMenu(true, k === 'ArrowUp' ? 'sign-out' : 'open-zap')\n },\n },\n },\n [avatar(name), icon(doc, 'chevron', 13)],\n ),\n withTip(\n el(\n doc,\n 'button',\n {\n class: 'tool hide',\n attrs: { type: 'button', 'aria-label': m.hide, 'data-action': 'hide' },\n on: { click: () => setHidden(true, true) },\n },\n [icon(doc, 'eyeOff', 16)],\n ),\n m.hide,\n true,\n ),\n ],\n )\n }\n\n function trayCard(): HTMLElement {\n return el(doc, 'div', { class: 'card tray', attrs: { role: 'status' } }, [\n el(doc, 'span', { text: m.selected(selection.length) }),\n el(doc, 'button', {\n class: 'btn btn-outline',\n text: m.clearSelection,\n attrs: { type: 'button' },\n on: {\n click: () => {\n selection = []\n overlay.clearSelection()\n renderBottom()\n },\n },\n }),\n el(doc, 'button', {\n class: 'btn btn-primary',\n text: m.comment,\n attrs: { type: 'button', 'data-action': 'comment-selection' },\n on: {\n click: () => {\n const elements = selection\n selection = []\n overlay.clearSelection()\n openComposer(elements, null)\n },\n },\n }),\n ])\n }\n\n function listCard(comments: OnPageComment[]): HTMLElement {\n return el(\n doc,\n 'div',\n { class: 'card list sheet', attrs: { role: 'dialog', 'aria-label': m.openTitle } },\n [\n el(doc, 'div', { class: 'head' }, [\n el(doc, 'h2', { text: m.openTitle }),\n closeButton(m.dismiss, () => {\n list = null\n renderBottom()\n }),\n ]),\n comments.length === 0\n ? el(doc, 'p', { class: 'muted', text: m.noneOpen })\n : el(\n doc,\n 'ul',\n {},\n comments.map((comment) => {\n const n = numbers.get(comment.id)\n return el(doc, 'li', {}, [\n el(\n doc,\n 'button',\n {\n class: 'item',\n attrs: { type: 'button', 'data-comment': comment.id },\n on: { click: () => reveal(comment.id) },\n },\n [\n n ? el(doc, 'span', { class: 'num', text: String(n) }) : null,\n el(doc, 'span', { class: 'item-text' }, [\n el(doc, 'span', { class: 'who', text: comment.author?.name || m.someone }),\n comment.isChangeRequest\n ? el(doc, 'span', { class: 'flag', text: m.changeRequest })\n : null,\n el(doc, 'span', { class: 'what', text: comment.excerpt ?? '' }),\n ]),\n ],\n ),\n ])\n }),\n ),\n ],\n )\n }\n\n /** Scroll to a thread's pin. */\n function reveal(id: string): void {\n const pin = pins.find((entry) => entry.id === id)\n if (pin?.element) scrollTo(win, pin.element)\n else if (pin?.spot) {\n const root = doc.documentElement\n win.scrollTo?.({\n top: Math.max(0, pin.spot.y * root.scrollHeight - win.innerHeight / 2),\n behavior: 'smooth',\n })\n }\n }\n\n function toastCard(value: { title: string; body: string; error?: boolean }): HTMLElement {\n return el(\n doc,\n 'div',\n {\n class: value.error ? 'card toast toast-error' : 'card toast',\n attrs: { role: 'status', 'aria-live': 'polite' },\n },\n [\n icon(doc, value.error ? 'alert' : 'check', 18),\n el(doc, 'div', { class: 'toast-text' }, [\n el(doc, 'span', { class: 'title', text: value.title }),\n el(doc, 'span', { class: 'muted', text: value.body }),\n ]),\n closeButton(m.dismiss, () => setToast(null)),\n ],\n )\n }\n\n /** The guard's pause (the editor banner's words), quiet: the refused card's layout, a muted icon. */\n function pausedCard(reason: PauseReason): HTMLElement {\n return el(doc, 'div', { class: 'card refused paused', attrs: { role: 'status' } }, [\n icon(doc, 'alert', 18),\n el(doc, 'div', { class: 'toast-text' }, [\n el(doc, 'span', { class: 'title', text: m.paused }),\n el(doc, 'span', {\n class: 'muted',\n text: reason === 'cap' ? m.pausedCap : m.pausedRunaway,\n }),\n ]),\n el(doc, 'button', {\n class: 'tool',\n text: m.reload,\n attrs: { type: 'button', 'data-action': 'reload' },\n on: { click: () => win.location.reload() },\n }),\n ])\n }\n\n /** The session ran out (item 32): not a refusal, so the way back is one click. */\n function expiredCard(): HTMLElement {\n return el(doc, 'div', { class: 'card refused', attrs: { role: 'alert' } }, [\n icon(doc, 'alert', 18),\n el(doc, 'div', { class: 'toast-text' }, [\n el(doc, 'span', { class: 'title', text: sm.expiredTitle }),\n el(doc, 'span', { class: 'muted', text: sm.expiredBody }),\n ]),\n el(\n doc,\n 'button',\n {\n class: 'tool',\n attrs: { type: 'button', 'data-action': 'sign-in-again' },\n on: { click: signInAgain },\n },\n [icon(doc, 'eel'), sm.signInAgain],\n ),\n ])\n }\n\n function refusedCard(): HTMLElement {\n return el(doc, 'div', { class: 'card refused', attrs: { role: 'alert' } }, [\n icon(doc, 'alert', 18),\n el(doc, 'div', { class: 'toast-text' }, [\n el(doc, 'span', { class: 'title', text: m.refusedTitle }),\n el(doc, 'span', { class: 'muted', text: m.refusedBody }),\n ]),\n el(\n doc,\n 'button',\n { class: 'tool', attrs: { type: 'button', 'data-action': 'exit' }, on: { click: exit } },\n [icon(doc, 'exit'), m.exit],\n ),\n ])\n }\n\n function closeButton(label: string, onClick: () => void): HTMLElement {\n return el(\n doc,\n 'button',\n {\n class: 'iconbtn',\n attrs: { type: 'button', 'aria-label': label, title: label },\n on: { click: onClick },\n },\n [icon(doc, 'x')],\n )\n }\n\n function setToast(value: typeof toast): void {\n toast = value\n if (toastTimer !== null) win.clearTimeout(toastTimer)\n toastTimer = value ? win.setTimeout(() => setToast(null), TOAST_MS) : null\n renderBottom()\n }\n\n function setStatus(value: typeof status): void {\n status = value\n if (statusTimer !== null) win.clearTimeout(statusTimer)\n statusTimer = value === 'saved' ? win.setTimeout(() => setStatus(null), SAVED_MS) : null\n renderBottom()\n }\n\n function exit(): void {\n // Drop this tab's draft session too (revoked at Zap, the cookie through\n // the site's exit route, then a published reload) when it has one.\n void leaveDraftSession(ctx, auth.token(), index.elements.length > 0)\n clearToken(win)\n ctx.close()\n }\n\n // ── Pins and marks ──────────────────────────────────────────────────────\n\n function placePins(): void {\n if (destroyed || refused || paused || !data) return\n const placed = pinsFor(data.comments ?? [], index, doc, win)\n pins = placed.pins\n numbers = placed.numbers\n overlay.setPins(composer?.pin ? [...pins, composer.pin] : pins)\n }\n\n /** The soft gold outline around what is being edited or commented (SitioEditar). */\n function drawMarks(): void {\n const targets = editing ? [editing.element] : (composer?.elements ?? [])\n marks.replaceChildren(\n ...targets\n .filter((element) => element.isConnected)\n .map((element) => {\n const rect = element.getBoundingClientRect()\n const box = el(doc, 'div', { class: 'mark' })\n box.style.left = `${rect.left - 3}px`\n box.style.top = `${rect.top - 3}px`\n box.style.width = `${rect.width + 6}px`\n box.style.height = `${rect.height + 6}px`\n return box\n }),\n )\n }\n\n function schedule(): void {\n if (frame !== null) return\n const raf = win.requestAnimationFrame?.bind(win) ?? ((fn: () => void) => win.setTimeout(fn, 16))\n frame = raf(() => {\n frame = null\n drawMarks()\n if (composer) position(composer.card, anchorRect(composer))\n if (editing?.card) position(editing.card, editing.element.getBoundingClientRect())\n }) as number\n }\n\n function position(card: HTMLElement, rect: Pick<DOMRect, 'left' | 'top' | 'bottom'>): void {\n const width = Math.min(420, win.innerWidth - 16)\n const height = card.offsetHeight || 260\n const below = rect.bottom + 10\n const top = below + height < win.innerHeight - 90 ? below : Math.max(8, rect.top - height - 10)\n const left = Math.min(Math.max(8, rect.left), Math.max(8, win.innerWidth - width - 8))\n card.style.width = `${width}px`\n card.style.top = `${top}px`\n card.style.left = `${left}px`\n }\n\n // ── Comentar ────────────────────────────────────────────────────────────\n\n function onSelect(elements: Element[]): void {\n if (mode !== 'comment' || composer) return\n if (elements.length === 0) {\n if (selection.length > 0) {\n selection = []\n renderBottom()\n }\n return\n }\n if (lastClick.additive || elements.length > 1) {\n selection = elements\n renderBottom()\n return\n }\n const element = elements[0]!\n overlay.clearSelection()\n if (isLarge(element)) openComposer([], { x: lastClick.x, y: lastClick.y }, element)\n else openComposer([element], null)\n }\n\n /** Most of the viewport: a wrapper, not the thing the person pointed at. */\n function isLarge(element: Element): boolean {\n const rect = element.getBoundingClientRect()\n const area = Math.max(1, win.innerWidth * win.innerHeight)\n return (rect.width * rect.height) / area >= LARGE_SHARE\n }\n\n function anchorRect(session: Composer): Pick<DOMRect, 'left' | 'top' | 'bottom'> {\n const first = session.elements[0]\n if (first) return first.getBoundingClientRect()\n const point = session.point ?? { x: 0, y: 0 }\n return { left: point.x, top: point.y, bottom: point.y }\n }\n\n function openComposer(\n elements: Element[],\n point: { x: number; y: number } | null,\n owner?: Element,\n ): void {\n if (refused || (elements.length === 0 && !point)) return\n const recordRef = recordFor(elements[0] ?? owner ?? doc.body, index)\n if (!recordRef) {\n setToast({ title: m.failed, body: m.noRecord, error: true })\n return\n }\n list = null\n const pageUrl = currentPageUrl(win)\n const anchors: ApiAnchor[] = point\n ? [spotAnchor(point.x, point.y, doc, win)]\n : elements\n .slice(0, 20)\n .map((element) => toApiAnchor(buildAnchor(element, index, pageUrl, doc, win), recordRef))\n const single = elements.length === 1 ? elements[0]! : null\n const own = single ? index.get(single) : null\n const tagged = own && own.recordRef === recordRef ? own : null\n const field = fieldOf(data, tagged)\n const proposable = editKindFor(tagged, field) !== null\n const target = single as HTMLElement | null\n const before =\n field?.type === 'URL' && target?.localName === 'a'\n ? (target.getAttribute('href') ?? '')\n : normalizeText(target?.textContent ?? '')\n const spotPin = point ? anchors[0] : null\n\n const textarea = el(doc, 'textarea', {\n class: 'composer',\n attrs: {\n 'aria-label': m.commentLabel,\n rows: '3',\n maxlength: '10000',\n placeholder: m.commentPlaceholder,\n },\n })\n const error = el(doc, 'p', { class: 'error', attrs: { role: 'alert' } })\n const sendButton = el(\n doc,\n 'button',\n {\n class: 'btn btn-primary',\n attrs: { type: 'button', 'data-action': 'send' },\n on: { click: () => void submit() },\n },\n [icon(doc, 'commentPlus', 16), m.comment],\n )\n const title = tagged\n ? el(doc, 'span', { class: 'chip' }, [\n icon(doc, 'field', 12),\n field?.label || tagged.fieldKey,\n ])\n : el(doc, 'h2', {\n text: elements.length > 1 ? m.selected(elements.length) : m.commentTitle,\n })\n const extra = el(doc, 'div', { class: 'extra' })\n const card = el(\n doc,\n 'div',\n { class: 'card popover sheet', attrs: { role: 'dialog', 'aria-label': m.newComment } },\n [\n el(doc, 'div', { class: 'head' }, [title, closeButton(m.close, closeComposer)]),\n el(doc, 'div', { class: 'content' }, [\n textarea,\n extra,\n error,\n // A dialog footer: a full-bleed rule, Cancelar and the primary (OWNER-PASS 19).\n el(doc, 'div', { class: 'foot' }, [\n el(doc, 'button', {\n class: 'btn btn-outline',\n text: m.cancel,\n attrs: { type: 'button' },\n on: { click: closeComposer },\n }),\n sendButton,\n ]),\n ]),\n ],\n )\n layer.append(card)\n\n composer = {\n elements,\n point,\n pin:\n spotPin && 'spot' in spotPin\n ? { id: PENDING_PIN, n: (numbers.size || 0) + 1, spot: spotPin.spot }\n : null,\n recordRef,\n pageUrl,\n anchors,\n tagged: proposable ? tagged : null,\n field: proposable ? field : null,\n before,\n card,\n textarea,\n request: false,\n proposing: false,\n proposal: null,\n error,\n sendButton,\n busy: false,\n idempotency: null,\n }\n renderExtra(extra)\n textarea.addEventListener('input', refreshSend)\n // Enter sends, Shift+Enter breaks the line, as the editor's comment box and\n // Swarm's; the Enter that commits an IME candidate never sends.\n textarea.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || event.shiftKey || event.isComposing || event.keyCode === 229) {\n return\n }\n event.preventDefault()\n if (!sendButton.disabled) void submit()\n })\n overlay.setMode('off')\n placePins()\n refreshSend()\n renderBottom()\n position(card, anchorRect(composer))\n textarea.focus()\n }\n\n /** «Solicitar cambio», who receives it, and «Proponer texto» (SitioSugerencia). */\n function renderExtra(extra: HTMLElement): void {\n const session = composer\n if (!session) return\n const toggle = el(\n doc,\n 'button',\n {\n class: 'check',\n attrs: {\n type: 'button',\n role: 'checkbox',\n 'aria-checked': String(session.request),\n 'data-action': 'request-change',\n },\n on: {\n click: () => {\n session.request = !session.request\n if (!session.request) {\n session.proposing = false\n session.proposal = null\n }\n renderExtra(extra)\n refreshSend()\n },\n },\n },\n [el(doc, 'span', { class: 'box', attrs: { 'aria-hidden': 'true' } }), m.requestChange],\n )\n const parts: Array<HTMLElement | null> = [toggle]\n if (session.request) {\n parts.push(el(doc, 'p', { class: 'muted small', text: m.recipient }))\n parts.push(el(doc, 'p', { class: 'muted small', text: m.requestHelp }))\n if (session.tagged && session.field && !session.proposing) {\n parts.push(\n el(\n doc,\n 'button',\n {\n class: 'btn btn-outline propose',\n attrs: { type: 'button', 'data-action': 'propose' },\n on: {\n click: () => {\n session.proposing = true\n renderExtra(extra)\n refreshSend()\n session.proposal?.focus()\n },\n },\n },\n [icon(doc, 'pencil', 14), m.propose],\n ),\n )\n }\n if (session.tagged && session.field && session.proposing) {\n const label = session.field.label || session.tagged.fieldKey\n const input =\n session.field.type === 'LONG_TEXT'\n ? el(doc, 'textarea', {\n class: 'value',\n attrs: { 'aria-label': m.proposal, rows: '3', maxlength: '10000' },\n })\n : el(doc, 'input', {\n class: 'value',\n attrs: {\n 'aria-label': m.proposal,\n type: 'text',\n inputmode: session.field.type === 'NUMBER' ? 'decimal' : null,\n },\n })\n input.value = session.proposal?.value ?? session.before\n input.addEventListener('input', refreshSend)\n session.proposal = input\n parts.push(\n el(doc, 'div', { class: 'proposal' }, [\n el(doc, 'div', { class: 'head' }, [\n el(doc, 'span', { class: 'small strong-text', text: `${m.proposalFor} ${label}` }),\n closeButton(m.removeProposal, () => {\n session.proposing = false\n session.proposal = null\n renderExtra(extra)\n refreshSend()\n }),\n ]),\n session.before\n ? el(doc, 'p', { class: 'muted small before' }, [\n `${m.now} `,\n el(doc, 'span', { class: 'strong-text', text: session.before }),\n ])\n : null,\n input,\n ]),\n )\n }\n }\n extra.replaceChildren(...parts.filter((part): part is HTMLElement => part !== null))\n }\n\n /** The proposal typed, null when none or unchanged, `invalid` for a number that is not one. */\n function proposalOf(session: Composer): Proposal | null | 'invalid' {\n if (!session.request || !session.proposing || !session.proposal) return null\n if (!session.tagged || !session.field) return null\n const parsed = parseProposed(session.field.type, session.proposal.value)\n if (!parsed.ok) return 'invalid'\n const before = parseProposed(session.field.type, session.before)\n if (before.ok && sameValue(before.value, parsed.value)) return null\n return { fieldKey: session.tagged.fieldKey, locale: session.tagged.locale, value: parsed.value }\n }\n\n function refreshSend(): void {\n const session = composer\n if (!session) return\n const proposal = proposalOf(session)\n const comment = session.textarea.value.trim()\n // The primary names what it does: «Comentar», or «Solicitar cambio» once flagged.\n session.sendButton.replaceChildren(\n icon(doc, session.request ? 'pencil' : 'commentPlus', 16),\n session.busy ? m.sending : session.request ? m.requestChange : m.comment,\n )\n // Text, or a parsed proposal that is not empty: either makes a body.\n const proposed = proposal && proposal !== 'invalid' && String(proposal.value) !== ''\n session.sendButton.disabled = session.busy || proposal === 'invalid' || (!comment && !proposed)\n session.error.textContent =\n proposal === 'invalid' ? m.invalidNumber : (session.error.dataset.sticky ?? '')\n }\n\n function showError(message: string): void {\n if (!composer) return\n composer.error.dataset.sticky = message\n composer.error.textContent = message\n }\n\n async function submit(): Promise<void> {\n const session = composer\n if (!session || session.busy) return\n const proposal = proposalOf(session)\n if (proposal === 'invalid') return\n const body = buildCreateBody({\n recordRef: session.recordRef,\n pageUrl: session.pageUrl,\n anchors: session.anchors,\n comment: session.textarea.value,\n isChangeRequest: session.request,\n proposal,\n })\n if (!body.body) return\n // One key per payload: a retry of the same request is the same request.\n const payload = JSON.stringify(body)\n if (session.idempotency?.payload !== payload) {\n session.idempotency = { payload, key: newIdempotencyKey(win) }\n }\n session.busy = true\n delete session.error.dataset.sticky\n refreshSend()\n const key = session.idempotency.key\n const result = await auth.call((token) => createComment(ctx, token, body, key))\n if (destroyed || composer !== session) return\n session.busy = false\n if (!result.ok) {\n refreshSend()\n onFailure(result, 'comment')\n return\n }\n closeComposer()\n const assignee = result.data?.thread?.assignee?.name\n setToast(\n body.isChangeRequest\n ? {\n title: m.sentRequest,\n body: m.sentRequestBody(\n typeof assignee === 'string' && assignee ? assignee : null,\n !!body.proposedValues,\n ),\n }\n : { title: m.sentComment, body: m.sentCommentBody },\n )\n void load()\n }\n\n function closeComposer(): void {\n const session = composer\n if (!session) return\n composer = null\n session.card.remove()\n if (!refused) {\n overlay.setMode(OVERLAY_MODE[mode])\n placePins()\n }\n renderBottom()\n }\n\n // ── Editar ──────────────────────────────────────────────────────────────\n\n function beginEdit(tagged: TaggedElement): void {\n if (mode !== 'edit' || refused || !canEdit()) return\n if (editing && !editing.done) {\n if (editing.element === tagged.element) return\n commitEdit(editing)\n }\n const field = fieldOf(data, tagged)\n const kind = editKindFor(tagged, field)\n if (!kind || !field) {\n setToast({ title: m.notEditable, body: m.notEditableBody, error: true })\n return\n }\n const element = tagged.element as HTMLElement\n const pageUrl = currentPageUrl(win)\n // The anchor BEFORE any edit: its text quote is what was published.\n const anchors = [toApiAnchor(buildAnchor(element, index, pageUrl, doc, win), tagged.recordRef)]\n const before =\n field.type === 'URL' && element.localName === 'a'\n ? (element.getAttribute('href') ?? '')\n : normalizeText(element.textContent ?? '')\n const inline = kind === 'text' ? beginInlineEdit(element) : null\n const session: Editing = {\n element,\n tagged,\n field,\n kind,\n recordRef: tagged.recordRef,\n pageUrl,\n anchors,\n before,\n revert: inline?.revert ?? (() => {}),\n keep: inline?.keep ?? (() => {}),\n card: null,\n input: null,\n done: false,\n }\n editing = session\n if (inline) {\n element.addEventListener('blur', () => commitEdit(session), { once: true })\n element.focus?.()\n } else {\n openInputCard(session)\n }\n renderBottom()\n }\n\n /** NUMBER and URL: a small input beside the element; the page itself is not touched. */\n function openInputCard(session: Editing): void {\n const input = el(doc, 'input', {\n class: 'value',\n attrs: {\n 'aria-label': session.field.label || session.tagged.fieldKey,\n type: 'text',\n inputmode: session.field.type === 'NUMBER' ? 'decimal' : 'url',\n },\n })\n input.value = session.before\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n commitEdit(session)\n }\n })\n const card = el(doc, 'div', { class: 'card popover sheet', attrs: { role: 'dialog' } }, [\n el(doc, 'div', { class: 'head' }, [\n el(doc, 'span', { class: 'chip' }, [\n icon(doc, 'field', 12),\n session.field.label || session.tagged.fieldKey,\n ]),\n closeButton(m.close, () => cancelEdit(session)),\n ]),\n el(doc, 'div', { class: 'content' }, [\n input,\n el(doc, 'div', { class: 'actions' }, [\n el(doc, 'button', {\n class: 'btn btn-outline',\n text: m.cancel,\n attrs: { type: 'button' },\n on: { click: () => cancelEdit(session) },\n }),\n el(doc, 'button', {\n class: 'btn btn-primary',\n text: m.save,\n attrs: { type: 'button', 'data-action': 'save' },\n on: { click: () => commitEdit(session) },\n }),\n ]),\n ]),\n ])\n session.card = card\n session.input = input\n layer.append(card)\n position(card, session.element.getBoundingClientRect())\n input.focus()\n }\n\n /** Make the element editable in place; how to put it back, or keep what was typed. */\n function beginInlineEdit(target: HTMLElement): { revert: () => void; keep: () => void } {\n const children = Array.from(target.childNodes)\n const texts: Array<[Text, string]> = []\n const walker = doc.createTreeWalker(target, 4 /* NodeFilter.SHOW_TEXT */)\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n texts.push([node as Text, (node as Text).data])\n }\n const hadAttribute = target.getAttribute('contenteditable')\n target.setAttribute('contenteditable', 'plaintext-only')\n if (target.contentEditable !== 'plaintext-only') target.setAttribute('contenteditable', 'true')\n target.setAttribute('spellcheck', 'true')\n const keep = () => {\n if (hadAttribute === null) target.removeAttribute('contenteditable')\n else target.setAttribute('contenteditable', hadAttribute)\n target.removeAttribute('spellcheck')\n }\n return {\n keep,\n revert: () => {\n keep()\n // The SAME nodes back, with their text: a framework holding them keeps working.\n target.replaceChildren(...children)\n for (const [node, text] of texts) node.data = text\n },\n }\n }\n\n function typedValue(session: Editing): string {\n if (session.input) return session.input.value\n return editableText(session.element)\n }\n\n function finishEdit(session: Editing, keepTyped: boolean): void {\n session.done = true\n if (keepTyped) session.keep()\n else session.revert()\n session.card?.remove()\n if (editing === session) editing = null\n renderBottom()\n }\n\n function cancelEdit(session: Editing): void {\n if (session.done) return\n finishEdit(session, false)\n }\n\n /** Save what was typed to the draft, or put the element back when nothing changed. */\n function commitEdit(session: Editing): void {\n if (session.done) return\n const parsed = parseProposed(session.field.type, typedValue(session))\n if (!parsed.ok) {\n finishEdit(session, false)\n setToast({ title: m.saveFailed, body: m.invalidNumber, error: true })\n return\n }\n // Nothing changed (stega markers and whitespace aside): put the element\n // back and write nothing, no thread and no draft.\n const before = parseProposed(session.field.type, session.before)\n if (before.ok && sameValue(before.value, parsed.value)) {\n finishEdit(session, false)\n return\n }\n finishEdit(session, true)\n void save(session, {\n fieldKey: session.tagged.fieldKey,\n locale: session.tagged.locale,\n value: parsed.value,\n })\n }\n\n async function save(session: Editing, proposal: Proposal): Promise<void> {\n setStatus('saving')\n const body = buildDraftBody({\n recordRef: session.recordRef,\n pageUrl: session.pageUrl,\n anchors: session.anchors,\n proposal,\n })\n // One key for the retry after a renewal too: a 401 wrote nothing, and the\n // same key keeps a doubled answer from saving twice.\n const draftKey = newIdempotencyKey(win)\n const result = await auth.call((token) => saveToDraft(ctx, token, body, draftKey))\n if (destroyed) return\n if (!result.ok) {\n // The page goes back to what is published; nothing was saved.\n session.revert()\n setStatus(null)\n onFailure(result, 'edit')\n return\n }\n setStatus('saved')\n }\n\n function endEdit(): void {\n if (editing && !editing.done) commitEdit(editing)\n }\n\n // ── Page events ─────────────────────────────────────────────────────────\n\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') hideTip()\n if (menuOpen && event.key === 'Escape') {\n event.preventDefault()\n setMenu(false, 'account')\n return\n }\n // Shift Z: bar to pill and back, never while editing a field or writing a comment.\n if (ctx.shortcut && !editing && !composer && isShortcut(event, ctx.shortcut)) {\n setHidden(!drag.hidden(), !!host.root.activeElement)\n return\n }\n if (composer && event.key === 'Escape') {\n event.preventDefault()\n closeComposer()\n return\n }\n const session = editing\n if (!session || session.done) return\n if (event.key === 'Escape') {\n event.preventDefault()\n cancelEdit(session)\n } else if (\n event.key === 'Enter' &&\n session.kind === 'text' &&\n event.target === session.element &&\n (session.field.type === 'TEXT' || event.metaKey || event.ctrlKey)\n ) {\n // A one-line field stays one line; Enter (Cmd or Ctrl Enter for long text) saves.\n event.preventDefault()\n commitEdit(session)\n }\n }\n /** Links and forms work in Navegar (or with the bar folded) only. */\n const blocks = () => mode !== 'navigate' && !drag.hidden()\n const onClick = (event: MouseEvent) => {\n // The element being edited may be (or sit in) a link: place the caret, never navigate.\n // The overlay consumes link clicks while it is on; this covers the\n // moments it is off in Editar or Comentar (the composer is open).\n if (\n (editing?.kind === 'text' &&\n !editing.done &&\n editing.element.contains(event.target as Node)) ||\n (blocks() && (event.target as Element).closest?.('a[href],area[href]'))\n ) {\n event.preventDefault()\n }\n }\n const onSubmit = (event: Event) => {\n if (blocks()) event.preventDefault()\n }\n win.addEventListener('keydown', onKey, true)\n win.addEventListener('click', onClick, true)\n win.addEventListener('submit', onSubmit, true)\n win.addEventListener('scroll', schedule, true)\n win.addEventListener('resize', schedule)\n\n overlay.setMode(drag.hidden() ? 'off' : OVERLAY_MODE[mode])\n renderBottom()\n void load()\n\n return {\n destroy() {\n endEdit()\n destroyed = true\n closeComposer()\n auth.destroy()\n if (toastTimer !== null) win.clearTimeout(toastTimer)\n if (statusTimer !== null) win.clearTimeout(statusTimer)\n win.removeEventListener('click', onClickFirst, true)\n win.removeEventListener('pointerdown', onPressFirst, true)\n win.removeEventListener('keydown', onKey, true)\n win.removeEventListener('click', onClick, true)\n win.removeEventListener('submit', onSubmit, true)\n win.removeEventListener('scroll', schedule, true)\n win.removeEventListener('resize', schedule)\n stopObserving()\n overlay.destroy()\n drag.destroy()\n host.destroy()\n },\n }\n}\n\n/**\n * «Abrir en Zap»: the record's editor URL when Zap sent one (http or https\n * only, never another scheme), else Zap's home.\n */\nexport function zapUrl(editorUrl: string | null | undefined, zapOrigin: string): string {\n const home = new URL('/', zapOrigin)\n try {\n const url = new URL(editorUrl ?? '')\n if (url.protocol === 'https:' || url.protocol === 'http:') return url.href\n } catch {\n // No URL, or not one: Zap's home.\n }\n return home.href\n}\n\n/** Exported for specs: the overlay's own host tag, which the site tools never draw over. */\nexport { OVERLAY_HOST_TAG }\n\nconst CSS = `\n.marks { position: fixed; inset: 0; pointer-events: none; }\n.mark { position: fixed; border-radius: 4px; outline: 2px solid rgba(207,135,0,.55); }\n.bottom { position: fixed; left: 0; right: 0; bottom: 22px; display: flex; flex-direction: column;\n align-items: center; gap: 10px; pointer-events: none; padding: 0 8px; }\n.bottom > .card { position: relative; }\n.toolbar { display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 4px; white-space: nowrap;\n max-width: 100%; overflow-x: auto; }\n.segments { display: inline-flex; gap: 2px; padding: 2px; border-radius: 7px; background: ${T.subtle};\n background: oklch(0.94 0.008 250); }\n.seg { position: relative; height: 28px; padding: 0 10px; border-radius: 5px; font-size: 12px; color: ${T.muted}; }\n.seg[aria-pressed=\"true\"] { background: ${T.bg}; color: ${T.fg}; box-shadow: 0 1px 2px rgba(15,23,42,.05); }\n.seg[aria-disabled=\"true\"] { opacity: .5; cursor: default; }\n.seg[data-tip]:hover::after { content: attr(data-tip); position: absolute; bottom: 34px; left: 50%;\n transform: translateX(-50%); padding: 6px 10px; border-radius: 9px; background: ${T.dark}; color: #FFFFFF;\n font-size: 12px; white-space: nowrap; }\n.tool { height: 30px; padding: 0 9px; border-radius: 9px; color: ${T.muted}; }\n/* Hover as the suite's SegmentedControl and ghost button (SitioBarraEstados): a tool on the track\n gets foreground text over white at 60%, no shadow; the bar's own buttons, on the white card, the\n ghost hover: foreground text over slate-100. Both keep the focus ring. */\n.seg:not([aria-pressed=\"true\"]):not([aria-disabled=\"true\"]):hover { background: rgba(255,255,255,.6); color: ${T.fg}; }\n.tool:hover, .grip:hover, .account[aria-expanded=\"true\"] { background: #F1F5F9; color: ${T.fg}; }\n.seg, .tool, .grip, .pill { transition: color .15s cubic-bezier(.4,0,.2,1), background-color .15s cubic-bezier(.4,0,.2,1); }\n.seg:focus-visible, .tool:focus-visible, .grip:focus-visible { box-shadow: 0 0 0 3px ${T.focus}; }\n/* The account chip and the hide arrow (SitioBarraEstados): ghost buttons, chevrons muted until hover. */\n.account { padding: 0 4px 0 2px; gap: 3px; }\n.hide { width: 30px; padding: 0; justify-content: center; }\n.avatar.lg { width: 32px; height: 32px; }\n.menu { width: 260px; padding: 4px; border-radius: 11px; outline: none;\n box-shadow: 0 10px 15px -3px rgba(15,23,42,.1), 0 4px 6px -4px rgba(15,23,42,.08); }\n.menu-head { display: flex; align-items: center; gap: 10px; padding: 8px 8px 10px; }\n.menu-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n.menu-name { font-weight: 500; }\n.menu-mail { font-size: 12px; color: ${T.muted}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.sep { height: 1px; background: ${T.border}; margin: 4px -4px; }\n.menu-head + .sep { margin-top: 0; }\n.mi { width: 100%; height: 32px; gap: 9px; padding: 0 8px; border-radius: 7px; font-weight: 400; color: ${T.fg}; }\n.mi > .icon { color: ${T.muted}; }\n.mi:focus, .mi:focus-visible { outline: none; background: #F1F5F9; box-shadow: none; }\n.pill { height: 44px; gap: 8px; padding: 0 12px 0 11px; border-radius: 999px; }\n.pill:hover { background: #F8FAFC; }\n.pill:focus-visible { box-shadow: 0 0 0 3px ${T.focus}, 0 20px 25px -5px rgba(15,23,42,.12); }\n.pill-count { display: inline-flex; align-items: center; gap: 4px; }\n.tip { position: fixed; display: inline-flex; align-items: center; gap: 8px; padding: 5px 6px 5px 9px;\n border-radius: 7px; background: #101828; color: #FFFFFF; font-weight: 500; font-size: 12px; line-height: 18px;\n white-space: nowrap; pointer-events: none; }\n.tip:not(.on) { display: none; }\n.kbd { font-size: 11px; line-height: 16px; color: #CBD5E1; padding: 1px 5px; border-radius: 4px;\n background: rgba(255,255,255,.12); }\n[data-enter] { animation: eelzap-in .16s cubic-bezier(.4,0,.2,1); }\n@keyframes eelzap-in { from { opacity: 0; transform: scale(.96); } }\n@media (prefers-reduced-motion: reduce) { .seg, .tool, .grip, .pill { transition: none; } [data-enter] { animation: none; } }\n.tool.strong { color: ${T.fg}; }\n.divider { width: 1px; height: 22px; background: ${T.border}; }\n.avatar { width: 26px; height: 26px; border-radius: 7px; background: #DBEAFE; color: #1D4ED8;\n display: inline-flex; align-items: center; justify-content: center; font-weight: 600; font-size: 12px; }\n.status { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px;\n font-size: 12px; font-weight: 500; }\n.status > .icon { color: #16A34A; }\n.tray { display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 14px; }\n.list { width: min(420px, calc(100vw - 16px)); padding: 13px 10px 10px 15px; max-height: 50vh; overflow: auto; }\n.list ul { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }\n.item { width: 100%; text-align: left; align-items: flex-start; gap: 10px; padding: 8px; border-radius: 9px; }\n.item:hover { background: ${T.subtle}; }\n.num { flex-shrink: 0; width: 22px; height: 22px; border-radius: 999px 999px 999px 0; background: #CF8700;\n color: #FFFFFF; font-weight: 700; font-size: 11px; display: inline-flex; align-items: center; justify-content: center; }\n.item-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n.who { font-weight: 600; font-size: 12px; }\n.flag { font-size: 11px; color: ${T.goldText}; }\n.what { font-weight: 400; color: ${T.muted}; overflow-wrap: anywhere; }\n.toast, .refused { width: min(340px, calc(100vw - 16px)); display: flex; gap: 11px; padding: 14px 12px 14px 16px;\n align-self: flex-end; margin-right: 16px; }\n.refused { align-self: center; margin-right: 0; width: min(420px, calc(100vw - 16px)); align-items: flex-start; }\n.toast > .icon { color: #16A34A; }\n.refused > .icon, .toast-error > .icon { color: ${T.danger}; }\n.paused > .icon { color: ${T.muted}; }\n.toast-text { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }\n.title { font-weight: 600; }\n.head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.popover { border-radius: 13px; }\n.popover > .head { padding: 13px 10px 0 15px; }\n.content { display: flex; flex-direction: column; gap: 11px; padding: 10px 15px 15px; }\n.extra { display: flex; flex-direction: column; gap: 8px; }\n.check { gap: 8px; font-size: 13px; align-self: flex-start; }\n.check .box { width: 16px; height: 16px; border-radius: 4px; border: 1px solid #90A1B9; background: ${T.bg}; }\n.check[aria-checked=\"true\"] .box { background: ${T.primary}; border-color: ${T.primaryBorder};\n box-shadow: inset 0 0 0 3px ${T.bg}; }\n.propose { align-self: flex-start; height: 30px; }\n.proposal { display: flex; flex-direction: column; gap: 6px; padding: 10px; border-radius: 12px; background: ${T.goldTint}; }\n.chip { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px 0 6px; border-radius: 7px;\n background: ${T.goldTint}; color: ${T.goldText}; font: 400 12px Poppins, ui-sans-serif, system-ui, sans-serif;\n white-space: nowrap; max-width: 220px; overflow: hidden; text-overflow: ellipsis; }\n.before { overflow-wrap: anywhere; }\n.strong-text { color: ${T.fg}; }\n.small { font-size: 12px; }\n.composer, .value { width: 100%; font: 400 13px/22px Poppins, ui-sans-serif, system-ui, sans-serif; color: ${T.fg};\n border: 1px solid ${T.border}; border-radius: 12px; padding: 8px 12px; background: ${T.bg}; resize: vertical; }\ninput.value { height: 36px; border-radius: 9px; }\n.composer:focus, .value:focus { border-color: #90A1B9; box-shadow: 0 0 0 3px ${T.focus}; outline: none; }\n.error:empty { display: none; }\n.actions { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }\n.foot { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; margin: 2px -15px -15px;\n padding: 11px 15px; border-top: 1px solid ${T.border}; }\n.foot .btn { height: 30px; gap: 7px; }\n.foot .btn-outline { padding: 0 14px; }\n`\n"],"mappings":"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","names":["storage","write","call","key","reveal","onClick"]}
|