@seatlayer/js 0.49.0 → 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hostedCheckout.ts","../src/index.ts","../src/SeatingChart.ts","../src/buyerRealtime.ts","../src/api.ts","../src/buyerAccess.ts","../src/seatLayerBrand.ts","../src/EmbeddedDesigner.ts","../src/SeatPicker.ts","../src/buyerAssets.ts","../src/offerAvailability.ts","../src/attachPickerFrame.ts"],"sourcesContent":["/**\n * Hosted checkout — the payment step, as a module nobody downloads until a\n * buyer actually asks to pay.\n *\n * This is the whole of what `checkout: 'hosted'` adds to SeatPicker: a card\n * that collects an email, starts a payment against `POST /pub/events/:key/\n * checkout`, hands off to the gateway, and waits for the webhook to land. It is\n * a straight port of the panel our own buyer page has shipped since hosted\n * checkout existed (`src/pages/CheckoutPanel.tsx`), with React and the app's\n * shared api client taken out.\n *\n * IT IMPORTS NOTHING AT RUNTIME. Not `@seatlayer/core`, not `./api`, not even a\n * type from `./SeatPicker` — every input arrives through {@link CheckoutMount},\n * including the two API calls, which arrive as functions. That is not\n * fastidiousness: this file is built as a standalone CDN asset\n * (`seatlayer-checkout.mjs`), and a single value import from the engine would\n * pull a second copy of it into that asset and undo the point of splitting.\n *\n * Three states, one card, because they are the same moment in the buyer's\n * journey and share every pixel of chrome:\n *\n * pay a live hold — collect an email and START a payment\n * resume back from a hosted gateway page — the hold and its line items\n * are gone with the old document, so this can only WAIT on the\n * order id that survived in the return URL. It must never offer\n * to start a second payment for a purchase that may have already\n * succeeded.\n * unavailable the event cannot take money here, and the buyer is holding\n * seats. Say which of the three reasons it is, because two of\n * them give opposite advice.\n */\n\n/** The gateways `payment-options` can name. */\nexport type CheckoutProviderName = 'stripe' | 'razorpay';\n\n/**\n * Why `payment-options` came back with an empty list. Mirrors the server enum\n * (`workers/api/src/checkout.ts`); see {@link unavailableCopy} for what each one\n * is allowed to say.\n */\nexport type CheckoutUnavailableReason =\n | 'not_configured'\n | 'payments_off_for_event'\n | 'unavailable_for_event';\n\n/** What `POST /pub/events/:key/checkout` returns. Exactly one handoff is set. */\nexport interface CheckoutSessionResult {\n orderId: string;\n totalMinor: number;\n currency: string;\n expiresAt: number;\n /** Hosted gateway page (Stripe) — leave for it. */\n redirectUrl?: string;\n /** In-page modal gateway (Razorpay) — open it here. */\n clientPayload?: Record<string, unknown>;\n}\n\n/** What `GET /pub/orders/:id/status` returns while the webhook is in flight. */\nexport interface CheckoutOrderStatus {\n orderId: string;\n status: string;\n totalMinor: number;\n currency: string;\n amountFormatted: string;\n seatCount: number;\n // Present once the order is settled: the confirmed card names the seats it\n // just sold and points at the hosted ticket page that outlives this modal.\n tickets?: Array<{\n label: string;\n token: string;\n status: 'issued' | 'checked_in' | 'void';\n checkedInAt: number | null;\n }>;\n /** Hosted ticket page — the durable re-entry point after the card closes. */\n ticketUrl?: string;\n /** Printable A4 PDF, up to three ticket cards per page. */\n pdfUrl?: string;\n}\n\n/** The buyer's held order, flattened out of the widget's CheckoutHandoff. */\nexport interface CheckoutOrderSummary {\n holdId: string;\n /** Epoch ms the hold expires — shown so the buyer knows their deadline. */\n expiresAt: number;\n currency: string;\n /** Total in MAJOR units, already carrying any host `pricing` overrides. */\n total: number;\n /** Buyer-facing unit labels (displayLabel where the designer set one). */\n labels: string[];\n}\n\nexport type CheckoutState =\n | { kind: 'pay'; order: CheckoutOrderSummary; provider: CheckoutProviderName | null }\n | { kind: 'resume'; orderId: string }\n | { kind: 'unavailable'; reason: CheckoutUnavailableReason; seatCount: number };\n\nexport interface CheckoutMount {\n /** Where the card mounts — the widget root, so every `--sl-*` token inherits. */\n root: HTMLElement;\n state: CheckoutState;\n /** `POST /pub/events/:key/checkout`, already bound to the event and client. */\n startSession(input: {\n holdId: string; buyerEmail: string; buyerName?: string;\n }): Promise<CheckoutSessionResult>;\n /** `GET /pub/orders/:id/status`. */\n orderStatus(orderId: string): Promise<CheckoutOrderStatus>;\n /** Buyer backed out, or closed a finished card. The hold is NOT touched. */\n onCancel(): void;\n /** The webhook landed and the order is paid. Fires at most once. */\n onConfirmed(order: CheckoutOrderStatus): void;\n /** Anything the buyer was already told about, forwarded to the host. */\n onError?(err: unknown): void;\n}\n\nexport interface CheckoutHandle {\n destroy(): void;\n}\n\n/** How long to wait on the webhook before telling the buyer to watch their email. */\nconst CONFIRM_TIMEOUT_MS = 90_000;\nconst CONFIRM_POLL_MS = 2_000;\nconst RAZORPAY_SCRIPT = 'https://checkout.razorpay.com/v1/checkout.js';\nconst STYLE_ID = 'seatlayer-checkout-style';\n\n/**\n * The card's stylesheet. Every colour, font and radius is a `--sl-*` token the\n * widget root already defines, so an organizer's accent and a host's `theme`\n * overrides reach the payment step without this module knowing either exists.\n *\n * The `@sl-css` marker opts it into build-time minification — see\n * cdn/minifyCssLiterals.ts. Keep writing it long-hand.\n */\nconst CSS = /* @sl-css */ `\n.sl-hco{position:absolute;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;\n padding:16px;background:color-mix(in srgb, var(--sl-bg) 82%, transparent);backdrop-filter:blur(3px)}\n.sl-hco-card{width:100%;max-width:380px;max-height:100%;overflow:auto;padding:22px;\n background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);\n border-radius:var(--sl-radius);box-shadow:0 18px 48px rgba(0,0,0,.28)}\n.sl-hco-title{margin:0 0 14px;font-size:19px;font-weight:650;letter-spacing:-.01em}\n.sl-hco-summary{margin-bottom:16px;padding-bottom:14px;border-bottom:1px solid var(--sl-line)}\n.sl-hco-seats{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}\n.sl-hco-seat{padding:3px 8px;font-size:12px;font-weight:600;border-radius:calc(var(--sl-radius) * .5);\n background:var(--sl-bg);border:1px solid var(--sl-line)}\n.sl-hco-total{display:flex;justify-content:space-between;align-items:baseline;font-size:14px}\n.sl-hco-total strong{font-size:17px;font-weight:700}\n.sl-hco-label{display:block;margin:12px 0 5px;font-size:12px;font-weight:600;color:var(--sl-muted)}\n.sl-hco-input{width:100%;padding:10px 11px;font:inherit;font-size:15px;color:var(--sl-text);\n background:var(--sl-bg);border:1px solid var(--sl-line);border-radius:calc(var(--sl-radius) * .55)}\n.sl-hco-input:focus-visible{outline:2px solid var(--sl-accent);outline-offset:1px}\n.sl-hco-pay{width:100%;margin-top:16px;padding:12px;font:inherit;font-size:15px;font-weight:650;\n color:var(--sl-accent-ink);background:var(--sl-accent);border:0;\n border-radius:calc(var(--sl-radius) * .55);cursor:pointer}\n.sl-hco-pay[disabled]{opacity:.5;cursor:default}\n.sl-hco-back{width:100%;margin-top:8px;padding:10px;font:inherit;font-size:14px;color:var(--sl-muted);\n background:none;border:0;cursor:pointer;text-decoration:underline}\n.sl-hco-note{margin:12px 0 0;font-size:12px;line-height:1.5;color:var(--sl-muted)}\n.sl-hco-note a{color:inherit;text-decoration:underline;text-underline-offset:2px}\n.sl-hco-status{margin:8px 0 0;font-size:14px;line-height:1.55}\n.sl-hco-error{color:var(--sl-danger, #c0392b)}\n.sl-hco-receipt{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin:14px 0 0;font-size:13px}\n.sl-hco-receipt dt{color:var(--sl-muted)}\n.sl-hco-receipt dd{margin:0;text-align:right}\n.sl-hco-ref{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all}\n.sl-hco-tickets{display:block;width:100%;margin-top:14px;padding:12px;font:inherit;font-size:15px;\n font-weight:650;text-align:center;text-decoration:none;color:var(--sl-accent-ink);\n background:var(--sl-accent);border-radius:calc(var(--sl-radius) * .55)}\n`;\n\nfunction ensureStyle(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\n/**\n * Money for the buyer's eye. `Intl` is the right answer everywhere it exists;\n * the fallback is a plain amount and a code, which is never wrong — only plain.\n */\nexport function formatMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(amount);\n } catch {\n return `${amount.toFixed(2)} ${currency}`;\n }\n}\n\n/**\n * What a buyer holding seats is told when the event cannot take their money,\n * and why the three differ. Pure, so the wording is unit-tested rather than\n * eyeballed.\n *\n * not_configured The organizer integrates by API and owns payment.\n * SeatLayer holds the inventory; their host takes the\n * money. Nothing is wrong and the buyer's checkout is\n * somewhere else on this very page.\n * payments_off_for_event The organizer sells other events through us and chose\n * not to sell this one online. NOTHING IS WRONG.\n * Telling this buyer to \"let the organiser know\" would\n * send them to complain about a deliberate decision.\n * unavailable_for_event The organizer switched this event on and it still\n * cannot charge — a test key against a live event, or a\n * gateway disconnected after assignment. Something IS\n * wrong and only they can fix it.\n *\n * None of them names a provider, a mode or an account: the buyer is anonymous\n * and the reason enum is the entire disclosure budget.\n */\nexport function unavailableCopy(reason: CheckoutUnavailableReason, seatCount: number): {\n title: string; body: string; detail: string;\n} {\n const held = `${seatCount} ${seatCount === 1 ? 'seat is' : 'seats are'} held for a limited time.`;\n if (reason === 'payments_off_for_event') {\n return {\n title: 'This event isn’t sold online',\n body: `${held} The organiser isn’t taking payment for this event here.`,\n detail: 'Nothing has been charged. Check where you found this event for how to get tickets.',\n };\n }\n if (reason === 'unavailable_for_event') {\n return {\n title: 'This event isn’t taking payment yet',\n body: `${held} Online payment is not switched on for this event.`,\n detail: 'Nothing has been charged. If you were sent here to pay, let the organiser know — '\n + 'only they can turn payment on for this event.',\n };\n }\n return {\n title: 'Finish in the ticketing checkout',\n body: `${held} Payment for this event is taken elsewhere.`,\n detail: 'Nothing has been charged. Continue in the checkout on this page to pay for your seats.',\n };\n}\n\n/**\n * Buyer-facing text for a server error code.\n *\n * Each one says what happened to their MONEY, because that is the only question\n * a buyer has at this moment. None of these paths can have charged them — the\n * charge does not exist until the gateway page — so every message says so.\n */\nexport function errorCopy(code: string | undefined): string {\n switch (code) {\n case 'gateway_not_connected':\n case 'payments_not_enabled_for_event':\n return 'This event is not taking online payments. Contact the organiser to buy these seats.';\n case 'provider_mismatch':\n // Only reachable if a caller sent a provider of its own. The widget never\n // does — it lets the event row decide — so this is a host integration bug,\n // and the buyer is told the one thing that is true for them.\n return 'This event’s payment setup changed while you were choosing. Nothing was charged — '\n + 'please try again.';\n case 'hold_not_active':\n case 'hold_not_found':\n return 'Your seats were released before checkout started. Nothing was charged — please pick again.';\n case 'checkout_already_started':\n return 'A payment for these seats is already in progress. Finish that one, or wait for it to '\n + 'time out before starting again.';\n case 'event_closed':\n return 'Sales for this event have closed.';\n case 'insufficient_hosted_credits':\n return 'Ticket sales are temporarily paused while the organiser updates their SeatLayer balance. '\n + 'Nothing was charged — please try again later or contact the organiser.';\n case 'gateway_currency_mismatch':\n case 'unsupported_currency':\n case 'mixed_currency_hold':\n case 'price_unusable':\n return 'These seats cannot be checked out right now because of a pricing configuration '\n + 'problem. Nothing was charged — please contact the organiser.';\n case 'rate_limited':\n return 'Too many attempts. Wait a moment and try again.';\n default:\n return 'We could not start the payment. Nothing was charged — please try again.';\n }\n}\n\n/** Razorpay's script attaches this constructor; typed narrowly at the call site. */\ninterface RazorpayCheckout { open(): void }\ntype RazorpayConstructor = new (options: Record<string, unknown>) => RazorpayCheckout;\n\nfunction loadRazorpay(): Promise<RazorpayConstructor> {\n const existing = (window as unknown as { Razorpay?: RazorpayConstructor }).Razorpay;\n if (existing) return Promise.resolve(existing);\n return new Promise((resolve, reject) => {\n // Reuse an in-flight tag if the buyer retries before the first load settles.\n const previous = document.querySelector<HTMLScriptElement>(`script[src=\"${RAZORPAY_SCRIPT}\"]`);\n const tag = previous ?? document.createElement('script');\n const done = (): void => {\n const ctor = (window as unknown as { Razorpay?: RazorpayConstructor }).Razorpay;\n if (ctor) resolve(ctor);\n else reject(new Error('razorpay_unavailable'));\n };\n tag.addEventListener('load', done, { once: true });\n tag.addEventListener('error', () => reject(new Error('razorpay_script_failed')), { once: true });\n if (previous) return;\n tag.src = RAZORPAY_SCRIPT;\n tag.async = true;\n document.head.appendChild(tag);\n });\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K, className?: string, text?: string,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (className) node.className = className;\n // textContent, never innerHTML: an event name, a seat label and a server\n // message all reach this card, and none of them is trusted markup.\n if (text !== undefined) node.textContent = text;\n return node;\n}\n\n/**\n * Mount the payment card.\n *\n * Returns a handle rather than a promise: the card outlives the call (the buyer\n * types, pays, waits), and the widget needs a way to tear it down if the host\n * destroys the picker mid-payment.\n */\nexport function mountCheckout(mount: CheckoutMount): CheckoutHandle {\n ensureStyle();\n\n let live = true;\n let confirmed = false;\n const scrim = el('div', 'sl-hco');\n scrim.setAttribute('role', 'dialog');\n scrim.setAttribute('aria-modal', 'true');\n const card = el('div', 'sl-hco-card');\n scrim.appendChild(card);\n\n const destroy = (): void => {\n live = false;\n scrim.remove();\n document.removeEventListener('keydown', onKey, true);\n };\n const cancel = (): void => {\n destroy();\n mount.onCancel();\n };\n function onKey(event: KeyboardEvent): void {\n if (event.key !== 'Escape' || !scrim.isConnected) return;\n // The picker has its own document-level ESC handler for modal mode. Stopping\n // here means one press closes the payment card, not the whole widget with a\n // payment possibly in flight.\n event.stopPropagation();\n event.preventDefault();\n cancel();\n }\n document.addEventListener('keydown', onKey, true);\n\n const title = el('h2', 'sl-hco-title', 'Checkout');\n const titleId = `sl-hco-t-${Math.random().toString(36).slice(2, 8)}`;\n title.id = titleId;\n scrim.setAttribute('aria-labelledby', titleId);\n\n /** Replace everything under the title — each phase owns the card's body. */\n const show = (...nodes: Node[]): void => {\n card.replaceChildren(title, ...nodes);\n };\n\n const fail = (message: string): void => {\n if (!live) return;\n const status = el('p', 'sl-hco-status sl-hco-error', message);\n status.setAttribute('role', 'alert');\n const back = el('button', 'sl-hco-back', 'Back to seats');\n back.type = 'button';\n back.addEventListener('click', cancel);\n show(status, back);\n };\n\n const waiting = (message: string): void => {\n if (!live) return;\n const status = el('p', 'sl-hco-status', message);\n status.setAttribute('role', 'status');\n show(status);\n };\n\n /**\n * Poll the order until the webhook lands.\n *\n * The buyer's browser is never the authority here — it is only waiting for\n * one. On timeout we tell them the truth (payment likely taken, confirmation\n * by email) rather than claiming a failure that did not happen.\n */\n const awaitConfirmation = async (orderId: string): Promise<void> => {\n waiting('Payment received — confirming your seats…');\n const deadline = Date.now() + CONFIRM_TIMEOUT_MS;\n while (live && Date.now() < deadline) {\n try {\n const body = await mount.orderStatus(orderId);\n if (!live) return;\n if (body.status === 'confirmed') {\n confirmed = true;\n title.textContent = 'Your tickets are confirmed';\n const status = el(\n 'p', 'sl-hco-status',\n `${body.seatCount} ${body.seatCount === 1 ? 'seat' : 'seats'} confirmed. `\n + 'Your tickets — with their door QR codes — are in your email.',\n );\n const receipt = el('dl', 'sl-hco-receipt');\n const seatLabels = (body.tickets ?? []).map((t) => t.label);\n if (seatLabels.length) {\n receipt.append(el('dt', undefined, 'Seats'), el('dd', undefined, seatLabels.join(', ')));\n }\n receipt.append(\n el('dt', undefined, 'Paid'),\n el('dd', undefined, `${body.amountFormatted} ${body.currency}`),\n el('dt', undefined, 'Order'),\n el('dd', 'sl-hco-ref', body.orderId),\n );\n const close = el('button', 'sl-hco-back', 'Close');\n close.type = 'button';\n close.addEventListener('click', cancel);\n if (body.ticketUrl) {\n // The durable exit: a hosted page owning the QRs and the PDF, so\n // closing this card is no longer the end of the buyer's artifacts.\n const view = el('a', 'sl-hco-tickets', 'View tickets & QR codes');\n view.href = body.ticketUrl;\n view.target = '_blank';\n view.rel = 'noreferrer';\n show(status, receipt, view, close);\n } else {\n show(status, receipt, close);\n }\n mount.onConfirmed(body);\n return;\n }\n if (body.status === 'failed' || body.status === 'expired') {\n fail(body.status === 'expired'\n ? 'Your seats were released before payment completed. Nothing was charged — please pick again.'\n : 'The payment did not complete. If you were charged, it has been refunded automatically.');\n return;\n }\n } catch {\n // A transient blip while polling is not an answer. Keep waiting.\n }\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS));\n }\n if (!live || confirmed) return;\n // Deliberately not an error: the money may well have gone through and the\n // webhook is just slow. The confirmation email is the durable receipt.\n fail('Still confirming with the payment provider. If your payment went through, your tickets '\n + 'will arrive by email shortly — you do not need to pay again.');\n };\n\n if (mount.state.kind === 'unavailable') {\n const copy = unavailableCopy(mount.state.reason, mount.state.seatCount);\n title.textContent = copy.title;\n const kicker = el('p', 'sl-hco-label', 'Seats held');\n const back = el('button', 'sl-hco-back', 'Back to seat map');\n back.type = 'button';\n back.addEventListener('click', cancel);\n card.replaceChildren(\n kicker, title,\n el('p', 'sl-hco-status', copy.body),\n el('p', 'sl-hco-note', copy.detail),\n back,\n );\n mount.root.appendChild(scrim);\n back.focus();\n return { destroy };\n }\n\n if (mount.state.kind === 'resume') {\n // A fresh document after a hosted gateway page. Everything except the order\n // id died with the old one, so this can only wait.\n mount.root.appendChild(scrim);\n void awaitConfirmation(mount.state.orderId);\n return { destroy };\n }\n\n const { order, provider } = mount.state;\n const summary = el('div', 'sl-hco-summary');\n const seats = el('div', 'sl-hco-seats');\n for (const label of order.labels) seats.appendChild(el('span', 'sl-hco-seat', label));\n const totalText = formatMoney(order.total, order.currency);\n const totalRow = el('div', 'sl-hco-total');\n totalRow.append(el('span', undefined, 'Total'), el('strong', undefined, totalText));\n summary.append(seats, totalRow);\n\n const form = el('form', 'sl-hco-form');\n const emailLabel = el('label', 'sl-hco-label', 'Email — your tickets go here');\n const email = el('input', 'sl-hco-input');\n email.type = 'email';\n email.required = true;\n email.autocomplete = 'email';\n email.placeholder = 'you@example.com';\n email.id = `${titleId}-email`;\n emailLabel.htmlFor = email.id;\n\n const nameLabel = el('label', 'sl-hco-label', 'Name (optional)');\n const name = el('input', 'sl-hco-input');\n name.type = 'text';\n name.autocomplete = 'name';\n name.placeholder = 'Your name';\n name.id = `${titleId}-name`;\n nameLabel.htmlFor = name.id;\n\n const pay = el('button', 'sl-hco-pay', `Pay ${totalText}`);\n pay.type = 'submit';\n pay.disabled = true;\n const back = el('button', 'sl-hco-back', 'Back to seats');\n back.type = 'button';\n back.addEventListener('click', cancel);\n\n const until = new Date(order.expiresAt)\n .toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n const note = el(\n 'p', 'sl-hco-note',\n `Your seats are held until ${until}. Payment is handled by `\n + `${provider === 'razorpay' ? 'Razorpay' : 'Stripe'} — we never see your card details.`,\n );\n const privacy = el('p', 'sl-hco-note');\n privacy.append('The event organizer and SeatLayer use your email to issue and manage your tickets. ');\n const privacyLink = el('a', undefined, 'Privacy Policy');\n privacyLink.href = 'https://seatlayer.io/privacy/';\n privacyLink.target = '_blank';\n privacyLink.rel = 'noreferrer';\n privacy.appendChild(privacyLink);\n\n const emailValid = (): boolean => /.+@.+\\..+/.test(email.value.trim());\n email.addEventListener('input', () => { pay.disabled = !emailValid(); });\n\n const start = async (): Promise<void> => {\n waiting('Opening secure payment…');\n try {\n const body = await mount.startSession({\n holdId: order.holdId,\n buyerEmail: email.value.trim(),\n // Deliberately no `provider`: since W2 the EVENT row decides which\n // gateway charges, and naming one here can only ever 409 on a mismatch\n // the buyer cannot do anything about.\n ...(name.value.trim() ? { buyerName: name.value.trim() } : {}),\n });\n if (!live) return;\n\n // Hosted-page provider: leave the page. Where the gateway sends the buyer\n // back is the SERVER's choice, not ours — see the `checkout` option's note\n // in SeatPicker.\n if (body.redirectUrl) {\n waiting('Taking you to secure payment…');\n window.location.assign(body.redirectUrl);\n return;\n }\n\n // In-page modal provider — the embed never leaves the host's page.\n if (body.clientPayload) {\n const payload = body.clientPayload as {\n key: string; orderId: string; amount: number; currency: string;\n name: string; prefill?: { email?: string; name?: string };\n };\n const Razorpay = await loadRazorpay();\n if (!live) return;\n waiting('Waiting for payment…');\n new Razorpay({\n key: payload.key,\n order_id: payload.orderId,\n amount: payload.amount,\n currency: payload.currency,\n name: payload.name,\n prefill: payload.prefill,\n // The handler fires on the browser's word alone, so it only starts the\n // wait — the webhook is what actually confirms the order.\n handler: () => { void awaitConfirmation(body.orderId); },\n modal: { ondismiss: () => { if (live) details(); } },\n }).open();\n return;\n }\n\n fail(errorCopy('gateway_unavailable'));\n } catch (err) {\n mount.onError?.(err);\n fail(errorCopy((err as { code?: string } | null)?.code));\n }\n };\n\n form.addEventListener('submit', (event) => {\n event.preventDefault();\n if (emailValid()) void start();\n });\n form.append(emailLabel, email, nameLabel, name, privacy, pay, back, note);\n\n const details = (): void => {\n title.textContent = 'Checkout';\n show(summary, form);\n pay.disabled = !emailValid();\n };\n details();\n mount.root.appendChild(scrim);\n email.focus();\n\n return { destroy };\n}\n","/**\n * @seatlayer/js — the framework-agnostic SeatLayer embed SDK.\n *\n * Works in any JS environment (plain HTML, React, Vue, Svelte, Angular, …).\n * Framework wrappers (@seatlayer/react, …) build on top of this.\n */\nexport { SeatingChart } from './SeatingChart';\nexport type { SeatingChartOptions, SelectedSeat, GAAreaAvailability } from './SeatingChart';\nexport { ApiError } from './api';\nexport type { HoldResult, ResumedHoldResult, HoldConflict, HoldLineItem, BestAvailableResult, PubApiOptions } from './api';\n// Hosted checkout (SeatPicker's `checkout: 'hosted'`). TYPES ONLY — the card\n// that takes the payment is a lazy chunk and never enters this entry's graph,\n// so importing these costs a host nothing at runtime.\nexport type {\n PaymentProviderName,\n PaymentOptionsReason,\n PaymentOptionsResult,\n CheckoutSessionResult,\n OrderStatusResult,\n} from './api';\n// Sales Channels — buyer access sessions (private channel inventory).\nexport { BuyerAccessContext, BuyerAccessUnavailableError, createBuyerAccessContext } from './buyerAccess';\nexport type {\n BuyerAccessToken,\n BuyerAccessTokenProvider,\n BuyerAccessRefreshReason,\n BuyerAccessUnavailableReason,\n BuyerAccessExpiredEvent,\n BuyerAccessUnavailableEvent,\n SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nexport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nexport type {\n RealtimeSink,\n StatusChange,\n Projection,\n SubscribeTicket,\n BuyerRealtimeOptions,\n} from './buyerRealtime';\nexport { EmbeddedDesigner } from './EmbeddedDesigner';\nexport type {\n EmbeddedDesignerOptions,\n EmbeddedDesignerMessage,\n EmbeddedDesignerEventType,\n} from './EmbeddedDesigner';\nexport type { SeatHoverDetails } from '@seatlayer/core';\nexport { SeatPicker } from './SeatPicker';\nexport type {\n SeatPickerOptions,\n SeatPickerTheme,\n SeatPickerPricing,\n SeatPickerBestAvailableOptions,\n SeatPickerBuyerView,\n SeatPickerBuyerViewOptions,\n CheckoutHandoff,\n CheckoutLineItem,\n} from './SeatPicker';\nexport type { PickerMapTheme, RendererViewMode } from '@seatlayer/core';\n// Ticket-offer availability: the payload `onOfferAvailabilityChange` republishes.\nexport { parseTicketOfferAvailability, ticketOfferPrices } from './offerAvailability';\nexport type {\n TicketOfferAvailability,\n TicketOfferPrice,\n TicketOfferSummary,\n SaleState,\n} from './offerAvailability';\n// Host helper for iframe picker embeds: auto-height + fullscreen pin/restore.\nexport { attachPickerFrame } from './attachPickerFrame';\nexport type { AttachPickerFrameOptions } from './attachPickerFrame';\n// Organizer runtime values live at `@seatlayer/js/manager` so the buyer entry\n// never eagerly loads the cockpit, channels application, or ManageApi. Keep\n// type-only compatibility here: TypeScript erases these exports from the graph.\nexport type {\n SeatManager,\n SeatManagerOptions,\n SeatManagerMode,\n EventScopedManageToken,\n SeatManagerCapability,\n SeatManagerTallies,\n SeatManagerActivity,\n SeatManagerActionResult,\n SeatManagerConnection,\n} from './SeatManager';\nexport type {\n ChannelsMode, ChannelsCapabilities, ChannelsClient, ChannelsModeHost, ChannelsRowView,\n ChannelsSeatView,\n} from './channelsMode';\nexport type {\n AccessIntentForbidsDetails,\n AccessLinkRecord,\n AccessLinkReveal,\n AccessLinkState,\n AccessLinkStatus,\n AccessLinkStatusRecord,\n ArchiveBlockedDetails,\n AssignmentBuckets,\n AssignmentDropDetails,\n AssignmentResult,\n BucketRow,\n ChannelAccessIntent,\n ChannelAccessSummary,\n ChannelCounts,\n ChannelListResult,\n ChannelRecord,\n ChannelSeatStatus,\n ChannelState,\n IntentSwitchBlockedDetails,\n SelectionSourceRow,\n} from './channelPlan';\nexport type {\n ManageApi,\n ManageApiError,\n ChannelAllocationPage,\n ChannelAuditEntry,\n ChannelAuditPage,\n ChannelPreviewProjection,\n ChannelAttribution,\n ChannelReportRow,\n ChannelReport,\n ChannelReportResult,\n ChannelReportLinkRecord,\n ChannelReportLinkReveal,\n ReportResult,\n ReportByStatus,\n ReportCategoryRow,\n ReportCategoryMeta,\n ControlRoomActivityEntry,\n ControlRoomSectionMetric,\n ControlRoomSnapshot,\n LogEntry,\n LogPage,\n InventoryBookingState,\n InventoryBookingObject,\n InventoryBooking,\n InventoryBookingsQuery,\n InventoryBookingsPage,\n InventoryBookingActivity,\n InventoryBookingDetail,\n} from './manageApi';\n// Engine seat shape — surfaced for manage callbacks (selection payloads).\nexport type { ExpandedSeat } from '@seatlayer/core';\n","/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport {\n PickerController,\n loadLocale,\n setStringOverrides,\n t,\n type PickerSeat,\n type RendererViewMode,\n type SeatHoverDetails,\n} from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\nimport {\n createBuyerAccessContext,\n type BuyerAccessContext,\n type BuyerAccessExpiredEvent,\n type BuyerAccessToken,\n type BuyerAccessTokenProvider,\n type BuyerAccessUnavailableEvent,\n type SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nimport { SEATLAYER_ATTRIBUTION_MARK_SVG } from './seatLayerBrand';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\nexport interface GAAreaAvailability {\n id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string;\n /** Buyer-facing copy authored separately from stable inventory identity. */\n displayLabel?: string;\n displayType?: string;\n tiers?: Array<{ id: string; name: string; price: number }>;\n}\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent.\n * NOT the channel-access credential: a buyer access session is a different\n * thing with different authority, and uses the two options below. */\n publicKey?: string;\n /**\n * Buyer access session provider — the recommended way to render private\n * channel inventory (Sales Channels guide §6).\n *\n * Called with a `reason` whenever the SDK needs a bearer: first acquisition,\n * a near/actual expiry, a 401 `buyer_access_expired`, a realtime reconnect,\n * or `refreshAccess()`. It should POST to YOUR backend, which mints the\n * session with your secret key and returns `{ token, expiresAt }`.\n *\n * The token lives in memory for the widget's lifetime and nowhere else: never\n * in storage, never in a URL, never in a log or an error message. Refresh\n * returns the same or a narrower scope — the SDK never widens to Public sale\n * on its own, and a failed refresh stops the scoped operation rather than\n * retrying it anonymously.\n */\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n /**\n * One-shot escape hatch for hosts that already own the session lifecycle.\n * Cannot be renewed — when it lapses the widget reports `onAccessExpired`\n * and then `onAccessUnavailable`. Prefer `buyerAccessTokenProvider`.\n */\n buyerAccessToken?: string | BuyerAccessToken;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n /** Initial canvas projection.\n * @deprecated `'isometric'` and `'perspective'` are retired in favour of the\n * real 3D venue view (`setBuyerView('venue3d')`); they remain accepted for\n * source compatibility and will be removed in the next major. Use `'flat'`. */\n initialView?: RendererViewMode;\n /**\n * Built-in seat tooltip on mouse hover (seat · category · price · status).\n * Rendered inside the widget so every host gets it; default true. Turn off\n * to draw your own popover from onSeatHover.\n */\n seatTooltip?: boolean;\n /**\n * Seat hover with everything a popover needs (category label/color, resolved\n * tier-aware price, live status, currency); null on hover-out. Fires whether\n * or not the built-in tooltip is enabled.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n /** A prior active hold was restored with resumeHold(). */\n onHoldRestored?: (result: HoldResult) => void;\n onHoldExpired?: () => void;\n onGAClick?: (area: GAAreaAvailability) => void;\n /**\n * The buyer access session lapsed. `refreshed` says whether the provider\n * already recovered it — false means private inventory is now unavailable and\n * `onAccessUnavailable` follows. Distinct from `onError` on purpose: this is\n * never a network failure (guide §10).\n */\n onAccessExpired?: (event: BuyerAccessExpiredEvent) => void;\n /**\n * Private inventory is unavailable and refreshing will not fix it — revoked,\n * paused, wrong origin/event/mode, or the provider failed. Carries a reason,\n * never a channel name, id, colour or count.\n */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /**\n * Selected-but-unheld units stopped being selectable — someone else took\n * them, or an allocation change moved them out of this buyer's scope. The\n * widget has already dropped them from the selection.\n */\n onSelectedObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n onError?: (err: unknown) => void;\n /**\n * What the BUYER sees when the chart cannot load.\n *\n * `'message'` (the default) renders a plain, styleable notice with a Try\n * again button. This used to be silent unconditionally: `render()` returned\n * with an EMPTY mounted div and only `onError` fired, so a host that had not\n * wired `onError` — or had wired it to a logger — showed buyers a blank\n * rectangle where the seat map belongs, on the host's own domain, which\n * reads as a broken website rather than a temporary fault. `SeatPicker` has\n * always failed loud with a retry; this is the embed class catching up.\n *\n * `'none'` restores the silent behaviour for hosts that render their own\n * failure UI from `onError`.\n */\n errorDisplay?: 'message' | 'none';\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n private mode_: 'live' | 'test' | null = null;\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private onTipMove: ((e: MouseEvent) => void) | null = null;\n /** Null for the ordinary public chart — the tokenless path is untouched. */\n private readonly access: BuyerAccessContext | null;\n private readonly api: PubApi;\n private realtime: BuyerRealtimeClient | null = null;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n this.access = createBuyerAccessContext(options, {\n onExpired: (event) => this.opts.onAccessExpired?.(event),\n onUnavailable: (event) => this.opts.onAccessUnavailable?.(event),\n });\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''), {\n access: this.access ?? undefined,\n onObjectUnavailable: (event) => this.opts.onSelectedObjectUnavailable?.(event),\n });\n this.api = api;\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldRestored: (h) => this.opts.onHoldRestored?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldExpired: () => this.opts.onHoldExpired?.(),\n onGAClick: (areaId) => {\n const area = this.controller.getGAAreas().find((candidate) => candidate.id === areaId);\n if (area) this.opts.onGAClick?.(area);\n },\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n // Live-activity cue: pulse seats that other buyers take while the map is\n // open — the WS feed already streams the status change, this makes it felt.\n flashOnLiveChange: true,\n onSeatHover: (details) => {\n this.opts.onSeatHover?.(details);\n if (this.opts.seatTooltip !== false) this.updateTooltip(details);\n },\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const info = await this.controller.render(host);\n if (!info) {\n this.rendered = false;\n if (this.opts.errorDisplay !== 'none') this.showLoadFailure(host);\n return this;\n }\n this.controller.setViewMode(this.opts.initialView ?? 'flat');\n this.startRealtime();\n // The served event's mode. Anything the API does not explicitly mark as a\n // test event is a live one — the same rule the test-mode ribbon below uses.\n this.mode_ = info.mode === 'test' ? 'test' : 'live';\n\n // Tooltip element + cursor tracking (mouse only — touch selects directly and\n // reviews seats in the host tray). Positioned at the cursor, flipped at edges.\n // Appended AFTER controller.render — mounting the canvas replaces the host's\n // prior children, so anything added earlier would be wiped.\n if (this.opts.seatTooltip !== false) {\n const tip = document.createElement('div');\n tip.setAttribute('role', 'tooltip');\n tip.style.cssText =\n 'position:absolute;z-index:7;pointer-events:none;display:none;max-width:240px;' +\n 'background:#10162a;color:#fff;border-radius:10px;padding:9px 12px;' +\n 'font:500 12px/1.45 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;' +\n 'box-shadow:0 10px 30px -10px rgba(0,0,0,.5);';\n host.appendChild(tip);\n this.tipEl = tip;\n this.onTipMove = (e: MouseEvent) => {\n const r = host.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n };\n host.addEventListener('mousemove', this.onTipMove);\n }\n if (info.mode === 'test') {\n host.style.overflow = 'hidden';\n const ribbon = document.createElement('div');\n ribbon.textContent = t('picker.testMode');\n ribbon.setAttribute('aria-label', t('picker.testMode'));\n ribbon.style.cssText =\n 'position:absolute;top:18px;right:-34px;z-index:6;transform:rotate(45deg);' +\n 'width:140px;text-align:center;padding:4px 0;background:#f4b740;color:#1a1200;' +\n 'font:800 10.5px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.12em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.25);pointer-events:none;';\n host.appendChild(ribbon);\n }\n\n // \"Powered by SeatLayer\" attribution — the SDK embed is canvas-only, so\n // (unlike the full SeatPicker widget) nothing else renders this badge; no\n // duplication guard is needed. Shown by default; hidden only when the SERVED\n // chart doc's theme sets hideBadge (the API forces that false for orgs\n // without the white-label entitlement, so the client can trust the flag).\n this.buildBadge(host);\n return this;\n }\n\n /**\n * Attribution badge pinned to the embed's bottom-right, linking to\n * seatlayer.io. Rendered as an absolutely-positioned overlay with\n * self-contained inline styles — the SDK embed ships no widget CSS, and an\n * overlay keeps it out of the layout flow so it never disturbs the SDK v0.22\n * fill-height resize contract. Mirrors the full widget's mark + wordmark and\n * reuses the `picker.poweredBy` i18n string.\n */\n private buildBadge(host: HTMLDivElement): void {\n if (this.controller.doc?.theme?.hideBadge) return;\n const badge = document.createElement('a');\n badge.href = 'https://seatlayer.io';\n badge.target = '_blank';\n badge.rel = 'noopener noreferrer';\n badge.setAttribute('aria-label', t('picker.poweredBy'));\n badge.style.cssText =\n 'position:absolute;bottom:10px;right:12px;z-index:5;' +\n 'display:inline-flex;align-items:center;gap:6px;padding:5px 9px;border-radius:999px;' +\n 'background:rgba(255,255,255,.92);color:#4a5163;text-decoration:none;' +\n 'font:600 11px/1 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;letter-spacing:.02em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.12);';\n badge.innerHTML =\n '<span aria-hidden=\"true\" style=\"width:16px;height:16px;border-radius:4px;flex:none;' +\n 'display:flex;align-items:center;justify-content:center;background:#0c1220;color:#fcf7ee\">' +\n SEATLAYER_ATTRIBUTION_MARK_SVG + '</span>' +\n `<span>${t('picker.poweredBy')}</span>`;\n host.appendChild(badge);\n }\n\n private placeTooltip(): void {\n if (!this.tipEl || !this.hostEl) return;\n const hw = this.hostEl.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const money = (() => {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: details.currency }).format(details.price);\n } catch {\n return `${details.price} ${details.currency}`;\n }\n })();\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div style=\"margin-top:5px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#fca5a5;font-weight:700\">${\n details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')\n }</div>`;\n this.tipEl.innerHTML =\n `<div style=\"font-weight:700;font-size:13px\">${details.label}</div>` +\n `<div style=\"display:flex;align-items:center;gap:6px;margin-top:4px;color:#c7cddc\">` +\n `<span style=\"width:9px;height:9px;border-radius:50%;flex:none;background:${details.categoryColor}\"></span>` +\n `<span>${details.categoryLabel}</span>` +\n `<span style=\"margin-left:auto;font-weight:700;color:#fff\">${money}</span></div>` +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n /**\n * Whether the SERVED event is a live or a test event (`sk_test_` keys create\n * test events, which never book real inventory). `null` before render()\n * resolves — the mode comes from the server with the chart, not from options.\n *\n * The widget already surfaces this visually with the test-mode ribbon; this\n * getter is for hosts that draw their own chrome — notably a native WebView\n * wrapper, which must be able to tell an integrator that the build they are\n * about to ship is pointed at a test event.\n */\n getMode(): 'live' | 'test' | null {\n return this.mode_;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n try {\n return await this.holdOrThrow(options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * @internal Like {@link hold} but RE-THROWS the structured API error (409\n * `reason`/`code` + `conflicts`) instead of swallowing it into `onError` +\n * `null`. The native WebView host adapter needs the throw so it can answer the\n * originating command with a correlated error carrying the SPECIFIC reason\n * (`sold_out` vs `not_enough_together`); the public method above keeps the\n * catch-and-onError contract that direct web consumers rely on. Not a stable\n * part of the embed API.\n */\n async holdOrThrow(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n const h = await this.controller.hold(undefined, options.ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /** Restore an active hold by its opaque id without extending its expiry. */\n async resumeHold(holdId: string): Promise<HoldResult | null> {\n try {\n return await this.resumeHoldOrThrow(holdId);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link resumeHold} for the native host adapter. See {@link holdOrThrow}. */\n async resumeHoldOrThrow(holdId: string): Promise<HoldResult | null> {\n const h = await this.controller.resumeHold(holdId);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /**\n * Push the OPEN hold's expiry out (\"need more time?\"). Resolves the refreshed\n * hold, or `null` when there is nothing held or the server refused (the hold\n * is gone, already expired, or at its renewal cap) — refusal is a normal\n * outcome, not an error, so the host decides the copy. The client-side expiry\n * timer is re-armed to match, so `onHoldExpired` won't fire early.\n */\n async extendHold(ttlMs?: number): Promise<HoldResult | null> {\n try {\n const h = await this.controller.extendHold(ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Current active hold known to this chart, if any. */\n getCurrentHold(): HoldResult | null {\n const h = this.controller.currentHold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n getGAAreas(): GAAreaAvailability[] {\n return this.controller.getGAAreas();\n }\n\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n try {\n return await this.holdGAOrThrow(areaId, qty, options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link holdGA} for the native host adapter. See {@link holdOrThrow}. */\n async holdGAOrThrow(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n const h = await this.controller.holdGA(areaId, qty, options);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /**\n * Ask the server for the `qty` best free seats and hold them atomically.\n * `options.ttlMs` sets the checkout window exactly like {@link hold}; omit it\n * and the server falls back to the event setting, then its own default.\n */\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n options: { zoneId?: string; preferPremium?: boolean; ttlMs?: number } = {},\n ): Promise<BestAvailableResult | null> {\n try {\n return await this.bestAvailableOrThrow(qty, categoryKey, options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link bestAvailable} for the native host adapter. See {@link holdOrThrow}. */\n async bestAvailableOrThrow(\n qty: number,\n categoryKey?: string,\n options: { zoneId?: string; preferPremium?: boolean; ttlMs?: number } = {},\n ): Promise<BestAvailableResult | null> {\n const h = await this.controller.bestAvailable(qty, categoryKey, options);\n return h ? {\n holdId: h.holdId,\n expiresAt: h.expiresAt,\n labels: h.labels,\n seats: h.seats,\n items: h.items,\n ...(options.zoneId ? { zoneId: options.zoneId } : {}),\n } : null;\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Switch the 2D canvas projection.\n * @deprecated `'isometric'` and `'perspective'` are retired in favour of the\n * real 3D venue view (`setBuyerView('venue3d')`); accepted for source\n * compatibility until the next major. */\n setViewMode(mode: RendererViewMode): void {\n this.controller.setViewMode(mode);\n }\n\n /** Current canvas projection. */\n getViewMode(): RendererViewMode {\n return this.controller.getViewMode();\n }\n\n /** Zoom in one step (same increment as the wheel/pinch gesture). */\n zoomIn(): void {\n this.controller.zoomIn();\n }\n\n /** Zoom out one step. */\n zoomOut(): void {\n this.controller.zoomOut();\n }\n\n /** Reset the camera so the whole chart fits the container. */\n zoomToFit(): void {\n this.controller.zoomToFit();\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Release selected labels from the current hold while keeping the remainder. */\n async releaseLabels(labels: string[]): Promise<boolean> {\n return this.controller.releaseLabels(labels);\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n /**\n * Realtime for an access-scoped chart.\n *\n * A tokenless chart never gets here: `access` is null, `PubApi.socketUrl()`\n * returns the URL it always has, and PickerController keeps its own socket\n * and its own legacy frames. Nothing about the public path changes.\n */\n private startRealtime(): void {\n if (!this.access?.configured || this.realtime) return;\n this.realtime = new BuyerRealtimeClient({\n url: this.api.subscribeUrl(this.opts.event),\n mintTicket: () => this.api.subscribeTicket(this.opts.event),\n onAccessUnavailable: (event) => this.opts.onAccessUnavailable?.(event),\n sink: createControllerSink(this.controller, {\n flashOnLiveChange: true,\n onSelectedObjectUnavailable: (labels, reason) =>\n this.opts.onSelectedObjectUnavailable?.({ labels, reason }),\n }),\n });\n this.realtime.start();\n }\n\n /**\n * Re-acquire the buyer access session — call after your app has re-authorized\n * the buyer (a revoked session cannot be recovered any other way). Resolves\n * true when a fresh bearer is held; the realtime feed restarts with it.\n */\n async refreshAccess(): Promise<boolean> {\n if (!this.access?.configured) return false;\n const ok = await this.access.refresh('manual');\n if (ok) {\n await this.controller.refresh();\n this.realtime?.restart();\n if (!this.realtime) this.startRealtime();\n }\n return ok;\n }\n\n /**\n * The visible failure state. Deliberately inline-styled and dependency-free:\n * this renders on a stranger's website, where our stylesheet may not have\n * loaded (the chart fetch just failed) and where inheriting the host's own\n * styles is likelier to produce something unreadable than something on-brand.\n */\n private showLoadFailure(host: HTMLDivElement): void {\n const box = document.createElement('div');\n box.setAttribute('role', 'status');\n box.style.cssText =\n 'display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;' +\n 'width:100%;height:100%;min-height:180px;box-sizing:border-box;padding:24px;text-align:center;' +\n 'font:500 14px/1.5 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;color:#3b4256;';\n\n const text = document.createElement('div');\n // No error detail: a buyer cannot act on it, and it can carry internals.\n text.textContent = 'The seat map didn’t load.';\n box.appendChild(text);\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.textContent = 'Try again';\n btn.style.cssText =\n 'appearance:none;border:1px solid #c9cede;background:#fff;color:#10162a;border-radius:8px;' +\n 'padding:8px 16px;font:600 13px/1 inherit;cursor:pointer;';\n btn.addEventListener('click', () => {\n // Full remount: the controller holds no partial state worth salvaging\n // after a failed render, and this is the same recovery SeatPicker uses.\n this.destroy();\n void this.render().catch((err) => this.opts.onError?.(err));\n });\n box.appendChild(btn);\n host.appendChild(box);\n }\n\n destroy(): void {\n this.realtime?.stop();\n this.realtime = null;\n this.access?.clear();\n if (this.hostEl && this.onTipMove) this.hostEl.removeEventListener('mousemove', this.onTipMove);\n this.tipEl = null;\n this.onTipMove = null;\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n this.mode_ = null;\n }\n}\n","/**\n * BuyerRealtimeClient — the client half of `docs/realtime-protocol-2026-08-01.md`.\n *\n * Why this exists as a separate socket rather than inside PickerController:\n * a private scope authenticates with a one-use **subscribe ticket** carried in\n * `Sec-WebSocket-Protocol`, and a browser can only set that at construction —\n * `new WebSocket(url, protocols)`. The controller's socket is built from a URL\n * alone (`PickerTransport.socketUrl`), and a bearer must never travel in a URL\n * because URLs are routinely logged. So an access-scoped picker asks the\n * transport for an empty `socketUrl()` (the controller then skips its own\n * connection entirely) and this client owns the wire instead.\n *\n * A tokenless public picker never reaches this file. It keeps the controller's\n * original socket, offers no subprotocol, and therefore receives byte-for-byte\n * the frames it received before this module existed (protocol doc §1).\n *\n * What it implements:\n * - protocol negotiation: offer `seatlayer.v1`, believe the 101 echo, and fall\n * back to legacy frame handling when the server (or a proxy) does not echo;\n * - the ticket exchange, one mint per connection attempt, ticket in the\n * subprotocol list and never in the URL;\n * - compact `{default, exceptions}` snapshot reconstruction;\n * - `sv.<n>` resume, handling BOTH outcomes (a `resumed` delta or a full\n * snapshot) on every reconnect;\n * - close code 4401 as a typed access-revoked state, never a reconnect loop;\n * - liveness by ping/pong only. Silence is normal and carries no information\n * (protocol doc §5) — a quiet socket is never treated as a dead one.\n */\nimport type { BuyerAccessUnavailableEvent } from './buyerAccess';\n\n/** The projected status of one unit, as the server words it on the wire. */\nexport type WireStatus = string;\n\n/** A scope's projection: one default plus the units that differ from it. */\nexport interface Projection {\n default: WireStatus;\n exceptions: Record<string, WireStatus>;\n}\n\nexport interface StatusChange {\n label: string;\n status: WireStatus;\n}\n\n/** Where reconstructed inventory goes. Implemented over PickerController. */\nexport interface RealtimeSink {\n /** Apply a batch of label→status changes. Implementations must paint this as\n * ONE pass, not one pass per label (motion system §4 rule 2). */\n applyStatuses(changes: StatusChange[]): void;\n /**\n * Paint a COMPLETE projection — the default plus the units that differ.\n *\n * Every case that cannot be expressed as a bounded diff (the first snapshot,\n * or a changed default) still arrives as a whole authoritative projection: the\n * client holds it, it just has no way to hand it over. This is that way, and\n * where a sink provides it the {@link resync} round trip is skipped entirely.\n *\n * Optional, so an older sink keeps working unchanged.\n */\n applyProjection?(projection: Projection): void;\n /** Re-pull authoritative state over the scoped HTTP route. Used when a frame\n * cannot be diffed against what we hold (first snapshot, or the scope's\n * default itself changed, which redefines every unit we were never told\n * about), and the sink cannot take a whole projection. */\n resync(): void | Promise<void>;\n /** Section availability changed (channel-agnostic; identical for every scope). */\n onSections?(hidden: string[], closed: string[]): void;\n /** Scope-projected presence counters. */\n onPresence?(counts: { shoppingSessions: number; activeHolds: number }): void;\n}\n\nexport interface SubscribeTicket {\n ticket?: string;\n /** Exactly what to hand `new WebSocket(url, protocols)`, per protocol doc §3. */\n protocols?: string[];\n}\n\nexport interface BuyerRealtimeOptions {\n /** The subscribe URL. Must never carry a credential — asserted below. */\n url: string;\n sink: RealtimeSink;\n /** Mint a one-use ticket for THIS connection attempt. Returns null for the\n * anonymous public case (no ticket needed). Throwing stops the client. */\n mintTicket?: () => Promise<SubscribeTicket | null>;\n /** Typed access states. 4401 arrives here as `revoked`. */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /** Test seam. Defaults to the global WebSocket. */\n socketFactory?: (url: string, protocols: string[]) => WebSocket;\n /** Test seam for the keepalive/backoff timers. */\n now?: () => number;\n}\n\nexport const SEATLAYER_V1 = 'seatlayer.v1';\n/**\n * Join separator for the section-visibility dedupe keys. A NUL can never occur\n * in a section id, so two different arrays can never collide on one key. It is\n * written as an escape deliberately: a literal NUL byte in the source made the\n * whole file read as binary to grep, diff, and review tooling.\n */\nconst SEP = '\\u0000';\n\n/** Protocol doc §3: revocation closes the socket with this code. */\nexport const CLOSE_ACCESS_REVOKED = 4401;\n\nconst MAX_BACKOFF_MS = 15_000;\nconst PING_INTERVAL_MS = 25_000;\nconst PONG_GRACE_MS = 10_000;\n/** Only armed when we offered a resume; the server always answers a resume. */\nconst RESUME_ANSWER_GRACE_MS = 5_000;\n\n/**\n * Turn a snapshot frame into a projection. Handles both wire forms: the v1\n * compact frame states its `default` and lists only the exceptions; the legacy\n * verbose frame lists every non-free unit, which is the same thing with an\n * implicit default of `free`.\n */\nexport function projectionFromSnapshot(frame: {\n default?: unknown;\n seats?: unknown;\n}): Projection {\n const fallback = typeof frame.default === 'string' ? frame.default : 'free';\n const exceptions: Record<string, WireStatus> = {};\n if (frame.seats && typeof frame.seats === 'object') {\n for (const [label, status] of Object.entries(frame.seats as Record<string, unknown>)) {\n if (typeof status === 'string' && status !== fallback) exceptions[label] = status;\n }\n }\n return { default: fallback, exceptions };\n}\n\n/**\n * The changes needed to move a renderer from `prev` to `next`.\n *\n * Returns null when the two projections have different defaults: the default\n * describes every unit the frame does NOT name, and the client does not hold\n * that universe, so the move cannot be expressed as a bounded diff. The caller\n * resyncs over HTTP instead — correct, and rare (it means a channel pause or an\n * allocation change moved the whole scope).\n */\nexport function diffProjections(prev: Projection | null, next: Projection): StatusChange[] | null {\n if (!prev || prev.default !== next.default) return null;\n const changes: StatusChange[] = [];\n for (const [label, status] of Object.entries(next.exceptions)) {\n if (prev.exceptions[label] !== status) changes.push({ label, status });\n }\n for (const label of Object.keys(prev.exceptions)) {\n if (!(label in next.exceptions)) changes.push({ label, status: next.default });\n }\n return changes;\n}\n\n/** Fold a delta batch into a projection (an exception equal to the default\n * stops being an exception, so the model cannot grow without bound). */\nexport function applyChanges(projection: Projection, changes: StatusChange[]): void {\n for (const change of changes) {\n if (change.status === projection.default) delete projection.exceptions[change.label];\n else projection.exceptions[change.label] = change.status;\n }\n}\n\n/** Belt and braces for the \"no bearer in a URL\" rule — cheap, and it turns a\n * future refactor that reintroduces one into a thrown error, not a silent leak. */\nexport function assertCredentialFreeUrl(url: string): void {\n if (/(?:^|[?&#])(?:token|access_token|bearer|authorization|ticket|tkt|bse)=/i.test(url)) {\n throw new Error('seatlayer: refusing to open a socket with a credential in the URL');\n }\n if (/\\bbse_[A-Za-z0-9._-]+/.test(url)) {\n throw new Error('seatlayer: refusing to open a socket with a credential in the URL');\n }\n}\n\nexport class BuyerRealtimeClient {\n private readonly opts: BuyerRealtimeOptions;\n private ws: WebSocket | null = null;\n private stopped = true;\n private attempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n private resumeTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Our model of this scope's projection. Null until the first snapshot. */\n private projection: Projection | null = null;\n /** Last `snapshotVersion` seen on any frame that carried one — the resume point. */\n private version: number | null = null;\n /** True once the 101 echoed `seatlayer.v1`. */\n private v1 = false;\n /** Set when we offered v1 and the handshake came back without it — a proxy\n * most likely stripped the header, so the next attempt selects the v1 frame\n * format with the `?pv=1` marker instead (protocol doc §1). The marker\n * selects a format and can never carry a credential or widen a scope. */\n private useQueryMarker = false;\n private hidden: string | null = null;\n private closedSections: string | null = null;\n\n constructor(options: BuyerRealtimeOptions) {\n this.opts = options;\n assertCredentialFreeUrl(options.url);\n }\n\n /** Negotiated protocol, for tests and diagnostics. */\n get protocol(): 'v1' | 'legacy' | null {\n return this.ws ? (this.v1 ? 'v1' : 'legacy') : null;\n }\n\n get snapshotVersion(): number | null {\n return this.version;\n }\n\n start(): void {\n if (!this.stopped) return;\n this.stopped = false;\n void this.connect();\n }\n\n /** Stop for good (destroy, or a revocation). Safe to call twice. */\n stop(): void {\n this.stopped = true;\n this.clearTimers();\n const ws = this.ws;\n this.ws = null;\n if (ws) {\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n try {\n ws.close();\n } catch {\n /* already closing */\n }\n }\n }\n\n /** Restart after the host re-authorized a revoked buyer (`refreshAccess()`). */\n restart(): void {\n this.stop();\n this.projection = null;\n this.version = null;\n this.attempt = 0;\n this.start();\n }\n\n // ---- connection -----------------------------------------------------------\n\n private async connect(): Promise<void> {\n if (this.stopped) return;\n\n let protocols: string[] = [SEATLAYER_V1];\n if (this.opts.mintTicket) {\n let minted: SubscribeTicket | null;\n try {\n // One mint per connection attempt, including every reconnect. Tickets\n // are TTL ≤ 30s and single-redemption, so reusing one cannot work.\n minted = await this.opts.mintTicket();\n } catch (err) {\n // The mint is an ordinary scoped HTTP call: the transport has already\n // classified and reported any access failure. A transport-level failure\n // is transient, so back off rather than give up.\n this.reportIfAccessError(err);\n this.scheduleReconnect();\n return;\n }\n if (this.stopped) return;\n if (minted?.protocols?.length) {\n protocols = [...minted.protocols];\n if (!protocols.includes(SEATLAYER_V1)) protocols.unshift(SEATLAYER_V1);\n } else if (minted?.ticket) {\n protocols = [SEATLAYER_V1, `tkt.${minted.ticket}`];\n }\n }\n\n // Resume from the last version we actually saw. Both outcomes — a `resumed`\n // delta or a full snapshot — are handled in onmessage.\n const offeredResume = this.version !== null;\n if (offeredResume) protocols.push(`sv.${this.version}`);\n\n const url = this.useQueryMarker\n ? `${this.opts.url}${this.opts.url.includes('?') ? '&' : '?'}pv=1`\n : this.opts.url;\n assertCredentialFreeUrl(url);\n\n let ws: WebSocket;\n try {\n const make = this.opts.socketFactory ?? ((u: string, p: string[]) => new WebSocket(u, p));\n ws = make(url, protocols);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n if (this.ws !== ws) return;\n this.attempt = 0;\n this.v1 = ws.protocol === SEATLAYER_V1;\n // We asked for v1 and the server did not echo it. Either it is a\n // pre-M5 server (legacy frames are correct and byte-compatible) or a\n // proxy ate the header — the next attempt tries the query marker.\n if (!this.v1) this.useQueryMarker = true;\n this.startKeepalive(ws);\n if (offeredResume) {\n // The server always answers a resume with a delta or a snapshot. If\n // neither lands, fall back to authoritative HTTP rather than sit on a\n // possibly stale map. This timer is NOT a liveness check — ordinary\n // silence on a live socket never triggers it.\n this.resumeTimer = setTimeout(() => {\n this.resumeTimer = null;\n void this.opts.sink.resync();\n }, RESUME_ANSWER_GRACE_MS);\n } else {\n // Parity with the controller's own socket: pull authoritative state on\n // every fresh connection.\n void this.opts.sink.resync();\n }\n };\n\n ws.onmessage = (event: MessageEvent) => {\n if (this.ws !== ws) return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(typeof event.data === 'string' ? event.data : '');\n } catch {\n return;\n }\n if (!parsed || typeof parsed !== 'object') return;\n this.handleFrame(parsed as Record<string, unknown>);\n };\n\n ws.onclose = (event: CloseEvent) => {\n if (this.ws !== ws) return;\n this.ws = null;\n this.clearTimers();\n if (event?.code === CLOSE_ACCESS_REVOKED) {\n // Retrying with the same credential is guaranteed to fail, so this is\n // a typed terminal state, not a reconnect loop (protocol doc §3).\n this.stopped = true;\n this.opts.onAccessUnavailable?.({\n reason: 'revoked',\n code: 'access_revoked',\n retryable: false,\n });\n return;\n }\n this.scheduleReconnect();\n };\n\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives the reconnect */\n }\n };\n }\n\n private handleFrame(frame: Record<string, unknown>): void {\n const type = typeof frame.type === 'string' ? frame.type : '';\n\n // A frame carrying `protocol: 1` proves v1 even when the 101 echo was\n // stripped in transit (the `?pv=1` path).\n if (frame.protocol === 1) this.v1 = true;\n\n if (typeof frame.snapshotVersion === 'number') this.version = frame.snapshotVersion;\n\n if (type === 'pong') {\n this.clearPongTimer();\n return;\n }\n\n // Section availability rides on `hidden`/`closed`, either on its own frame\n // or alongside a snapshot. Identical for every scope.\n if (Array.isArray(frame.hidden) || Array.isArray(frame.closed)) {\n const hidden = Array.isArray(frame.hidden) ? (frame.hidden as string[]) : [];\n const closed = Array.isArray(frame.closed) ? (frame.closed as string[]) : [];\n const hKey = hidden.join(SEP);\n const cKey = closed.join(SEP);\n if (hKey !== this.hidden || cKey !== this.closedSections) {\n this.hidden = hKey;\n this.closedSections = cKey;\n this.opts.sink.onSections?.(hidden, closed);\n }\n }\n if (type === 'hidden') return; // carries no inventory\n\n if (type === 'presence') {\n this.opts.sink.onPresence?.({\n shoppingSessions: Number(frame.shoppingSessions) || 0,\n activeHolds: Number(frame.activeHolds) || 0,\n });\n return;\n }\n\n if (type === 'allocation') {\n // Always followed by a fresh snapshot, which is authoritative. Nothing to\n // do here — and deliberately NO dedupe on allocationVersion: a pause or\n // unpause changes the projection without moving that number.\n return;\n }\n\n if (type === 'snapshot' || (!type && frame.seats)) {\n this.answered();\n const next = projectionFromSnapshot(frame);\n const changes = diffProjections(this.projection, next);\n this.projection = next;\n if (changes === null) {\n // Undiffable — the first snapshot, or a default that moved. `next` is\n // nonetheless the WHOLE authoritative projection, so a sink that can\n // take one is painted directly and the HTTP round trip never happens.\n if (this.opts.sink.applyProjection) this.opts.sink.applyProjection(next);\n else void this.opts.sink.resync();\n } else if (changes.length) {\n this.opts.sink.applyStatuses(changes);\n }\n return;\n }\n\n if (type === 'delta' && Array.isArray(frame.changes)) {\n this.answered();\n const changes = (frame.changes as Array<Record<string, unknown>>)\n .filter((c) => typeof c?.label === 'string' && typeof c?.status === 'string')\n .map((c) => ({ label: c.label as string, status: c.status as string }));\n if (!changes.length) return;\n if (this.projection) applyChanges(this.projection, changes);\n this.opts.sink.applyStatuses(changes);\n }\n }\n\n /** The server answered our resume; cancel the fallback resync. */\n private answered(): void {\n if (!this.resumeTimer) return;\n clearTimeout(this.resumeTimer);\n this.resumeTimer = null;\n }\n\n private reportIfAccessError(err: unknown): void {\n const reason = (err as { reason?: string } | null)?.reason;\n if ((err as { name?: string } | null)?.name !== 'BuyerAccessUnavailableError') return;\n this.stopped = true;\n this.opts.onAccessUnavailable?.({\n reason: (reason ?? 'invalid') as BuyerAccessUnavailableEvent['reason'],\n code: (err as { code?: string }).code,\n status: (err as { status?: number }).status,\n retryable: reason === 'paused',\n });\n }\n\n // ---- keepalive & backoff --------------------------------------------------\n\n /**\n * Liveness is ping/pong, and only ping/pong. A socket that receives nothing\n * for minutes is the normal, correct state for a narrowly-scoped buyer on a\n * busy event (protocol doc §5), so quiet time never triggers a reconnect.\n */\n private startKeepalive(ws: WebSocket): void {\n this.pingTimer = setInterval(() => {\n if (this.ws !== ws) return;\n try {\n ws.send(JSON.stringify({ type: 'ping' }));\n } catch {\n return;\n }\n this.clearPongTimer();\n this.pongTimer = setTimeout(() => {\n this.pongTimer = null;\n try {\n ws.close();\n } catch {\n /* onclose drives the reconnect */\n }\n }, PONG_GRACE_MS);\n }, PING_INTERVAL_MS);\n }\n\n /**\n * FULL jitter, not plain exponential backoff.\n *\n * A deterministic `2**attempt` schedule makes every browser that lost the same\n * socket — a worker redeploy, a DO eviction, a flaky edge PoP — come back in\n * the same millisecond, and an on-sale crowd reconnecting in lockstep is the\n * thing that turns one blip into a self-sustaining thundering herd. Full\n * jitter (`random() * ceiling`) spreads the same crowd across the whole\n * window; the ceiling still doubles, so a persistent outage still backs off.\n *\n * `Math.random` is correct here: this is client code choosing a delay, not a\n * Workflow step that has to replay deterministically.\n */\n private scheduleReconnect(): void {\n if (this.stopped || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const ceiling = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n const delay = Math.random() * ceiling;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n void this.connect();\n }, delay);\n }\n\n private clearPongTimer(): void {\n if (!this.pongTimer) return;\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n\n private clearTimers(): void {\n if (this.pingTimer) clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.clearPongTimer();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n if (this.resumeTimer) clearTimeout(this.resumeTimer);\n this.resumeTimer = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Controller sink\n// ---------------------------------------------------------------------------\n\n/**\n * The slice of PickerController this module drives. Structural on purpose — it\n * keeps this file free of an `@seatlayer/core` import, and every member here is\n * public controller API, so nothing in the engine mirror has to change.\n */\nexport interface PickerControllerLike {\n idForLabel(label: string): string | undefined;\n tableSelection(seatIdOrLabel: string): { physicalSeatIds: string[] } | null;\n setStatus(ids: string[], status: 'free' | 'held' | 'booked' | 'not_for_sale'): void;\n getStatus(id: string): string | undefined;\n flashSeat(id: string, color?: string): void;\n currentHold(): { labels: string[] } | null;\n getSelection(): Array<{ id: string; label: string }>;\n deselect(ids: string[]): void;\n refresh(): Promise<void>;\n}\n\n/** Wire status → renderer status. `blocked` is the one neutral unavailable\n * value an out-of-scope unit reads as; the buyer must not be able to tell it\n * apart from ordinary off-sale inventory (protocol doc §5). */\nfunction rendererStatus(wire: string): 'free' | 'held' | 'booked' | 'not_for_sale' {\n if (wire === 'blocked') return 'not_for_sale';\n if (wire === 'held' || wire === 'booked' || wire === 'free' || wire === 'not_for_sale') return wire;\n return 'free';\n}\n\nexport interface ControllerSinkOptions {\n /** Pulse seats other buyers take, as the controller's own socket does. */\n flashOnLiveChange?: boolean;\n /** Selected-but-unheld units that stopped being selectable. */\n onSelectedObjectUnavailable?: (labels: string[], reason: 'ineligible' | 'taken') => void;\n /** Section availability changed and the chart itself needs rebuilding. */\n onSections?: (hidden: string[], closed: string[]) => void;\n onStatusChange?: () => void;\n}\n\nexport function createControllerSink(\n controller: PickerControllerLike,\n options: ControllerSinkOptions = {},\n): RealtimeSink {\n const idsForLabel = (label: string): string[] => {\n const table = controller.tableSelection(label);\n if (table) return table.physicalSeatIds;\n const id = controller.idForLabel(label);\n return id ? [id] : [];\n };\n\n return {\n applyStatuses(changes) {\n const held = controller.currentHold()?.labels ?? [];\n // Bucket the whole batch and paint one call per status: a 256-label\n // delta must animate as ONE canvas pass, never one per seat.\n const buckets: Record<string, string[]> = {\n free: [], held: [], booked: [], not_for_sale: [],\n };\n const flashes: Array<{ id: string; color: string }> = [];\n const lost: string[] = [];\n const selected = new Map(controller.getSelection().map((s) => [s.label, s.id]));\n\n for (const change of changes) {\n const ids = idsForLabel(change.label);\n if (!ids.length) continue;\n const next = rendererStatus(change.status);\n buckets[next].push(...ids);\n if (\n options.flashOnLiveChange &&\n next !== 'free' &&\n !held.includes(change.label) &&\n ids.some((id) => controller.getStatus(id) === 'free')\n ) {\n const color = next === 'held' ? '#f4b740' : '#f43f5e';\n for (const id of ids) flashes.push({ id, color });\n }\n if (next !== 'free' && !held.includes(change.label) && selected.has(change.label)) {\n lost.push(change.label);\n }\n }\n\n for (const status of ['free', 'held', 'booked', 'not_for_sale'] as const) {\n if (buckets[status].length) controller.setStatus(buckets[status], status);\n }\n for (const flash of flashes) controller.flashSeat(flash.id, flash.color);\n\n if (lost.length) {\n // One deselect call, so the map cross-fades in a single pass rather\n // than blinking seat by seat (motion system §3, buyer picker).\n const ids = lost.flatMap((label) => idsForLabel(label));\n if (ids.length) controller.deselect(ids);\n const ineligible = changes.some(\n (c) => c.status === 'blocked' && lost.includes(c.label),\n );\n options.onSelectedObjectUnavailable?.(lost, ineligible ? 'ineligible' : 'taken');\n }\n options.onStatusChange?.();\n },\n\n async resync() {\n await controller.refresh();\n },\n\n /**\n * Section availability moved. Statuses are re-pulled so the map repaints.\n *\n * Known limit: rebuilding the chart when a section is newly HIDDEN (its\n * seats are stripped, not greyed) lives inside PickerController's own\n * socket handler and has no public entry point, so an access-scoped picker\n * repaints statuses but does not restructure the chart until its next\n * mount. Closing/opening a section — the common mid-sale move — is a\n * status-level change and is handled here in full.\n */\n onSections(hidden, closed) {\n void controller.refresh();\n options.onSections?.(hidden, closed);\n },\n };\n}\n","/**\n * Minimal client for the browser embed surface of workers/api (the `/pub/*`\n * routes). Platform events bind this client to a buyer access context; Managed\n * public/unlisted events may still use it anonymously. Deliberately\n * self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\nimport type {\n BuyerAccessContext,\n SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, SEATLAYER_V1, type RealtimeSink } from './buyerRealtime';\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\nexport interface HoldLineItem {\n label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga' | 'table'; categoryKey: string;\n tierId: string | null;\n /** Price in major currency units (for example 45 means $45.00). */\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n /**\n * Seconds the server asked the caller to wait, off a 429's `Retry-After`.\n *\n * Present ONLY on a rate-limit error, and it is the server's number — never a\n * guess. A widget that catches this can say \"try again in N seconds\" instead\n * of rendering the blank map a swallowed 429 used to produce.\n */\n retryAfterS?: number;\n\n constructor(\n status: number,\n message: string,\n code?: string,\n conflicts?: HoldConflict[],\n reason?: string,\n retryAfterS?: number,\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n this.retryAfterS = retryAfterS;\n }\n}\n\n/**\n * Longest advertised delay we will sit out inside a request.\n *\n * A rate limit the buyer can wait through invisibly is worth absorbing; one\n * that is 30 seconds long is not — sleeping that long inside `chart()` looks\n * like a hung widget, and the retry would very likely 429 again anyway. Past\n * the cap the error is thrown WITH `retryAfterS`, so the host decides.\n */\nconst MAX_RATE_LIMIT_WAIT_S = 10;\n/** What to assume when a 429 names no delay at all. */\nconst DEFAULT_RATE_LIMIT_WAIT_S = 1;\n\n/**\n * `Retry-After` in seconds. RFC 9110 allows either a delta-seconds integer or\n * an HTTP-date; the API sends the integer, and the date form is handled so a\n * proxy that rewrites it cannot turn a well-formed 429 into an untyped one.\n * Returns undefined when neither the header nor the body says anything.\n */\nexport function parseRetryAfter(header: string | null, bodyValue?: unknown): number | undefined {\n const raw = (header ?? '').trim();\n if (raw) {\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds >= 0) return Math.ceil(seconds);\n const at = Date.parse(raw);\n if (Number.isFinite(at)) return Math.max(0, Math.ceil((at - Date.now()) / 1000));\n }\n if (typeof bodyValue === 'number' && Number.isFinite(bodyValue) && bodyValue >= 0) {\n return Math.ceil(bodyValue);\n }\n return undefined;\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string; inventoryModelVersion?: 1 | 2 };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /**\n * The status every seat NOT named in `seats` holds.\n *\n * Present because {@link PubApi.objects} asks for the compact form: the modal\n * status is stated once and only the exceptions are listed, which on a\n * mostly-sold event makes `default` `booked` rather than `free`. Readers must\n * honour it — treating an absent seat as free renders a sold-out venue as\n * wide open. Absent only from an older server, where every seat is named and\n * `free` is the correct assumption.\n */\n default?: string;\n /** The seats whose status differs from {@link PubObjectsResult.default}. */\n seats: Record<string, string>;\n /** Section/zone ids hidden from buyers this event (seats stripped from the map). */\n hidden?: string[];\n /** Section/zone ids in the `closed` state (Phase 2): rendered grey + not purchasable. */\n closed?: string[];\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n items?: HoldLineItem[];\n}\n\n/** Browser-safe active-hold projection returned by the resume endpoint. */\nexport interface ResumedHoldResult extends HoldResult {\n items: HoldLineItem[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n items?: HoldResult['items'];\n zoneId?: string;\n}\n\n/** A gateway the organizer can be connected to. */\nexport type PaymentProviderName = 'stripe' | 'razorpay';\n\n/**\n * Why `payment-options` came back with an empty list.\n *\n * The three are NOT interchangeable and two of them give opposite advice:\n * `not_configured` means the organizer takes payment somewhere else,\n * `payments_off_for_event` means they deliberately do not sell THIS event\n * online, and `unavailable_for_event` means they switched it on and it is\n * broken. Collapsing them makes the widget blame a working integration for a\n * decision that was made on purpose.\n */\nexport type PaymentOptionsReason =\n | 'not_configured'\n | 'payments_off_for_event'\n | 'unavailable_for_event';\n\n/**\n * What this event can take money through. Since the per-event gateway column\n * landed, `providers` holds AT MOST ONE entry — the gateway the organizer\n * assigned — so no browser can choose which one charges.\n *\n * `reason` is optional on the wire: a widget pinned against an older worker\n * still parses, and its absence means what that worker meant by an empty list.\n */\nexport interface PaymentOptionsResult {\n providers: PaymentProviderName[];\n currency: string | null;\n reason?: PaymentOptionsReason | null;\n}\n\n/** A started payment. Exactly one of the two handoffs comes back. */\nexport interface CheckoutSessionResult {\n orderId: string;\n totalMinor: number;\n currency: string;\n expiresAt: number;\n /** Hosted gateway page — navigate to it. */\n redirectUrl?: string;\n /** In-page modal gateway — open it without leaving the page. */\n clientPayload?: Record<string, unknown>;\n}\n\n/** An order's state while its gateway webhook is in flight. */\nexport interface OrderStatusResult {\n orderId: string;\n status: string;\n totalMinor: number;\n currency: string;\n amountFormatted: string;\n seatCount: number;\n // Present once the order is settled (confirmed / refund states): the same\n // capability now also unlocks the ticket view.\n eventName?: string | null;\n venue?: string | null;\n startsAt?: number | null;\n tickets?: Array<{\n label: string;\n token: string;\n status: 'issued' | 'checked_in' | 'void';\n checkedInAt: number | null;\n }>;\n /** Hosted ticket page — the durable re-entry point after the modal closes. */\n ticketUrl?: string;\n /** Printable A4 PDF, up to three ticket cards per page. */\n pdfUrl?: string;\n}\n\n/** Codes a 409 uses to say \"the unit you picked is no longer yours to pick\". */\nconst OBJECT_UNAVAILABLE_CODES: Record<string, SelectedObjectUnavailableEvent['reason']> = {\n seat_conflict: 'taken',\n conflict: 'taken',\n channel_assignment_conflict: 'ineligible',\n allocation_exhausted: 'exhausted',\n};\n\nexport interface PubApiOptions {\n /**\n * Buyer access session. When present, EVERY scoped operation on this client\n * carries `Authorization: Bearer bse_…` — chart, objects, hold, replace-hold,\n * best-available, resume, release, extend, resnapshot and the realtime\n * subscribe ticket. The binding is immutable for the client's lifetime: there\n * is no method that turns it off, so no operation can silently downgrade to\n * anonymous Public sale (guide §6, §7).\n */\n access?: BuyerAccessContext;\n /** A 409 named specific inventory the buyer can no longer have. */\n onObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n private readonly viewerId = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `viewer_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n\n private readonly access?: BuyerAccessContext;\n private readonly onObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n\n constructor(private readonly base: string, options: PubApiOptions = {}) {\n this.access = options.access;\n this.onObjectUnavailable = options.onObjectUnavailable;\n }\n\n /** True when this client is bound to a buyer access session. */\n get accessScoped(): boolean {\n return !!this.access?.configured;\n }\n\n private async request<T>(\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown; labels?: string[] } = {},\n retried: { auth?: boolean; rateLimit?: boolean } = {},\n ): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n // Throws BuyerAccessUnavailableError rather than returning undefined when a\n // configured session cannot produce a bearer — the request must not go out\n // anonymous, because anonymous means Public sale.\n const authorization = await this.access?.authorization(retried.auth ? 'unauthorized' : 'initial');\n if (authorization) headers.Authorization = authorization;\n\n const res = await fetch(`${this.base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | {\n error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string;\n retryAfterSeconds?: number;\n }\n | null;\n // The public API names its machine code in `error` (`conflict`, `event_closed`,\n // …); older/other routes may send `code`. Carry whichever into ApiError.code so\n // the code is populated (it was previously always undefined — nothing reads it\n // yet) and the bridge can pass it through. The specific 409 discriminator still\n // rides in `reason` (`sold_out` | `not_enough_together`) and wins downstream.\n const code = err?.code ?? err?.error;\n\n if (this.access?.configured && (res.status === 401 || res.status === 403 || res.status === 422)) {\n const refreshed = await this.access.handleFailure(res.status, code);\n // Exactly one retry, and only for an expiry the provider just renewed.\n // A refresh returns the same or a narrower scope; it never widens, and\n // a second failure is reported rather than looped.\n if (refreshed && !retried.auth) return this.request<T>(path, init, { ...retried, auth: true });\n }\n if (res.status === 409) {\n const reason = code ? OBJECT_UNAVAILABLE_CODES[code] : undefined;\n const labels = err?.conflicts?.map((c) => c.label) ?? init.labels ?? [];\n if (reason) this.onObjectUnavailable?.({ labels, reason, code });\n }\n\n let retryAfterS: number | undefined;\n if (res.status === 429) {\n retryAfterS = parseRetryAfter(res.headers.get('Retry-After'), err?.retryAfterSeconds)\n ?? DEFAULT_RATE_LIMIT_WAIT_S;\n // One automatic retry, and only for a READ.\n //\n // A rate-limited `chart()`/`objects()` is what turns an on-sale spike\n // into a blank widget, and re-reading is free of consequence — the same\n // GET twice is the same GET. A hold, a best-available, a checkout or an\n // extend is NOT: replaying one can take a second seat, start a second\n // payment, or burn an extend allowance, so a 429 on those is reported to\n // the caller with the server's delay attached and never replayed here.\n if (\n method === 'GET'\n && !retried.rateLimit\n && retryAfterS <= MAX_RATE_LIMIT_WAIT_S\n ) {\n await new Promise((resolve) => setTimeout(resolve, retryAfterS! * 1000));\n return this.request<T>(path, init, { ...retried, rateLimit: true });\n }\n }\n\n throw new ApiError(\n res.status,\n err?.error ?? `request_failed_${res.status}`,\n code,\n err?.conflicts,\n err?.reason,\n retryAfterS,\n );\n }\n return data as T;\n }\n\n /**\n * Binary counterpart to `request`. Buyer media needs the same in-memory\n * bearer/refresh rules as JSON, but returns bytes that the picker turns into\n * a blob URL. The bearer stays in the Authorization header and is never\n * appended to `path`.\n */\n private async requestBlob(\n path: string,\n retried: { auth?: boolean; rateLimit?: boolean } = {},\n ): Promise<Blob> {\n const headers: Record<string, string> = {};\n const authorization = await this.access?.authorization(retried.auth ? 'unauthorized' : 'initial');\n if (authorization) headers.Authorization = authorization;\n const res = await fetch(`${this.base}${path}`, { method: 'GET', headers, credentials: 'omit' });\n if (res.ok) return res.blob();\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson\n ? await res.json().catch(() => null) as { error?: string; code?: string; retryAfterSeconds?: number } | null\n : null;\n const code = data?.code ?? data?.error;\n\n if (this.access?.configured && (res.status === 401 || res.status === 403 || res.status === 422)) {\n const refreshed = await this.access.handleFailure(res.status, code);\n if (refreshed && !retried.auth) return this.requestBlob(path, { ...retried, auth: true });\n }\n\n let retryAfterS: number | undefined;\n if (res.status === 429) {\n retryAfterS = parseRetryAfter(res.headers.get('Retry-After'), data?.retryAfterSeconds)\n ?? DEFAULT_RATE_LIMIT_WAIT_S;\n if (!retried.rateLimit && retryAfterS <= MAX_RATE_LIMIT_WAIT_S) {\n await new Promise((resolve) => setTimeout(resolve, retryAfterS! * 1000));\n return this.requestBlob(path, { ...retried, rateLimit: true });\n }\n }\n\n throw new ApiError(\n res.status,\n data?.error ?? `request_failed_${res.status}`,\n code,\n undefined,\n undefined,\n retryAfterS,\n );\n }\n\n chart(key: string): Promise<PubChartResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n /** Authenticated bytes for an Event-scoped authored view image. */\n asset(key: string, asset: string): Promise<Blob> {\n if (!/^[a-zA-Z0-9._-]+$/.test(asset)) {\n return Promise.reject(new ApiError(404, 'not_found', 'not_found'));\n }\n return this.requestBlob(\n `/pub/events/${encodeURIComponent(key)}/assets/${encodeURIComponent(asset)}`,\n );\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n // `compact=1` costs nothing to ask for and is ignored by a server that\n // predates it, which then answers with every seat named and no `default` —\n // the shape this client already handled.\n return this.request(`/pub/events/${encodeURIComponent(key)}/objects?compact=1`);\n }\n\n hold(key: string, selections: Array<{ label: string; tierId?: string | null; quantity?: number }>, ttlMs?: number, replaceHoldId?: string): Promise<HoldResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { selections, ...(ttlMs ? { ttlMs } : {}), ...(replaceHoldId ? { replaceHoldId } : {}) },\n labels: selections.map((s) => s.label),\n });\n }\n\n // `zoneId` scopes the pick to one zone and `ttlMs` carries the host's checkout\n // window — both are part of the route contract, and dropping either here made\n // the SDK quietly pick venue-wide and hold for the server default instead.\n bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string, ttlMs?: number): Promise<BestAvailableResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}), ...(zoneId ? { zoneId } : {}), ...(ttlMs ? { ttlMs } : {}) },\n });\n }\n\n resume(key: string, holdId: string): Promise<ResumedHoldResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/hold/resume`, {\n method: 'POST',\n body: { holdId },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true; released?: string[] }> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n /** P4 \"need more time?\": push an active hold's expiry out. Throws ApiError 409\n * (reason: expired | extend_limit | not_found | not_active) if it can't. */\n extend(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends: number }> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/extend`, {\n method: 'POST',\n body: { holdId, ...(ttlMs ? { ttlMs } : {}) },\n });\n }\n\n /**\n * Which gateways this event can actually take money through — the question\n * `checkout: 'hosted'` has to answer BEFORE it shows a buyer a Pay button, so\n * the answer is never discovered by failing a payment.\n *\n * Anonymous, and it discloses no account, key, mode or currency for a gateway\n * that did not match.\n */\n paymentOptions(key: string): Promise<PaymentOptionsResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/payment-options`);\n }\n\n /** Server-resolved active ticket offers and category prices. */\n availability(key: string, live = false): Promise<unknown> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/availability${live ? '?live=1' : ''}`);\n }\n\n /**\n * Turn a live hold into an order and start a payment.\n *\n * The amount is NOT sent: the server recomputes it from the hold's own items,\n * which is the only reason a browser cannot alter what it pays. Nor is the\n * PROVIDER — the event row decides which gateway charges, and a `provider` in\n * the body is checked rather than obeyed (409 `provider_mismatch`). Omitting\n * it is the shape that cannot disagree.\n */\n startCheckout(\n key: string,\n input: { holdId: string; buyerEmail: string; buyerName?: string; returnUrl?: string },\n ): Promise<CheckoutSessionResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/checkout`, {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Poll an order while its gateway webhook lands. The order id is an\n * unguessable token the buyer already holds, so it acts as the capability —\n * which is also why a buyer returning from a gateway page can be told what\n * happened with nothing but the id in the return URL.\n */\n orderStatus(orderId: string): Promise<OrderStatusResult> {\n return this.request(`/pub/orders/${encodeURIComponent(orderId)}/status`);\n }\n\n /**\n * Mint a one-use subscribe ticket for the next socket attempt (protocol doc\n * §3). The bearer travels here, over ordinary HTTPS where CORS and Origin\n * already apply; the socket then carries only the short-lived ticket, in its\n * subprotocol list. TTL ≤ 30s, single redemption — mint one per attempt.\n */\n subscribeTicket(key: string): Promise<{ ticket?: string; protocols?: string[] } | null> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/subscribe-tickets`, {\n method: 'POST',\n body: {},\n });\n }\n\n /**\n * The subscribe URL. Never carries a credential — not the bearer, not the\n * ticket. Query parameters are diagnostics only.\n */\n subscribeUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n const params = new URLSearchParams({ surface: 'picker', viewerId: this.viewerId });\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe?${params}`;\n }\n\n /**\n * What PickerController opens its own socket with.\n *\n * Empty for an access-scoped client: a scoped audience authenticates with a\n * subprotocol ticket, which a URL-only constructor cannot carry, so the SDK's\n * BuyerRealtimeClient owns that socket instead and the controller skips its\n * own (an empty URL is its documented \"no live feed\" contract). A tokenless\n * Managed public client returns exactly the URL it always has.\n */\n socketUrl(key: string): string {\n return this.accessScoped ? '' : this.subscribeUrl(key);\n }\n\n /**\n * The subprotocol list a PLAIN `new WebSocket(url, protocols)` must offer for\n * this transport — `PickerTransport.socketProtocols`, which PickerController\n * calls optionally and which nothing implemented until now.\n *\n * Offering `seatlayer.v1` is the whole point: without it the DO answers an\n * anonymous socket with the LEGACY verbose frame — every unit of a 10k-seat\n * event, on connect and on every reconnect — instead of the compact\n * `{default, exceptions}` form. Empty for an access-scoped client, which\n * authenticates with a one-use ticket a URL-only constructor cannot carry and\n * whose socket BuyerRealtimeClient owns instead (see `socketUrl`).\n *\n * `createRealtime` below is the preferred path and supersedes this for any\n * host that can use it; this stays the correct answer for a host that builds\n * the socket itself from the transport contract.\n */\n socketProtocols(key: string): string[] {\n void key; // same answer for every event; the parameter is the interface's\n return this.accessScoped ? [] : [SEATLAYER_V1];\n }\n\n /**\n * Hand PickerController the v1 realtime client instead of letting it open a\n * bare socket — `PickerTransport.createRealtime`.\n *\n * This is what puts an ANONYMOUS buyer (the on-sale case) on the same wire as\n * a private-channel one: compact snapshots, `sv.<n>` resume so a reconnect\n * inside the ring costs a delta rather than a full re-snapshot, ping/pong\n * liveness, and one jittered backoff implementation shared by both. The\n * anonymous case simply passes no `mintTicket` — the `/pub/events/:key/\n * subscribe` upgrade requires no ticket, and the DO resolves a ticketless\n * socket to the public scope.\n *\n * Null when access-scoped: that socket is owned by the widget's own\n * BuyerRealtimeClient (with the ticket exchange), and `socketUrl()` already\n * returns '' so the controller opens nothing.\n */\n createRealtime(key: string, sink: RealtimeSink): BuyerRealtimeClient | null {\n if (this.accessScoped) return null;\n return new BuyerRealtimeClient({ url: this.subscribeUrl(key), sink });\n }\n}\n","/**\n * Buyer access context — the browser half of the Sales Channels contract\n * (`docs/sales-channels-integration-guide-2026-08-01.md` §6, §9, §10).\n *\n * A promoter's own backend mints a short-lived, opaque buyer-access session\n * (`bse_…`) that grants exactly one event's private channel scope. That bearer\n * reaches the browser, and only the browser — this module is where it lives,\n * and the rules it enforces are the ones the guide states outright:\n *\n * - the token is held in memory on a private field. It is never written to\n * localStorage/sessionStorage/cookies, never appended to a URL, and never\n * placed in a log, an Error message, telemetry, or JSON. `toJSON()` and\n * `toString()` are overridden so an accidental `JSON.stringify(context)` or\n * template interpolation cannot leak it;\n * - refresh goes through the host's `buyerAccessTokenProvider`, which is\n * called with a `reason` so the host can distinguish a first acquisition\n * from an expiry from a 401;\n * - **a configured context never falls back to anonymous Public sale.** When\n * no bearer can be obtained the operation fails with a typed access error\n * instead of going out unauthenticated. Sending the request without the\n * bearer would silently widen the buyer's scope to Public — the exact\n * failure the feature exists to prevent (guide §7).\n *\n * Deliberately free of any `@seatlayer/core` import: it deals in tokens, HTTP\n * status codes and callbacks only, so it vendors into the app's widget copy\n * with no engine coupling.\n */\n\n/** Why the SDK is asking the host for a token. Passed to the provider. */\nexport type BuyerAccessRefreshReason =\n /** First acquisition, before the chart is fetched. */\n | 'initial'\n /** Proactive: the held token is inside the renewal skew. */\n | 'expiring'\n /** Reactive: the held token's own expiry has passed. */\n | 'expired'\n /** Reactive: the server answered 401 `buyer_access_expired`. */\n | 'unauthorized'\n /** A realtime reconnect needs a live bearer to mint a subscribe ticket. */\n | 'reconnect'\n /** The host called `refreshAccess()`. */\n | 'manual';\n\n/** What a `buyerAccessTokenProvider` resolves to — the response body of the\n * host's own mint endpoint, unchanged. */\nexport interface BuyerAccessToken {\n /** The opaque `bse_…` buyer-access session bearer. */\n token: string;\n /** Epoch ms. Optional — absent means \"trust the server\", and the SDK then\n * refreshes only reactively on a 401. */\n expiresAt?: number;\n}\n\nexport type BuyerAccessTokenProvider = (\n context: { reason: BuyerAccessRefreshReason },\n) => BuyerAccessToken | Promise<BuyerAccessToken>;\n\n/**\n * Why private inventory is not available. Never collapsed into a generic\n * network failure (guide §10) and never carrying channel identity — the buyer\n * is told the state, not which allocation they missed.\n */\nexport type BuyerAccessUnavailableReason =\n /** The session was revoked (HTTP 401 after refresh, or WS close 4401). */\n | 'revoked'\n /** The channel is paused — a legitimate, temporary organizer state. */\n | 'paused'\n /** 401 `buyer_access_invalid`: do not retry this bearer. */\n | 'invalid'\n /** 403 `buyer_access_origin_mismatch`. */\n | 'origin_mismatch'\n /** 403 `buyer_access_event_mismatch`. */\n | 'event_mismatch'\n /** 403 `buyer_access_mode_mismatch` (test bearer on a live event or v.v.). */\n | 'mode_mismatch'\n /** 403 `channel_access_denied`. */\n | 'channel_denied'\n /** 422 `invalid_channel_scope` — an integration configuration error. */\n | 'invalid_scope'\n /** The host's token provider threw or returned nothing usable. */\n | 'provider_failed'\n /** A one-shot `buyerAccessToken` lapsed and no provider was configured. */\n | 'no_token';\n\n/** The access session expired. Carries whether the refresh recovered it. */\nexport interface BuyerAccessExpiredEvent {\n reason: BuyerAccessRefreshReason;\n /** The server's machine code when the expiry was observed over HTTP. */\n code?: string;\n /** True when the provider handed back a fresh token and work continues. */\n refreshed: boolean;\n}\n\n/** Private inventory is unavailable, and refreshing will not fix it. */\nexport interface BuyerAccessUnavailableEvent {\n reason: BuyerAccessUnavailableReason;\n /** The server's machine code, when there was one. */\n code?: string;\n /** The HTTP status, when the state came from an HTTP response. */\n status?: number;\n /** True only for states a later retry could clear (`paused`). */\n retryable: boolean;\n}\n\n/** One or more selected-but-unheld units stopped being selectable. */\nexport interface SelectedObjectUnavailableEvent {\n /** Inventory labels (never channel identity). */\n labels: string[];\n reason:\n /** An allocation change moved it out of this buyer's scope (guide §9). */\n | 'ineligible'\n /** Someone else held or booked it. */\n | 'taken'\n /** 409 `allocation_exhausted` — this private allocation has none left. */\n | 'exhausted';\n code?: string;\n}\n\nexport interface BuyerAccessContextOptions {\n provider?: BuyerAccessTokenProvider;\n /** One-shot escape hatch for hosts that already own the token lifecycle. */\n token?: string | BuyerAccessToken;\n /** Renew this long before the stated expiry. Default 30s. */\n skewMs?: number;\n onExpired?: (event: BuyerAccessExpiredEvent) => void;\n onUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n}\n\n/**\n * Thrown instead of letting a scoped request go out unauthenticated. Carries no\n * bearer and no channel identity, so it is safe to log or hand to an error\n * reporter verbatim.\n */\nexport class BuyerAccessUnavailableError extends Error {\n readonly reason: BuyerAccessUnavailableReason;\n readonly code?: string;\n readonly status?: number;\n\n constructor(event: BuyerAccessUnavailableEvent) {\n super(`buyer_access_unavailable:${event.reason}`);\n this.name = 'BuyerAccessUnavailableError';\n this.reason = event.reason;\n this.code = event.code;\n this.status = event.status;\n }\n}\n\n/** Server error codes that mean \"this session lapsed; run the refresh flow\". */\nconst EXPIRED_CODES = new Set(['buyer_access_expired']);\n\n/**\n * Reasons that describe ONE request, not the session behind it. They report to\n * the host but never latch the context terminal and never discard the bearer.\n *\n * `channel_denied` is here on the guide's own reading: §10 answers a 403\n * `channel_access_denied` with \"return buyer to permitted inventory\" — the\n * buyer asked for a seat outside their allocation, which is a mis-click, not a\n * dead session. Latching it meant one wrong seat permanently killed a live\n * buyer's access, including their ability to RELEASE the hold they already\n * legitimately owned. Found against a live worker in the M9 pass.\n */\nconst RECOVERABLE = new Set<BuyerAccessUnavailableReason>([\n 'paused',\n 'provider_failed',\n 'channel_denied',\n]);\n\n/**\n * Guide §10 error table → an unavailable reason. Anything not in the table is\n * not an access failure and must stay an ordinary error, so this returns null.\n */\nexport function classifyAccessFailure(\n status: number,\n code: string | undefined,\n): BuyerAccessUnavailableReason | null {\n switch (code) {\n case 'buyer_access_invalid':\n return 'invalid';\n case 'buyer_access_revoked':\n return 'revoked';\n case 'buyer_access_origin_mismatch':\n return 'origin_mismatch';\n case 'buyer_access_event_mismatch':\n return 'event_mismatch';\n case 'buyer_access_mode_mismatch':\n return 'mode_mismatch';\n case 'channel_access_denied':\n return 'channel_denied';\n case 'channel_paused':\n return 'paused';\n case 'invalid_channel_scope':\n return 'invalid_scope';\n default:\n break;\n }\n // An unnamed 401 on a scoped request is still an access failure; treat it as\n // the non-retryable kind rather than falling through to Public sale.\n if (status === 401) return 'invalid';\n return null;\n}\n\n/** True when this HTTP failure means \"refresh the session and try again\". */\nexport function isAccessExpiry(status: number, code: string | undefined): boolean {\n return status === 401 && !!code && EXPIRED_CODES.has(code);\n}\n\nconst DEFAULT_SKEW_MS = 30_000;\n\nexport class BuyerAccessContext {\n /** Private field: not enumerable, not spreadable, not serializable. */\n #token: string | null = null;\n #expiresAt = 0;\n #provider?: BuyerAccessTokenProvider;\n #skewMs: number;\n #inflight: Promise<string | null> | null = null;\n #terminal: BuyerAccessUnavailableEvent | null = null;\n /** The most recent failure, terminal or not — so one cause reports once. */\n #lastFailure: BuyerAccessUnavailableEvent | null = null;\n #onExpired?: (event: BuyerAccessExpiredEvent) => void;\n #onUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /** Decided once, at construction. See the `configured` getter. */\n #configured = false;\n\n constructor(options: BuyerAccessContextOptions) {\n this.#provider = options.provider;\n this.#skewMs = options.skewMs ?? DEFAULT_SKEW_MS;\n this.#onExpired = options.onExpired;\n this.#onUnavailable = options.onUnavailable;\n if (options.token) {\n const seed = typeof options.token === 'string' ? { token: options.token } : options.token;\n this.#accept(seed);\n }\n this.#configured = !!this.#provider || !!this.#token;\n }\n\n /**\n * True when this picker is access-scoped at all. A false here is the\n * tokenless public picker, which must behave exactly as it always has.\n *\n * Answered from what the HOST asked for, never from live token state. It used\n * to be `!!#provider || !!#token`, which quietly inverted this file's central\n * rule for a one-shot `buyerAccessToken` host: `#fail()` clears `#token`, so\n * the first refusal turned a configured context into an \"unconfigured\" one,\n * `authorization()` then returned null instead of throwing, and the very next\n * call went out with no bearer — the anonymous Public sale fallback this\n * module exists to prevent. A provider host never saw it, because `#provider`\n * held `configured` true. Found against a live worker in the M9 pass.\n */\n get configured(): boolean {\n return this.#configured;\n }\n\n /** Set once a state arrives that refreshing cannot clear. */\n get unavailable(): BuyerAccessUnavailableEvent | null {\n return this.#terminal;\n }\n\n /** True while a usable bearer is held (ignores skew). */\n get hasToken(): boolean {\n return !!this.#token && (this.#expiresAt === 0 || this.#expiresAt > Date.now());\n }\n\n /** Epoch ms the current token expires, or 0 when the host didn't say. */\n get expiresAt(): number {\n return this.#expiresAt;\n }\n\n /**\n * The `Authorization` header value for a scoped operation.\n *\n * Returns null only when this context is not configured at all (the ordinary\n * anonymous public picker). A configured context either returns a bearer or\n * throws `BuyerAccessUnavailableError` — it never returns null, because a\n * null here would send the request as anonymous Public sale.\n */\n async authorization(reason: BuyerAccessRefreshReason = 'initial'): Promise<string | null> {\n if (!this.configured) return null;\n if (this.#terminal) throw new BuyerAccessUnavailableError(this.#terminal);\n\n const now = Date.now();\n const stale = !this.#token || (this.#expiresAt > 0 && this.#expiresAt - this.#skewMs <= now);\n if (stale) {\n const expired = !!this.#token && this.#expiresAt > 0 && this.#expiresAt <= now;\n const why: BuyerAccessRefreshReason = this.#token ? (expired ? 'expired' : 'expiring') : reason;\n const token = await this.#renew(why);\n if (!token) {\n // #renew already classified and reported the failure; reuse that event\n // rather than raising a second one for the same cause.\n throw new BuyerAccessUnavailableError(\n this.#terminal ?? this.#lastFailure ?? this.#fail('provider_failed'),\n );\n }\n return `Bearer ${token}`;\n }\n return `Bearer ${this.#token}`;\n }\n\n /**\n * Handle a 401/403 from a scoped call. Returns true when the caller should\n * retry the same request once with the refreshed bearer.\n */\n async handleFailure(status: number, code: string | undefined): Promise<boolean> {\n if (!this.configured) return false;\n\n if (isAccessExpiry(status, code)) {\n this.#token = null;\n this.#expiresAt = 0;\n const token = await this.#renew('unauthorized', code);\n this.#onExpired?.({ reason: 'unauthorized', code, refreshed: !!token });\n return !!token;\n }\n\n const reason = classifyAccessFailure(status, code);\n if (reason) {\n this.#fail(reason, code, status);\n return false;\n }\n return false;\n }\n\n /** Host-driven re-acquisition (after the buyer signs in again, say). */\n async refresh(reason: BuyerAccessRefreshReason = 'manual'): Promise<boolean> {\n this.#terminal = null;\n this.#lastFailure = null;\n this.#token = null;\n this.#expiresAt = 0;\n return !!(await this.#renew(reason));\n }\n\n /** Drop the bearer. Called on destroy so nothing outlives the widget. */\n clear(): void {\n this.#token = null;\n this.#expiresAt = 0;\n this.#inflight = null;\n }\n\n /** Redaction: the bearer must not survive a stringify or an interpolation. */\n toJSON(): { configured: boolean; hasToken: boolean } {\n return { configured: this.configured, hasToken: this.hasToken };\n }\n\n toString(): string {\n return '[BuyerAccessContext redacted]';\n }\n\n // ---- internals ------------------------------------------------------------\n\n #accept(next: BuyerAccessToken | null | undefined): string | null {\n if (!next || typeof next.token !== 'string' || !next.token) return null;\n this.#token = next.token;\n this.#expiresAt = typeof next.expiresAt === 'number' ? next.expiresAt : 0;\n return this.#token;\n }\n\n /**\n * One provider call at a time. Several operations racing an expiry (chart +\n * objects + a socket ticket) must not mint several sessions — the guide's\n * rotate-on-retry rule would revoke the ones they didn't observe.\n */\n #renew(reason: BuyerAccessRefreshReason, code?: string): Promise<string | null> {\n if (this.#inflight) return this.#inflight;\n const provider = this.#provider;\n if (!provider) {\n // A one-shot token with no provider cannot be renewed. That is a legal\n // host choice, so it is a typed state, not a crash.\n this.#fail('no_token', code);\n return Promise.resolve(null);\n }\n const run = (async (): Promise<string | null> => {\n try {\n const next = await provider({ reason });\n const token = this.#accept(next);\n if (!token) {\n this.#fail('provider_failed', code);\n return null;\n }\n return token;\n } catch {\n // The provider's own error text may contain host detail; it is not\n // rethrown and not logged. The host already saw its own failure.\n this.#fail('provider_failed', code);\n return null;\n } finally {\n this.#inflight = null;\n }\n })();\n this.#inflight = run;\n return run;\n }\n\n #fail(\n reason: BuyerAccessUnavailableReason,\n code?: string,\n status?: number,\n ): BuyerAccessUnavailableEvent {\n const event: BuyerAccessUnavailableEvent = {\n reason,\n code,\n status,\n // Unchanged: `retryable` means \"the SAME request may succeed later\".\n // `provider_failed` is recoverable but not retryable — the host must fix\n // its mint endpoint first — so the two sets are deliberately different.\n retryable: reason === 'paused' || reason === 'channel_denied',\n };\n this.#lastFailure = event;\n // A recoverable reason says nothing about the SESSION, so it must not latch\n // the context terminal and must not throw the bearer away.\n if (!RECOVERABLE.has(reason)) {\n this.#terminal = event;\n this.#token = null;\n this.#expiresAt = 0;\n }\n this.#onUnavailable?.(event);\n return event;\n }\n}\n\n/** Build a context from widget options, or null for the tokenless public path. */\nexport function createBuyerAccessContext(\n options: {\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n buyerAccessToken?: string | BuyerAccessToken;\n },\n hooks: Pick<BuyerAccessContextOptions, 'onExpired' | 'onUnavailable'> = {},\n): BuyerAccessContext | null {\n if (!options.buyerAccessTokenProvider && !options.buyerAccessToken) return null;\n return new BuyerAccessContext({\n provider: options.buyerAccessTokenProvider,\n token: options.buyerAccessToken,\n ...hooks,\n });\n}\n","/** Dependency-free canonical SeatLayer mark for distributed SDK attribution.\n *\n * Keep the geometry in sync with `SeatLayerMark` and\n * `scripts/generate-brand-assets.py`. The fixed dark-surface palette makes the\n * fragment safe inside the self-contained midnight attribution tile.\n */\nexport const SEATLAYER_ATTRIBUTION_MARK_SVG =\n '<svg viewBox=\"0 0 64 56\" width=\"12\" height=\"11\" fill=\"none\" aria-hidden=\"true\" focusable=\"false\" style=\"display:block\">' +\n '<path d=\"M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z\" fill=\"#f4b740\"/>' +\n '<path d=\"M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z\" fill=\"#f4b740\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '<path d=\"M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z\" fill=\"#fcf7ee\"/>' +\n '<path d=\"M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z\" fill=\"#fcf7ee\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '<path d=\"M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z\" fill=\"#fcf7ee\"/>' +\n '<path d=\"M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z\" fill=\"#fcf7ee\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '</svg>';\n","/**\n * A secure, framework-neutral host for the SeatLayer chart Designer.\n *\n * The Designer remains an iframe so a platform never gives its SeatLayer secret\n * key to a browser. This class owns the iframe lifecycle and accepts messages\n * only from that iframe's exact origin.\n */\nexport type EmbeddedDesignerEventType =\n | 'seatlayer.designer.ready'\n | 'seatlayer.designer.saved'\n | 'seatlayer.designer.published'\n | 'seatlayer.designer.close'\n | 'seatlayer.designer.error';\n\nexport interface EmbeddedDesignerMessage {\n type: EmbeddedDesignerEventType;\n chartId?: string;\n workspaceId?: string;\n expiresAt?: number;\n code?: string;\n message?: string;\n meta?: unknown;\n /**\n * Set by the Designer on an error it raised while the editor was already\n * running (a failed autosave, thumbnail upload, reload…). Such an error is\n * about ONE operation, not about the session, so the SDK reports it to the\n * host and leaves the live editor mounted instead of replacing it with the\n * dead-end card. Absent on older Designer builds — see\n * {@link EmbeddedDesigner} for the phase-based fallback.\n */\n fatal?: boolean;\n /** The operation that failed, when `fatal` is `false` (e.g. `'save'`). */\n action?: string;\n}\n\nexport interface EmbeddedDesignerOptions {\n /** The short-lived URL returned by your backend's Designer-session call. */\n designerUrl: string;\n /** CSS selector or element where the iframe is mounted. */\n container: string | HTMLElement;\n /**\n * Verify the message belongs to the chart your backend opened. When set, the\n * id is required on `ready` and every runtime lifecycle message. Only an error\n * raised before the iframe resolves its session may omit it.\n */\n expectedChartId?: string;\n /**\n * Verify the message belongs to the workspace your backend opened. Uses the\n * same ready/runtime requirement and pre-session error exception as\n * `expectedChartId`.\n */\n expectedWorkspaceId?: string;\n title?: string;\n className?: string;\n style?: Partial<CSSStyleDeclaration>;\n allow?: string;\n referrerPolicy?: ReferrerPolicy;\n /**\n * Show the built-in branded loading skeleton and error/expiry card inside the\n * container while the Designer boots. Defaults to `true`. Set `false` when the\n * host renders its own loading and error chrome.\n */\n showLoadingState?: boolean;\n /**\n * If the Designer never posts `ready` within this many milliseconds, the host\n * transitions to the error card with a timeout message. Defaults to `20000`.\n * Only used when `showLoadingState` is enabled.\n */\n loadingTimeoutMs?: number;\n /**\n * How to size the iframe's height. The Designer is a full application (its\n * shell is `position:fixed; height:100dvh`), not flowing content, so it should\n * fill its box rather than be measured.\n *\n * - `'fill'` (default): container-aware. On mount the SDK probes whether the\n * host gave the container a DEFINITE (bounded) height:\n * - **Bounded container** (a fixed-height block, `height`/`max-height`,\n * `flex:1; min-h:0`, a resolved `%`, etc.) → the iframe fills 100% of\n * that block and tracks its size live via a `ResizeObserver`.\n * - **Content-sized container** (the block collapses to whatever the iframe\n * measures — typical full-page usage) → the iframe grows so its bottom\n * edge reaches the bottom of the viewport (`window.innerHeight -\n * iframe.top`), recomputed (rAF-throttled) on `resize` /\n * `orientationchange` / `scroll`.\n * Either way the result is clamped to `minHeight`. The verdict is cached but\n * re-probed on `resize`/`orientationchange` so a responsive host layout can\n * flip between the two. The legacy `seatlayer.designer.resize` message is\n * ignored in `'fill'` mode: it is circular, because the fixed-position shell\n * just echoes the iframe height.\n * - a number: a fixed pixel height. In this mode the legacy resize message is\n * still honoured (unless `autoResize` is `false`) so older hosts keep growing.\n *\n * All SDK-managed heights are written with `!important` priority so a host\n * theme's `iframe { height: … !important }` cannot override them.\n */\n height?: 'fill' | number;\n /** Minimum height (px) that `'fill'` mode clamps to. Defaults to `480`. */\n minHeight?: number;\n /**\n * Auto-grow the iframe to the height the Designer reports over the resize\n * protocol (`seatlayer.designer.resize`). Only applies when `height` is a fixed\n * number; ignored in `'fill'` mode. Defaults to `true`. Set `false` when the\n * host sizes a fixed-height iframe itself.\n */\n autoResize?: boolean;\n /**\n * Called when the user presses \"Try again\" on the error card. Use it to mint a\n * fresh Designer session and call `setDesignerUrl()` with the new URL, which\n * recreates the iframe and returns to the loading state. When omitted, \"Try\n * again\" reloads the current `designerUrl` in place.\n *\n * When supplied, it also powers automatic session renewal — see\n * {@link EmbeddedDesignerOptions.autoRenewSession}.\n */\n onRequestRelaunch?: () => void;\n /**\n * Keep long editing sessions alive without the user ever hitting the expiry\n * wall. Designer sessions are short-lived security tokens; when the host wires\n * `onRequestRelaunch` the SDK, with this enabled, will:\n *\n * - **Renew proactively.** From each `ready` message's `expiresAt` it schedules\n * a silent relaunch shortly before the session lapses (~3 min ahead; for a\n * TTL under 15 min it renews after 80% of the remaining life, and never\n * sooner than 30s after `ready`). The host mints a fresh session and swaps\n * `designerUrl`, so the editor keeps working with no error card.\n * - **Recover on expiry.** If an expiry error still slips through (a slept\n * laptop woke past the renewal window, say) it makes ONE automatic relaunch\n * attempt before showing the \"Try again\" card, and only falls back to the\n * card if that relaunch also fails.\n *\n * Defaults to `true` whenever `onRequestRelaunch` is provided; a no-op without\n * it. Set `false` to keep the fully manual \"Try again\" behavior.\n */\n autoRenewSession?: boolean;\n onReady?: (message: EmbeddedDesignerMessage) => void;\n onSaved?: (message: EmbeddedDesignerMessage) => void;\n onPublished?: (message: EmbeddedDesignerMessage) => void;\n onClose?: (message: EmbeddedDesignerMessage) => void;\n onError?: (message: EmbeddedDesignerMessage) => void;\n}\n\nconst TYPES = new Set<EmbeddedDesignerEventType>([\n 'seatlayer.designer.ready',\n 'seatlayer.designer.saved',\n 'seatlayer.designer.published',\n 'seatlayer.designer.close',\n 'seatlayer.designer.error',\n]);\n\nconst DEFAULT_LOADING_TIMEOUT_MS = 20000;\nconst DEFAULT_MIN_FILL_HEIGHT = 480;\n/**\n * Proactive session-renewal timing (see {@link EmbeddedDesigner.scheduleRenewal}).\n * We aim to relaunch a comfortable lead ahead of `expiresAt`; short-lived sessions\n * instead renew after a fraction of their life so the lead never overshoots the TTL.\n */\nconst RENEW_LEAD_MS = 3 * 60 * 1000; // standard lead: renew ~3 min before expiry\nconst RENEW_SHORT_TTL_MS = 15 * 60 * 1000; // below this TTL, use the fraction clamp\nconst RENEW_SHORT_TTL_FRACTION = 0.8; // short TTL: renew after 80% of remaining life\nconst RENEW_MIN_DELAY_MS = 30 * 1000; // never renew sooner than 30s after `ready`\n/**\n * Container-fill detection tunables. The probe drives the iframe to two extreme\n * heights within one synchronous task (no paint between reads, so no flash) and\n * watches whether the container tracks it.\n */\nconst FILL_PROBE_HEIGHT_PX = 100000; // \"huge\" iframe used to see if the box grows with it\nconst FILL_PROBE_TRACK_EPSILON_PX = 4; // container grew with the iframe ⇒ content-sized\nconst FILL_MIN_DEFINITE_HEIGHT_PX = 50; // a bounded box must keep at least this much height\n\n/** Internal reason the error card is being shown, used to pick human copy. */\ntype ErrorCause = 'expired' | 'mismatch' | 'timeout' | 'load';\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container !== 'string') return container;\n const element = document.querySelector<HTMLElement>(container);\n if (!element) throw new Error(`EmbeddedDesigner container not found: ${container}`);\n return element;\n}\n\n/** Map an error message's `code` onto one of the human-copy causes. */\nfunction causeFromCode(code: string | undefined): ErrorCause {\n const value = (code ?? '').toLowerCase();\n if (value.includes('expire') || value.includes('revoke') || value === '401') return 'expired';\n if (value.includes('mismatch')) return 'mismatch';\n if (value.includes('timeout')) return 'timeout';\n return 'load';\n}\n\nconst ERROR_COPY: Record<ErrorCause, { title: string; body: string }> = {\n expired: {\n title: 'This design session expired',\n body: 'For your security, editing sessions are short-lived. Start a fresh one to keep designing.',\n },\n mismatch: {\n title: \"This editor doesn't match this chart\",\n body: 'The session that loaded belongs to a different chart or workspace. Reopen the designer to continue.',\n },\n timeout: {\n title: 'The designer is taking too long',\n body: 'It did not finish loading in time. This is usually a slow connection — try again.',\n },\n load: {\n title: \"We couldn't load the designer\",\n body: 'Something went wrong while opening the editor. Please try again.',\n },\n};\n\n/** Mount, replace, and destroy a scoped Designer iframe safely. */\nexport class EmbeddedDesigner {\n private options: EmbeddedDesignerOptions;\n private frame: HTMLIFrameElement | null = null;\n private designerOrigin = '';\n private overlay: HTMLDivElement | null = null;\n private timeoutTimer: ReturnType<typeof setTimeout> | null = null;\n /** Proactive session-renewal timer; armed from each `ready`, cleared on re-mount. */\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n /** Last identity-checked session expiry, so a live policy change can re-arm. */\n private sessionExpiresAt: number | undefined;\n /**\n * One automatic recovery relaunch is allowed per expiry. Reset ONLY when a fresh\n * `ready` arrives — deliberately not on re-mount — so a session that keeps failing\n * to load can't loop the host through endless silent relaunches.\n */\n private autoRecoverUsed = false;\n private phase: 'loading' | 'ready' | 'error' = 'loading';\n /**\n * Set only after an identity-checked `ready`. Unlike `phase`, this remains true\n * if a later fatal error renders the error card, so no subsequent callback can\n * shed the chart/workspace identity the live session already established.\n */\n private identityEstablished = false;\n private restoreContainerPosition: string | null = null;\n // Host-side fullscreen pin: saved state we restore on `off`/Escape/destroy.\n private pinned = false;\n private frameStyleBeforeFs: string | null = null;\n private docOverflowBeforeFs: string | null = null;\n private bodyOverflowBeforeFs: string | null = null;\n private fsKeyHandler: ((event: KeyboardEvent) => void) | null = null;\n /** Latest height (px string) the Designer reported; re-applied after unpin. */\n private lastAutoHeight = '';\n // Fill sizing: pending rAF handles + whether window listeners are attached.\n private fillRaf: number | null = null;\n private reprobeRaf: number | null = null;\n private fillListening = false;\n /** Resolved container element (fill measurement + ResizeObserver target). */\n private containerEl: HTMLElement | null = null;\n /** Cached fill verdict: 'container' = bounded block, 'viewport' = full page. */\n private fillMode: 'viewport' | 'container' | null = null;\n /** Live block-size tracking in container-fill mode; disconnected on destroy. */\n private resizeObs: ResizeObserver | null = null;\n\n constructor(options: EmbeddedDesignerOptions) {\n this.options = options;\n }\n\n mount(): HTMLIFrameElement {\n this.destroy();\n const url = new URL(this.options.designerUrl, window.location.href);\n if (url.protocol !== 'https:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {\n throw new Error('EmbeddedDesigner requires an HTTPS designerUrl outside local development.');\n }\n this.designerOrigin = url.origin;\n\n const frame = document.createElement('iframe');\n frame.title = this.options.title ?? 'Venue chart Designer';\n frame.allow = this.options.allow ?? 'fullscreen; clipboard-write';\n frame.referrerPolicy = this.options.referrerPolicy ?? 'origin';\n frame.src = url.toString();\n // Width/height are written with `!important` priority so a host theme's\n // `iframe { height: … !important }` cannot beat the SDK's inline sizing.\n frame.style.setProperty('width', '100%', 'important');\n // `'fill'` (default) is (re)computed once the frame is in the DOM (see\n // startFill); a numeric height is a fixed pixel box.\n frame.style.setProperty(\n 'height',\n typeof this.options.height === 'number' ? `${this.options.height}px` : '100%',\n 'important',\n );\n frame.style.border = '0';\n Object.assign(frame.style, this.options.style);\n if (this.options.className) frame.className = this.options.className;\n\n const container = resolveContainer(this.options.container);\n this.containerEl = container;\n window.addEventListener('message', this.handleMessage);\n container.append(frame);\n this.frame = frame;\n\n // Fill mode owns the height from the viewport now the frame is measurable.\n if (this.fillEnabled()) this.startFill();\n\n this.phase = 'loading';\n if (this.loadingStateEnabled()) {\n this.ensureContainerPositioned(container);\n this.renderOverlay(container, 'loading');\n const timeout = this.options.loadingTimeoutMs ?? DEFAULT_LOADING_TIMEOUT_MS;\n if (timeout > 0 && Number.isFinite(timeout)) {\n this.timeoutTimer = setTimeout(() => {\n if (this.phase === 'loading') this.showError('timeout');\n }, timeout);\n }\n }\n return frame;\n }\n\n /** Replace the iframe instead of assigning a new fragment to an existing one. */\n setDesignerUrl(designerUrl: string): HTMLIFrameElement {\n this.options = { ...this.options, designerUrl };\n // mount() tears everything down and re-enters the loading state.\n return this.mount();\n }\n\n getIframe(): HTMLIFrameElement | null {\n return this.frame;\n }\n\n /** Update iframe sizing without replacing the live Designer session. */\n setSizing(height: 'fill' | number | undefined, minHeight: number | undefined): void {\n this.options = { ...this.options, height, minHeight };\n if (!this.frame) return;\n\n this.stopFill();\n this.lastAutoHeight = '';\n if (this.fillEnabled()) {\n if (!this.pinned) this.setFrameHeight('100%');\n this.startFill();\n } else if (!this.pinned) {\n this.setFrameHeight(`${height}px`);\n }\n }\n\n /** Update renewal/expiry-recovery policy without replacing the iframe. */\n setRelaunchPolicy(\n onRequestRelaunch: (() => void) | undefined,\n autoRenewSession: boolean | undefined,\n ): void {\n this.options = { ...this.options, onRequestRelaunch, autoRenewSession };\n this.clearRenewTimer();\n if (this.phase === 'ready') this.scheduleRenewal(this.sessionExpiresAt);\n }\n\n destroy(): void {\n window.removeEventListener('message', this.handleMessage);\n this.stopFill();\n this.unpinFullscreen();\n this.clearTimeoutTimer();\n this.clearRenewTimer();\n this.removeOverlay();\n this.restoreContainerStyle();\n this.frame?.remove();\n this.frame = null;\n this.containerEl = null;\n this.fillMode = null;\n this.designerOrigin = '';\n this.phase = 'loading';\n this.identityEstablished = false;\n this.sessionExpiresAt = undefined;\n this.lastAutoHeight = '';\n }\n\n private loadingStateEnabled(): boolean {\n return this.options.showLoadingState !== false;\n }\n\n private autoResizeEnabled(): boolean {\n return this.options.autoResize !== false;\n }\n\n /** Fill mode is the default; a numeric `height` opts into a fixed pixel box. */\n private fillEnabled(): boolean {\n return typeof this.options.height !== 'number';\n }\n\n /** Write an SDK-managed height with `!important` so a host theme can't win. */\n private setFrameHeight(value: string): void {\n this.frame?.style.setProperty('height', value, 'important');\n }\n\n /**\n * Decide whether the host gave the container a DEFINITE (bounded) height — a\n * fixed block the embed should fill 100% of — versus a content-sized container\n * that collapses to whatever the iframe measures (full-page usage).\n *\n * We drive the iframe to two extreme heights within a single synchronous task\n * and watch whether the container follows: a bounded box barely moves, a\n * content-sized one grows with the iframe. Because we restore the height before\n * yielding, the browser only lays out — it never paints the extremes, so there\n * is no visible flash. Works for px, resolved `%`, and flex (`flex:1;min-h:0`)\n * heights, and leaves a mere `min-height` floor classified as content-sized so\n * full-page hosts keep the old viewport-fill behavior.\n */\n private detectFillMode(): 'viewport' | 'container' {\n const container = this.containerEl;\n const frame = this.frame;\n if (this.pinned || !container || !frame) return this.fillMode ?? 'viewport';\n const measure = (): number => container.getBoundingClientRect().height;\n const savedValue = frame.style.getPropertyValue('height');\n const savedPriority = frame.style.getPropertyPriority('height');\n\n frame.style.setProperty('height', '0px', 'important');\n const collapsed = measure();\n frame.style.setProperty('height', `${FILL_PROBE_HEIGHT_PX}px`, 'important');\n const expanded = measure();\n\n if (savedValue) frame.style.setProperty('height', savedValue, savedPriority);\n else frame.style.removeProperty('height');\n\n const tracksIframe = expanded - collapsed > FILL_PROBE_TRACK_EPSILON_PX;\n const bounded = !tracksIframe && collapsed >= FILL_MIN_DEFINITE_HEIGHT_PX;\n return bounded ? 'container' : 'viewport';\n }\n\n /**\n * Size the iframe for the current fill verdict, clamped to `minHeight`. In\n * container mode it fills 100% of the bounded block; in viewport mode its\n * bottom edge meets the bottom of the viewport (`window.innerHeight - top`).\n * No-op while pinned fullscreen (the pin fills the viewport itself).\n */\n private applyFill(): void {\n if (!this.frame || this.pinned) return;\n const min = this.options.minHeight ?? DEFAULT_MIN_FILL_HEIGHT;\n if (this.fillMode === 'container' && this.containerEl) {\n const target = Math.max(min, Math.round(this.containerEl.getBoundingClientRect().height));\n this.setFrameHeight(`${target}px`);\n return;\n }\n const top = this.frame.getBoundingClientRect().top;\n const target = Math.max(min, Math.round(window.innerHeight - top));\n this.setFrameHeight(`${target}px`);\n }\n\n /** rAF-throttled fill recompute, so a burst of scroll/RO ticks coalesces. */\n private scheduleFill = (): void => {\n if (this.fillRaf !== null) return;\n this.fillRaf = requestAnimationFrame(() => {\n this.fillRaf = null;\n this.applyFill();\n });\n };\n\n /**\n * rAF-throttled re-probe: a host layout change (responsive breakpoint, a block\n * gaining/losing a definite height) can flip the verdict, so `resize` /\n * `orientationchange` re-detect and swap the container observer accordingly.\n */\n private scheduleReprobe = (): void => {\n if (this.reprobeRaf !== null) return;\n this.reprobeRaf = requestAnimationFrame(() => {\n this.reprobeRaf = null;\n if (this.pinned) return;\n this.fillMode = this.detectFillMode();\n this.syncContainerObserver();\n this.applyFill();\n });\n };\n\n /** Attach/detach the container ResizeObserver to match the current verdict. */\n private syncContainerObserver(): void {\n const want =\n this.fillMode === 'container' && !!this.containerEl && typeof ResizeObserver !== 'undefined';\n if (want && !this.resizeObs) {\n this.resizeObs = new ResizeObserver(() => this.scheduleFill());\n this.resizeObs.observe(this.containerEl!);\n } else if (!want && this.resizeObs) {\n this.resizeObs.disconnect();\n this.resizeObs = null;\n }\n }\n\n private startFill(): void {\n this.fillMode = this.detectFillMode();\n this.syncContainerObserver();\n this.applyFill();\n if (this.fillListening) return;\n this.fillListening = true;\n // Layout-changing events re-probe (the verdict can flip); scroll only shifts\n // the viewport-fill top offset, so it just re-applies.\n window.addEventListener('resize', this.scheduleReprobe);\n window.addEventListener('orientationchange', this.scheduleReprobe);\n window.addEventListener('scroll', this.scheduleFill, { passive: true });\n }\n\n private stopFill(): void {\n if (this.fillRaf !== null) {\n cancelAnimationFrame(this.fillRaf);\n this.fillRaf = null;\n }\n if (this.reprobeRaf !== null) {\n cancelAnimationFrame(this.reprobeRaf);\n this.reprobeRaf = null;\n }\n if (this.resizeObs) {\n this.resizeObs.disconnect();\n this.resizeObs = null;\n }\n if (!this.fillListening) return;\n this.fillListening = false;\n window.removeEventListener('resize', this.scheduleReprobe);\n window.removeEventListener('orientationchange', this.scheduleReprobe);\n window.removeEventListener('scroll', this.scheduleFill);\n }\n\n /**\n * Pin the iframe over the host page as a viewport-filling overlay. We save the\n * iframe's inline style and the document scroll state so `unpinFullscreen`\n * restores everything exactly. Escape (host-side) also exits.\n */\n private pinFullscreen(): void {\n if (this.pinned || !this.frame) return;\n this.pinned = true;\n this.frameStyleBeforeFs = this.frame.getAttribute('style');\n // Every pin property is `!important` so a host theme's `iframe { … }` rules\n // (height/width/inset) can't unpin us. `inset` is written as its four longhands\n // for reliability across engines. Restored wholesale via the saved style attr.\n const pin: Record<string, string> = {\n position: 'fixed',\n top: '0',\n right: '0',\n bottom: '0',\n left: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n border: '0',\n 'z-index': '2147483000',\n background: '#101625',\n };\n for (const [property, value] of Object.entries(pin)) {\n this.frame.style.setProperty(property, value, 'important');\n }\n\n const docEl = document.documentElement;\n this.docOverflowBeforeFs = docEl.style.overflow;\n docEl.style.overflow = 'hidden';\n if (document.body) {\n this.bodyOverflowBeforeFs = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n this.fsKeyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') this.unpinFullscreen();\n };\n window.addEventListener('keydown', this.fsKeyHandler);\n }\n\n /** Undo `pinFullscreen`: restore the iframe style + scroll lock. Idempotent. */\n private unpinFullscreen(): void {\n if (!this.pinned) return;\n this.pinned = false;\n if (this.frame) {\n if (this.frameStyleBeforeFs === null) this.frame.removeAttribute('style');\n else this.frame.setAttribute('style', this.frameStyleBeforeFs);\n // Restore the right height for the mode: recompute the fill, or re-apply\n // the last height the Designer reported (numeric mode). Both use\n // `!important` so a host theme can't win after we unpin.\n if (this.fillEnabled()) this.applyFill();\n else if (this.autoResizeEnabled() && this.lastAutoHeight) this.setFrameHeight(this.lastAutoHeight);\n else if (typeof this.options.height === 'number') this.setFrameHeight(`${this.options.height}px`);\n }\n this.frameStyleBeforeFs = null;\n\n if (this.docOverflowBeforeFs !== null) {\n document.documentElement.style.overflow = this.docOverflowBeforeFs;\n this.docOverflowBeforeFs = null;\n }\n if (this.bodyOverflowBeforeFs !== null && document.body) {\n document.body.style.overflow = this.bodyOverflowBeforeFs;\n this.bodyOverflowBeforeFs = null;\n }\n if (this.fsKeyHandler) {\n window.removeEventListener('keydown', this.fsKeyHandler);\n this.fsKeyHandler = null;\n }\n }\n\n private clearTimeoutTimer(): void {\n if (this.timeoutTimer !== null) {\n clearTimeout(this.timeoutTimer);\n this.timeoutTimer = null;\n }\n }\n\n /**\n * Auto-renewal (proactive + one expiry recovery) is on when the host wired a\n * relaunch hook and did not opt out. Without the hook there is nothing to call,\n * so it is a no-op.\n */\n private autoRenewEnabled(): boolean {\n return !!this.options.onRequestRelaunch && this.options.autoRenewSession !== false;\n }\n\n private clearRenewTimer(): void {\n if (this.renewTimer !== null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n\n /**\n * Arm the proactive renewal timer from a `ready` message's `expiresAt` (epoch\n * ms). We relaunch a comfortable lead before expiry so the host can mint a fresh\n * session and swap `designerUrl` without the user ever seeing the expiry card:\n *\n * - normal TTL (≥ 15 min): renew {@link RENEW_LEAD_MS} (~3 min) before expiry;\n * - short TTL (< 15 min): renew after {@link RENEW_SHORT_TTL_FRACTION} (80%) of\n * the remaining life, so the lead can't overshoot the whole session;\n * - either way, never sooner than {@link RENEW_MIN_DELAY_MS} (30s) after `ready`\n * so a burst of `ready` messages can't spin the host.\n *\n * Re-armed on every `ready`; cleared on destroy / setDesignerUrl (via re-mount).\n * A no-op when auto-renewal is off or `expiresAt` is missing/already past — the\n * expiry-error path recovers a session that has already lapsed.\n */\n private scheduleRenewal(expiresAt: number | undefined): void {\n this.clearRenewTimer();\n if (!this.autoRenewEnabled()) return;\n if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) return;\n const remaining = expiresAt - Date.now();\n if (remaining <= 0) return;\n const lead =\n remaining < RENEW_SHORT_TTL_MS\n ? remaining * RENEW_SHORT_TTL_FRACTION\n : remaining - RENEW_LEAD_MS;\n const delay = Math.max(RENEW_MIN_DELAY_MS, lead);\n this.renewTimer = setTimeout(() => {\n this.renewTimer = null;\n // Silent renewal: the host mints a fresh session and swaps designerUrl,\n // which re-mounts the iframe and re-arms us from the next `ready`.\n if (this.autoRenewEnabled()) this.options.onRequestRelaunch!();\n }, delay);\n }\n\n private ensureContainerPositioned(container: HTMLElement): void {\n // The overlay is absolutely positioned; the container must establish a\n // positioning context. Only touch a `static` container, and remember to\n // restore it on destroy.\n const position = getComputedStyle(container).position;\n if (position === 'static') {\n this.restoreContainerPosition = container.style.position;\n container.style.position = 'relative';\n }\n }\n\n private restoreContainerStyle(): void {\n if (this.restoreContainerPosition === null) return;\n try {\n resolveContainer(this.options.container).style.position = this.restoreContainerPosition;\n } catch {\n /* container already gone — nothing to restore */\n }\n this.restoreContainerPosition = null;\n }\n\n private removeOverlay(): void {\n this.overlay?.remove();\n this.overlay = null;\n }\n\n private showError(cause: ErrorCause): void {\n this.phase = 'error';\n this.clearTimeoutTimer();\n if (!this.loadingStateEnabled()) return;\n let container: HTMLElement;\n try {\n container = resolveContainer(this.options.container);\n } catch {\n return;\n }\n this.renderOverlay(container, 'error', cause);\n }\n\n private handleTryAgain(): void {\n if (this.options.onRequestRelaunch) {\n // Host mints a fresh session and calls setDesignerUrl(), which re-mounts\n // the iframe and returns to the loading state.\n this.options.onRequestRelaunch();\n return;\n }\n // No relaunch hook: reload the same session URL in place.\n this.mount();\n }\n\n /**\n * Build (or rebuild) the overlay for the given phase. A single overlay element\n * is reused so we never stack stale skeletons or cards.\n */\n private renderOverlay(container: HTMLElement, phase: 'loading' | 'error', cause?: ErrorCause): void {\n this.removeOverlay();\n const overlay = document.createElement('div');\n overlay.setAttribute('data-seatlayer-designer-overlay', phase);\n overlay.setAttribute('role', phase === 'error' ? 'alert' : 'status');\n overlay.setAttribute('aria-live', 'polite');\n Object.assign(overlay.style, {\n position: 'absolute',\n inset: '0',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: '#101625',\n color: '#e6ebf5',\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif',\n zIndex: '2',\n overflow: 'hidden',\n } satisfies Partial<CSSStyleDeclaration>);\n\n if (phase === 'loading') this.buildSkeleton(overlay);\n else this.buildErrorCard(overlay, cause ?? 'load');\n\n container.append(overlay);\n this.overlay = overlay;\n }\n\n private buildSkeleton(overlay: HTMLDivElement): void {\n // Scoped keyframes; the shimmer only runs when the user allows motion.\n // `@sl-css` opts it into build-time minification (cdn/minifyCssLiterals.ts).\n const style = document.createElement('style');\n style.textContent = /* @sl-css */ `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes seatlayer-designer-shimmer {\n 0% { background-position: -320px 0; }\n 100% { background-position: 320px 0; }\n }\n [data-seatlayer-designer-overlay=\"loading\"] .sl-shimmer {\n animation: seatlayer-designer-shimmer 1.25s ease-in-out infinite;\n background-size: 640px 100%;\n }\n}`;\n overlay.append(style);\n\n const shimmer =\n 'linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.10) 37%, rgba(255,255,255,0.04) 63%)';\n\n const scaffold = document.createElement('div');\n Object.assign(scaffold.style, {\n position: 'absolute',\n inset: '0',\n display: 'flex',\n flexDirection: 'column',\n padding: '16px',\n gap: '14px',\n opacity: '0.9',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const bar = (styles: Partial<CSSStyleDeclaration>): HTMLDivElement => {\n const node = document.createElement('div');\n node.className = 'sl-shimmer';\n Object.assign(node.style, {\n background: shimmer,\n borderRadius: '8px',\n } satisfies Partial<CSSStyleDeclaration>);\n Object.assign(node.style, styles);\n return node;\n };\n\n // Top toolbar row.\n scaffold.append(bar({ height: '40px', width: '100%', flex: '0 0 auto' }));\n\n // Body: side panel + canvas.\n const body = document.createElement('div');\n Object.assign(body.style, {\n display: 'flex',\n gap: '14px',\n flex: '1 1 auto',\n minHeight: '0',\n } satisfies Partial<CSSStyleDeclaration>);\n body.append(bar({ width: '220px', height: '100%', flex: '0 0 auto' }));\n body.append(bar({ flex: '1 1 auto', height: '100%' }));\n scaffold.append(body);\n\n overlay.append(scaffold);\n\n // Centered caption above the scaffold.\n const caption = document.createElement('div');\n Object.assign(caption.style, {\n position: 'relative',\n zIndex: '1',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 16px',\n borderRadius: '999px',\n background: 'rgba(16, 22, 37, 0.72)',\n fontSize: '13px',\n fontWeight: '500',\n letterSpacing: '0.01em',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const dot = document.createElement('span');\n dot.className = 'sl-shimmer';\n Object.assign(dot.style, {\n width: '9px',\n height: '9px',\n borderRadius: '50%',\n background: shimmer,\n flex: '0 0 auto',\n } satisfies Partial<CSSStyleDeclaration>);\n caption.append(dot);\n caption.append(document.createTextNode('Loading designer…'));\n overlay.append(caption);\n }\n\n private buildErrorCard(overlay: HTMLDivElement, cause: ErrorCause): void {\n const copy = ERROR_COPY[cause];\n const card = document.createElement('div');\n Object.assign(card.style, {\n maxWidth: '420px',\n margin: '0 24px',\n padding: '28px',\n textAlign: 'center',\n background: 'rgba(255, 255, 255, 0.03)',\n border: '1px solid rgba(255, 255, 255, 0.08)',\n borderRadius: '16px',\n boxShadow: '0 12px 40px rgba(0, 0, 0, 0.35)',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const heading = document.createElement('h2');\n heading.textContent = copy.title;\n Object.assign(heading.style, {\n margin: '0 0 8px',\n fontSize: '17px',\n fontWeight: '600',\n color: '#f4f7ff',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const body = document.createElement('p');\n body.textContent = copy.body;\n Object.assign(body.style, {\n margin: '0 0 20px',\n fontSize: '13.5px',\n lineHeight: '1.5',\n color: '#aab4c8',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = 'Try again';\n Object.assign(button.style, {\n appearance: 'none',\n cursor: 'pointer',\n border: '0',\n borderRadius: '10px',\n padding: '10px 22px',\n fontSize: '14px',\n fontWeight: '600',\n color: '#101625',\n background: '#7aa2ff',\n } satisfies Partial<CSSStyleDeclaration>);\n button.addEventListener('click', () => this.handleTryAgain());\n\n card.append(heading, body, button);\n overlay.append(card);\n }\n\n private handleMessage = (event: MessageEvent<unknown>) => {\n if (!this.frame || event.origin !== this.designerOrigin || event.source !== this.frame.contentWindow) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n\n // Layout protocol — origin-locked like everything else, but handled here\n // rather than dispatched to the host callbacks.\n if (data.type === 'seatlayer.designer.resize') {\n // Fill mode owns the height from the viewport; the reported scrollHeight is\n // circular (the fixed-position shell echoes the iframe height), so ignore\n // it. Only a fixed numeric height honours the legacy auto-grow.\n if (!this.fillEnabled() && this.autoResizeEnabled()\n && typeof data.px === 'number' && Number.isFinite(data.px) && data.px > 0) {\n this.lastAutoHeight = `${Math.round(data.px)}px`;\n // While pinned fullscreen the iframe fills the viewport; apply the\n // reported height only when not pinned (it's re-applied on unpin).\n // `!important` so a host theme's `iframe { height … }` can't win.\n if (!this.pinned) this.setFrameHeight(this.lastAutoHeight);\n }\n return;\n }\n if (data.type === 'seatlayer.designer.fullscreen') {\n if (data.on === true) this.pinFullscreen();\n else if (data.on === false) this.unpinFullscreen();\n return;\n }\n\n if (typeof data.type !== 'string' || !TYPES.has(data.type as EmbeddedDesignerEventType)) return;\n\n const message: EmbeddedDesignerMessage = {\n type: data.type as EmbeddedDesignerEventType,\n chartId: typeof data.chartId === 'string' ? data.chartId : undefined,\n workspaceId: typeof data.workspaceId === 'string' ? data.workspaceId : undefined,\n expiresAt: typeof data.expiresAt === 'number' ? data.expiresAt : undefined,\n code: typeof data.code === 'string' ? data.code : undefined,\n message: typeof data.message === 'string' ? data.message : undefined,\n meta: data.meta,\n fatal: typeof data.fatal === 'boolean' ? data.fatal : undefined,\n action: typeof data.action === 'string' ? data.action : undefined,\n };\n\n // `ready` establishes the session identity, and saved/published/close are\n // runtime-only lifecycle events, so every configured expected id is required\n // on those messages. After an accepted `ready`, errors are strict too. The\n // sole omission exception is a genuinely pre-identity boot error: the iframe\n // can fail before its session response reveals either id. Any id it does send\n // must still match. Resize/fullscreen returned above and deliberately remain\n // identity-free layout protocol messages.\n const identityRequired = this.identityEstablished\n || message.type === 'seatlayer.designer.ready'\n || message.type === 'seatlayer.designer.saved'\n || message.type === 'seatlayer.designer.published'\n || message.type === 'seatlayer.designer.close';\n const chartMismatch = this.options.expectedChartId !== undefined\n && (message.chartId !== this.options.expectedChartId)\n && (identityRequired || message.chartId !== undefined);\n const workspaceMismatch = this.options.expectedWorkspaceId !== undefined\n && (message.workspaceId !== this.options.expectedWorkspaceId)\n && (identityRequired || message.workspaceId !== undefined);\n if (\n chartMismatch || workspaceMismatch\n ) {\n // A message from our exact iframe carrying the wrong identity is a real\n // session mismatch, not spoofing. Surface it (loading state on) rather than\n // dispatching it to the host callbacks.\n this.showError('mismatch');\n return;\n }\n\n switch (message.type) {\n case 'seatlayer.designer.ready':\n this.identityEstablished = true;\n this.sessionExpiresAt = message.expiresAt;\n this.phase = 'ready';\n this.clearTimeoutTimer();\n this.removeOverlay();\n // A fresh live session: clear the recovery guard and (re)arm proactive\n // renewal from this session's expiry.\n this.autoRecoverUsed = false;\n this.scheduleRenewal(message.expiresAt);\n this.options.onReady?.(message);\n break;\n case 'seatlayer.designer.saved': this.options.onSaved?.(message); break;\n case 'seatlayer.designer.published': this.options.onPublished?.(message); break;\n case 'seatlayer.designer.close': this.options.onClose?.(message); break;\n case 'seatlayer.designer.error': {\n const cause = causeFromCode(message.code);\n // Expiry is recoverable. If the host wired a relaunch hook, make ONE\n // silent auto-relaunch before ever showing the dead-end card — the user\n // never sees an overlay. Guarded (reset only on a fresh `ready`) so a\n // session that keeps failing to load falls through to the card instead of\n // looping the host.\n if (cause === 'expired' && this.autoRenewEnabled() && !this.autoRecoverUsed) {\n this.autoRecoverUsed = true;\n this.clearRenewTimer();\n this.options.onRequestRelaunch!();\n return;\n }\n // Only a dead session justifies tearing the editor down. An operation\n // that failed inside a running editor (autosave hitting a transient 5xx,\n // a thumbnail upload) leaves the session and the user's work intact, so\n // it is reported to the host and surfaced by the Designer's own in-editor\n // banner — replacing the canvas with \"We couldn't load the designer\"\n // would be both wrong and destructive. `fatal` is authoritative when the\n // Designer sends it; otherwise we fall back to the phase, which is the\n // same signal (we already had a `ready`).\n const fatal = typeof message.fatal === 'boolean'\n ? message.fatal\n : (cause !== 'load' || this.phase !== 'ready');\n if (fatal) this.showError(cause);\n this.options.onError?.(message);\n break;\n }\n }\n };\n}\n","/**\n * SeatPicker — the full buyer experience as a widget.\n *\n * Where `SeatingChart` is canvas-only, SeatPicker owns the complete chrome\n * from the canonical UX contract: branded header,\n * live price panel, selection tray with GA steppers, hold countdown, snipe\n * toasts and expiry recovery — all on top of the shared PickerController, so\n * every host gets the whole experience with one mount.\n *\n * Render contexts (owner requirement): the SAME widget adapts to a full-screen\n * takeover, an inline <div> in a content page, or a popup — breakpoints key\n * off the CONTAINER via ResizeObserver, never the viewport. `SeatPicker.open()`\n * mounts a document-level modal (scrim, ESC, focus restore) in one call.\n *\n * Theming (owner requirement): org account customization flows automatically —\n * the chart payload's ChartTheme (accent, accentInk, logoUrl, brand name,\n * fontFamily, …) seeds the look; the host `theme` option overrides any subset;\n * and every value lands as a `--sl-*` CSS custom property on the widget root\n * so plain host CSS can restyle too.\n */\nimport {\n PickerController,\n ACCESSIBILITY_TYPES,\n expandChart,\n // generateSeatPanorama is deliberately NOT here — see loadPanorama().\n generateSeatThumb,\n loadLocale,\n setStringOverrides,\n t,\n tCount,\n type AccessibilityType,\n type ChartTheme,\n type PickerMapTheme,\n type ExpandedSeat,\n type LodRung,\n type PanoramaResult,\n type PickerSeat,\n type PickerTransport,\n type RendererViewMode,\n type SeatCommercialAttributes,\n type SeatHoverDetails,\n type SectionSummary,\n type TableSelectionDetails,\n} from '@seatlayer/core';\nimport type { Venue3DHandle, SeatState3D, SeatView as View3DSeatView } from '@seatlayer/core/view3d';\nimport { isAuthoredSeatView, seatViewDisclosure } from '@seatlayer/core/view3d/crossfade/panorama';\nimport { seatConfidenceDisclosure } from '@seatlayer/core/core/seatConfidence';\nimport {\n browserPanoramaConstraints,\n loadPanoramaImage,\n planPanoramaDelivery,\n schedulePanoramaUpgrade,\n} from '@seatlayer/core/view/panoramaDelivery';\nimport {\n PubApi,\n type HoldLineItem,\n type HoldResult,\n type OrderStatusResult,\n type PaymentOptionsReason,\n type PaymentOptionsResult,\n} from './api';\nimport { BuyerAssetObjectUrls } from './buyerAssets';\n// mountCheckout is deliberately NOT imported here — see loadHostedCheckout().\nimport type { CheckoutHandle, CheckoutState } from './hostedCheckout';\nimport {\n createBuyerAccessContext,\n type BuyerAccessContext,\n type BuyerAccessExpiredEvent,\n type BuyerAccessToken,\n type BuyerAccessTokenProvider,\n type BuyerAccessUnavailableEvent,\n type BuyerAccessUnavailableReason,\n type SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nimport { SEATLAYER_ATTRIBUTION_MARK_SVG } from './seatLayerBrand';\nimport {\n nextOfferTransitionAt,\n parseTicketOfferAvailability,\n ticketOfferPrices,\n type TicketOfferAvailability,\n type TicketOfferPrice,\n} from './offerAvailability';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n/** Show the \"Need more time?\" prompt when the hold has this long (ms) left. */\nconst EXTEND_PROMPT_MS = 60_000;\n/**\n * Default seat ceiling for offering 3D — see the `max3DSeats` option.\n *\n * 15,000 was calibrated when the largest chart we had evidence for was the\n * 14,142-seat arena, so it read as \"a bit above the biggest venue\" rather than\n * as a measured limit. It silently withheld the 3D toggle from Mega Stadium\n * (53,018) — the chart whose entire purpose is to demonstrate 3D at stadium\n * scale — and did so invisibly, because the control is simply never built.\n *\n * 60,000 is grounded in `docs/phase-b-browser-and-53k-evidence-2026-08-04.md`:\n * the 53,018-seat bowl sustains 60fps on orbit and on the fly-to-seat descent\n * at 3 draw calls idle / 4 in flight — the same draw count as the 14k arena,\n * because the seat cloud is one instanced draw and does not scale with venue\n * size.\n *\n * The halving below is deliberately left to bite. That evidence is a desktop\n * GPU only; mobile at this scale is UNMEASURED. A small or low-core device\n * therefore lands at 30,000 and still refuses 3D for a 53k bowl, which is the\n * conservative side of a gap we have not closed. Raise the half only when a\n * phone has actually been measured.\n */\nconst MAX_3D_SEATS_DEFAULT = 60_000;\n/** Most section pills the 3D navigation rail will offer before it stays quiet. */\nconst MAX_3D_SECTION_PILLS = 12;\n\n/** Minimal shape of a section object read off the ChartDoc for the minimap. */\ninterface SectionLike {\n type: string;\n id: string;\n outline?: { x: number; y: number }[];\n color?: string;\n zone?: string;\n}\n\n/** Even-odd point-in-polygon test in world units (minimap click → section). */\nfunction pointInPolygon(x: number, y: number, poly: { x: number; y: number }[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x, yi = poly[i].y, xj = poly[j].x, yj = poly[j].y;\n if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) inside = !inside;\n }\n return inside;\n}\n\n/** One price band in the F4 filter — a set of category keys within a price range. */\ninterface PriceBand {\n id: string;\n label: string;\n keys: string[];\n min: number;\n max: number;\n}\n\n/**\n * Stable checkout-handoff contract (P4). Passed as the THIRD argument to\n * `onCheckout(hold, seats, handoff)` — additive, so the legacy `(hold, seats)`\n * shape used by DesiPass web-v2 (SDK 0.7.3+) is untouched. This is the object to\n * build your order against: it is self-contained (holdId, expiry, currency, and\n * per-line tier + price) and never changes shape across minor releases.\n */\nexport interface CheckoutLineItem {\n /** Seat label (or GA synthetic-unit label) — the stable booking identity. */\n label: string;\n /**\n * Buyer-facing name (the designer's `displayLabel` override), when set.\n * Show this in YOUR order summary; `label` stays the booking identity you\n * pass to the book call. Absent = no override, fall back to `label`.\n */\n displayLabel?: string;\n /**\n * Buyer-facing type word override (seats.io \"Displayed type\", e.g. \"Table\",\n * \"Bench\", \"Box\"), when the designer set one. Absent = the default word.\n */\n displayType?: string;\n /** Chart object id (row/booth/GA area) the unit belongs to. */\n objectId: string;\n objectType: 'seat' | 'booth' | 'ga' | 'table';\n categoryKey: string;\n /** Chosen ticket tier id (Adult/Child/…), or null when the category has no tiers. */\n tierId: string | null;\n /** Unit price in MAJOR currency units (e.g. 45 = 45.00). Server-authoritative. */\n unitPrice: number;\n /** ISO-4217, resolved server-side (per-event override → org → USD). */\n currency: string;\n quantity: number;\n}\n\nexport interface CheckoutHandoff {\n /** Server hold id — pass this to YOUR book call. */\n holdId: string;\n /** Epoch ms the hold expires (after any extensions). */\n expiresAt: number;\n /** ISO-4217 currency for the whole order. */\n currency: string;\n /** Priced line items (tier + unit price + currency), server-authoritative. */\n lineItems: CheckoutLineItem[];\n /** Convenience total in major units (Σ unitPrice × quantity). */\n total: number;\n}\n\n/** Host-authoritative pricing — see {@link SeatPickerOptions.pricing}. */\nexport interface SeatPickerPricing {\n /** Unit prices by category key: a flat number, or `{ base, tiers: { tierId: price } }`. */\n prices?: Record<string, number | { base?: number; tiers?: Record<string, number> }>;\n /** Custom money renderer (e.g. `(n) => n + '€'`). Defaults to Intl currency formatting. */\n formatter?: (amount: number, currency: string) => string;\n}\n\n/** Optional constraints for the server-authoritative best-available pick. */\nexport interface SeatPickerBestAvailableOptions {\n /** Prefer a contiguous premium block, falling back to the best overall block. */\n preferPremium?: boolean;\n /** Restrict the search to one configured chart zone. */\n zoneId?: string;\n}\n\n/** Buyer-facing surface shown by the full picker widget. */\nexport type SeatPickerBuyerView = 'map' | 'venue3d';\n\n/** Optional camera intent when switching the buyer-facing surface. */\nexport interface SeatPickerBuyerViewOptions {\n /** Enter (or remain in) 3D and fly the camera to this seat id. */\n flyToSeatId?: string;\n /** When already in 3D, return the camera to the venue overview. */\n resetView?: boolean;\n}\n\n/** Host theme overrides — any subset; unset keys fall back to the org's chart theme, then defaults. */\nexport interface SeatPickerTheme {\n /** Brand accent (CTA, active chips, hold pill). */\n accent?: string;\n /** Ink on the accent (button labels). */\n accentInk?: string;\n /** Widget background. */\n background?: string;\n /** Panel/card surface color. */\n surface?: string;\n /** Primary text color. */\n text?: string;\n /** Secondary text color. */\n muted?: string;\n /** Hairline/border color. */\n line?: string;\n /** Font stack for all widget chrome. */\n fontFamily?: string;\n /** Corner radius base (px). */\n radius?: number;\n /** Header logo URL (falls back to the org logo from the chart theme, then a monogram). */\n logoUrl?: string;\n /** Brand/event fallback name for the monogram. */\n brandName?: string;\n /**\n * The DRAWN MAP, which the tokens above deliberately do not reach.\n *\n * Everything else on this interface is CSS: it re-inks panels, buttons and\n * the sidebar. The seat map is a canvas, painted from the chart document's\n * own `ChartTheme`, so a host could re-ink the whole widget and still be\n * looking at somebody else's dark venue in the middle of it (which is exactly\n * what SeatLayer's own light event-page palettes did, found 2026-08-07).\n *\n * Nested rather than flattened because `background` already means the\n * WIDGET's background here and the canvas ground is a different surface —\n * two things one word cannot carry.\n *\n * Set it only when you can vouch for the result: these colours are drawn\n * behind and beside live seat statuses (held, sold, selected), and the map is\n * the one part of this widget a buyer has to be able to read.\n */\n map?: PickerMapTheme;\n}\n\nexport interface SeatPickerOptions {\n /** CSS selector or element to mount into. Omit when using SeatPicker.open(). */\n container?: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /**\n * Custom data transport. Defaults to the CORS-trivial PubApi against\n * `apiBase`. Inject to run the widget against another backend adapter (the\n * SeatLayer dashboard's own transport) or a fully local mock (demos).\n */\n transport?: PickerTransport;\n /** Reserved for future authenticated rendering. NOT the channel-access\n * credential — a buyer access session is a different thing with different\n * authority, and uses the two options below. */\n publicKey?: string;\n /**\n * Buyer access session provider — the recommended way to show private channel\n * inventory (Sales Channels guide §6).\n *\n * Called with a `reason` whenever the widget needs a bearer: first\n * acquisition, a near/actual expiry, a 401 `buyer_access_expired`, a realtime\n * reconnect, or `refreshAccess()`. It should POST to YOUR backend, which\n * mints the session with your secret key and returns `{ token, expiresAt }`.\n *\n * The token lives in memory for the widget's lifetime and nowhere else: never\n * in storage, never in a URL, never in a log or an error message. Refresh\n * returns the same or a narrower scope; the widget never widens to Public\n * sale on its own, and a failed refresh stops the scoped operation rather\n * than retrying it anonymously. Any held seats stay held — a hold is\n * relinquished by its own opaque capability, not by channel access, so\n * losing access never strands inventory (guide §9).\n *\n * Ignored when a custom `transport` is supplied: that host owns its own\n * credentials.\n */\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n /**\n * One-shot escape hatch for hosts that already own the session lifecycle.\n * Cannot be renewed — when it lapses the widget reports `onAccessExpired`\n * and then `onAccessUnavailable`. Prefer `buyerAccessTokenProvider`.\n */\n buyerAccessToken?: string | BuyerAccessToken;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** BCP 47 language for the widget UI. Built-in: en, es, de, fr. */\n locale?: string;\n /** Per-key string overrides layered over the active locale. */\n messages?: Record<string, string>;\n /** ISO 4217 currency fallback (the org/event currency on the chart wins). */\n currency?: string;\n /** Colorblind-safe rendering (Okabe-Ito palette, hollow booked seats). */\n colorblindSafe?: boolean;\n /** Initial map projection. Buyers now toggle **Map (flat 2D) + 3D** only; the\n * legacy `perspective` (2.5D) value is still ACCEPTED for source compatibility\n * but is deprecated — it is coerced to `flat` with a one-time console warning.\n * The 3D venue view is entered from the Map/3D control, not this option. */\n initialView?: RendererViewMode;\n /**\n * Offer the interactive 3D venue view (Map | 3D toggle + a \"See it in 3D\"\n * action on the seat-confirm card). Default true. The 3D button is shown only\n * when this is not false AND the browser exposes WebGL2; there are ZERO GL\n * bytes on the wire until the buyer actually opens 3D (the OGL chunk is\n * dynamically imported on first use). Set false for embed hosts that must\n * stay strictly 2D. */\n enable3D?: boolean;\n /**\n * Seat-count ceiling above which 3D is not offered. Default: 60,000 seats on\n * desktop, reduced to 30,000 on a device that reports itself as small/low-core.\n *\n * The 53,018-seat evidence is desktop-only; that scale remains unmeasured on\n * phones, which is why the small-device default stays conservative. The 3D\n * scene holds every seat resident until a streaming rung exists. */\n max3DSeats?: number;\n /**\n * Fires when the buyer enters/leaves 3D or targets a seat there. Hosts can\n * mirror this small, non-sensitive state into a shareable URL.\n */\n onBuyerViewChange?: (state: { view: SeatPickerBuyerView; seatId?: string }) => void;\n /**\n * Optional analytics sink for the widget's own journey events. Currently emits\n * the 3D venue-view journey (`3d_opened`, `3d_orbit_engaged`, `3d_seat_picked`,\n * `3d_cinematic_played`/`_skipped`/`_cancelled`, panorama outcomes, and WebGL\n * context loss/recovery)\n * with `{ surface: 'buyer' }` merged into the props. A throwing sink never\n * breaks the widget. Route it to your product analytics (e.g. PostHog). */\n onAnalytics?: (event: string, props: Record<string, unknown>) => void;\n /**\n * Hide the \"Powered by SeatLayer\" attribution badge in the side panel foot.\n * The chart theme's own `hideBadge` flag (paid orgs) also hides it — the badge\n * is shown only when BOTH this option and the theme flag are unset/false.\n */\n hideBadge?: boolean;\n /**\n * Hide the picker's event identity (logo, event name and venue/date metadata)\n * when the host surface already presents the same event heading. The hold\n * timer, sales status and modal close controls remain available. The identity\n * is restored automatically while the picker is full screen so it never\n * loses context on a small device or an expanded map. Default false.\n *\n * A mounted host can update this through `setEventDetailsHidden()` when its\n * own event chrome arrives asynchronously.\n */\n hideEventDetails?: boolean;\n /** Host theme overrides — see SeatPickerTheme. */\n theme?: SeatPickerTheme;\n /**\n * Host-authoritative pricing. When your shop charges different prices than\n * the chart's stored category prices, pass them here so the buyer sees the\n * price they will actually pay — on the map tooltip, confirm popover, price\n * panel, tray, totals, and in the checkout handoff's line items. Keyed by\n * category key; per-tier overrides nest under `tiers`. Unlisted categories\n * fall back to the chart price.\n */\n pricing?: SeatPickerPricing;\n /**\n * Fires when the server-resolved active offer changes. Hosted event pages use\n * this to keep their headline, sticky bar and the canonical picker on the\n * same live fact. The picker remains fully functional when it is omitted.\n */\n onOfferAvailabilityChange?: (availability: TicketOfferAvailability | null) => void;\n /** Hold TTL in ms passed to hold(); server clamps to its own limits. */\n holdTtlMs?: number;\n /**\n * An opaque hold id supplied by the host to restore after navigation. It is\n * verified against the event and active server state before anything renders\n * as owned by this buyer.\n */\n initialHoldId?: string;\n /**\n * Automatically remember the active hold id in sessionStorage and restore it\n * when this event's picker mounts again. Default true. Set false when the host\n * owns hold persistence and supplies initialHoldId itself.\n */\n restoreHold?: boolean;\n /**\n * Render the real chart and live seat statuses without allowing selection,\n * holds or checkout. This is for venue previews and pre-sale Website pages;\n * it is enforced by the widget even if the event later opens while mounted.\n * Default false.\n */\n readOnly?: boolean;\n /**\n * Confirm mode: tapping a seat shows a confirmation card with section, row,\n * seat, category, price and Select/Cancel before it enters the tray. Default\n * true for the full buyer picker; set false only when the host supplies its\n * own equivalent confirmation UI.\n */\n confirmSelection?: boolean;\n /**\n * Offer a \"View from seat\" 360° preview (confirm popover + tray chips). The\n * panorama is generated from the chart geometry, or the organizer's uploaded\n * photo when a seat carries one. Default true; set false to hide the affordance.\n */\n seatView?: boolean;\n /**\n * WHERE the buyer goes once their seats are held. Default `'handoff'`.\n *\n * 'handoff' (default, and every integration that has ever existed) the\n * widget fires {@link onCheckout} with a holdId and priced line\n * items, and YOUR server takes the money. Nothing about this path\n * changes, and no payment code is even downloaded.\n * 'hosted' the widget takes the money through the gateway the ORGANIZER\n * connected, on their account — the \"sell tickets with no\n * backend\" path. Requires the org to be on hosted checkout and\n * the event to have a gateway assigned; when it does not, this\n * falls back to `'handoff'` for that buyer rather than dead-ending\n * them, and reports why through {@link onCheckoutUnavailable}.\n *\n * Named for the destination rather than as a boolean flag because there is a\n * real third answer coming and `hostedCheckout: true` would have no room for\n * it; spelling the default out also makes a host's intent legible in their own\n * source instead of hiding it in an absent option.\n *\n * TWO THINGS ARE WORTH KNOWING BEFORE YOU SWITCH THIS ON:\n *\n * 1. It needs the widget's own transport. A host-supplied `transport` owns its\n * credentials and its backend, so hosted checkout stays off there (with one\n * console warning) rather than reaching past it to api.seatlayer.io.\n * 2. WHERE A HOSTED GATEWAY RETURNS THE BUYER is settled by {@link returnUrl}\n * and by the organizer. Without one — or from an origin the organizer has\n * not declared — the buyer comes back to SeatLayer's own buyer page and is\n * confirmed THERE, not in this widget. Declare the embedding site under\n * Embed domains in the dashboard and pass `returnUrl`, and the buyer\n * returns to your page instead. In-page gateways never navigate away at\n * all, so they are unaffected either way.\n */\n checkout?: 'handoff' | 'hosted';\n /**\n * Where a redirecting gateway should send the buyer back to, for\n * `checkout: 'hosted'`.\n *\n * The server keeps this URL verbatim — path and query included — and only\n * stamps `?order=…&status=success|cancelled` onto it, so point it at\n * whichever of YOUR pages should confirm the purchase (often just\n * `window.location.href`). Mount a picker on that page and it resumes in\n * place from those parameters.\n *\n * It is validated, not trusted: the organizer declares their embed origins\n * in the dashboard, and an undeclared origin is ignored rather than\n * refused — the sale still completes, the buyer just finishes on\n * SeatLayer's page. Supplying a URL therefore cannot authorize it, which is\n * what stops a copied snippet from redirecting a paid buyer anywhere it\n * likes.\n */\n returnUrl?: string;\n /**\n * Buyer pressed the CTA and the hold succeeded — hand off to YOUR checkout.\n * `hold` and `seats` are the legacy args (unchanged since 0.6). `handoff` (P4)\n * is the stable, self-contained {@link CheckoutHandoff} to build your order\n * against — holdId, expiry, currency and priced line items. Prefer it.\n *\n * Under `checkout: 'hosted'` this fires ONLY when hosted checkout cannot run\n * for this event, so a host can keep one code path for both. It never fires\n * alongside a payment the widget is taking itself.\n */\n onCheckout?: (hold: HoldResult, seats: PickerSeat[], handoff: CheckoutHandoff) => void;\n /**\n * `checkout: 'hosted'` was asked for and this event cannot take money.\n * The seats ARE held — the buyer is mid-journey — so this is a routing\n * decision, not an error, and it is never collapsed into {@link onError}.\n *\n * `reason` carries the server's three-way answer verbatim, because two of the\n * three give opposite advice: `payments_off_for_event` means the organizer\n * deliberately does not sell this event online (nothing is wrong), while\n * `unavailable_for_event` means they switched it on and it is broken. Anything\n * unreadable — a failed lookup, an older worker — reads as `not_configured`,\n * which asserts the least about them.\n *\n * `onCheckout` fires immediately after this with the same hold. Supply either\n * (or both) and you own the next screen; supply NEITHER and the widget shows\n * the buyer an honest card of its own rather than swallowing the press.\n */\n onCheckoutUnavailable?: (event: {\n reason: PaymentOptionsReason;\n handoff: CheckoutHandoff;\n }) => void;\n /**\n * `checkout: 'hosted'` only — the gateway's webhook landed and the order is\n * PAID. The one signal a host with no backend actually needs, and the only\n * place a receipt can come from on a page that has no server of its own.\n *\n * Distinct from {@link onBooked}, which reports the same sale seen from the\n * seat map over the realtime channel and cannot fire at all for a buyer whose\n * widget was torn down by a redirect to the gateway.\n */\n onOrderConfirmed?: (order: OrderStatusResult) => void;\n /**\n * The held seats were BOOKED (P4) — your server completed payment and the\n * booking landed over the realtime channel while the widget was still open.\n * The widget shows a success state; use this to advance your own UI (receipt,\n * redirect). Fires once per hold.\n */\n onBooked?: (handoff: CheckoutHandoff) => void;\n /** Selection changed (tap or best-available). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /**\n * Active hold changed because it was created, restored, extended, partially\n * released, or fully released. Hosts should persist this state for route\n * navigation and clear their checkout cart when `hold` becomes null.\n */\n onHoldChange?: (hold: HoldResult | null, seats: PickerSeat[], handoff: CheckoutHandoff | null) => void;\n /** The open hold expired server-side (widget already reset itself). */\n onHoldExpired?: () => void;\n /** A prior active hold was verified and restored into the tray. */\n onHoldRestored?: (hold: HoldResult, seats: PickerSeat[], handoff: CheckoutHandoff) => void;\n /** Modal only: the buyer closed the picker (ESC / scrim / ✕). */\n onClose?: () => void;\n /**\n * The buyer access session lapsed. `refreshed` says whether the provider\n * already recovered it — false means private inventory is now unavailable and\n * `onAccessUnavailable` follows. Never collapsed into `onError`: an expiry is\n * a recoverable, buyer-explainable state, not a network failure (guide §10).\n */\n onAccessExpired?: (event: BuyerAccessExpiredEvent) => void;\n /**\n * Private inventory is unavailable and refreshing will not fix it — revoked,\n * paused, wrong origin/event/mode, or the provider failed. Carries a reason,\n * never a channel name, id, colour or count. The widget shows its own\n * explanatory panel; return nothing to keep it, or handle the state yourself.\n */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /**\n * Selected-but-unheld units stopped being selectable — someone else took\n * them, or an allocation change moved them out of this buyer's scope. The\n * widget has already dropped them from the tray.\n */\n onSelectedObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n onError?: (err: unknown) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nfunction escapeOption(value: unknown): string {\n return String(value ?? '').replace(/[&<>\"']/g, (character) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;',\n })[character]!);\n}\n\n// ---- 3D venue view: lazy loader + capability probe -------------------------\n\n/** The full module type for the lazy OGL venue-view chunk (`@seatlayer/core/view3d`). */\ntype Venue3DModule = typeof import('@seatlayer/core/view3d');\n\n/**\n * Injected `true` only in the CDN/IIFE build (see cdn/vite.config.ts `define`).\n * Undefined in the npm/tsup build and the vendored app copy, so the runtime-URL\n * branch below is never taken there and esbuild dead-code-eliminates it in the\n * CDN build once the constant folds to `true`.\n */\ndeclare const __SEATLAYER_CDN__: boolean | undefined;\n\n/**\n * This bundle's own URL, used only in the CDN build to locate its sibling lazy\n * chunks (`./seatlayer-view3d.mjs`, `./seatlayer-panorama.mjs`).\n * `import.meta.url` resolves to the module URL in\n * the ESM CDN output (`…/seatlayer.mjs`), and Rollup auto-shims it to a\n * `document.currentScript.src` expression in the IIFE output (`…/seatlayer.js`),\n * so both CDN formats find the chunk next to them. Guarded so no environment\n * that lacks `import.meta` throws at module init.\n */\nconst SEATLAYER_MODULE_URL: string | undefined = (() => {\n // IIFE/classic-script (CDN seatlayer.js): the tag sets document.currentScript\n // synchronously while this module's top level runs. Resolve from it first —\n // the IIFE build folds `import.meta` to `{}`, so import.meta.url is unusable\n // there anyway.\n if (typeof document !== 'undefined'\n && document.currentScript instanceof HTMLScriptElement\n && document.currentScript.src) {\n return document.currentScript.src;\n }\n // ESM (CDN seatlayer.mjs / bundlers): import.meta.url is the module URL.\n try {\n const u = import.meta.url;\n if (typeof u === 'string' && u) return u;\n } catch {\n /* no import.meta in this environment */\n }\n return undefined;\n})();\n\nlet _webgl2Cache: boolean | null = null;\n/** Whether the browser exposes WebGL2 (cached). Gates the 3D affordances. */\nfunction hasWebGL2(): boolean {\n if (_webgl2Cache !== null) return _webgl2Cache;\n try {\n if (typeof document === 'undefined') return (_webgl2Cache = false);\n const canvas = document.createElement('canvas');\n _webgl2Cache = !!canvas.getContext('webgl2');\n } catch {\n _webgl2Cache = false;\n }\n return _webgl2Cache;\n}\n\n/** Absolute URL of a sibling lazy chunk in this bundle's pinned CDN directory. */\nfunction cdnChunkUrl(fileName: string): string {\n const base = SEATLAYER_MODULE_URL ?? (typeof location !== 'undefined' ? location.href : undefined);\n if (!base) throw new Error(`seatlayer: cannot resolve the ${fileName} chunk URL`);\n return new URL(`./${fileName}`, base).href;\n}\n\n/**\n * Dynamically load the view3d module. Two build targets, one source:\n * - CDN/IIFE (cannot code-split): load the sibling ESM asset by absolute URL\n * derived from this script's own src.\n * - npm/ESM and the vendored app copy (rewritten to `../../view3d`): a bare\n * dynamic import the consumer's bundler chunk-splits automatically.\n * Either way, ZERO GL bytes are fetched until this actually runs.\n */\nasync function loadVenue3d(): Promise<Venue3DModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-view3d.mjs')) as Promise<Venue3DModule>;\n }\n return import('@seatlayer/core/view3d');\n}\n\n/** Just the generator, so the type does not drag the rest of the engine in. */\ntype PanoramaModule = Pick<typeof import('@seatlayer/core'), 'generateSeatPanorama'>;\n\n/**\n * Dynamically load the view-from-seat panorama generator, on exactly the same\n * pattern as {@link loadVenue3d}. It is ~25 KB of drawing code that runs only\n * when a buyer asks to see the view from a seat, so it stays out of the bytes\n * every buyer downloads to look at a seat map.\n *\n * Its own chunk rather than a fold into the 3D one: the 2D \"View from here\"\n * button does not enter 3D, so folding would make that tap pull the whole OGL\n * scene — 74 KB gzipped, unrunnable without WebGL2 — to draw a 2D canvas.\n *\n * On npm and in the vendored app copy this is a dynamic import of a module the\n * widget ALREADY imports statically, so every bundler resolves it out of the\n * chunk that is loaded anyway: same bytes, same behaviour, no extra request.\n */\nasync function loadPanorama(): Promise<PanoramaModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-panorama.mjs')) as Promise<PanoramaModule>;\n }\n return import('@seatlayer/core');\n}\n\n/** Just the mount function, so the type does not drag the module's DOM in. */\ntype HostedCheckoutModule = Pick<typeof import('./hostedCheckout'), 'mountCheckout'>;\n\n/**\n * Dynamically load the hosted-checkout card, on the same pattern as\n * {@link loadVenue3d} and {@link loadPanorama}, and for a stronger reason than\n * either: this is payment UI, and the overwhelming majority of buyers who load\n * a seat map never reach it. Most integrations never enable it at all —\n * `checkout` defaults to `'handoff'`, where these bytes are unreachable code.\n *\n * So there are ZERO payment bytes on the wire until a buyer presses the CTA in\n * a picker whose host opted into `checkout: 'hosted'`. Unlike the panorama\n * chunk, `./hostedCheckout` is NOT imported statically anywhere, so on npm this\n * is a genuine code split rather than a free reference into a module that was\n * loading anyway — which is exactly what we want here.\n */\nasync function loadHostedCheckout(): Promise<HostedCheckoutModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-checkout.mjs')) as Promise<HostedCheckoutModule>;\n }\n return import('./hostedCheckout');\n}\n\n/**\n * Read the wire's reason, failing to the least-accusing one.\n *\n * Anything unrecognised — a failed read, an older worker that sent nothing, a\n * newer one naming a reason this build has never heard of — becomes\n * `not_configured`, which asserts the least about the organizer. A story\n * invented from a missing field is worse than the coarse truth.\n */\nexport function paymentsOffReason(reason: string | null | undefined): PaymentOptionsReason {\n return reason === 'unavailable_for_event' || reason === 'payments_off_for_event'\n ? reason\n : 'not_configured';\n}\n\n/**\n * Widget stylesheet — injected once per document. Every color/font/radius is a\n * --sl-* token.\n *\n * The `@sl-css` marker opts this literal into build-time CSS minification (see\n * cdn/minifyCssLiterals.ts). Keep writing it long-hand and commented: the CDN\n * build strips the comments and the indentation, the source keeps them.\n */\nconst STYLE_ID = 'seatlayer-picker-style';\nconst CSS = /* @sl-css */ `\n.sl-picker{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:420px;overflow:hidden;\n background:var(--sl-bg);color:var(--sl-text);font-family:var(--sl-font);border-radius:var(--sl-radius);\n --sl-r-sm:calc(var(--sl-radius) * .55);\n /* Motion tokens, defined ON the widget root so an embed is self-contained and\n never inherits (or fights) the host page's own timing. Values mirror\n docs/motion-system-2026-08-01.md §2. */\n --slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;\n --slm-mo-out:cubic-bezier(0.2,0.8,0.2,1);--slm-mo-exit:cubic-bezier(0.4,0,1,1)}\n.sl-picker *{box-sizing:border-box;margin:0;padding:0}\n.sl-picker button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}\n\n/* header */\n.sl-head{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--sl-line);flex:none}\n.sl-logo{width:34px;height:34px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:800;font-size:15px;overflow:hidden}\n.sl-logo img{width:100%;height:100%;object-fit:cover;display:block}\n.sl-head-info{min-width:0;flex:1}\n.sl-head-name{font-weight:700;font-size:15px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-head-meta{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);margin-top:3px;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-hold-pill{display:none;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;flex:none;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:700;font-size:12px;font-variant-numeric:tabular-nums;\n transform-origin:right center}\n.sl-hold-pill.on{display:inline-flex;animation:slPillIn .34s cubic-bezier(.2,.8,.2,1) both}\n.sl-hold-dot{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.78;box-shadow:0 0 0 0 currentColor}\n.sl-hold-pill.is-expiring .sl-hold-dot{animation:slHoldPulse 1.4s ease-out infinite}\n.sl-hold-time{min-width:3.35em;text-align:left}\n.sl-close{width:32px;height:32px;border-radius:999px;flex:none;display:none;align-items:center;justify-content:center;\n border:1px solid var(--sl-line);color:var(--sl-muted);transition:color .15s,border-color .15s}\n.sl-close:hover{color:var(--sl-text);border-color:var(--sl-muted)}\n.sl-close.on{display:inline-flex}\n.sl-close svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}\n\n/* A page or popup may already own the event heading. In that case only the\n duplicate identity disappears; operational header controls stay available.\n Zero block padding lets an otherwise-empty header collapse completely. */\n.sl-picker[data-event-details-hidden=\"true\"] .sl-head{padding-block:0;border-bottom-width:0}\n.sl-picker[data-event-details-hidden=\"true\"] .sl-logo,\n.sl-picker[data-event-details-hidden=\"true\"] .sl-head-info{display:none!important}\n.sl-picker[data-event-details-hidden=\"true\"] .sl-hold-pill.on,\n.sl-picker[data-event-details-hidden=\"true\"] .sl-closed-pill.on,\n.sl-picker[data-event-details-hidden=\"true\"] .sl-close.on{margin-block:10px}\n\n/* body */\n.sl-body{display:flex;flex:1;min-height:0}\n.sl-map{position:relative;flex:1;min-width:0}\n.sl-map-host{position:absolute;inset:0}\n.sl-side{width:300px;flex:none;border-left:1px solid var(--sl-line);display:flex;flex-direction:column;min-height:0;overflow:hidden}\n\n/* narrow (container < 640px): map-first — the map claims ~80-85% of the\n container and the side panel becomes a PEEKING bottom sheet (AXS/Ticketmaster\n mobile pattern). data-sheet on the root: \"peek\" (default: grab handle + one\n summary line) / \"open\" (room for rows + checkout, swipe up to open).\n Swipe handling lives on the sheet head ONLY — never the map host, so the\n map's raw-pointer gesture pipeline is untouched. */\n.sl-picker[data-layout=\"narrow\"] .sl-body{flex-direction:column}\n.sl-picker[data-layout=\"narrow\"] .sl-map{min-height:0;flex:1}\n.sl-picker[data-layout=\"narrow\"] .sl-side{width:100%;border-left:0;border-top:1px solid var(--sl-line);\n flex:none;height:min(72%,480px);overflow:hidden;transition:height .3s cubic-bezier(.2,.8,.2,1);overscroll-behavior:contain}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"][data-has-selection=\"false\"] .sl-side{height:min(252px,52%)}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-side{height:76px;overflow:hidden}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-side > :not(.sl-sheet-head){display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-tray{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}\n.sl-picker[data-layout=\"narrow\"] .sl-foot{position:static;background:var(--sl-bg)}\n.sl-picker[data-layout=\"narrow\"] .sl-foot.empty{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-sheet-head{order:0}\n.sl-picker[data-layout=\"narrow\"] .sl-seats-sec{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-tray{order:2}\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec{order:3}\n.sl-picker[data-layout=\"narrow\"] .sl-filters{order:4}\n.sl-picker[data-layout=\"narrow\"] .sl-prices-sec{order:5}\n.sl-picker[data-layout=\"narrow\"] .sl-pricef{order:6}\n.sl-picker[data-layout=\"narrow\"] .sl-prices{order:7}\n.sl-picker[data-layout=\"narrow\"] .sl-foot{order:8}\n.sl-picker[data-layout=\"narrow\"] .sl-tray-hint,\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec,\n.sl-picker[data-layout=\"narrow\"] .sl-filters,\n.sl-picker[data-layout=\"narrow\"] .sl-prices-sec,\n.sl-picker[data-layout=\"narrow\"] .sl-prices{display:none!important}\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filtersec,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filters,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-prices-sec{display:none}\n/* Reclaim the bottom sheet once the cart has anything: the \"Find best seats\"\n panel collapses too. EXCEPT the confirm (\"Replace your current choices?\") and\n in-flight busy states, which legitimately show with a non-empty cart — those\n set data-ba-active=\"true\" (see setAttribute alongside data-has-selection). */\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"]:not([data-ba-active=\"true\"]) .sl-ba{display:none}\n/* touch chrome: pinch-zoom exists — hide +/− on the sheet layout (keep fit) */\n.sl-picker[data-layout=\"narrow\"] .sl-zoom [data-ref=\"zin\"],\n.sl-picker[data-layout=\"narrow\"] .sl-zoom [data-ref=\"zout\"]{display:none}\n\n/* bottom-sheet head: grab handle + one-line summary (narrow only). The WHOLE\n head is the tap/swipe toggle target (min 44px), so it reads as one control. */\n.sl-sheet-head{display:none;flex-direction:column;justify-content:center;padding:6px 12px 8px;min-height:56px;\n cursor:pointer;touch-action:none;user-select:none;-webkit-user-select:none;flex:none}\n.sl-picker[data-layout=\"narrow\"] .sl-sheet-head{display:flex;min-height:64px;padding:4px 10px 6px}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-sheet-head{height:100%}\n.sl-sheet-grab{width:36px;height:4px;border-radius:999px;background:var(--sl-muted);opacity:.55;margin:1px auto 5px}\n.sl-sheet-bar{display:flex;align-items:center;gap:8px;min-height:44px}\n.sl-sheet-peek{display:flex;align-items:center;gap:7px;flex:1;min-width:0;font-size:13px;font-weight:700;color:var(--sl-text);\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-sheet-peek .sub{color:var(--sl-muted);font-weight:600}\n/* collapsed-peek \"Continue\" affordance: a real accent pill, not plain text */\n.sl-sheet-peek .go{margin-left:auto;flex:none;display:inline-flex;align-items:center;min-height:30px;\n padding:6px 13px;border-radius:999px;background:var(--sl-accent);color:var(--sl-accent-ink);\n font-weight:800;font-size:12.5px}\n/* state chevron: points UP while peeking, rotates to point DOWN when open.\n Base keeps an explicit rotate(0) — transitioning to/from a bare 'none' leaves\n the value stuck in some engines, so both endpoints must be real transforms. */\n.sl-sheet-toggle{width:44px;height:44px;margin:-8px -8px -8px 0;border-radius:999px;flex:none;display:flex;\n align-items:center;justify-content:center;color:var(--sl-muted);transition:color .15s,background .15s}\n.sl-sheet-toggle:hover,.sl-sheet-toggle:focus-visible{color:var(--sl-text);background:color-mix(in srgb,var(--sl-line) 44%,transparent)}\n.sl-sheet-toggle svg{width:21px;height:21px;stroke:currentColor;stroke-width:2.4;fill:none;\n stroke-linecap:round;stroke-linejoin:round}\n.sl-sheet-toggle svg{transform:rotate(0deg);transition:transform .24s cubic-bezier(.2,.8,.2,1)}\n.sl-picker[data-sheet=\"open\"] .sl-sheet-toggle svg{transform:rotate(180deg)}\n\n/* consolidated Filters row inside the sheet (a11y chips + colorblind toggle\n dock here on narrow; they live on the map / zoom column on wide) */\n.sl-filtersec{display:none}\n.sl-filters{display:none;gap:6px;flex-wrap:wrap;align-items:center;padding:2px 16px 10px}\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec.has,\n.sl-picker[data-layout=\"narrow\"] .sl-filters.has{display:none}\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filtersec.has,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filters.has{display:none}\n/* Accessibility and colour-safety controls must remain reachable on phones.\n Keep them out of the collapsed peek, then reveal their consolidated row whenever\n the buyer explicitly opens the ticket panel. */\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-filtersec.has{display:block!important}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-filters.has{display:flex!important}\n.sl-cbbtn{width:32px;height:32px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-cbbtn:hover{border-color:var(--sl-muted)}\n.sl-cbbtn svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* price panel — one compact filter control replaces the wrapping price-chip row. */\n.sl-offer{display:none;margin:12px 14px 2px;padding:12px;border:1px solid color-mix(in srgb,var(--sl-accent) 34%,var(--sl-line));\n border-radius:12px;background:color-mix(in srgb,var(--sl-accent) 8%,var(--sl-surface));color:var(--sl-text)}\n.sl-offer.has{display:block}.sl-offer-main{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}\n.sl-offer-copy{min-width:0}.sl-offer-kicker{display:block;font-size:9px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-accent)}\n.sl-offer-name{display:block;margin-top:2px;font-size:13px;font-weight:800;line-height:1.3}.sl-offer-line{display:block;margin-top:3px;font-size:11px;line-height:1.35;color:var(--sl-muted)}\n.sl-offer-info{position:relative;flex:none}.sl-offer-info>summary{list-style:none;width:25px;height:25px;border:1px solid var(--sl-line);border-radius:999px;\n display:grid;place-items:center;cursor:pointer;font-size:12px;font-weight:850;color:var(--sl-text);background:var(--sl-surface)}\n.sl-offer-info>summary::-webkit-details-marker{display:none}.sl-offer-info[open]>summary{border-color:var(--sl-accent);color:var(--sl-accent)}\n.sl-offer-detail{margin-top:10px;padding-top:9px;border-top:1px solid var(--sl-line);font-size:10.5px;line-height:1.45;color:var(--sl-muted)}\n.sl-sec{padding:14px 14px 4px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}\n.sl-prices-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}\n.sl-price-select{min-height:32px;max-width:130px;padding:5px 28px 5px 9px;border:1px solid var(--sl-line);border-radius:9px;\n background:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}\n.sl-prices{display:flex;flex-direction:column;padding:4px 14px 8px;border-bottom:1px solid var(--sl-line)}\n.sl-prices-sec,.sl-prices,.sl-seats-sec{flex:none}\n.sl-price-row{display:flex;align-items:center;gap:7px;min-height:28px;font-size:12px;\n padding:0 6px;margin:0 -6px;border-radius:8px;cursor:pointer;transition:background .15s}\n.sl-price-row:hover,.sl-price-row:focus-visible{background:color-mix(in srgb,var(--sl-line) 40%,transparent)}\n.sl-price-row.sl-active{background:color-mix(in srgb,var(--sl-accent) 9%,transparent)}\n.sl-price-was{margin-left:auto;color:var(--sl-muted);font-size:10px;text-decoration:line-through}.sl-price-offer{display:block;color:var(--sl-accent);font-size:9px;font-weight:750}\n.sl-price-row.sl-active .sl-price-label{color:var(--sl-accent)}\n.sl-dot{width:9px;height:9px;border-radius:50%;flex:none}\n.sl-price-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-price-left{font-size:11px;color:var(--sl-muted);font-variant-numeric:tabular-nums}\n.sl-price-amt{font-weight:800;font-variant-numeric:tabular-nums}\n/* long category lists: capped by default, scroll once expanded */\n.sl-prices.sl-expanded{max-height:196px;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}\n.sl-price-more{display:flex;align-items:center;min-height:26px;padding:0;\n color:var(--sl-muted);font-size:11px;font-weight:750;transition:color .15s}\n.sl-price-more:hover,.sl-price-more:focus-visible{color:var(--sl-text)}\n/* held/sold key — one quiet caption line; the map itself teaches these states */\n.sl-status-key{display:flex;gap:11px;flex-wrap:wrap;padding:5px 0 0;margin-top:4px;border-top:1px solid var(--sl-line);color:var(--sl-muted);font-size:10px}\n.sl-status-item{display:inline-flex;align-items:center;gap:5px}\n.sl-status-icon{width:13px;height:13px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;\n color:#fff;background:#6b7280;line-height:1}\n.sl-status-icon svg{width:8px;height:8px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-status-icon.sold{background:#8b93a0}\n.sl-status-icon.sold svg{width:9px;height:9px;stroke-width:2.4}\n\n/* tray */\n.sl-seats-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}\n.sl-seat-summary{font-size:10px;letter-spacing:0;text-transform:none;white-space:nowrap}\n.sl-tray{flex:1;padding:10px 14px 14px;display:flex;flex-direction:column;gap:7px;min-height:0;overflow-y:auto;\n overscroll-behavior:contain;scrollbar-gutter:stable}\n.sl-tray-hint{font-size:12.5px;color:var(--sl-muted);line-height:1.5}\n.sl-chip{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 34px;align-items:stretch;\n flex:none;min-height:53px;border:1px solid var(--sl-line);border-radius:var(--sl-r-sm);overflow:hidden;\n background:var(--sl-surface);font-size:13px;transform-origin:center;transition:border-color .15s,background .15s}\n.sl-chip:hover{border-color:color-mix(in srgb,var(--sl-accent) 38%,var(--sl-line))}\n.sl-chip.sl-enter{animation:slChipIn .38s cubic-bezier(.2,.8,.2,1) both}\n.sl-chip.sl-leave{pointer-events:none;animation:slChipOut .16s ease-in both}\n.sl-chip.sl-held{border-color:var(--sl-line);background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface));\n box-shadow:inset 3px 0 0 color-mix(in srgb,var(--sl-accent) 72%,transparent)}\n.sl-ticket-state{width:17px;height:17px;border-radius:999px;flex:none;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-ticket-state.held{background:color-mix(in srgb,var(--sl-accent) 18%,var(--sl-surface));color:var(--sl-accent)}\n.sl-ticket-state svg{width:10px;height:10px;stroke:currentColor;stroke-width:2.6;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-chip-main{min-width:0;padding:8px 10px 8px 11px;display:flex;flex-direction:column;justify-content:center;gap:5px}\n.sl-chip-id{display:flex;gap:12px;min-width:0}\n.sl-chip-id .fld{min-width:0}\n.sl-chip-id .fld.sec{flex:1}\n.sl-chip-id .fld.mid{flex:none;text-align:center}\n.sl-chip-eb{display:block;font-size:8px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);margin-bottom:1px}\n.sl-chip-id .val{display:block;font-weight:600;font-size:13px;line-height:1.25;white-space:nowrap}\n.sl-chip-id .fld.sec .val{overflow:hidden;text-overflow:ellipsis}\n.sl-chip-sub{display:flex;align-items:center;gap:6px;min-width:0}\n.sl-chip .cat{color:var(--sl-muted);font-size:10.5px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-chip .amt{font-weight:700;font-variant-numeric:tabular-nums;flex:none;white-space:nowrap}\n.sl-chip-rail{display:flex;flex-direction:column;border-left:1px solid var(--sl-line)}\n.sl-chip .rm,.sl-chip .view{flex:1;min-height:26px;border-radius:0;display:flex;align-items:center;justify-content:center;\n color:var(--sl-muted);transition:color .15s,background .15s}\n.sl-chip .view{border-top:1px solid var(--sl-line)}\n.sl-chip .rm:hover,.sl-chip .rm:focus-visible{color:#e5484d;background:color-mix(in srgb,#e5484d 9%,transparent)}\n.sl-chip .view:hover,.sl-chip .view:focus-visible{color:var(--sl-text);background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n.sl-chip .rm svg{width:11px;height:11px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round}\n.sl-chip .view svg{width:13px;height:13px;stroke:currentColor;stroke-width:1.8;fill:none}\n/* live-activity strip — narrates WS availability deltas (social proof + urgency).\n Hidden until a delta actually happens: a static \"seats update in real time\"\n banner is dead vertical space, a \"2 seats just taken\" flash is a signal. */\n.sl-live{display:none;align-items:center;gap:7px;margin:10px 14px 0;padding:7px 9px;flex:none;\n border:1px solid var(--sl-line);border-radius:8px;background:color-mix(in srgb,var(--sl-accent) 4%,var(--sl-surface));\n font-size:11px;color:var(--sl-muted)}\n.sl-live .dot{width:6px;height:6px;border-radius:999px;background:#22a06b;box-shadow:0 0 6px rgba(34,160,107,.75);flex:none}\n.sl-live span:last-child{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-live.on{display:flex;animation:slNoticeIn .38s cubic-bezier(.2,.8,.2,1) both}\n\n/* GA rows */\n.sl-ga{display:flex;align-items:center;gap:10px;padding:9px 11px;border:1px dashed var(--sl-line);border-radius:var(--sl-r-sm)}\n.sl-ga-info{flex:1;min-width:0}\n.sl-ga-name{font-weight:700;font-size:13px}\n.sl-ga-sub{font-size:11px;color:var(--sl-muted);margin-top:2px}\n.sl-ga-qty{display:flex;align-items:center;gap:8px}\n.sl-ga-qty button{width:26px;height:26px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n font-size:15px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-ga-qty button:hover{border-color:var(--sl-muted)}\n.sl-ga-qty span{min-width:16px;text-align:center;font-weight:800;font-variant-numeric:tabular-nums}\n\n/* footer */\n.sl-foot{position:relative;z-index:2;padding:12px 16px 14px;border-top:1px solid var(--sl-line);flex:none;\n background:var(--sl-bg);box-shadow:0 -10px 24px -22px rgba(0,0,0,.72)}\n.sl-hold-note{display:none;align-items:center;gap:7px;margin-bottom:8px;padding:7px 8px;border-radius:var(--sl-r-sm);\n border:1px solid var(--sl-line);background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface));\n box-shadow:inset 3px 0 0 color-mix(in srgb,var(--sl-accent) 72%,transparent);\n font-size:11.5px;line-height:1.35;color:var(--sl-muted)}\n.sl-hold-note.on{display:flex;animation:slNoticeIn .38s cubic-bezier(.2,.8,.2,1) both}\n.sl-hold-note svg{width:16px;height:16px;flex:none;stroke:var(--sl-accent);stroke-width:2.4;fill:none;\n stroke-linecap:round;stroke-linejoin:round}\n.sl-hold-note b{display:block;color:var(--sl-text);font-size:11.5px;white-space:nowrap}\n.sl-hold-copy{display:block;white-space:nowrap;font-size:10.5px}\n.sl-hold-note>span{flex:1;min-width:0}\n.sl-hold-change{flex:none;min-height:30px;padding:5px 8px;border-radius:8px;border:1px solid var(--sl-line);\n color:var(--sl-text);font-size:10.5px;font-weight:750;white-space:nowrap}\n.sl-hold-change:hover,.sl-hold-change:focus-visible{border-color:var(--sl-accent);color:var(--sl-accent)}\n.sl-hold-change:disabled{opacity:.58;cursor:wait}\n.sl-total{display:flex;justify-content:space-between;align-items:center;font-size:13px;margin-bottom:10px}\n.sl-total b{font-size:17px;font-variant-numeric:tabular-nums}\n.sl-value-pop{animation:slValuePop .32s cubic-bezier(.2,.8,.2,1)}\n/* Primary checkout CTA. Scoped under .sl-picker so it OUTWEIGHS the\n '.sl-picker button' reset (0,1,1) — an unscoped '.sl-cta' (0,1,0) loses to it\n and the button renders as plain text with no accent fill. */\n.sl-picker .sl-cta{display:flex;align-items:center;justify-content:center;width:100%;min-height:44px;\n padding:12px 16px;border-radius:var(--sl-r-sm);font-weight:800;font-size:14px;line-height:1.1;\n background:var(--sl-accent);color:var(--sl-accent-ink);\n transition:filter .15s,background .22s,color .22s,transform .12s,box-shadow .22s;gap:8px}\n.sl-picker .sl-cta:hover{filter:brightness(1.08)}\n.sl-picker .sl-cta:active{transform:translateY(1px);filter:brightness(.94)}\n.sl-picker .sl-cta.sl-ready{animation:slCtaReady .42s cubic-bezier(.2,.8,.2,1)}\n.sl-cta-spin,.sl-ba-spin{width:14px;height:14px;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;\n animation:slspin .7s linear infinite;flex:none}\n/* Disabled (\"Select seats\"): quieter, but still a full-width button shape. */\n.sl-picker .sl-cta:disabled{background:var(--sl-surface);color:var(--sl-muted);opacity:1;\n cursor:not-allowed;filter:none;transform:none}\n\n/* Chrome anchor regions (Feature 6) — every interactive map overlay is APPENDED\n INTO one of these positioned flex containers and flows/stacks within it, so no\n two controls free-float on top of each other. Regions never overlap: the top\n strip splits into left/center/right; rails + corners own their edge. */\n.sl-anchor{position:absolute;z-index:5;display:flex;align-items:center;gap:8px;pointer-events:none}\n.sl-anchor > *{pointer-events:auto}\n.sl-anchor[data-region=\"top-left\"]{top:12px;left:12px;flex-wrap:wrap;max-width:38%}\n.sl-anchor[data-region=\"top-center\"]{top:12px;left:50%;transform:translateX(-50%);flex-direction:column;\n align-items:center;max-width:44%}\n.sl-anchor[data-region=\"top-right\"]{top:12px;right:12px;justify-content:flex-end;flex-wrap:wrap;max-width:38%}\n.sl-anchor[data-region=\"left-rail\"]{top:50%;left:12px;transform:translateY(-50%);flex-direction:column;max-width:42%;gap:6px}\n.sl-anchor[data-region=\"bottom-left\"]{left:12px;bottom:12px;flex-direction:column;align-items:flex-start}\n.sl-anchor[data-region=\"bottom-center\"]{left:50%;bottom:14px;transform:translateX(-50%);z-index:9;\n flex-direction:column;align-items:center;gap:8px;max-width:92%}\n.sl-anchor[data-region=\"bottom-right\"]{right:12px;bottom:12px;flex-direction:column;align-items:flex-end;gap:6px}\n/* narrow: tighten the top strip so left/center can't crowd each other */\n.sl-picker[data-layout=\"narrow\"] .sl-anchor[data-region=\"top-left\"]{max-width:30%}\n.sl-picker[data-layout=\"narrow\"] .sl-anchor[data-region=\"top-center\"]{max-width:44%}\n\n/* TEST MODE is environment context, not an action. A clipped corner ribbon\n keeps it persistent without impersonating a button or competing with Map/3D.\n The top-left interactive region moves below it only on test events. */\n.sl-testbadge{position:absolute;top:17px;left:-38px;z-index:6;width:142px;padding:5px 0;\n transform:rotate(-45deg);text-align:center;pointer-events:none;\n font-size:9.5px;font-weight:850;letter-spacing:.13em;line-height:1.2;text-transform:uppercase;\n white-space:nowrap;background:var(--sl-accent);color:var(--sl-accent-ink);\n box-shadow:0 2px 8px rgba(0,0,0,.28)}\n.sl-picker[data-event-mode=\"test\"] .sl-anchor[data-region=\"top-left\"]{top:96px}\n.sl-picker[data-layout=\"narrow\"] .sl-testbadge{top:14px;left:-35px;width:128px;font-size:8.5px}\n.sl-picker[data-layout=\"narrow\"][data-event-mode=\"test\"] .sl-anchor[data-region=\"top-left\"]{top:88px}\n\n/* zoom column (flows within the bottom-right region) */\n.sl-zoom{display:flex;flex-direction:column;gap:6px}\n/* CSS-fallback full screen (iOS Safari has no element fullscreen API) */\n.sl-picker.sl-fs{position:fixed;inset:0;z-index:2147483000;width:auto;height:auto;max-height:none;border-radius:0}\n.sl-zoom button{width:36px;height:36px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-zoom button:hover{border-color:var(--sl-muted)}\n.sl-zoom svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* toast + boot states (toast flows in the bottom-center region) */\n.sl-toast{transform:translateY(6px) scale(.98);max-width:100%;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);border-radius:999px;padding:9px 16px;\n font-size:12.5px;font-weight:600;opacity:0;pointer-events:none;transition:opacity .22s,transform .22s;white-space:nowrap;\n overflow:hidden;text-overflow:ellipsis}\n.sl-toast.on{opacity:1;transform:translateY(0) scale(1)}\n.sl-toast.has-action{pointer-events:auto;display:flex;align-items:center;gap:12px;padding-right:8px}\n.sl-toast-action{min-height:30px;padding:5px 10px;border-radius:999px;background:var(--sl-accent);color:var(--sl-accent-ink);\n font:inherit;font-weight:800}\n.sl-toast[data-tone=\"error\"]{border-color:#ef4444}\n.sl-toast[data-tone=\"warning\"]{border-color:var(--sl-accent)}\n.sl-toast[data-tone=\"success\"]{border-color:#22c55e}\n.sl-toast.on[data-tone=\"error\"]{animation:slToastNudge .32s ease-out}\n.sl-boot{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;\n gap:10px;background:var(--sl-bg);font-size:13px;font-weight:600;color:var(--sl-muted)}\n.sl-boot-spin{width:24px;height:24px;border-radius:50%;border:3px solid var(--sl-line);border-top-color:var(--sl-accent);\n animation:slspin .8s linear infinite}\n@keyframes slspin{to{transform:rotate(360deg)}}\n.sl-boot-title{font-weight:800;font-size:15px;color:var(--sl-text)}\n.sl-boot-retry{margin-top:4px;padding:9px 20px;border-radius:var(--sl-r-sm);background:var(--sl-accent);\n color:var(--sl-accent-ink);font-weight:700;font-size:13px}\n\n/* \"Need more time?\" extend prompt (flows in the bottom-center region, above the toast) */\n.sl-extend{transform:translateY(6px);\n display:none;align-items:center;gap:12px;max-width:100%;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);border-radius:14px;padding:10px 12px 10px 16px;box-shadow:0 18px 50px -18px rgba(0,0,0,.6);\n opacity:0;transition:opacity .2s,transform .2s}\n.sl-extend.on{display:flex;opacity:1;transform:translateY(0)}\n.sl-extend-txt{font-size:12.5px;font-weight:600;line-height:1.35}\n.sl-extend-txt b{font-variant-numeric:tabular-nums}\n.sl-extend-btn{flex:none;padding:8px 14px;border-radius:999px;font-weight:800;font-size:12.5px;\n background:var(--sl-accent);color:var(--sl-accent-ink);transition:filter .15s,opacity .15s}\n.sl-extend-btn:hover{filter:brightness(1.08)}\n.sl-extend-btn:disabled{opacity:.5;cursor:not-allowed}\n\n/* booked confirmation overlay (covers the widget once the held seats are sold) */\n.sl-booked{position:absolute;inset:0;z-index:11;display:flex;flex-direction:column;align-items:center;\n justify-content:center;gap:12px;text-align:center;padding:28px;background:var(--sl-bg);opacity:0;visibility:hidden;\n pointer-events:none;transition:opacity .34s ease,visibility 0s linear .34s}\n.sl-booked.on{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .34s ease,visibility 0s}\n.sl-booked-badge{width:60px;height:60px;border-radius:999px;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink);transform:scale(.72)}\n.sl-booked.on .sl-booked-badge{animation:slSuccessPop .58s cubic-bezier(.2,1.25,.3,1) .08s both}\n.sl-booked-badge svg{width:30px;height:30px;stroke:currentColor;stroke-width:2.6;fill:none;stroke-linecap:round;stroke-linejoin:round;\n stroke-dasharray:30;stroke-dashoffset:30}\n.sl-booked.on .sl-booked-badge svg{animation:slCheckDraw .42s ease-out .32s forwards}\n.sl-booked-title{font-weight:800;font-size:19px;color:var(--sl-text)}\n.sl-booked-sub{font-size:13px;color:var(--sl-muted);line-height:1.5;max-width:320px}\n.sl-booked-seats{font-weight:700;color:var(--sl-text)}\n.sl-booked.on .sl-booked-title,.sl-booked.on .sl-booked-sub{animation:slCopyRise .42s ease-out both}\n.sl-booked.on .sl-booked-title{animation-delay:.22s}\n.sl-booked.on .sl-booked-sub{animation-delay:.3s}\n\n/* sold-out overlay — every SEATED category's live availability is 0. This is\n informational only: no waitlist workflow exists. Suppressed when GA areas\n exist (GA capacity isn't seat-counted). Clears live when WS frees a seat. */\n.sl-soldout{position:absolute;inset:0;z-index:10;display:none;flex-direction:column;align-items:center;\n justify-content:center;text-align:center;gap:8px;padding:24px;\n background:color-mix(in srgb,var(--sl-bg) 82%,transparent);backdrop-filter:blur(4px)}\n.sl-soldout.on{display:flex}\n.sl-soldout-eyebrow{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--sl-accent);font-weight:800}\n.sl-soldout-title{font-size:32px;font-weight:800;color:var(--sl-text);line-height:1.05}\n.sl-soldout-copy{max-width:360px;font-size:13px;color:var(--sl-muted);line-height:1.5}\n\n/* sales-closed pill (header) — persistent read-only state when the event's sales\n window is closed at load or closes live mid-session. Neutral (not accent) so it\n reads as \"unavailable\", distinct from the accent hold pill next to it. */\n.sl-closed-pill{display:none;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;flex:none;\n background:color-mix(in srgb,var(--sl-text) 12%,var(--sl-surface));color:var(--sl-text);\n font-weight:700;font-size:12px;white-space:nowrap}\n.sl-closed-pill.on{display:inline-flex}\n.sl-closed-pill svg{width:13px;height:13px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* \"Powered by SeatLayer\" attribution badge (side-panel foot) — the canonical\n Layered Rows mark + wordmark. Hidden when the host opts out or the org's paid\n theme sets hideBadge. */\n.sl-powered{display:flex;align-items:center;justify-content:center;gap:6px;margin-top:10px;\n font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--sl-text);opacity:.72;\n text-decoration:none;padding:6px 10px;border-radius:999px;width:fit-content;margin-inline:auto;\n transition:opacity .15s ease,background-color .15s ease}\n.sl-powered:hover{opacity:1;background:color-mix(in srgb,var(--sl-text) 8%,transparent)}\n.sl-powered:focus-visible{opacity:1;outline:2px solid var(--sl-accent);outline-offset:2px}\n.sl-powered-mark{width:16px;height:16px;border-radius:4px;flex:none;display:flex;align-items:center;justify-content:center;\n background:#0c1220;color:#fcf7ee}\n.sl-powered-mark svg{width:12px;height:11px}\n\n/* a11y filter chips (flow within the top-left region) */\n.sl-chips{display:flex;gap:6px;flex-wrap:wrap}\n.sl-chip-f{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:999px;font-size:12px;font-weight:700;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted);transition:color .15s,border-color .15s}\n.sl-chip-f:hover{color:var(--sl-text)}\n.sl-chip-f.on{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n\n/* confirm card: a candidate is not in the tray until Select. Map gestures and\n floating chrome pause while the card owns focus, keeping the camera stable. */\n.sl-picker[data-confirming=\"true\"] .sl-map-host>:not(.sl-confirm){pointer-events:none}\n.sl-picker[data-confirming=\"true\"] .sl-anchor{pointer-events:none;opacity:.28;transition:opacity .16s}\n.sl-picker[data-confirming=\"true\"] .sl-side{pointer-events:none;opacity:.58;transition:opacity .16s}\n.sl-confirm{position:absolute;z-index:10;width:276px;max-width:calc(100% - 24px);overflow:hidden;pointer-events:auto;\n background:var(--sl-surface);border:1px solid color-mix(in srgb,var(--sl-line) 70%,var(--sl-text));\n border-radius:15px;box-shadow:0 24px 64px -18px rgba(0,0,0,.72);transform:translate(-50%,calc(-100% - 16px));\n animation:slConfirmIn .24s cubic-bezier(.2,.8,.2,1) both}\n.sl-confirm[data-placement=\"below\"]{transform:translate(-50%,16px);animation:slConfirmBelowIn .24s cubic-bezier(.2,.8,.2,1) both}\n.sl-confirm-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(52px,auto) minmax(52px,auto);border-bottom:1px solid var(--sl-line)}\n.sl-confirm-field{min-width:0;padding:12px 11px 10px;border-right:1px solid var(--sl-line)}\n.sl-confirm-field:last-child{border-right:0;text-align:center}\n.sl-confirm-field:nth-child(2){text-align:center}\n.sl-confirm-key{display:block;font-size:8.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-confirm-value{display:block;margin-top:4px;color:var(--sl-text);font-size:17px;line-height:1.1;font-weight:850;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n/* Long venue section names must read in full: smaller type + up to two lines\n beats an ellipsis at identity-confirmation time. Row/seat stay big — they're\n short and they're what the buyer double-checks against the map. */\n.sl-confirm-field:first-child .sl-confirm-value{font-size:13.5px;line-height:1.25;white-space:normal;\n display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}\n.sl-confirm-cat{display:flex;align-items:center;gap:8px;padding:10px 12px;background:color-mix(in srgb,var(--sl-cat) 76%,var(--sl-surface))}\n.sl-confirm-cat .sl-dot{border:2px solid rgba(255,255,255,.78);width:11px;height:11px}\n.sl-confirm-cat-name{font-size:13.5px;font-weight:800;color:#fff;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-confirm-price{font-size:17px;font-weight:850;color:#fff;font-variant-numeric:tabular-nums}\n.sl-confirm-body{padding:11px 12px 12px}\n.sl-confirm-row{display:flex;gap:8px;margin-top:10px}\n.sl-confirm-row button{flex:1;min-height:44px;padding:9px 12px;border-radius:9px;font-weight:800;font-size:13px}\n.sl-confirm-add{background:var(--sl-accent)!important;color:var(--sl-accent-ink)!important;display:flex;align-items:center;justify-content:center;gap:7px}\n.sl-confirm-add svg{width:16px;height:16px;stroke:currentColor;stroke-width:2.8;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-confirm-cancel{background:color-mix(in srgb,var(--sl-line) 44%,transparent)!important;border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}\n.sl-confirm-cancel:hover{color:var(--sl-text)}\n.sl-picker[data-layout=\"narrow\"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(342px,calc(100% - 24px));\n transform:translateX(-50%);animation:slConfirmMobileIn .24s cubic-bezier(.2,.8,.2,1) both}\n\n/* Atomic whole/variable-table chooser. Lives inside the widget so the same\n accessible dialog works in inline, modal, desktop and 390px mobile hosts. */\n.sl-table-scrim{position:absolute;inset:0;z-index:45;display:flex;align-items:center;justify-content:center;padding:18px;\n background:color-mix(in srgb,var(--sl-bg) 66%,transparent);backdrop-filter:blur(3px)}\n.sl-table-dialog{width:min(408px,100%);max-height:calc(100% - 24px);overflow:auto;border:1px solid var(--sl-line);\n border-radius:calc(var(--sl-radius) * 1.15);background:var(--sl-surface);box-shadow:0 28px 70px rgba(0,0,0,.42)}\n.sl-table-head{padding:18px 18px 14px;border-bottom:1px solid var(--sl-line)}\n.sl-table-eyebrow{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-table-title{margin-top:5px;font-size:22px;line-height:1.15;font-weight:850}\n.sl-table-copy{margin-top:7px;color:var(--sl-muted);font-size:13px;line-height:1.45}\n.sl-table-body{padding:16px 18px 18px}\n.sl-table-summary{display:grid;grid-template-columns:1fr auto;gap:8px 16px;padding:12px;border:1px solid var(--sl-line);\n border-radius:var(--sl-r-sm);background:color-mix(in srgb,var(--sl-line) 22%,transparent);font-size:13px}\n.sl-table-summary b{font-size:15px}.sl-table-summary .muted{color:var(--sl-muted)}\n.sl-table-qtylabel{display:block;margin:16px 0 8px;font-size:12px;font-weight:800}\n.sl-table-stepper{display:grid;grid-template-columns:48px 1fr 48px;align-items:center;border:1px solid var(--sl-line);\n border-radius:12px;overflow:hidden;background:var(--sl-bg)}\n.sl-table-stepper button{height:48px;font-size:24px;font-weight:700;background:color-mix(in srgb,var(--sl-line) 34%,transparent)!important}\n.sl-table-stepper button:disabled{opacity:.38;cursor:not-allowed}\n.sl-table-stepper output{text-align:center;font-size:19px;font-weight:850;font-variant-numeric:tabular-nums}\n.sl-table-range{margin-top:7px;color:var(--sl-muted);font-size:11px;text-align:center}\n.sl-table-actions{display:flex;gap:9px;margin-top:17px}.sl-table-actions button{flex:1;min-height:46px;border-radius:10px;font-weight:800}\n.sl-table-cancel{border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}\n.sl-table-confirm{background:var(--sl-accent)!important;color:var(--sl-accent-ink)!important}\n.sl-table-confirm:disabled{opacity:.62;cursor:wait}\n.sl-table-edit{margin-left:4px;padding:2px 7px!important;border:1px solid var(--sl-line)!important;border-radius:999px!important;\n color:var(--sl-muted)!important;font-size:10px!important;font-weight:800!important}\n.sl-picker[data-layout=\"narrow\"] .sl-table-scrim{align-items:flex-end;padding:0;background:rgba(5,7,12,.58)}\n.sl-picker[data-layout=\"narrow\"] .sl-table-dialog{width:100%;max-height:min(78%,620px);border-radius:18px 18px 0 0;border-width:1px 0 0}\n.sl-picker[data-layout=\"narrow\"] .sl-table-head{padding-top:22px}.sl-picker[data-layout=\"narrow\"] .sl-table-body{padding-bottom:max(20px,env(safe-area-inset-bottom))}\n\n/* hover preview — a COMPACT echo of the confirm card (deliberately smaller: it's\n a passing preview on hover, not the click/select action surface). Reuses the\n Section·Row·Seat identity grid so hover, confirm and the cart chip all share\n one visual language, just at three sizes. */\n.sl-tip{position:absolute;z-index:7;pointer-events:none;display:none;width:190px;overflow:hidden;\n background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:11px;\n box-shadow:0 12px 30px -14px rgba(0,0,0,.6)}\n.sl-tip-grid{display:grid;grid-template-columns:1.3fr .85fr .85fr;border-bottom:1px solid var(--sl-line)}\n.sl-tip-grid.one{grid-template-columns:1fr}\n.sl-tip-field{min-width:0;padding:6px 9px;border-right:1px solid var(--sl-line)}\n.sl-tip-field:last-child{border-right:0;text-align:center}\n.sl-tip-grid:not(.one) .sl-tip-field:nth-child(2){text-align:center}\n.sl-tip-key{display:block;font-size:7.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-tip-val{display:block;margin-top:2px;color:var(--sl-text);font-size:13px;line-height:1.1;font-weight:750;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-tip-cat{display:flex;align-items:center;gap:7px;padding:6px 10px;font-size:11px;\n background:color-mix(in srgb,var(--sl-cat) 12%,var(--sl-surface))}\n.sl-tip-dot{width:8px;height:8px;border-radius:50%;flex:none}\n.sl-tip-name{color:var(--sl-muted);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-tip-amt{margin-left:auto;font-weight:800;color:var(--sl-text);font-variant-numeric:tabular-nums;font-size:12px}\n.sl-tip-status{padding:5px 10px 7px;font-size:8.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;color:var(--sl-muted)}\n\n/* Best available is a first-class shortcut, not an anonymous utility row. */\n.sl-ba{position:relative;flex:none;overflow:hidden;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:7px;\n padding:13px;border:1px solid color-mix(in srgb,var(--sl-accent) 34%,var(--sl-line));border-radius:13px;\n background:linear-gradient(135deg,color-mix(in srgb,var(--sl-accent) 5%,var(--sl-surface)),color-mix(in srgb,var(--sl-accent) 11%,var(--sl-surface)))}\n.sl-ba::after{content:'✦';position:absolute;right:10px;top:3px;color:color-mix(in srgb,var(--sl-accent) 20%,transparent);font-size:42px;line-height:1}\n.sl-ba-title,.sl-ba-copy,.sl-ba select,.sl-ba-qty,.sl-ba-go{position:relative;z-index:1}\n.sl-ba-title{grid-column:1/-1;display:flex;align-items:center;gap:7px;font-size:13px;font-weight:850}\n.sl-ba-title .spark{color:var(--sl-accent);font-size:16px}\n.sl-ba-copy{grid-column:1/-1;margin:-4px 0 2px 23px;color:var(--sl-muted);font-size:10.5px;line-height:1.35}\n.sl-ba-copy .narrow{display:none}\n/* \"★ Best seats\" premium quick-pick — gold accent echoing the ★ Premium pill on\n the confirm popover; deliberately distinct from the accent-toned qty/go. */\n.sl-ba-premium{position:relative;z-index:1;grid-column:1/-1;justify-self:start;display:inline-flex;align-items:center;gap:6px;\n padding:6px 12px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.02em;cursor:pointer;\n color:#c9a24b;background:color-mix(in srgb,#e8c15a 10%,var(--sl-surface));\n border:1px solid color-mix(in srgb,#e8c15a 34%,var(--sl-line));transition:filter .15s,background .15s,color .15s}\n.sl-ba-premium .star{font-size:12px;line-height:1;color:#e8c15a}\n.sl-ba-premium:hover{filter:brightness(1.05)}\n.sl-ba-premium.on{color:#1c1608;background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;\n box-shadow:0 6px 16px color-mix(in srgb,#e8c15a 26%,transparent)}\n.sl-ba-premium.on .star{color:#5a4410}\n.sl-ba select{background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;\n font:inherit;font-size:11px;padding:7px 8px;min-width:0;width:100%;max-width:none}\n.sl-ba-qty{display:flex;align-items:center;gap:7px;padding:3px;border:1px solid var(--sl-line);border-radius:9px;background:var(--sl-surface)}\n.sl-ba-qty button{width:25px;height:25px;border-radius:7px;background:color-mix(in srgb,var(--sl-line) 35%,transparent);border:0;\n font-size:14px;font-weight:800;display:flex;align-items:center;justify-content:center}\n.sl-ba-qty span{min-width:14px;text-align:center;font-weight:800}\n.sl-picker .sl-ba-go{grid-column:1/-1;width:100%;min-height:37px;padding:7px 12px;border-radius:9px;background:var(--sl-accent);\n color:var(--sl-accent-ink);font-weight:800;font-size:12px;transition:filter .15s,opacity .15s;display:flex;align-items:center;justify-content:center;gap:6px;\n box-shadow:0 8px 18px color-mix(in srgb,var(--sl-accent) 18%,transparent)}\n.sl-picker .sl-ba-go:hover{filter:brightness(1.06)}\n.sl-picker .sl-ba-go:disabled{opacity:.62;cursor:wait}\n.sl-ba-replace{grid-column:1/-1;padding:3px 0 1px}\n.sl-ba-replace b{display:block;font-size:12.5px}\n.sl-ba-replace span{display:block;margin-top:3px;color:var(--sl-muted);font-size:10.5px;line-height:1.35}\n.sl-ba-actions{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr;gap:7px}\n.sl-ba-actions button{min-height:36px;border-radius:9px;border:1px solid var(--sl-line);font-size:11.5px;font-weight:800}\n.sl-ba-actions .replace{border-color:var(--sl-accent);background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-picker[data-layout=\"narrow\"] .sl-ba{padding:9px;gap:6px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba::after{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-title{font-size:12.5px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy .wide{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy .narrow{display:inline}\n.sl-picker[data-layout=\"narrow\"] .sl-ba select{min-height:40px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-qty button{width:30px;height:30px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-go{min-height:40px}\n\n/* screen-reader live region */\n.sl-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n\n/* per-seat ticket-tier select + view-from-seat button in tray chips */\n.sl-chip .tier{background:var(--sl-bg);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:6px;\n font:inherit;font-size:10px;padding:2px 4px;min-width:0;max-width:100%;cursor:pointer}\n\n/* arena: LOD rung pills (flow within the top-center region) */\n.sl-rungs{display:none;background:var(--sl-surface);border:1px solid var(--sl-line);border-radius:999px;padding:3px}\n.sl-rungs.on{display:inline-flex;gap:2px}\n.sl-rungs button{padding:6px 13px;border-radius:999px;font-size:10.5px;font-weight:800;letter-spacing:.07em;\n color:var(--sl-muted);white-space:nowrap;transition:color .15s}\n.sl-rungs button:hover{color:var(--sl-text)}\n.sl-rungs button.on{background:var(--sl-accent);color:var(--sl-accent-ink)}\n/* narrow: shrink the rung pills so the centered row can't reach the corner regions */\n.sl-picker[data-layout=\"narrow\"] .sl-rungs button{padding:5px 9px;font-size:9px;letter-spacing:.03em}\n\n/* Projection is deliberately a separate control from zoom/LOD. Perspective\n changes geometry; the two choices stay explicit and keyboard-native. */\n.sl-projection{display:inline-flex;align-items:center;gap:2px;padding:3px;border-radius:999px;\n background:var(--sl-surface);border:1px solid var(--sl-line);box-shadow:0 8px 24px -16px rgba(0,0,0,.65)}\n.sl-projection button{min-width:42px;min-height:30px;padding:5px 10px;border-radius:999px;color:var(--sl-muted);\n font-size:10px;font-weight:800;letter-spacing:.04em;white-space:nowrap}\n.sl-projection button:hover,.sl-projection button:focus-visible{color:var(--sl-text)}\n.sl-projection button.on{background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-picker[data-layout=\"narrow\"] .sl-projection button{min-width:38px;min-height:32px;padding:5px 8px;font-size:9.5px}\n\n/* 3D venue overlay — mounts over the (paused) Konva stage inside the map host.\n Carries its own gradient so it paints instantly before the scene builds, and\n cross-fades on enter/exit via a compositor-only opacity transition. Sits below\n the anchored chrome (z-index:5) and the confirm card (z-index:10) so the\n Map|3D toggle and the seat confirm both stay usable over it. */\n.sl-view3d{position:absolute;inset:0;z-index:4;opacity:0;touch-action:none;\n transition:opacity .3s ease;background:radial-gradient(120% 120% at 50% 0%,#191f28 0%,#0d1014 70%)}\n.sl-view3d.has-comparison,.sl-view3d.has-passport{z-index:20}\n/* Confirm mode normally disables the entire GL sibling. Modal surfaces live\n inside that sibling, so explicitly restore pointer input only while one is\n open; their own inert contract keeps the venue underneath unavailable. */\n.sl-picker[data-confirming=\"true\"] .sl-view3d.has-comparison,\n.sl-picker[data-confirming=\"true\"] .sl-view3d.has-passport{pointer-events:auto}\n.sl-view3d canvas{display:block;width:100%;height:100%}\n.sl-view3d canvas:focus-visible{outline:2px solid var(--sl-accent);outline-offset:-3px}\n.sl-view3d-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;\n z-index:1;color:#d9e2f2;font-size:13px;font-weight:700;letter-spacing:.02em;pointer-events:none}\n.sl-view3d-loading::before{content:\"\";width:18px;height:18px;border-radius:50%;\n border:2px solid rgba(217,226,242,.28);border-top-color:#d9e2f2;animation:slSpin .8s linear infinite}\n[data-view3d=on] .sl-chips,[data-view3d=on] .sl-rungs{display:none}\n.sl-view3d-back{position:absolute;top:12px;left:12px;z-index:2;display:inline-flex;align-items:center;gap:6px;\n min-height:44px;padding:7px 13px 7px 9px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.03em;\n color:#e6edf3;background:rgba(10,14,20,.62);border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-back:hover,.sl-view3d-back:focus-visible{background:rgba(16,22,30,.82);border-color:rgba(255,255,255,.4)}\n.sl-view3d-back svg{width:15px;height:15px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round;stroke-linejoin:round}\n/* Map|3D already exits an overview to the 2D map. Reserve Back for the one\n state where it adds meaning: returning from an exact seat to the venue. */\n.sl-view3d:not(.is-seat-focused) .sl-view3d-back{display:none}\n.sl-view3d-fs{position:absolute;top:12px;right:12px;z-index:2;min-width:44px;min-height:44px;padding:8px 12px;\n border-radius:999px;font-size:16px;color:#e6edf3;background:rgba(10,14,20,.62);\n border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-fs:hover,.sl-view3d-fs:focus-visible{background:rgba(16,22,30,.82);border-color:rgba(255,255,255,.4)}\n/* Venue navigation inside 3D: levels (isolate a floor) and areas (fly to a zone).\n Bottom-LEFT, clear of the module's own chips (Overview bottom-right, 360\n bottom-centre) and of the bottom-sheeted confirm card. Horizontally scrollable\n so a venue with many zones never pushes the rail off a phone screen.\n\n EVERY WIDTH HERE IS RELATIVE TO THE RAIL, NEVER TO THE WINDOW. These three\n rules used to size off 100vw, which contradicts the one contract this widget\n states about itself: it adapts to a full-screen takeover, an inline div in a\n content page, or a popup, and its breakpoints key off the CONTAINER, never the\n viewport. A 390 px picker embedded in a 1400 px page asked for\n calc(100vw - 180px) = 1220 inside a 390 px rail.\n\n MEASURED, IT DID NOT OVERFLOW: the scroll parent is a flex container, so the\n over-large declaration was shrunk back to the rail and both the old and new\n rules resolve to 364 px in situ. So this is a latent correctness fix, not a\n visible bug -- the numbers were wrong and were being covered for by a\n flex-shrink one level up. Left as 100% because the next person to change that\n parent's display should not inherit a rule that only works by accident. */\n.sl-view3d-nav{position:absolute;left:12px;bottom:16px;z-index:3;display:flex;flex-direction:column;gap:6px;\n max-width:calc(100% - 150px);pointer-events:none}\n.sl-view3d-nav > div{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;pointer-events:auto;\n padding:1px;-webkit-overflow-scrolling:touch}\n.sl-view3d-nav > div::-webkit-scrollbar{display:none}\n.sl-view3d-nav button{flex:0 0 auto;min-height:32px;padding:7px 12px;border-radius:999px;white-space:nowrap;\n font-size:11.5px;font-weight:700;color:#c9d4ea;background:rgba(12,18,32,.72);\n border:1px solid rgba(150,165,205,.35);backdrop-filter:blur(6px);cursor:pointer}\n.sl-view3d-nav button:hover,.sl-view3d-nav button:focus-visible{color:#eef1f8;border-color:rgba(190,205,240,.6)}\n.sl-view3d-nav button[aria-pressed=\"true\"]{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n.sl-view3d-nav button:disabled{opacity:.45;cursor:not-allowed}\n.sl-view3d-nav-toggle{display:none!important}\n.sl-view3d-nav select{min-height:38px;max-width:100%;padding:7px 34px 7px 12px;\n border-radius:999px;font:700 11.5px/1 inherit;color:#eef1f8;background:rgba(12,18,32,.86);\n border:1px solid rgba(150,165,205,.45);backdrop-filter:blur(6px);cursor:pointer}\n.sl-view3d-nav select:focus-visible{outline:2px solid var(--sl-accent);outline-offset:2px}\n.sl-view3d-nav .sl-view3d-locator{display:grid;grid-template-columns:minmax(150px,1.25fr) minmax(110px,.8fr) minmax(105px,.7fr) auto;\n width:min(720px,100%);overflow:visible}\n.sl-view3d-nav.is-seat-focused .sl-view3d-locator{display:none}\n.sl-view3d-locator select{width:100%;min-width:0}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav .sl-view3d-locator{display:flex;width:100%;overflow-x:auto}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-locator select{flex:0 0 155px}\n/* On phones the library owns the bottom edge for seat/panorama/overview actions.\n Keep venue navigation in a separate top rail so those control families never\n stack over one another. */\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav{left:120px;top:12px;bottom:auto;max-width:calc(100% - 132px)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav-toggle{display:inline-flex!important;align-items:center;pointer-events:auto;min-height:44px}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav:not(.is-open)>div{display:none!important}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open{left:12px;top:68px;max-width:calc(100% - 24px);padding:8px;\n border:1px solid rgba(150,165,205,.35);border-radius:14px;background:rgba(8,12,22,.9);backdrop-filter:blur(10px)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open>div{display:flex}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator{display:grid;grid-template-columns:1fr 1fr;width:100%;overflow:visible}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator select{width:100%;min-width:0;flex:auto}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator button{width:100%}\n/* Seat-eye is a decision state, not another venue-navigation state. Once the\n buyer arrives, clear the floor/area/locator rails and the module's duplicate\n Overview action. The picker-owned Back button becomes the one predictable\n escape: seat -> venue -> 2D map. */\n.sl-view3d.is-seat-focused .sl-view3d-nav,\n.sl-view3d.is-seat-focused .sl-3d-overview-control,\n.sl-view3d.is-seat-focused .sl-view3d-compare-saved{display:none!important}\n/* While immersed, the 2D-only chrome is meaningless — hide it, keep Map|3D. */\n.sl-picker[data-view3d=\"on\"] .sl-rungs,\n.sl-picker[data-view3d=\"on\"] .sl-floors,\n.sl-picker[data-view3d=\"on\"] .sl-zoom,\n.sl-picker[data-view3d=\"on\"] .sl-seccard,\n.sl-picker[data-view3d=\"on\"] .sl-minimap{display:none!important}\n/* The confirm card bottom-sheets over 3D (no 2D screen anchor to track). */\n.sl-picker[data-view3d=\"on\"] .sl-confirm{left:50%!important;top:auto!important;bottom:16px;\n transform:translateX(-50%);width:min(342px,calc(100% - 24px))}\n.sl-picker[data-view3d=\"on\"] .sl-confirm[data-placement]{transform:translateX(-50%)}\n.sl-confirm-inspect-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:9px}\n.sl-confirm-inspect-row .sl-confirm-3d{margin-top:0;min-height:44px}\n.sl-confirm-compare{min-height:44px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:transparent}\n.sl-confirm-compare:hover,.sl-confirm-compare:focus-visible{border-color:var(--sl-accent);\n background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n.sl-confirm-compare:disabled{opacity:.62;cursor:default}\n.sl-confirm-confidence{width:100%;min-height:44px;margin-top:8px;padding:8px 10px;border-radius:9px;\n border:1px solid color-mix(in srgb,var(--sl-accent) 35%,var(--sl-line));display:flex;align-items:center;\n justify-content:space-between;gap:10px;text-align:left;color:var(--sl-text);\n background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface))}\n.sl-confirm-confidence>span{min-width:0}\n.sl-confirm-confidence strong,.sl-confirm-confidence small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.sl-confirm-confidence strong{font-size:11px}.sl-confirm-confidence small{margin-top:2px;color:var(--sl-muted);font-size:9.5px}\n.sl-confirm-confidence em{display:none;font-style:normal}\n.sl-confirm-confidence>b{flex:none;font-size:11px;color:var(--sl-accent)}\n.sl-confirm-confidence:hover,.sl-confirm-confidence:focus-visible{border-color:var(--sl-accent)}\n/* The production 3D decision dock is deliberately denser than the 2D popup:\n the venue remains the main content and the two inspection actions share one\n row. Truth-bearing accessibility/restriction copy is never hidden. */\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm{bottom:10px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-field{padding:8px 9px 7px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-value{font-size:14px;margin-top:2px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-field:first-child .sl-confirm-value{font-size:12px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-cat{padding:7px 10px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-price{font-size:15px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-body{padding:8px 10px 9px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-row{margin-top:7px}\n/* A short embedded/mobile picker cannot afford a full decision sheet over a\n 285px map. Keep three 44px action rows and move all disclosure into the\n passport instead of hiding it without a route back. */\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm{bottom:6px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-grid,\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-cat,\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-body>.sl-cx{display:none}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-body{padding:6px 8px 7px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence{margin-top:0}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence em{display:block;margin-bottom:2px;\n color:var(--sl-text);font-size:12px;font-weight:850;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence strong{font-size:9.5px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence small{display:none}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-inspect-row{margin-top:5px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-row{margin-top:5px}\n\n/* Saved comparison lives in the top journey row, away from checkout, arrival\n controls and the bottom-right privacy position. */\n.sl-view3d-compare-saved{position:absolute;top:12px;left:136px;z-index:5;display:flex;align-items:stretch;\n max-width:180px;min-height:38px;border-radius:999px;overflow:hidden;color:#e6edf3;\n background:rgba(10,14,20,.72);border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-compare-saved button{min-width:0;padding:7px 10px;color:inherit;font-size:11px;font-weight:800;white-space:nowrap}\n.sl-view3d-compare-saved .main{overflow:hidden;text-overflow:ellipsis}\n.sl-view3d-compare-saved .clear{width:34px;padding:7px;border-left:1px solid rgba(255,255,255,.18)}\n.sl-view3d-compare-saved button:hover,.sl-view3d-compare-saved button:focus-visible{background:rgba(255,255,255,.1)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-compare-saved{left:126px;max-width:calc(100% - 194px);min-height:44px}\n\n/* An unavailable seat is still inspectable. This compact, non-modal status\n card explains the exact chair the buyer touched without selecting it or\n obscuring the venue with the full purchase confirmation sheet. */\n.sl-view3d-unavailable{position:absolute;left:50%;bottom:18px;z-index:9;display:grid;\n grid-template-columns:minmax(0,1fr) auto;gap:4px 14px;width:min(330px,calc(100% - 24px));\n padding:13px 14px;border:1px solid rgba(255,255,255,.22);border-radius:14px;\n color:#eef3fb;background:rgba(10,14,22,.94);box-shadow:0 18px 48px rgba(0,0,0,.48);\n backdrop-filter:blur(10px);transform:translateX(-50%)}\n.sl-view3d-unavailable[data-state=\"held\"]{border-color:rgba(242,168,56,.7)}\n.sl-view3d-unavailable[data-state=\"sold\"],.sl-view3d-unavailable[data-state=\"dimmed\"]{border-color:rgba(160,170,188,.48)}\n.sl-view3d-unavailable-copy{min-width:0}\n.sl-view3d-unavailable-eyebrow{display:block;font-size:9px;line-height:1.2;letter-spacing:.13em;\n text-transform:uppercase;color:#aab7cc;font-weight:850}\n.sl-view3d-unavailable strong{display:block;margin-top:3px;font-size:17px;line-height:1.2}\n.sl-view3d-unavailable p{grid-column:1/-1;margin:4px 0 0;color:#b9c4d7;font-size:11px;line-height:1.4}\n.sl-view3d-unavailable button{align-self:start;min-width:44px;min-height:44px;margin:-5px -6px 0 0;\n border-radius:999px;color:#eef3fb;font-size:18px;border:1px solid rgba(255,255,255,.18)}\n.sl-view3d-unavailable button:hover,.sl-view3d-unavailable button:focus-visible{background:rgba(255,255,255,.1)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-unavailable{bottom:10px;padding-bottom:max(13px,env(safe-area-inset-bottom))}\n\n.sl-view3d-compare-shell{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:16px}\n.sl-view3d-compare-scrim{position:absolute;inset:0;background:rgba(3,6,12,.74);backdrop-filter:blur(5px)}\n.sl-view3d-compare{position:relative;width:min(720px,100%);max-height:min(680px,calc(100% - 20px));overflow:auto;\n border:1px solid rgba(160,177,214,.34);border-radius:18px;background:var(--sl-bg);color:var(--sl-text);\n box-shadow:0 28px 90px rgba(0,0,0,.55);padding:18px}\n.sl-view3d-compare>header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}\n.sl-view3d-compare>header span{display:block;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-compare>header strong{display:block;margin-top:4px;font-size:20px}\n.sl-view3d-compare>header button{min-width:44px;min-height:44px;border-radius:999px;border:1px solid var(--sl-line);color:var(--sl-text)}\n.sl-view3d-compare-note{margin:12px 0;color:var(--sl-muted);font-size:12px;line-height:1.45}\n.sl-view3d-compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n.sl-view3d-compare article{min-width:0;padding:14px;border:1px solid var(--sl-line);border-radius:13px;background:var(--sl-surface)}\n.sl-view3d-compare article>span{font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-compare article>strong{display:block;margin-top:3px;font-size:20px}\n.sl-view3d-compare article>small{display:block;margin-top:3px;color:var(--sl-muted)}\n.sl-view3d-compare dl{margin:12px 0 0}\n.sl-view3d-compare dl div{display:grid;grid-template-columns:minmax(90px,.8fr) minmax(0,1.2fr);gap:10px;padding:8px 0;border-top:1px solid var(--sl-line)}\n.sl-view3d-compare dt{font-size:10.5px;color:var(--sl-muted)}\n.sl-view3d-compare dd{margin:0;text-align:right;font-size:11px;font-weight:750;overflow-wrap:anywhere}\n.sl-view3d-compare-actions{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:12px}\n.sl-view3d-compare-actions button{min-height:44px;border-radius:9px;border:1px solid var(--sl-line);font-size:12px;font-weight:800}\n.sl-view3d-compare-actions .select{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n.sl-view3d-compare-actions button:disabled{opacity:.5;cursor:not-allowed}\n.sl-view3d-passport-shell{position:absolute;inset:0;z-index:40;display:grid;place-items:center;padding:16px}\n.sl-view3d-passport-scrim{position:absolute;inset:0;background:rgba(3,6,12,.8);backdrop-filter:blur(6px)}\n.sl-view3d-passport{position:relative;width:min(540px,100%);max-height:min(700px,calc(100% - 20px));overflow:auto;\n padding:18px;border:1px solid rgba(160,177,214,.38);border-radius:18px;background:var(--sl-bg);color:var(--sl-text);\n box-shadow:0 28px 90px rgba(0,0,0,.6)}\n.sl-view3d-passport>header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}\n.sl-view3d-passport>header span{display:block;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-passport>header strong{display:block;margin-top:4px;font-size:20px}\n.sl-view3d-passport>header button{min-width:44px;min-height:44px;border:1px solid var(--sl-line);border-radius:999px;color:var(--sl-text)}\n.sl-view3d-passport-summary{margin:14px 0;padding:12px;border-radius:12px;background:color-mix(in srgb,var(--sl-accent) 9%,var(--sl-surface));\n border:1px solid color-mix(in srgb,var(--sl-accent) 30%,var(--sl-line))}\n.sl-view3d-passport-summary strong{display:block;font-size:15px}.sl-view3d-passport-summary span{display:block;margin-top:4px;font-size:11px;color:var(--sl-muted)}\n.sl-view3d-passport dl{margin:0}.sl-view3d-passport dl div{display:grid;grid-template-columns:minmax(105px,.75fr) minmax(0,1.25fr);\n gap:12px;padding:9px 0;border-top:1px solid var(--sl-line)}\n.sl-view3d-passport dt{font-size:10.5px;color:var(--sl-muted)}.sl-view3d-passport dd{margin:0;text-align:right;font-size:11px;font-weight:750;overflow-wrap:anywhere}\n.sl-view3d-passport h4{margin:14px 0 6px;font-size:11px}.sl-view3d-passport ul{margin:0;padding-left:18px;color:var(--sl-muted);font-size:10.5px;line-height:1.5}\n.sl-view3d-passport-note{margin:14px 0 0;color:var(--sl-muted);font-size:10.5px;line-height:1.45}\n@media(max-width:640px){\n .sl-view3d-compare-shell{padding:max(10px,env(safe-area-inset-top)) 10px max(10px,env(safe-area-inset-bottom))}\n .sl-view3d-compare{width:100%;max-height:100%;padding:14px 14px max(86px,calc(14px + env(safe-area-inset-bottom)));border-radius:15px}\n .sl-view3d-compare-grid{grid-template-columns:1fr}\n .sl-view3d-compare article{padding:12px}\n .sl-view3d-passport-shell{padding:max(10px,env(safe-area-inset-top)) 10px max(10px,env(safe-area-inset-bottom))}\n .sl-view3d-passport{width:100%;max-height:100%;padding:14px 14px max(24px,calc(14px + env(safe-area-inset-bottom)));border-radius:15px}\n}\n\n/* Plain \"View from here\" action shown when no real photo exists (the synthetic\n thumb is suppressed at card size — full-screen is where it earns its keep). */\n.sl-confirm-viewbtn{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:transparent;transition:border-color .15s,background .15s}\n.sl-confirm-viewbtn:hover,.sl-confirm-viewbtn:focus-visible{border-color:var(--sl-accent);background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n/* confirm-card \"See it in 3D\" / \"View from this seat\" action — the purchase-\n moment bridge into the cinematic. Styled like the view-from-seat button. */\n.sl-confirm-3d{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:color-mix(in srgb,var(--sl-accent) 12%,transparent);transition:border-color .15s,background .15s}\n.sl-confirm-3d:hover,.sl-confirm-3d:focus-visible{border-color:var(--sl-accent);background:color-mix(in srgb,var(--sl-accent) 20%,transparent)}\n.sl-confirm-3d svg{width:15px;height:15px;stroke:currentColor;stroke-width:1.9;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* multi-floor switcher (flows within the left-rail region) */\n.sl-floors{display:none;flex-direction:column;gap:6px;max-width:100%}\n.sl-floors.on{display:flex}\n.sl-floors button{padding:7px 13px;border-radius:999px;font-size:12px;font-weight:700;background:var(--sl-surface);\n border:1px solid var(--sl-line);color:var(--sl-muted);white-space:nowrap;max-width:100%;overflow:hidden;\n text-overflow:ellipsis;transition:color .15s,border-color .15s}\n.sl-floors button:hover{color:var(--sl-text)}\n.sl-floors button.on{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n\n/* tapped-section summary card — docks INSIDE the top-center anchor region on\n wide (flows below the rung pills, never over them, never floating over the\n seats at the tap point). Auto-collapses to a slim pill once seat-picking\n begins (first seat select, or a pan/zoom after the focus glide); tapping the\n pill re-expands; ✕ closes in both states. On narrow it renders as a compact\n strip inside the bottom sheet's peek head — never over the canvas. */\n.sl-seccard{width:250px;max-width:100%;background:var(--sl-surface);border:1px solid var(--sl-line);border-radius:12px;\n padding:12px 14px;box-shadow:0 18px 50px -18px rgba(0,0,0,.6);display:none}\n.sl-seccard.on{display:block}\n/* collapsed pill (wide) */\n.sl-seccard.mini{width:auto;padding:5px 7px 5px 12px;border-radius:999px;cursor:pointer}\n.sl-seccard.mini.on{display:inline-flex;align-items:center;gap:7px}\n.sl-seccard.mini .sl-seccard-name{font-size:12px;flex:none;max-width:120px}\n.sl-seccard.mini .sl-seccard-left{font-size:11px}\n/* narrow: compact strip inside the sheet head (peek area) */\n.sl-seccard.strip{width:100%;padding:7px 0 0;border:0;border-radius:0;box-shadow:none;background:none;cursor:default}\n.sl-seccard.strip.on{display:flex;align-items:center;gap:7px;font-size:12.5px}\n.sl-seccard.strip .sl-seccard-name{font-size:12.5px}\n.sl-seccard.strip .sl-seccard-price{margin-left:auto}\n.sl-seccard-head{display:flex;align-items:center;gap:8px}\n.sl-seccard-dot{width:10px;height:10px;border-radius:50%;flex:none}\n.sl-seccard-name{font-weight:800;font-size:14px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-seccard-price{font-weight:800;font-size:12.5px;font-variant-numeric:tabular-nums}\n.sl-seccard-x{width:22px;height:22px;border-radius:999px;flex:none;display:flex;align-items:center;justify-content:center;\n color:var(--sl-muted);font-size:12px}\n.sl-seccard-x:hover{color:var(--sl-text)}\n.sl-seccard-zone{font-size:11.5px;color:var(--sl-muted);margin-top:6px}\n.sl-seccard-left{color:var(--sl-text);font-weight:700}\n.sl-seccard-mix{display:flex;flex-wrap:wrap;gap:6px 10px;margin-top:8px}\n.sl-seccard-mix-item{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--sl-muted)}\n.sl-seccard-mix-dot{width:8px;height:8px;border-radius:50%;flex:none}\n.sl-seccard-mix-price{font-weight:700;color:var(--sl-text)}\n.sl-seccard-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:10px}\n.sl-seccard-overview{font-size:12px;font-weight:800;color:var(--sl-accent)}\n.sl-seccard-hint{font-size:10.5px;color:var(--sl-muted)}\n\n/* view-from-seat button on the confirm popover */\n/* Eager sightline preview inside the confirm card */\n.sl-confirm-thumbwrap{position:relative;display:block;width:100%;height:74px;margin:0 0 8px;padding:0!important;\n border-radius:9px;overflow:hidden;border:1px solid var(--sl-line);cursor:pointer}\n.sl-confirm-thumb{display:block;width:100%;height:100%;object-fit:cover}\n.sl-confirm-thumb-badge{position:absolute;right:7px;top:7px;display:inline-flex;align-items:center;gap:5px;\n font-size:10px;font-weight:700;color:#fff;background:rgba(10,14,22,0.72);border-radius:12px;padding:4px 9px;backdrop-filter:blur(3px)}\n.sl-confirm-sight{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--sl-muted);margin-bottom:2px}\n.sl-confirm-view{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n color:var(--sl-text);font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center;gap:7px}\n.sl-confirm-view:hover{border-color:var(--sl-muted)}\n.sl-confirm-view svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* commercial seat flags — limited-view caution + premium tag. Amber tone,\n deliberately distinct from the red taken/held state; shown on the confirm\n card, echoed as a small ◐ marker on cart chips and the hover tip. */\n.sl-cx{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}\n.sl-cx-warn{display:flex;align-items:flex-start;gap:7px;padding:8px 10px;border-radius:9px;\n background:color-mix(in srgb,#f4b740 13%,var(--sl-surface));border:1px solid color-mix(in srgb,#f4b740 40%,var(--sl-line));\n animation:slNoticeIn .28s ease both}\n.sl-cx-glyph{flex:none;font-size:14px;line-height:1.2;color:#f4b740}\n.sl-cx-txt{min-width:0;display:flex;flex-direction:column;gap:2px}\n.sl-cx-txt b{font-size:12px;font-weight:800;color:var(--sl-text)}\n.sl-cx-note{font-size:11px;line-height:1.4;color:var(--sl-muted)}\n.sl-cx-premium{display:inline-flex;align-items:center;gap:6px;align-self:flex-start;padding:4px 10px;border-radius:999px;\n font-size:11px;font-weight:800;letter-spacing:.02em;color:#c9a24b;\n background:color-mix(in srgb,#e8c15a 13%,var(--sl-surface));border:1px solid color-mix(in srgb,#e8c15a 38%,var(--sl-line))}\n.sl-cx-star{font-size:12px;line-height:1;color:#e8c15a}\n.sl-cx-mark{flex:none;font-size:12px;line-height:1;color:#f4b740;cursor:help}\n.sl-tip-cx{display:flex;align-items:center;gap:6px;padding:5px 10px 7px;font-size:10.5px;font-weight:700;color:#e8b24a}\n.sl-tip-cx .g{font-size:12px}\n\n/* 360° seat-view modal (fills the widget; drag-to-look-around equirectangular) */\n.sl-view{position:absolute;inset:0;z-index:12;display:flex;flex-direction:column;background:var(--sl-bg)}\n.sl-view-head{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--sl-line);flex:none}\n.sl-view-title{font-weight:800;font-size:15px}\n.sl-view-cap{font-size:11px;color:var(--sl-muted)}\n.sl-view-x{margin-left:auto;width:32px;height:32px;border-radius:999px;border:1px solid var(--sl-line);color:var(--sl-muted);\n flex:none;display:flex;align-items:center;justify-content:center;transition:color .15s,border-color .15s}\n.sl-view-x:hover{color:var(--sl-text);border-color:var(--sl-muted)}\n.sl-view-x svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}\n.sl-view-pano{position:relative;flex:1;min-height:0;overflow:hidden;cursor:grab;background-color:#05070c;\n background-repeat:repeat-x;touch-action:none;user-select:none}\n.sl-view-pano.drag{cursor:grabbing}\n.sl-view-badge{position:absolute;top:12px;left:12px;padding:5px 11px;border-radius:999px;font-size:10px;font-weight:800;\n letter-spacing:.08em;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted)}\n.sl-view-hint{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);padding:6px 14px;border-radius:999px;\n font-size:11.5px;font-weight:600;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted);\n white-space:nowrap;pointer-events:none;max-width:90%;overflow:hidden;text-overflow:ellipsis}\n\n/* F3 minimap — venue overview + live viewport rect (flows in the bottom-left region) */\n.sl-minimap{border:1px solid var(--sl-line);border-radius:9px;\n overflow:hidden;background:var(--sl-surface);box-shadow:0 12px 34px -14px rgba(0,0,0,.55);line-height:0;cursor:pointer}\n.sl-minimap canvas{display:block}\n.sl-picker[data-layout=\"narrow\"] .sl-minimap{display:none}\n\n/* F4 legend reflection: rows + counts for out-of-band categories read muted */\n.sl-price-row.sl-dim{opacity:.4}\n.sl-seccard-mix-item.sl-dim{opacity:.4}\n\n/* Buyer-journey motion: every animation explains a state transition (selected,\n held, checkout handoff, conflict or booked). No decorative infinite motion\n except the expiring-hold pulse and active progress spinners. */\n@keyframes slPillIn{from{opacity:0;transform:translateX(7px) scale(.9)}to{opacity:1;transform:translateX(0) scale(1)}}\n@keyframes slHoldPulse{0%{box-shadow:0 0 0 0 currentColor;opacity:.9}75%,100%{box-shadow:0 0 0 7px transparent;opacity:.55}}\n@keyframes slChipIn{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}\n@keyframes slChipOut{to{opacity:0;transform:translateX(10px) scale(.98)}}\n@keyframes slNoticeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}\n@keyframes slValuePop{0%{opacity:.6;transform:translateY(3px)}55%{transform:translateY(-1px) scale(1.05)}100%{opacity:1;transform:none}}\n@keyframes slCtaReady{0%{transform:scale(.98);box-shadow:0 0 0 0 transparent}55%{transform:scale(1.01);box-shadow:0 0 0 5px color-mix(in srgb,var(--sl-accent) 18%,transparent)}100%{transform:none;box-shadow:none}}\n@keyframes slToastNudge{0%,100%{margin-left:0}30%{margin-left:-4px}60%{margin-left:3px}}\n@keyframes slSuccessPop{0%{opacity:0;transform:scale(.72)}65%{opacity:1;transform:scale(1.08)}100%{opacity:1;transform:scale(1)}}\n@keyframes slCheckDraw{to{stroke-dashoffset:0}}\n@keyframes slCopyRise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n@keyframes slConfirmIn{from{opacity:0;transform:translate(-50%,calc(-100% - 8px)) scale(.96)}to{opacity:1;transform:translate(-50%,calc(-100% - 14px)) scale(1)}}\n@keyframes slConfirmBelowIn{from{opacity:0;transform:translate(-50%,8px) scale(.96)}to{opacity:1;transform:translate(-50%,16px) scale(1)}}\n@keyframes slConfirmMobileIn{from{opacity:0;transform:translate(-50%,10px) scale(.97)}to{opacity:1;transform:translate(-50%,0) scale(1)}}\n\n/* Access state (channels): the panel fades AND rises at --slm-mo-base. It never\n covers the map — inventory is cross-faded to neutral by the canvas in one\n batched pass, so nothing blinks away underneath it. */\n.sl-access{position:absolute;left:50%;bottom:18px;z-index:9;transform:translateX(-50%);\n max-width:min(420px,calc(100% - 24px));display:flex;gap:12px;align-items:flex-start;\n padding:12px 14px;border-radius:var(--sl-r-sm);background:var(--sl-panel,#151b2c);color:var(--sl-text);\n border:1px solid var(--sl-line);box-shadow:0 18px 44px -18px rgba(0,0,0,.6);\n animation:slAccessIn var(--slm-mo-base) var(--slm-mo-out) both}\n.sl-access-title{font-weight:700;font-size:13px}\n.sl-access-body{font-size:12px;line-height:1.5;opacity:.82;margin-top:2px}\n.sl-access-act{margin-top:8px;padding:6px 12px;border-radius:999px;font-size:12px;font-weight:700;\n background:var(--sl-accent);color:var(--sl-accent-ink)}\n@keyframes slAccessIn{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}\n\n@media(prefers-reduced-motion:reduce){\n .sl-picker *,.sl-modal-scrim *{animation-duration:.001ms!important;animation-iteration-count:1!important;\n transition-duration:.001ms!important;scroll-behavior:auto!important}\n .sl-access{animation:none;opacity:1;transform:translate(-50%,0)}\n}\n.sl-ba [data-ba-zone]{grid-column:1/-1;width:100%}\n\n/* modal host */\n.sl-modal-scrim{position:fixed;inset:0;z-index:2147483000;background:rgba(5,7,12,.66);display:flex;align-items:center;justify-content:center;padding:18px}\n.sl-modal-frame{width:min(1200px,100%);height:min(820px,100%);border-radius:16px;overflow:hidden;box-shadow:0 40px 120px -30px rgba(0,0,0,.8)}\n/* The frame already clips to 16px. A picker rounding itself to --sl-radius\n (14px) inside it leaves a sliver of scrim showing at each corner, which\n reads as a rendering fault rather than as a rounded card. One owner of the\n corners, and it is the frame. */\n.sl-modal-frame > .sl-picker{border-radius:0}\n@media(max-width:640px){.sl-modal-scrim{padding:0}.sl-modal-frame{width:100%;height:100%;border-radius:0}}\n`;\n\nfunction ensureStyle(): void {\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\n/**\n * The header's start time, in the EVENT's zone.\n *\n * Exported for the test that pins the one rule this exists for: every surface\n * that prints an event's start time prints the same time. A zone Intl cannot\n * use throws, and the fallback is the reader's own clock — worse than the\n * venue's, far better than a header with a hole in it.\n */\nexport function formatWhen(startsAt: number, timezone: string | null, locale?: string): string {\n const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' };\n const at = new Date(startsAt);\n if (timezone) {\n try {\n return at.toLocaleString(locale, { ...options, timeZone: timezone });\n } catch {\n /* falls through to the reader's own zone */\n }\n }\n return at.toLocaleString(locale, options);\n}\n\n/** Merge order: defaults ← org chart theme ← host overrides. */\nfunction resolveTokens(chart: ChartTheme | undefined, host: SeatPickerTheme | undefined): Record<string, string> {\n const accent = host?.accent ?? chart?.accent ?? '#f4b740';\n const accentInk = host?.accentInk ?? chart?.accentInk ?? '#1a1200';\n return {\n '--sl-accent': accent,\n '--sl-accent-ink': accentInk,\n '--sl-bg': host?.background ?? chart?.background ?? '#0f1522',\n '--sl-surface': host?.surface ?? '#1a2234',\n '--sl-text': host?.text ?? chart?.textColor ?? '#eef1f8',\n '--sl-muted': host?.muted ?? '#8b93a7',\n '--sl-line': host?.line ?? 'rgba(139,147,167,.22)',\n '--sl-font': host?.fontFamily ?? chart?.fontFamily ?? \"-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,sans-serif\",\n '--sl-radius': `${host?.radius ?? 14}px`,\n };\n}\n\n/**\n * Colorblind-safe preference is a SHARED buyer preference across every SeatLayer\n * surface (the bespoke public page persists it too), so the widget reads/writes\n * the SAME localStorage key. All access is guarded — private-mode/SSR safe.\n */\nconst CB_STORAGE_KEY = 'seatmap.a11y.cb';\nfunction readStoredColorblind(): boolean | null {\n try {\n if (typeof window === 'undefined') return null;\n const raw = window.localStorage.getItem(CB_STORAGE_KEY);\n return raw == null ? null : raw === '1';\n } catch {\n return null;\n }\n}\nfunction writeStoredColorblind(on: boolean): void {\n try {\n window.localStorage.setItem(CB_STORAGE_KEY, on ? '1' : '0');\n } catch {\n /* private mode / storage disabled — preference is best-effort */\n }\n}\n\nexport class SeatPicker {\n private readonly opts: SeatPickerOptions;\n private readonly api: PickerTransport;\n /** Authenticated view media, cached only for this picker lifetime. */\n private readonly buyerAssetUrls: BuyerAssetObjectUrls;\n /** Our own public client, or null when the host injected a transport. */\n private readonly pubApi: PubApi | null;\n /** Null for the ordinary public picker — the tokenless path is untouched. */\n private readonly access: BuyerAccessContext | null;\n private realtime: BuyerRealtimeClient | null = null;\n private accessEl: HTMLDivElement | null = null;\n private readonly apiBase: string;\n private readonly controller: PickerController;\n private readonly maxTickets: number;\n /** Original host pricing, kept separate from live server offer overrides. */\n private readonly hostPricing: SeatPickerPricing | undefined;\n\n private root: HTMLDivElement | null = null;\n private mapHost: HTMLDivElement | null = null;\n private rendered = false;\n private destroyed = false;\n\n // chrome refs\n private els: Record<string, HTMLElement> = {};\n /** Feature 6 anchor regions — positioned flex containers over the map. */\n private regions: Record<string, HTMLElement> = {};\n private ro: ResizeObserver | null = null;\n private holdTimer: ReturnType<typeof setInterval> | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private offerRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n /** Armed only when the offer schedule has a known future transition (or as a\n * bounded retry after a failed read) — never a fixed-cadence poll. */\n private offerBoundaryTimer: ReturnType<typeof setTimeout> | null = null;\n private offerVisibilityHandler: (() => void) | null = null;\n /** Short-lived UI motion timers; all are cancelled on destroy. */\n private motionTimers = new Set<ReturnType<typeof setTimeout>>();\n\n // state\n private currency = 'USD';\n private eventTimezone: string | null = null;\n private offerAvailability: TicketOfferAvailability | null = null;\n private hold: HoldResult | null = null;\n /** Latest server expiry for the open hold (moves on extend). */\n private holdExpiresAt = 0;\n /** True once we handed off to checkout — arms booked-confirmation detection. */\n private handedOff = false;\n /** Guards single onBooked + single success overlay per hold. */\n private bookedShown = false;\n /**\n * `'hosted'` only when the host asked for it AND the widget owns its own\n * transport. Resolved once in the constructor so every later read is a field\n * comparison rather than a re-derivation that could drift.\n */\n private readonly checkoutMode: 'handoff' | 'hosted';\n /**\n * In-flight or settled `payment-options` for this event, started at render in\n * hosted mode. One request, kicked off while the buyer is still choosing, so\n * pressing Pay does not wait on a lookup whose answer never changes mid-session.\n */\n private paymentOptions: Promise<PaymentOptionsResult> | null = null;\n /** The mounted payment card, while one is up. */\n private checkoutPanel: CheckoutHandle | null = null;\n private extendEl: HTMLDivElement | null = null;\n private bookedEl: HTMLDivElement | null = null;\n private gaQty = new Map<string, number>();\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private confirmEl: HTMLDivElement | null = null;\n private confirmSeat: ExpandedSeat | null = null;\n private tableDialogEl: HTMLDivElement | null = null;\n private tableDialog: TableSelectionDetails | null = null;\n private tableDialogHeld = false;\n private tableDialogReturnFocus: HTMLElement | null = null;\n private srEl: HTMLDivElement | null = null;\n private baQty = 2;\n private baCat = '';\n /** Optional navigation-zone scope for buyer best-available. */\n private baZone = '';\n /** \"★ Best seats\" premium quick-pick toggle — biases best-available to premium seats. */\n private baPremium = false;\n private bestAvailableConfirm = false;\n private releasingHold = false;\n /** Event sales window is closed (read-only load state / live close). */\n private salesClosed = false;\n /** Every seated category's live availability is 0 (sold-out overlay is up). */\n private soldOut = false;\n private soldoutEl: HTMLDivElement | null = null;\n /** Resolved colorblind-safe state — stored preference wins over the option. */\n private cbSafe = false;\n\n // arena / multi-floor / seat-view chrome\n private rungsEl: HTMLDivElement | null = null;\n private projectionEl: HTMLDivElement | null = null;\n // --- 3D venue view (Map | 3D) ---\n private buyerView: 'map' | 'venue3d' = 'map';\n private view3dEl: HTMLDivElement | null = null;\n private view3dHandle: Venue3DHandle | null = null;\n /** Monotonic token so a stale async mount (buyer left before OGL finished\n * loading) never installs its handle over a newer state. */\n private view3dGen = 0;\n /** Seat whose 2D confirm card launched \"See it in 3D\"; re-shown on return. */\n private view3dReturnSeat: ExpandedSeat | null = null;\n /** Current premium 3D journey depth. `null` is the venue; a seat id is the\n * fixed seat-eye state. It lets Back unwind one step before leaving 3D. */\n private view3dTargetSeatId: string | null = null;\n /** Inspection-only comparison. These ids never represent cart selection. */\n private view3dCompareSeatIds: string[] = [];\n private view3dCompareChip: HTMLDivElement | null = null;\n private view3dCompareEl: HTMLDivElement | null = null;\n private view3dCompareCleanup: (() => void) | null = null;\n private view3dPassportEl: HTMLDivElement | null = null;\n private view3dPassportCleanup: (() => void) | null = null;\n private floorsEl: HTMLDivElement | null = null;\n private secCardEl: HTMLDivElement | null = null;\n private viewEl: HTMLDivElement | null = null;\n private viewCleanup: (() => void) | null = null;\n /** Supersedes an older authored-view byte request when another seat is opened. */\n private seatViewGen = 0;\n private allSeatsCache: ExpandedSeat[] | null = null;\n\n // F3 minimap\n private miniCanvas: HTMLCanvasElement | null = null;\n private miniBase: HTMLCanvasElement | null = null;\n private miniTf: { scale: number; offX: number; offY: number; dpr: number } | null = null;\n\n // F4 price-band filter — active band's category keys (null = all prices)\n private priceBandKeys: Set<string> | null = null;\n private focusedCatKey: string | null = null;\n /** \"Hide limited-view seats\" — mirrored into 3D by `seatState3dFor`. */\n private limitedViewFilter = false;\n private pricesExpanded = false;\n /** Last surfaced section summary (re-rendered when the price band changes). */\n private lastSection: SectionSummary | null = null;\n /** Section card collapsed to its slim pill (seat-picking has begun). */\n private secCardCollapsed = false;\n /** When the card was (re)shown — the focus glide's own view change must not collapse it. */\n private secCardShownAt = 0;\n /** Previous tray ticket count — first 0→n transition auto-expands the mobile sheet. */\n private lastTrayCount = 0;\n /** Previous computed total — drives a single explanatory value bump. */\n private lastTrayTotal = 0;\n /** Stable item keys prevent tray chips re-animating on unrelated realtime syncs. */\n private lastTrayKeys = new Set<string>();\n private bestAvailableBusy = false;\n private releasingLabels = new Set<string>();\n /** Selected labels awaiting the hold response; their own realtime echo can arrive first. */\n private holdingLabels = new Set<string>();\n private ctaPhase: 'idle' | 'holding' | 'checkout' = 'idle';\n // narrow-layout chrome that docks into the sheet's Filters row on mobile\n private a11yChipsEl: HTMLDivElement | null = null;\n private fsFallback = false;\n private fsChangeHandler: (() => void) | null = null;\n private fsEscHandler: ((e: KeyboardEvent) => void) | null = null;\n /** Host-level event chrome owns the duplicate identity outside full screen. */\n private eventDetailsHidden = false;\n /** True once we've asked the host page to pin us fullscreen (framed, no native). */\n private framedFs = false;\n /** Last height (px) posted to a host frame; dedupes redundant reports. */\n private lastPostedHeight = 0;\n\n /** True when the chart carries a real performance anchor — a stage-kind shape.\n * Every chart has a `focalPoint` (a bare look-at coordinate), so its presence\n * alone never justifies a \"to stage\" claim; only an actual stage does. */\n private chartHasStage(): boolean {\n const doc = this.controller.doc;\n if (!doc) return false;\n const objectSets = doc.floors?.length ? doc.floors.map((f) => f.objects ?? []) : [doc.objects ?? []];\n for (const objects of objectSets) {\n for (const obj of objects) {\n if (obj.type === 'shape' && (obj.role === 'stage' || obj.stageKind)) return true;\n }\n }\n return false;\n }\n\n /**\n * Eager sightline preview for the confirm card: the organizer's real view\n * photo, or — only when the chart has an actual stage to look at — a generated\n * forward view plus an approximate distance-to-stage line. On a stageless\n * chart both the distance claim and the generic stage silhouette are\n * invented promises, so we suppress them; a real attached photo always shows.\n * (OV-52)\n */\n private confirmThumbHtml(seat: ExpandedSeat): string {\n const doc = this.controller.doc;\n if (!doc) return '';\n const realPhoto = seat.viewUrl ?? '';\n const hasStage = this.chartHasStage();\n // No organizer photo AND no stage to measure against → nothing honest to show.\n if (!realPhoto && !hasStage) return '';\n let distance: number | null = null;\n if (!realPhoto) {\n try {\n // Rendered only for its distance figure — the synthetic image itself is\n // deliberately NOT shown at card size, where it reads as a cheap fake\n // photo (owner call 2026-07-24). Full-screen is where generated views\n // earn their keep; the card keeps a plain \"View from here\" button.\n const thumb = generateSeatThumb(seat, seat.focalPoint ?? doc.focalPoint);\n distance = thumb.distanceM ?? null;\n } catch {\n return '';\n }\n }\n // Distance is geometric and defensible. Visibility is not: the procedural\n // model has no columns, rails, overhangs or other obstruction geometry.\n const sightHtml = hasStage && distance != null\n ? `<div class=\"sl-confirm-sight\">${t('picker.sightline', { m: distance })}</div>`\n : '';\n const viewBtn = realPhoto\n ? `<button type=\"button\" class=\"sl-confirm-view sl-confirm-thumbwrap\" aria-label=\"${t('picker.viewFromSeat', { label: seat.label })}\">` +\n // Filled after mount through the binary transport. A direct <img src>\n // cannot attach the Event's buyer bearer.\n `<img class=\"sl-confirm-thumb\" alt=\"\" />` +\n `<span class=\"sl-confirm-thumb-badge\">🔭 ${this.tf('picker.viewFromHere', 'View from here')}</span>` +\n `</button>`\n : `<button type=\"button\" class=\"sl-confirm-view sl-confirm-viewbtn\" aria-label=\"${t('picker.viewFromSeat', { label: seat.label })}\">` +\n `<span aria-hidden=\"true\">🔭</span><span>${this.tf('picker.viewFromHere', 'View from here')}</span>` +\n `</button>`;\n return viewBtn + sightHtml;\n }\n\n /** \"See it in 3D\" (2D) / \"View from this seat\" (already in 3D) action for the\n * confirm card. Only when 3D is available — the purchase-moment bridge into\n * the cinematic that reaches buyers who never press the Map | 3D toggle. */\n private see3dConfirmHtml(): string {\n if (!this.canOffer3d()) return '';\n const label = this.buyerView === 'venue3d'\n ? this.tf('picker.viewFromThisSeat', 'View from this seat')\n : this.tf('picker.seeItIn3d', 'See it in 3D');\n return (\n `<button type=\"button\" class=\"sl-confirm-3d\" aria-label=\"${label}\">`\n + '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 2l9 5v10l-9 5-9-5V7z\"/><path d=\"M12 12l9-5M12 12v10M12 12L3 7\"/></svg>'\n + `<span>${label}</span></button>`\n );\n }\n\n /** Minimal HTML/attribute escaper for buyer-authored commercial text (notes). */\n private escCx(value: unknown): string {\n return String(value ?? '').replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n }\n\n /** Localized \"Restricted view\" / \"Obstructed view\" label for a seat's flags,\n * or '' when neither is set. Restricted takes precedence when both are on. */\n private limitedViewLabel(c: SeatCommercialAttributes | undefined): string {\n if (c?.restrictedView) return this.tf('picker.restrictedView', 'Restricted view');\n if (c?.obstructedView) return this.tf('picker.obstructedView', 'Obstructed view');\n return '';\n }\n\n /**\n * Commercial flags block for the confirm/detail surface: a subtle ★ Premium\n * tag plus an amber ◐ limited-view caution (with the organizer's note when\n * present). '' when the seat carries no surfaced commercial flag.\n */\n private commercialConfirmHtml(c: SeatCommercialAttributes | undefined): string {\n if (!c) return '';\n const rows: string[] = [];\n if (c.premium) {\n rows.push(\n `<div class=\"sl-cx-premium\"><span class=\"sl-cx-star\" aria-hidden=\"true\">★</span>${this.tf('picker.premiumSeat', 'Premium seat')}</div>`,\n );\n }\n const limited = this.limitedViewLabel(c);\n if (limited) {\n rows.push(\n `<div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">◐</span>` +\n `<span class=\"sl-cx-txt\"><b>${limited}</b>${c.note ? `<span class=\"sl-cx-note\">${this.escCx(c.note)}</span>` : ''}</span></div>`,\n );\n } else if (c.note) {\n // A note with no view flag (e.g. seller info) still deserves a calm line.\n rows.push(\n `<div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">ℹ</span>` +\n `<span class=\"sl-cx-txt\"><span class=\"sl-cx-note\">${this.escCx(c.note)}</span></span></div>`,\n );\n }\n return rows.length ? `<div class=\"sl-cx\">${rows.join('')}</div>` : '';\n }\n\n /** Small ◐ limited-view marker for a cart chip; title/aria uses the seat's\n * note when present, else the generic view label. '' for a clear-view seat. */\n private commercialChipMarker(c: SeatCommercialAttributes | undefined): string {\n const limited = this.limitedViewLabel(c);\n if (!limited) return '';\n const title = this.escCx(c?.note ? c.note : limited);\n return `<span class=\"sl-cx-mark\" role=\"img\" aria-label=\"${title}\" title=\"${title}\">◐</span>`;\n }\n\n private wheelchairProvisionLabel(type: 'seat-present' | 'no-seat' | undefined): string {\n if (type === 'no-seat') return 'Empty wheelchair space';\n if (type === 'seat-present') return 'Accessible physical seat';\n return '';\n }\n\n private wheelchairConfirmHtml(type: 'seat-present' | 'no-seat' | undefined): string {\n const label = this.wheelchairProvisionLabel(type);\n return label\n ? `<div class=\"sl-cx\"><div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">♿</span><span class=\"sl-cx-txt\"><b>${label}</b></span></div></div>`\n : '';\n }\n\n private wheelchairChipMarker(type: 'seat-present' | 'no-seat' | undefined): string {\n const label = this.wheelchairProvisionLabel(type);\n return label\n ? `<span class=\"sl-cx-mark\" role=\"img\" aria-label=\"${label}\" title=\"${label}\">♿</span>`\n : '';\n }\n\n /** True when the picker is rendered inside an iframe (snippet embed at /e/:key). */\n private isFramed(): boolean {\n return typeof window !== 'undefined' && window.parent !== window;\n }\n\n /**\n * Post a widget→host message when framed. targetOrigin is '*' because the\n * payload carries nothing sensitive (a height number / a fullscreen flag);\n * hosts verify `event.origin` on their side (see `attachPickerFrame`).\n */\n private postToHost(message: { type: string; [key: string]: unknown }): void {\n if (!this.isFramed()) return;\n try {\n window.parent.postMessage(message, '*');\n } catch {\n /* a hostile/cross-origin parent may reject postMessage — nothing to do */\n }\n }\n\n /**\n * Height (px) to advertise to a host frame.\n *\n * The picker fills whatever box it's given: `.sl-picker` is `height:100%;\n * overflow:hidden`, and the /e/:key shell mounts it `position:fixed; inset:0`.\n * So it has no intrinsic *document* height to read — `scrollHeight` just\n * collapses to the current viewport, which for a framed embed would echo the\n * host's own iframe height straight back (a circular value). We therefore\n * report a width-driven *desired* height: a pleasant landscape box on desktop,\n * taller on narrow widths where the bottom sheet needs room, clamped to the\n * widget's `min-height` of 420. Width is host-controlled and never moves in\n * response to the height we report, so this cannot feedback-loop.\n */\n private measureFramedHeight(): number {\n const root = this.root;\n if (!root) return 0;\n const width = root.clientWidth || (typeof window !== 'undefined' ? window.innerWidth : 0) || 0;\n if (width <= 0) return 0;\n const ratio = width < 640 ? 1.2 : 0.62;\n return Math.max(420, Math.round(width * ratio));\n }\n\n /** Post `seatlayer:height` to the host when framed and the value changed. */\n private reportFramedHeight(): void {\n if (!this.isFramed()) return;\n const px = this.measureFramedHeight();\n if (px <= 0 || px === this.lastPostedHeight) return;\n this.lastPostedHeight = px;\n this.postToHost({ type: 'seatlayer:height', px });\n }\n\n /** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */\n private toggleFullscreen(): void {\n const root = this.root;\n if (!root) return;\n const active = !!document.fullscreenElement || this.fsFallback || this.framedFs;\n if (!active) {\n if (root.requestFullscreen) {\n root.requestFullscreen().catch(() => this.enterFsFallback());\n } else {\n this.enterFsFallback();\n }\n } else if (document.fullscreenElement) {\n void document.exitFullscreen().catch(() => {});\n } else if (this.framedFs) {\n this.setFramedFs(false);\n } else {\n this.setFsFallback(false);\n }\n }\n\n private syncFullscreenButtons(): void {\n const active = !!document.fullscreenElement || this.fsFallback || this.framedFs;\n // Full screen removes the surrounding page/popup from view, so the SDK\n // becomes responsible for restoring the event context it hid while inline.\n const hideEventDetails = this.eventDetailsHidden && !active;\n this.root?.setAttribute('data-event-details-hidden', String(hideEventDetails));\n this.els.logo?.toggleAttribute('hidden', hideEventDetails);\n this.els.headInfo?.toggleAttribute('hidden', hideEventDetails);\n this.els.zfs?.setAttribute('aria-pressed', String(active));\n this.view3dEl?.querySelector<HTMLButtonElement>('.sl-view3d-fs')\n ?.setAttribute('aria-pressed', String(active));\n }\n\n /**\n * Native element-fullscreen was unavailable or rejected. When framed, a CSS\n * `.sl-fs` overlay can't escape the iframe, so we ask the host page to pin us\n * (`seatlayer:fullscreen`). Otherwise (iOS Safari, same document) fall back to\n * the `.sl-fs` overlay as before.\n */\n private enterFsFallback(): void {\n if (this.isFramed()) this.setFramedFs(true);\n else this.setFsFallback(true);\n }\n\n /** Toggle host-driven (framed) fullscreen: post the flag + own the Esc key. */\n private setFramedFs(on: boolean): void {\n if (this.framedFs === on) return;\n this.framedFs = on;\n this.syncFullscreenButtons();\n this.postToHost({ type: 'seatlayer:fullscreen', on });\n if (on && !this.fsEscHandler) {\n this.fsEscHandler = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && !document.fullscreenElement) this.setFramedFs(false);\n };\n window.addEventListener('keydown', this.fsEscHandler);\n } else if (!on && this.fsEscHandler) {\n window.removeEventListener('keydown', this.fsEscHandler);\n this.fsEscHandler = null;\n }\n requestAnimationFrame(() => this.controller.zoomToFit());\n }\n\n private setFsFallback(on: boolean): void {\n if (this.fsFallback === on) return;\n this.fsFallback = on;\n this.root?.classList.toggle('sl-fs', on);\n this.syncFullscreenButtons();\n if (on && !this.fsEscHandler) {\n this.fsEscHandler = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && !document.fullscreenElement) this.setFsFallback(false);\n };\n window.addEventListener('keydown', this.fsEscHandler);\n } else if (!on && this.fsEscHandler) {\n window.removeEventListener('keydown', this.fsEscHandler);\n this.fsEscHandler = null;\n }\n requestAnimationFrame(() => this.controller.zoomToFit());\n }\n private cbEl: HTMLButtonElement | null = null;\n\n // modal plumbing (set by open())\n private modalScrim: HTMLElement | null = null;\n private prevFocus: HTMLElement | null = null;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n /** Set by open(): closes the modal (scroll restore + destroy + onClose). */\n private closeModal: (() => void) | null = null;\n\n /**\n * Close the picker. In modal mode (SeatPicker.open()) this dismisses the\n * modal exactly like ESC/scrim/✕ — restores page scroll and fires onClose.\n * For inline mounts it simply destroys the widget.\n */\n close(): void {\n if (this.closeModal) this.closeModal();\n else this.destroy();\n }\n\n /** Mount the full picker as a document-level modal. Resolves after render. */\n static async open(options: Omit<SeatPickerOptions, 'container'>): Promise<SeatPicker> {\n ensureStyle();\n const priorFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const scrim = document.createElement('div');\n scrim.className = 'sl-modal-scrim';\n const frame = document.createElement('div');\n frame.className = 'sl-modal-frame';\n frame.setAttribute('role', 'dialog');\n frame.setAttribute('aria-modal', 'true');\n frame.setAttribute('aria-label', 'Seat selection');\n frame.tabIndex = -1;\n scrim.appendChild(frame);\n document.body.appendChild(scrim);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n const picker = new SeatPicker({ ...options, container: frame });\n picker.modalScrim = scrim;\n picker.prevFocus = priorFocus;\n\n const focusableSelector = [\n 'a[href]', 'area[href]', 'button', 'input', 'select', 'textarea',\n 'iframe', 'object', 'embed', 'summary', 'audio[controls]', 'video[controls]',\n '[contenteditable]:not([contenteditable=\"false\"])', '[tabindex]',\n ].join(',');\n const activeDialog = (): HTMLElement => {\n const nested = [...frame.querySelectorAll<HTMLElement>('[role=\"dialog\"][aria-modal=\"true\"]')]\n .filter((dialog) => dialog.isConnected && !dialog.closest('[hidden], [aria-hidden=\"true\"], [inert]'));\n return nested[nested.length - 1] ?? frame;\n };\n const hiddenWithin = (element: HTMLElement, scope: HTMLElement): boolean => {\n let current: HTMLElement | null = element;\n while (current) {\n const style = window.getComputedStyle(current);\n if (\n current.hidden\n || current.getAttribute('aria-hidden') === 'true'\n || current.hasAttribute('inert')\n || style.display === 'none'\n || style.visibility === 'hidden'\n || style.visibility === 'collapse'\n ) return true;\n if (current === scope) return false;\n current = current.parentElement;\n }\n return true;\n };\n const tabbableWithin = (scope: HTMLElement): HTMLElement[] =>\n [...scope.querySelectorAll<HTMLElement>(focusableSelector)]\n .filter((element) => element.tabIndex >= 0 && !element.matches(':disabled') && !hiddenWithin(element, scope));\n const focusEdge = (scope: HTMLElement, backwards: boolean): void => {\n const tabbable = tabbableWithin(scope);\n const target = backwards ? tabbable[tabbable.length - 1] : tabbable[0];\n if (target) target.focus({ preventScroll: true });\n else {\n if (!scope.hasAttribute('tabindex')) scope.tabIndex = -1;\n scope.focus({ preventScroll: true });\n }\n };\n\n let closing = false;\n const close = (): void => {\n if (closing) return;\n closing = true;\n document.body.style.overflow = prevOverflow;\n // Remove the modal and its document-level keyboard containment immediately,\n // while still letting an abandoned auto-hold finish releasing before the\n // transport is torn down.\n if (picker.escHandler) document.removeEventListener('keydown', picker.escHandler);\n scrim.remove();\n picker.modalScrim = null;\n const restoreTarget = picker.prevFocus;\n picker.prevFocus = null;\n if (restoreTarget?.isConnected) restoreTarget.focus({ preventScroll: true });\n const finish = (): void => {\n picker.destroy();\n options.onClose?.();\n };\n if (picker.hold && !picker.handedOff) void picker.release().finally(finish);\n else finish();\n };\n picker.closeModal = close;\n scrim.addEventListener('mousedown', (e) => {\n if (e.target === scrim) close();\n });\n picker.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n if (e.defaultPrevented) return;\n const scope = activeDialog();\n const tabbable = tabbableWithin(scope);\n const first = tabbable[0];\n const last = tabbable[tabbable.length - 1];\n const active = document.activeElement;\n if (!first || !last) {\n e.preventDefault();\n focusEdge(scope, e.shiftKey);\n } else if (active === scope || !active || !scope.contains(active)) {\n e.preventDefault();\n (e.shiftKey ? last : first).focus({ preventScroll: true });\n } else if (e.shiftKey && active === first) {\n e.preventDefault();\n last.focus({ preventScroll: true });\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus({ preventScroll: true });\n }\n return;\n }\n if (e.key !== 'Escape') return;\n if (picker.tableDialog) {\n e.preventDefault();\n picker.cancelTableDialog();\n } else if (picker.confirmSeat) {\n e.preventDefault();\n picker.cancelConfirm();\n } else if (picker.bestAvailableConfirm) {\n e.preventDefault();\n picker.bestAvailableConfirm = false;\n picker.syncTray();\n } else {\n e.preventDefault();\n close();\n }\n };\n document.addEventListener('keydown', picker.escHandler);\n await picker.render();\n picker.els.close?.classList.add('on');\n picker.els.close?.addEventListener('click', close);\n focusEdge(activeDialog(), false);\n return picker;\n }\n\n constructor(options: SeatPickerOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n if (!options.container) throw new Error('seatmap: `container` is required (or use SeatPicker.open())');\n this.opts = { ...options, confirmSelection: options.confirmSelection ?? true };\n this.eventDetailsHidden = !!options.hideEventDetails;\n this.hostPricing = options.pricing;\n this.apiBase = (options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, '');\n // A host-supplied transport owns its own credentials, so the access context\n // is only built for our own PubApi.\n this.access = options.transport\n ? null\n : createBuyerAccessContext(options, {\n onExpired: (event) => {\n this.opts.onAccessExpired?.(event);\n if (!event.refreshed) this.showAccessPanel({ reason: 'no_token', retryable: false });\n },\n onUnavailable: (event) => {\n this.opts.onAccessUnavailable?.(event);\n this.showAccessPanel(event);\n },\n });\n this.pubApi = options.transport\n ? null\n : new PubApi(this.apiBase, {\n access: this.access ?? undefined,\n onObjectUnavailable: (event) => this.opts.onSelectedObjectUnavailable?.(event),\n });\n this.api = options.transport ?? this.pubApi!;\n this.buyerAssetUrls = new BuyerAssetObjectUrls(\n options.event,\n this.api.asset ? (key, asset) => this.api.asset!(key, asset) : undefined,\n );\n // Hosted checkout talks to OUR /pub routes with OUR client. A host that\n // injected a transport owns its backend and its credentials, and quietly\n // reaching past it to api.seatlayer.io would be the widget deciding where a\n // buyer's money goes. Refuse out loud, once, and stay on the default.\n if (options.checkout === 'hosted' && !this.pubApi) {\n console.warn(\n 'seatlayer: checkout: \"hosted\" needs the widget\\'s own transport — a custom `transport` '\n + 'owns its backend, so the picker is staying on onCheckout for this mount.',\n );\n }\n this.checkoutMode = options.checkout === 'hosted' && this.pubApi ? 'hosted' : 'handoff';\n this.maxTickets = Math.max(1, Math.floor(options.maxSelection ?? DEFAULT_MAX_SELECTION));\n // Colorblind preference: the stored (cross-surface) value wins over the\n // option; the option is only the initial default when nothing is stored.\n this.cbSafe = readStoredColorblind() ?? !!options.colorblindSafe;\n this.controller = new PickerController({\n transport: this.api,\n eventKey: options.event,\n maxSelection: this.maxTickets,\n currency: options.currency,\n flashOnLiveChange: true,\n colorblindSafe: this.cbSafe,\n // The drawn map's own overrides, when the host supplied them up front.\n // Everything else on `theme` is CSS and lands on the root instead.\n mapTheme: options.theme?.map ?? null,\n onSelectionChange: () => {\n this.syncTray();\n // Seat-picking has begun — collapse the section card out of the way.\n if (this.committedSelection().length) this.collapseSectionCard();\n // Keep the 3D overlay's selection highlight in lockstep (both directions).\n this.syncSelectionTo3d();\n },\n onStatusChange: () => {\n this.syncPrices();\n this.scheduleOfferRefresh(true);\n this.evictTakenSelections();\n this.detectBooked();\n // Live open/close of a section repaints the minimap's static overview.\n this.refreshMinimap();\n // Mirror every live availability delta into the 3D view while it's open.\n this.pushAvailabilityTo3d();\n },\n onHoldExpired: () => {\n this.hold = null;\n this.forgetHold();\n this.handedOff = false;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.stopHoldTimer();\n this.gaQty.clear();\n this.toast(t('picker.holdExpired', undefined) || 'Your hold expired — seats released. Pick again.', 'warning');\n this.syncTray();\n this.emitHoldChange();\n this.opts.onHoldExpired?.();\n },\n confirmSelection: this.opts.confirmSelection,\n onSelect: (seat) => {\n // Sales-closed is a read-only state — refuse the pick (the controller\n // doesn't gate tapping; server would 409 the eventual hold anyway).\n if (this.salesClosed) {\n this.controller.deselect([seat.id]);\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n // Grouped tables own a dedicated whole/guest-count dialog. The raw\n // chair callback is retained for compatibility, but must not open the\n // ordinary one-seat confirm card in this full buyer widget.\n if (this.controller.tableSelection(seat.id)) return;\n this.flashPickedSeat(seat.id);\n if (this.opts.confirmSelection) this.showConfirm(seat);\n },\n onTableSelectionRequest: (table) => {\n if (this.salesClosed) {\n this.controller.deselect(table.physicalSeatIds);\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n this.showTableDialog(table, false);\n },\n onDeselect: (seat) => {\n if (this.confirmSeat?.id === seat.id) this.dismissConfirm();\n if (this.tableDialog?.physicalSeatIds.includes(seat.id)) this.dismissTableDialog();\n },\n onSelectionLimit: () => {\n this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, 'warning');\n },\n onViewChange: () => {\n this.reanchorConfirm();\n this.syncRung();\n this.syncProjection();\n this.drawMinimapRect();\n this.sectionCardOnView();\n },\n // Tapped-section glide-in → surface (or clear) the section-summary card.\n onSectionFocus: (summary) => this.showSectionCard(summary),\n onFocusSeat: (seat) => this.announceSeat(seat),\n onSeatHover: (d) => this.updateTooltip(d),\n onHint: (m) => {\n if (m) this.toast(m);\n },\n // Server declared the event closed mid-session (409 event_closed) — keep\n // the toast (raised by handleCta), and add the persistent read-only state.\n onSalesClosed: () => this.setSalesClosed(true),\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n ensureStyle();\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Hosted checkout asks the server what this event can charge through while\n // the buyer is still looking at the map. The answer cannot change mid-\n // session, and asking now means pressing Pay is not gated on a round trip.\n // A rejection is caught at the point of use, not here — a widget must not\n // die because a payment lookup failed.\n if (this.checkoutMode === 'hosted') this.paymentOptions = this.pubApi!.paymentOptions(this.opts.event);\n\n const mount = resolveContainer(this.opts.container!);\n const root = document.createElement('div');\n root.className = 'sl-picker';\n root.tabIndex = -1;\n this.root = root;\n mount.appendChild(root);\n root.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n if (this.tableDialog) {\n e.preventDefault();\n e.stopPropagation();\n this.cancelTableDialog();\n } else if (this.confirmSeat) {\n e.preventDefault();\n e.stopPropagation();\n this.cancelConfirm();\n } else if (this.bestAvailableConfirm) {\n e.preventDefault();\n e.stopPropagation();\n this.bestAvailableConfirm = false;\n this.syncTray();\n }\n });\n\n // skeleton first — tokens get re-applied once the chart theme arrives\n Object.entries(resolveTokens(undefined, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n root.innerHTML = `\n <div class=\"sl-head\">\n <div class=\"sl-logo\" data-ref=\"logo\"></div>\n <div class=\"sl-head-info\" data-ref=\"headInfo\">\n <div class=\"sl-head-name\" data-ref=\"name\"></div>\n <div class=\"sl-head-meta\" data-ref=\"meta\"></div>\n </div>\n <span class=\"sl-hold-pill\" data-ref=\"hold\"></span>\n <span class=\"sl-closed-pill\" data-ref=\"closedPill\" role=\"status\">\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n <span data-ref=\"closedPillText\"></span>\n </span>\n <button type=\"button\" class=\"sl-close\" data-ref=\"close\" aria-label=\"Close\">\n <svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"sl-body\">\n <div class=\"sl-map\">\n <div class=\"sl-map-host\" data-ref=\"map\"></div>\n <div class=\"sl-zoom\" data-ref=\"zoom\">\n <button type=\"button\" aria-label=\"Zoom in\" data-ref=\"zin\">+</button>\n <button type=\"button\" aria-label=\"Zoom out\" data-ref=\"zout\">−</button>\n <button type=\"button\" aria-label=\"Fit to screen\" data-ref=\"zfit\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3\"/></svg>\n </button>\n <button type=\"button\" aria-label=\"Full screen\" aria-pressed=\"false\" data-ref=\"zfs\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"/></svg>\n </button>\n </div>\n <div class=\"sl-boot\" data-ref=\"boot\"><span class=\"sl-boot-spin\"></span>Loading seat map…</div>\n <div class=\"sl-toast\" data-ref=\"toast\" role=\"status\" aria-live=\"polite\"></div>\n </div>\n <div class=\"sl-side\" data-ref=\"side\">\n <div class=\"sl-sheet-head\" data-ref=\"sheetHead\">\n <div class=\"sl-sheet-grab\"></div>\n <div class=\"sl-sheet-bar\">\n <div class=\"sl-sheet-peek\" data-ref=\"peek\"></div>\n <button type=\"button\" class=\"sl-sheet-toggle\" data-ref=\"sheetToggle\" aria-label=\"Open ticket panel\" aria-expanded=\"false\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"sl-sec sl-filtersec\" data-ref=\"filtersSec\">Filters</div>\n <div class=\"sl-filters\" data-ref=\"filters\"></div>\n <div class=\"sl-offer\" data-ref=\"offer\" role=\"status\" aria-live=\"polite\"></div>\n <div class=\"sl-sec sl-prices-sec\" data-ref=\"pricesSec\"><span>Ticket prices</span></div>\n <div class=\"sl-prices\" data-ref=\"prices\"></div>\n <div class=\"sl-live\" data-ref=\"live\" role=\"status\" aria-live=\"polite\"><span class=\"dot\" aria-hidden=\"true\"></span><span data-ref=\"liveText\">Live availability — seats update in real time</span></div>\n <div class=\"sl-sec sl-seats-sec\"><span>Your seats</span><span class=\"sl-seat-summary\" data-ref=\"seatSummary\"></span></div>\n <div class=\"sl-tray\" data-ref=\"tray\"></div>\n <div class=\"sl-foot\" data-ref=\"foot\">\n <div class=\"sl-hold-note\" data-ref=\"holdNote\" role=\"status\" aria-live=\"polite\">\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M20 6L9 17l-5-5\"/></svg>\n <span><b data-ref=\"holdTitle\">Seats secured</b><span class=\"sl-hold-copy\" data-ref=\"holdCopy\">Checkout timer is running.</span></span>\n <button type=\"button\" class=\"sl-hold-change\" data-ref=\"holdChange\" aria-label=\"Release held tickets and choose different seats\">Change</button>\n </div>\n <div class=\"sl-total\"><span data-ref=\"count\"></span><b data-ref=\"total\"></b></div>\n <button type=\"button\" class=\"sl-cta\" data-ref=\"cta\" disabled></button>\n </div>\n </div>\n </div>`;\n root.querySelectorAll<HTMLElement>('[data-ref]').forEach((el) => {\n this.els[el.dataset.ref!] = el;\n });\n this.mapHost = this.els.map as HTMLDivElement;\n this.syncFullscreenButtons();\n\n // Offer pricing belongs to the canonical picker, not only SeatLayer's own\n // page wrapper. One cached read at mount, then the picker is entirely\n // event-driven: live seat frames trigger a no-store refresh via\n // `onStatusChange`, a successful read arms a timer for the next SCHEDULED\n // transition (a window opening/closing — the one change no seat frame\n // announces), and regaining visibility re-reads once. There is no fixed\n // cadence — a 10s interval here once made a handful of forgotten tabs the\n // top row of the platform's entire Durable Object bill.\n void this.refreshOfferAvailability(false);\n if (this.api.availability) {\n this.offerVisibilityHandler = (): void => {\n if (!document.hidden && !this.destroyed) void this.refreshOfferAvailability(false);\n };\n document.addEventListener('visibilitychange', this.offerVisibilityHandler);\n }\n\n // container-adaptive layout (breakpoint keys off the CONTAINER, not the viewport)\n const applyLayout = (): void => {\n const w = root.clientWidth;\n if (w <= 0) return;\n // Report our desired height to a host frame on every size change (deduped),\n // not just when the layout breakpoint flips below.\n this.reportFramedHeight();\n const next = w < 640 ? 'narrow' : 'wide';\n const density = root.clientHeight < 560 ? 'compact' : 'comfortable';\n if (root.dataset.layout === next && root.dataset.density === density) return;\n root.dataset.layout = next;\n root.dataset.density = density;\n // Entering the mobile sheet layout: start in the peek state (map-first).\n if (next === 'narrow' && !root.dataset.sheet) root.dataset.sheet = 'peek';\n this.dockLayoutChrome();\n };\n this.ro = new ResizeObserver(applyLayout);\n this.ro.observe(root);\n // Some environments defer the ResizeObserver's initial callback (backgrounded\n // tabs throttle delivery). Seed the layout synchronously + next frame so a\n // container that mounts already-wide gets data-layout=\"wide\" immediately,\n // instead of waiting on a resize that may never arrive.\n applyLayout();\n requestAnimationFrame(applyLayout);\n\n // zoom + tooltip wiring\n this.els.zin.addEventListener('click', () => this.controller.zoomIn());\n this.els.zout.addEventListener('click', () => this.controller.zoomOut());\n this.els.zfit.addEventListener('click', () => this.controller.zoomToFit());\n // Full screen: native API with a CSS-fallback overlay for iOS Safari\n // (which has no element fullscreen). Esc exits both paths; the renderer's\n // ResizeObserver re-fits, plus an explicit zoomToFit for a crisp frame.\n this.els.zfs.addEventListener('click', () => this.toggleFullscreen());\n this.fsChangeHandler = (): void => {\n if (!document.fullscreenElement) this.setFsFallback(false);\n this.syncFullscreenButtons();\n requestAnimationFrame(() => this.controller.zoomToFit());\n };\n document.addEventListener('fullscreenchange', this.fsChangeHandler);\n\n // Mobile bottom sheet: swipe/tap on the sheet HEAD only (never the map host,\n // so the map's raw-pointer gesture pipeline is untouched). Swipe up → open\n // (≤50%); swipe down → peek; a plain tap toggles. The section-card strip's\n // ✕ lives inside the head — taps on the card must not toggle the sheet.\n const head = this.els.sheetHead;\n if (head) {\n const toggle = this.els.sheetToggle as HTMLButtonElement | undefined;\n const setSheet = (open: boolean): void => {\n root.dataset.sheet = open ? 'open' : 'peek';\n toggle?.setAttribute('aria-expanded', String(open));\n toggle?.setAttribute('aria-label', open ? 'Collapse ticket panel' : 'Open ticket panel');\n };\n setSheet(root.dataset.sheet === 'open');\n toggle?.addEventListener('click', (e) => {\n e.stopPropagation();\n setSheet(root.dataset.sheet !== 'open');\n });\n /* Delegated, because the pill is re-rendered on every selection change and\n a listener bound to the node would be lost with it. */\n this.els.peek?.addEventListener('click', (e) => {\n const go = (e.target as HTMLElement).closest<HTMLElement>('.sl-sheet-go');\n if (!go) return;\n e.stopPropagation();\n if (go.dataset.act === 'checkout') void this.handleCta();\n else setSheet(true);\n });\n let startY = 0;\n let swiped = false;\n let tracking = false;\n head.addEventListener('pointerdown', (e: PointerEvent) => {\n /* THE CHEVRON DOUBLE-TOGGLED AND SO APPEARED DEAD.\n This handler captures the pointer, and capture RETARGETS every later\n event for it to the capturing element. So the pointerup below saw\n `e.target === head`, its `closest('.sl-sheet-toggle')` guard returned\n null, and the head toggled the sheet — then the button's own click\n toggled it back. Two toggles, no net change, and an owner reporting\n that tapping the arrow does nothing.\n\n The guard has to run HERE, where the target is still the real hit\n element: capture is set on this very line, so pointerdown is the last\n moment the truth is available. A press that starts on the toggle (or\n on a section card) is left entirely to that control. */\n if ((e.target as HTMLElement).closest?.('.sl-seccard,.sl-sheet-toggle,.sl-sheet-go')) {\n tracking = false;\n return;\n }\n tracking = true;\n swiped = false;\n startY = e.clientY;\n head.setPointerCapture?.(e.pointerId);\n });\n head.addEventListener('pointermove', (e: PointerEvent) => {\n if (!tracking || swiped) return;\n const dy = e.clientY - startY;\n if (dy < -18) {\n setSheet(true);\n swiped = true;\n } else if (dy > 18) {\n setSheet(false);\n swiped = true;\n }\n });\n head.addEventListener('pointerup', (e: PointerEvent) => {\n // The guard now lives in pointerdown, where the target has not been\n // retargeted by capture. Reaching here at all means the press did not\n // start on a control of its own.\n if (tracking && !swiped && Math.abs(e.clientY - startY) < 6) {\n setSheet(root.dataset.sheet !== 'open');\n }\n tracking = false;\n head.releasePointerCapture?.(e.pointerId);\n });\n }\n this.tipEl = document.createElement('div');\n this.tipEl.setAttribute('role', 'tooltip');\n this.tipEl.className = 'sl-tip';\n this.els.map.appendChild(this.tipEl);\n this.els.map.addEventListener('mousemove', (e: MouseEvent) => {\n const r = this.els.map.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n });\n\n this.els.cta.addEventListener('click', () => void this.handleCta());\n this.els.holdChange?.addEventListener('click', () => void this.handleChangeSeats());\n\n const canvasHost = document.createElement('div');\n canvasHost.style.cssText = 'position:absolute;inset:0';\n this.mapHost.appendChild(canvasHost);\n const info = await this.controller.render(canvasHost);\n if (this.destroyed) return this;\n if (!info) {\n this.els.boot.innerHTML =\n '<div class=\"sl-boot-title\">The seat map didn’t load</div>' +\n '<div>Check your connection and try again.</div>' +\n '<button type=\"button\" class=\"sl-boot-retry\">Try again</button>';\n this.els.boot.querySelector('button')!.addEventListener('click', () => {\n // full remount: cheapest reliable recovery\n const container = this.opts.container!;\n const opts = this.opts;\n this.destroy();\n void new SeatPicker({ ...opts, container }).render();\n });\n return this;\n }\n this.els.boot.remove();\n this.startRealtime();\n // Read-only load state: the chart payload is authoritative, while an\n // embedding host may deliberately make an otherwise-open map preview-only.\n this.salesClosed = !!info.salesClosed || !!this.opts.readOnly;\n root.dataset.eventMode = info.mode === 'test' ? 'test' : 'live';\n this.controller.setViewMode(this.normalizeInitialView(this.opts.initialView));\n\n // Feature 6: anchor regions for all persistent map chrome, then move the\n // pre-built zoom column + toast into their regions (both were in the skeleton).\n this.buildRegions();\n this.regions['bottom-right'].appendChild(this.els.zoom);\n this.regions['bottom-center'].appendChild(this.els.toast);\n\n if (info.mode === 'test') {\n // Environment context is a passive corner ribbon, never another control\n // beside Map/3D. The CSS moves any top-left filters below its footprint.\n const badge = document.createElement('div');\n badge.className = 'sl-testbadge';\n badge.textContent = t('picker.testMode');\n badge.setAttribute('aria-label', t('picker.testMode'));\n this.els.map.appendChild(badge);\n }\n\n // theme: defaults ← org chart theme ← host overrides\n const chartTheme = this.controller.doc?.theme;\n Object.entries(resolveTokens(chartTheme, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n this.currency = info.currency ?? this.opts.currency ?? 'USD';\n this.eventTimezone = info.timezone ?? null;\n\n // header\n const logoUrl = this.opts.theme?.logoUrl ?? chartTheme?.logoUrl;\n if (logoUrl) this.els.logo.innerHTML = `<img src=\"${logoUrl}\" alt=\"\">`;\n else this.els.logo.textContent = (this.opts.theme?.brandName ?? chartTheme?.brandName ?? info.eventName ?? '?').slice(0, 1).toUpperCase();\n this.els.name.textContent = info.eventName ?? '';\n // THE EVENT'S ZONE, NOT THE READER'S. This line used to format in whatever\n // zone the browser happened to be in, while the hosted landing page around\n // it formatted the same instant in the venue's — so one page showed a gig\n // starting at two different times and gave a buyer no way to tell which one\n // the doors follow. An unusable zone string (a typo, a name this engine has\n // never heard of) throws inside Intl, and a header that cannot render is a\n // worse answer than the reader's own clock, so that case falls through.\n const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : '';\n this.els.meta.textContent = [info.venue, when].filter(Boolean).join(' · ');\n\n // \"Powered by SeatLayer\" attribution badge — hidden when the host opts out\n // OR the org's paid chart theme sets hideBadge (either being true hides it).\n this.buildBadge(chartTheme);\n\n // Accessibility filter chips — only for types actually present in the chart.\n // Same sweep also detects whether ANY seat carries a limited-view (restricted\n // or obstructed) commercial flag, which gates the \"Hide limited-view seats\"\n // toggle that shares this chip row.\n const present = new Set<AccessibilityType>();\n let hasLimitedView = false;\n if (this.controller.doc) {\n for (const seat of expandChart(this.controller.doc)) {\n for (const type of seat.accessibility ?? []) present.add(type);\n if (seat.accessible && !seat.accessibility?.length) present.add('wheelchair');\n if (seat.commercial?.restrictedView || seat.commercial?.obstructedView) hasLimitedView = true;\n }\n }\n // Jump to the seats rung when a dimming filter turns on — the dimming only\n // renders at seat detail; applying it zoomed out would silently dim seats\n // the buyer can't see. Shared by the a11y chips and the limited-view toggle.\n const focusSeatsForFilter = (): void => {\n if (this.rungsEl && this.controller.getRung() !== 'seats') {\n this.controller.setRung('seats');\n this.collapseSectionCard();\n this.syncRung();\n }\n };\n if (present.size || hasLimitedView) {\n const chips = document.createElement('div');\n chips.className = 'sl-chips';\n this.regions['top-left'].appendChild(chips);\n this.a11yChipsEl = chips;\n\n if (present.size) {\n const mk = (key: AccessibilityType | 'all', label: string): string =>\n `<button type=\"button\" class=\"sl-chip-f${key === 'all' ? ' on' : ''}\" data-a11y=\"1\" data-f=\"${key}\">${label}</button>`;\n chips.insertAdjacentHTML('beforeend',\n mk('all', 'All seats') +\n ACCESSIBILITY_TYPES\n .filter(({ key }) => present.has(key))\n .map(({ key, short, icon }) => mk(key, `${icon} ${short}`))\n .join(''));\n // Multi-select OR semantics (parity with the buyer page): each type chip\n // toggles independently; the active filter is the union; \"All seats\"\n // clears. A buyer needing wheelchair AND companion seats combines both.\n const active = new Set<AccessibilityType>();\n const syncChips = (): void => {\n chips.querySelectorAll<HTMLButtonElement>('button[data-a11y]').forEach((b) => {\n const f = b.dataset.f as AccessibilityType | 'all';\n const on = f === 'all' ? active.size === 0 : active.has(f);\n b.classList.toggle('on', on);\n b.setAttribute('aria-pressed', String(on));\n });\n const filter = active.size ? [...active] : null;\n this.controller.setAccessibilityFilter(filter);\n if (filter) focusSeatsForFilter();\n };\n chips.querySelectorAll<HTMLButtonElement>('button[data-a11y]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const f = btn.dataset.f as AccessibilityType | 'all';\n if (f === 'all') active.clear();\n else if (active.has(f)) active.delete(f);\n else active.add(f);\n syncChips();\n });\n });\n }\n\n // \"Hide limited-view seats\" toggle — one independent on/off chip that dims\n // free seats flagged restricted/obstructed view (same chip pattern, sits\n // beside the a11y chips). Isolated from the a11y OR-union above.\n if (hasLimitedView) {\n const limited = document.createElement('button');\n limited.type = 'button';\n limited.className = 'sl-chip-f';\n limited.setAttribute('aria-pressed', 'false');\n limited.innerHTML = `◐ ${this.tf('picker.hideLimitedView', 'Hide limited-view seats')}`;\n chips.appendChild(limited);\n limited.addEventListener('click', () => {\n const limitedOn = !this.limitedViewFilter;\n this.limitedViewFilter = limitedOn;\n limited.classList.toggle('on', limitedOn);\n limited.setAttribute('aria-pressed', String(limitedOn));\n this.controller.setCommercialLimitedFilter(limitedOn);\n // Keep 3D in step — the filter must survive the switch between views.\n this.pushAvailabilityTo3d();\n if (limitedOn) focusSeatsForFilter();\n });\n }\n }\n\n // Colorblind-safe toggle rides in the zoom column (wide) or the sheet's\n // Filters row (narrow) — dockLayoutChrome moves it between the two.\n const cb = document.createElement('button');\n cb.type = 'button';\n cb.className = 'sl-cbbtn';\n this.cbEl = cb;\n cb.setAttribute('aria-label', 'Toggle colorblind-friendly colors');\n // Rehydrated from the shared preference (constructor read stored → this.cbSafe).\n cb.setAttribute('aria-pressed', String(this.cbSafe));\n cb.innerHTML = '<svg viewBox=\"0 0 24 24\"><path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>';\n this.els.zfit.parentElement!.appendChild(cb);\n // Route through the single source of truth so host chrome (e.g. the Designer\n // preview chip) and this in-widget button always agree.\n cb.addEventListener('click', () => { this.setColorblindSafe(!this.cbSafe); });\n\n // Screen-reader announcements for keyboard seat focus.\n this.srEl = document.createElement('div');\n this.srEl.className = 'sl-sr';\n this.srEl.setAttribute('aria-live', 'polite');\n root.appendChild(this.srEl);\n\n // Big-venue chrome: LOD rung pills, multi-floor switcher, section card.\n // Appended AFTER controller.render() — render() wipes the map host's children.\n this.buildArenaChrome();\n\n // F3 minimap (venue overview + viewport rect) and F4 price-band filter.\n // Same post-render append (the map host was wiped by controller.render()).\n this.buildMinimap();\n this.buildPriceFilter();\n\n // \"Need more time?\" prompt (over the map) + booked-confirmation overlay (over\n // the whole widget). Both appended post-render for the same wipe reason.\n this.buildExtendPrompt();\n this.buildBookedOverlay();\n this.buildSoldoutOverlay();\n\n // Dock layout-dependent chrome (a11y chips + colorblind toggle) for the\n // CURRENT layout — the initial applyLayout ran before these were built.\n this.dockLayoutChrome();\n\n await this.restoreRememberedHold();\n if (this.destroyed) return this;\n\n // Reflect the read-only load state (pill + disabled CTA/controls) with no\n // toast — a fresh mount into a closed event is not a live \"just closed\" event.\n if (this.salesClosed) this.applySalesClosed();\n this.syncPrices();\n this.syncTray();\n // Last, so a buyer coming back from a gateway sees a finished map behind the\n // confirmation rather than a skeleton.\n this.resumeHostedOrder();\n return this;\n }\n\n /**\n * A hosted gateway returned this buyer to a page that runs the widget, with\n * `?order=…&status=…` in the URL. Pick the order up and finish the story.\n *\n * Only `success` resumes. `cancelled` means the buyer backed out at the\n * gateway and their seats are still held — the map they are looking at IS the\n * right screen, and opening a card to say \"you cancelled\" would be noise.\n *\n * The two parameters are then stripped with `replaceState`, because they are a\n * one-shot instruction: leaving them in place would re-open the confirmation\n * on every later navigation, and would carry an order id into browser history\n * and any Referer this page later sends. `status` is only ever removed\n * alongside an `order` we actually consumed, so a host page that uses a\n * `status` parameter of its own keeps it.\n */\n private resumeHostedOrder(): void {\n if (this.checkoutMode !== 'hosted' || typeof location === 'undefined') return;\n const params = new URLSearchParams(location.search);\n const orderId = params.get('order');\n if (!orderId) return;\n const status = params.get('status');\n params.delete('order');\n params.delete('status');\n try {\n const query = params.toString();\n history.replaceState(history.state, '', `${location.pathname}${query ? `?${query}` : ''}${location.hash}`);\n } catch {\n // A sandboxed frame can refuse replaceState. Losing the tidy-up is not a\n // reason to lose the confirmation.\n }\n if (status !== 'success') return;\n void this.openCheckoutPanel({ kind: 'resume', orderId });\n }\n\n /**\n * Move layout-dependent chrome between its wide dock (map regions / zoom\n * column) and its narrow dock (the sheet's consolidated Filters row), and\n * re-render the section card in the form the layout wants (docked card/pill\n * on wide, sheet strip on narrow). Runs on every layout flip + once post-render.\n */\n private dockLayoutChrome(): void {\n const narrow = this.root?.dataset.layout === 'narrow';\n const filters = this.els.filters;\n if (filters) {\n /* THE COLOURBLIND TOGGLE IS A MAP CONTROL, NOT A CART ROW.\n It used to dock into the sheet on narrow, and the result was a FILTERS\n section heading standing over a single 32 px eye — placed between the\n buyer's tickets and their checkout. Measured on a 390 px phone: 29 px of\n heading plus a 44 px row, 73 of a 252 px sheet, to caption one icon. The\n second ticket of two was pushed out of the tray to pay for it.\n\n It lives with the zoom cluster in BOTH layouts now. Nothing is lost —\n the toggle is where the map it recolours is. */\n if (this.cbEl) this.els.zoom?.appendChild(this.cbEl);\n if (narrow) {\n if (this.a11yChipsEl) filters.appendChild(this.a11yChipsEl);\n } else {\n if (this.a11yChipsEl) this.regions['top-left']?.appendChild(this.a11yChipsEl);\n }\n /* So FILTERS now appears only when there are real accessibility filters to\n show, and never as a caption for chrome that had nowhere else to go. */\n const has = narrow && filters.children.length > 0;\n filters.classList.toggle('has', has);\n this.els.filtersSec?.classList.toggle('has', has);\n }\n if (this.lastSection) this.renderSectionCard(this.lastSection);\n }\n\n /** The \"Need more time?\" prompt shown in the hold's final EXTEND_PROMPT_MS. */\n private buildExtendPrompt(): void {\n const el = document.createElement('div');\n el.className = 'sl-extend';\n el.setAttribute('role', 'status');\n el.innerHTML =\n `<span class=\"sl-extend-txt\" data-ref=\"extendTxt\"></span>` +\n `<button type=\"button\" class=\"sl-extend-btn\" data-ref=\"extendBtn\"></button>`;\n (this.regions['bottom-center'] ?? this.els.map).appendChild(el);\n this.extendEl = el;\n this.els.extendTxt = el.querySelector('[data-ref=\"extendTxt\"]') as HTMLElement;\n this.els.extendBtn = el.querySelector('[data-ref=\"extendBtn\"]') as HTMLElement;\n this.els.extendBtn.textContent = 'Add time';\n this.els.extendBtn.addEventListener('click', () => void this.handleExtend());\n }\n\n /** Success overlay + onBooked fire when the held seats settle to booked. */\n private buildBookedOverlay(): void {\n const el = document.createElement('div');\n el.className = 'sl-booked';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML =\n `<div class=\"sl-booked-badge\"><svg viewBox=\"0 0 24 24\"><path d=\"M20 6L9 17l-5-5\"/></svg></div>` +\n `<div class=\"sl-booked-title\">You're all set</div>` +\n `<div class=\"sl-booked-sub\" data-ref=\"bookedSub\"></div>`;\n this.root!.appendChild(el);\n this.bookedEl = el;\n this.els.bookedSub = el.querySelector('[data-ref=\"bookedSub\"]') as HTMLElement;\n }\n\n /**\n * Localized string with a literal fallback. `t()` returns the key itself for\n * unknown keys, so this collapses that to `fallback` — while still honoring a\n * host `messages` override (which makes `t()` return the override, not the key).\n */\n private tf(key: string, fallback: string): string {\n const v = t(key);\n return v === key ? fallback : v;\n }\n\n /** Sold-out overlay — an informational state with no unavailable action. */\n private buildSoldoutOverlay(): void {\n if (!this.els.map) return;\n const el = document.createElement('div');\n el.className = 'sl-soldout';\n el.setAttribute('role', 'status');\n const name = (this.controller.doc?.theme?.brandName ?? this.opts.theme?.brandName ?? this.els.name?.textContent ?? this.tf('picker.soldOutEyebrow', 'This event')).toUpperCase();\n el.innerHTML =\n `<div class=\"sl-soldout-eyebrow\">${name}</div>` +\n `<div class=\"sl-soldout-title\">${this.tf('picker.soldOutTitle', 'Sold out')}</div>` +\n `<p class=\"sl-soldout-copy\">${this.tf('picker.soldOutCopy', 'No reserved seats are currently available for this event.')}</p>`;\n this.els.map.appendChild(el);\n this.soldoutEl = el;\n }\n\n /**\n * Recompute the sold-out state on every price/availability sync. Sold-out ⇔\n * every SEATED category's live free count is 0. Suppressed when the chart has\n * GA areas (GA capacity isn't per-seat, so seated counts would read 0 and\n * falsely block standing room) — mirrors the public page. Clears live when WS\n * frees a seat up.\n */\n private syncSoldout(categories: Array<{ key: string }>, left: Record<string, number>): void {\n const hasGA = this.controller.getGAAreas().length > 0;\n const soldOut = this.isSoldOut(categories, left, hasGA);\n if (soldOut === this.soldOut) return;\n this.soldOut = soldOut;\n this.soldoutEl?.classList.toggle('on', soldOut);\n }\n\n /**\n * Pure sold-out predicate: every SEATED category's free count is 0, there is at\n * least one seated category, and there are no GA areas (GA capacity isn't\n * per-seat, so seated counts read 0 and would falsely block standing room).\n * `left` is seeded implicitly — a missing key means a fully-booked tier (0 free).\n */\n private isSoldOut(categories: Array<{ key: string }>, left: Record<string, number>, hasGA: boolean): boolean {\n return !hasGA && categories.length > 0 && categories.every((c) => (left[c.key] ?? 0) === 0);\n }\n\n /**\n * Sales-closed read-only state (Gap 3): persistent header pill, disabled CTA\n * with a closed label, and frozen best-available / GA controls. `setSalesClosed`\n * is the reactive entry (live 409 event_closed); `applySalesClosed` is the\n * idempotent DOM apply used at load and on transition.\n */\n private setSalesClosed(closed: boolean): void {\n const next = closed || !!this.opts.readOnly;\n if (this.salesClosed === next) return;\n this.salesClosed = next;\n this.applySalesClosed();\n }\n\n private applySalesClosed(): void {\n if (this.salesClosed && this.tableDialog && !this.tableDialogHeld) this.cancelTableDialog();\n const pill = this.els.closedPill;\n if (pill) {\n pill.classList.toggle('on', this.salesClosed);\n const text = this.els.closedPillText ?? pill;\n text.textContent = this.tf('picker.salesClosedPill', 'Sales are closed');\n }\n this.root?.setAttribute('data-sales-closed', String(this.salesClosed));\n this.syncCta();\n this.syncTray();\n }\n\n /** The badge is hidden when the host opts out OR the org's theme sets hideBadge. */\n private badgeHidden(chartTheme?: ChartTheme): boolean {\n return !!(this.opts.hideBadge || chartTheme?.hideBadge);\n }\n\n /** Attribution badge in the side-panel foot (Gap 7). Hidden per host/theme. */\n private buildBadge(chartTheme: ChartTheme | undefined): void {\n if (this.badgeHidden(chartTheme)) return;\n const foot = this.els.foot;\n if (!foot) return;\n // An anchor, not a div: this badge is the only route from a buyer's seat\n // map back to us, and SeatingChart's equivalent badge has always been a\n // link — the two were inconsistent for no reason. Attribution that cannot\n // be clicked is decoration.\n const el = document.createElement('a');\n el.className = 'sl-powered';\n el.href = 'https://seatlayer.io/?ref=picker';\n el.target = '_blank';\n el.rel = 'noopener noreferrer';\n el.setAttribute('aria-label', this.tf('picker.poweredBy', 'Powered by SeatLayer'));\n el.innerHTML =\n `<span class=\"sl-powered-mark\" aria-hidden=\"true\">` +\n SEATLAYER_ATTRIBUTION_MARK_SVG +\n `</span><span>${this.tf('picker.poweredBy', 'Powered by SeatLayer')}</span>`;\n foot.appendChild(el);\n }\n\n // ---- Feature 6: chrome anchor regions -------------------------------------\n\n /**\n * Create the positioned flex containers that own every persistent map overlay.\n * Appended once after controller.render(); each chrome piece is then appended\n * INTO its region and flows within it, so nothing free-floats over anything\n * else. Regions carve the map into non-overlapping zones (top strip split into\n * left/center/right, left rail, and the three used corners).\n */\n private buildRegions(): void {\n if (!this.els.map) return;\n const REGIONS = ['top-left', 'top-center', 'top-right', 'left-rail', 'bottom-left', 'bottom-center', 'bottom-right'];\n for (const region of REGIONS) {\n const el = document.createElement('div');\n el.className = 'sl-anchor';\n el.dataset.region = region;\n this.els.map.appendChild(el);\n this.regions[region] = el;\n }\n }\n\n // ---- F3 minimap -----------------------------------------------------------\n\n /** Read a resolved --sl-* token value (canvas needs a real color, not var()). */\n private cssVar(name: string): string {\n return this.root ? getComputedStyle(this.root).getPropertyValue(name).trim() : '';\n }\n\n /** Motion is progressive enhancement; all state remains legible when reduced. */\n private reducedMotion(): boolean {\n return typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n }\n\n private scheduleMotion(fn: () => void, delay: number): void {\n const timer = setTimeout(() => {\n this.motionTimers.delete(timer);\n if (!this.destroyed) fn();\n }, delay);\n this.motionTimers.add(timer);\n }\n\n /** Restart one finite CSS animation without leaving a permanent state class. */\n private animateOnce(el: HTMLElement | undefined, className: string, duration = 600): void {\n if (!el || this.reducedMotion()) return;\n el.classList.remove(className);\n void el.offsetWidth;\n el.classList.add(className);\n this.scheduleMotion(() => el.classList.remove(className), duration);\n }\n\n /** Selection feedback belongs on the selected seat, not across the whole map. */\n private flashPickedSeat(id: string): void {\n if (this.reducedMotion()) return;\n this.controller.flashSeat(id, this.cssVar('--sl-accent') || '#f4b740');\n }\n\n /** A completed hold gets one short map ripple per concrete seat. */\n private flashHeldSeats(hold: HoldResult): void {\n if (this.reducedMotion()) return;\n const labels = (hold.items ?? []).filter((item) => item.objectType !== 'ga').map((item) => item.label);\n labels.slice(0, 10).forEach((label, index) => {\n const seat = this.controller.seatByLabel(label);\n if (!seat) return;\n this.scheduleMotion(\n () => this.controller.flashSeat(seat.id, this.cssVar('--sl-accent') || '#f4b740'),\n index * 55,\n );\n });\n }\n\n /** Update only the action affordance; selection callbacks must not refire. */\n private committedSelection(): PickerSeat[] {\n const candidateId = this.confirmSeat?.id;\n const pendingTableId = this.tableDialog && !this.tableDialogHeld ? this.tableDialog.id : null;\n return this.controller.getSelection().filter((seat) => seat.id !== candidateId && seat.id !== pendingTableId);\n }\n\n private pendingSelectionCount(): number {\n const heldItems = this.hold?.items ?? [];\n const heldLabels = new Set(heldItems.map((item) => item.label));\n const pendingSeats = this.committedSelection()\n .filter((seat) => !heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n return pendingSeats + this.pendingGACount();\n }\n\n private heldGACounts(): Map<string, number> {\n const heldGA = new Map<string, number>();\n for (const item of (this.hold?.items ?? []).filter((candidate) => candidate.objectType === 'ga')) {\n heldGA.set(item.objectId, (heldGA.get(item.objectId) ?? 0) + (item.quantity ?? 1));\n }\n return heldGA;\n }\n\n private pendingGACount(): number {\n const heldGA = this.heldGACounts();\n return [...this.gaQty.entries()].reduce(\n (sum, [areaId, qty]) => sum + Math.max(0, qty - (heldGA.get(areaId) ?? 0)),\n 0,\n );\n }\n\n private heldTicketCount(): number {\n return (this.hold?.items ?? []).reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n }\n\n private totalTicketCount(): number {\n const heldLabels = new Set((this.hold?.items ?? []).map((item) => item.label));\n const freshSeats = this.committedSelection()\n .filter((seat) => !heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n return this.heldTicketCount() + freshSeats + this.pendingGACount();\n }\n\n /** Held tickets and standing quantities consume the same order-wide cap. */\n private updateSelectionCapacity(): void {\n const heldLabels = new Set((this.hold?.items ?? []).map((item) => item.label));\n const selectedHeld = this.committedSelection()\n .filter((seat) => heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n const remaining = Math.max(0, this.maxTickets - this.heldTicketCount() - this.pendingGACount());\n this.controller.setMaxSelection(selectedHeld + remaining);\n }\n\n private canAddTicket(): boolean {\n if (this.totalTicketCount() < this.maxTickets) return true;\n this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, 'warning');\n return false;\n }\n\n private pendingGATotal(gaAreas: ReturnType<PickerController['getGAAreas']>): number {\n const heldGA = new Map<string, number>();\n for (const item of (this.hold?.items ?? []).filter((candidate) => candidate.objectType === 'ga')) {\n heldGA.set(item.objectId, (heldGA.get(item.objectId) ?? 0) + (item.quantity ?? 1));\n }\n return gaAreas.reduce(\n (sum, area) => sum + this.paidPrice(area.categoryKey, null, area.price) * Math.max(0, (this.gaQty.get(area.id) ?? 0) - (heldGA.get(area.id) ?? 0)),\n 0,\n );\n }\n\n private syncCta(count = this.lastTrayCount, pending = this.pendingSelectionCount()): void {\n const cta = this.els.cta as HTMLButtonElement | undefined;\n if (!cta) return;\n if (this.salesClosed) {\n cta.disabled = true;\n cta.textContent = this.tf('picker.salesClosedCta', 'Sales closed');\n return;\n }\n if (this.confirmSeat || (this.tableDialog && !this.tableDialogHeld)) {\n cta.disabled = true;\n cta.textContent = this.tableDialog ? 'Confirm your table' : 'Confirm or cancel this seat';\n return;\n }\n if (this.ctaPhase === 'holding') {\n cta.disabled = true;\n cta.innerHTML = '<span class=\"sl-cta-spin\" aria-hidden=\"true\"></span>Securing seats…';\n return;\n }\n if (this.ctaPhase === 'checkout') {\n cta.disabled = true;\n cta.innerHTML = '<span class=\"sl-cta-spin\" aria-hidden=\"true\"></span>Opening checkout…';\n return;\n }\n cta.disabled = count === 0;\n cta.textContent = this.hold\n ? pending\n ? `Secure ${pending} more & checkout`\n : 'Continue to checkout'\n : count\n ? 'Hold seats & checkout'\n : 'Select seats';\n }\n\n private setCtaPhase(phase: 'idle' | 'holding' | 'checkout'): void {\n this.ctaPhase = phase;\n this.syncCta();\n if (phase === 'checkout') {\n this.scheduleMotion(() => {\n if (this.ctaPhase !== 'checkout') return;\n this.ctaPhase = 'idle';\n this.syncCta();\n }, 1100);\n }\n }\n\n /** Session-scoped capability key: isolated by API origin and event. */\n private holdStorageKey(): string {\n return `@seatlayer/hold/v1/${encodeURIComponent(this.apiBase)}/${encodeURIComponent(this.opts.event)}`;\n }\n\n private rememberedHoldId(): string | null {\n if (this.opts.initialHoldId) return this.opts.initialHoldId;\n if (this.opts.restoreHold === false || typeof window === 'undefined') return null;\n try {\n return window.sessionStorage.getItem(this.holdStorageKey());\n } catch {\n return null;\n }\n }\n\n private rememberHold(hold: HoldResult): void {\n if (this.opts.restoreHold === false || typeof window === 'undefined') return;\n try {\n // Persist only the opaque capability. Labels, prices and expiry are\n // always reloaded from the authoritative server projection.\n window.sessionStorage.setItem(this.holdStorageKey(), hold.holdId);\n } catch {\n // Storage can be unavailable in privacy/sandboxed embeds; the live picker\n // remains fully functional for the current mount.\n }\n }\n\n private forgetHold(): void {\n if (typeof window === 'undefined') return;\n try {\n window.sessionStorage.removeItem(this.holdStorageKey());\n } catch {\n // Best-effort cleanup only.\n }\n }\n\n private async resumeHoldFromServer(holdId: string, automatic: boolean): Promise<HoldResult | null> {\n try {\n const h = await this.controller.resumeHold(holdId);\n if (!h) return null;\n const restored: HoldResult = {\n holdId: h.holdId,\n expiresAt: h.expiresAt,\n seats: h.seats,\n items: h.items,\n };\n this.hold = restored;\n // A resumed capability came from an earlier checkout handoff. Keep it\n // alive if this picker mount is refreshed or torn down before the buyer\n // explicitly removes/releases it.\n this.handedOff = true;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.startHoldTimer(restored.expiresAt);\n this.rememberHold(restored);\n this.syncTray();\n this.emitHoldChange();\n this.opts.onHoldRestored?.(restored, restored.seats ?? [], this.buildHandoff(restored));\n if (automatic) this.toast('Your held tickets have been restored.', 'success');\n return restored;\n } catch (error) {\n const status = (error as { status?: number })?.status;\n if (status === 404 || status === 409) {\n // A stale/foreign/settled capability is expected recovery state, not a\n // picker failure. Drop it and let the buyer choose again.\n this.forgetHold();\n } else {\n this.opts.onError?.(error);\n }\n return null;\n }\n }\n\n private async restoreRememberedHold(): Promise<void> {\n const holdId = this.rememberedHoldId();\n if (holdId) await this.resumeHoldFromServer(holdId, true);\n }\n\n /** Section-bearing objects on the active floor (single-floor → doc.objects). */\n private activeFloorObjects(): SectionLike[] {\n const doc = this.controller.doc;\n if (!doc) return [];\n const floors = doc.floors;\n if (floors?.length) {\n const id = this.controller.getActiveFloorId();\n return ((floors.find((f) => f.id === id) ?? floors[0]).objects as unknown as SectionLike[]) ?? [];\n }\n return (doc.objects as unknown as SectionLike[]) ?? [];\n }\n\n /**\n * Build the overview minimap: a static venue thumbnail (section outlines, or\n * seat dots when the chart has no sections) with the live viewport rectangle\n * drawn on top. The rect tracks pan/zoom via the constructor's onViewChange.\n */\n private buildMinimap(): void {\n const vp = this.controller.getViewport();\n if (!vp || !this.els.map) return;\n const b = vp.bounds;\n if (!(b.width > 0 && b.height > 0)) return;\n\n const MAXW = 158;\n const MAXH = 118;\n const PAD = 6;\n const aspect = b.width / Math.max(1, b.height);\n let w = MAXW;\n let h = Math.round(MAXW / aspect);\n if (h > MAXH) {\n h = MAXH;\n w = Math.round(MAXH * aspect);\n }\n w = Math.max(64, w);\n h = Math.max(48, h);\n const dpr = Math.min(2, window.devicePixelRatio || 1);\n\n const wrap = document.createElement('div');\n wrap.className = 'sl-minimap';\n wrap.setAttribute('aria-hidden', 'true'); // decorative; the map itself is the keyboard surface\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(w * dpr);\n canvas.height = Math.round(h * dpr);\n canvas.style.width = `${w}px`;\n canvas.style.height = `${h}px`;\n wrap.appendChild(canvas);\n (this.regions['bottom-left'] ?? this.els.map).appendChild(wrap);\n this.miniCanvas = canvas;\n\n // world → minimap (device px), contain + centre — matches thumb.ts.\n const scale = Math.min((w - PAD * 2) / Math.max(1, b.width), (h - PAD * 2) / Math.max(1, b.height)) * dpr;\n const offX = (w * dpr - b.width * scale) / 2 - b.x * scale;\n const offY = (h * dpr - b.height * scale) / 2 - b.y * scale;\n this.miniTf = { scale, offX, offY, dpr };\n\n const base = document.createElement('canvas');\n base.width = canvas.width;\n base.height = canvas.height;\n this.miniBase = base;\n\n // Click a section on the minimap → glide the camera into it (existing API).\n wrap.addEventListener('click', (e) => this.minimapJump(e));\n\n this.drawMinimapStatic();\n this.drawMinimapRect();\n }\n\n /** Repaint the static overview + rect (floor switch, live open/close). */\n private refreshMinimap(): void {\n if (!this.miniBase) return;\n this.drawMinimapStatic();\n this.drawMinimapRect();\n }\n\n /** Paint the venue overview into the offscreen base canvas. */\n private drawMinimapStatic(): void {\n const base = this.miniBase;\n const tf = this.miniTf;\n const doc = this.controller.doc;\n if (!base || !tf || !doc) return;\n const ctx = base.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, base.width, base.height);\n const fx = (x: number): number => x * tf.scale + tf.offX;\n const fy = (y: number): number => y * tf.scale + tf.offY;\n const line = this.cssVar('--sl-line') || 'rgba(139,147,167,.5)';\n const muted = this.cssVar('--sl-muted') || '#8b93a7';\n const accent = this.cssVar('--sl-accent') || '#6e7bff';\n const zoneColor = new Map((doc.zones ?? []).map((z) => [z.id, z.color] as const));\n\n let drewSection = false;\n for (const o of this.activeFloorObjects()) {\n if (o.type !== 'section' || !o.outline || o.outline.length < 3) continue;\n drewSection = true;\n const closed = this.controller.isSectionClosed(o.id);\n const fill = closed ? muted : o.color ?? (o.zone && zoneColor.get(o.zone)) ?? accent;\n ctx.beginPath();\n o.outline.forEach((p, i) => (i === 0 ? ctx.moveTo(fx(p.x), fy(p.y)) : ctx.lineTo(fx(p.x), fy(p.y))));\n ctx.closePath();\n ctx.globalAlpha = closed ? 0.26 : 0.42;\n ctx.fillStyle = fill;\n ctx.fill();\n ctx.globalAlpha = 0.85;\n ctx.lineWidth = Math.max(1, tf.dpr);\n ctx.strokeStyle = line;\n ctx.stroke();\n }\n ctx.globalAlpha = 1;\n\n // Section-less charts: fall back to faint category-colored seat dots.\n if (!drewSection) {\n const r = Math.max(1, tf.dpr);\n for (const seat of expandChart(doc)) {\n const cat = doc.categories.find((c) => c.key === seat.categoryKey);\n ctx.fillStyle = cat?.color ?? accent;\n ctx.beginPath();\n ctx.arc(fx(seat.x), fy(seat.y), r, 0, Math.PI * 2);\n ctx.fill();\n }\n }\n }\n\n /** Blit the base overview, then stroke the current viewport rectangle on top. */\n private drawMinimapRect(): void {\n const canvas = this.miniCanvas;\n const base = this.miniBase;\n const tf = this.miniTf;\n if (!canvas || !base || !tf) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(base, 0, 0);\n const vp = this.controller.getViewport();\n if (!vp) return;\n const v = vp.visible;\n const x = v.x * tf.scale + tf.offX;\n const y = v.y * tf.scale + tf.offY;\n const w = v.width * tf.scale;\n const h = v.height * tf.scale;\n const accent = this.cssVar('--sl-accent') || '#f4b740';\n ctx.save();\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = accent;\n ctx.fillRect(x, y, w, h);\n ctx.globalAlpha = 1;\n ctx.lineWidth = Math.max(1.5, tf.dpr * 1.5);\n ctx.strokeStyle = accent;\n ctx.strokeRect(x, y, w, h);\n ctx.restore();\n }\n\n /** Minimap click → focus the section under the point (or overview on a miss). */\n private minimapJump(e: MouseEvent): void {\n const canvas = this.miniCanvas;\n const tf = this.miniTf;\n if (!canvas || !tf) return;\n const r = canvas.getBoundingClientRect();\n const px = (e.clientX - r.left) * (canvas.width / r.width);\n const py = (e.clientY - r.top) * (canvas.height / r.height);\n const wx = (px - tf.offX) / tf.scale;\n const wy = (py - tf.offY) / tf.scale;\n for (const o of this.activeFloorObjects()) {\n if (o.type !== 'section' || !o.outline || o.outline.length < 3) continue;\n if (this.controller.isSectionClosed(o.id)) continue;\n if (pointInPolygon(wx, wy, o.outline)) {\n this.controller.focusSection(o.id);\n return;\n }\n }\n this.controller.overview();\n }\n\n // ---- F4 price-band filter -------------------------------------------------\n\n /** Effective display price of a category: host pricing override → first tier → base. */\n private catPrice(c: { key?: string; price?: number; tiers?: { id?: string; price: number }[] }): number | undefined {\n const chart = c.tiers?.length ? c.tiers[0].price : c.price;\n if (chart === undefined || !c.key) return chart;\n return this.paidPrice(c.key, c.tiers?.[0]?.id ?? null, chart);\n }\n\n /** Derive price bands: one chip per distinct price (≤5), else quantile ranges. */\n private priceBands(): PriceBand[] {\n const doc = this.controller.doc;\n if (!doc) return [];\n const priced = doc.categories\n .map((c) => ({ key: c.key, price: this.catPrice(c) }))\n .filter((x): x is { key: string; price: number } => x.price != null);\n if (!priced.length) return [];\n const distinct = [...new Set(priced.map((p) => p.price))].sort((a, b) => a - b);\n if (distinct.length <= 5) {\n return distinct.map((price) => ({\n id: `p${price}`,\n label: this.money(price),\n keys: priced.filter((p) => p.price === price).map((p) => p.key),\n min: price,\n max: price,\n }));\n }\n // Many distinct prices → ~4 contiguous quantile bands (ranges).\n const chunk = Math.ceil(distinct.length / 4);\n const bands: PriceBand[] = [];\n for (let i = 0; i < distinct.length; i += chunk) {\n const slice = distinct.slice(i, i + chunk);\n const lo = slice[0];\n const hi = slice[slice.length - 1];\n bands.push({\n id: `b${i}`,\n label: lo === hi ? this.money(lo) : `${this.money(lo)}–${this.money(hi)}`,\n keys: priced.filter((p) => p.price >= lo && p.price <= hi).map((p) => p.key),\n min: lo,\n max: hi,\n });\n }\n return bands;\n }\n\n /** Build the compact price selector in the panel header. Choosing a band both\n * filters availability and smoothly frames the matching seats on the map. */\n private buildPriceFilter(): void {\n if (!this.els.prices || !this.els.pricesSec) return;\n const bands = this.priceBands();\n if (bands.length < 2) return;\n const select = document.createElement('select');\n select.className = 'sl-price-select';\n select.setAttribute('aria-label', 'Filter and focus seats by price');\n select.innerHTML = `<option value=\"all\">All prices</option>` + bands\n .map((band) => `<option value=\"${band.id}\">${band.label}</option>`)\n .join('');\n this.els.pricesSec.appendChild(select);\n select.addEventListener('change', () => {\n const band = bands.find((candidate) => candidate.id === select.value);\n const keys = band?.keys ?? null;\n this.focusedCatKey = null; // band filter supersedes any pinned row focus\n this.priceBandKeys = keys ? new Set(keys) : null;\n this.controller.setCategoryFilter(keys);\n this.controller.focusCategoryFilter(keys);\n // The band has to survive a switch into 3D, which paints from its own\n // state snapshot rather than from Konva opacity.\n this.pushAvailabilityTo3d();\n // A band whose seats live on another deck switches floors — mirror it.\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n // Reflect the band in the legend rows + any open section card.\n this.syncPrices();\n if (this.lastSection) this.showSectionCard(this.lastSection);\n });\n }\n\n // ---- arena / multi-floor chrome -------------------------------------------\n\n /** Build projection, rung and floor controls for arena-scale charts. */\n private buildArenaChrome(): void {\n const doc = this.controller.doc;\n if (!doc || !this.els.map) return;\n const hasSections = doc.objects.some((o) => o.type === 'section')\n || (doc.floors ?? []).some((f) => f.objects.some((o) => o.type === 'section'));\n\n // Buyer view toggle: **Map | 3D** (2.5D/perspective is retired from the buyer\n // surface). The 3D button is offered only when 3D is enabled AND the browser\n // exposes WebGL2 — otherwise the picker stays a plain flat map with no toggle\n // at all. Available for ANY chart with a real 3D relief source, not just\n // sectioned venues.\n if (this.canOffer3d()) {\n const projection = document.createElement('div');\n projection.className = 'sl-projection';\n projection.setAttribute('role', 'group');\n projection.setAttribute('aria-label', 'Venue view');\n projection.innerHTML =\n '<button type=\"button\" data-view=\"map\" aria-pressed=\"true\" title=\"Flat 2D map\">Map</button>' +\n '<button type=\"button\" data-view=\"venue3d\" aria-pressed=\"false\" title=\"Interactive 3D venue view\">3D</button>';\n projection.querySelectorAll<HTMLButtonElement>('button').forEach((button) => {\n button.addEventListener('click', () => {\n this.setBuyerView(button.dataset.view as 'map' | 'venue3d');\n });\n });\n this.regions['top-right'].appendChild(projection);\n this.projectionEl = projection;\n this.syncProjection();\n }\n\n // LOD rung pills — jump straight between zones / sections / seats.\n if (hasSections) {\n const RUNGS: LodRung[] = ['zones', 'sections', 'seats'];\n const pills = document.createElement('div');\n pills.className = 'sl-rungs on';\n pills.setAttribute('role', 'group');\n pills.setAttribute('aria-label', t('picker.zoomLevel'));\n const LABEL: Record<LodRung, string> = {\n zones: t('picker.rungLabel.zones'),\n sections: t('picker.rungLabel.sections'),\n seats: t('picker.rungLabel.seats'),\n };\n const TIP: Record<LodRung, string> = {\n zones: t('picker.rungTip.zones'),\n sections: t('picker.rungTip.sections'),\n seats: t('picker.rungTip.seats'),\n };\n pills.innerHTML = RUNGS.map(\n (r) => `<button type=\"button\" data-rung=\"${r}\" title=\"${TIP[r]}\" aria-pressed=\"false\">${LABEL[r]}</button>`,\n ).join('');\n pills.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.addEventListener('click', () => {\n const rung = btn.dataset.rung as LodRung;\n this.controller.setRung(rung);\n if (rung === 'seats') this.collapseSectionCard();\n });\n });\n this.regions['top-center'].appendChild(pills);\n this.rungsEl = pills;\n this.syncRung();\n }\n\n // Multi-floor switcher — only when the chart truly has >1 floor.\n if (this.controller.isMultiFloor()) {\n const floors = this.controller.getFloors();\n const rail = document.createElement('div');\n rail.className = 'sl-floors on';\n rail.setAttribute('role', 'group');\n rail.setAttribute('aria-label', t('picker.floor'));\n rail.innerHTML = floors\n .map((f) => `<button type=\"button\" data-floor=\"${f.id}\">${f.name}</button>`)\n .join('');\n rail.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.controller.setFloor(btn.dataset.floor!);\n this.showSectionCard(null);\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n });\n });\n this.regions['left-rail'].appendChild(rail);\n this.floorsEl = rail;\n this.syncFloors();\n }\n }\n\n /** Reflect the engine's current LOD rung onto the pill group. */\n private syncRung(): void {\n if (!this.rungsEl) return;\n const active = this.controller.getRung();\n this.rungsEl.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n const on = btn.dataset.rung === active;\n btn.classList.toggle('on', on);\n btn.setAttribute('aria-pressed', String(on));\n });\n }\n\n private syncProjection(): void {\n if (!this.projectionEl) return;\n this.projectionEl.querySelectorAll<HTMLButtonElement>('button').forEach((button) => {\n const on = button.dataset.view === this.buyerView;\n button.classList.toggle('on', on);\n button.setAttribute('aria-pressed', String(on));\n });\n }\n\n /** Can this picker offer the 3D venue view? Requires the option (default on),\n * WebGL2, a chart to render, and a chart small enough to render WELL. */\n private canOffer3d(): boolean {\n if (this.opts.enable3D === false || !this.controller.doc || !hasWebGL2()) return false;\n return this.allSeats().length <= this.max3dSeats();\n }\n\n /**\n * The seat ceiling for offering 3D. See `max3DSeats` — an explicit host value\n * always wins; otherwise a small/low-core device gets half the desktop budget,\n * because it is the device that turns \"slow\" into \"stalled\".\n */\n private max3dSeats(): number {\n const authored = this.opts.max3DSeats;\n if (typeof authored === 'number' && authored > 0) return authored;\n const nav = globalThis.navigator as (Navigator & { deviceMemory?: number }) | undefined;\n const small = (nav?.hardwareConcurrency ?? 8) <= 4\n || (nav?.deviceMemory ?? 8) <= 4\n || (globalThis.matchMedia?.('(pointer: coarse)').matches ?? false);\n return small ? MAX_3D_SEATS_DEFAULT / 2 : MAX_3D_SEATS_DEFAULT;\n }\n\n /** Reflect the active floor onto the switcher rail. */\n private syncFloors(): void {\n if (!this.floorsEl) return;\n const active = this.controller.getActiveFloorId();\n this.floorsEl.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.classList.toggle('on', btn.dataset.floor === active);\n });\n }\n\n /** Show (or clear, on null) the tapped-section summary card. */\n private showSectionCard(summary: SectionSummary | null): void {\n this.lastSection = summary;\n this.secCardEl?.remove();\n this.secCardEl = null;\n if (!summary) return;\n // At seat level the summary is context, not a blocking decision surface.\n // Keep it as the compact pill from the first seat-level paint.\n this.secCardCollapsed = this.controller.getRung() === 'seats';\n this.secCardShownAt = Date.now();\n this.renderSectionCard(summary);\n }\n\n /**\n * Render the section card in the form the layout + state want: expanded card\n * or slim pill in the top-center anchor region (wide), or a compact strip in\n * the sheet head (narrow). Never floats over the seats at the tap point.\n */\n private renderSectionCard(summary: SectionSummary): void {\n if (!this.els.map) return;\n this.secCardEl?.remove();\n // min/max over the section's categories at the price the buyer will PAY\n // (host pricing override aware) — not the chart's stored range.\n const paid = summary.categories.length\n ? summary.categories.map((c) => this.paidPrice(c.key, null, c.price))\n : [summary.priceMin, summary.priceMax];\n const paidMin = Math.min(...paid);\n const paidMax = Math.max(...paid);\n const priceLabel =\n paidMin === paidMax\n ? this.money(paidMin)\n : `${this.money(paidMin)}–${this.money(paidMax)}`;\n const leftLabel = tCount('picker.seatsLeftInSection', summary.seatsLeft);\n const xBtn = `<button type=\"button\" class=\"sl-seccard-x\" aria-label=\"${t('picker.closeSectionSummary')}\">✕</button>`;\n const card = document.createElement('div');\n const narrow = this.root?.dataset.layout === 'narrow';\n\n if (narrow) {\n // Compact strip inside the bottom sheet's peek head — never over the map.\n card.className = 'sl-seccard strip on';\n card.setAttribute('role', 'status');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n card.innerHTML =\n `<span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span>` +\n (summary.categories.length ? `<span class=\"sl-seccard-price\">${priceLabel}</span>` : '') +\n xBtn;\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n (this.els.sheetHead ?? this.els.side ?? this.els.map).appendChild(card);\n } else if (this.secCardCollapsed) {\n // Slim pill — seat-picking has begun. Tap to re-expand; ✕ still closes.\n card.className = 'sl-seccard mini on';\n card.setAttribute('role', 'button');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n card.innerHTML =\n `<span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span>` +\n xBtn;\n card.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.sl-seccard-x')) return;\n this.secCardCollapsed = false;\n this.secCardShownAt = Date.now();\n this.renderSectionCard(summary);\n });\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n (this.regions['top-center'] ?? this.els.map).appendChild(card);\n } else {\n card.className = 'sl-seccard on';\n card.setAttribute('role', 'dialog');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n const mix = summary.categories\n .map((c) => {\n const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);\n return (\n `<span class=\"sl-seccard-mix-item${dim ? ' sl-dim' : ''}\"><span class=\"sl-seccard-mix-dot\" style=\"background:${c.color}\"></span>` +\n `${c.label} <span class=\"sl-seccard-mix-price\">${this.money(this.paidPrice(c.key, null, c.price))}</span></span>`\n );\n })\n .join('');\n card.innerHTML =\n `<div class=\"sl-seccard-head\"><span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n (summary.categories.length ? `<span class=\"sl-seccard-price\">${priceLabel}</span>` : '') +\n xBtn + `</div>` +\n `<div class=\"sl-seccard-zone\">${summary.zoneLabel ? `${summary.zoneLabel} · ` : ''}` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span></div>` +\n (summary.entrance\n ? `<div class=\"sl-seccard-entrance\">${t('picker.entrance')} ${String(summary.entrance).replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!))}</div>`\n : '') +\n (mix ? `<div class=\"sl-seccard-mix\">${mix}</div>` : '') +\n `<div class=\"sl-seccard-foot\">` +\n `<button type=\"button\" class=\"sl-seccard-overview\">← ${t('picker.overview')}</button>` +\n `<span class=\"sl-seccard-hint\">${t('picker.tapSeatHint')}</span></div>`;\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n card.querySelector('.sl-seccard-overview')!.addEventListener('click', () => this.controller.overview());\n (this.regions['top-center'] ?? this.els.map).appendChild(card);\n }\n this.secCardEl = card;\n }\n\n /** Collapse the expanded card to its slim pill (seat-picking started). */\n private collapseSectionCard(): void {\n if (!this.secCardEl || this.secCardCollapsed || !this.lastSection) return;\n if (this.root?.dataset.layout === 'narrow') return; // strip is already compact\n this.secCardCollapsed = true;\n this.renderSectionCard(this.lastSection);\n }\n\n /**\n * onViewChange hook for the card. The focus glide's own settle (within the\n * grace window) enforces the ~25% coverage rule with the FINAL viewport; any\n * later pan/zoom means seat-picking has begun → collapse to the pill.\n */\n private sectionCardOnView(): void {\n if (!this.secCardEl || this.secCardCollapsed || !this.lastSection) return;\n if (this.root?.dataset.layout === 'narrow') return;\n if (this.controller.getRung() === 'seats') {\n this.collapseSectionCard();\n return;\n }\n if (Date.now() - this.secCardShownAt < 1400) {\n if (this.sectionCardCoverage() > 0.25) this.collapseSectionCard();\n return;\n }\n this.collapseSectionCard();\n }\n\n /** Fraction of the focused section's on-screen bbox covered by the card. */\n private sectionCardCoverage(): number {\n const card = this.secCardEl;\n const sec = this.lastSection;\n if (!card || !sec || !this.els.map) return 0;\n const outline = this.activeFloorObjects().find((o) => o.type === 'section' && o.id === sec.id)?.outline;\n if (!outline || outline.length < 3) return 0;\n const pts = outline.map((p) => this.controller.worldToScreen(p));\n const xs = pts.map((p) => p.x);\n const ys = pts.map((p) => p.y);\n const bx = Math.min(...xs);\n const by = Math.min(...ys);\n const bw = Math.max(...xs) - bx;\n const bh = Math.max(...ys) - by;\n if (bw <= 0 || bh <= 0) return 0;\n const mapR = this.els.map.getBoundingClientRect();\n const cr = card.getBoundingClientRect();\n const cx = cr.left - mapR.left;\n const cy = cr.top - mapR.top;\n const ox = Math.max(0, Math.min(cx + cr.width, bx + bw) - Math.max(cx, bx));\n const oy = Math.max(0, Math.min(cy + cr.height, by + bh) - Math.max(cy, by));\n return (ox * oy) / (bw * bh);\n }\n\n /** aria-live readout when keyboard focus lands on a seat. */\n private announceSeat(seat: ExpandedSeat | null): void {\n if (!this.srEl) return;\n if (!seat) {\n this.srEl.textContent = '';\n return;\n }\n const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);\n const status = this.controller.getStatus(seat.id) ?? 'free';\n const statusText = status === 'free' ? 'available' : status === 'held' ? 'on hold' : 'taken';\n const price = cat ? this.catPrice(cat) : undefined;\n const table = this.controller.tableSelection(seat.id);\n const details = table ?? this.controller.seatDetails(seat.id);\n const typeWord = this.rowTypeWord(details);\n const buyerName = details?.rowLabel ?? details?.displayLabel ?? seat.displayLabel ?? seat.label;\n const identity = table\n ? `${typeWord} ${buyerName}, ${table.bookingMode === 'variable' ? `${table.minOccupancy} to ${table.maxOccupancy} guests` : `${table.capacity} guests`}`\n : details?.objectType === 'booth'\n ? `${typeWord} ${buyerName}`\n : details?.objectType === 'table'\n ? `${typeWord} ${buyerName}, seat ${details.seatNumber ?? seat.label}`\n : `Seat ${details?.displayLabel ?? seat.displayLabel ?? seat.label}`;\n this.srEl.textContent = `${identity}, ${cat?.label ?? seat.categoryKey}${\n price != null ? `, ${this.money(price)}` : ''\n }, ${statusText}`;\n }\n\n // ---- atomic table confirmation / guest quantity ---------------------------\n\n private showTableDialog(\n table: TableSelectionDetails,\n held: boolean,\n returnFocus?: HTMLElement | null,\n ): void {\n this.dismissTableDialog(false);\n this.tableDialog = { ...table };\n this.tableDialogHeld = held;\n this.tableDialogReturnFocus = returnFocus ?? (document.activeElement as HTMLElement | null);\n const esc = (value: unknown): string => String(value ?? '').replace(/[&<>\"']/g, (ch) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;',\n })[ch]!);\n const cat = this.controller.doc?.categories.find((candidate) => candidate.key === table.categoryKey);\n const variable = table.bookingMode === 'variable';\n const typeWord = this.rowTypeWord(table);\n const el = document.createElement('div');\n el.className = 'sl-table-scrim';\n el.innerHTML =\n `<section class=\"sl-table-dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-table-title\" aria-describedby=\"sl-table-copy\">` +\n `<div class=\"sl-table-head\"><div class=\"sl-table-eyebrow\">${esc(variable ? `Flexible party · ${typeWord}` : `Whole ${typeWord}`)}</div>` +\n `<h2 class=\"sl-table-title\" id=\"sl-table-title\">${esc(table.displayLabel ?? table.label)}</h2>` +\n `<p class=\"sl-table-copy\" id=\"sl-table-copy\">${variable\n ? `Choose how many guests will sit together. This table is held exclusively for your party.`\n : `All ${table.capacity} places are booked together as one exclusive table.`}</p></div>` +\n `<div class=\"sl-table-body\">` +\n `<div class=\"sl-table-summary\"><span>${esc(cat?.label ?? table.categoryKey)}</span><b data-table-unit>${this.money(this.paidPrice(table.categoryKey, table.tierId ?? null, table.price))} per guest</b>` +\n `<span class=\"muted\">Table capacity</span><span>${table.capacity} guests</span>` +\n `<span class=\"muted\">Total</span><b data-table-total></b></div>` +\n (variable\n ? `<label class=\"sl-table-qtylabel\" id=\"sl-table-qty-label\">Number of guests</label>` +\n `<div class=\"sl-table-stepper\" role=\"group\" aria-labelledby=\"sl-table-qty-label\">` +\n `<button type=\"button\" data-table-step=\"-1\" aria-label=\"Fewer guests\">−</button>` +\n `<output aria-live=\"polite\" data-table-qty>${table.quantity}</output>` +\n `<button type=\"button\" data-table-step=\"1\" aria-label=\"More guests\">+</button></div>` +\n `<div class=\"sl-table-range\">Choose ${table.minOccupancy}–${table.maxOccupancy} guests</div>`\n : `<input type=\"hidden\" data-table-qty value=\"${table.capacity}\">`) +\n `<div class=\"sl-table-actions\"><button type=\"button\" class=\"sl-table-cancel\">Cancel</button>` +\n `<button type=\"button\" class=\"sl-table-confirm\">${held ? 'Update table' : variable ? 'Select table' : 'Select whole table'}</button></div>` +\n `</div></section>`;\n this.root!.appendChild(el);\n this.tableDialogEl = el;\n this.renderTableDialogState();\n\n el.querySelectorAll<HTMLButtonElement>('[data-table-step]').forEach((button) => {\n button.addEventListener('click', () => {\n if (!this.tableDialog) return;\n const next = Math.max(\n this.tableDialog.minOccupancy,\n Math.min(this.tableDialog.maxOccupancy, this.tableDialog.quantity + Number(button.dataset.tableStep)),\n );\n this.tableDialog = { ...this.tableDialog, quantity: next };\n this.renderTableDialogState();\n });\n });\n el.querySelector<HTMLButtonElement>('.sl-table-cancel')!.addEventListener('click', () => this.cancelTableDialog());\n el.querySelector<HTMLButtonElement>('.sl-table-confirm')!.addEventListener('click', () => void this.confirmTableDialog());\n el.addEventListener('mousedown', (event) => {\n if (event.target === el) this.cancelTableDialog();\n });\n el.addEventListener('keydown', (event) => {\n if (event.key !== 'Tab') return;\n const focusable = [...el.querySelectorAll<HTMLElement>('button:not(:disabled),[tabindex]:not([tabindex=\"-1\"])')];\n if (!focusable.length) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n });\n requestAnimationFrame(() => (\n el.querySelector<HTMLButtonElement>(variable ? '[data-table-step=\"-1\"]' : '.sl-table-confirm')?.focus()\n ));\n }\n\n private renderTableDialogState(): void {\n const table = this.tableDialog;\n const el = this.tableDialogEl;\n if (!table || !el) return;\n const output = el.querySelector<HTMLOutputElement>('output[data-table-qty]');\n if (output) output.value = String(table.quantity);\n const hidden = el.querySelector<HTMLInputElement>('input[data-table-qty]');\n if (hidden) hidden.value = String(table.quantity);\n el.querySelectorAll<HTMLButtonElement>('[data-table-step]').forEach((button) => {\n const delta = Number(button.dataset.tableStep);\n button.disabled = delta < 0\n ? table.quantity <= table.minOccupancy\n : table.quantity >= table.maxOccupancy;\n });\n const unit = this.paidPrice(table.categoryKey, table.tierId ?? null, table.price);\n const total = el.querySelector<HTMLElement>('[data-table-total]');\n if (total) total.textContent = this.money(unit * table.quantity);\n }\n\n private async confirmTableDialog(): Promise<void> {\n const table = this.tableDialog;\n const held = this.tableDialogHeld;\n if (!table) return;\n const button = this.tableDialogEl?.querySelector<HTMLButtonElement>('.sl-table-confirm');\n if (button) {\n button.disabled = true;\n button.textContent = held ? 'Updating…' : 'Selecting…';\n }\n if (held) {\n try {\n const updated = await this.controller.replaceTableQuantity(table.label, table.quantity, this.opts.holdTtlMs);\n if (!updated) {\n this.toast('That guest count could not be secured. Your current table hold is unchanged.', 'warning');\n this.renderTableDialogState();\n if (button) {\n button.disabled = false;\n button.textContent = 'Update table';\n }\n return;\n }\n this.hold = {\n holdId: updated.holdId,\n expiresAt: updated.expiresAt,\n seats: updated.seats,\n items: updated.items,\n };\n this.startHoldTimer(updated.expiresAt);\n this.dismissTableDialog();\n this.syncTray();\n this.emitHoldChange();\n this.toast(`${table.label} updated for ${table.quantity} guests.`, 'success');\n } catch (error) {\n this.opts.onError?.(error);\n this.toast('That guest count is no longer available. Your current hold is unchanged.', 'error');\n if (button) {\n button.disabled = false;\n button.textContent = 'Update table';\n }\n }\n return;\n }\n\n if (!this.controller.setTableQuantity(table.label, table.quantity)) {\n if (button) {\n button.disabled = false;\n button.textContent = table.bookingMode === 'variable' ? 'Select table' : 'Select whole table';\n }\n return;\n }\n this.dismissTableDialog();\n this.collapseSectionCard();\n this.syncTray();\n }\n\n private cancelTableDialog(): void {\n const table = this.tableDialog;\n const held = this.tableDialogHeld;\n this.dismissTableDialog();\n if (table && !held) this.controller.deselect(table.physicalSeatIds);\n }\n\n private dismissTableDialog(restoreFocus = true): void {\n const focus = this.tableDialogReturnFocus;\n this.tableDialogEl?.remove();\n this.tableDialogEl = null;\n this.tableDialog = null;\n this.tableDialogHeld = false;\n this.tableDialogReturnFocus = null;\n if (restoreFocus) requestAnimationFrame(() => (focus?.isConnected ? focus : this.root)?.focus());\n }\n\n // ---- seat candidate confirmation ------------------------------------------\n\n private showConfirm(seat: ExpandedSeat): void {\n const previousId = this.confirmSeat?.id;\n this.confirmEl?.remove();\n this.confirmEl = null;\n this.confirmSeat = seat;\n this.root?.setAttribute('data-confirming', 'true');\n this.controller.setSelectionFocus(seat.id);\n if (previousId && previousId !== seat.id) this.controller.deselect([previousId]);\n if (this.tipEl) this.tipEl.style.display = 'none';\n const details = this.controller.seatDetails(seat.id);\n const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);\n const chartPrice = details?.price ?? (cat?.tiers?.length ? cat.tiers[0].price : cat?.price);\n const price = chartPrice != null\n ? this.paidPrice(seat.categoryKey, details?.tierId ?? cat?.tiers?.[0]?.id ?? null, chartPrice)\n : undefined;\n const safe = (value: unknown): string => String(value ?? '—').replace(/[&<>\"]/g, (char) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\n })[char]!);\n const identityFields = [\n details?.sectionLabel\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">Section</span><span class=\"sl-confirm-value\">${safe(details.sectionLabel)}</span></div>`\n : '',\n details?.rowLabel || details?.objectType === 'booth'\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">${safe(this.rowTypeWord(details))}</span><span class=\"sl-confirm-value\">${safe(this.rowShort(details) ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>`\n : '',\n details?.objectType !== 'booth'\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">Seat</span><span class=\"sl-confirm-value\">${safe(details?.seatNumber ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>`\n : '',\n ].filter(Boolean).join('');\n const el = document.createElement('div');\n el.className = 'sl-confirm';\n el.setAttribute('role', 'dialog');\n el.setAttribute('aria-modal', 'true');\n el.setAttribute('aria-label', `Confirm seat ${seat.label}`);\n el.style.setProperty('--sl-cat', cat?.color ?? '#6e7bff');\n el.innerHTML =\n `<div class=\"sl-confirm-grid\">` +\n identityFields +\n `</div>` +\n `<div class=\"sl-confirm-cat\"><span class=\"sl-dot\" style=\"background:${cat?.color ?? '#6e7bff'}\"></span>` +\n `<span class=\"sl-confirm-cat-name\">${safe(details?.categoryLabel ?? cat?.label ?? seat.categoryKey)}</span>` +\n (price != null ? `<span class=\"sl-confirm-price\">${this.money(price)}</span>` : '') + `</div>` +\n `<div class=\"sl-confirm-body\">` +\n this.wheelchairConfirmHtml(details?.wheelchairSpaceType) +\n this.commercialConfirmHtml(seat.commercial) +\n (this.seatViewEnabled() && this.buyerView !== 'venue3d' ? this.confirmThumbHtml(seat) : '') +\n (this.buyerView === 'venue3d'\n ? `${this.seatConfidenceConfirmHtml(seat, `${details?.displayLabel ?? seat.displayLabel ?? seat.label} · ${price == null ? this.tf('picker.priceNotSupplied', 'Price not supplied') : this.money(price)}`)}<div class=\"sl-confirm-inspect-row\">${this.view3dCompareConfirmHtml(seat)}${this.see3dConfirmHtml()}</div>`\n : this.see3dConfirmHtml()) +\n `<div class=\"sl-confirm-row\">` +\n `<button type=\"button\" class=\"sl-confirm-cancel\">Cancel</button>` +\n `<button type=\"button\" class=\"sl-confirm-add\"><svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M5 12.5l4 4L19 7\"/></svg>Select</button></div></div>`;\n this.els.map.appendChild(el);\n this.confirmEl = el;\n const thumb = el.querySelector<HTMLImageElement>('.sl-confirm-thumb');\n if (thumb && seat.viewUrl) {\n const thumbReference = seat.viewMeta?.previewUrl ?? seat.viewUrl;\n void this.buyerAssetUrls.resolve(thumbReference).then((url) => {\n if (url && el.isConnected && this.confirmEl === el) thumb.src = url;\n }).catch((error) => this.opts.onError?.(error));\n }\n this.reanchorConfirm();\n el.querySelector('.sl-confirm-view')?.addEventListener('click', () => void this.openSeatView(seat));\n el.querySelector('.sl-confirm-confidence')?.addEventListener('click', (event) => {\n this.openSeatConfidencePassport(seat, event.currentTarget instanceof HTMLElement ? event.currentTarget : null);\n });\n el.querySelector('.sl-confirm-compare')?.addEventListener('click', () => this.saveView3dComparisonSeat(seat));\n el.querySelector('.sl-confirm-3d')?.addEventListener('click', () => {\n if (this.buyerView === 'venue3d') {\n // Already immersed — just fly the cinematic to this seat.\n this.dismissConfirm();\n void this.view3dHandle?.flyToSeat(seat.id);\n } else {\n // Enter 3D flying straight to the seat; re-show this card on return.\n this.view3dReturnSeat = seat;\n this.dismissConfirm();\n void this.enter3d(seat.id);\n }\n });\n el.querySelector('.sl-confirm-add')!.addEventListener('click', () => this.commitConfirm());\n el.querySelector('.sl-confirm-cancel')!.addEventListener('click', () => this.cancelConfirm());\n requestAnimationFrame(() => el.querySelector<HTMLButtonElement>('.sl-confirm-add')?.focus());\n }\n\n private reanchorConfirm(): void {\n if (!this.confirmEl || !this.confirmSeat) return;\n // In 3D the seat has no stable 2D screen anchor, so CSS bottom-sheets the\n // card (same treatment as the narrow layout). Nothing to position here.\n if (this.root?.dataset.view3d === 'on') return;\n const p = this.controller.worldToScreen({ x: this.confirmSeat.x, y: this.confirmSeat.y });\n if (this.root?.dataset.layout === 'narrow') return;\n const mapWidth = this.els.map.clientWidth;\n const mapHeight = this.els.map.clientHeight;\n const cardWidth = this.confirmEl.offsetWidth || 276;\n const cardHeight = this.confirmEl.offsetHeight || 230;\n const half = cardWidth / 2 + 12;\n const x = Math.max(half, Math.min(mapWidth - half, p.x));\n const belowFits = p.y + cardHeight + 24 <= mapHeight;\n const placeBelow = p.y < cardHeight + 24 && belowFits;\n this.confirmEl.dataset.placement = placeBelow ? 'below' : 'above';\n this.confirmEl.style.left = `${x}px`;\n this.confirmEl.style.top = `${Math.max(8, Math.min(mapHeight - 8, p.y))}px`;\n }\n\n private dismissConfirm(): void {\n this.confirmEl?.remove();\n this.confirmEl = null;\n this.confirmSeat = null;\n this.root?.removeAttribute('data-confirming');\n this.controller.setSelectionFocus(null);\n }\n\n private commitConfirm(): void {\n if (!this.confirmSeat) return;\n this.dismissConfirm();\n this.collapseSectionCard();\n this.syncTray();\n this.syncSelectionTo3d();\n }\n\n private cancelConfirm(): void {\n const seat = this.confirmSeat;\n if (!seat) return;\n this.controller.deselect([seat.id]);\n if (this.confirmSeat) this.dismissConfirm();\n this.syncSelectionTo3d();\n this.root?.focus({ preventScroll: true });\n }\n\n private closeConfirm(): void {\n this.dismissConfirm();\n }\n\n // ---- 360° view-from-seat modal --------------------------------------------\n\n private seatViewEnabled(): boolean {\n return this.opts.seatView !== false;\n }\n\n /** Every bookable seat (cached) — neighbor heads for the generated panorama. */\n private allSeats(): ExpandedSeat[] {\n if (!this.allSeatsCache) {\n const doc = this.controller.doc;\n this.allSeatsCache = doc ? expandChart(doc) : [];\n }\n return this.allSeatsCache;\n }\n\n /**\n * Open the drag-to-look-around 360° preview for a seat. Uses the organizer's\n * uploaded photo (seat.viewUrl) when present, else a panorama generated from\n * the chart geometry — the stage placed at this seat's true bearing + size.\n * Zero extra dependencies: an equirectangular image panned with `repeat-x`.\n *\n * Async only because the generator is a lazy chunk (see `loadPanorama`); an\n * organizer photo needs no generator and never waits on it. The two callers\n * are click handlers, so nothing observes the promise.\n */\n private async openSeatView(seat: ExpandedSeat): Promise<void> {\n if (!this.root || !this.seatViewEnabled()) return;\n const generation = ++this.seatViewGen;\n\n const doc = this.controller.doc;\n const activeId = this.controller.getActiveFloorId();\n const focal = seat.focalPoint\n ?? doc?.floors?.find((f) => f.id === activeId)?.focalPoint\n ?? doc?.focalPoint\n ?? { x: 0, y: 0 };\n let panoSource: View3DSeatView;\n let caption: string;\n let real = false;\n if (seat.viewUrl) {\n let resolvedUrl: string | null;\n let resolvedPreviewUrl: string | null = null;\n try {\n const previewReference = seat.viewMeta?.previewUrl;\n if (previewReference && previewReference !== seat.viewUrl) {\n // Preserve progressive delivery: fetch only the lightweight first\n // paint now. The sharp source is resolved with Authorization inside\n // the scheduled upgrade below, and is never assigned directly.\n resolvedPreviewUrl = await this.buyerAssetUrls.resolve(previewReference);\n resolvedUrl = seat.viewUrl;\n } else {\n resolvedUrl = await this.buyerAssetUrls.resolve(seat.viewUrl);\n }\n } catch (error) {\n if (generation === this.seatViewGen) this.opts.onError?.(error);\n return;\n }\n if (\n generation !== this.seatViewGen\n || !resolvedUrl\n || (seat.viewMeta?.previewUrl && seat.viewMeta.previewUrl !== seat.viewUrl && !resolvedPreviewUrl)\n || !this.root\n || !this.seatViewEnabled()\n ) return;\n const view: View3DSeatView = {\n url: resolvedUrl,\n ...(resolvedPreviewUrl ? { previewUrl: resolvedPreviewUrl } : {}),\n ...(seat.viewMeta?.sourceWidth !== undefined ? { sourceWidth: seat.viewMeta.sourceWidth } : {}),\n ...(seat.viewMeta?.sourceHeight !== undefined ? { sourceHeight: seat.viewMeta.sourceHeight } : {}),\n ...(seat.viewMeta?.previewWidth !== undefined ? { previewWidth: seat.viewMeta.previewWidth } : {}),\n ...(seat.viewMeta?.previewHeight !== undefined ? { previewHeight: seat.viewMeta.previewHeight } : {}),\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n };\n panoSource = view;\n caption = seatViewDisclosure(view);\n real = isAuthoredSeatView(view);\n } else {\n let pano: PanoramaResult;\n try {\n const { generateSeatPanorama } = await loadPanorama();\n pano = generateSeatPanorama(seat, focal, this.allSeats());\n } catch (err) {\n // The chunk failed to fetch, or the draw threw. Report it and leave the\n // buyer on the map rather than opening an empty viewer.\n if (generation === this.seatViewGen) this.opts.onError?.(err);\n return;\n }\n // Torn down (or another view opened) while the chunk loaded.\n if (generation !== this.seatViewGen || !this.root || !this.seatViewEnabled()) return;\n panoSource = { url: pano.url, generated: true };\n caption = t('picker.illustrationCaption', { m: pano.distanceM });\n }\n\n // Retire any open view HERE, not before the await: two quick taps would\n // otherwise each close nothing and then leave the first viewer orphaned in\n // the DOM. It also means the current view stays up while the chunk loads.\n this.closeSeatView(false);\n\n const el = document.createElement('div');\n el.className = 'sl-view';\n el.setAttribute('role', 'dialog');\n el.setAttribute('aria-label', t('picker.viewFromSeat', { label: seat.label }));\n el.innerHTML =\n `<div class=\"sl-view-head\">` +\n `<span class=\"sl-view-title\">${t('picker.viewFromSeat', { label: seat.label })}</span>` +\n `<span class=\"sl-view-cap\">${caption}</span>` +\n `<button type=\"button\" class=\"sl-view-x\" aria-label=\"Close\">` +\n `<svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg></button></div>` +\n `<div class=\"sl-view-pano\">` +\n `<span class=\"sl-view-badge\">${real ? t('picker.real360') : t('picker.preview')}</span>` +\n `<span class=\"sl-view-hint\">Drag to look around · scroll to zoom</span>` +\n `</div>`;\n this.root.appendChild(el);\n this.viewEl = el;\n\n const pano = el.querySelector<HTMLDivElement>('.sl-view-pano')!;\n const delivery = planPanoramaDelivery(panoSource, browserPanoramaConstraints());\n const loadAbort = new AbortController();\n pano.style.backgroundImage = `url(\"${delivery.initialUrl}\")`;\n let cancelUpgrade = (): void => {};\n if (delivery.upgradeUrl) {\n cancelUpgrade = schedulePanoramaUpgrade(() => {\n void this.buyerAssetUrls.resolve(delivery.upgradeUrl!).then((url) => {\n if (!url || loadAbort.signal.aborted) return null;\n return loadPanoramaImage(url, loadAbort.signal).then(() => url);\n }).then((url) => {\n if (!url || !el.isConnected || loadAbort.signal.aborted) return;\n pano.style.backgroundImage = `url(\"${url}\")`;\n }).catch(() => { /* retain the preview */ });\n });\n }\n\n // Equirectangular pan: repeat-x gives seamless 360° horizontal wrap. The\n // source is a full 180° sphere; showing it raw wastes ~⅔ of the frame on\n // dead sky + black floor. So we WINDOW a ~70° vertical slice (horizon-centred)\n // to fill the viewport height, and clamp the vertical drag to ±35° so the\n // buyer looks around a real seat's field of view, never past the image edge.\n // `zoom` narrows the FOV further (scroll to zoom in); it never widens past 70°.\n const VFOV_DEG = 70;\n const MAX_PITCH_DEG = 35;\n let zoom = 1;\n // The generator draws the STAGE at the image's horizontal centre (yaw 0 =\n // stage). Open with that centre in the middle of the viewport — a view\n // that opens facing away from the stage is disorienting (seat 11G-21\n // owner report). Same default is right for uploaded 360s until Case-1\n // calibration exists. bgW = 2·bgH (2:1 equirect), zoom 1 at open.\n const vh0 = pano.clientHeight || 1;\n const vw0 = pano.clientWidth || 1;\n let posX = -(vh0 * (180 / VFOV_DEG) * 2 / 2 - vw0 / 2);\n let posY = 0;\n const apply = (): void => {\n const h = pano.clientHeight || 1;\n const bgH = h * (180 / VFOV_DEG) * zoom;\n const overV = Math.max(0, bgH - h);\n // Clamp pitch to ±35° of image travel (bgH px map the full 180°), and never\n // past the image edge (overV/2).\n const pitchLimit = Math.min(overV / 2, (MAX_PITCH_DEG / 180) * bgH);\n posY = Math.min(pitchLimit, Math.max(-pitchLimit, posY));\n pano.style.backgroundSize = `auto ${bgH}px`;\n // Horizon-centred: -overV/2 places the image's vertical centre at the\n // viewport centre; `posY` (drag, clamped ±35°) tilts up/down from there.\n pano.style.backgroundPosition = `${posX}px ${posY - overV / 2}px`;\n };\n apply();\n\n let dragging = false;\n let lastX = 0;\n let lastY = 0;\n const onDown = (e: PointerEvent): void => {\n dragging = true;\n lastX = e.clientX;\n lastY = e.clientY;\n pano.classList.add('drag');\n pano.setPointerCapture?.(e.pointerId);\n };\n const onMove = (e: PointerEvent): void => {\n if (!dragging) return;\n posX += e.clientX - lastX;\n posY += e.clientY - lastY;\n lastX = e.clientX;\n lastY = e.clientY;\n apply();\n };\n const onUp = (e: PointerEvent): void => {\n dragging = false;\n pano.classList.remove('drag');\n pano.releasePointerCapture?.(e.pointerId);\n };\n const onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n zoom = Math.min(2.4, Math.max(1, zoom + (e.deltaY < 0 ? 0.12 : -0.12)));\n apply();\n };\n pano.addEventListener('pointerdown', onDown);\n pano.addEventListener('pointermove', onMove);\n pano.addEventListener('pointerup', onUp);\n pano.addEventListener('pointercancel', onUp);\n pano.addEventListener('wheel', onWheel, { passive: false });\n\n const closeBtn = el.querySelector<HTMLButtonElement>('.sl-view-x')!;\n closeBtn.addEventListener('click', () => this.closeSeatView());\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n this.closeSeatView();\n }\n };\n el.addEventListener('keydown', onKey);\n closeBtn.focus();\n\n this.viewCleanup = () => {\n cancelUpgrade();\n loadAbort.abort();\n pano.removeEventListener('pointerdown', onDown);\n pano.removeEventListener('pointermove', onMove);\n pano.removeEventListener('pointerup', onUp);\n pano.removeEventListener('pointercancel', onUp);\n pano.removeEventListener('wheel', onWheel);\n el.removeEventListener('keydown', onKey);\n };\n }\n\n private closeSeatView(cancelPending = true): void {\n if (cancelPending) this.seatViewGen += 1;\n this.viewCleanup?.();\n this.viewCleanup = null;\n this.viewEl?.remove();\n this.viewEl = null;\n }\n\n // ---- chrome sync ----------------------------------------------------------\n\n private money(n: number): string {\n const formatter = this.opts.pricing?.formatter;\n if (formatter) return formatter(n, this.currency);\n try {\n return new Intl.NumberFormat(this.opts.locale, { style: 'currency', currency: this.currency }).format(n);\n } catch {\n return `${n} ${this.currency}`;\n }\n }\n\n /**\n * Sleep until the offer schedule's next known transition, then re-read.\n *\n * A far-away boundary is capped: the wake re-reads, learns the (unchanged)\n * schedule, and re-arms — so a picker left open for days still tracks an\n * organizer's schedule edits at a cost of one request every few hours. No\n * future transition means no timer at all; an event with no releases does\n * zero background traffic. A wake in a hidden tab fetches nothing — the\n * visibilitychange handler owns catching that tab up.\n */\n private scheduleOfferBoundary(availability: TicketOfferAvailability | null): void {\n if (this.offerBoundaryTimer) clearTimeout(this.offerBoundaryTimer);\n this.offerBoundaryTimer = null;\n if (!this.api.availability || this.destroyed) return;\n const now = Date.now();\n const boundary = nextOfferTransitionAt(availability, now);\n if (boundary == null) return;\n // +1s past the boundary so the server's clock has provably crossed it.\n const MAX_SLEEP_MS = 6 * 3600_000;\n const delay = Math.min(Math.max(boundary - now + 1_000, 1_000), MAX_SLEEP_MS);\n this.offerBoundaryTimer = setTimeout(() => {\n this.offerBoundaryTimer = null;\n if (document.hidden) return;\n void this.refreshOfferAvailability(false);\n }, delay);\n }\n\n /** Debounce the no-store offer read behind a burst of seat-status frames. */\n private scheduleOfferRefresh(live: boolean): void {\n if (!this.api.availability || this.destroyed) return;\n if (this.offerRefreshTimer) clearTimeout(this.offerRefreshTimer);\n this.offerRefreshTimer = setTimeout(() => {\n this.offerRefreshTimer = null;\n void this.refreshOfferAvailability(live);\n }, live ? 180 : 0);\n }\n\n /**\n * Pull the server's resolved answer. A failed refresh keeps the last truthful\n * answer: flashing back to a chart price while checkout still charges an\n * offer is worse than a temporarily stale remaining count.\n */\n private async refreshOfferAvailability(live: boolean): Promise<void> {\n if (!this.api.availability || this.destroyed) return;\n try {\n const body = await this.api.availability(this.opts.event, live);\n if (this.destroyed) return;\n const availability = parseTicketOfferAvailability(body);\n if (!availability) return;\n this.offerAvailability = availability;\n this.scheduleOfferBoundary(availability);\n\n // Server offers win for the categories they resolve; an unrelated host\n // override remains the fallback for every category the server omitted.\n const server = ticketOfferPrices(availability);\n const merged = { ...(this.hostPricing?.prices ?? {}), ...server };\n const pricing = Object.keys(merged).length > 0 || this.hostPricing?.formatter\n ? { prices: merged, ...(this.hostPricing?.formatter ? { formatter: this.hostPricing.formatter } : {}) }\n : undefined;\n this.setPricing(pricing);\n this.syncOffer();\n this.opts.onOfferAvailabilityChange?.(availability);\n } catch {\n // The seat map and an open hold remain usable, and the last truthful\n // answer stays on screen. One bounded, visible-only retry so a fault at\n // a price boundary cannot strand a stale card — a persistent outage\n // costs one request per 30s, not a different price on screen.\n if (!this.destroyed && !this.offerBoundaryTimer && !document.hidden) {\n this.offerBoundaryTimer = setTimeout(() => {\n this.offerBoundaryTimer = null;\n if (document.hidden) return;\n void this.refreshOfferAvailability(false);\n }, 30_000);\n }\n }\n }\n\n private offerPrice(categoryKey: string | undefined): TicketOfferPrice | null {\n if (!categoryKey) return null;\n return this.offerAvailability?.prices.find((entry) => entry.categoryKey === categoryKey) ?? null;\n }\n\n /** The compact current/upcoming offer card above Ticket prices. */\n private syncOffer(): void {\n const host = this.els.offer;\n if (!host) return;\n const availability = this.offerAvailability;\n const active = availability?.release ?? null;\n const upcoming = !active ? availability?.upcoming ?? null : null;\n if (!availability || availability.state === 'closed' || availability.state === 'sold-out'\n || (!active && !upcoming)) {\n host.classList.remove('has');\n host.replaceChildren();\n return;\n }\n\n const offer = active ?? upcoming!;\n const main = document.createElement('div');\n main.className = 'sl-offer-main';\n const copy = document.createElement('div');\n copy.className = 'sl-offer-copy';\n const kicker = document.createElement('span');\n kicker.className = 'sl-offer-kicker';\n kicker.textContent = active ? 'Current ticket offer' : 'Upcoming ticket offer';\n const name = document.createElement('strong');\n name.className = 'sl-offer-name';\n name.textContent = offer.name || (active ? 'Current offer' : 'Scheduled offer');\n const line = document.createElement('span');\n line.className = 'sl-offer-line';\n const facts: string[] = [];\n if (active && availability.fromPrice != null) facts.push(this.money(availability.fromPrice / 100));\n if (active && offer.remaining != null) facts.push(`${offer.remaining} available`);\n if (active && offer.endsAt != null) facts.push(`until ${formatWhen(offer.endsAt, this.eventTimezone, this.opts.locale)}`);\n if (upcoming?.startsAt != null) facts.push(`starts ${formatWhen(upcoming.startsAt, this.eventTimezone, this.opts.locale)}`);\n line.textContent = facts.join(' · ');\n copy.append(kicker, name, line);\n\n const info = document.createElement('details');\n info.className = 'sl-offer-info';\n const summary = document.createElement('summary');\n summary.setAttribute('aria-label', `How the ${name.textContent} offer works`);\n summary.textContent = 'i';\n const detail = document.createElement('div');\n detail.className = 'sl-offer-detail';\n detail.textContent = active\n ? `This price applies automatically to eligible seats. Tickets in active carts temporarily reduce the available quantity; released or expired holds return it. When the offer ends, the next matching offer or normal ticket price takes over.`\n : `Tickets are available at their normal price now. This scheduled offer will apply automatically to eligible seats when it starts.`;\n info.append(summary, detail);\n main.append(copy, info);\n host.replaceChildren(main);\n host.classList.add('has');\n }\n\n /**\n * The price the buyer will actually pay for a category (+tier): the host's\n * `pricing` override when present, else the chart's stored price. Every\n * price the widget DISPLAYS or hands off must flow through here — a map\n * that shows one price while checkout charges another destroys trust.\n */\n private paidPrice(categoryKey: string | undefined, tierId: string | null | undefined, fallback: number): number {\n const entry = categoryKey ? this.opts.pricing?.prices?.[categoryKey] : undefined;\n if (entry === undefined) return fallback;\n if (typeof entry === 'number') return entry;\n if (tierId && entry.tiers?.[tierId] !== undefined) return entry.tiers[tierId];\n return entry.base ?? fallback;\n }\n\n private syncPrices(): void {\n const doc = this.controller.doc;\n if (!doc || !this.els.prices) return;\n const left = this.controller.categoryAvailability();\n this.narrateAvailability(doc.categories, left);\n this.syncSoldout(doc.categories, left);\n // Big events ship 10–20 ticket types; an uncapped list shoves \"Your seats\"\n // and the CTA below the fold. Cap the closed list and expand on demand\n // (never hide a single row behind a toggle — that costs more than it saves).\n const PRICE_LIMIT = 5;\n const overflow = doc.categories.length - PRICE_LIMIT;\n const collapsed = overflow > 1 && !this.pricesExpanded;\n const shown = collapsed ? doc.categories.slice(0, PRICE_LIMIT) : doc.categories;\n this.els.prices.classList.toggle('sl-expanded', overflow > 1 && this.pricesExpanded);\n this.els.prices.innerHTML = shown\n .map((c) => {\n const price = this.catPrice(c);\n const offer = this.offerPrice(c.key);\n const previous = offer?.previousPrice != null && offer.previousPrice > offer.price\n ? offer.previousPrice\n : null;\n const active = this.focusedCatKey === c.key;\n const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);\n return (\n `<div class=\"sl-price-row${dim ? ' sl-dim' : ''}${active ? ' sl-active' : ''}\" data-cat=\"${escapeOption(c.key)}\"` +\n ` role=\"button\" tabindex=\"0\" aria-pressed=\"${active}\"` +\n ` title=\"${escapeOption(active ? 'Show all seats' : `Show ${c.label} seats on the map`)}\">` +\n `<span class=\"sl-dot\" style=\"background:${escapeOption(c.color)}\"></span>` +\n `<span class=\"sl-price-label\">${escapeOption(c.label)}` +\n (offer?.offerName ? `<small class=\"sl-price-offer\">${escapeOption(offer.offerName)}</small>` : '') +\n `</span>` +\n `<span class=\"sl-price-left\">${left[c.key] ?? 0} left</span>` +\n (previous != null ? `<span class=\"sl-price-was\">${escapeOption(this.money(previous))}</span>` : '') +\n (price != null ? `<span class=\"sl-price-amt\">${this.money(price)}</span>` : '') +\n `</div>`\n );\n })\n .join('') +\n (overflow > 1\n ? `<button type=\"button\" class=\"sl-price-more\" aria-expanded=\"${!collapsed}\">` +\n (collapsed ? `Show all ${doc.categories.length} ticket types` : 'Show fewer') +\n `</button>`\n : '') +\n `<div class=\"sl-status-key\" aria-label=\"Seat status legend\">` +\n `<span class=\"sl-status-item\"><i class=\"sl-status-icon\" aria-hidden=\"true\">` +\n `<svg viewBox=\"0 0 24 24\"><rect x=\"5\" y=\"10\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 10V7a4 4 0 0 1 8 0v3\"/></svg>` +\n `</i>Temporarily held</span>` +\n `<span class=\"sl-status-item\"><i class=\"sl-status-icon sold\" aria-hidden=\"true\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M7 17L17 7\"/></svg>` +\n `</i>Sold</span>` +\n `</div>`;\n // Legend-hover highlight: dim other categories on the map while hovering a row.\n // Click (or Enter/Space) pins that focus — filter + frame the category on\n // the map; a second click clears it.\n this.els.prices.querySelectorAll<HTMLElement>('.sl-price-row').forEach((row) => {\n row.addEventListener('mouseenter', () => this.controller.getRenderer()?.setCategoryHighlight?.(row.dataset.cat ?? null));\n row.addEventListener('mouseleave', () => this.controller.getRenderer()?.setCategoryHighlight?.(null));\n const toggle = () => this.focusCategory(row.dataset.cat ?? '');\n row.addEventListener('click', toggle);\n row.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle();\n }\n });\n });\n this.els.prices.querySelector<HTMLButtonElement>('.sl-price-more')?.addEventListener('click', () => {\n this.pricesExpanded = !this.pricesExpanded;\n this.syncPrices();\n });\n }\n\n /** Tap a price row → filter + frame that category on the map; tap again to\n * clear. Shares `priceBandKeys` with the band selector so the row-dim state\n * has one source of truth (and each control resets the other). */\n private focusCategory(key: string): void {\n if (!key) return;\n const next = this.focusedCatKey === key ? null : key;\n this.focusedCatKey = next;\n this.priceBandKeys = next ? new Set([next]) : null;\n const select = this.els.pricesSec?.querySelector<HTMLSelectElement>('.sl-price-select');\n if (select) select.value = 'all';\n this.controller.setCategoryFilter(next ? [next] : null);\n this.controller.focusCategoryFilter(next ? [next] : null);\n this.pushAvailabilityTo3d();\n // Focusing a category on another deck switches floors — mirror that onto\n // the floor pills / rung pills / minimap, same as a manual deck switch.\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n this.syncPrices();\n if (this.lastSection) this.showSectionCard(this.lastSection);\n }\n\n /**\n * Live-activity strip: turn WS availability deltas into one quiet line of\n * social proof (\"2 seats just taken in VIP · 118 left\"). Diffs per-category\n * counts on every status change — no per-seat payload needed. Skips the very\n * first computation (initial load is not \"activity\").\n */\n private narrateAvailability(\n categories: Array<{ key: string; label: string }>,\n left: Record<string, number>,\n ): void {\n const textEl = this.els.liveText;\n const prev = this.lastCatAvail;\n this.lastCatAvail = { ...left };\n // A floor switch re-baselines availability (counts are per-rendered-floor,\n // and the post-switch status snapshot lands asynchronously a beat later).\n // Narrating across that window produces a phantom \"N seats just taken\", so\n // stay quiet until the new floor settles — only genuine WS deltas after\n // that are news.\n const floorId = this.controller.getActiveFloorId();\n if (floorId !== this.lastAvailFloorId) {\n this.lastAvailFloorId = floorId;\n this.availQuietUntil = performance.now() + 2000;\n }\n if (!textEl || !prev || performance.now() < this.availQuietUntil) return;\n for (const cat of categories) {\n const before = prev[cat.key];\n const now = left[cat.key] ?? 0;\n if (before === undefined || now >= before) continue;\n const taken = before - now;\n textEl.textContent = `${taken} seat${taken === 1 ? '' : 's'} just taken in ${cat.label} · ${now} left`;\n // Surface the strip only while it carries news, then give the space back.\n this.els.live?.classList.remove('on');\n // Reflow between remove/add restarts the entrance animation on repeats.\n void (this.els.live as HTMLElement | undefined)?.offsetWidth;\n this.els.live?.classList.add('on');\n if (this.liveTimer) clearTimeout(this.liveTimer);\n this.liveTimer = setTimeout(() => this.els.live?.classList.remove('on'), 8000);\n return;\n }\n }\n private lastCatAvail: Record<string, number> | null = null;\n private lastAvailFloorId = '';\n private availQuietUntil = 0;\n private liveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** A live delta took one of OUR selected (not yet held) seats — evict + tell the buyer. */\n private evictTakenSelections(): void {\n // Our own hold's WS echo paints our seats 'held' — never treat those as sniped.\n const ownLabels = new Set<string>([\n ...(this.controller.currentHold()?.labels ?? []),\n ...this.holdingLabels,\n ]);\n const gone = this.controller\n .getSelection()\n .filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? 'free') !== 'free');\n if (!gone.length) return;\n this.controller.deselect(gone.map((s) => s.id));\n this.toast(`Seat ${gone[0].label} was just taken by another buyer.`, 'error');\n }\n\n private syncTray(): void {\n if (!this.els.tray) return;\n this.updateSelectionCapacity();\n const seats = this.committedSelection();\n const gaAreas = this.controller.getGAAreas();\n const heldItems = this.hold?.items ?? [];\n const parts: string[] = [];\n const nextTrayKeys = new Set<string>();\n\n if (!seats.length && !heldItems.length && !gaAreas.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map, or let us pick the best available for you.</div>`);\n } else if (!seats.length && !heldItems.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map — or grab standing tickets below.</div>`);\n }\n\n // Best available is the fastest path for buyers who haven't picked yet —\n // but the moment a seat lands in the tray, the ticket cards own this space.\n // (Busy/confirm states stay visible so an in-flight search isn't cut off.)\n const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();\n if (!this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {\n const cats = this.controller.doc?.categories ?? [];\n const zones = this.controller.getBestAvailableZones();\n if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = '';\n parts.push(this.bestAvailableConfirm\n ? `<div class=\"sl-ba\" role=\"alert\">` +\n `<div class=\"sl-ba-title\"><span class=\"spark\" aria-hidden=\"true\">✦</span>Replace your current choices?</div>` +\n `<div class=\"sl-ba-replace\"><b>We’ll find ${this.baQty} seats together.</b>` +\n `<span>Your manually selected tickets will be removed only after a new group is secured.</span></div>` +\n `<div class=\"sl-ba-actions\"><button type=\"button\" data-ba-cancel>Keep mine</button>` +\n `<button type=\"button\" class=\"replace\" data-ba-replace>Find new seats</button></div></div>`\n : `<div class=\"sl-ba\">` +\n `<div class=\"sl-ba-title\"><span class=\"spark\" aria-hidden=\"true\">✦</span>Find the best seats together</div>` +\n `<div class=\"sl-ba-copy\"><span class=\"wide\">We’ll choose the closest available group for you.</span>` +\n `<span class=\"narrow\">Closest available group, chosen instantly.</span></div>` +\n // Premium quick-pick — present only when the chart actually has premium\n // seats (same present-only philosophy as the a11y filter chips).\n (this.controller.hasPremiumSeats()\n ? `<button type=\"button\" class=\"sl-ba-premium${this.baPremium ? ' on' : ''}\" data-ba-premium aria-pressed=\"${this.baPremium ? 'true' : 'false'}\">` +\n `<span class=\"star\" aria-hidden=\"true\">★</span>${this.tf('picker.bestSeatsPremium', 'Best seats')}</button>`\n : '') +\n (cats.length > 1\n ? `<select aria-label=\"Preferred ticket type\" data-ba-cat>` +\n `<option value=\"\">Any ticket type</option>` +\n cats.map((c) => `<option value=\"${c.key}\"${this.baCat === c.key ? ' selected' : ''}>${c.label}</option>`).join('') +\n `</select>`\n : `<span aria-hidden=\"true\"></span>`) +\n (zones.length\n ? `<select aria-label=\"Preferred venue zone\" data-ba-zone>` +\n `<option value=\"\">Any venue zone</option>` +\n zones.map((zone) => `<option value=\"${escapeOption(zone.id)}\"${this.baZone === zone.id ? ' selected' : ''}>${escapeOption(zone.label)}</option>`).join('') +\n `</select>`\n : '') +\n `<div class=\"sl-ba-qty\">` +\n `<button type=\"button\" data-ba=\"-1\" aria-label=\"Fewer seats\">−</button><span>${this.baQty}</span>` +\n `<button type=\"button\" data-ba=\"1\" aria-label=\"More seats\">+</button></div>` +\n `<button type=\"button\" class=\"sl-ba-go\"${this.bestAvailableBusy ? ' disabled' : ''}>` +\n (this.bestAvailableBusy\n ? `<span class=\"sl-ba-spin\" aria-hidden=\"true\"></span>Finding the best seats…`\n : `Find ${this.baQty} best ${this.baQty === 1 ? 'seat' : 'seats'}`) +\n `</button></div>`);\n }\n\n // Held line items (best-available, completed, or restored). Tier is\n // server-committed, but each item can be released without discarding the\n // rest of the hold.\n // Ticket-card identity grid: SECTION | ROW | SEAT, echoing the confirm\n // popover so the buyer meets the same identity pattern at confirm and in\n // the cart. Falls back to the raw label when spatial context is missing\n // (GA lines, legacy labels).\n const idGrid = (\n seatId: string | null,\n label: string,\n objectType?: HoldLineItem['objectType'] | PickerSeat['objectType'],\n quantity = 1,\n objectId?: string,\n identity?: Partial<PickerSeat>,\n ): string => {\n const esc = (value: unknown): string => String(value ?? '—').replace(/[&<>\"]/g, (char) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\n })[char]!);\n const d = seatId ? this.controller.seatDetails(seatId) : null;\n const area = objectType === 'ga' ? gaAreas.find((candidate) => candidate.id === objectId) : undefined;\n const effectiveType = objectType === 'ga' ? 'ga' : d?.objectType ?? objectType;\n const typeWord = identity?.displayType?.trim()\n || d?.displayType?.trim()\n || area?.displayType?.trim()\n || (effectiveType === 'table' ? 'Table' : effectiveType === 'booth' ? 'Booth' : effectiveType === 'ga' ? 'General admission' : 'Row');\n const buyerName = identity?.rowLabel\n ?? identity?.displayLabel\n ?? d?.rowLabel\n ?? d?.displayLabel\n ?? area?.displayLabel\n ?? area?.label\n ?? label;\n if (effectiveType === 'table' && identity?.bookingMode) {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span>` +\n `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Guests</span><span class=\"val\">${quantity}</span></span></div>`;\n }\n if (effectiveType === 'ga') {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span>` +\n (quantity > 1 ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Tickets</span><span class=\"val\">${quantity}</span></span>` : '') + `</div>`;\n }\n if (effectiveType === 'booth') {\n return `<div class=\"sl-chip-id\">` +\n (d?.sectionLabel ? `<span class=\"fld sec\"><span class=\"sl-chip-eb\">Section</span><span class=\"val\">${esc(d.sectionLabel)}</span></span>` : '') +\n `<span class=\"fld mid\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span></div>`;\n }\n if (!d?.sectionLabel && !d?.rowLabel && !d?.seatNumber) {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">Seat</span><span class=\"val\">${esc(buyerName)}</span></span></div>`;\n }\n return (\n `<div class=\"sl-chip-id\">` +\n (d.sectionLabel ? `<span class=\"fld sec\"><span class=\"sl-chip-eb\">Section</span><span class=\"val\">${esc(d.sectionLabel)}</span></span>` : '') +\n (d.rowLabel ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(this.rowShort(d))}</span></span>` : '') +\n (d.seatNumber ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Seat</span><span class=\"val\">${esc(d.seatNumber)}</span></span>` : '') +\n `</div>`\n );\n };\n // Right icon rail per the canonical mock: remove on top, seat view below.\n const iconRail = (rmAria: string, viewLabel: string | null): string =>\n `<div class=\"sl-chip-rail\">` +\n `<button type=\"button\" class=\"rm\" aria-label=\"${rmAria}\">` +\n `<svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg></button>` +\n (viewLabel\n ? `<button type=\"button\" class=\"view\" data-view-label=\"${viewLabel}\" aria-label=\"${t('picker.viewFromSeat', { label: viewLabel })}\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg></button>`\n : '') +\n `</div>`;\n\n for (const item of heldItems) {\n const itemKey = `held:${item.label}`;\n nextTrayKeys.add(itemKey);\n const cat = this.controller.doc?.categories.find((c) => c.key === item.categoryKey);\n const tierName = item.tierId ? cat?.tiers?.find((ti) => ti.id === item.tierId)?.name : undefined;\n const heldSeat = item.objectType !== 'ga' ? this.controller.seatByLabel(item.label) : null;\n const table = item.objectType === 'table' ? this.controller.tableSelection(item.label) : null;\n const canView = this.seatViewEnabled() && !!heldSeat && item.objectType !== 'table';\n parts.push(\n `<div class=\"sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? '' : ' sl-enter'}\" data-key=\"${itemKey}\" data-held=\"${encodeURIComponent(item.label)}\"${heldSeat ? ` data-locate=\"${heldSeat.id}\"` : ''}>` +\n `<div class=\"sl-chip-main\">` +\n idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? undefined) +\n `<div class=\"sl-chip-sub\">` +\n `<span class=\"sl-ticket-state held\" aria-label=\"Held for you\" title=\"Held for you\">` +\n `<svg viewBox=\"0 0 24 24\"><rect x=\"5\" y=\"10\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 10V7a4 4 0 0 1 8 0v3\"/></svg></span>` +\n `<span class=\"cat\">${cat?.label ?? item.categoryKey}${tierName ? ` · ${tierName}` : ''}</span>` +\n (table?.bookingMode === 'variable'\n ? `<button type=\"button\" class=\"sl-table-edit\" data-table-edit=\"${encodeURIComponent(item.label)}\">${item.quantity ?? 1} guests · Edit</button>`\n : '') +\n this.wheelchairChipMarker(heldSeat?.wheelchairSpaceType) +\n this.commercialChipMarker(heldSeat?.commercial) +\n `<span class=\"amt\">${this.money(this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1))}</span>` +\n `</div></div>` +\n iconRail(`Remove held ticket ${item.label}`, canView ? item.label : null) +\n `</div>`,\n );\n }\n\n const heldLabels = new Set(heldItems.map((item) => item.label));\n const canView = this.seatViewEnabled();\n for (const s of seats.filter((seat) => !heldLabels.has(seat.label))) {\n const itemKey = `seat:${s.id}`;\n nextTrayKeys.add(itemKey);\n const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);\n const tierSelect =\n s.tiers && s.tiers.length\n ? `<select class=\"tier\" data-tier=\"${s.id}\" aria-label=\"${t('picker.ticketTierFor', { label: s.label })}\">` +\n s.tiers\n .map((ti) => `<option value=\"${ti.id}\"${ti.id === s.tierId ? ' selected' : ''}>${ti.name} · ${this.money(this.paidPrice(s.categoryKey, ti.id, ti.price))}</option>`)\n .join('') +\n `</select>`\n : '';\n parts.push(\n `<div class=\"sl-chip${this.lastTrayKeys.has(itemKey) ? '' : ' sl-enter'}\" data-key=\"${itemKey}\" data-seat=\"${s.id}\" data-locate=\"${s.id}\">` +\n `<div class=\"sl-chip-main\">` +\n idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) +\n `<div class=\"sl-chip-sub\">` +\n `<span class=\"sl-ticket-state\" aria-label=\"Selected\" title=\"Selected\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M5 12l4 4L19 6\"/></svg></span>` +\n `<span class=\"cat\">${cat?.label ?? s.categoryKey}</span>` +\n (s.objectType === 'table' && s.bookingMode === 'variable'\n ? `<button type=\"button\" class=\"sl-table-edit\" data-table-edit=\"${encodeURIComponent(s.label)}\">${s.quantity ?? 1} guests · Edit</button>`\n : '') +\n `${this.wheelchairChipMarker(s.wheelchairSpaceType)}${this.commercialChipMarker(s.commercial)}${tierSelect}` +\n `<span class=\"amt\">${this.money(this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1))}</span>` +\n `</div></div>` +\n iconRail(`Remove ${s.label}`, canView && s.objectType !== 'table' ? s.label : null) +\n `</div>`,\n );\n }\n\n for (const area of gaAreas) {\n const qty = this.gaQty.get(area.id) ?? 0;\n parts.push(\n `<div class=\"sl-ga\" data-ga=\"${area.id}\"><div class=\"sl-ga-info\">` +\n `<div class=\"sl-ga-name\">${area.displayLabel ?? area.label}</div>` +\n `<div class=\"sl-ga-sub\">${area.displayType ?? 'General admission'} · ${this.money(this.paidPrice(area.categoryKey, null, area.price))} · ${area.available} left</div></div>` +\n `<div class=\"sl-ga-qty\">` +\n `<button type=\"button\" data-d=\"-1\" aria-label=\"Fewer\">−</button><span>${qty}</span>` +\n `<button type=\"button\" data-d=\"1\" aria-label=\"More\">+</button></div></div>`,\n );\n }\n\n this.els.tray.innerHTML = parts.join('');\n this.lastTrayKeys = nextTrayKeys;\n this.els.tray.querySelectorAll<HTMLButtonElement>('[data-ba]').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.baQty = Math.max(1, Math.min(this.maxTickets, this.baQty + Number(btn.dataset.ba)));\n this.syncTray();\n });\n });\n this.els.tray.querySelector<HTMLSelectElement>('[data-ba-cat]')?.addEventListener('change', (e) => {\n this.baCat = (e.target as HTMLSelectElement).value;\n });\n this.els.tray.querySelector<HTMLSelectElement>('[data-ba-zone]')?.addEventListener('change', (e) => {\n this.baZone = (e.target as HTMLSelectElement).value;\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-premium]')?.addEventListener('click', () => {\n this.baPremium = !this.baPremium;\n this.syncTray();\n });\n this.els.tray.querySelector<HTMLButtonElement>('.sl-ba-go')?.addEventListener('click', () => {\n if (this.pendingSelectionCount() > 0) {\n this.bestAvailableConfirm = true;\n this.syncTray();\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-replace]')?.focus();\n return;\n }\n void this.bestAvailable(this.baQty, this.baCat || undefined, { preferPremium: this.baPremium, zoneId: this.baZone || undefined });\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-cancel]')?.addEventListener('click', () => {\n this.bestAvailableConfirm = false;\n this.syncTray();\n this.els.tray.querySelector<HTMLButtonElement>('.sl-ba-go')?.focus();\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-replace]')?.addEventListener('click', () => {\n this.bestAvailableConfirm = false;\n void this.bestAvailable(this.baQty, this.baCat || undefined, { preferPremium: this.baPremium, zoneId: this.baZone || undefined });\n });\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip .rm').forEach((btn) => {\n btn.addEventListener('click', () => {\n const chip = btn.closest('.sl-chip') as HTMLElement;\n if (chip.dataset.held) {\n void this.removeHeldLabel(decodeURIComponent(chip.dataset.held), chip);\n return;\n }\n const id = chip.dataset.seat!;\n const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? 'Seat';\n const remove = (): void => {\n this.controller.deselect([id]);\n this.toast(`${label} removed.`, 'neutral', {\n label: 'Undo',\n onClick: () => {\n const restored = this.controller.select([id]);\n this.toast(\n restored.length ? `${label} restored.` : `${label} is no longer available.`,\n restored.length ? 'success' : 'warning',\n );\n },\n });\n };\n if (this.reducedMotion()) {\n remove();\n return;\n }\n chip.classList.add('sl-leave');\n this.scheduleMotion(remove, 150);\n });\n });\n this.els.tray.querySelectorAll<HTMLButtonElement>('[data-table-edit]').forEach((button) => {\n button.addEventListener('click', (event) => {\n event.stopPropagation();\n const label = decodeURIComponent(button.dataset.tableEdit ?? '');\n const details = this.controller.tableSelection(label);\n if (!details) return;\n const heldItem = heldItems.find((item) => item.label === label && item.objectType === 'table');\n this.showTableDialog(\n { ...details, quantity: heldItem?.quantity ?? details.quantity },\n !!heldItem,\n button,\n );\n });\n });\n // Per-seat ticket-tier pick (Adult/Child/…) — updates price via onSelectionChange.\n this.els.tray.querySelectorAll<HTMLSelectElement>('.sl-chip .tier').forEach((sel) => {\n sel.addEventListener('change', () => this.controller.setSeatTier(sel.dataset.tier!, sel.value || null));\n });\n // View-from-seat button (data-view-label = seat label) on fresh + held chips.\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip .view[data-view-label]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const seat = this.controller.seatByLabel(btn.dataset.viewLabel!);\n if (seat) void this.openSeatView(seat);\n });\n });\n // Card ↔ map linkage: hovering (or keyboard-focusing) a ticket card pulses\n // its seat on the map so the buyer can locate what they picked.\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip[data-locate]').forEach((chip) => {\n const locate = (): void => this.controller.flashSeat(chip.dataset.locate!, this.cssVar('--sl-accent') || '#f4b740');\n chip.addEventListener('mouseenter', locate);\n chip.addEventListener('focusin', locate);\n });\n this.els.tray.querySelectorAll<HTMLElement>('.sl-ga button').forEach((btn) => {\n btn.addEventListener('click', () => {\n const areaEl = btn.closest('.sl-ga') as HTMLElement;\n const id = areaEl.dataset.ga!;\n const area = gaAreas.find((a) => a.id === id);\n const delta = Number(btn.dataset.d);\n if (delta > 0 && !this.canAddTicket()) return;\n const next = Math.max(0, Math.min(area?.available ?? 0, (this.gaQty.get(id) ?? 0) + delta));\n this.gaQty.set(id, next);\n this.syncTray();\n });\n });\n\n // Sales closed: freeze the best-available + GA controls (read-only state).\n if (this.salesClosed) {\n this.els.tray\n .querySelectorAll<HTMLButtonElement | HTMLSelectElement>('.sl-ba-go,[data-ba],[data-ba-cat],[data-ba-zone],[data-ba-replace],.sl-ga button')\n .forEach((el) => {\n el.disabled = true;\n });\n }\n\n // totals + CTA (held lines + fresh selections + GA)\n const gaTotal = this.pendingGATotal(gaAreas);\n const gaCount = this.pendingGACount();\n const heldTotal = heldItems.reduce((sum, item) => sum + this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1), 0);\n const heldCount = heldItems.reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n const freshSeats = seats.filter((seat) => !heldLabels.has(seat.label));\n const total = freshSeats.reduce(\n (sum, s) => sum + this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1),\n 0,\n ) + gaTotal + heldTotal;\n const count = freshSeats.reduce((sum, seat) => sum + (seat.quantity ?? 1), 0) + gaCount + heldCount;\n const pendingCount = this.pendingSelectionCount();\n const previousCount = this.lastTrayCount;\n const previousTotal = this.lastTrayTotal;\n this.els.count.textContent = count\n ? `${count} ${count === 1 ? 'ticket' : 'tickets'}`\n : 'No seats selected';\n this.els.total.textContent = count ? this.money(total) : '';\n this.root?.setAttribute('data-has-selection', String(count > 0));\n // The best-available panel's confirm (\"Replace your current choices?\") and\n // in-flight busy states must survive the narrow-layout collapse that hides\n // .sl-ba once the cart is non-empty. Mark them so the CSS keeps them shown.\n this.root?.setAttribute(\n 'data-ba-active',\n String(this.bestAvailableConfirm || this.bestAvailableBusy),\n );\n this.els.foot?.classList.toggle('empty', count === 0);\n if (this.els.seatSummary) {\n this.els.seatSummary.textContent = count ? `${count} selected` : '';\n }\n this.syncCta(count, pendingCount);\n if (this.hold) {\n const securedCount = heldCount || this.hold.seats?.length || 0;\n if (this.els.holdTitle) {\n this.els.holdTitle.textContent = `${securedCount} secured`;\n }\n if (this.els.holdCopy) {\n this.els.holdCopy.textContent = pendingCount\n ? `${pendingCount} more selected`\n : 'Checkout timer running';\n }\n const change = this.els.holdChange as HTMLButtonElement | undefined;\n if (change) {\n change.disabled = this.releasingHold;\n change.textContent = this.releasingHold ? 'Releasing…' : 'Change';\n }\n }\n if (count !== previousCount) this.animateOnce(this.els.count, 'sl-value-pop', 380);\n if (total !== previousTotal) this.animateOnce(this.els.total, 'sl-value-pop', 380);\n if (previousCount === 0 && count > 0) this.animateOnce(this.els.cta, 'sl-ready', 520);\n\n // Mobile sheet: one-line peek summary. Selected → \"N tickets · $X · Continue\";\n // empty → \"From $min · Best available\". Tap (sheet head) expands the sheet.\n if (this.els.peek) {\n if (count) {\n // Sheet state is shown by the persistent chevron in the head; the pill is\n // the action affordance (\"Continue\"/\"Review\") — no inline text arrow.\n /* THE PILL IS A BUTTON, AND IT DOES WHAT IT SAYS.\n It was a <span class=\"go\"> — role null, tabIndex -1, cursor:pointer.\n Dressed as a control and reachable by neither keyboard nor assistive\n tech, its taps fell through to the sheet head, which merely toggled the\n panel. So \"Continue\" closed the sheet and \"Best seats\" did nothing,\n which is exactly what the owner reported.\n\n With a hold and nothing pending, \"Continue\" IS the checkout — the same\n handleCta the footer button runs. That also answers the second half of\n the report: the footer lives inside the sheet and is hidden at peek, so\n a buyer with seats held had no visible way to pay. Now the collapsed\n bar is the way to pay. */\n const holding = !!this.hold && !pendingCount;\n this.els.peek.innerHTML =\n `<span>${count} ${count === 1 ? 'ticket' : 'tickets'} · ${this.money(total)}</span>` +\n `<button type=\"button\" class=\"go sl-sheet-go\" data-act=\"${holding ? 'checkout' : 'open'}\">` +\n `${this.hold ? (pendingCount ? 'Secure more' : 'Continue') : 'Review'}</button>`;\n } else {\n const prices = (this.controller.doc?.categories ?? [])\n .map((c) => this.catPrice(c))\n .filter((p): p is number => p != null);\n /* Best-available is a FORM, not a verb — quantity, ticket type and zone\n are chosen first — so this opens the sheet at those controls rather\n than guessing a pick on the buyer's behalf. */\n this.els.peek.innerHTML =\n (prices.length ? `<span>From ${this.money(Math.min(...prices))}</span>` : '<span>Pick your seats</span>') +\n `<button type=\"button\" class=\"go sl-sheet-go\" data-act=\"open\">✦ Best seats</button>`;\n }\n }\n // Keep the mobile map stable after selection. The persistent Review pill\n // exposes the updated count/total without covering the seat the buyer just\n // confirmed; opening the sheet remains an explicit tap or swipe.\n this.lastTrayCount = count;\n this.lastTrayTotal = total;\n\n this.opts.onSelectionChange?.(seats);\n }\n\n private async removeHeldLabel(label: string, chip?: HTMLElement): Promise<boolean> {\n if (!label || this.releasingLabels.has(label)) return false;\n this.releasingLabels.add(label);\n chip?.setAttribute('aria-busy', 'true');\n const button = chip?.querySelector<HTMLButtonElement>('.rm');\n if (button) button.disabled = true;\n try {\n const preserveAcrossNavigation = this.handedOff;\n const released = await this.controller.releaseLabels([label]);\n if (!released) {\n this.toast(`Couldn't remove ${label}. Your hold is unchanged.`, 'error');\n return false;\n }\n const remaining = this.controller.currentHold();\n this.hold = remaining\n ? { holdId: remaining.holdId, expiresAt: remaining.expiresAt, seats: remaining.seats, items: remaining.items }\n : null;\n this.handedOff = !!this.hold && preserveAcrossNavigation;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n if (this.hold) {\n this.startHoldTimer(this.hold.expiresAt);\n } else {\n this.stopHoldTimer();\n this.forgetHold();\n }\n this.syncTray();\n this.emitHoldChange();\n this.toast(`${label} removed from your hold.`, 'success');\n return true;\n } finally {\n this.releasingLabels.delete(label);\n chip?.removeAttribute('aria-busy');\n if (button?.isConnected) button.disabled = false;\n }\n }\n\n private async handleChangeSeats(): Promise<void> {\n if (!this.hold || this.releasingHold) return;\n this.releasingHold = true;\n const button = this.els.holdChange as HTMLButtonElement | undefined;\n if (button) {\n button.disabled = true;\n button.textContent = 'Releasing…';\n }\n try {\n await this.release();\n if (!this.hold) this.toast('Held tickets released. Choose your new seats.', 'success');\n } finally {\n this.releasingHold = false;\n if (button?.isConnected) {\n button.disabled = false;\n button.textContent = 'Change';\n }\n }\n }\n\n private async handleCta(): Promise<void> {\n if (this.salesClosed) return;\n if (this.totalTicketCount() > this.maxTickets) {\n this.toast(`Remove tickets until your order has ${this.maxTickets} or fewer.`, 'warning');\n return;\n }\n // Best-available (or a prior CTA press) already holds the seats — hand off.\n // Held seats are NOT in the client selection (the server holds them), so\n // pass the hold's own seat list to the host.\n const committed = this.committedSelection();\n if (this.hold && !committed.some((s) => !(this.hold!.items ?? []).some((i) => i.label === s.label))) {\n const seats = this.hold.seats ?? committed;\n this.handedOff = true;\n this.setCtaPhase('checkout');\n this.checkoutHandoff(this.hold, seats);\n return;\n }\n this.holdingLabels = new Set(committed.map((seat) => seat.label));\n this.setCtaPhase('holding');\n try {\n // seats first (controller.hold covers selected seats); GA quantities ride along\n let hold: HoldResult | null = null;\n const gaEntries = [...this.gaQty.entries()].filter(([, q]) => q > 0);\n // Snapshot before hold — the hold's own WS echo repaints these seats.\n const chosenSeats = this.committedSelection();\n if (chosenSeats.length) {\n const h = await this.controller.hold(undefined, this.opts.holdTtlMs);\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n for (const [areaId, qty] of gaEntries) {\n const h = await this.controller.holdGA(areaId, qty, { ttlMs: this.opts.holdTtlMs });\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;\n }\n if (!hold) {\n this.toast('One or more seats were just taken. Please pick again.', 'error');\n this.setCtaPhase('idle');\n this.syncTray();\n return;\n }\n this.hold = hold;\n this.handedOff = true;\n this.startHoldTimer(hold.expiresAt);\n this.flashHeldSeats(hold);\n this.setCtaPhase('checkout');\n this.emitHoldChange();\n // The replacement hold can combine an earlier best-available set with\n // newly selected seats. Hand the host the complete held seat set; the\n // server-priced line items remain authoritative for GA and totals.\n this.checkoutHandoff(hold, hold.seats ?? chosenSeats);\n } catch (err) {\n this.opts.onError?.(err);\n const problem = err as { reason?: string; conflicts?: Array<{ label?: string }> };\n const labels = (problem.conflicts ?? []).map((conflict) => conflict.label).filter(Boolean).slice(0, 3);\n // The CTA's controller.hold() path doesn't surface onSalesClosed — apply the\n // persistent read-only state here (the toast below stays). book/bestAvailable\n // paths reach it via the onSalesClosed callback.\n if (problem.reason === 'event_closed') this.setSalesClosed(true);\n const message = problem.reason === 'event_closed'\n ? 'Seat sales have closed for this event.'\n : labels.length\n ? `${labels.join(', ')} ${labels.length === 1 ? 'is' : 'are'} no longer available. Choose another ${labels.length === 1 ? 'seat' : 'group'}.`\n : 'One or more seats were just taken. Please pick again.';\n this.toast(message, 'error');\n this.setCtaPhase('idle');\n } finally {\n this.holdingLabels.clear();\n if (this.ctaPhase === 'holding') this.ctaPhase = 'idle';\n this.syncTray();\n }\n }\n\n private startHoldTimer(expiresAt: number): void {\n this.stopHoldTimer();\n this.holdExpiresAt = expiresAt;\n if (this.hold) this.rememberHold(this.hold);\n const pill = this.els.hold;\n pill.innerHTML =\n '<span class=\"sl-hold-dot\" aria-hidden=\"true\"></span><span>Held</span><span class=\"sl-hold-time\" data-ref=\"holdTime\"></span>';\n const time = pill.querySelector<HTMLElement>('[data-ref=\"holdTime\"]');\n this.els.holdNote?.classList.add('on');\n const tick = (): void => {\n const ms = Math.max(0, this.holdExpiresAt - Date.now());\n const m = Math.floor(ms / 60000);\n const s = String(Math.floor((ms % 60000) / 1000)).padStart(2, '0');\n if (time) time.textContent = `${m}:${s}`;\n pill.classList.add('on');\n pill.classList.toggle('is-expiring', ms > 0 && ms <= EXTEND_PROMPT_MS);\n // Offer an extension in the final stretch (but not once it's booked/expired).\n this.setExtendPrompt(ms > 0 && ms <= EXTEND_PROMPT_MS, ms);\n if (ms <= 0) this.stopHoldTimer();\n };\n tick();\n this.holdTimer = setInterval(tick, 500);\n }\n\n private stopHoldTimer(): void {\n if (this.holdTimer) clearInterval(this.holdTimer);\n this.holdTimer = null;\n this.els.hold?.classList.remove('on', 'is-expiring');\n this.els.holdNote?.classList.remove('on');\n this.setExtendPrompt(false, 0);\n }\n\n /** Show/refresh (or hide) the \"Need more time?\" prompt with the live seconds left. */\n private setExtendPrompt(show: boolean, ms: number): void {\n if (!this.extendEl) return;\n if (show && this.controller.currentHold() && !this.bookedShown) {\n const secs = Math.ceil(ms / 1000);\n this.els.extendTxt.innerHTML = `Your seats are held for <b>0:${String(secs).padStart(2, '0')}</b>. Need more time?`;\n this.extendEl.classList.add('on');\n } else {\n this.extendEl.classList.remove('on');\n }\n }\n\n private async handleExtend(): Promise<void> {\n const btn = this.els.extendBtn as HTMLButtonElement;\n btn.disabled = true;\n const prev = btn.textContent;\n btn.textContent = 'Adding…';\n try {\n const h = await this.controller.extendHold(this.opts.holdTtlMs);\n if (h) {\n // The controller re-armed its own expiry; sync ours + the pill, hide prompt.\n this.hold = { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items };\n this.holdExpiresAt = h.expiresAt;\n this.extendEl?.classList.remove('on');\n this.rememberHold(this.hold);\n this.emitHoldChange();\n this.toast('More time added — your seats are still held.', 'success');\n } else {\n this.toast(\"Couldn't add more time — please head to checkout now.\", 'warning');\n }\n } catch (err) {\n this.opts.onError?.(err);\n this.toast(\"Couldn't add more time — please head to checkout now.\", 'warning');\n } finally {\n btn.disabled = false;\n btn.textContent = prev;\n }\n }\n\n /**\n * Fire the booked-confirmation state once the buyer's held seats settle to\n * booked. The controller clears its own hold the moment every held label reads\n * 'booked' over the realtime channel (clearBookedHoldIfSettled), and this runs\n * on the same onStatusChange — so `currentHold() === null` while we still hold\n * a checkout handoff means \"sold\", not expired (expiry clears via onHoldExpired\n * on a different path, which nulls this.hold first).\n */\n private detectBooked(): void {\n if (this.bookedShown || !this.handedOff || !this.hold) return;\n if (this.controller.currentHold() !== null) return; // hold still open\n this.showBooked();\n }\n\n private showBooked(): void {\n if (this.bookedShown || !this.hold) return;\n this.bookedShown = true;\n const handoff = this.buildHandoff(this.hold);\n this.stopHoldTimer();\n this.forgetHold();\n const n = handoff.lineItems.reduce((sum, i) => sum + i.quantity, 0);\n if (this.els.bookedSub) {\n this.els.bookedSub.innerHTML =\n `<span class=\"sl-booked-seats\">${n} ${n === 1 ? 'ticket' : 'tickets'}</span> confirmed. ` +\n `A confirmation is on its way.`;\n }\n this.bookedEl?.classList.add('on');\n this.opts.onBooked?.(handoff);\n }\n\n /**\n * The seats are held. Send the buyer wherever this picker's `checkout` option\n * says they go.\n *\n * The default branch is the literal call that stood here before hosted\n * checkout existed, unchanged, so nothing about an existing integration moves.\n */\n private checkoutHandoff(hold: HoldResult, seats: PickerSeat[]): void {\n if (this.checkoutMode === 'hosted') {\n void this.startHostedCheckout(hold, seats);\n return;\n }\n this.opts.onCheckout?.(hold, seats, this.buildHandoff(hold));\n }\n\n /**\n * Take the money ourselves, through the organizer's own gateway.\n *\n * Order of operations matters: ASK FIRST, load second. `payment-options` is\n * already in flight from render, and its answer decides whether any payment\n * code is fetched at all — an event that cannot charge never downloads the\n * card that would have charged it.\n *\n * An empty list is not a failure and never dead-ends the buyer. It routes them\n * to whatever the host has: `onCheckoutUnavailable` (with the server's reason,\n * so the host can say the right one of three very different sentences), then\n * `onCheckout` with the ordinary handoff. A host that supplied neither gets\n * the widget's own honest card instead of a press that did nothing.\n */\n private async startHostedCheckout(hold: HoldResult, seats: PickerSeat[]): Promise<void> {\n const handoff = this.buildHandoff(hold);\n let options: PaymentOptionsResult | null = null;\n try {\n options = await (this.paymentOptions ??= this.pubApi!.paymentOptions(this.opts.event));\n } catch (err) {\n // A failed lookup is not evidence about the organizer's setup, so it falls\n // through to the reason that asserts the least about them.\n this.opts.onError?.(err);\n }\n if (this.destroyed) return;\n\n const provider = options?.providers?.[0];\n if (!provider) {\n const reason = paymentsOffReason(options?.reason);\n const handled = !!this.opts.onCheckoutUnavailable || !!this.opts.onCheckout;\n this.opts.onCheckoutUnavailable?.({ reason, handoff });\n this.opts.onCheckout?.(hold, seats, handoff);\n if (!handled) {\n void this.openCheckoutPanel({\n kind: 'unavailable',\n reason,\n seatCount: handoff.lineItems.reduce((sum, item) => sum + item.quantity, 0),\n });\n }\n return;\n }\n\n await this.openCheckoutPanel({\n kind: 'pay',\n provider,\n order: {\n holdId: handoff.holdId,\n expiresAt: handoff.expiresAt,\n currency: handoff.currency,\n total: handoff.total,\n labels: handoff.lineItems.map((item) => item.displayLabel ?? item.label),\n },\n });\n }\n\n /**\n * Fetch the checkout chunk and put its card over the map.\n *\n * Every failure here lands the buyer back on a map with their seats still\n * held, which is a place they can act from — a blocked chunk request must not\n * leave them staring at a CTA that no longer does anything.\n */\n private async openCheckoutPanel(state: CheckoutState): Promise<void> {\n let mountCheckout: HostedCheckoutModule['mountCheckout'];\n try {\n ({ mountCheckout } = await loadHostedCheckout());\n } catch (err) {\n this.opts.onError?.(err);\n this.toast('Checkout could not be opened. Your seats are still held — please try again.', 'error');\n this.setCtaPhase('idle');\n return;\n }\n if (this.destroyed || !this.root) return;\n this.closeCheckoutPanel();\n this.checkoutPanel = mountCheckout({\n root: this.root,\n state,\n // `returnUrl` rides along so a redirecting gateway can come back to the\n // HOST's page. The server validates its origin against the organizer's\n // declared embed domains and silently falls back to our own buyer page\n // when it does not match, so passing one can never redirect a paid buyer\n // somewhere the organizer did not sanction.\n startSession: (input) => this.pubApi!.startCheckout(this.opts.event, {\n ...input,\n ...(this.opts.returnUrl ? { returnUrl: this.opts.returnUrl } : {}),\n }),\n orderStatus: (orderId) => this.pubApi!.orderStatus(orderId),\n onCancel: () => {\n this.checkoutPanel = null;\n // The hold is untouched by cancelling — the buyer goes back to a map\n // that still has their seats, and the CTA still says checkout.\n if (!this.hold) this.setCtaPhase('idle');\n },\n onConfirmed: (order) => {\n this.opts.onOrderConfirmed?.(order);\n // The seats are sold. Re-read the map so they repaint as booked for this\n // buyer immediately rather than whenever the next realtime frame lands.\n void this.controller.refresh();\n },\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n private closeCheckoutPanel(): void {\n this.checkoutPanel?.destroy();\n this.checkoutPanel = null;\n }\n\n /** Assemble the stable {@link CheckoutHandoff} from a hold's server line items. */\n private buildHandoff(hold: HoldResult): CheckoutHandoff {\n const items = hold.items ?? [];\n // Host `pricing` overrides win in the handoff too — the host gets back the\n // prices it will actually charge, so map display and order total agree.\n const lineItems: CheckoutLineItem[] = items.map((it: HoldLineItem) => {\n const display = this.controller.lineItemDisplay(it);\n return {\n label: it.label,\n ...(display.displayLabel ? { displayLabel: display.displayLabel } : {}),\n ...(display.displayType ? { displayType: display.displayType } : {}),\n objectId: it.objectId,\n objectType: it.objectType,\n categoryKey: it.categoryKey,\n tierId: it.tierId,\n unitPrice: this.paidPrice(it.categoryKey, it.tierId, it.unitPrice),\n currency: it.currency ?? this.currency,\n quantity: it.quantity ?? 1,\n };\n });\n const currency = lineItems[0]?.currency ?? this.currency;\n const total = lineItems.reduce((sum, i) => sum + i.unitPrice * i.quantity, 0);\n return { holdId: hold.holdId, expiresAt: hold.expiresAt, currency, lineItems, total };\n }\n\n private emitHoldChange(): void {\n const hold = this.hold;\n this.scheduleOfferRefresh(true);\n this.opts.onHoldChange?.(\n hold,\n hold?.seats ?? [],\n hold ? this.buildHandoff(hold) : null,\n );\n }\n\n private toast(\n msg: string,\n tone: 'neutral' | 'success' | 'warning' | 'error' = 'neutral',\n action?: { label: string; onClick: () => void },\n ): void {\n const el = this.els.toast;\n if (!el) return;\n el.replaceChildren();\n const copy = document.createElement('span');\n copy.textContent = msg;\n el.appendChild(copy);\n el.classList.toggle('has-action', !!action);\n if (action) {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'sl-toast-action';\n button.textContent = action.label;\n button.addEventListener('click', action.onClick, { once: true });\n el.appendChild(button);\n }\n el.dataset.tone = tone;\n el.classList.add('on');\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toastTimer = setTimeout(() => {\n el.classList.remove('on');\n el.classList.remove('has-action');\n el.dataset.tone = 'neutral';\n }, 4200);\n }\n\n private placeTooltip(): void {\n if (!this.tipEl) return;\n const hw = this.els.map.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n /**\n * Row label without the redundant section prefix. Charts commonly name row\n * objects \"104-A\" while the Section column already shows \"104\" — so the Row\n * cell repeats the section and, in the compact hover card, truncates to\n * \"10…\". Strip a leading \"<section><sep>\" so Row reads a clean \"A\". Only when\n * the prefix is exact (won't touch \"1040-A\" under section \"104\"); otherwise\n * the label is shown verbatim.\n */\n /** Buyer-facing type word for the row/table key label — the designer's\n * per-object \"Displayed type\" override, or the default \"Row\". */\n private rowTypeWord(details: { displayType?: string; rowType?: string; objectType?: PickerSeat['objectType'] } | null | undefined): string {\n const authored = details?.displayType?.trim() || details?.rowType?.trim();\n if (authored) return authored;\n if (details?.objectType === 'table') return 'Table';\n if (details?.objectType === 'booth') return 'Booth';\n return 'Row';\n }\n\n private rowShort(details: { sectionLabel?: string; rowLabel?: string } | null | undefined): string | undefined {\n const row = details?.rowLabel;\n const sec = details?.sectionLabel;\n if (!row || !sec) return row;\n for (const sep of ['-', ' ', '·', '/', '_']) {\n const prefix = `${sec}${sep}`;\n if (row.startsWith(prefix) && row.length > prefix.length) return row.slice(prefix.length);\n }\n return row;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const esc = (v: unknown): string =>\n String(v ?? '—').replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n const price = this.money(this.paidPrice(details.categoryKey, details.tierId ?? null, details.price));\n // Identity grid — the same Section·Row·Seat card the buyer meets on confirm\n // and in the cart, just smaller. Falls back to a single field for a bare\n // label (GA / legacy seats with no spatial context).\n const isGroupedTable = details.objectType === 'table' && !!details.bookingMode;\n const isBooth = details.objectType === 'booth';\n const hasLoc = details.sectionLabel || details.rowLabel || details.seatNumber;\n const grid = isGroupedTable\n ? `<div class=\"sl-tip-grid\">` +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div>` +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Guests</span><span class=\"sl-tip-val\">${details.bookingMode === 'variable' ? `${details.minOccupancy}–${details.maxOccupancy}` : details.capacity}</span></div>` +\n `</div>`\n : isBooth\n ? `<div class=\"sl-tip-grid\">` +\n (details.sectionLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Section</span><span class=\"sl-tip-val\">${esc(details.sectionLabel)}</span></div>` : '') +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div>` +\n `</div>`\n : hasLoc\n ? `<div class=\"sl-tip-grid\">` +\n (details.sectionLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Section</span><span class=\"sl-tip-val\">${esc(details.sectionLabel)}</span></div>` : '') +\n (details.rowLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(this.rowShort(details))}</span></div>` : '') +\n (details.seatNumber ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Seat</span><span class=\"sl-tip-val\">${esc(details.seatNumber)}</span></div>` : '') +\n `</div>`\n : `<div class=\"sl-tip-grid one\"><div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Seat</span><span class=\"sl-tip-val\">${esc(details.displayLabel ?? details.label)}</span></div></div>`;\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div class=\"sl-tip-status\">${details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')}</div>`;\n const limited = this.limitedViewLabel(details.commercial);\n const cxLine = limited\n ? `<div class=\"sl-tip-cx\"><span class=\"g\" aria-hidden=\"true\">◐</span>${esc(limited)}</div>`\n : '';\n const wheelchair = this.wheelchairProvisionLabel(details.wheelchairSpaceType);\n const wheelchairLine = wheelchair\n ? `<div class=\"sl-tip-cx\"><span class=\"g\" aria-hidden=\"true\">♿</span>${esc(wheelchair)}</div>`\n : '';\n this.tipEl.style.setProperty('--sl-cat', details.categoryColor);\n this.tipEl.innerHTML =\n grid +\n `<div class=\"sl-tip-cat\"><span class=\"sl-tip-dot\" style=\"background:${details.categoryColor}\"></span>` +\n `<span class=\"sl-tip-name\">${esc(details.categoryLabel)}</span>` +\n `<span class=\"sl-tip-amt\">${price}</span></div>` +\n wheelchairLine +\n cxLine +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n // ---- public conveniences ----------------------------------------------------\n\n getSelection(): PickerSeat[] {\n return this.committedSelection();\n }\n\n /**\n * Re-ink the DRAWN MAP after mount, so the canvas can follow a page palette\n * the host did not know at construction time.\n *\n * Deliberately narrower than the `theme` option: it takes only the map half.\n * The chrome half is CSS custom properties, which a host restyles from its\n * own stylesheet without asking the widget for anything — and a host that\n * used both mechanisms at once would have two things writing one token. This\n * method exists for the half CSS genuinely cannot reach: pixels Konva draws.\n *\n * The rebuild is the controller's (`setMapTheme`), which repaints statuses\n * from the map already in memory and restores the selection, so a buyer\n * mid-pick keeps their seats and no round trip is spent. A no-op when the\n * colours have not changed; safe to call on every render.\n */\n setMapTheme(map: PickerMapTheme | null): void {\n if (this.destroyed) return;\n this.opts.theme = { ...(this.opts.theme ?? {}), map: map ?? undefined };\n this.controller.setMapTheme(map);\n }\n\n /**\n * Let a host suppress duplicate event identity after mount without remounting\n * the live picker (and therefore without disturbing a selection or hold).\n * Full-screen mode still restores the identity until the buyer exits it.\n */\n setEventDetailsHidden(hidden: boolean): void {\n this.eventDetailsHidden = hidden;\n this.syncFullscreenButtons();\n }\n\n /**\n * Replace the host pricing override AFTER mount, and repaint everything that\n * shows a price.\n *\n * WHY IT CANNOT JUST BE A MOUNT OPTION. The prices a host knows are often not\n * the prices it knows AT MOUNT: SeatLayer's own event page learns them from\n * `GET /pub/events/:key/availability`, a separate cached read that lands a\n * round trip after the map does — deliberately, because the map is not\n * allowed to wait on it. Remounting the widget to hand it new options would\n * tear down a live hold, so the override is settable in place.\n *\n * The prices themselves are still the SERVER'S. This method takes an answer;\n * it never derives one. Nothing here re-reads a release, a window or a quota\n * — see `paidPrice`, the one funnel every displayed price flows through, and\n * note that the checkout handoff's line items do not come from here at all:\n * they are priced by the worker from its own hold. So the worst a wrong call\n * to this method can do is misprint a price, never mischarge one.\n *\n * A no-op when the map is unchanged, so a host may call it on every poll.\n */\n setPricing(pricing: SeatPickerPricing | undefined): void {\n const before = JSON.stringify(this.opts.pricing ?? null);\n const after = JSON.stringify(pricing ?? null);\n if (before === after) return;\n this.opts.pricing = pricing;\n if (this.destroyed || !this.els.prices) return;\n // The band selector is DERIVED from prices, so a repriced chart can have a\n // different set of bands (or stop having enough distinct prices to warrant\n // one at all). Rebuild it rather than leaving a stale chip list behind.\n this.els.pricesSec?.querySelector('.sl-price-select')?.remove();\n this.buildPriceFilter();\n this.syncPrices();\n this.syncTray();\n // An open section card and an open confirm popover both print a price.\n if (this.lastSection) this.showSectionCard(this.lastSection);\n }\n\n /** Current colorblind-safe render state, resolved from the stored buyer\n * preference at mount. Host chrome (e.g. the Designer preview) reads this to\n * surface the state rather than rendering colorblind colors silently. */\n isColorblindSafe(): boolean {\n return this.cbSafe;\n }\n\n /** Single source of truth for the colorblind-safe toggle — used by both the\n * in-widget button and host chrome. Updates the renderer, the persisted\n * cross-surface preference, and the in-widget button's pressed state together\n * so the two controls never diverge. */\n setColorblindSafe(on: boolean): void {\n if (on === this.cbSafe) return;\n this.cbSafe = on;\n this.cbEl?.setAttribute('aria-pressed', String(on));\n this.controller.setColorblindSafe(on);\n // Persist under the SAME key the public page uses (cross-surface preference).\n writeStoredColorblind(on);\n }\n\n /** Switch the underlying 2D renderer projection (flat / isometric). The buyer\n * UI no longer exposes `perspective`; it is coerced to `flat`. */\n setViewMode(mode: RendererViewMode): void {\n this.controller.setViewMode(this.normalizeInitialView(mode));\n this.syncProjection();\n this.dismissConfirm();\n }\n\n /** Current buyer canvas projection. */\n getViewMode(): RendererViewMode {\n return this.controller.getViewMode();\n }\n\n /** `perspective` (2.5D) is retired from the buyer surface — accept it for\n * source compatibility but coerce to `flat` with a one-time deprecation warn. */\n private perspectiveWarned = false;\n private normalizeInitialView(mode: RendererViewMode | undefined): RendererViewMode {\n if (mode === 'perspective') {\n if (!this.perspectiveWarned) {\n this.perspectiveWarned = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[seatlayer] initialView:'perspective' (2.5D) is deprecated for the buyer picker and \"\n + \"was coerced to 'flat'. Use the Map | 3D control for the immersive view.\",\n );\n }\n return 'flat';\n }\n return mode ?? 'flat';\n }\n\n // ---- 3D venue view ---------------------------------------------------------\n\n /** Current buyer view: the flat map, or the interactive 3D venue. */\n getBuyerView(): SeatPickerBuyerView {\n return this.buyerView;\n }\n\n /**\n * Switch between the flat seat **Map** and the interactive **3D venue** view —\n * the same control the buyer's on-widget `Map | 3D` toggle drives.\n *\n * Entering `'venue3d'` with `opts.flyToSeatId` runs the cinematic tour: the\n * camera flies to the seat and holds in the live scene (a chip offers the\n * 360° view-from-seat). When the widget is **already** in the 3D\n * view, the camera simply flies to the requested seat — the GL scene is not\n * torn down or rebuilt, so there is no flash or re-entry.\n *\n * No-op when the view is unchanged and no `flyToSeatId` is given, or when 3D is\n * unavailable for this chart.\n *\n * @param view `'map'` for the flat picker, `'venue3d'` for the 3D venue.\n * @param opts.flyToSeatId When entering (or already in) `'venue3d'`, the seat\n * id to fly the camera to — cinematic → live seat view.\n * Ignored when `view` is `'map'`.\n *\n * @example\n * // Public 3D tour entry — enter 3D and fly straight to the buyer's seat:\n * picker.setBuyerView('venue3d', { flyToSeatId: 'A-12' });\n */\n setBuyerView(view: SeatPickerBuyerView, opts?: SeatPickerBuyerViewOptions): void {\n if (view === 'map') {\n this.exit3d();\n return;\n }\n const flyToSeatId = opts?.flyToSeatId;\n if (this.buyerView === 'venue3d') {\n // Already immersed — just fly the cinematic to the requested seat (if any),\n // without a jarring teardown/rebuild of the GL scene.\n if (flyToSeatId) {\n this.opts.onBuyerViewChange?.({ view: 'venue3d', seatId: flyToSeatId });\n void this.view3dHandle?.flyToSeat(flyToSeatId);\n } else if (opts?.resetView) {\n this.view3dHandle?.focusOverview();\n }\n return;\n }\n // Enter 3D; when a seat is given, the cinematic flies straight to it.\n void this.enter3d(flyToSeatId);\n }\n\n /** SeatStatus → the view3d palette state. Selection is layered separately. */\n private seatState3dFor(seat: ExpandedSeat): 'available' | 'held' | 'sold' | 'dimmed' {\n switch (this.controller.getStatus(seat.id)) {\n case 'held': return 'held';\n case 'booked': return 'sold';\n case 'not_for_sale': return 'dimmed';\n default: break;\n }\n // A filter that dims a seat on the map has to dim it in 3D too. 2D applies\n // these as Konva opacity, which the GL view never saw — so a buyer who\n // filtered to one price band and then switched to 3D got the unfiltered\n // venue back with no indication the filter was still on. The 'dimmed' state\n // already exists for held-back inventory and is exactly this treatment.\n if (this.priceBandKeys != null && !this.priceBandKeys.has(seat.categoryKey)) return 'dimmed';\n if (this.limitedViewFilter && (seat.commercial?.restrictedView || seat.commercial?.obstructedView)) {\n return 'dimmed';\n }\n return 'available';\n }\n\n /** Push the full live availability snapshot into the 3D handle (selection is\n * preserved inside the module). Cheap enough per status delta. */\n private pushAvailabilityTo3d(): void {\n if (!this.view3dHandle) return;\n const updates = this.allSeats().map((s) => ({ seatId: s.id, state: this.seatState3dFor(s) }));\n this.view3dHandle.setAvailability(updates);\n }\n\n /** Mirror the authoritative widget selection into the 3D handle. */\n private syncSelectionTo3d(): void {\n if (!this.view3dHandle) return;\n this.view3dHandle.setSelection(this.controller.getSelection().map((s) => s.id));\n }\n\n /** Build the view-from-seat panorama the cinematic dissolves into — reuses the\n * exact input path as the 2D `openSeatView` (organizer photo, else generated). */\n private async seatViewFor3d(seatId: string): Promise<View3DSeatView | null> {\n const seat = this.allSeats().find((s) => s.id === seatId);\n if (!seat) return null;\n if (seat.viewUrl) {\n try {\n const previewReference = seat.viewMeta?.previewUrl;\n const progressive = !!previewReference && previewReference !== seat.viewUrl;\n const previewUrl = progressive\n ? await this.buyerAssetUrls.resolve(previewReference)\n : null;\n const url = progressive\n ? seat.viewUrl\n : await this.buyerAssetUrls.resolve(seat.viewUrl);\n if (!url) return null;\n if (progressive && !previewUrl) return null;\n return {\n url,\n ...(previewUrl ? { previewUrl } : {}),\n ...(progressive ? { resolveUrl: (reference: string) => this.buyerAssetUrls.resolve(reference) } : {}),\n ...(seat.viewMeta?.sourceWidth !== undefined ? { sourceWidth: seat.viewMeta.sourceWidth } : {}),\n ...(seat.viewMeta?.sourceHeight !== undefined ? { sourceHeight: seat.viewMeta.sourceHeight } : {}),\n ...(seat.viewMeta?.previewWidth !== undefined ? { previewWidth: seat.viewMeta.previewWidth } : {}),\n ...(seat.viewMeta?.previewHeight !== undefined ? { previewHeight: seat.viewMeta.previewHeight } : {}),\n ...(seat.viewMeta?.initialBearingDeg !== undefined ? { initialBearingDeg: seat.viewMeta.initialBearingDeg } : {}),\n ...(seat.viewMeta?.initialPitchDeg !== undefined ? { initialPitchDeg: seat.viewMeta.initialPitchDeg } : {}),\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n };\n } catch (error) {\n this.opts.onError?.(error);\n return null;\n }\n }\n // No authored panorama: keep the buyer in the resolution-independent live\n // venue at the selected seat-eye. The old path eagerly generated a 2048px\n // bitmap only so view3d could discard it and render this same scene again.\n return {\n url: '',\n generated: true,\n mediaKind: 'model',\n coverage: 'exact-seat',\n sourceLabel: this.tf('picker.chartDerivedModel', 'Chart-derived model'),\n };\n }\n\n /** Route the module's decoupled analytics into the host callback, tagged buyer. */\n private emit3dAnalytics(event: string, props?: Record<string, unknown>): void {\n try {\n this.opts.onAnalytics?.(event, { ...props, surface: 'buyer' });\n } catch {\n /* a throwing host sink never breaks the widget */\n }\n }\n\n /** A 3D seat tap runs the SAME selection path as a 2D tap: toggle through the\n * controller, then raise the shared confirm card (bottom-sheeted in 3D). */\n private onView3dSeatPick(seatId: string): void {\n if (this.salesClosed) {\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n this.syncSelectionTo3d();\n return;\n }\n const seat = this.allSeats().find((s) => s.id === seatId);\n if (!seat) return;\n const table = this.controller.tableSelection(seatId);\n // Tapping an already-committed seat clears it (mirrors the 2D toggle).\n const already = this.committedSelection().some((s) => table ? s.label === table.label : s.id === seatId);\n if (already) {\n this.controller.deselect([seatId]);\n this.dismissConfirm();\n this.syncSelectionTo3d();\n return;\n }\n const visualState = this.seatState3dFor(seat);\n if (visualState !== 'available') {\n this.showUnavailable3dSeat(seat, visualState);\n this.syncSelectionTo3d();\n return;\n }\n this.dismissUnavailable3dSeat();\n const added = this.controller.select([seatId]); // programmatic select is silent\n if (!added.length) {\n // The GL picker optimistically highlighted the instance. Restore the\n // controller's authoritative state when inventory rejects the tap.\n this.syncSelectionTo3d();\n this.dismissConfirm();\n return;\n }\n this.opts.onBuyerViewChange?.({ view: 'venue3d', seatId });\n this.flashPickedSeat(seatId);\n if (table) {\n this.showTableDialog(table, false);\n this.syncSelectionTo3d();\n return;\n }\n if (this.opts.confirmSelection !== false) this.showConfirm(seat);\n else this.syncTray();\n // Replace the renderer's one-seat optimistic preview with the controller's\n // complete authoritative selection after the host mutation. Otherwise a\n // newly tapped blue chair can disagree with the committed \"Your seats\" list.\n this.syncSelectionTo3d();\n }\n\n /** Explain a visible-but-unselectable 3D seat without entering the booking\n * flow. Category colour remains visible in the venue; this card names the\n * availability state explicitly so yellow never has to carry both meanings. */\n private showUnavailable3dSeat(seat: ExpandedSeat, visualState: SeatState3D): void {\n const overlay = this.view3dEl;\n if (!overlay) return;\n this.dismissUnavailable3dSeat();\n const status = this.controller.getStatus(seat.id);\n const details = this.controller.seatDetails(seat.id);\n const identity = details?.displayLabel ?? seat.displayLabel ?? seat.label;\n const section = details?.sectionLabel;\n const row = this.rowShort(details);\n const location = [section, row ? `Row ${row}` : null, identity].filter(Boolean).join(' · ');\n const copy = status === 'held'\n ? {\n title: this.tf('picker.temporarilyHeld', 'Temporarily held'),\n message: this.tf('picker.heldSeatExplanation', 'Another buyer is holding this seat. It may become available again.'),\n }\n : status === 'booked'\n ? {\n title: this.tf('picker.sold', 'Sold'),\n message: this.tf('picker.soldSeatExplanation', 'This seat has already been booked.'),\n }\n : status === 'not_for_sale'\n ? {\n title: this.tf('picker.notForSale', 'Not for sale'),\n message: this.tf('picker.notForSaleExplanation', 'This seat is not included in the current sale.'),\n }\n : {\n title: this.tf('picker.filteredSeat', 'Unavailable with current filters'),\n message: this.tf('picker.filteredSeatExplanation', 'Change the active price or view filters to make this seat selectable.'),\n };\n const card = document.createElement('div');\n card.className = 'sl-view3d-unavailable';\n card.dataset.state = visualState;\n card.setAttribute('role', 'status');\n card.setAttribute('aria-live', 'polite');\n const eyebrow = document.createElement('span');\n eyebrow.className = 'sl-view3d-unavailable-eyebrow';\n eyebrow.textContent = location || identity;\n const title = document.createElement('strong');\n title.textContent = copy.title;\n const content = document.createElement('div');\n content.className = 'sl-view3d-unavailable-copy';\n content.append(eyebrow, title);\n const close = document.createElement('button');\n close.type = 'button';\n close.setAttribute('aria-label', this.tf('picker.closeSeatStatus', 'Close seat status'));\n close.textContent = '×';\n const message = document.createElement('p');\n message.textContent = copy.message;\n card.append(content, close, message);\n close.addEventListener('click', () => card.remove());\n overlay.appendChild(card);\n this.announceSeat(seat);\n }\n\n private dismissUnavailable3dSeat(): void {\n this.view3dEl?.querySelector('.sl-view3d-unavailable')?.remove();\n }\n\n /** Comparison belongs to inspection, never selection. The confirm candidate\n * remains excluded from checkout until Select; saving it releases that\n * candidate before any comparison state is created. */\n private view3dCompareConfirmHtml(seat: ExpandedSeat): string {\n if (this.buyerView !== 'venue3d') return '';\n const saved = this.view3dCompareSeatIds;\n const included = saved.includes(seat.id);\n const label = included\n ? saved.length > 1\n ? this.tf('picker.openComparison', 'Open comparison')\n : this.tf('picker.savedForComparison', 'Saved for comparison')\n : saved.length\n ? this.tf('picker.compareWithSaved', 'Compare with saved')\n : this.tf('picker.saveToCompare', 'Save to compare');\n return `<button type=\"button\" class=\"sl-confirm-compare\"${included && saved.length === 1 ? ' disabled' : ''}>`\n + `<span aria-hidden=\"true\">⇄</span><span>${this.escCx(label)}</span></button>`;\n }\n\n private seatConfidenceConfirmHtml(seat: ExpandedSeat, compactSummary: string): string {\n if (this.buyerView !== 'venue3d') return '';\n const disclosure = seatConfidenceDisclosure(seat.confidenceEvidence);\n const detail = disclosure.modeledTarget ?? disclosure.reality;\n return `<button type=\"button\" class=\"sl-confirm-confidence\" aria-label=\"Open seat confidence passport for ${this.escCx(seat.displayLabel ?? seat.label)}\">`\n + `<span><em>${this.escCx(compactSummary)}</em><strong>${this.escCx(disclosure.headline)}</strong><small>${this.escCx(detail)}</small></span>`\n + `<b>Passport</b></button>`;\n }\n\n private saveView3dComparisonSeat(seat: ExpandedSeat): void {\n if (this.buyerView !== 'venue3d') return;\n const previous = this.view3dCompareSeatIds;\n if (!previous.includes(seat.id)) {\n this.view3dCompareSeatIds = previous.length === 0\n ? [seat.id]\n : [previous[0]!, seat.id];\n }\n // A confirm candidate is an optimistic renderer/controller selection. A\n // saved comparison seat must not survive as a cart line or checkout total.\n if (this.confirmSeat?.id === seat.id) {\n this.controller.deselect([seat.id]);\n this.dismissConfirm();\n this.syncSelectionTo3d();\n this.syncTray();\n }\n this.syncView3dCompareChip();\n this.emit3dAnalytics('3d_comparison_saved', {\n seatId: seat.id,\n count: this.view3dCompareSeatIds.length,\n });\n if (this.view3dCompareSeatIds.length > 1) this.openView3dComparison();\n else this.toast(this.tf('picker.chooseAnotherToCompare', 'Seat saved. Choose another seat to compare.'), 'success');\n }\n\n private clearView3dComparison(): void {\n this.closeView3dComparison(false);\n this.view3dCompareSeatIds = [];\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n this.emit3dAnalytics('3d_comparison_cleared');\n }\n\n private syncView3dCompareChip(): void {\n const overlay = this.view3dEl;\n if (!overlay || this.view3dCompareSeatIds.length === 0) {\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n return;\n }\n let chip = this.view3dCompareChip;\n if (!chip) {\n chip = document.createElement('div');\n chip.className = 'sl-view3d-compare-saved';\n chip.setAttribute('role', 'group');\n chip.setAttribute('aria-label', 'Saved seat comparison');\n const main = document.createElement('button');\n main.type = 'button';\n main.className = 'main';\n main.addEventListener('click', () => {\n if (this.view3dCompareSeatIds.length > 1) this.openView3dComparison();\n else this.toast(this.tf('picker.chooseAnotherToCompare', 'Choose another seat to compare.'), 'neutral');\n });\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'clear';\n clear.textContent = '×';\n clear.setAttribute('aria-label', 'Clear saved seat comparison');\n clear.addEventListener('click', () => this.clearView3dComparison());\n chip.append(main, clear);\n overlay.appendChild(chip);\n this.view3dCompareChip = chip;\n }\n const count = this.view3dCompareSeatIds.length;\n const main = chip.querySelector<HTMLButtonElement>('.main');\n if (main) {\n main.textContent = count > 1 ? `Compare ${count}` : '1 seat saved';\n main.setAttribute('aria-label', count > 1 ? `Open comparison of ${count} seats` : 'One seat saved; choose another to compare');\n }\n }\n\n private view3dComparisonSnapshot(seatId: string) {\n const seat = this.allSeats().find((candidate) => candidate.id === seatId);\n if (!seat) return null;\n const details = this.controller.seatDetails(seat.id);\n const cat = this.controller.doc?.categories.find((candidate) => candidate.key === seat.categoryKey);\n const chartPrice = details?.price ?? (cat?.tiers?.length ? cat.tiers[0].price : cat?.price);\n const price = chartPrice != null\n ? this.paidPrice(seat.categoryKey, details?.tierId ?? cat?.tiers?.[0]?.id ?? null, chartPrice)\n : undefined;\n const status = this.controller.getStatus(seat.id);\n const availability = status === 'held'\n ? this.tf('picker.temporarilyHeld', 'Temporarily held')\n : status === 'booked'\n ? this.tf('picker.sold', 'Sold')\n : status === 'not_for_sale'\n ? this.tf('picker.notForSale', 'Not for sale')\n : this.tf('picker.available', 'Available');\n const viewSource = seat.viewUrl\n ? seatViewDisclosure({\n url: seat.viewUrl,\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n })\n : this.tf('picker.chartDerivedSeatEye', 'Live 3D · chart-derived seat-eye · not surveyed');\n const limited = this.limitedViewLabel(seat.commercial)\n || this.tf('picker.noAuthoredRestriction', 'No organizer-authored restriction');\n const accessibility = details?.wheelchairSpaceType\n ? `${this.wheelchairProvisionLabel(details.wheelchairSpaceType)} · metadata, not access certification`\n : this.tf('picker.noAccessibilityMetadata', 'No accessibility metadata supplied');\n const confidence = seatConfidenceDisclosure(seat.confidenceEvidence);\n return {\n seat,\n label: details?.displayLabel ?? seat.displayLabel ?? seat.label,\n section: details?.sectionLabel ?? seat.sectionId ?? '—',\n row: this.rowShort(details) ?? details?.rowLabel ?? '—',\n category: details?.categoryLabel ?? cat?.label ?? seat.categoryKey,\n price: price == null ? this.tf('picker.priceNotSupplied', 'Not supplied') : this.money(price),\n availability,\n selectable: status == null || status === 'free',\n viewSource,\n limited,\n accessibility,\n confidence,\n };\n }\n\n private openSeatConfidencePassport(seat: ExpandedSeat, returnFocus: HTMLElement | null = null): void {\n const overlay = this.view3dEl;\n if (!overlay) return;\n this.closeSeatConfidencePassport(false);\n const disclosure = seatConfidenceDisclosure(seat.confidenceEvidence);\n const evidence = seat.confidenceEvidence;\n const details = this.controller.seatDetails(seat.id);\n const safe = (value: unknown): string => this.escCx(value);\n const limitations = disclosure.limitations.length\n ? `<h4>Known limits</h4><ul>${disclosure.limitations.map((item) => `<li>${safe(item)}</li>`).join('')}</ul>`\n : '';\n const modeledTarget = disclosure.modeledTarget\n ? `<div><dt>Modeled target</dt><dd>${safe(disclosure.modeledTarget)}</dd></div>`\n : '';\n const evidenceRows = evidence\n ? `<div><dt>Evidence ID</dt><dd>${safe(evidence.evidenceId)}</dd></div>`\n + `<div><dt>Model version</dt><dd>${safe(evidence.modelVersion)}</dd></div>`\n + `<div><dt>Event configuration</dt><dd>${safe(evidence.eventConfigurationId ?? 'Not configuration-specific')}</dd></div>`\n + `<div><dt>Approval</dt><dd>${safe(evidence.approvedByRole ?? 'No external approval supplied')}</dd></div>`\n + (evidence.validUntil ? `<div><dt>Valid until</dt><dd>${safe(evidence.validUntil.slice(0, 10))}</dd></div>` : '')\n : `<div><dt>Evidence ID</dt><dd>None supplied</dd></div>`;\n const restriction = this.limitedViewLabel(seat.commercial)\n || this.tf('picker.noAuthoredRestriction', 'No organizer-authored restriction');\n const commercialRows = `<div><dt>View restriction</dt><dd>${safe(restriction)}</dd></div>`\n + (seat.commercial?.note ? `<div><dt>Organizer note</dt><dd>${safe(seat.commercial.note)}</dd></div>` : '');\n const shell = document.createElement('div');\n shell.className = 'sl-view3d-passport-shell';\n shell.innerHTML = `<div class=\"sl-view3d-passport-scrim\" aria-hidden=\"true\"></div>`\n + `<section class=\"sl-view3d-passport\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-view3d-passport-title\">`\n + `<header><div><span>Seat confidence passport</span><strong id=\"sl-view3d-passport-title\">${safe(details?.displayLabel ?? seat.displayLabel ?? seat.label)}</strong></div>`\n + `<button type=\"button\" data-close aria-label=\"Close seat confidence passport\">×</button></header>`\n + `<div class=\"sl-view3d-passport-summary\"><strong>${safe(disclosure.headline)}</strong>`\n + `<span>${safe(disclosure.coverage)} · ${safe(disclosure.freshness)}</span></div>`\n + `<dl><div><dt>Model status</dt><dd>${safe(disclosure.model)}</dd></div>`\n + `<div><dt>Reality evidence</dt><dd>${safe(disclosure.reality)}</dd></div>`\n + `<div><dt>Source</dt><dd>${safe(disclosure.provenance)}</dd></div>`\n + commercialRows + modeledTarget + evidenceRows + `</dl>${limitations}`\n + `<p class=\"sl-view3d-passport-note\">This passport describes supplied evidence and known limits. It does not guarantee that every temporary obstruction or real-world condition is knowable before the event build.</p></section>`;\n const background = [...new Set([\n ...overlay.children,\n ...[...this.els.map.children].filter((element) => element !== overlay),\n ])].filter((element): element is HTMLElement => element instanceof HTMLElement);\n const prior = background.map((element) => ({\n element,\n inert: element.inert,\n ariaHidden: element.getAttribute('aria-hidden'),\n }));\n for (const element of background) {\n element.inert = true;\n element.setAttribute('aria-hidden', 'true');\n }\n overlay.appendChild(shell);\n overlay.classList.add('has-passport');\n this.view3dPassportEl = shell;\n const dialog = shell.querySelector<HTMLElement>('.sl-view3d-passport')!;\n const controls = (): HTMLElement[] => [...dialog.querySelectorAll<HTMLElement>('button:not(:disabled),[href],[tabindex]:not([tabindex=\"-1\"])')];\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n this.closeSeatConfidencePassport();\n return;\n }\n if (event.key !== 'Tab') return;\n const focusable = controls();\n if (!focusable.length) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n // Capture before the picker's ordinary Escape handler. Closing this nested\n // disclosure must return to the same seat decision, not also cancel it.\n window.addEventListener('keydown', onKey, true);\n this.view3dPassportCleanup = () => {\n window.removeEventListener('keydown', onKey, true);\n for (const state of prior) {\n state.element.inert = state.inert;\n if (state.ariaHidden === null) state.element.removeAttribute('aria-hidden');\n else state.element.setAttribute('aria-hidden', state.ariaHidden);\n }\n const returnCandidate = returnFocus?.isConnected\n ? returnFocus\n : this.confirmEl?.querySelector<HTMLElement>('.sl-confirm-confidence')\n ?? this.view3dCompareEl?.querySelector<HTMLElement>('[data-passport-seat]')\n ?? null;\n const returnSurface = returnCandidate?.closest<HTMLElement>('.sl-confirm,.sl-view3d-compare');\n if (returnSurface?.isConnected) {\n returnSurface.inert = false;\n returnSurface.removeAttribute('aria-hidden');\n }\n shell.remove();\n overlay.classList.remove('has-passport');\n if (this.view3dPassportEl === shell) this.view3dPassportEl = null;\n const fallback = returnCandidate\n ?? this.view3dCompareEl?.querySelector<HTMLElement>('[data-passport-seat]')\n ?? this.confirmEl?.querySelector<HTMLElement>('.sl-confirm-confidence')\n ?? this.view3dCompareChip?.querySelector<HTMLElement>('.main');\n (returnFocus?.isConnected ? returnFocus : fallback)?.focus();\n };\n shell.addEventListener('click', (event) => {\n const target = event.target instanceof HTMLElement ? event.target : null;\n if (target?.closest('[data-close]') || target?.classList.contains('sl-view3d-passport-scrim')) {\n this.closeSeatConfidencePassport();\n }\n });\n requestAnimationFrame(() => controls()[0]?.focus());\n this.emit3dAnalytics('3d_confidence_passport_opened', {\n seatId: seat.id,\n evidenceId: evidence?.evidenceId ?? null,\n eventConfigurationId: evidence?.eventConfigurationId ?? null,\n modelLevel: evidence?.modelLevel ?? 'unverified',\n realityLevel: evidence?.realityLevel ?? 'none',\n });\n }\n\n private closeSeatConfidencePassport(restoreFocus = true): void {\n const cleanup = this.view3dPassportCleanup;\n this.view3dPassportCleanup = null;\n if (!cleanup) {\n this.view3dPassportEl?.remove();\n this.view3dPassportEl = null;\n this.view3dEl?.classList.remove('has-passport');\n return;\n }\n if (!restoreFocus) (document.activeElement instanceof HTMLElement ? document.activeElement : null)?.blur();\n cleanup();\n if (!restoreFocus) this.root?.focus({ preventScroll: true });\n }\n\n private openView3dComparison(): void {\n const overlay = this.view3dEl;\n if (!overlay || this.view3dCompareSeatIds.length < 2) return;\n this.closeView3dComparison(false);\n const snapshots = this.view3dCompareSeatIds\n .map((seatId) => this.view3dComparisonSnapshot(seatId))\n .filter((value): value is NonNullable<ReturnType<SeatPicker['view3dComparisonSnapshot']>> => !!value);\n if (snapshots.length < 2) {\n this.clearView3dComparison();\n return;\n }\n const safe = (value: unknown): string => this.escCx(value);\n const shell = document.createElement('div');\n shell.className = 'sl-view3d-compare-shell';\n const cards = snapshots.map((snapshot, index) => (\n `<article><span>Seat ${index === 0 ? 'A' : 'B'}</span><strong>${safe(snapshot.label)}</strong>`\n + `<small>Section ${safe(snapshot.section)} · Row ${safe(snapshot.row)}</small><dl>`\n + `<div><dt>Current price</dt><dd>${safe(snapshot.price)}</dd></div>`\n + `<div><dt>Ticket type</dt><dd>${safe(snapshot.category)}</dd></div>`\n + `<div><dt>Availability</dt><dd>${safe(snapshot.availability)}</dd></div>`\n + `<div><dt>View source</dt><dd>${safe(snapshot.viewSource)}</dd></div>`\n + `<div><dt>View restriction</dt><dd>${safe(snapshot.limited)}</dd></div>`\n + `<div><dt>Seat confidence</dt><dd>${safe(snapshot.confidence.headline)}</dd></div>`\n + `<div><dt>Reality check</dt><dd>${safe(snapshot.confidence.reality)}</dd></div>`\n + `<div><dt>Accessibility</dt><dd>${safe(snapshot.accessibility)}</dd></div></dl>`\n + `<div class=\"sl-view3d-compare-actions\">`\n + `<button type=\"button\" data-passport-seat=\"${safe(snapshot.seat.id)}\">Passport</button>`\n + `<button type=\"button\" data-view-seat=\"${safe(snapshot.seat.id)}\">View seat</button>`\n + `<button type=\"button\" class=\"select\" data-select-seat=\"${safe(snapshot.seat.id)}\"${snapshot.selectable ? '' : ' disabled'}>Select seat</button>`\n + `</div></article>`\n )).join('');\n shell.innerHTML = `<div class=\"sl-view3d-compare-scrim\" aria-hidden=\"true\"></div>`\n + `<section class=\"sl-view3d-compare\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-view3d-compare-title\">`\n + `<header><div><span>Seat inspection</span><strong id=\"sl-view3d-compare-title\">Compare disclosed attributes</strong></div>`\n + `<button type=\"button\" data-close aria-label=\"Close seat comparison\">×</button></header>`\n + `<p class=\"sl-view3d-compare-note\">Current price and availability come from this picker. Modeled views are chart-derived unless organizer media is labeled; SeatLayer does not invent why a seat has its price.</p>`\n + `<div class=\"sl-view3d-compare-grid\">${cards}</div></section>`;\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const background = [...overlay.children].filter((element): element is HTMLElement => element instanceof HTMLElement);\n const prior = background.map((element) => ({\n element,\n inert: element.inert,\n ariaHidden: element.getAttribute('aria-hidden'),\n }));\n for (const element of background) {\n element.inert = true;\n element.setAttribute('aria-hidden', 'true');\n }\n overlay.appendChild(shell);\n overlay.classList.add('has-comparison');\n this.view3dCompareEl = shell;\n const dialog = shell.querySelector<HTMLElement>('.sl-view3d-compare')!;\n const controls = (): HTMLElement[] => [...dialog.querySelectorAll<HTMLElement>('button:not(:disabled),[href],[tabindex]:not([tabindex=\"-1\"])')];\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closeView3dComparison();\n return;\n }\n if (event.key !== 'Tab') return;\n const focusable = controls();\n if (!focusable.length) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n window.addEventListener('keydown', onKey);\n this.view3dCompareCleanup = () => {\n window.removeEventListener('keydown', onKey);\n for (const state of prior) {\n state.element.inert = state.inert;\n if (state.ariaHidden === null) state.element.removeAttribute('aria-hidden');\n else state.element.setAttribute('aria-hidden', state.ariaHidden);\n }\n shell.remove();\n overlay.classList.remove('has-comparison');\n if (this.view3dCompareEl === shell) this.view3dCompareEl = null;\n if (previousFocus?.isConnected) previousFocus.focus();\n else this.view3dCompareChip?.querySelector<HTMLButtonElement>('.main')?.focus();\n };\n shell.querySelector<HTMLButtonElement>('[data-close]')?.addEventListener('click', () => this.closeView3dComparison());\n shell.querySelectorAll<HTMLButtonElement>('[data-passport-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.passportSeat;\n const seat = seatId ? this.allSeats().find((candidate) => candidate.id === seatId) : undefined;\n if (seat) this.openSeatConfidencePassport(seat, button);\n }));\n shell.querySelectorAll<HTMLButtonElement>('[data-view-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.viewSeat;\n this.closeView3dComparison(false);\n if (seatId) void this.view3dHandle?.flyToSeat(seatId);\n }));\n shell.querySelectorAll<HTMLButtonElement>('[data-select-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.selectSeat;\n if (seatId) this.selectComparedSeat(seatId);\n }));\n requestAnimationFrame(() => controls()[0]?.focus());\n this.emit3dAnalytics('3d_comparison_opened', { seatIds: this.view3dCompareSeatIds.slice() });\n }\n\n private closeView3dComparison(restoreFocus = true): void {\n const cleanup = this.view3dCompareCleanup;\n this.view3dCompareCleanup = null;\n if (!cleanup) {\n this.view3dCompareEl?.remove();\n this.view3dCompareEl = null;\n this.view3dEl?.classList.remove('has-comparison');\n return;\n }\n if (!restoreFocus) {\n const active = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n active?.blur();\n }\n cleanup();\n if (!restoreFocus) this.root?.focus({ preventScroll: true });\n }\n\n private selectComparedSeat(seatId: string): void {\n if (this.salesClosed) {\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n const seat = this.allSeats().find((candidate) => candidate.id === seatId);\n if (!seat) return;\n this.closeView3dComparison(false);\n const added = this.controller.select([seatId]);\n if (!added.length) {\n this.syncSelectionTo3d();\n this.toast(this.tf('picker.seatNoLongerAvailable', 'That seat is no longer available.'), 'warning');\n return;\n }\n this.syncSelectionTo3d();\n this.showConfirm(seat);\n this.emit3dAnalytics('3d_comparison_selected', { seatId });\n }\n\n /**\n * The venue-navigation rail inside 3D: levels and areas.\n *\n * In 2D a buyer moves through the venue by floor switcher and by the LOD\n * rungs. Both are hidden while immersed, and the 3D module's own chips only\n * cover \"go home\" and \"see the 360\" — so on a multi-floor or multi-zone chart\n * the buyer entered 3D and LOST the ability to reach the level or area they\n * were booking. The camera moves for both already exist on the handle\n * (`focusFloor` / `focusZone`); this is the surface that offers them.\n *\n * Levels are a TOGGLE (a floor stays isolated until you pick another), areas\n * are an ACTION (the camera flies there and you are then free to orbit), which\n * is why only the level pills carry a pressed state.\n */\n private buildView3dNav(overlay: HTMLElement, handle: Venue3DHandle): void {\n const floors = handle.floors();\n // An empty zone has nothing to frame and `focusZone` refuses it — offering\n // a pill that cannot move the camera is worse than offering nothing.\n // Some multi-floor charts also expose each floor as a same-named zone. That\n // is one venue concept represented twice, not two useful navigation rungs.\n // Keep the level toggle and suppress its duplicate area action.\n const floorLabels = new Set(floors.map((floor) => floor.label.trim().toLocaleLowerCase()));\n const zones = handle.zones().filter((zone) => (\n zone.seatCount > 0\n && !floorLabels.has(zone.label.trim().toLocaleLowerCase())\n ));\n // Zones are optional; sections are not. A chart that authors no zones (or\n // one) still needs a way to move around the venue, so the rail falls back to\n // the rung below. A long section list becomes one native jump control rather\n // than being truncated or rendered as dozens of pills.\n const allSections = handle.sections().filter((s) => s.seatCount > 0);\n const sections = zones.length > 1\n ? []\n : allSections;\n // One of anything is not a choice — a single-floor, single-zone venue gets\n // no rail rather than a rail that does nothing.\n const wantFloors = floors.length > 1;\n const wantZones = zones.length > 1;\n const wantSections = sections.length > 1;\n const wantLocator = allSections.length > 0 && handle.rows().length > 0;\n if (!wantFloors && !wantZones && !wantSections && !wantLocator) return;\n\n const nav = document.createElement('div');\n nav.className = 'sl-view3d-nav';\n const finderToggle = document.createElement('button');\n finderToggle.type = 'button';\n finderToggle.className = 'sl-view3d-nav-toggle';\n finderToggle.setAttribute('aria-expanded', 'false');\n const setFinderOpen = (open: boolean): void => {\n nav.classList.toggle('is-open', open);\n finderToggle.setAttribute('aria-expanded', String(open));\n finderToggle.textContent = open ? 'Close seat finder' : 'Find a seat';\n };\n finderToggle.addEventListener('click', () => setFinderOpen(!nav.classList.contains('is-open')));\n nav.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape' || !nav.classList.contains('is-open')) return;\n event.preventDefault();\n event.stopPropagation();\n setFinderOpen(false);\n finderToggle.focus();\n });\n setFinderOpen(false);\n nav.appendChild(finderToggle);\n\n if (wantFloors) {\n const row = document.createElement('div');\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', this.tf('picker.levels', 'Levels'));\n const pills: HTMLButtonElement[] = [];\n const select = (index: number | null): void => {\n if (!handle.focusFloor(index)) return;\n pills.forEach((p) => {\n p.setAttribute('aria-pressed', String((p.dataset.floor === '' ? null : Number(p.dataset.floor)) === index));\n });\n };\n const add = (label: string, index: number | null): void => {\n const b = document.createElement('button');\n b.type = 'button';\n b.textContent = label;\n b.dataset.floor = index === null ? '' : String(index);\n b.setAttribute('aria-pressed', String(index === null));\n b.addEventListener('click', () => {\n select(index);\n setFinderOpen(false);\n });\n pills.push(b);\n row.appendChild(b);\n };\n add(this.tf('picker.allLevels', 'All levels'), null);\n for (const f of floors) add(f.label || `Level ${f.index + 1}`, f.index);\n nav.appendChild(row);\n }\n\n if (wantZones || wantSections) {\n const row = document.createElement('div');\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', this.tf('picker.areas', 'Areas'));\n const entries: Array<{ id: string; label: string; go: () => void }> = wantZones\n ? zones.map((z) => ({ id: z.id, label: z.label || z.id, go: () => { handle.focusZone(z.id); } }))\n : sections.map((s) => ({ id: s.id, label: s.label || s.id, go: () => { handle.focusSection(s.id); } }));\n if (!wantZones && entries.length > MAX_3D_SECTION_PILLS) {\n const select = document.createElement('select');\n select.setAttribute('aria-label', this.tf('picker.jumpToSection', 'Jump to section'));\n const placeholder = document.createElement('option');\n placeholder.value = '';\n placeholder.textContent = this.tf('picker.jumpToSection', 'Jump to section');\n select.appendChild(placeholder);\n for (const entry of entries) {\n const option = document.createElement('option');\n option.value = entry.id;\n option.textContent = entry.label;\n select.appendChild(option);\n }\n select.addEventListener('change', () => {\n entries.find((entry) => entry.id === select.value)?.go();\n });\n row.appendChild(select);\n } else {\n for (const e of entries) {\n const b = document.createElement('button');\n b.type = 'button';\n b.textContent = e.label;\n b.addEventListener('click', () => {\n e.go();\n setFinderOpen(false);\n });\n row.appendChild(b);\n }\n }\n nav.appendChild(row);\n }\n\n if (wantLocator) {\n const locator = document.createElement('div');\n locator.className = 'sl-view3d-locator';\n locator.setAttribute('role', 'group');\n locator.setAttribute('aria-label', 'Find an exact seat in 3D');\n\n const sectionSelect = document.createElement('select');\n sectionSelect.setAttribute('aria-label', 'Choose section in 3D');\n const rowSelect = document.createElement('select');\n rowSelect.setAttribute('aria-label', 'Choose row in 3D');\n const seatSelect = document.createElement('select');\n seatSelect.setAttribute('aria-label', 'Choose seat in 3D');\n const view = document.createElement('button');\n view.type = 'button';\n view.textContent = 'Inspect seat';\n view.disabled = true;\n\n const fill = (\n select: HTMLSelectElement,\n placeholder: string,\n entries: Array<{ id: string; label: string }>,\n ): void => {\n select.replaceChildren();\n const first = document.createElement('option');\n first.value = '';\n first.textContent = placeholder;\n select.appendChild(first);\n for (const entry of entries) {\n const option = document.createElement('option');\n option.value = entry.id;\n option.textContent = entry.label;\n select.appendChild(option);\n }\n select.value = '';\n };\n\n fill(sectionSelect, '1. Section', allSections.map((section) => ({\n id: section.id,\n label: `${section.label} · ${section.seatCount.toLocaleString()} seats`,\n })));\n fill(rowSelect, '2. Row', []);\n fill(seatSelect, '3. Seat', []);\n rowSelect.disabled = true;\n seatSelect.disabled = true;\n\n sectionSelect.addEventListener('change', () => {\n const sectionId = sectionSelect.value;\n view.disabled = true;\n fill(seatSelect, '3. Seat', []);\n seatSelect.disabled = true;\n if (!sectionId || !handle.focusSection(sectionId)) {\n fill(rowSelect, '2. Row', []);\n rowSelect.disabled = true;\n return;\n }\n const rows = handle.rows(sectionId);\n fill(rowSelect, '2. Row', rows.map((row) => ({\n id: row.id,\n label: `${row.label} · ${row.seatCount} seats`,\n })));\n rowSelect.disabled = rows.length === 0;\n });\n\n rowSelect.addEventListener('change', () => {\n const rowId = rowSelect.value;\n view.disabled = true;\n if (!rowId || !handle.focusRow(rowId)) {\n fill(seatSelect, '3. Seat', []);\n seatSelect.disabled = true;\n return;\n }\n const seats = handle.seatsInRow(rowId);\n fill(seatSelect, '3. Seat', seats);\n seatSelect.disabled = seats.length === 0;\n });\n\n seatSelect.addEventListener('change', () => {\n const seatId = seatSelect.value;\n view.disabled = !seatId;\n });\n view.addEventListener('click', () => {\n const seatId = seatSelect.value;\n // Keyboard and screen-reader users must reach the same candidate\n // decision surface as a canvas tap. This creates only the existing\n // temporary confirm candidate; it is excluded from checkout until the\n // buyer explicitly selects it, and saving to compare releases it.\n if (seatId) {\n setFinderOpen(false);\n this.onView3dSeatPick(seatId);\n }\n });\n\n locator.append(sectionSelect, rowSelect, seatSelect, view);\n nav.appendChild(locator);\n }\n\n overlay.appendChild(nav);\n }\n\n private async enter3d(flySeatId?: string): Promise<void> {\n if (this.view3dEl || !this.canOffer3d() || !this.els.map) return;\n const doc = this.controller.doc;\n if (!doc) return;\n this.buyerView = 'venue3d';\n this.view3dTargetSeatId = null;\n this.opts.onBuyerViewChange?.({ view: 'venue3d', ...(flySeatId ? { seatId: flySeatId } : {}) });\n this.root?.setAttribute('data-view3d', 'on');\n this.dismissConfirm();\n this.syncProjection();\n\n const overlay = document.createElement('div');\n overlay.className = 'sl-view3d';\n overlay.setAttribute('role', 'group');\n overlay.setAttribute('aria-label', 'Interactive 3D venue view');\n const back = document.createElement('button');\n back.type = 'button';\n back.className = 'sl-view3d-back';\n back.innerHTML =\n '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M15 18l-6-6 6-6\"/></svg>'\n + `<span>${this.tf('picker.backToMap', 'Back to map')}</span>`;\n const backLabel = back.querySelector<HTMLSpanElement>('span');\n const setJourneyTarget = (seatId: string | null): void => {\n this.view3dTargetSeatId = seatId;\n const atSeat = !!seatId;\n overlay.classList.toggle('is-seat-focused', atSeat);\n const label = atSeat\n ? this.tf('picker.backToVenue', 'Back to venue')\n : this.tf('picker.backToMap', 'Back to map');\n if (backLabel) backLabel.textContent = label;\n back.setAttribute('aria-label', label);\n };\n back.addEventListener('click', () => {\n if (this.view3dTargetSeatId && this.view3dHandle) {\n this.view3dHandle.focusOverview();\n return;\n }\n this.exit3d();\n });\n overlay.appendChild(back);\n const fullscreen = document.createElement('button');\n fullscreen.type = 'button';\n fullscreen.className = 'sl-view3d-fs';\n fullscreen.textContent = '⛶';\n fullscreen.setAttribute('aria-label', 'Full screen');\n fullscreen.setAttribute('aria-pressed', String(!!document.fullscreenElement || this.fsFallback || this.framedFs));\n fullscreen.addEventListener('click', () => this.toggleFullscreen());\n overlay.appendChild(fullscreen);\n const loading = document.createElement('div');\n loading.className = 'sl-view3d-loading';\n loading.setAttribute('role', 'status');\n loading.setAttribute('aria-live', 'polite');\n loading.textContent = this.tf('picker.loading3d', 'Building the 3D venue…');\n overlay.appendChild(loading);\n this.els.map.appendChild(overlay);\n this.view3dEl = overlay;\n this.syncView3dCompareChip();\n requestAnimationFrame(() => { overlay.style.opacity = '1'; });\n\n const gen = ++this.view3dGen;\n try {\n const seats = expandChart(doc);\n const mod = await loadVenue3d();\n // Left 3D (or was torn down) while the OGL chunk loaded → abandon.\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n const prepared = await mod.prepareVenue3D({ doc, seats });\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n const handle = mod.mountVenue3D(overlay, { doc, seats, prepared }, {\n // A strict contain fit turns a wide bowl into a postage stamp inside a\n // phone. The bounded portrait fit was validated against every UX-lab\n // fixture; keep editor previews strict while making buyer seats legible.\n portraitOverviewCrop: true,\n // Premium buyer mode lands at the modeled seated-eye and locks the\n // venue orbit there. Explicit look-around rotates at that same origin;\n // zooming cannot escape through the shell or reveal backstage geometry.\n arriveAtSeatEye: true,\n seatViewActionLabel: (seatId) => this.allSeats().find((seat) => seat.id === seatId)?.viewUrl\n ? this.tf('picker.openAuthored360', 'Open venue 360°')\n : this.tf('picker.lookAroundLive3d', 'Look around in live 3D'),\n onSeatPick: (id) => this.onView3dSeatPick(id),\n onSeatInspect: (id) => this.onView3dSeatPick(id),\n onSectionFocusChange: (sectionId) => {\n // A stand clicked directly in the 3D overview must drive the same\n // Section → Row → Seat ladder as the exact-seat control. Dispatching\n // change populates the row list; the equality guard prevents the\n // callback from looping when that handler re-focuses the camera.\n const select = overlay.querySelector<HTMLSelectElement>(\n 'select[aria-label=\"Choose section in 3D\"]',\n );\n const next = sectionId ?? '';\n if (!select || select.value === next) return;\n select.value = next;\n select.dispatchEvent(new Event('change'));\n },\n onViewTargetChange: (seatId) => {\n overlay.querySelector('.sl-view3d-nav')?.classList.toggle('is-seat-focused', !!seatId);\n setJourneyTarget(seatId);\n this.opts.onBuyerViewChange?.({\n view: 'venue3d',\n ...(seatId ? { seatId } : {}),\n });\n },\n // Deferred off the tap gesture: generateSeatPanorama walks every seat\n // (O(n) on a 13k chart), and the module prefetches at pick — by the\n // time the flight lands (~2.5s) the idle render has long finished. A\n // null view REJECTS so the module's no-panorama path keeps the buyer\n // in orbit instead of dissolving into an empty overlay.\n getSeatView: (id) =>\n new Promise((resolve, reject) => {\n const run = () => {\n void this.seatViewFor3d(id).then((view) => {\n if (view) resolve(view);\n else reject(new Error('seat_view_unavailable'));\n });\n };\n const ric = (globalThis as { requestIdleCallback?: (cb: () => void, opts?: { timeout: number }) => void }).requestIdleCallback;\n if (typeof ric === 'function') ric(run, { timeout: 1500 });\n else setTimeout(run, 50);\n }),\n onAnalytics: (event, props) => this.emit3dAnalytics(event, props),\n });\n this.view3dHandle = handle;\n loading.remove();\n this.pushAvailabilityTo3d();\n this.syncSelectionTo3d();\n this.buildView3dNav(overlay, handle);\n if (flySeatId) void handle.flyToSeat(flySeatId);\n } catch (err) {\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n this.opts.onError?.(err);\n this.toast(this.tf('picker.unavailable3d', '3D could not start. The seat map is still available.'), 'warning');\n this.exit3d();\n }\n }\n\n private exit3d(): void {\n if (this.buyerView !== 'venue3d' && !this.view3dEl) return;\n this.view3dGen++; // supersede any in-flight mount\n this.buyerView = 'map';\n this.view3dTargetSeatId = null;\n this.opts.onBuyerViewChange?.({ view: 'map' });\n this.root?.removeAttribute('data-view3d');\n this.closeSeatConfidencePassport(false);\n this.closeView3dComparison(false);\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n try { this.view3dHandle?.dispose(); } catch { /* GL teardown best-effort */ }\n this.view3dHandle = null;\n const overlay = this.view3dEl;\n this.view3dEl = null;\n if (overlay) {\n overlay.style.opacity = '0';\n setTimeout(() => overlay.remove(), 320);\n }\n this.syncProjection();\n // Zoom/pan of the underlying 2D stage was never touched, so the map is\n // restored exactly. Re-offer the confirm the buyer left via \"See it in 3D\".\n const seat = this.view3dReturnSeat;\n this.view3dReturnSeat = null;\n if (seat && this.committedSelection().some((s) => s.id === seat.id)\n && this.opts.confirmSelection !== false) {\n this.showConfirm(seat);\n }\n }\n\n /** Current active/restored hold reflected in the tray. */\n getCurrentHold(): HoldResult | null {\n return this.hold;\n }\n\n /** Explicit host-driven hold restore (automatic session restore is on by default). */\n async resumeHold(holdId: string): Promise<HoldResult | null> {\n return this.resumeHoldFromServer(holdId, false);\n }\n\n /** Remove one server-held ticket while keeping the rest of the hold active. */\n async removeHeldTicket(label: string): Promise<boolean> {\n return this.removeHeldLabel(label);\n }\n\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: SeatPickerBestAvailableOptions = {},\n ): Promise<HoldResult | null> {\n if (this.salesClosed || this.bestAvailableBusy) return null;\n qty = Math.max(1, Math.min(this.maxTickets, Math.floor(qty)));\n if (this.confirmSeat) this.cancelConfirm();\n this.bestAvailableConfirm = false;\n this.bestAvailableBusy = true;\n const button = this.els.tray?.querySelector<HTMLButtonElement>('.sl-ba-go');\n if (button) {\n button.disabled = true;\n button.innerHTML = '<span class=\"sl-ba-spin\" aria-hidden=\"true\"></span>Finding…';\n }\n try {\n // Same checkout window as a clicked selection — see the CTA's hold() call.\n const h = await this.controller.bestAvailable(qty, categoryKey, { ...opts, ttlMs: this.opts.holdTtlMs });\n if (h) {\n this.hold = { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items };\n this.handedOff = false;\n this.bookedShown = false;\n this.gaQty.clear();\n this.startHoldTimer(h.expiresAt);\n this.flashHeldSeats(this.hold);\n this.syncTray();\n this.emitHoldChange();\n // Premium quick-pick asked for a premium block but no full block of\n // `qty` existed → we held the best overall instead. Surface a subtle note.\n if (opts.preferPremium && h.seats.length && !h.seats.every((s) => s.commercial?.premium)) {\n this.toast(t('picker.premiumFallbackNote', { count: qty }), 'neutral');\n }\n return this.hold;\n }\n return null;\n } catch (err) {\n this.opts.onError?.(err);\n const reason = (err as { reason?: string })?.reason;\n const message = reason === 'not_enough_together'\n ? `We couldn't find ${qty} seats together. Try fewer seats or another ticket type.`\n : reason === 'sold_out'\n ? 'That ticket type is sold out. Try another ticket type.'\n : reason === 'event_closed'\n ? 'Seat sales have closed for this event.'\n : 'Those seats are no longer available. Try another quantity or ticket type.';\n this.toast(message, 'error');\n return null;\n } finally {\n this.bestAvailableBusy = false;\n this.syncTray();\n }\n }\n\n async release(): Promise<void> {\n const tracked = this.hold;\n const controllerHold = this.controller.currentHold();\n let released = true;\n if (controllerHold) {\n released = await this.controller.release();\n } else if (tracked) {\n // The live controller can legitimately settle/clear its local hold before\n // the shell finishes dismissing. The shell still owns the server handoff,\n // so release from that authoritative copy instead of silently no-oping.\n const labels = [...new Set([\n ...(tracked.items ?? []).map((item) => item.label),\n ...(tracked.seats ?? []).map((seat) => seat.label),\n ])];\n if (labels.length) {\n try {\n await this.api.release(this.opts.event, labels, tracked.holdId);\n } catch (error) {\n this.opts.onError?.(error);\n released = false;\n }\n }\n }\n if (!released) {\n this.toast(\"Couldn't release your tickets. Your hold is unchanged.\", 'error');\n return;\n }\n this.hold = null;\n this.forgetHold();\n this.handedOff = false;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.stopHoldTimer();\n this.gaQty.clear();\n this.syncTray();\n this.emitHoldChange();\n }\n\n // ---- buyer access (Sales Channels) ---------------------------------------\n\n /**\n * Realtime for an access-scoped picker.\n *\n * A tokenless picker never gets here: `access` is null, `PubApi.socketUrl()`\n * returns the URL it always has, and PickerController keeps its own socket\n * and its own legacy frames. Nothing about the public path changes.\n */\n private startRealtime(): void {\n if (!this.access?.configured || !this.pubApi || this.realtime) return;\n const event = this.opts.event;\n this.realtime = new BuyerRealtimeClient({\n url: this.pubApi.subscribeUrl(event),\n mintTicket: () => this.pubApi!.subscribeTicket(event),\n onAccessUnavailable: (state) => {\n this.opts.onAccessUnavailable?.(state);\n this.showAccessPanel(state);\n },\n sink: createControllerSink(this.controller, {\n flashOnLiveChange: true,\n onStatusChange: () => {\n this.syncPrices();\n this.scheduleOfferRefresh(true);\n this.detectBooked();\n this.refreshMinimap();\n this.pushAvailabilityTo3d();\n },\n onSelectedObjectUnavailable: (labels, reason) => {\n this.opts.onSelectedObjectUnavailable?.({ labels, reason });\n this.syncTray();\n this.toast(\n reason === 'ineligible'\n ? this.tf(\n 'picker.seatNoLongerYours',\n 'Some seats are no longer available to you. They have been removed from your order.',\n )\n : this.tf(\n 'picker.seatTaken',\n 'Someone else took a seat you had picked. It has been removed from your order.',\n ),\n 'warning',\n );\n },\n }),\n });\n this.realtime.start();\n }\n\n /**\n * Re-acquire the buyer access session — call after your app has re-authorized\n * the buyer. A revoked session cannot recover any other way. Resolves true\n * when a fresh bearer is held; the map and the realtime feed resume with it.\n */\n async refreshAccess(): Promise<boolean> {\n if (!this.access?.configured) return false;\n const ok = await this.access.refresh('manual');\n if (!ok) return false;\n this.dismissAccessPanel();\n await this.controller.refresh();\n if (this.realtime) this.realtime.restart();\n else this.startRealtime();\n return true;\n }\n\n /**\n * The buyer-facing access state. Plain language, no internal vocabulary, and\n * never a channel name, id or count — the buyer is told what happened and\n * what to do, not which allocation they missed (guide §7, §10).\n *\n * Held seats are deliberately left alone: a hold is relinquished by its own\n * opaque capability, not by channel access, so losing access never strands\n * inventory and never silently drops a buyer's cart (guide §9).\n */\n private showAccessPanel(state: { reason: BuyerAccessUnavailableReason; retryable: boolean }): void {\n if (this.destroyed || !this.root) return;\n const copy = this.accessCopy(state.reason);\n this.dismissAccessPanel();\n const panel = document.createElement('div');\n panel.className = 'sl-access';\n panel.setAttribute('role', 'status');\n panel.setAttribute('aria-live', 'polite');\n const text = document.createElement('div');\n const title = document.createElement('div');\n title.className = 'sl-access-title';\n title.textContent = copy.title;\n const body = document.createElement('div');\n body.className = 'sl-access-body';\n body.textContent = copy.body;\n text.appendChild(title);\n text.appendChild(body);\n if (copy.action) {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'sl-access-act';\n button.textContent = copy.action;\n button.addEventListener('click', () => {\n void this.refreshAccess();\n });\n text.appendChild(button);\n }\n panel.appendChild(text);\n (this.regions?.['bottom-center'] ?? this.root).appendChild(panel);\n this.accessEl = panel;\n }\n\n private dismissAccessPanel(): void {\n this.accessEl?.remove();\n this.accessEl = null;\n }\n\n private accessCopy(reason: BuyerAccessUnavailableReason): {\n title: string;\n body: string;\n action?: string;\n } {\n switch (reason) {\n case 'paused':\n return {\n title: this.tf('picker.accessPausedTitle', 'These seats are on hold right now'),\n body: this.tf(\n 'picker.accessPausedBody',\n 'The organizer has paused this selection. Try again in a few minutes.',\n ),\n action: this.tf('picker.accessRetry', 'Try again'),\n };\n case 'revoked':\n return {\n title: this.tf('picker.accessRevokedTitle', 'This access link is no longer active'),\n body: this.tf(\n 'picker.accessRevokedBody',\n 'Ask whoever sent you here for a new link to keep booking these seats.',\n ),\n };\n case 'no_token':\n case 'provider_failed':\n return {\n title: this.tf('picker.accessExpiredTitle', 'Your access session has ended'),\n body: this.tf(\n 'picker.accessExpiredBody',\n 'Sign in again, or reload the page, to keep browsing these seats. Anything you are already holding stays yours.',\n ),\n action: this.tf('picker.accessRetry', 'Try again'),\n };\n default:\n return {\n title: this.tf('picker.accessInvalidTitle', 'We couldn’t verify your access'),\n body: this.tf(\n 'picker.accessInvalidBody',\n 'You can still book anything shown as available. Contact whoever sent you here for access to the rest.',\n ),\n };\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.realtime?.stop();\n this.realtime = null;\n this.dismissAccessPanel();\n this.access?.clear();\n // Closing/tearing down before checkout means the buyer abandoned any\n // best-available hold. Release it server-side; a handed-off checkout keeps\n // its hold alive across the host's route transition.\n if (this.hold && !this.handedOff) void this.controller.release();\n this.closeConfirm();\n this.dismissTableDialog(false);\n this.closeSeatView();\n // A payment card outlives its own mount node (it listens on the document for\n // ESC), so it is torn down explicitly rather than left to root.remove().\n this.closeCheckoutPanel();\n this.exit3d(); // dispose GL + remove the 3D overlay if it's up\n this.buyerAssetUrls.dispose();\n this.stopHoldTimer();\n if (this.toastTimer) clearTimeout(this.toastTimer);\n if (this.liveTimer) clearTimeout(this.liveTimer);\n if (this.offerRefreshTimer) clearTimeout(this.offerRefreshTimer);\n if (this.offerBoundaryTimer) clearTimeout(this.offerBoundaryTimer);\n this.offerRefreshTimer = null;\n this.offerBoundaryTimer = null;\n if (this.offerVisibilityHandler) {\n document.removeEventListener('visibilitychange', this.offerVisibilityHandler);\n this.offerVisibilityHandler = null;\n }\n for (const timer of this.motionTimers) clearTimeout(timer);\n this.motionTimers.clear();\n this.ro?.disconnect();\n this.ro = null;\n // Don't strand a host frame pinned fullscreen across a route teardown.\n if (this.framedFs) this.setFramedFs(false);\n if (this.escHandler) document.removeEventListener('keydown', this.escHandler);\n if (this.fsChangeHandler) document.removeEventListener('fullscreenchange', this.fsChangeHandler);\n if (this.fsEscHandler) window.removeEventListener('keydown', this.fsEscHandler);\n this.controller.destroy();\n this.projectionEl = null;\n this.root?.remove();\n this.root = null;\n if (this.modalScrim) {\n this.modalScrim.remove();\n this.modalScrim = null;\n if (this.prevFocus?.isConnected) this.prevFocus.focus({ preventScroll: true });\n this.prevFocus = null;\n }\n }\n}\n","/**\n * Token-safe delivery for Event-scoped buyer media.\n *\n * The chart document contains an ordinary URL so it remains portable JSON, but\n * the browser must not assign that URL directly to <img>/CSS: private and\n * Platform events need an Authorization header, which those element requests\n * cannot attach. The picker asks its transport for bytes, creates an in-memory\n * object URL, and revokes every URL when the picker is destroyed.\n */\n\nconst SAFE_ASSET = /^[a-zA-Z0-9._-]+$/;\n\nexport interface BuyerEventAssetReference {\n eventKey: string;\n asset: string;\n}\n\n/** Parse only SeatLayer's event-scoped buyer-asset path. */\nexport function buyerEventAssetReference(value: string): BuyerEventAssetReference | null {\n let url: URL;\n try {\n // A fixed dummy base also supports a future relative chart projection\n // without trusting the embedding page's current location.\n url = new URL(value, 'https://seatlayer.invalid');\n } catch {\n return null;\n }\n if (url.search || url.hash) return null;\n const match = /^\\/pub\\/events\\/([^/]+)\\/assets\\/([^/]+)$/.exec(url.pathname);\n if (!match) return null;\n try {\n const eventKey = decodeURIComponent(match[1]);\n const asset = decodeURIComponent(match[2]);\n if (!eventKey || !SAFE_ASSET.test(asset)) return null;\n return { eventKey, asset };\n } catch {\n return null;\n }\n}\n\nfunction looksLikeBuyerAsset(value: string): boolean {\n try {\n return /^\\/pub\\/events\\/[^/]+\\/assets(?:\\/|$)/.test(\n new URL(value, 'https://seatlayer.invalid').pathname,\n );\n } catch {\n return false;\n }\n}\n\nexport type BuyerAssetLoader = (eventKey: string, asset: string) => Promise<Blob>;\n\n/**\n * One picker-lifetime cache. Reusing a blob URL avoids downloading an 8K\n * panorama again when a buyer opens the same row/venue view from another seat.\n */\nexport class BuyerAssetObjectUrls {\n private readonly pending = new Map<string, Promise<string | null>>();\n private readonly created = new Set<string>();\n private disposed = false;\n\n constructor(\n private readonly eventKey: string,\n private readonly load?: BuyerAssetLoader,\n ) {}\n\n /**\n * External organizer/CDN URLs pass through unchanged. SeatLayer event assets\n * never do: they require the transport, and a reference for another Event is\n * refused instead of being loaded anonymously.\n */\n resolve(reference: string): Promise<string | null> {\n const parsed = buyerEventAssetReference(reference);\n if (!parsed) {\n // A malformed SeatLayer buyer-media path is never passed to <img>/CSS,\n // where it would bypass the authenticated byte transport.\n return Promise.resolve(looksLikeBuyerAsset(reference) ? null : reference);\n }\n if (parsed.eventKey !== this.eventKey || !this.load || this.disposed) return Promise.resolve(null);\n\n const existing = this.pending.get(reference);\n if (existing) return existing;\n\n const task = this.load(this.eventKey, parsed.asset).then((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n if (this.disposed) {\n URL.revokeObjectURL(objectUrl);\n return null;\n }\n this.created.add(objectUrl);\n return objectUrl;\n }).catch((error) => {\n // A transient load can be retried on the buyer's next explicit open.\n this.pending.delete(reference);\n throw error;\n });\n this.pending.set(reference, task);\n return task;\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const url of this.created) URL.revokeObjectURL(url);\n this.created.clear();\n this.pending.clear();\n }\n}\n","/**\n * Buyer-safe ticket-offer availability shared by the canonical picker and the\n * hosted event-page templates.\n *\n * This module intentionally owns the wire parser. A hosted page, iframe, popup\n * and SDK mount must refuse or accept the same payload; duplicating this reader\n * is how one surface eventually prints a price another surface will not charge.\n */\n\nexport type SaleState = 'on-sale' | 'low' | 'sold-out' | 'presale' | 'closed';\n\nexport interface TicketOfferSummary {\n /** Legacy ordering fields kept for older page templates and payloads. */\n index: number;\n count: number;\n /** Units currently available at this offer price; null means unlimited. */\n remaining: number | null;\n /** Buyer-facing fields added by the offers UX. Absent on older workers. */\n id?: string;\n name?: string;\n categoryKey?: string | null;\n startsAt?: number | null;\n endsAt?: number | null;\n}\n\nexport interface TicketOfferPrice {\n categoryKey: string;\n /** Major units. What a hold on this category is charged right now. */\n price: number;\n /** Major units, or null. Printed only when genuinely higher. */\n previousPrice: number | null;\n /** Offer provenance for the price row. Absent on older workers. */\n offerId?: string;\n offerName?: string;\n remaining?: number | null;\n startsAt?: number | null;\n endsAt?: number | null;\n}\n\nexport interface TicketOfferAvailability {\n state: SaleState;\n /** Currently advertised offer price, in minor units. */\n fromPrice: number | null;\n previousPrice: number | null;\n currency: string | null;\n /** The highest-priority active buy offer, when one exists. */\n release: TicketOfferSummary | null;\n /** The next scheduled price offer. It does not close ordinary ticket sales. */\n upcoming: TicketOfferSummary | null;\n /** Server-resolved active offer prices by category, in major units. */\n prices: TicketOfferPrice[];\n}\n\nexport const SALE_STATES: readonly SaleState[] = [\n 'on-sale', 'low', 'sold-out', 'presale', 'closed',\n];\n\nfunction money(value: unknown): number | null | undefined {\n if (value === null || value === undefined) return null;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction timestamp(value: unknown): number | null | undefined {\n if (value === null || value === undefined) return null;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction parseSummary(value: unknown): TicketOfferSummary | null | undefined {\n if (value == null) return null;\n if (typeof value !== 'object' || Array.isArray(value)) return undefined;\n const source = value as Record<string, unknown>;\n const count = source.count;\n const index = source.index;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 1) return undefined;\n if (typeof count !== 'number' || !Number.isInteger(count) || count < index) return undefined;\n const remaining = source.remaining;\n if (remaining != null && (typeof remaining !== 'number' || !Number.isInteger(remaining) || remaining < 0)) {\n return undefined;\n }\n\n const result: TicketOfferSummary = {\n index,\n count,\n remaining: remaining == null ? null : remaining,\n };\n if (source.id !== undefined) {\n if (typeof source.id !== 'string' || !source.id.trim()) return undefined;\n result.id = source.id.trim();\n }\n if (source.name !== undefined) {\n if (typeof source.name !== 'string' || !source.name.trim()) return undefined;\n result.name = source.name.trim();\n }\n if (source.categoryKey !== undefined) {\n if (source.categoryKey !== null && (typeof source.categoryKey !== 'string' || !source.categoryKey.trim())) {\n return undefined;\n }\n result.categoryKey = source.categoryKey == null ? null : source.categoryKey.trim();\n }\n for (const key of ['startsAt', 'endsAt'] as const) {\n if (source[key] === undefined) continue;\n const parsed = timestamp(source[key]);\n if (parsed === undefined) return undefined;\n result[key] = parsed;\n }\n return result;\n}\n\n/** Parse a public offer payload without repairing a half-understood price. */\nexport function parseTicketOfferAvailability(body: unknown): TicketOfferAvailability | null {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null;\n const raw = body as Record<string, unknown>;\n const state = SALE_STATES.find((candidate) => candidate === raw.state);\n if (!state) return null;\n\n const fromPrice = money(raw.fromPrice);\n const previousPrice = money(raw.previousPrice);\n if (fromPrice === undefined || previousPrice === undefined) return null;\n const currency = raw.currency == null ? null\n : typeof raw.currency === 'string' && raw.currency.trim() ? raw.currency.trim() : undefined;\n if (currency === undefined) return null;\n\n const release = parseSummary(raw.release);\n if (release === undefined) return null;\n const upcoming = raw.upcoming === undefined ? null : parseSummary(raw.upcoming);\n if (upcoming === undefined) return null;\n\n let prices: TicketOfferPrice[] = [];\n if (raw.prices != null) {\n if (!Array.isArray(raw.prices)) return null;\n const parsed: TicketOfferPrice[] = [];\n for (const entry of raw.prices) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;\n const row = entry as Record<string, unknown>;\n const categoryKey = typeof row.categoryKey === 'string' ? row.categoryKey.trim() : '';\n if (!categoryKey) return null;\n const price = money(row.price);\n const previous = money(row.previousPrice);\n if (price === undefined || price === null || previous === undefined) return null;\n const item: TicketOfferPrice = { categoryKey, price, previousPrice: previous };\n if (row.offerId !== undefined) {\n if (typeof row.offerId !== 'string' || !row.offerId.trim()) return null;\n item.offerId = row.offerId.trim();\n }\n if (row.offerName !== undefined) {\n if (typeof row.offerName !== 'string' || !row.offerName.trim()) return null;\n item.offerName = row.offerName.trim();\n }\n if (row.remaining !== undefined) {\n if (row.remaining !== null && (typeof row.remaining !== 'number'\n || !Number.isInteger(row.remaining) || row.remaining < 0)) return null;\n item.remaining = row.remaining == null ? null : row.remaining;\n }\n for (const key of ['startsAt', 'endsAt'] as const) {\n if (row[key] === undefined) continue;\n const at = timestamp(row[key]);\n if (at === undefined) return null;\n item[key] = at;\n }\n parsed.push(item);\n }\n prices = parsed;\n }\n\n return { state, fromPrice, previousPrice, currency, release, upcoming, prices };\n}\n\n/**\n * The earliest FUTURE instant at which the advertised offer schedule changes\n * on its own — a window opening or closing — or null when nothing scheduled\n * lies ahead. This is what lets the picker sleep until the transition instead\n * of asking the server every few seconds whether the clock has moved: every\n * other way the answer changes (a purchase, a hold expiring, an organizer\n * edit that touches seats) already arrives as a live seat frame.\n */\nexport function nextOfferTransitionAt(\n availability: TicketOfferAvailability | null,\n now: number,\n): number | null {\n if (!availability) return null;\n let next: number | null = null;\n const consider = (at: number | null | undefined): void => {\n if (at != null && at > now && (next === null || at < next)) next = at;\n };\n for (const summary of [availability.release, availability.upcoming]) {\n consider(summary?.startsAt);\n consider(summary?.endsAt);\n }\n for (const price of availability.prices) {\n consider(price.startsAt);\n consider(price.endsAt);\n }\n return next;\n}\n\n/** Translate the server-resolved category map into SeatPicker pricing. */\nexport function ticketOfferPrices(\n availability: TicketOfferAvailability | null,\n): Record<string, number> {\n const map: Record<string, number> = {};\n for (const entry of availability?.prices ?? []) map[entry.categoryKey] = entry.price;\n return map;\n}\n","/**\n * Host-side helper for embedding the SeatLayer picker as an iframe.\n *\n * The picker (the /e/:key page, mounted `position:fixed; inset:0`) reports its\n * desired height and fullscreen intent to whatever page frames it, using the\n * picker wire contract:\n *\n * • `{ type: 'seatlayer:height', px:number }` — grow the iframe to `px`.\n * • `{ type: 'seatlayer:fullscreen', on:boolean }` — pin/unpin over the host.\n *\n * A framed picker cannot escape its own iframe with CSS, so it delegates both\n * concerns to the host. `attachPickerFrame` wires those two behaviours onto a\n * picker iframe and returns a detach function that tears everything back down.\n */\nexport interface AttachPickerFrameOptions {\n /**\n * Origin to accept messages from. Defaults to the origin parsed from\n * `iframe.src`. Messages from any other origin (or any other window) are\n * ignored — the picker posts with `targetOrigin:'*'`, so the host is the side\n * that must verify `event.origin`.\n */\n origin?: string;\n}\n\n/**\n * Attach the picker resize + fullscreen protocol to a picker iframe.\n *\n * ```ts\n * const iframe = document.querySelector('iframe#seatlayer')!;\n * const detach = attachPickerFrame(iframe);\n * // …later, when removing the embed:\n * detach();\n * ```\n *\n * @param iframe The `<iframe>` element pointing at a SeatLayer picker embed.\n * @param opts Optional `{ origin }` override for the accepted message origin.\n * @returns A detach function: removes the listener and restores any pinned state.\n */\nexport function attachPickerFrame(\n iframe: HTMLIFrameElement,\n opts: AttachPickerFrameOptions = {},\n): () => void {\n let expectedOrigin = opts.origin ?? '';\n if (!expectedOrigin) {\n try {\n expectedOrigin = new URL(iframe.src, window.location.href).origin;\n } catch {\n expectedOrigin = '';\n }\n }\n\n let pinned = false;\n let frameStyleBeforeFs: string | null = null;\n let docOverflowBeforeFs: string | null = null;\n let bodyOverflowBeforeFs: string | null = null;\n let lastAutoHeight = '';\n let keyHandler: ((event: KeyboardEvent) => void) | null = null;\n\n const pin = (): void => {\n if (pinned) return;\n pinned = true;\n frameStyleBeforeFs = iframe.getAttribute('style');\n Object.assign(iframe.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n border: '0',\n zIndex: '2147483000',\n background: '#101625',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const docEl = document.documentElement;\n docOverflowBeforeFs = docEl.style.overflow;\n docEl.style.overflow = 'hidden';\n if (document.body) {\n bodyOverflowBeforeFs = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') unpin();\n };\n window.addEventListener('keydown', keyHandler);\n };\n\n const unpin = (): void => {\n if (!pinned) return;\n pinned = false;\n if (frameStyleBeforeFs === null) iframe.removeAttribute('style');\n else iframe.setAttribute('style', frameStyleBeforeFs);\n frameStyleBeforeFs = null;\n // Re-apply any height reported while we were pinned.\n if (lastAutoHeight) iframe.style.height = lastAutoHeight;\n\n if (docOverflowBeforeFs !== null) {\n document.documentElement.style.overflow = docOverflowBeforeFs;\n docOverflowBeforeFs = null;\n }\n if (bodyOverflowBeforeFs !== null && document.body) {\n document.body.style.overflow = bodyOverflowBeforeFs;\n bodyOverflowBeforeFs = null;\n }\n if (keyHandler) {\n window.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n }\n };\n\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.source !== iframe.contentWindow) return;\n if (expectedOrigin && event.origin !== expectedOrigin) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n\n if (data.type === 'seatlayer:height') {\n if (typeof data.px === 'number' && Number.isFinite(data.px) && data.px > 0) {\n lastAutoHeight = `${Math.round(data.px)}px`;\n // While pinned the iframe fills the viewport; the height is re-applied on unpin.\n if (!pinned) iframe.style.height = lastAutoHeight;\n }\n return;\n }\n if (data.type === 'seatlayer:fullscreen') {\n if (data.on === true) pin();\n else if (data.on === false) unpin();\n }\n };\n\n window.addEventListener('message', onMessage);\n\n return (): void => {\n window.removeEventListener('message', onMessage);\n unpin();\n };\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["el","back","t","el","money","resolveContainer","target","import_core","DEFAULT_API_BASE","DEFAULT_MAX_SELECTION","resolveContainer","el","STYLE_ID","CSS","ensureStyle","pano","canView","mountCheckout","location","main"]}
1
+ {"version":3,"sources":["../src/hostedCheckout.ts","../src/index.ts","../src/SeatingChart.ts","../src/buyerRealtime.ts","../src/api.ts","../src/buyerAccess.ts","../src/seatLayerBrand.ts","../src/EmbeddedDesigner.ts","../src/SeatPicker.ts","../src/buyerAssets.ts","../src/offerAvailability.ts","../src/attachPickerFrame.ts"],"sourcesContent":["/**\n * Hosted checkout — the payment step, as a module nobody downloads until a\n * buyer actually asks to pay.\n *\n * This is the whole of what `checkout: 'hosted'` adds to SeatPicker: a card\n * that collects an email, starts a payment against `POST /pub/events/:key/\n * checkout`, hands off to the gateway, and waits for the webhook to land. It is\n * a straight port of the panel our own buyer page has shipped since hosted\n * checkout existed (`src/pages/CheckoutPanel.tsx`), with React and the app's\n * shared api client taken out.\n *\n * IT IMPORTS NOTHING AT RUNTIME. Not `@seatlayer/core`, not `./api`, not even a\n * type from `./SeatPicker` — every input arrives through {@link CheckoutMount},\n * including the two API calls, which arrive as functions. That is not\n * fastidiousness: this file is built as a standalone CDN asset\n * (`seatlayer-checkout.mjs`), and a single value import from the engine would\n * pull a second copy of it into that asset and undo the point of splitting.\n *\n * Three states, one card, because they are the same moment in the buyer's\n * journey and share every pixel of chrome:\n *\n * pay a live hold — collect an email and START a payment\n * resume back from a hosted gateway page — the hold and its line items\n * are gone with the old document, so this can only WAIT on the\n * order id that survived in the return URL. It must never offer\n * to start a second payment for a purchase that may have already\n * succeeded.\n * unavailable the event cannot take money here, and the buyer is holding\n * seats. Say which of the three reasons it is, because two of\n * them give opposite advice.\n */\n\n/** The gateways `payment-options` can name. */\nexport type CheckoutProviderName = 'stripe' | 'razorpay';\n\n/**\n * Why `payment-options` came back with an empty list. Mirrors the server enum\n * (`workers/api/src/checkout.ts`); see {@link unavailableCopy} for what each one\n * is allowed to say.\n */\nexport type CheckoutUnavailableReason =\n | 'not_configured'\n | 'payments_off_for_event'\n | 'unavailable_for_event';\n\n/** What `POST /pub/events/:key/checkout` returns. Exactly one handoff is set. */\nexport interface CheckoutSessionResult {\n orderId: string;\n totalMinor: number;\n currency: string;\n expiresAt: number;\n /** Hosted gateway page (Stripe) — leave for it. */\n redirectUrl?: string;\n /** In-page modal gateway (Razorpay) — open it here. */\n clientPayload?: Record<string, unknown>;\n}\n\n/** What `GET /pub/orders/:id/status` returns while the webhook is in flight. */\nexport interface CheckoutOrderStatus {\n orderId: string;\n status: string;\n totalMinor: number;\n currency: string;\n amountFormatted: string;\n seatCount: number;\n // Present once the order is settled: the confirmed card names the seats it\n // just sold and points at the hosted ticket page that outlives this modal.\n tickets?: Array<{\n label: string;\n token: string;\n status: 'issued' | 'checked_in' | 'void';\n checkedInAt: number | null;\n }>;\n /** Hosted ticket page — the durable re-entry point after the card closes. */\n ticketUrl?: string;\n /** Printable A4 PDF, up to three ticket cards per page. */\n pdfUrl?: string;\n}\n\n/** The buyer's held order, flattened out of the widget's CheckoutHandoff. */\nexport interface CheckoutOrderSummary {\n holdId: string;\n /** Epoch ms the hold expires — shown so the buyer knows their deadline. */\n expiresAt: number;\n currency: string;\n /** Total in MAJOR units, already carrying any host `pricing` overrides. */\n total: number;\n /** Buyer-facing unit labels (displayLabel where the designer set one). */\n labels: string[];\n}\n\nexport type CheckoutState =\n | { kind: 'pay'; order: CheckoutOrderSummary; provider: CheckoutProviderName | null }\n | { kind: 'resume'; orderId: string }\n | { kind: 'unavailable'; reason: CheckoutUnavailableReason; seatCount: number };\n\nexport interface CheckoutMount {\n /** Where the card mounts — the widget root, so every `--sl-*` token inherits. */\n root: HTMLElement;\n state: CheckoutState;\n /** `POST /pub/events/:key/checkout`, already bound to the event and client. */\n startSession(input: {\n holdId: string; buyerEmail: string; buyerName?: string;\n }): Promise<CheckoutSessionResult>;\n /** `GET /pub/orders/:id/status`. */\n orderStatus(orderId: string): Promise<CheckoutOrderStatus>;\n /** Buyer backed out, or closed a finished card. The hold is NOT touched. */\n onCancel(): void;\n /** The webhook landed and the order is paid. Fires at most once. */\n onConfirmed(order: CheckoutOrderStatus): void;\n /** Anything the buyer was already told about, forwarded to the host. */\n onError?(err: unknown): void;\n}\n\nexport interface CheckoutHandle {\n destroy(): void;\n}\n\n/** How long to wait on the webhook before telling the buyer to watch their email. */\nconst CONFIRM_TIMEOUT_MS = 90_000;\nconst CONFIRM_POLL_MS = 2_000;\nconst RAZORPAY_SCRIPT = 'https://checkout.razorpay.com/v1/checkout.js';\nconst STYLE_ID = 'seatlayer-checkout-style';\n\n/**\n * The card's stylesheet. Every colour, font and radius is a `--sl-*` token the\n * widget root already defines, so an organizer's accent and a host's `theme`\n * overrides reach the payment step without this module knowing either exists.\n *\n * The `@sl-css` marker opts it into build-time minification — see\n * cdn/minifyCssLiterals.ts. Keep writing it long-hand.\n */\nconst CSS = /* @sl-css */ `\n.sl-hco{position:absolute;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;\n padding:16px;background:color-mix(in srgb, var(--sl-bg) 82%, transparent);backdrop-filter:blur(3px)}\n.sl-hco-card{width:100%;max-width:380px;max-height:100%;overflow:auto;padding:22px;\n background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);\n border-radius:var(--sl-radius);box-shadow:0 18px 48px rgba(0,0,0,.28)}\n.sl-hco-title{margin:0 0 14px;font-size:19px;font-weight:650;letter-spacing:-.01em}\n.sl-hco-summary{margin-bottom:16px;padding-bottom:14px;border-bottom:1px solid var(--sl-line)}\n.sl-hco-seats{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}\n.sl-hco-seat{padding:3px 8px;font-size:12px;font-weight:600;border-radius:calc(var(--sl-radius) * .5);\n background:var(--sl-bg);border:1px solid var(--sl-line)}\n.sl-hco-total{display:flex;justify-content:space-between;align-items:baseline;font-size:14px}\n.sl-hco-total strong{font-size:17px;font-weight:700}\n.sl-hco-label{display:block;margin:12px 0 5px;font-size:12px;font-weight:600;color:var(--sl-muted)}\n.sl-hco-input{width:100%;padding:10px 11px;font:inherit;font-size:15px;color:var(--sl-text);\n background:var(--sl-bg);border:1px solid var(--sl-line);border-radius:calc(var(--sl-radius) * .55)}\n.sl-hco-input:focus-visible{outline:2px solid var(--sl-accent);outline-offset:1px}\n.sl-hco-pay{width:100%;margin-top:16px;padding:12px;font:inherit;font-size:15px;font-weight:650;\n color:var(--sl-accent-ink);background:var(--sl-accent);border:0;\n border-radius:calc(var(--sl-radius) * .55);cursor:pointer}\n.sl-hco-pay[disabled]{opacity:.5;cursor:default}\n.sl-hco-back{width:100%;margin-top:8px;padding:10px;font:inherit;font-size:14px;color:var(--sl-muted);\n background:none;border:0;cursor:pointer;text-decoration:underline}\n.sl-hco-note{margin:12px 0 0;font-size:12px;line-height:1.5;color:var(--sl-muted)}\n.sl-hco-note a{color:inherit;text-decoration:underline;text-underline-offset:2px}\n.sl-hco-status{margin:8px 0 0;font-size:14px;line-height:1.55}\n.sl-hco-error{color:var(--sl-danger, #c0392b)}\n.sl-hco-receipt{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin:14px 0 0;font-size:13px}\n.sl-hco-receipt dt{color:var(--sl-muted)}\n.sl-hco-receipt dd{margin:0;text-align:right}\n.sl-hco-ref{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all}\n.sl-hco-tickets{display:block;width:100%;margin-top:14px;padding:12px;font:inherit;font-size:15px;\n font-weight:650;text-align:center;text-decoration:none;color:var(--sl-accent-ink);\n background:var(--sl-accent);border-radius:calc(var(--sl-radius) * .55)}\n`;\n\nfunction ensureStyle(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\n/**\n * Money for the buyer's eye. `Intl` is the right answer everywhere it exists;\n * the fallback is a plain amount and a code, which is never wrong — only plain.\n */\nexport function formatMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(amount);\n } catch {\n return `${amount.toFixed(2)} ${currency}`;\n }\n}\n\n/**\n * What a buyer holding seats is told when the event cannot take their money,\n * and why the three differ. Pure, so the wording is unit-tested rather than\n * eyeballed.\n *\n * not_configured The organizer integrates by API and owns payment.\n * SeatLayer holds the inventory; their host takes the\n * money. Nothing is wrong and the buyer's checkout is\n * somewhere else on this very page.\n * payments_off_for_event The organizer sells other events through us and chose\n * not to sell this one online. NOTHING IS WRONG.\n * Telling this buyer to \"let the organiser know\" would\n * send them to complain about a deliberate decision.\n * unavailable_for_event The organizer switched this event on and it still\n * cannot charge — a test key against a live event, or a\n * gateway disconnected after assignment. Something IS\n * wrong and only they can fix it.\n *\n * None of them names a provider, a mode or an account: the buyer is anonymous\n * and the reason enum is the entire disclosure budget.\n */\nexport function unavailableCopy(reason: CheckoutUnavailableReason, seatCount: number): {\n title: string; body: string; detail: string;\n} {\n const held = `${seatCount} ${seatCount === 1 ? 'seat is' : 'seats are'} held for a limited time.`;\n if (reason === 'payments_off_for_event') {\n return {\n title: 'This event isn’t sold online',\n body: `${held} The organiser isn’t taking payment for this event here.`,\n detail: 'Nothing has been charged. Check where you found this event for how to get tickets.',\n };\n }\n if (reason === 'unavailable_for_event') {\n return {\n title: 'This event isn’t taking payment yet',\n body: `${held} Online payment is not switched on for this event.`,\n detail: 'Nothing has been charged. If you were sent here to pay, let the organiser know — '\n + 'only they can turn payment on for this event.',\n };\n }\n return {\n title: 'Finish in the ticketing checkout',\n body: `${held} Payment for this event is taken elsewhere.`,\n detail: 'Nothing has been charged. Continue in the checkout on this page to pay for your seats.',\n };\n}\n\n/**\n * Buyer-facing text for a server error code.\n *\n * Each one says what happened to their MONEY, because that is the only question\n * a buyer has at this moment. None of these paths can have charged them — the\n * charge does not exist until the gateway page — so every message says so.\n */\nexport function errorCopy(code: string | undefined): string {\n switch (code) {\n case 'gateway_not_connected':\n case 'payments_not_enabled_for_event':\n return 'This event is not taking online payments. Contact the organiser to buy these seats.';\n case 'provider_mismatch':\n // Only reachable if a caller sent a provider of its own. The widget never\n // does — it lets the event row decide — so this is a host integration bug,\n // and the buyer is told the one thing that is true for them.\n return 'This event’s payment setup changed while you were choosing. Nothing was charged — '\n + 'please try again.';\n case 'hold_not_active':\n case 'hold_not_found':\n return 'Your seats were released before checkout started. Nothing was charged — please pick again.';\n case 'checkout_already_started':\n return 'A payment for these seats is already in progress. Finish that one, or wait for it to '\n + 'time out before starting again.';\n case 'event_closed':\n return 'Sales for this event have closed.';\n case 'insufficient_hosted_credits':\n return 'Ticket sales are temporarily paused while the organiser updates their SeatLayer balance. '\n + 'Nothing was charged — please try again later or contact the organiser.';\n case 'gateway_currency_mismatch':\n case 'unsupported_currency':\n case 'mixed_currency_hold':\n case 'price_unusable':\n return 'These seats cannot be checked out right now because of a pricing configuration '\n + 'problem. Nothing was charged — please contact the organiser.';\n case 'rate_limited':\n return 'Too many attempts. Wait a moment and try again.';\n default:\n return 'We could not start the payment. Nothing was charged — please try again.';\n }\n}\n\n/** Razorpay's script attaches this constructor; typed narrowly at the call site. */\ninterface RazorpayCheckout { open(): void }\ntype RazorpayConstructor = new (options: Record<string, unknown>) => RazorpayCheckout;\n\nfunction loadRazorpay(): Promise<RazorpayConstructor> {\n const existing = (window as unknown as { Razorpay?: RazorpayConstructor }).Razorpay;\n if (existing) return Promise.resolve(existing);\n return new Promise((resolve, reject) => {\n // Reuse an in-flight tag if the buyer retries before the first load settles.\n const previous = document.querySelector<HTMLScriptElement>(`script[src=\"${RAZORPAY_SCRIPT}\"]`);\n const tag = previous ?? document.createElement('script');\n const done = (): void => {\n const ctor = (window as unknown as { Razorpay?: RazorpayConstructor }).Razorpay;\n if (ctor) resolve(ctor);\n else reject(new Error('razorpay_unavailable'));\n };\n tag.addEventListener('load', done, { once: true });\n tag.addEventListener('error', () => reject(new Error('razorpay_script_failed')), { once: true });\n if (previous) return;\n tag.src = RAZORPAY_SCRIPT;\n tag.async = true;\n document.head.appendChild(tag);\n });\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K, className?: string, text?: string,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (className) node.className = className;\n // textContent, never innerHTML: an event name, a seat label and a server\n // message all reach this card, and none of them is trusted markup.\n if (text !== undefined) node.textContent = text;\n return node;\n}\n\n/**\n * Mount the payment card.\n *\n * Returns a handle rather than a promise: the card outlives the call (the buyer\n * types, pays, waits), and the widget needs a way to tear it down if the host\n * destroys the picker mid-payment.\n */\nexport function mountCheckout(mount: CheckoutMount): CheckoutHandle {\n ensureStyle();\n\n let live = true;\n let confirmed = false;\n const scrim = el('div', 'sl-hco');\n scrim.setAttribute('role', 'dialog');\n scrim.setAttribute('aria-modal', 'true');\n const card = el('div', 'sl-hco-card');\n scrim.appendChild(card);\n\n const destroy = (): void => {\n live = false;\n scrim.remove();\n document.removeEventListener('keydown', onKey, true);\n };\n const cancel = (): void => {\n destroy();\n mount.onCancel();\n };\n function onKey(event: KeyboardEvent): void {\n if (event.key !== 'Escape' || !scrim.isConnected) return;\n // The picker has its own document-level ESC handler for modal mode. Stopping\n // here means one press closes the payment card, not the whole widget with a\n // payment possibly in flight.\n event.stopPropagation();\n event.preventDefault();\n cancel();\n }\n document.addEventListener('keydown', onKey, true);\n\n const title = el('h2', 'sl-hco-title', 'Checkout');\n const titleId = `sl-hco-t-${Math.random().toString(36).slice(2, 8)}`;\n title.id = titleId;\n scrim.setAttribute('aria-labelledby', titleId);\n\n /** Replace everything under the title — each phase owns the card's body. */\n const show = (...nodes: Node[]): void => {\n card.replaceChildren(title, ...nodes);\n };\n\n const fail = (message: string): void => {\n if (!live) return;\n const status = el('p', 'sl-hco-status sl-hco-error', message);\n status.setAttribute('role', 'alert');\n const back = el('button', 'sl-hco-back', 'Back to seats');\n back.type = 'button';\n back.addEventListener('click', cancel);\n show(status, back);\n };\n\n const waiting = (message: string): void => {\n if (!live) return;\n const status = el('p', 'sl-hco-status', message);\n status.setAttribute('role', 'status');\n show(status);\n };\n\n /**\n * Poll the order until the webhook lands.\n *\n * The buyer's browser is never the authority here — it is only waiting for\n * one. On timeout we tell them the truth (payment likely taken, confirmation\n * by email) rather than claiming a failure that did not happen.\n */\n const awaitConfirmation = async (orderId: string): Promise<void> => {\n waiting('Payment received — confirming your seats…');\n const deadline = Date.now() + CONFIRM_TIMEOUT_MS;\n while (live && Date.now() < deadline) {\n try {\n const body = await mount.orderStatus(orderId);\n if (!live) return;\n if (body.status === 'confirmed') {\n confirmed = true;\n title.textContent = 'Your tickets are confirmed';\n const status = el(\n 'p', 'sl-hco-status',\n `${body.seatCount} ${body.seatCount === 1 ? 'seat' : 'seats'} confirmed. `\n + 'Your tickets — with their door QR codes — are in your email.',\n );\n const receipt = el('dl', 'sl-hco-receipt');\n const seatLabels = (body.tickets ?? []).map((t) => t.label);\n if (seatLabels.length) {\n receipt.append(el('dt', undefined, 'Seats'), el('dd', undefined, seatLabels.join(', ')));\n }\n receipt.append(\n el('dt', undefined, 'Paid'),\n el('dd', undefined, `${body.amountFormatted} ${body.currency}`),\n el('dt', undefined, 'Order'),\n el('dd', 'sl-hco-ref', body.orderId),\n );\n const close = el('button', 'sl-hco-back', 'Close');\n close.type = 'button';\n close.addEventListener('click', cancel);\n if (body.ticketUrl) {\n // The durable exit: a hosted page owning the QRs and the PDF, so\n // closing this card is no longer the end of the buyer's artifacts.\n const view = el('a', 'sl-hco-tickets', 'View tickets & QR codes');\n view.href = body.ticketUrl;\n view.target = '_blank';\n view.rel = 'noreferrer';\n show(status, receipt, view, close);\n } else {\n show(status, receipt, close);\n }\n mount.onConfirmed(body);\n return;\n }\n if (body.status === 'failed' || body.status === 'expired') {\n fail(body.status === 'expired'\n ? 'Your seats were released before payment completed. Nothing was charged — please pick again.'\n : 'The payment did not complete. If you were charged, it has been refunded automatically.');\n return;\n }\n } catch {\n // A transient blip while polling is not an answer. Keep waiting.\n }\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS));\n }\n if (!live || confirmed) return;\n // Deliberately not an error: the money may well have gone through and the\n // webhook is just slow. The confirmation email is the durable receipt.\n fail('Still confirming with the payment provider. If your payment went through, your tickets '\n + 'will arrive by email shortly — you do not need to pay again.');\n };\n\n if (mount.state.kind === 'unavailable') {\n const copy = unavailableCopy(mount.state.reason, mount.state.seatCount);\n title.textContent = copy.title;\n const kicker = el('p', 'sl-hco-label', 'Seats held');\n const back = el('button', 'sl-hco-back', 'Back to seat map');\n back.type = 'button';\n back.addEventListener('click', cancel);\n card.replaceChildren(\n kicker, title,\n el('p', 'sl-hco-status', copy.body),\n el('p', 'sl-hco-note', copy.detail),\n back,\n );\n mount.root.appendChild(scrim);\n back.focus();\n return { destroy };\n }\n\n if (mount.state.kind === 'resume') {\n // A fresh document after a hosted gateway page. Everything except the order\n // id died with the old one, so this can only wait.\n mount.root.appendChild(scrim);\n void awaitConfirmation(mount.state.orderId);\n return { destroy };\n }\n\n const { order, provider } = mount.state;\n const summary = el('div', 'sl-hco-summary');\n const seats = el('div', 'sl-hco-seats');\n for (const label of order.labels) seats.appendChild(el('span', 'sl-hco-seat', label));\n const totalText = formatMoney(order.total, order.currency);\n const totalRow = el('div', 'sl-hco-total');\n totalRow.append(el('span', undefined, 'Total'), el('strong', undefined, totalText));\n summary.append(seats, totalRow);\n\n const form = el('form', 'sl-hco-form');\n const emailLabel = el('label', 'sl-hco-label', 'Email — your tickets go here');\n const email = el('input', 'sl-hco-input');\n email.type = 'email';\n email.required = true;\n email.autocomplete = 'email';\n email.placeholder = 'you@example.com';\n email.id = `${titleId}-email`;\n emailLabel.htmlFor = email.id;\n\n const nameLabel = el('label', 'sl-hco-label', 'Name (optional)');\n const name = el('input', 'sl-hco-input');\n name.type = 'text';\n name.autocomplete = 'name';\n name.placeholder = 'Your name';\n name.id = `${titleId}-name`;\n nameLabel.htmlFor = name.id;\n\n const pay = el('button', 'sl-hco-pay', `Pay ${totalText}`);\n pay.type = 'submit';\n pay.disabled = true;\n const back = el('button', 'sl-hco-back', 'Back to seats');\n back.type = 'button';\n back.addEventListener('click', cancel);\n\n const until = new Date(order.expiresAt)\n .toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n const note = el(\n 'p', 'sl-hco-note',\n `Your seats are held until ${until}. Payment is handled by `\n + `${provider === 'razorpay' ? 'Razorpay' : 'Stripe'} — we never see your card details.`,\n );\n const privacy = el('p', 'sl-hco-note');\n privacy.append('The event organizer and SeatLayer use your email to issue and manage your tickets. ');\n const privacyLink = el('a', undefined, 'Privacy Policy');\n privacyLink.href = 'https://seatlayer.io/privacy/';\n privacyLink.target = '_blank';\n privacyLink.rel = 'noreferrer';\n privacy.appendChild(privacyLink);\n\n const emailValid = (): boolean => /.+@.+\\..+/.test(email.value.trim());\n email.addEventListener('input', () => { pay.disabled = !emailValid(); });\n\n const start = async (): Promise<void> => {\n waiting('Opening secure payment…');\n try {\n const body = await mount.startSession({\n holdId: order.holdId,\n buyerEmail: email.value.trim(),\n // Deliberately no `provider`: since W2 the EVENT row decides which\n // gateway charges, and naming one here can only ever 409 on a mismatch\n // the buyer cannot do anything about.\n ...(name.value.trim() ? { buyerName: name.value.trim() } : {}),\n });\n if (!live) return;\n\n // Hosted-page provider: leave the page. Where the gateway sends the buyer\n // back is the SERVER's choice, not ours — see the `checkout` option's note\n // in SeatPicker.\n if (body.redirectUrl) {\n waiting('Taking you to secure payment…');\n window.location.assign(body.redirectUrl);\n return;\n }\n\n // In-page modal provider — the embed never leaves the host's page.\n if (body.clientPayload) {\n const payload = body.clientPayload as {\n key: string; orderId: string; amount: number; currency: string;\n name: string; prefill?: { email?: string; name?: string };\n };\n const Razorpay = await loadRazorpay();\n if (!live) return;\n waiting('Waiting for payment…');\n new Razorpay({\n key: payload.key,\n order_id: payload.orderId,\n amount: payload.amount,\n currency: payload.currency,\n name: payload.name,\n prefill: payload.prefill,\n // The handler fires on the browser's word alone, so it only starts the\n // wait — the webhook is what actually confirms the order.\n handler: () => { void awaitConfirmation(body.orderId); },\n modal: { ondismiss: () => { if (live) details(); } },\n }).open();\n return;\n }\n\n fail(errorCopy('gateway_unavailable'));\n } catch (err) {\n mount.onError?.(err);\n fail(errorCopy((err as { code?: string } | null)?.code));\n }\n };\n\n form.addEventListener('submit', (event) => {\n event.preventDefault();\n if (emailValid()) void start();\n });\n form.append(emailLabel, email, nameLabel, name, privacy, pay, back, note);\n\n const details = (): void => {\n title.textContent = 'Checkout';\n show(summary, form);\n pay.disabled = !emailValid();\n };\n details();\n mount.root.appendChild(scrim);\n email.focus();\n\n return { destroy };\n}\n","/**\n * @seatlayer/js — the framework-agnostic SeatLayer embed SDK.\n *\n * Works in any JS environment (plain HTML, React, Vue, Svelte, Angular, …).\n * Framework wrappers (@seatlayer/react, …) build on top of this.\n */\nexport { SeatingChart } from './SeatingChart';\nexport type { SeatingChartOptions, SelectedSeat, GAAreaAvailability } from './SeatingChart';\nexport { ApiError } from './api';\nexport type { HoldResult, ResumedHoldResult, HoldConflict, HoldLineItem, BestAvailableResult, PubApiOptions } from './api';\n// Hosted checkout (SeatPicker's `checkout: 'hosted'`). TYPES ONLY — the card\n// that takes the payment is a lazy chunk and never enters this entry's graph,\n// so importing these costs a host nothing at runtime.\nexport type {\n PaymentProviderName,\n PaymentOptionsReason,\n PaymentOptionsResult,\n CheckoutSessionResult,\n OrderStatusResult,\n} from './api';\n// Sales Channels — buyer access sessions (private channel inventory).\nexport { BuyerAccessContext, BuyerAccessUnavailableError, createBuyerAccessContext } from './buyerAccess';\nexport type {\n BuyerAccessToken,\n BuyerAccessTokenProvider,\n BuyerAccessRefreshReason,\n BuyerAccessUnavailableReason,\n BuyerAccessExpiredEvent,\n BuyerAccessUnavailableEvent,\n SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nexport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nexport type {\n RealtimeSink,\n StatusChange,\n Projection,\n SubscribeTicket,\n BuyerRealtimeOptions,\n} from './buyerRealtime';\nexport { EmbeddedDesigner } from './EmbeddedDesigner';\nexport type {\n EmbeddedDesignerOptions,\n EmbeddedDesignerMessage,\n EmbeddedDesignerEventType,\n} from './EmbeddedDesigner';\nexport type { SeatHoverDetails } from '@seatlayer/core';\nexport { SeatPicker } from './SeatPicker';\nexport type {\n SeatPickerOptions,\n SeatPickerTheme,\n SeatPickerPricing,\n SeatPickerBestAvailableOptions,\n SeatPickerBuyerView,\n SeatPickerBuyerViewOptions,\n CheckoutHandoff,\n CheckoutLineItem,\n} from './SeatPicker';\nexport type { PickerMapTheme, RendererViewMode } from '@seatlayer/core';\n// Ticket-offer availability: the payload `onOfferAvailabilityChange` republishes.\nexport { parseTicketOfferAvailability, ticketOfferPrices } from './offerAvailability';\nexport type {\n TicketOfferAvailability,\n TicketOfferPrice,\n TicketOfferSummary,\n SaleState,\n} from './offerAvailability';\n// Host helper for iframe picker embeds: auto-height + fullscreen pin/restore.\nexport { attachPickerFrame } from './attachPickerFrame';\nexport type { AttachPickerFrameOptions } from './attachPickerFrame';\n// Organizer runtime values live at `@seatlayer/js/manager` so the buyer entry\n// never eagerly loads the cockpit, channels application, or ManageApi. Keep\n// type-only compatibility here: TypeScript erases these exports from the graph.\nexport type {\n SeatManager,\n SeatManagerOptions,\n SeatManagerMode,\n EventScopedManageToken,\n SeatManagerCapability,\n SeatManagerTallies,\n SeatManagerActivity,\n SeatManagerActionResult,\n SeatManagerConnection,\n} from './SeatManager';\nexport type {\n ChannelsMode, ChannelsCapabilities, ChannelsClient, ChannelsModeHost, ChannelsRowView,\n ChannelsSeatView,\n} from './channelsMode';\nexport type {\n AccessIntentForbidsDetails,\n AccessLinkRecord,\n AccessLinkReveal,\n AccessLinkState,\n AccessLinkStatus,\n AccessLinkStatusRecord,\n ArchiveBlockedDetails,\n AssignmentBuckets,\n AssignmentDropDetails,\n AssignmentResult,\n BucketRow,\n ChannelAccessIntent,\n ChannelAccessSummary,\n ChannelCounts,\n ChannelListResult,\n ChannelRecord,\n ChannelSeatStatus,\n ChannelState,\n IntentSwitchBlockedDetails,\n SelectionSourceRow,\n} from './channelPlan';\nexport type {\n ManageApi,\n ManageApiError,\n ChannelAllocationPage,\n ChannelAuditEntry,\n ChannelAuditPage,\n ChannelPreviewProjection,\n ChannelAttribution,\n ChannelReportRow,\n ChannelReport,\n ChannelReportResult,\n ChannelReportLinkRecord,\n ChannelReportLinkReveal,\n ReportResult,\n ReportByStatus,\n ReportCategoryRow,\n ReportCategoryMeta,\n ControlRoomActivityEntry,\n ControlRoomSectionMetric,\n ControlRoomSnapshot,\n LogEntry,\n LogPage,\n InventoryBookingState,\n InventoryBookingObject,\n InventoryBooking,\n InventoryBookingsQuery,\n InventoryBookingsPage,\n InventoryBookingActivity,\n InventoryBookingDetail,\n} from './manageApi';\n// Engine seat shape — surfaced for manage callbacks (selection payloads).\nexport type { ExpandedSeat } from '@seatlayer/core';\n","/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport {\n PickerController,\n loadLocale,\n setStringOverrides,\n t,\n type PickerSeat,\n type RendererViewMode,\n type SeatHoverDetails,\n} from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\nimport {\n createBuyerAccessContext,\n type BuyerAccessContext,\n type BuyerAccessExpiredEvent,\n type BuyerAccessToken,\n type BuyerAccessTokenProvider,\n type BuyerAccessUnavailableEvent,\n type SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nimport { SEATLAYER_ATTRIBUTION_MARK_SVG } from './seatLayerBrand';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\nexport interface GAAreaAvailability {\n id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string;\n /** Buyer-facing copy authored separately from stable inventory identity. */\n displayLabel?: string;\n displayType?: string;\n tiers?: Array<{ id: string; name: string; price: number }>;\n}\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent.\n * NOT the channel-access credential: a buyer access session is a different\n * thing with different authority, and uses the two options below. */\n publicKey?: string;\n /**\n * Buyer access session provider — the recommended way to render private\n * channel inventory (Sales Channels guide §6).\n *\n * Called with a `reason` whenever the SDK needs a bearer: first acquisition,\n * a near/actual expiry, a 401 `buyer_access_expired`, a realtime reconnect,\n * or `refreshAccess()`. It should POST to YOUR backend, which mints the\n * session with your secret key and returns `{ token, expiresAt }`.\n *\n * The token lives in memory for the widget's lifetime and nowhere else: never\n * in storage, never in a URL, never in a log or an error message. Refresh\n * returns the same or a narrower scope — the SDK never widens to Public sale\n * on its own, and a failed refresh stops the scoped operation rather than\n * retrying it anonymously.\n */\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n /**\n * One-shot escape hatch for hosts that already own the session lifecycle.\n * Cannot be renewed — when it lapses the widget reports `onAccessExpired`\n * and then `onAccessUnavailable`. Prefer `buyerAccessTokenProvider`.\n */\n buyerAccessToken?: string | BuyerAccessToken;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n /** Initial canvas projection.\n * @deprecated `'isometric'` and `'perspective'` are retired in favour of the\n * real 3D venue view (`setBuyerView('venue3d')`); they remain accepted for\n * source compatibility and will be removed in the next major. Use `'flat'`. */\n initialView?: RendererViewMode;\n /**\n * Built-in seat tooltip on mouse hover (seat · category · price · status).\n * Rendered inside the widget so every host gets it; default true. Turn off\n * to draw your own popover from onSeatHover.\n */\n seatTooltip?: boolean;\n /**\n * Seat hover with everything a popover needs (category label/color, resolved\n * tier-aware price, live status, currency); null on hover-out. Fires whether\n * or not the built-in tooltip is enabled.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n /** A prior active hold was restored with resumeHold(). */\n onHoldRestored?: (result: HoldResult) => void;\n onHoldExpired?: () => void;\n onGAClick?: (area: GAAreaAvailability) => void;\n /**\n * The buyer access session lapsed. `refreshed` says whether the provider\n * already recovered it — false means private inventory is now unavailable and\n * `onAccessUnavailable` follows. Distinct from `onError` on purpose: this is\n * never a network failure (guide §10).\n */\n onAccessExpired?: (event: BuyerAccessExpiredEvent) => void;\n /**\n * Private inventory is unavailable and refreshing will not fix it — revoked,\n * paused, wrong origin/event/mode, or the provider failed. Carries a reason,\n * never a channel name, id, colour or count.\n */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /**\n * Selected-but-unheld units stopped being selectable — someone else took\n * them, or an allocation change moved them out of this buyer's scope. The\n * widget has already dropped them from the selection.\n */\n onSelectedObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n onError?: (err: unknown) => void;\n /**\n * What the BUYER sees when the chart cannot load.\n *\n * `'message'` (the default) renders a plain, styleable notice with a Try\n * again button. This used to be silent unconditionally: `render()` returned\n * with an EMPTY mounted div and only `onError` fired, so a host that had not\n * wired `onError` — or had wired it to a logger — showed buyers a blank\n * rectangle where the seat map belongs, on the host's own domain, which\n * reads as a broken website rather than a temporary fault. `SeatPicker` has\n * always failed loud with a retry; this is the embed class catching up.\n *\n * `'none'` restores the silent behaviour for hosts that render their own\n * failure UI from `onError`.\n */\n errorDisplay?: 'message' | 'none';\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n private mode_: 'live' | 'test' | null = null;\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private onTipMove: ((e: MouseEvent) => void) | null = null;\n /** Null for the ordinary public chart — the tokenless path is untouched. */\n private readonly access: BuyerAccessContext | null;\n private readonly api: PubApi;\n private realtime: BuyerRealtimeClient | null = null;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n this.access = createBuyerAccessContext(options, {\n onExpired: (event) => this.opts.onAccessExpired?.(event),\n onUnavailable: (event) => this.opts.onAccessUnavailable?.(event),\n });\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''), {\n access: this.access ?? undefined,\n onObjectUnavailable: (event) => this.opts.onSelectedObjectUnavailable?.(event),\n });\n this.api = api;\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldRestored: (h) => this.opts.onHoldRestored?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldExpired: () => this.opts.onHoldExpired?.(),\n onGAClick: (areaId) => {\n const area = this.controller.getGAAreas().find((candidate) => candidate.id === areaId);\n if (area) this.opts.onGAClick?.(area);\n },\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n // Live-activity cue: pulse seats that other buyers take while the map is\n // open — the WS feed already streams the status change, this makes it felt.\n flashOnLiveChange: true,\n onSeatHover: (details) => {\n this.opts.onSeatHover?.(details);\n if (this.opts.seatTooltip !== false) this.updateTooltip(details);\n },\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const info = await this.controller.render(host);\n if (!info) {\n this.rendered = false;\n if (this.opts.errorDisplay !== 'none') this.showLoadFailure(host);\n return this;\n }\n this.controller.setViewMode(this.opts.initialView ?? 'flat');\n this.startRealtime();\n // The served event's mode. Anything the API does not explicitly mark as a\n // test event is a live one — the same rule the test-mode ribbon below uses.\n this.mode_ = info.mode === 'test' ? 'test' : 'live';\n\n // Tooltip element + cursor tracking (mouse only — touch selects directly and\n // reviews seats in the host tray). Positioned at the cursor, flipped at edges.\n // Appended AFTER controller.render — mounting the canvas replaces the host's\n // prior children, so anything added earlier would be wiped.\n if (this.opts.seatTooltip !== false) {\n const tip = document.createElement('div');\n tip.setAttribute('role', 'tooltip');\n tip.style.cssText =\n 'position:absolute;z-index:7;pointer-events:none;display:none;max-width:240px;' +\n 'background:#10162a;color:#fff;border-radius:10px;padding:9px 12px;' +\n 'font:500 12px/1.45 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;' +\n 'box-shadow:0 10px 30px -10px rgba(0,0,0,.5);';\n host.appendChild(tip);\n this.tipEl = tip;\n this.onTipMove = (e: MouseEvent) => {\n const r = host.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n };\n host.addEventListener('mousemove', this.onTipMove);\n }\n if (info.mode === 'test') {\n host.style.overflow = 'hidden';\n const ribbon = document.createElement('div');\n ribbon.textContent = t('picker.testMode');\n ribbon.setAttribute('aria-label', t('picker.testMode'));\n ribbon.style.cssText =\n 'position:absolute;top:18px;right:-34px;z-index:6;transform:rotate(45deg);' +\n 'width:140px;text-align:center;padding:4px 0;background:#f4b740;color:#1a1200;' +\n 'font:800 10.5px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.12em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.25);pointer-events:none;';\n host.appendChild(ribbon);\n }\n\n // \"Powered by SeatLayer\" attribution — the SDK embed is canvas-only, so\n // (unlike the full SeatPicker widget) nothing else renders this badge; no\n // duplication guard is needed. Shown by default; hidden only when the SERVED\n // chart doc's theme sets hideBadge (the API forces that false for orgs\n // without the white-label entitlement, so the client can trust the flag).\n this.buildBadge(host);\n return this;\n }\n\n /**\n * Attribution badge pinned to the embed's bottom-right, linking to\n * seatlayer.io. Rendered as an absolutely-positioned overlay with\n * self-contained inline styles — the SDK embed ships no widget CSS, and an\n * overlay keeps it out of the layout flow so it never disturbs the SDK v0.22\n * fill-height resize contract. Mirrors the full widget's mark + wordmark and\n * reuses the `picker.poweredBy` i18n string.\n */\n private buildBadge(host: HTMLDivElement): void {\n if (this.controller.doc?.theme?.hideBadge) return;\n const badge = document.createElement('a');\n badge.href = 'https://seatlayer.io';\n badge.target = '_blank';\n badge.rel = 'noopener noreferrer';\n badge.setAttribute('aria-label', t('picker.poweredBy'));\n badge.style.cssText =\n 'position:absolute;bottom:10px;right:12px;z-index:5;' +\n 'display:inline-flex;align-items:center;gap:6px;padding:5px 9px;border-radius:999px;' +\n 'background:rgba(255,255,255,.92);color:#4a5163;text-decoration:none;' +\n 'font:600 11px/1 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;letter-spacing:.02em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.12);';\n badge.innerHTML =\n '<span aria-hidden=\"true\" style=\"width:16px;height:16px;border-radius:4px;flex:none;' +\n 'display:flex;align-items:center;justify-content:center;background:#0c1220;color:#fcf7ee\">' +\n SEATLAYER_ATTRIBUTION_MARK_SVG + '</span>' +\n `<span>${t('picker.poweredBy')}</span>`;\n host.appendChild(badge);\n }\n\n private placeTooltip(): void {\n if (!this.tipEl || !this.hostEl) return;\n const hw = this.hostEl.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const money = (() => {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: details.currency }).format(details.price);\n } catch {\n return `${details.price} ${details.currency}`;\n }\n })();\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div style=\"margin-top:5px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#fca5a5;font-weight:700\">${\n details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')\n }</div>`;\n this.tipEl.innerHTML =\n `<div style=\"font-weight:700;font-size:13px\">${details.label}</div>` +\n `<div style=\"display:flex;align-items:center;gap:6px;margin-top:4px;color:#c7cddc\">` +\n `<span style=\"width:9px;height:9px;border-radius:50%;flex:none;background:${details.categoryColor}\"></span>` +\n `<span>${details.categoryLabel}</span>` +\n `<span style=\"margin-left:auto;font-weight:700;color:#fff\">${money}</span></div>` +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n /**\n * Whether the SERVED event is a live or a test event (`sk_test_` keys create\n * test events, which never book real inventory). `null` before render()\n * resolves — the mode comes from the server with the chart, not from options.\n *\n * The widget already surfaces this visually with the test-mode ribbon; this\n * getter is for hosts that draw their own chrome — notably a native WebView\n * wrapper, which must be able to tell an integrator that the build they are\n * about to ship is pointed at a test event.\n */\n getMode(): 'live' | 'test' | null {\n return this.mode_;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n try {\n return await this.holdOrThrow(options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * @internal Like {@link hold} but RE-THROWS the structured API error (409\n * `reason`/`code` + `conflicts`) instead of swallowing it into `onError` +\n * `null`. The native WebView host adapter needs the throw so it can answer the\n * originating command with a correlated error carrying the SPECIFIC reason\n * (`sold_out` vs `not_enough_together`); the public method above keeps the\n * catch-and-onError contract that direct web consumers rely on. Not a stable\n * part of the embed API.\n */\n async holdOrThrow(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n const h = await this.controller.hold(undefined, options.ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /** Restore an active hold by its opaque id without extending its expiry. */\n async resumeHold(holdId: string): Promise<HoldResult | null> {\n try {\n return await this.resumeHoldOrThrow(holdId);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link resumeHold} for the native host adapter. See {@link holdOrThrow}. */\n async resumeHoldOrThrow(holdId: string): Promise<HoldResult | null> {\n const h = await this.controller.resumeHold(holdId);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /**\n * Push the OPEN hold's expiry out (\"need more time?\"). Resolves the refreshed\n * hold, or `null` when there is nothing held or the server refused (the hold\n * is gone, already expired, or at its renewal cap) — refusal is a normal\n * outcome, not an error, so the host decides the copy. The client-side expiry\n * timer is re-armed to match, so `onHoldExpired` won't fire early.\n */\n async extendHold(ttlMs?: number): Promise<HoldResult | null> {\n try {\n const h = await this.controller.extendHold(ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Current active hold known to this chart, if any. */\n getCurrentHold(): HoldResult | null {\n const h = this.controller.currentHold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n getGAAreas(): GAAreaAvailability[] {\n return this.controller.getGAAreas();\n }\n\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n try {\n return await this.holdGAOrThrow(areaId, qty, options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link holdGA} for the native host adapter. See {@link holdOrThrow}. */\n async holdGAOrThrow(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n const h = await this.controller.holdGA(areaId, qty, options);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n\n /**\n * Ask the server for the `qty` best free seats and hold them atomically.\n * `options.ttlMs` sets the checkout window exactly like {@link hold}; omit it\n * and the server falls back to the event setting, then its own default.\n */\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n options: { zoneId?: string; preferPremium?: boolean; ttlMs?: number } = {},\n ): Promise<BestAvailableResult | null> {\n try {\n return await this.bestAvailableOrThrow(qty, categoryKey, options);\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** @internal Throwing variant of {@link bestAvailable} for the native host adapter. See {@link holdOrThrow}. */\n async bestAvailableOrThrow(\n qty: number,\n categoryKey?: string,\n options: { zoneId?: string; preferPremium?: boolean; ttlMs?: number } = {},\n ): Promise<BestAvailableResult | null> {\n const h = await this.controller.bestAvailable(qty, categoryKey, options);\n return h ? {\n holdId: h.holdId,\n expiresAt: h.expiresAt,\n labels: h.labels,\n seats: h.seats,\n items: h.items,\n ...(options.zoneId ? { zoneId: options.zoneId } : {}),\n } : null;\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Switch the 2D canvas projection.\n * @deprecated `'isometric'` and `'perspective'` are retired in favour of the\n * real 3D venue view (`setBuyerView('venue3d')`); accepted for source\n * compatibility until the next major. */\n setViewMode(mode: RendererViewMode): void {\n this.controller.setViewMode(mode);\n }\n\n /** Current canvas projection. */\n getViewMode(): RendererViewMode {\n return this.controller.getViewMode();\n }\n\n /** Zoom in one step (same increment as the wheel/pinch gesture). */\n zoomIn(): void {\n this.controller.zoomIn();\n }\n\n /** Zoom out one step. */\n zoomOut(): void {\n this.controller.zoomOut();\n }\n\n /** Reset the camera so the whole chart fits the container. */\n zoomToFit(): void {\n this.controller.zoomToFit();\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Release selected labels from the current hold while keeping the remainder. */\n async releaseLabels(labels: string[]): Promise<boolean> {\n return this.controller.releaseLabels(labels);\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n /**\n * Realtime for an access-scoped chart.\n *\n * A tokenless chart never gets here: `access` is null, `PubApi.socketUrl()`\n * returns the URL it always has, and PickerController keeps its own socket\n * and its own legacy frames. Nothing about the public path changes.\n */\n private startRealtime(): void {\n if (!this.access?.configured || this.realtime) return;\n this.realtime = new BuyerRealtimeClient({\n url: this.api.subscribeUrl(this.opts.event),\n mintTicket: () => this.api.subscribeTicket(this.opts.event),\n onAccessUnavailable: (event) => this.opts.onAccessUnavailable?.(event),\n sink: createControllerSink(this.controller, {\n flashOnLiveChange: true,\n onSelectedObjectUnavailable: (labels, reason) =>\n this.opts.onSelectedObjectUnavailable?.({ labels, reason }),\n }),\n });\n this.realtime.start();\n }\n\n /**\n * Re-acquire the buyer access session — call after your app has re-authorized\n * the buyer (a revoked session cannot be recovered any other way). Resolves\n * true when a fresh bearer is held; the realtime feed restarts with it.\n */\n async refreshAccess(): Promise<boolean> {\n if (!this.access?.configured) return false;\n const ok = await this.access.refresh('manual');\n if (ok) {\n await this.controller.refresh();\n this.realtime?.restart();\n if (!this.realtime) this.startRealtime();\n }\n return ok;\n }\n\n /**\n * The visible failure state. Deliberately inline-styled and dependency-free:\n * this renders on a stranger's website, where our stylesheet may not have\n * loaded (the chart fetch just failed) and where inheriting the host's own\n * styles is likelier to produce something unreadable than something on-brand.\n */\n private showLoadFailure(host: HTMLDivElement): void {\n const box = document.createElement('div');\n box.setAttribute('role', 'status');\n box.style.cssText =\n 'display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;' +\n 'width:100%;height:100%;min-height:180px;box-sizing:border-box;padding:24px;text-align:center;' +\n 'font:500 14px/1.5 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;color:#3b4256;';\n\n const text = document.createElement('div');\n // No error detail: a buyer cannot act on it, and it can carry internals.\n text.textContent = 'The seat map didn’t load.';\n box.appendChild(text);\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.textContent = 'Try again';\n btn.style.cssText =\n 'appearance:none;border:1px solid #c9cede;background:#fff;color:#10162a;border-radius:8px;' +\n 'padding:8px 16px;font:600 13px/1 inherit;cursor:pointer;';\n btn.addEventListener('click', () => {\n // Full remount: the controller holds no partial state worth salvaging\n // after a failed render, and this is the same recovery SeatPicker uses.\n this.destroy();\n void this.render().catch((err) => this.opts.onError?.(err));\n });\n box.appendChild(btn);\n host.appendChild(box);\n }\n\n destroy(): void {\n this.realtime?.stop();\n this.realtime = null;\n this.access?.clear();\n if (this.hostEl && this.onTipMove) this.hostEl.removeEventListener('mousemove', this.onTipMove);\n this.tipEl = null;\n this.onTipMove = null;\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n this.mode_ = null;\n }\n}\n","/**\n * BuyerRealtimeClient — the client half of `docs/realtime-protocol-2026-08-01.md`.\n *\n * Why this exists as a separate socket rather than inside PickerController:\n * a private scope authenticates with a one-use **subscribe ticket** carried in\n * `Sec-WebSocket-Protocol`, and a browser can only set that at construction —\n * `new WebSocket(url, protocols)`. The controller's socket is built from a URL\n * alone (`PickerTransport.socketUrl`), and a bearer must never travel in a URL\n * because URLs are routinely logged. So an access-scoped picker asks the\n * transport for an empty `socketUrl()` (the controller then skips its own\n * connection entirely) and this client owns the wire instead.\n *\n * A tokenless public picker never reaches this file. It keeps the controller's\n * original socket, offers no subprotocol, and therefore receives byte-for-byte\n * the frames it received before this module existed (protocol doc §1).\n *\n * What it implements:\n * - protocol negotiation: offer `seatlayer.v1`, believe the 101 echo, and fall\n * back to legacy frame handling when the server (or a proxy) does not echo;\n * - the ticket exchange, one mint per connection attempt, ticket in the\n * subprotocol list and never in the URL;\n * - compact `{default, exceptions}` snapshot reconstruction;\n * - `sv.<n>` resume, handling BOTH outcomes (a `resumed` delta or a full\n * snapshot) on every reconnect;\n * - close code 4401 as a typed access-revoked state, never a reconnect loop;\n * - liveness by ping/pong only. Silence is normal and carries no information\n * (protocol doc §5) — a quiet socket is never treated as a dead one.\n */\nimport type { BuyerAccessUnavailableEvent } from './buyerAccess';\n\n/** The projected status of one unit, as the server words it on the wire. */\nexport type WireStatus = string;\n\n/** A scope's projection: one default plus the units that differ from it. */\nexport interface Projection {\n default: WireStatus;\n exceptions: Record<string, WireStatus>;\n}\n\nexport interface StatusChange {\n label: string;\n status: WireStatus;\n}\n\n/** Where reconstructed inventory goes. Implemented over PickerController. */\nexport interface RealtimeSink {\n /** Apply a batch of label→status changes. Implementations must paint this as\n * ONE pass, not one pass per label (motion system §4 rule 2). */\n applyStatuses(changes: StatusChange[]): void;\n /**\n * Paint a COMPLETE projection — the default plus the units that differ.\n *\n * Every case that cannot be expressed as a bounded diff (the first snapshot,\n * or a changed default) still arrives as a whole authoritative projection: the\n * client holds it, it just has no way to hand it over. This is that way, and\n * where a sink provides it the {@link resync} round trip is skipped entirely.\n *\n * Optional, so an older sink keeps working unchanged.\n */\n applyProjection?(projection: Projection): void;\n /** Re-pull authoritative state over the scoped HTTP route. Used when a frame\n * cannot be diffed against what we hold (first snapshot, or the scope's\n * default itself changed, which redefines every unit we were never told\n * about), and the sink cannot take a whole projection. */\n resync(): void | Promise<void>;\n /** Section availability changed (channel-agnostic; identical for every scope). */\n onSections?(hidden: string[], closed: string[]): void;\n /** Scope-projected presence counters. */\n onPresence?(counts: { shoppingSessions: number; activeHolds: number }): void;\n}\n\nexport interface SubscribeTicket {\n ticket?: string;\n /** Exactly what to hand `new WebSocket(url, protocols)`, per protocol doc §3. */\n protocols?: string[];\n}\n\nexport interface BuyerRealtimeOptions {\n /** The subscribe URL. Must never carry a credential — asserted below. */\n url: string;\n sink: RealtimeSink;\n /** Mint a one-use ticket for THIS connection attempt. Returns null for the\n * anonymous public case (no ticket needed). Throwing stops the client. */\n mintTicket?: () => Promise<SubscribeTicket | null>;\n /** Typed access states. 4401 arrives here as `revoked`. */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /** Test seam. Defaults to the global WebSocket. */\n socketFactory?: (url: string, protocols: string[]) => WebSocket;\n /** Test seam for the keepalive/backoff timers. */\n now?: () => number;\n}\n\nexport const SEATLAYER_V1 = 'seatlayer.v1';\n/**\n * Join separator for the section-visibility dedupe keys. A NUL can never occur\n * in a section id, so two different arrays can never collide on one key. It is\n * written as an escape deliberately: a literal NUL byte in the source made the\n * whole file read as binary to grep, diff, and review tooling.\n */\nconst SEP = '\\u0000';\n\n/** Protocol doc §3: revocation closes the socket with this code. */\nexport const CLOSE_ACCESS_REVOKED = 4401;\n\nconst MAX_BACKOFF_MS = 15_000;\nconst PING_INTERVAL_MS = 25_000;\nconst PONG_GRACE_MS = 10_000;\n/** Only armed when we offered a resume; the server always answers a resume. */\nconst RESUME_ANSWER_GRACE_MS = 5_000;\n\n/**\n * Turn a snapshot frame into a projection. Handles both wire forms: the v1\n * compact frame states its `default` and lists only the exceptions; the legacy\n * verbose frame lists every non-free unit, which is the same thing with an\n * implicit default of `free`.\n */\nexport function projectionFromSnapshot(frame: {\n default?: unknown;\n seats?: unknown;\n}): Projection {\n const fallback = typeof frame.default === 'string' ? frame.default : 'free';\n const exceptions: Record<string, WireStatus> = {};\n if (frame.seats && typeof frame.seats === 'object') {\n for (const [label, status] of Object.entries(frame.seats as Record<string, unknown>)) {\n if (typeof status === 'string' && status !== fallback) exceptions[label] = status;\n }\n }\n return { default: fallback, exceptions };\n}\n\n/**\n * The changes needed to move a renderer from `prev` to `next`.\n *\n * Returns null when the two projections have different defaults: the default\n * describes every unit the frame does NOT name, and the client does not hold\n * that universe, so the move cannot be expressed as a bounded diff. The caller\n * resyncs over HTTP instead — correct, and rare (it means a channel pause or an\n * allocation change moved the whole scope).\n */\nexport function diffProjections(prev: Projection | null, next: Projection): StatusChange[] | null {\n if (!prev || prev.default !== next.default) return null;\n const changes: StatusChange[] = [];\n for (const [label, status] of Object.entries(next.exceptions)) {\n if (prev.exceptions[label] !== status) changes.push({ label, status });\n }\n for (const label of Object.keys(prev.exceptions)) {\n if (!(label in next.exceptions)) changes.push({ label, status: next.default });\n }\n return changes;\n}\n\n/** Fold a delta batch into a projection (an exception equal to the default\n * stops being an exception, so the model cannot grow without bound). */\nexport function applyChanges(projection: Projection, changes: StatusChange[]): void {\n for (const change of changes) {\n if (change.status === projection.default) delete projection.exceptions[change.label];\n else projection.exceptions[change.label] = change.status;\n }\n}\n\n/** Belt and braces for the \"no bearer in a URL\" rule — cheap, and it turns a\n * future refactor that reintroduces one into a thrown error, not a silent leak. */\nexport function assertCredentialFreeUrl(url: string): void {\n if (/(?:^|[?&#])(?:token|access_token|bearer|authorization|ticket|tkt|bse)=/i.test(url)) {\n throw new Error('seatlayer: refusing to open a socket with a credential in the URL');\n }\n if (/\\bbse_[A-Za-z0-9._-]+/.test(url)) {\n throw new Error('seatlayer: refusing to open a socket with a credential in the URL');\n }\n}\n\nexport class BuyerRealtimeClient {\n private readonly opts: BuyerRealtimeOptions;\n private ws: WebSocket | null = null;\n private stopped = true;\n private attempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n private resumeTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Our model of this scope's projection. Null until the first snapshot. */\n private projection: Projection | null = null;\n /** Last `snapshotVersion` seen on any frame that carried one — the resume point. */\n private version: number | null = null;\n /** True once the 101 echoed `seatlayer.v1`. */\n private v1 = false;\n /** Set when we offered v1 and the handshake came back without it — a proxy\n * most likely stripped the header, so the next attempt selects the v1 frame\n * format with the `?pv=1` marker instead (protocol doc §1). The marker\n * selects a format and can never carry a credential or widen a scope. */\n private useQueryMarker = false;\n private hidden: string | null = null;\n private closedSections: string | null = null;\n\n constructor(options: BuyerRealtimeOptions) {\n this.opts = options;\n assertCredentialFreeUrl(options.url);\n }\n\n /** Negotiated protocol, for tests and diagnostics. */\n get protocol(): 'v1' | 'legacy' | null {\n return this.ws ? (this.v1 ? 'v1' : 'legacy') : null;\n }\n\n get snapshotVersion(): number | null {\n return this.version;\n }\n\n start(): void {\n if (!this.stopped) return;\n this.stopped = false;\n void this.connect();\n }\n\n /** Stop for good (destroy, or a revocation). Safe to call twice. */\n stop(): void {\n this.stopped = true;\n this.clearTimers();\n const ws = this.ws;\n this.ws = null;\n if (ws) {\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n try {\n ws.close();\n } catch {\n /* already closing */\n }\n }\n }\n\n /** Restart after the host re-authorized a revoked buyer (`refreshAccess()`). */\n restart(): void {\n this.stop();\n this.projection = null;\n this.version = null;\n this.attempt = 0;\n this.start();\n }\n\n // ---- connection -----------------------------------------------------------\n\n private async connect(): Promise<void> {\n if (this.stopped) return;\n\n let protocols: string[] = [SEATLAYER_V1];\n if (this.opts.mintTicket) {\n let minted: SubscribeTicket | null;\n try {\n // One mint per connection attempt, including every reconnect. Tickets\n // are TTL ≤ 30s and single-redemption, so reusing one cannot work.\n minted = await this.opts.mintTicket();\n } catch (err) {\n // The mint is an ordinary scoped HTTP call: the transport has already\n // classified and reported any access failure. A transport-level failure\n // is transient, so back off rather than give up.\n this.reportIfAccessError(err);\n this.scheduleReconnect();\n return;\n }\n if (this.stopped) return;\n if (minted?.protocols?.length) {\n protocols = [...minted.protocols];\n if (!protocols.includes(SEATLAYER_V1)) protocols.unshift(SEATLAYER_V1);\n } else if (minted?.ticket) {\n protocols = [SEATLAYER_V1, `tkt.${minted.ticket}`];\n }\n }\n\n // Resume from the last version we actually saw. Both outcomes — a `resumed`\n // delta or a full snapshot — are handled in onmessage.\n const offeredResume = this.version !== null;\n if (offeredResume) protocols.push(`sv.${this.version}`);\n\n const url = this.useQueryMarker\n ? `${this.opts.url}${this.opts.url.includes('?') ? '&' : '?'}pv=1`\n : this.opts.url;\n assertCredentialFreeUrl(url);\n\n let ws: WebSocket;\n try {\n const make = this.opts.socketFactory ?? ((u: string, p: string[]) => new WebSocket(u, p));\n ws = make(url, protocols);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n if (this.ws !== ws) return;\n this.attempt = 0;\n this.v1 = ws.protocol === SEATLAYER_V1;\n // We asked for v1 and the server did not echo it. Either it is a\n // pre-M5 server (legacy frames are correct and byte-compatible) or a\n // proxy ate the header — the next attempt tries the query marker.\n if (!this.v1) this.useQueryMarker = true;\n this.startKeepalive(ws);\n if (offeredResume) {\n // The server always answers a resume with a delta or a snapshot. If\n // neither lands, fall back to authoritative HTTP rather than sit on a\n // possibly stale map. This timer is NOT a liveness check — ordinary\n // silence on a live socket never triggers it.\n this.resumeTimer = setTimeout(() => {\n this.resumeTimer = null;\n void this.opts.sink.resync();\n }, RESUME_ANSWER_GRACE_MS);\n } else {\n // Parity with the controller's own socket: pull authoritative state on\n // every fresh connection.\n void this.opts.sink.resync();\n }\n };\n\n ws.onmessage = (event: MessageEvent) => {\n if (this.ws !== ws) return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(typeof event.data === 'string' ? event.data : '');\n } catch {\n return;\n }\n if (!parsed || typeof parsed !== 'object') return;\n this.handleFrame(parsed as Record<string, unknown>);\n };\n\n ws.onclose = (event: CloseEvent) => {\n if (this.ws !== ws) return;\n this.ws = null;\n this.clearTimers();\n if (event?.code === CLOSE_ACCESS_REVOKED) {\n // Retrying with the same credential is guaranteed to fail, so this is\n // a typed terminal state, not a reconnect loop (protocol doc §3).\n this.stopped = true;\n this.opts.onAccessUnavailable?.({\n reason: 'revoked',\n code: 'access_revoked',\n retryable: false,\n });\n return;\n }\n this.scheduleReconnect();\n };\n\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives the reconnect */\n }\n };\n }\n\n private handleFrame(frame: Record<string, unknown>): void {\n const type = typeof frame.type === 'string' ? frame.type : '';\n\n // A frame carrying `protocol: 1` proves v1 even when the 101 echo was\n // stripped in transit (the `?pv=1` path).\n if (frame.protocol === 1) this.v1 = true;\n\n if (typeof frame.snapshotVersion === 'number') this.version = frame.snapshotVersion;\n\n if (type === 'pong') {\n this.clearPongTimer();\n return;\n }\n\n // Section availability rides on `hidden`/`closed`, either on its own frame\n // or alongside a snapshot. Identical for every scope.\n if (Array.isArray(frame.hidden) || Array.isArray(frame.closed)) {\n const hidden = Array.isArray(frame.hidden) ? (frame.hidden as string[]) : [];\n const closed = Array.isArray(frame.closed) ? (frame.closed as string[]) : [];\n const hKey = hidden.join(SEP);\n const cKey = closed.join(SEP);\n if (hKey !== this.hidden || cKey !== this.closedSections) {\n this.hidden = hKey;\n this.closedSections = cKey;\n this.opts.sink.onSections?.(hidden, closed);\n }\n }\n if (type === 'hidden') return; // carries no inventory\n\n if (type === 'presence') {\n this.opts.sink.onPresence?.({\n shoppingSessions: Number(frame.shoppingSessions) || 0,\n activeHolds: Number(frame.activeHolds) || 0,\n });\n return;\n }\n\n if (type === 'allocation') {\n // Always followed by a fresh snapshot, which is authoritative. Nothing to\n // do here — and deliberately NO dedupe on allocationVersion: a pause or\n // unpause changes the projection without moving that number.\n return;\n }\n\n if (type === 'snapshot' || (!type && frame.seats)) {\n this.answered();\n const next = projectionFromSnapshot(frame);\n const changes = diffProjections(this.projection, next);\n this.projection = next;\n if (changes === null) {\n // Undiffable — the first snapshot, or a default that moved. `next` is\n // nonetheless the WHOLE authoritative projection, so a sink that can\n // take one is painted directly and the HTTP round trip never happens.\n if (this.opts.sink.applyProjection) this.opts.sink.applyProjection(next);\n else void this.opts.sink.resync();\n } else if (changes.length) {\n this.opts.sink.applyStatuses(changes);\n }\n return;\n }\n\n if (type === 'delta' && Array.isArray(frame.changes)) {\n this.answered();\n const changes = (frame.changes as Array<Record<string, unknown>>)\n .filter((c) => typeof c?.label === 'string' && typeof c?.status === 'string')\n .map((c) => ({ label: c.label as string, status: c.status as string }));\n if (!changes.length) return;\n if (this.projection) applyChanges(this.projection, changes);\n this.opts.sink.applyStatuses(changes);\n }\n }\n\n /** The server answered our resume; cancel the fallback resync. */\n private answered(): void {\n if (!this.resumeTimer) return;\n clearTimeout(this.resumeTimer);\n this.resumeTimer = null;\n }\n\n private reportIfAccessError(err: unknown): void {\n const reason = (err as { reason?: string } | null)?.reason;\n if ((err as { name?: string } | null)?.name !== 'BuyerAccessUnavailableError') return;\n this.stopped = true;\n this.opts.onAccessUnavailable?.({\n reason: (reason ?? 'invalid') as BuyerAccessUnavailableEvent['reason'],\n code: (err as { code?: string }).code,\n status: (err as { status?: number }).status,\n retryable: reason === 'paused',\n });\n }\n\n // ---- keepalive & backoff --------------------------------------------------\n\n /**\n * Liveness is ping/pong, and only ping/pong. A socket that receives nothing\n * for minutes is the normal, correct state for a narrowly-scoped buyer on a\n * busy event (protocol doc §5), so quiet time never triggers a reconnect.\n */\n private startKeepalive(ws: WebSocket): void {\n this.pingTimer = setInterval(() => {\n if (this.ws !== ws) return;\n try {\n ws.send(JSON.stringify({ type: 'ping' }));\n } catch {\n return;\n }\n this.clearPongTimer();\n this.pongTimer = setTimeout(() => {\n this.pongTimer = null;\n try {\n ws.close();\n } catch {\n /* onclose drives the reconnect */\n }\n }, PONG_GRACE_MS);\n }, PING_INTERVAL_MS);\n }\n\n /**\n * FULL jitter, not plain exponential backoff.\n *\n * A deterministic `2**attempt` schedule makes every browser that lost the same\n * socket — a worker redeploy, a DO eviction, a flaky edge PoP — come back in\n * the same millisecond, and an on-sale crowd reconnecting in lockstep is the\n * thing that turns one blip into a self-sustaining thundering herd. Full\n * jitter (`random() * ceiling`) spreads the same crowd across the whole\n * window; the ceiling still doubles, so a persistent outage still backs off.\n *\n * `Math.random` is correct here: this is client code choosing a delay, not a\n * Workflow step that has to replay deterministically.\n */\n private scheduleReconnect(): void {\n if (this.stopped || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const ceiling = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n const delay = Math.random() * ceiling;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n void this.connect();\n }, delay);\n }\n\n private clearPongTimer(): void {\n if (!this.pongTimer) return;\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n\n private clearTimers(): void {\n if (this.pingTimer) clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.clearPongTimer();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n if (this.resumeTimer) clearTimeout(this.resumeTimer);\n this.resumeTimer = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Controller sink\n// ---------------------------------------------------------------------------\n\n/**\n * The slice of PickerController this module drives. Structural on purpose — it\n * keeps this file free of an `@seatlayer/core` import, and every member here is\n * public controller API, so nothing in the engine mirror has to change.\n */\nexport interface PickerControllerLike {\n idForLabel(label: string): string | undefined;\n tableSelection(seatIdOrLabel: string): { physicalSeatIds: string[] } | null;\n setStatus(ids: string[], status: 'free' | 'held' | 'booked' | 'not_for_sale'): void;\n getStatus(id: string): string | undefined;\n flashSeat(id: string, color?: string): void;\n currentHold(): { labels: string[] } | null;\n getSelection(): Array<{ id: string; label: string }>;\n deselect(ids: string[]): void;\n refresh(): Promise<void>;\n}\n\n/** Wire status → renderer status. `blocked` is the one neutral unavailable\n * value an out-of-scope unit reads as; the buyer must not be able to tell it\n * apart from ordinary off-sale inventory (protocol doc §5). */\nfunction rendererStatus(wire: string): 'free' | 'held' | 'booked' | 'not_for_sale' {\n if (wire === 'blocked') return 'not_for_sale';\n if (wire === 'held' || wire === 'booked' || wire === 'free' || wire === 'not_for_sale') return wire;\n return 'free';\n}\n\nexport interface ControllerSinkOptions {\n /** Pulse seats other buyers take, as the controller's own socket does. */\n flashOnLiveChange?: boolean;\n /** Selected-but-unheld units that stopped being selectable. */\n onSelectedObjectUnavailable?: (labels: string[], reason: 'ineligible' | 'taken') => void;\n /** Section availability changed and the chart itself needs rebuilding. */\n onSections?: (hidden: string[], closed: string[]) => void;\n onStatusChange?: () => void;\n}\n\nexport function createControllerSink(\n controller: PickerControllerLike,\n options: ControllerSinkOptions = {},\n): RealtimeSink {\n const idsForLabel = (label: string): string[] => {\n const table = controller.tableSelection(label);\n if (table) return table.physicalSeatIds;\n const id = controller.idForLabel(label);\n return id ? [id] : [];\n };\n\n return {\n applyStatuses(changes) {\n const held = controller.currentHold()?.labels ?? [];\n // Bucket the whole batch and paint one call per status: a 256-label\n // delta must animate as ONE canvas pass, never one per seat.\n const buckets: Record<string, string[]> = {\n free: [], held: [], booked: [], not_for_sale: [],\n };\n const flashes: Array<{ id: string; color: string }> = [];\n const lost: string[] = [];\n const selected = new Map(controller.getSelection().map((s) => [s.label, s.id]));\n\n for (const change of changes) {\n const ids = idsForLabel(change.label);\n if (!ids.length) continue;\n const next = rendererStatus(change.status);\n buckets[next].push(...ids);\n if (\n options.flashOnLiveChange &&\n next !== 'free' &&\n !held.includes(change.label) &&\n ids.some((id) => controller.getStatus(id) === 'free')\n ) {\n const color = next === 'held' ? '#f4b740' : '#f43f5e';\n for (const id of ids) flashes.push({ id, color });\n }\n if (next !== 'free' && !held.includes(change.label) && selected.has(change.label)) {\n lost.push(change.label);\n }\n }\n\n for (const status of ['free', 'held', 'booked', 'not_for_sale'] as const) {\n if (buckets[status].length) controller.setStatus(buckets[status], status);\n }\n for (const flash of flashes) controller.flashSeat(flash.id, flash.color);\n\n if (lost.length) {\n // One deselect call, so the map cross-fades in a single pass rather\n // than blinking seat by seat (motion system §3, buyer picker).\n const ids = lost.flatMap((label) => idsForLabel(label));\n if (ids.length) controller.deselect(ids);\n const ineligible = changes.some(\n (c) => c.status === 'blocked' && lost.includes(c.label),\n );\n options.onSelectedObjectUnavailable?.(lost, ineligible ? 'ineligible' : 'taken');\n }\n options.onStatusChange?.();\n },\n\n async resync() {\n await controller.refresh();\n },\n\n /**\n * Section availability moved. Statuses are re-pulled so the map repaints.\n *\n * Known limit: rebuilding the chart when a section is newly HIDDEN (its\n * seats are stripped, not greyed) lives inside PickerController's own\n * socket handler and has no public entry point, so an access-scoped picker\n * repaints statuses but does not restructure the chart until its next\n * mount. Closing/opening a section — the common mid-sale move — is a\n * status-level change and is handled here in full.\n */\n onSections(hidden, closed) {\n void controller.refresh();\n options.onSections?.(hidden, closed);\n },\n };\n}\n","/**\n * Minimal client for the browser embed surface of workers/api (the `/pub/*`\n * routes). Platform events bind this client to a buyer access context; Managed\n * public/unlisted events may still use it anonymously. Deliberately\n * self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\nimport type {\n BuyerAccessContext,\n SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, SEATLAYER_V1, type RealtimeSink } from './buyerRealtime';\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\nexport interface HoldLineItem {\n label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga' | 'table'; categoryKey: string;\n tierId: string | null;\n /** Price in major currency units (for example 45 means $45.00). */\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n /**\n * Seconds the server asked the caller to wait, off a 429's `Retry-After`.\n *\n * Present ONLY on a rate-limit error, and it is the server's number — never a\n * guess. A widget that catches this can say \"try again in N seconds\" instead\n * of rendering the blank map a swallowed 429 used to produce.\n */\n retryAfterS?: number;\n\n constructor(\n status: number,\n message: string,\n code?: string,\n conflicts?: HoldConflict[],\n reason?: string,\n retryAfterS?: number,\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n this.retryAfterS = retryAfterS;\n }\n}\n\n/**\n * Longest advertised delay we will sit out inside a request.\n *\n * A rate limit the buyer can wait through invisibly is worth absorbing; one\n * that is 30 seconds long is not — sleeping that long inside `chart()` looks\n * like a hung widget, and the retry would very likely 429 again anyway. Past\n * the cap the error is thrown WITH `retryAfterS`, so the host decides.\n */\nconst MAX_RATE_LIMIT_WAIT_S = 10;\n/** What to assume when a 429 names no delay at all. */\nconst DEFAULT_RATE_LIMIT_WAIT_S = 1;\n\n/**\n * `Retry-After` in seconds. RFC 9110 allows either a delta-seconds integer or\n * an HTTP-date; the API sends the integer, and the date form is handled so a\n * proxy that rewrites it cannot turn a well-formed 429 into an untyped one.\n * Returns undefined when neither the header nor the body says anything.\n */\nexport function parseRetryAfter(header: string | null, bodyValue?: unknown): number | undefined {\n const raw = (header ?? '').trim();\n if (raw) {\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds >= 0) return Math.ceil(seconds);\n const at = Date.parse(raw);\n if (Number.isFinite(at)) return Math.max(0, Math.ceil((at - Date.now()) / 1000));\n }\n if (typeof bodyValue === 'number' && Number.isFinite(bodyValue) && bodyValue >= 0) {\n return Math.ceil(bodyValue);\n }\n return undefined;\n}\n\nexport interface PubChartResult {\n event: {\n key: string;\n name: string;\n inventoryModelVersion?: 1 | 2;\n /** Absolute event-poster URL, when the server can publicly serve one. */\n posterUrl?: string | null;\n };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /**\n * The status every seat NOT named in `seats` holds.\n *\n * Present because {@link PubApi.objects} asks for the compact form: the modal\n * status is stated once and only the exceptions are listed, which on a\n * mostly-sold event makes `default` `booked` rather than `free`. Readers must\n * honour it — treating an absent seat as free renders a sold-out venue as\n * wide open. Absent only from an older server, where every seat is named and\n * `free` is the correct assumption.\n */\n default?: string;\n /** The seats whose status differs from {@link PubObjectsResult.default}. */\n seats: Record<string, string>;\n /** Section/zone ids hidden from buyers this event (seats stripped from the map). */\n hidden?: string[];\n /** Section/zone ids in the `closed` state (Phase 2): rendered grey + not purchasable. */\n closed?: string[];\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n items?: HoldLineItem[];\n}\n\n/** Browser-safe active-hold projection returned by the resume endpoint. */\nexport interface ResumedHoldResult extends HoldResult {\n items: HoldLineItem[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n items?: HoldResult['items'];\n zoneId?: string;\n}\n\n/** A gateway the organizer can be connected to. */\nexport type PaymentProviderName = 'stripe' | 'razorpay';\n\n/**\n * Why `payment-options` came back with an empty list.\n *\n * The three are NOT interchangeable and two of them give opposite advice:\n * `not_configured` means the organizer takes payment somewhere else,\n * `payments_off_for_event` means they deliberately do not sell THIS event\n * online, and `unavailable_for_event` means they switched it on and it is\n * broken. Collapsing them makes the widget blame a working integration for a\n * decision that was made on purpose.\n */\nexport type PaymentOptionsReason =\n | 'not_configured'\n | 'payments_off_for_event'\n | 'unavailable_for_event';\n\n/**\n * What this event can take money through. Since the per-event gateway column\n * landed, `providers` holds AT MOST ONE entry — the gateway the organizer\n * assigned — so no browser can choose which one charges.\n *\n * `reason` is optional on the wire: a widget pinned against an older worker\n * still parses, and its absence means what that worker meant by an empty list.\n */\nexport interface PaymentOptionsResult {\n providers: PaymentProviderName[];\n currency: string | null;\n reason?: PaymentOptionsReason | null;\n}\n\n/** A started payment. Exactly one of the two handoffs comes back. */\nexport interface CheckoutSessionResult {\n orderId: string;\n totalMinor: number;\n currency: string;\n expiresAt: number;\n /** Hosted gateway page — navigate to it. */\n redirectUrl?: string;\n /** In-page modal gateway — open it without leaving the page. */\n clientPayload?: Record<string, unknown>;\n}\n\n/** An order's state while its gateway webhook is in flight. */\nexport interface OrderStatusResult {\n orderId: string;\n status: string;\n totalMinor: number;\n currency: string;\n amountFormatted: string;\n seatCount: number;\n // Present once the order is settled (confirmed / refund states): the same\n // capability now also unlocks the ticket view.\n eventName?: string | null;\n venue?: string | null;\n startsAt?: number | null;\n tickets?: Array<{\n label: string;\n token: string;\n status: 'issued' | 'checked_in' | 'void';\n checkedInAt: number | null;\n }>;\n /** Hosted ticket page — the durable re-entry point after the modal closes. */\n ticketUrl?: string;\n /** Printable A4 PDF, up to three ticket cards per page. */\n pdfUrl?: string;\n}\n\n/** Codes a 409 uses to say \"the unit you picked is no longer yours to pick\". */\nconst OBJECT_UNAVAILABLE_CODES: Record<string, SelectedObjectUnavailableEvent['reason']> = {\n seat_conflict: 'taken',\n conflict: 'taken',\n channel_assignment_conflict: 'ineligible',\n allocation_exhausted: 'exhausted',\n};\n\nexport interface PubApiOptions {\n /**\n * Buyer access session. When present, EVERY scoped operation on this client\n * carries `Authorization: Bearer bse_…` — chart, objects, hold, replace-hold,\n * best-available, resume, release, extend, resnapshot and the realtime\n * subscribe ticket. The binding is immutable for the client's lifetime: there\n * is no method that turns it off, so no operation can silently downgrade to\n * anonymous Public sale (guide §6, §7).\n */\n access?: BuyerAccessContext;\n /** A 409 named specific inventory the buyer can no longer have. */\n onObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n private readonly viewerId = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `viewer_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n\n private readonly access?: BuyerAccessContext;\n private readonly onObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n\n constructor(private readonly base: string, options: PubApiOptions = {}) {\n this.access = options.access;\n this.onObjectUnavailable = options.onObjectUnavailable;\n }\n\n /** True when this client is bound to a buyer access session. */\n get accessScoped(): boolean {\n return !!this.access?.configured;\n }\n\n private async request<T>(\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown; labels?: string[] } = {},\n retried: { auth?: boolean; rateLimit?: boolean } = {},\n ): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n // Throws BuyerAccessUnavailableError rather than returning undefined when a\n // configured session cannot produce a bearer — the request must not go out\n // anonymous, because anonymous means Public sale.\n const authorization = await this.access?.authorization(retried.auth ? 'unauthorized' : 'initial');\n if (authorization) headers.Authorization = authorization;\n\n const res = await fetch(`${this.base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | {\n error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string;\n retryAfterSeconds?: number;\n }\n | null;\n // The public API names its machine code in `error` (`conflict`, `event_closed`,\n // …); older/other routes may send `code`. Carry whichever into ApiError.code so\n // the code is populated (it was previously always undefined — nothing reads it\n // yet) and the bridge can pass it through. The specific 409 discriminator still\n // rides in `reason` (`sold_out` | `not_enough_together`) and wins downstream.\n const code = err?.code ?? err?.error;\n\n if (this.access?.configured && (res.status === 401 || res.status === 403 || res.status === 422)) {\n const refreshed = await this.access.handleFailure(res.status, code);\n // Exactly one retry, and only for an expiry the provider just renewed.\n // A refresh returns the same or a narrower scope; it never widens, and\n // a second failure is reported rather than looped.\n if (refreshed && !retried.auth) return this.request<T>(path, init, { ...retried, auth: true });\n }\n if (res.status === 409) {\n const reason = code ? OBJECT_UNAVAILABLE_CODES[code] : undefined;\n const labels = err?.conflicts?.map((c) => c.label) ?? init.labels ?? [];\n if (reason) this.onObjectUnavailable?.({ labels, reason, code });\n }\n\n let retryAfterS: number | undefined;\n if (res.status === 429) {\n retryAfterS = parseRetryAfter(res.headers.get('Retry-After'), err?.retryAfterSeconds)\n ?? DEFAULT_RATE_LIMIT_WAIT_S;\n // One automatic retry, and only for a READ.\n //\n // A rate-limited `chart()`/`objects()` is what turns an on-sale spike\n // into a blank widget, and re-reading is free of consequence — the same\n // GET twice is the same GET. A hold, a best-available, a checkout or an\n // extend is NOT: replaying one can take a second seat, start a second\n // payment, or burn an extend allowance, so a 429 on those is reported to\n // the caller with the server's delay attached and never replayed here.\n if (\n method === 'GET'\n && !retried.rateLimit\n && retryAfterS <= MAX_RATE_LIMIT_WAIT_S\n ) {\n await new Promise((resolve) => setTimeout(resolve, retryAfterS! * 1000));\n return this.request<T>(path, init, { ...retried, rateLimit: true });\n }\n }\n\n throw new ApiError(\n res.status,\n err?.error ?? `request_failed_${res.status}`,\n code,\n err?.conflicts,\n err?.reason,\n retryAfterS,\n );\n }\n return data as T;\n }\n\n /**\n * Binary counterpart to `request`. Buyer media needs the same in-memory\n * bearer/refresh rules as JSON, but returns bytes that the picker turns into\n * a blob URL. The bearer stays in the Authorization header and is never\n * appended to `path`.\n */\n private async requestBlob(\n path: string,\n retried: { auth?: boolean; rateLimit?: boolean } = {},\n ): Promise<Blob> {\n const headers: Record<string, string> = {};\n const authorization = await this.access?.authorization(retried.auth ? 'unauthorized' : 'initial');\n if (authorization) headers.Authorization = authorization;\n const res = await fetch(`${this.base}${path}`, { method: 'GET', headers, credentials: 'omit' });\n if (res.ok) return res.blob();\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson\n ? await res.json().catch(() => null) as { error?: string; code?: string; retryAfterSeconds?: number } | null\n : null;\n const code = data?.code ?? data?.error;\n\n if (this.access?.configured && (res.status === 401 || res.status === 403 || res.status === 422)) {\n const refreshed = await this.access.handleFailure(res.status, code);\n if (refreshed && !retried.auth) return this.requestBlob(path, { ...retried, auth: true });\n }\n\n let retryAfterS: number | undefined;\n if (res.status === 429) {\n retryAfterS = parseRetryAfter(res.headers.get('Retry-After'), data?.retryAfterSeconds)\n ?? DEFAULT_RATE_LIMIT_WAIT_S;\n if (!retried.rateLimit && retryAfterS <= MAX_RATE_LIMIT_WAIT_S) {\n await new Promise((resolve) => setTimeout(resolve, retryAfterS! * 1000));\n return this.requestBlob(path, { ...retried, rateLimit: true });\n }\n }\n\n throw new ApiError(\n res.status,\n data?.error ?? `request_failed_${res.status}`,\n code,\n undefined,\n undefined,\n retryAfterS,\n );\n }\n\n chart(key: string): Promise<PubChartResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n /** Authenticated bytes for an Event-scoped authored view image. */\n asset(key: string, asset: string): Promise<Blob> {\n if (!/^[a-zA-Z0-9._-]+$/.test(asset)) {\n return Promise.reject(new ApiError(404, 'not_found', 'not_found'));\n }\n return this.requestBlob(\n `/pub/events/${encodeURIComponent(key)}/assets/${encodeURIComponent(asset)}`,\n );\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n // `compact=1` costs nothing to ask for and is ignored by a server that\n // predates it, which then answers with every seat named and no `default` —\n // the shape this client already handled.\n return this.request(`/pub/events/${encodeURIComponent(key)}/objects?compact=1`);\n }\n\n hold(key: string, selections: Array<{ label: string; tierId?: string | null; quantity?: number }>, ttlMs?: number, replaceHoldId?: string): Promise<HoldResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { selections, ...(ttlMs ? { ttlMs } : {}), ...(replaceHoldId ? { replaceHoldId } : {}) },\n labels: selections.map((s) => s.label),\n });\n }\n\n // `zoneId` scopes the pick to one zone and `ttlMs` carries the host's checkout\n // window — both are part of the route contract, and dropping either here made\n // the SDK quietly pick venue-wide and hold for the server default instead.\n bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string, ttlMs?: number): Promise<BestAvailableResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}), ...(zoneId ? { zoneId } : {}), ...(ttlMs ? { ttlMs } : {}) },\n });\n }\n\n resume(key: string, holdId: string): Promise<ResumedHoldResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/hold/resume`, {\n method: 'POST',\n body: { holdId },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true; released?: string[] }> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n /** P4 \"need more time?\": push an active hold's expiry out. Throws ApiError 409\n * (reason: expired | extend_limit | not_found | not_active) if it can't. */\n extend(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends: number }> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/extend`, {\n method: 'POST',\n body: { holdId, ...(ttlMs ? { ttlMs } : {}) },\n });\n }\n\n /**\n * Which gateways this event can actually take money through — the question\n * `checkout: 'hosted'` has to answer BEFORE it shows a buyer a Pay button, so\n * the answer is never discovered by failing a payment.\n *\n * Anonymous, and it discloses no account, key, mode or currency for a gateway\n * that did not match.\n */\n paymentOptions(key: string): Promise<PaymentOptionsResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/payment-options`);\n }\n\n /** Server-resolved active ticket offers and category prices. */\n availability(key: string, live = false): Promise<unknown> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/availability${live ? '?live=1' : ''}`);\n }\n\n /**\n * Turn a live hold into an order and start a payment.\n *\n * The amount is NOT sent: the server recomputes it from the hold's own items,\n * which is the only reason a browser cannot alter what it pays. Nor is the\n * PROVIDER — the event row decides which gateway charges, and a `provider` in\n * the body is checked rather than obeyed (409 `provider_mismatch`). Omitting\n * it is the shape that cannot disagree.\n */\n startCheckout(\n key: string,\n input: { holdId: string; buyerEmail: string; buyerName?: string; returnUrl?: string },\n ): Promise<CheckoutSessionResult> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/checkout`, {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Poll an order while its gateway webhook lands. The order id is an\n * unguessable token the buyer already holds, so it acts as the capability —\n * which is also why a buyer returning from a gateway page can be told what\n * happened with nothing but the id in the return URL.\n */\n orderStatus(orderId: string): Promise<OrderStatusResult> {\n return this.request(`/pub/orders/${encodeURIComponent(orderId)}/status`);\n }\n\n /**\n * Mint a one-use subscribe ticket for the next socket attempt (protocol doc\n * §3). The bearer travels here, over ordinary HTTPS where CORS and Origin\n * already apply; the socket then carries only the short-lived ticket, in its\n * subprotocol list. TTL ≤ 30s, single redemption — mint one per attempt.\n */\n subscribeTicket(key: string): Promise<{ ticket?: string; protocols?: string[] } | null> {\n return this.request(`/pub/events/${encodeURIComponent(key)}/subscribe-tickets`, {\n method: 'POST',\n body: {},\n });\n }\n\n /**\n * The subscribe URL. Never carries a credential — not the bearer, not the\n * ticket. Query parameters are diagnostics only.\n */\n subscribeUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n const params = new URLSearchParams({ surface: 'picker', viewerId: this.viewerId });\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe?${params}`;\n }\n\n /**\n * What PickerController opens its own socket with.\n *\n * Empty for an access-scoped client: a scoped audience authenticates with a\n * subprotocol ticket, which a URL-only constructor cannot carry, so the SDK's\n * BuyerRealtimeClient owns that socket instead and the controller skips its\n * own (an empty URL is its documented \"no live feed\" contract). A tokenless\n * Managed public client returns exactly the URL it always has.\n */\n socketUrl(key: string): string {\n return this.accessScoped ? '' : this.subscribeUrl(key);\n }\n\n /**\n * The subprotocol list a PLAIN `new WebSocket(url, protocols)` must offer for\n * this transport — `PickerTransport.socketProtocols`, which PickerController\n * calls optionally and which nothing implemented until now.\n *\n * Offering `seatlayer.v1` is the whole point: without it the DO answers an\n * anonymous socket with the LEGACY verbose frame — every unit of a 10k-seat\n * event, on connect and on every reconnect — instead of the compact\n * `{default, exceptions}` form. Empty for an access-scoped client, which\n * authenticates with a one-use ticket a URL-only constructor cannot carry and\n * whose socket BuyerRealtimeClient owns instead (see `socketUrl`).\n *\n * `createRealtime` below is the preferred path and supersedes this for any\n * host that can use it; this stays the correct answer for a host that builds\n * the socket itself from the transport contract.\n */\n socketProtocols(key: string): string[] {\n void key; // same answer for every event; the parameter is the interface's\n return this.accessScoped ? [] : [SEATLAYER_V1];\n }\n\n /**\n * Hand PickerController the v1 realtime client instead of letting it open a\n * bare socket — `PickerTransport.createRealtime`.\n *\n * This is what puts an ANONYMOUS buyer (the on-sale case) on the same wire as\n * a private-channel one: compact snapshots, `sv.<n>` resume so a reconnect\n * inside the ring costs a delta rather than a full re-snapshot, ping/pong\n * liveness, and one jittered backoff implementation shared by both. The\n * anonymous case simply passes no `mintTicket` — the `/pub/events/:key/\n * subscribe` upgrade requires no ticket, and the DO resolves a ticketless\n * socket to the public scope.\n *\n * Null when access-scoped: that socket is owned by the widget's own\n * BuyerRealtimeClient (with the ticket exchange), and `socketUrl()` already\n * returns '' so the controller opens nothing.\n */\n createRealtime(key: string, sink: RealtimeSink): BuyerRealtimeClient | null {\n if (this.accessScoped) return null;\n return new BuyerRealtimeClient({ url: this.subscribeUrl(key), sink });\n }\n}\n","/**\n * Buyer access context — the browser half of the Sales Channels contract\n * (`docs/sales-channels-integration-guide-2026-08-01.md` §6, §9, §10).\n *\n * A promoter's own backend mints a short-lived, opaque buyer-access session\n * (`bse_…`) that grants exactly one event's private channel scope. That bearer\n * reaches the browser, and only the browser — this module is where it lives,\n * and the rules it enforces are the ones the guide states outright:\n *\n * - the token is held in memory on a private field. It is never written to\n * localStorage/sessionStorage/cookies, never appended to a URL, and never\n * placed in a log, an Error message, telemetry, or JSON. `toJSON()` and\n * `toString()` are overridden so an accidental `JSON.stringify(context)` or\n * template interpolation cannot leak it;\n * - refresh goes through the host's `buyerAccessTokenProvider`, which is\n * called with a `reason` so the host can distinguish a first acquisition\n * from an expiry from a 401;\n * - **a configured context never falls back to anonymous Public sale.** When\n * no bearer can be obtained the operation fails with a typed access error\n * instead of going out unauthenticated. Sending the request without the\n * bearer would silently widen the buyer's scope to Public — the exact\n * failure the feature exists to prevent (guide §7).\n *\n * Deliberately free of any `@seatlayer/core` import: it deals in tokens, HTTP\n * status codes and callbacks only, so it vendors into the app's widget copy\n * with no engine coupling.\n */\n\n/** Why the SDK is asking the host for a token. Passed to the provider. */\nexport type BuyerAccessRefreshReason =\n /** First acquisition, before the chart is fetched. */\n | 'initial'\n /** Proactive: the held token is inside the renewal skew. */\n | 'expiring'\n /** Reactive: the held token's own expiry has passed. */\n | 'expired'\n /** Reactive: the server answered 401 `buyer_access_expired`. */\n | 'unauthorized'\n /** A realtime reconnect needs a live bearer to mint a subscribe ticket. */\n | 'reconnect'\n /** The host called `refreshAccess()`. */\n | 'manual';\n\n/** What a `buyerAccessTokenProvider` resolves to — the response body of the\n * host's own mint endpoint, unchanged. */\nexport interface BuyerAccessToken {\n /** The opaque `bse_…` buyer-access session bearer. */\n token: string;\n /** Epoch ms. Optional — absent means \"trust the server\", and the SDK then\n * refreshes only reactively on a 401. */\n expiresAt?: number;\n}\n\nexport type BuyerAccessTokenProvider = (\n context: { reason: BuyerAccessRefreshReason },\n) => BuyerAccessToken | Promise<BuyerAccessToken>;\n\n/**\n * Why private inventory is not available. Never collapsed into a generic\n * network failure (guide §10) and never carrying channel identity — the buyer\n * is told the state, not which allocation they missed.\n */\nexport type BuyerAccessUnavailableReason =\n /** The session was revoked (HTTP 401 after refresh, or WS close 4401). */\n | 'revoked'\n /** The channel is paused — a legitimate, temporary organizer state. */\n | 'paused'\n /** 401 `buyer_access_invalid`: do not retry this bearer. */\n | 'invalid'\n /** 403 `buyer_access_origin_mismatch`. */\n | 'origin_mismatch'\n /** 403 `buyer_access_event_mismatch`. */\n | 'event_mismatch'\n /** 403 `buyer_access_mode_mismatch` (test bearer on a live event or v.v.). */\n | 'mode_mismatch'\n /** 403 `channel_access_denied`. */\n | 'channel_denied'\n /** 422 `invalid_channel_scope` — an integration configuration error. */\n | 'invalid_scope'\n /** The host's token provider threw or returned nothing usable. */\n | 'provider_failed'\n /** A one-shot `buyerAccessToken` lapsed and no provider was configured. */\n | 'no_token';\n\n/** The access session expired. Carries whether the refresh recovered it. */\nexport interface BuyerAccessExpiredEvent {\n reason: BuyerAccessRefreshReason;\n /** The server's machine code when the expiry was observed over HTTP. */\n code?: string;\n /** True when the provider handed back a fresh token and work continues. */\n refreshed: boolean;\n}\n\n/** Private inventory is unavailable, and refreshing will not fix it. */\nexport interface BuyerAccessUnavailableEvent {\n reason: BuyerAccessUnavailableReason;\n /** The server's machine code, when there was one. */\n code?: string;\n /** The HTTP status, when the state came from an HTTP response. */\n status?: number;\n /** True only for states a later retry could clear (`paused`). */\n retryable: boolean;\n}\n\n/** One or more selected-but-unheld units stopped being selectable. */\nexport interface SelectedObjectUnavailableEvent {\n /** Inventory labels (never channel identity). */\n labels: string[];\n reason:\n /** An allocation change moved it out of this buyer's scope (guide §9). */\n | 'ineligible'\n /** Someone else held or booked it. */\n | 'taken'\n /** 409 `allocation_exhausted` — this private allocation has none left. */\n | 'exhausted';\n code?: string;\n}\n\nexport interface BuyerAccessContextOptions {\n provider?: BuyerAccessTokenProvider;\n /** One-shot escape hatch for hosts that already own the token lifecycle. */\n token?: string | BuyerAccessToken;\n /** Renew this long before the stated expiry. Default 30s. */\n skewMs?: number;\n onExpired?: (event: BuyerAccessExpiredEvent) => void;\n onUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n}\n\n/**\n * Thrown instead of letting a scoped request go out unauthenticated. Carries no\n * bearer and no channel identity, so it is safe to log or hand to an error\n * reporter verbatim.\n */\nexport class BuyerAccessUnavailableError extends Error {\n readonly reason: BuyerAccessUnavailableReason;\n readonly code?: string;\n readonly status?: number;\n\n constructor(event: BuyerAccessUnavailableEvent) {\n super(`buyer_access_unavailable:${event.reason}`);\n this.name = 'BuyerAccessUnavailableError';\n this.reason = event.reason;\n this.code = event.code;\n this.status = event.status;\n }\n}\n\n/** Server error codes that mean \"this session lapsed; run the refresh flow\". */\nconst EXPIRED_CODES = new Set(['buyer_access_expired']);\n\n/**\n * Reasons that describe ONE request, not the session behind it. They report to\n * the host but never latch the context terminal and never discard the bearer.\n *\n * `channel_denied` is here on the guide's own reading: §10 answers a 403\n * `channel_access_denied` with \"return buyer to permitted inventory\" — the\n * buyer asked for a seat outside their allocation, which is a mis-click, not a\n * dead session. Latching it meant one wrong seat permanently killed a live\n * buyer's access, including their ability to RELEASE the hold they already\n * legitimately owned. Found against a live worker in the M9 pass.\n */\nconst RECOVERABLE = new Set<BuyerAccessUnavailableReason>([\n 'paused',\n 'provider_failed',\n 'channel_denied',\n]);\n\n/**\n * Guide §10 error table → an unavailable reason. Anything not in the table is\n * not an access failure and must stay an ordinary error, so this returns null.\n */\nexport function classifyAccessFailure(\n status: number,\n code: string | undefined,\n): BuyerAccessUnavailableReason | null {\n switch (code) {\n case 'buyer_access_invalid':\n return 'invalid';\n case 'buyer_access_revoked':\n return 'revoked';\n case 'buyer_access_origin_mismatch':\n return 'origin_mismatch';\n case 'buyer_access_event_mismatch':\n return 'event_mismatch';\n case 'buyer_access_mode_mismatch':\n return 'mode_mismatch';\n case 'channel_access_denied':\n return 'channel_denied';\n case 'channel_paused':\n return 'paused';\n case 'invalid_channel_scope':\n return 'invalid_scope';\n default:\n break;\n }\n // An unnamed 401 on a scoped request is still an access failure; treat it as\n // the non-retryable kind rather than falling through to Public sale.\n if (status === 401) return 'invalid';\n return null;\n}\n\n/** True when this HTTP failure means \"refresh the session and try again\". */\nexport function isAccessExpiry(status: number, code: string | undefined): boolean {\n return status === 401 && !!code && EXPIRED_CODES.has(code);\n}\n\nconst DEFAULT_SKEW_MS = 30_000;\n\nexport class BuyerAccessContext {\n /** Private field: not enumerable, not spreadable, not serializable. */\n #token: string | null = null;\n #expiresAt = 0;\n #provider?: BuyerAccessTokenProvider;\n #skewMs: number;\n #inflight: Promise<string | null> | null = null;\n #terminal: BuyerAccessUnavailableEvent | null = null;\n /** The most recent failure, terminal or not — so one cause reports once. */\n #lastFailure: BuyerAccessUnavailableEvent | null = null;\n #onExpired?: (event: BuyerAccessExpiredEvent) => void;\n #onUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /** Decided once, at construction. See the `configured` getter. */\n #configured = false;\n\n constructor(options: BuyerAccessContextOptions) {\n this.#provider = options.provider;\n this.#skewMs = options.skewMs ?? DEFAULT_SKEW_MS;\n this.#onExpired = options.onExpired;\n this.#onUnavailable = options.onUnavailable;\n if (options.token) {\n const seed = typeof options.token === 'string' ? { token: options.token } : options.token;\n this.#accept(seed);\n }\n this.#configured = !!this.#provider || !!this.#token;\n }\n\n /**\n * True when this picker is access-scoped at all. A false here is the\n * tokenless public picker, which must behave exactly as it always has.\n *\n * Answered from what the HOST asked for, never from live token state. It used\n * to be `!!#provider || !!#token`, which quietly inverted this file's central\n * rule for a one-shot `buyerAccessToken` host: `#fail()` clears `#token`, so\n * the first refusal turned a configured context into an \"unconfigured\" one,\n * `authorization()` then returned null instead of throwing, and the very next\n * call went out with no bearer — the anonymous Public sale fallback this\n * module exists to prevent. A provider host never saw it, because `#provider`\n * held `configured` true. Found against a live worker in the M9 pass.\n */\n get configured(): boolean {\n return this.#configured;\n }\n\n /** Set once a state arrives that refreshing cannot clear. */\n get unavailable(): BuyerAccessUnavailableEvent | null {\n return this.#terminal;\n }\n\n /** True while a usable bearer is held (ignores skew). */\n get hasToken(): boolean {\n return !!this.#token && (this.#expiresAt === 0 || this.#expiresAt > Date.now());\n }\n\n /** Epoch ms the current token expires, or 0 when the host didn't say. */\n get expiresAt(): number {\n return this.#expiresAt;\n }\n\n /**\n * The `Authorization` header value for a scoped operation.\n *\n * Returns null only when this context is not configured at all (the ordinary\n * anonymous public picker). A configured context either returns a bearer or\n * throws `BuyerAccessUnavailableError` — it never returns null, because a\n * null here would send the request as anonymous Public sale.\n */\n async authorization(reason: BuyerAccessRefreshReason = 'initial'): Promise<string | null> {\n if (!this.configured) return null;\n if (this.#terminal) throw new BuyerAccessUnavailableError(this.#terminal);\n\n const now = Date.now();\n const stale = !this.#token || (this.#expiresAt > 0 && this.#expiresAt - this.#skewMs <= now);\n if (stale) {\n const expired = !!this.#token && this.#expiresAt > 0 && this.#expiresAt <= now;\n const why: BuyerAccessRefreshReason = this.#token ? (expired ? 'expired' : 'expiring') : reason;\n const token = await this.#renew(why);\n if (!token) {\n // #renew already classified and reported the failure; reuse that event\n // rather than raising a second one for the same cause.\n throw new BuyerAccessUnavailableError(\n this.#terminal ?? this.#lastFailure ?? this.#fail('provider_failed'),\n );\n }\n return `Bearer ${token}`;\n }\n return `Bearer ${this.#token}`;\n }\n\n /**\n * Handle a 401/403 from a scoped call. Returns true when the caller should\n * retry the same request once with the refreshed bearer.\n */\n async handleFailure(status: number, code: string | undefined): Promise<boolean> {\n if (!this.configured) return false;\n\n if (isAccessExpiry(status, code)) {\n this.#token = null;\n this.#expiresAt = 0;\n const token = await this.#renew('unauthorized', code);\n this.#onExpired?.({ reason: 'unauthorized', code, refreshed: !!token });\n return !!token;\n }\n\n const reason = classifyAccessFailure(status, code);\n if (reason) {\n this.#fail(reason, code, status);\n return false;\n }\n return false;\n }\n\n /** Host-driven re-acquisition (after the buyer signs in again, say). */\n async refresh(reason: BuyerAccessRefreshReason = 'manual'): Promise<boolean> {\n this.#terminal = null;\n this.#lastFailure = null;\n this.#token = null;\n this.#expiresAt = 0;\n return !!(await this.#renew(reason));\n }\n\n /** Drop the bearer. Called on destroy so nothing outlives the widget. */\n clear(): void {\n this.#token = null;\n this.#expiresAt = 0;\n this.#inflight = null;\n }\n\n /** Redaction: the bearer must not survive a stringify or an interpolation. */\n toJSON(): { configured: boolean; hasToken: boolean } {\n return { configured: this.configured, hasToken: this.hasToken };\n }\n\n toString(): string {\n return '[BuyerAccessContext redacted]';\n }\n\n // ---- internals ------------------------------------------------------------\n\n #accept(next: BuyerAccessToken | null | undefined): string | null {\n if (!next || typeof next.token !== 'string' || !next.token) return null;\n this.#token = next.token;\n this.#expiresAt = typeof next.expiresAt === 'number' ? next.expiresAt : 0;\n return this.#token;\n }\n\n /**\n * One provider call at a time. Several operations racing an expiry (chart +\n * objects + a socket ticket) must not mint several sessions — the guide's\n * rotate-on-retry rule would revoke the ones they didn't observe.\n */\n #renew(reason: BuyerAccessRefreshReason, code?: string): Promise<string | null> {\n if (this.#inflight) return this.#inflight;\n const provider = this.#provider;\n if (!provider) {\n // A one-shot token with no provider cannot be renewed. That is a legal\n // host choice, so it is a typed state, not a crash.\n this.#fail('no_token', code);\n return Promise.resolve(null);\n }\n const run = (async (): Promise<string | null> => {\n try {\n const next = await provider({ reason });\n const token = this.#accept(next);\n if (!token) {\n this.#fail('provider_failed', code);\n return null;\n }\n return token;\n } catch {\n // The provider's own error text may contain host detail; it is not\n // rethrown and not logged. The host already saw its own failure.\n this.#fail('provider_failed', code);\n return null;\n } finally {\n this.#inflight = null;\n }\n })();\n this.#inflight = run;\n return run;\n }\n\n #fail(\n reason: BuyerAccessUnavailableReason,\n code?: string,\n status?: number,\n ): BuyerAccessUnavailableEvent {\n const event: BuyerAccessUnavailableEvent = {\n reason,\n code,\n status,\n // Unchanged: `retryable` means \"the SAME request may succeed later\".\n // `provider_failed` is recoverable but not retryable — the host must fix\n // its mint endpoint first — so the two sets are deliberately different.\n retryable: reason === 'paused' || reason === 'channel_denied',\n };\n this.#lastFailure = event;\n // A recoverable reason says nothing about the SESSION, so it must not latch\n // the context terminal and must not throw the bearer away.\n if (!RECOVERABLE.has(reason)) {\n this.#terminal = event;\n this.#token = null;\n this.#expiresAt = 0;\n }\n this.#onUnavailable?.(event);\n return event;\n }\n}\n\n/** Build a context from widget options, or null for the tokenless public path. */\nexport function createBuyerAccessContext(\n options: {\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n buyerAccessToken?: string | BuyerAccessToken;\n },\n hooks: Pick<BuyerAccessContextOptions, 'onExpired' | 'onUnavailable'> = {},\n): BuyerAccessContext | null {\n if (!options.buyerAccessTokenProvider && !options.buyerAccessToken) return null;\n return new BuyerAccessContext({\n provider: options.buyerAccessTokenProvider,\n token: options.buyerAccessToken,\n ...hooks,\n });\n}\n","/** Dependency-free canonical SeatLayer mark for distributed SDK attribution.\n *\n * Keep the geometry in sync with `SeatLayerMark` and\n * `scripts/generate-brand-assets.py`. The fixed dark-surface palette makes the\n * fragment safe inside the self-contained midnight attribution tile.\n */\nexport const SEATLAYER_ATTRIBUTION_MARK_SVG =\n '<svg viewBox=\"0 0 64 56\" width=\"12\" height=\"11\" fill=\"none\" aria-hidden=\"true\" focusable=\"false\" style=\"display:block\">' +\n '<path d=\"M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z\" fill=\"#f4b740\"/>' +\n '<path d=\"M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z\" fill=\"#f4b740\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '<path d=\"M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z\" fill=\"#fcf7ee\"/>' +\n '<path d=\"M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z\" fill=\"#fcf7ee\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '<path d=\"M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z\" fill=\"#fcf7ee\"/>' +\n '<path d=\"M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z\" fill=\"#fcf7ee\" transform=\"translate(64 0) scale(-1 1)\"/>' +\n '</svg>';\n","/**\n * A secure, framework-neutral host for the SeatLayer chart Designer.\n *\n * The Designer remains an iframe so a platform never gives its SeatLayer secret\n * key to a browser. This class owns the iframe lifecycle and accepts messages\n * only from that iframe's exact origin.\n */\nexport type EmbeddedDesignerEventType =\n | 'seatlayer.designer.ready'\n | 'seatlayer.designer.saved'\n | 'seatlayer.designer.published'\n | 'seatlayer.designer.close'\n | 'seatlayer.designer.error';\n\nexport interface EmbeddedDesignerMessage {\n type: EmbeddedDesignerEventType;\n chartId?: string;\n workspaceId?: string;\n expiresAt?: number;\n code?: string;\n message?: string;\n meta?: unknown;\n /**\n * Set by the Designer on an error it raised while the editor was already\n * running (a failed autosave, thumbnail upload, reload…). Such an error is\n * about ONE operation, not about the session, so the SDK reports it to the\n * host and leaves the live editor mounted instead of replacing it with the\n * dead-end card. Absent on older Designer builds — see\n * {@link EmbeddedDesigner} for the phase-based fallback.\n */\n fatal?: boolean;\n /** The operation that failed, when `fatal` is `false` (e.g. `'save'`). */\n action?: string;\n}\n\nexport interface EmbeddedDesignerOptions {\n /** The short-lived URL returned by your backend's Designer-session call. */\n designerUrl: string;\n /** CSS selector or element where the iframe is mounted. */\n container: string | HTMLElement;\n /**\n * Verify the message belongs to the chart your backend opened. When set, the\n * id is required on `ready` and every runtime lifecycle message. Only an error\n * raised before the iframe resolves its session may omit it.\n */\n expectedChartId?: string;\n /**\n * Verify the message belongs to the workspace your backend opened. Uses the\n * same ready/runtime requirement and pre-session error exception as\n * `expectedChartId`.\n */\n expectedWorkspaceId?: string;\n title?: string;\n className?: string;\n style?: Partial<CSSStyleDeclaration>;\n allow?: string;\n referrerPolicy?: ReferrerPolicy;\n /**\n * Show the built-in branded loading skeleton and error/expiry card inside the\n * container while the Designer boots. Defaults to `true`. Set `false` when the\n * host renders its own loading and error chrome.\n */\n showLoadingState?: boolean;\n /**\n * If the Designer never posts `ready` within this many milliseconds, the host\n * transitions to the error card with a timeout message. Defaults to `20000`.\n * Only used when `showLoadingState` is enabled.\n */\n loadingTimeoutMs?: number;\n /**\n * How to size the iframe's height. The Designer is a full application (its\n * shell is `position:fixed; height:100dvh`), not flowing content, so it should\n * fill its box rather than be measured.\n *\n * - `'fill'` (default): container-aware. On mount the SDK probes whether the\n * host gave the container a DEFINITE (bounded) height:\n * - **Bounded container** (a fixed-height block, `height`/`max-height`,\n * `flex:1; min-h:0`, a resolved `%`, etc.) → the iframe fills 100% of\n * that block and tracks its size live via a `ResizeObserver`.\n * - **Content-sized container** (the block collapses to whatever the iframe\n * measures — typical full-page usage) → the iframe grows so its bottom\n * edge reaches the bottom of the viewport (`window.innerHeight -\n * iframe.top`), recomputed (rAF-throttled) on `resize` /\n * `orientationchange` / `scroll`.\n * Either way the result is clamped to `minHeight`. The verdict is cached but\n * re-probed on `resize`/`orientationchange` so a responsive host layout can\n * flip between the two. The legacy `seatlayer.designer.resize` message is\n * ignored in `'fill'` mode: it is circular, because the fixed-position shell\n * just echoes the iframe height.\n * - a number: a fixed pixel height. In this mode the legacy resize message is\n * still honoured (unless `autoResize` is `false`) so older hosts keep growing.\n *\n * All SDK-managed heights are written with `!important` priority so a host\n * theme's `iframe { height: … !important }` cannot override them.\n */\n height?: 'fill' | number;\n /** Minimum height (px) that `'fill'` mode clamps to. Defaults to `480`. */\n minHeight?: number;\n /**\n * Auto-grow the iframe to the height the Designer reports over the resize\n * protocol (`seatlayer.designer.resize`). Only applies when `height` is a fixed\n * number; ignored in `'fill'` mode. Defaults to `true`. Set `false` when the\n * host sizes a fixed-height iframe itself.\n */\n autoResize?: boolean;\n /**\n * Called when the user presses \"Try again\" on the error card. Use it to mint a\n * fresh Designer session and call `setDesignerUrl()` with the new URL, which\n * recreates the iframe and returns to the loading state. When omitted, \"Try\n * again\" reloads the current `designerUrl` in place.\n *\n * When supplied, it also powers automatic session renewal — see\n * {@link EmbeddedDesignerOptions.autoRenewSession}.\n */\n onRequestRelaunch?: () => void;\n /**\n * Keep long editing sessions alive without the user ever hitting the expiry\n * wall. Designer sessions are short-lived security tokens; when the host wires\n * `onRequestRelaunch` the SDK, with this enabled, will:\n *\n * - **Renew proactively.** From each `ready` message's `expiresAt` it schedules\n * a silent relaunch shortly before the session lapses (~3 min ahead; for a\n * TTL under 15 min it renews after 80% of the remaining life, and never\n * sooner than 30s after `ready`). The host mints a fresh session and swaps\n * `designerUrl`, so the editor keeps working with no error card.\n * - **Recover on expiry.** If an expiry error still slips through (a slept\n * laptop woke past the renewal window, say) it makes ONE automatic relaunch\n * attempt before showing the \"Try again\" card, and only falls back to the\n * card if that relaunch also fails.\n *\n * Defaults to `true` whenever `onRequestRelaunch` is provided; a no-op without\n * it. Set `false` to keep the fully manual \"Try again\" behavior.\n */\n autoRenewSession?: boolean;\n onReady?: (message: EmbeddedDesignerMessage) => void;\n onSaved?: (message: EmbeddedDesignerMessage) => void;\n onPublished?: (message: EmbeddedDesignerMessage) => void;\n onClose?: (message: EmbeddedDesignerMessage) => void;\n onError?: (message: EmbeddedDesignerMessage) => void;\n}\n\nconst TYPES = new Set<EmbeddedDesignerEventType>([\n 'seatlayer.designer.ready',\n 'seatlayer.designer.saved',\n 'seatlayer.designer.published',\n 'seatlayer.designer.close',\n 'seatlayer.designer.error',\n]);\n\nconst DEFAULT_LOADING_TIMEOUT_MS = 20000;\nconst DEFAULT_MIN_FILL_HEIGHT = 480;\n/**\n * Proactive session-renewal timing (see {@link EmbeddedDesigner.scheduleRenewal}).\n * We aim to relaunch a comfortable lead ahead of `expiresAt`; short-lived sessions\n * instead renew after a fraction of their life so the lead never overshoots the TTL.\n */\nconst RENEW_LEAD_MS = 3 * 60 * 1000; // standard lead: renew ~3 min before expiry\nconst RENEW_SHORT_TTL_MS = 15 * 60 * 1000; // below this TTL, use the fraction clamp\nconst RENEW_SHORT_TTL_FRACTION = 0.8; // short TTL: renew after 80% of remaining life\nconst RENEW_MIN_DELAY_MS = 30 * 1000; // never renew sooner than 30s after `ready`\n/**\n * Container-fill detection tunables. The probe drives the iframe to two extreme\n * heights within one synchronous task (no paint between reads, so no flash) and\n * watches whether the container tracks it.\n */\nconst FILL_PROBE_HEIGHT_PX = 100000; // \"huge\" iframe used to see if the box grows with it\nconst FILL_PROBE_TRACK_EPSILON_PX = 4; // container grew with the iframe ⇒ content-sized\nconst FILL_MIN_DEFINITE_HEIGHT_PX = 50; // a bounded box must keep at least this much height\n\n/** Internal reason the error card is being shown, used to pick human copy. */\ntype ErrorCause = 'expired' | 'mismatch' | 'timeout' | 'load';\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container !== 'string') return container;\n const element = document.querySelector<HTMLElement>(container);\n if (!element) throw new Error(`EmbeddedDesigner container not found: ${container}`);\n return element;\n}\n\n/** Map an error message's `code` onto one of the human-copy causes. */\nfunction causeFromCode(code: string | undefined): ErrorCause {\n const value = (code ?? '').toLowerCase();\n if (value.includes('expire') || value.includes('revoke') || value === '401') return 'expired';\n if (value.includes('mismatch')) return 'mismatch';\n if (value.includes('timeout')) return 'timeout';\n return 'load';\n}\n\nconst ERROR_COPY: Record<ErrorCause, { title: string; body: string }> = {\n expired: {\n title: 'This design session expired',\n body: 'For your security, editing sessions are short-lived. Start a fresh one to keep designing.',\n },\n mismatch: {\n title: \"This editor doesn't match this chart\",\n body: 'The session that loaded belongs to a different chart or workspace. Reopen the designer to continue.',\n },\n timeout: {\n title: 'The designer is taking too long',\n body: 'It did not finish loading in time. This is usually a slow connection — try again.',\n },\n load: {\n title: \"We couldn't load the designer\",\n body: 'Something went wrong while opening the editor. Please try again.',\n },\n};\n\n/** Mount, replace, and destroy a scoped Designer iframe safely. */\nexport class EmbeddedDesigner {\n private options: EmbeddedDesignerOptions;\n private frame: HTMLIFrameElement | null = null;\n private designerOrigin = '';\n private overlay: HTMLDivElement | null = null;\n private timeoutTimer: ReturnType<typeof setTimeout> | null = null;\n /** Proactive session-renewal timer; armed from each `ready`, cleared on re-mount. */\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n /** Last identity-checked session expiry, so a live policy change can re-arm. */\n private sessionExpiresAt: number | undefined;\n /**\n * One automatic recovery relaunch is allowed per expiry. Reset ONLY when a fresh\n * `ready` arrives — deliberately not on re-mount — so a session that keeps failing\n * to load can't loop the host through endless silent relaunches.\n */\n private autoRecoverUsed = false;\n private phase: 'loading' | 'ready' | 'error' = 'loading';\n /**\n * Set only after an identity-checked `ready`. Unlike `phase`, this remains true\n * if a later fatal error renders the error card, so no subsequent callback can\n * shed the chart/workspace identity the live session already established.\n */\n private identityEstablished = false;\n private restoreContainerPosition: string | null = null;\n // Host-side fullscreen pin: saved state we restore on `off`/Escape/destroy.\n private pinned = false;\n private frameStyleBeforeFs: string | null = null;\n private docOverflowBeforeFs: string | null = null;\n private bodyOverflowBeforeFs: string | null = null;\n private fsKeyHandler: ((event: KeyboardEvent) => void) | null = null;\n /** Latest height (px string) the Designer reported; re-applied after unpin. */\n private lastAutoHeight = '';\n // Fill sizing: pending rAF handles + whether window listeners are attached.\n private fillRaf: number | null = null;\n private reprobeRaf: number | null = null;\n private fillListening = false;\n /** Resolved container element (fill measurement + ResizeObserver target). */\n private containerEl: HTMLElement | null = null;\n /** Cached fill verdict: 'container' = bounded block, 'viewport' = full page. */\n private fillMode: 'viewport' | 'container' | null = null;\n /** Live block-size tracking in container-fill mode; disconnected on destroy. */\n private resizeObs: ResizeObserver | null = null;\n\n constructor(options: EmbeddedDesignerOptions) {\n this.options = options;\n }\n\n mount(): HTMLIFrameElement {\n this.destroy();\n const url = new URL(this.options.designerUrl, window.location.href);\n if (url.protocol !== 'https:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {\n throw new Error('EmbeddedDesigner requires an HTTPS designerUrl outside local development.');\n }\n this.designerOrigin = url.origin;\n\n const frame = document.createElement('iframe');\n frame.title = this.options.title ?? 'Venue chart Designer';\n frame.allow = this.options.allow ?? 'fullscreen; clipboard-write';\n frame.referrerPolicy = this.options.referrerPolicy ?? 'origin';\n frame.src = url.toString();\n // Width/height are written with `!important` priority so a host theme's\n // `iframe { height: … !important }` cannot beat the SDK's inline sizing.\n frame.style.setProperty('width', '100%', 'important');\n // `'fill'` (default) is (re)computed once the frame is in the DOM (see\n // startFill); a numeric height is a fixed pixel box.\n frame.style.setProperty(\n 'height',\n typeof this.options.height === 'number' ? `${this.options.height}px` : '100%',\n 'important',\n );\n frame.style.border = '0';\n Object.assign(frame.style, this.options.style);\n if (this.options.className) frame.className = this.options.className;\n\n const container = resolveContainer(this.options.container);\n this.containerEl = container;\n window.addEventListener('message', this.handleMessage);\n container.append(frame);\n this.frame = frame;\n\n // Fill mode owns the height from the viewport now the frame is measurable.\n if (this.fillEnabled()) this.startFill();\n\n this.phase = 'loading';\n if (this.loadingStateEnabled()) {\n this.ensureContainerPositioned(container);\n this.renderOverlay(container, 'loading');\n const timeout = this.options.loadingTimeoutMs ?? DEFAULT_LOADING_TIMEOUT_MS;\n if (timeout > 0 && Number.isFinite(timeout)) {\n this.timeoutTimer = setTimeout(() => {\n if (this.phase === 'loading') this.showError('timeout');\n }, timeout);\n }\n }\n return frame;\n }\n\n /** Replace the iframe instead of assigning a new fragment to an existing one. */\n setDesignerUrl(designerUrl: string): HTMLIFrameElement {\n this.options = { ...this.options, designerUrl };\n // mount() tears everything down and re-enters the loading state.\n return this.mount();\n }\n\n getIframe(): HTMLIFrameElement | null {\n return this.frame;\n }\n\n /** Update iframe sizing without replacing the live Designer session. */\n setSizing(height: 'fill' | number | undefined, minHeight: number | undefined): void {\n this.options = { ...this.options, height, minHeight };\n if (!this.frame) return;\n\n this.stopFill();\n this.lastAutoHeight = '';\n if (this.fillEnabled()) {\n if (!this.pinned) this.setFrameHeight('100%');\n this.startFill();\n } else if (!this.pinned) {\n this.setFrameHeight(`${height}px`);\n }\n }\n\n /** Update renewal/expiry-recovery policy without replacing the iframe. */\n setRelaunchPolicy(\n onRequestRelaunch: (() => void) | undefined,\n autoRenewSession: boolean | undefined,\n ): void {\n this.options = { ...this.options, onRequestRelaunch, autoRenewSession };\n this.clearRenewTimer();\n if (this.phase === 'ready') this.scheduleRenewal(this.sessionExpiresAt);\n }\n\n destroy(): void {\n window.removeEventListener('message', this.handleMessage);\n this.stopFill();\n this.unpinFullscreen();\n this.clearTimeoutTimer();\n this.clearRenewTimer();\n this.removeOverlay();\n this.restoreContainerStyle();\n this.frame?.remove();\n this.frame = null;\n this.containerEl = null;\n this.fillMode = null;\n this.designerOrigin = '';\n this.phase = 'loading';\n this.identityEstablished = false;\n this.sessionExpiresAt = undefined;\n this.lastAutoHeight = '';\n }\n\n private loadingStateEnabled(): boolean {\n return this.options.showLoadingState !== false;\n }\n\n private autoResizeEnabled(): boolean {\n return this.options.autoResize !== false;\n }\n\n /** Fill mode is the default; a numeric `height` opts into a fixed pixel box. */\n private fillEnabled(): boolean {\n return typeof this.options.height !== 'number';\n }\n\n /** Write an SDK-managed height with `!important` so a host theme can't win. */\n private setFrameHeight(value: string): void {\n this.frame?.style.setProperty('height', value, 'important');\n }\n\n /**\n * Decide whether the host gave the container a DEFINITE (bounded) height — a\n * fixed block the embed should fill 100% of — versus a content-sized container\n * that collapses to whatever the iframe measures (full-page usage).\n *\n * We drive the iframe to two extreme heights within a single synchronous task\n * and watch whether the container follows: a bounded box barely moves, a\n * content-sized one grows with the iframe. Because we restore the height before\n * yielding, the browser only lays out — it never paints the extremes, so there\n * is no visible flash. Works for px, resolved `%`, and flex (`flex:1;min-h:0`)\n * heights, and leaves a mere `min-height` floor classified as content-sized so\n * full-page hosts keep the old viewport-fill behavior.\n */\n private detectFillMode(): 'viewport' | 'container' {\n const container = this.containerEl;\n const frame = this.frame;\n if (this.pinned || !container || !frame) return this.fillMode ?? 'viewport';\n const measure = (): number => container.getBoundingClientRect().height;\n const savedValue = frame.style.getPropertyValue('height');\n const savedPriority = frame.style.getPropertyPriority('height');\n\n frame.style.setProperty('height', '0px', 'important');\n const collapsed = measure();\n frame.style.setProperty('height', `${FILL_PROBE_HEIGHT_PX}px`, 'important');\n const expanded = measure();\n\n if (savedValue) frame.style.setProperty('height', savedValue, savedPriority);\n else frame.style.removeProperty('height');\n\n const tracksIframe = expanded - collapsed > FILL_PROBE_TRACK_EPSILON_PX;\n const bounded = !tracksIframe && collapsed >= FILL_MIN_DEFINITE_HEIGHT_PX;\n return bounded ? 'container' : 'viewport';\n }\n\n /**\n * Size the iframe for the current fill verdict, clamped to `minHeight`. In\n * container mode it fills 100% of the bounded block; in viewport mode its\n * bottom edge meets the bottom of the viewport (`window.innerHeight - top`).\n * No-op while pinned fullscreen (the pin fills the viewport itself).\n */\n private applyFill(): void {\n if (!this.frame || this.pinned) return;\n const min = this.options.minHeight ?? DEFAULT_MIN_FILL_HEIGHT;\n if (this.fillMode === 'container' && this.containerEl) {\n const target = Math.max(min, Math.round(this.containerEl.getBoundingClientRect().height));\n this.setFrameHeight(`${target}px`);\n return;\n }\n const top = this.frame.getBoundingClientRect().top;\n const target = Math.max(min, Math.round(window.innerHeight - top));\n this.setFrameHeight(`${target}px`);\n }\n\n /** rAF-throttled fill recompute, so a burst of scroll/RO ticks coalesces. */\n private scheduleFill = (): void => {\n if (this.fillRaf !== null) return;\n this.fillRaf = requestAnimationFrame(() => {\n this.fillRaf = null;\n this.applyFill();\n });\n };\n\n /**\n * rAF-throttled re-probe: a host layout change (responsive breakpoint, a block\n * gaining/losing a definite height) can flip the verdict, so `resize` /\n * `orientationchange` re-detect and swap the container observer accordingly.\n */\n private scheduleReprobe = (): void => {\n if (this.reprobeRaf !== null) return;\n this.reprobeRaf = requestAnimationFrame(() => {\n this.reprobeRaf = null;\n if (this.pinned) return;\n this.fillMode = this.detectFillMode();\n this.syncContainerObserver();\n this.applyFill();\n });\n };\n\n /** Attach/detach the container ResizeObserver to match the current verdict. */\n private syncContainerObserver(): void {\n const want =\n this.fillMode === 'container' && !!this.containerEl && typeof ResizeObserver !== 'undefined';\n if (want && !this.resizeObs) {\n this.resizeObs = new ResizeObserver(() => this.scheduleFill());\n this.resizeObs.observe(this.containerEl!);\n } else if (!want && this.resizeObs) {\n this.resizeObs.disconnect();\n this.resizeObs = null;\n }\n }\n\n private startFill(): void {\n this.fillMode = this.detectFillMode();\n this.syncContainerObserver();\n this.applyFill();\n if (this.fillListening) return;\n this.fillListening = true;\n // Layout-changing events re-probe (the verdict can flip); scroll only shifts\n // the viewport-fill top offset, so it just re-applies.\n window.addEventListener('resize', this.scheduleReprobe);\n window.addEventListener('orientationchange', this.scheduleReprobe);\n window.addEventListener('scroll', this.scheduleFill, { passive: true });\n }\n\n private stopFill(): void {\n if (this.fillRaf !== null) {\n cancelAnimationFrame(this.fillRaf);\n this.fillRaf = null;\n }\n if (this.reprobeRaf !== null) {\n cancelAnimationFrame(this.reprobeRaf);\n this.reprobeRaf = null;\n }\n if (this.resizeObs) {\n this.resizeObs.disconnect();\n this.resizeObs = null;\n }\n if (!this.fillListening) return;\n this.fillListening = false;\n window.removeEventListener('resize', this.scheduleReprobe);\n window.removeEventListener('orientationchange', this.scheduleReprobe);\n window.removeEventListener('scroll', this.scheduleFill);\n }\n\n /**\n * Pin the iframe over the host page as a viewport-filling overlay. We save the\n * iframe's inline style and the document scroll state so `unpinFullscreen`\n * restores everything exactly. Escape (host-side) also exits.\n */\n private pinFullscreen(): void {\n if (this.pinned || !this.frame) return;\n this.pinned = true;\n this.frameStyleBeforeFs = this.frame.getAttribute('style');\n // Every pin property is `!important` so a host theme's `iframe { … }` rules\n // (height/width/inset) can't unpin us. `inset` is written as its four longhands\n // for reliability across engines. Restored wholesale via the saved style attr.\n const pin: Record<string, string> = {\n position: 'fixed',\n top: '0',\n right: '0',\n bottom: '0',\n left: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n border: '0',\n 'z-index': '2147483000',\n background: '#101625',\n };\n for (const [property, value] of Object.entries(pin)) {\n this.frame.style.setProperty(property, value, 'important');\n }\n\n const docEl = document.documentElement;\n this.docOverflowBeforeFs = docEl.style.overflow;\n docEl.style.overflow = 'hidden';\n if (document.body) {\n this.bodyOverflowBeforeFs = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n this.fsKeyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') this.unpinFullscreen();\n };\n window.addEventListener('keydown', this.fsKeyHandler);\n }\n\n /** Undo `pinFullscreen`: restore the iframe style + scroll lock. Idempotent. */\n private unpinFullscreen(): void {\n if (!this.pinned) return;\n this.pinned = false;\n if (this.frame) {\n if (this.frameStyleBeforeFs === null) this.frame.removeAttribute('style');\n else this.frame.setAttribute('style', this.frameStyleBeforeFs);\n // Restore the right height for the mode: recompute the fill, or re-apply\n // the last height the Designer reported (numeric mode). Both use\n // `!important` so a host theme can't win after we unpin.\n if (this.fillEnabled()) this.applyFill();\n else if (this.autoResizeEnabled() && this.lastAutoHeight) this.setFrameHeight(this.lastAutoHeight);\n else if (typeof this.options.height === 'number') this.setFrameHeight(`${this.options.height}px`);\n }\n this.frameStyleBeforeFs = null;\n\n if (this.docOverflowBeforeFs !== null) {\n document.documentElement.style.overflow = this.docOverflowBeforeFs;\n this.docOverflowBeforeFs = null;\n }\n if (this.bodyOverflowBeforeFs !== null && document.body) {\n document.body.style.overflow = this.bodyOverflowBeforeFs;\n this.bodyOverflowBeforeFs = null;\n }\n if (this.fsKeyHandler) {\n window.removeEventListener('keydown', this.fsKeyHandler);\n this.fsKeyHandler = null;\n }\n }\n\n private clearTimeoutTimer(): void {\n if (this.timeoutTimer !== null) {\n clearTimeout(this.timeoutTimer);\n this.timeoutTimer = null;\n }\n }\n\n /**\n * Auto-renewal (proactive + one expiry recovery) is on when the host wired a\n * relaunch hook and did not opt out. Without the hook there is nothing to call,\n * so it is a no-op.\n */\n private autoRenewEnabled(): boolean {\n return !!this.options.onRequestRelaunch && this.options.autoRenewSession !== false;\n }\n\n private clearRenewTimer(): void {\n if (this.renewTimer !== null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n\n /**\n * Arm the proactive renewal timer from a `ready` message's `expiresAt` (epoch\n * ms). We relaunch a comfortable lead before expiry so the host can mint a fresh\n * session and swap `designerUrl` without the user ever seeing the expiry card:\n *\n * - normal TTL (≥ 15 min): renew {@link RENEW_LEAD_MS} (~3 min) before expiry;\n * - short TTL (< 15 min): renew after {@link RENEW_SHORT_TTL_FRACTION} (80%) of\n * the remaining life, so the lead can't overshoot the whole session;\n * - either way, never sooner than {@link RENEW_MIN_DELAY_MS} (30s) after `ready`\n * so a burst of `ready` messages can't spin the host.\n *\n * Re-armed on every `ready`; cleared on destroy / setDesignerUrl (via re-mount).\n * A no-op when auto-renewal is off or `expiresAt` is missing/already past — the\n * expiry-error path recovers a session that has already lapsed.\n */\n private scheduleRenewal(expiresAt: number | undefined): void {\n this.clearRenewTimer();\n if (!this.autoRenewEnabled()) return;\n if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) return;\n const remaining = expiresAt - Date.now();\n if (remaining <= 0) return;\n const lead =\n remaining < RENEW_SHORT_TTL_MS\n ? remaining * RENEW_SHORT_TTL_FRACTION\n : remaining - RENEW_LEAD_MS;\n const delay = Math.max(RENEW_MIN_DELAY_MS, lead);\n this.renewTimer = setTimeout(() => {\n this.renewTimer = null;\n // Silent renewal: the host mints a fresh session and swaps designerUrl,\n // which re-mounts the iframe and re-arms us from the next `ready`.\n if (this.autoRenewEnabled()) this.options.onRequestRelaunch!();\n }, delay);\n }\n\n private ensureContainerPositioned(container: HTMLElement): void {\n // The overlay is absolutely positioned; the container must establish a\n // positioning context. Only touch a `static` container, and remember to\n // restore it on destroy.\n const position = getComputedStyle(container).position;\n if (position === 'static') {\n this.restoreContainerPosition = container.style.position;\n container.style.position = 'relative';\n }\n }\n\n private restoreContainerStyle(): void {\n if (this.restoreContainerPosition === null) return;\n try {\n resolveContainer(this.options.container).style.position = this.restoreContainerPosition;\n } catch {\n /* container already gone — nothing to restore */\n }\n this.restoreContainerPosition = null;\n }\n\n private removeOverlay(): void {\n this.overlay?.remove();\n this.overlay = null;\n }\n\n private showError(cause: ErrorCause): void {\n this.phase = 'error';\n this.clearTimeoutTimer();\n if (!this.loadingStateEnabled()) return;\n let container: HTMLElement;\n try {\n container = resolveContainer(this.options.container);\n } catch {\n return;\n }\n this.renderOverlay(container, 'error', cause);\n }\n\n private handleTryAgain(): void {\n if (this.options.onRequestRelaunch) {\n // Host mints a fresh session and calls setDesignerUrl(), which re-mounts\n // the iframe and returns to the loading state.\n this.options.onRequestRelaunch();\n return;\n }\n // No relaunch hook: reload the same session URL in place.\n this.mount();\n }\n\n /**\n * Build (or rebuild) the overlay for the given phase. A single overlay element\n * is reused so we never stack stale skeletons or cards.\n */\n private renderOverlay(container: HTMLElement, phase: 'loading' | 'error', cause?: ErrorCause): void {\n this.removeOverlay();\n const overlay = document.createElement('div');\n overlay.setAttribute('data-seatlayer-designer-overlay', phase);\n overlay.setAttribute('role', phase === 'error' ? 'alert' : 'status');\n overlay.setAttribute('aria-live', 'polite');\n Object.assign(overlay.style, {\n position: 'absolute',\n inset: '0',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: '#101625',\n color: '#e6ebf5',\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif',\n zIndex: '2',\n overflow: 'hidden',\n } satisfies Partial<CSSStyleDeclaration>);\n\n if (phase === 'loading') this.buildSkeleton(overlay);\n else this.buildErrorCard(overlay, cause ?? 'load');\n\n container.append(overlay);\n this.overlay = overlay;\n }\n\n private buildSkeleton(overlay: HTMLDivElement): void {\n // Scoped keyframes; the shimmer only runs when the user allows motion.\n // `@sl-css` opts it into build-time minification (cdn/minifyCssLiterals.ts).\n const style = document.createElement('style');\n style.textContent = /* @sl-css */ `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes seatlayer-designer-shimmer {\n 0% { background-position: -320px 0; }\n 100% { background-position: 320px 0; }\n }\n [data-seatlayer-designer-overlay=\"loading\"] .sl-shimmer {\n animation: seatlayer-designer-shimmer 1.25s ease-in-out infinite;\n background-size: 640px 100%;\n }\n}`;\n overlay.append(style);\n\n const shimmer =\n 'linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.10) 37%, rgba(255,255,255,0.04) 63%)';\n\n const scaffold = document.createElement('div');\n Object.assign(scaffold.style, {\n position: 'absolute',\n inset: '0',\n display: 'flex',\n flexDirection: 'column',\n padding: '16px',\n gap: '14px',\n opacity: '0.9',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const bar = (styles: Partial<CSSStyleDeclaration>): HTMLDivElement => {\n const node = document.createElement('div');\n node.className = 'sl-shimmer';\n Object.assign(node.style, {\n background: shimmer,\n borderRadius: '8px',\n } satisfies Partial<CSSStyleDeclaration>);\n Object.assign(node.style, styles);\n return node;\n };\n\n // Top toolbar row.\n scaffold.append(bar({ height: '40px', width: '100%', flex: '0 0 auto' }));\n\n // Body: side panel + canvas.\n const body = document.createElement('div');\n Object.assign(body.style, {\n display: 'flex',\n gap: '14px',\n flex: '1 1 auto',\n minHeight: '0',\n } satisfies Partial<CSSStyleDeclaration>);\n body.append(bar({ width: '220px', height: '100%', flex: '0 0 auto' }));\n body.append(bar({ flex: '1 1 auto', height: '100%' }));\n scaffold.append(body);\n\n overlay.append(scaffold);\n\n // Centered caption above the scaffold.\n const caption = document.createElement('div');\n Object.assign(caption.style, {\n position: 'relative',\n zIndex: '1',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 16px',\n borderRadius: '999px',\n background: 'rgba(16, 22, 37, 0.72)',\n fontSize: '13px',\n fontWeight: '500',\n letterSpacing: '0.01em',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const dot = document.createElement('span');\n dot.className = 'sl-shimmer';\n Object.assign(dot.style, {\n width: '9px',\n height: '9px',\n borderRadius: '50%',\n background: shimmer,\n flex: '0 0 auto',\n } satisfies Partial<CSSStyleDeclaration>);\n caption.append(dot);\n caption.append(document.createTextNode('Loading designer…'));\n overlay.append(caption);\n }\n\n private buildErrorCard(overlay: HTMLDivElement, cause: ErrorCause): void {\n const copy = ERROR_COPY[cause];\n const card = document.createElement('div');\n Object.assign(card.style, {\n maxWidth: '420px',\n margin: '0 24px',\n padding: '28px',\n textAlign: 'center',\n background: 'rgba(255, 255, 255, 0.03)',\n border: '1px solid rgba(255, 255, 255, 0.08)',\n borderRadius: '16px',\n boxShadow: '0 12px 40px rgba(0, 0, 0, 0.35)',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const heading = document.createElement('h2');\n heading.textContent = copy.title;\n Object.assign(heading.style, {\n margin: '0 0 8px',\n fontSize: '17px',\n fontWeight: '600',\n color: '#f4f7ff',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const body = document.createElement('p');\n body.textContent = copy.body;\n Object.assign(body.style, {\n margin: '0 0 20px',\n fontSize: '13.5px',\n lineHeight: '1.5',\n color: '#aab4c8',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = 'Try again';\n Object.assign(button.style, {\n appearance: 'none',\n cursor: 'pointer',\n border: '0',\n borderRadius: '10px',\n padding: '10px 22px',\n fontSize: '14px',\n fontWeight: '600',\n color: '#101625',\n background: '#7aa2ff',\n } satisfies Partial<CSSStyleDeclaration>);\n button.addEventListener('click', () => this.handleTryAgain());\n\n card.append(heading, body, button);\n overlay.append(card);\n }\n\n private handleMessage = (event: MessageEvent<unknown>) => {\n if (!this.frame || event.origin !== this.designerOrigin || event.source !== this.frame.contentWindow) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n\n // Layout protocol — origin-locked like everything else, but handled here\n // rather than dispatched to the host callbacks.\n if (data.type === 'seatlayer.designer.resize') {\n // Fill mode owns the height from the viewport; the reported scrollHeight is\n // circular (the fixed-position shell echoes the iframe height), so ignore\n // it. Only a fixed numeric height honours the legacy auto-grow.\n if (!this.fillEnabled() && this.autoResizeEnabled()\n && typeof data.px === 'number' && Number.isFinite(data.px) && data.px > 0) {\n this.lastAutoHeight = `${Math.round(data.px)}px`;\n // While pinned fullscreen the iframe fills the viewport; apply the\n // reported height only when not pinned (it's re-applied on unpin).\n // `!important` so a host theme's `iframe { height … }` can't win.\n if (!this.pinned) this.setFrameHeight(this.lastAutoHeight);\n }\n return;\n }\n if (data.type === 'seatlayer.designer.fullscreen') {\n if (data.on === true) this.pinFullscreen();\n else if (data.on === false) this.unpinFullscreen();\n return;\n }\n\n if (typeof data.type !== 'string' || !TYPES.has(data.type as EmbeddedDesignerEventType)) return;\n\n const message: EmbeddedDesignerMessage = {\n type: data.type as EmbeddedDesignerEventType,\n chartId: typeof data.chartId === 'string' ? data.chartId : undefined,\n workspaceId: typeof data.workspaceId === 'string' ? data.workspaceId : undefined,\n expiresAt: typeof data.expiresAt === 'number' ? data.expiresAt : undefined,\n code: typeof data.code === 'string' ? data.code : undefined,\n message: typeof data.message === 'string' ? data.message : undefined,\n meta: data.meta,\n fatal: typeof data.fatal === 'boolean' ? data.fatal : undefined,\n action: typeof data.action === 'string' ? data.action : undefined,\n };\n\n // `ready` establishes the session identity, and saved/published/close are\n // runtime-only lifecycle events, so every configured expected id is required\n // on those messages. After an accepted `ready`, errors are strict too. The\n // sole omission exception is a genuinely pre-identity boot error: the iframe\n // can fail before its session response reveals either id. Any id it does send\n // must still match. Resize/fullscreen returned above and deliberately remain\n // identity-free layout protocol messages.\n const identityRequired = this.identityEstablished\n || message.type === 'seatlayer.designer.ready'\n || message.type === 'seatlayer.designer.saved'\n || message.type === 'seatlayer.designer.published'\n || message.type === 'seatlayer.designer.close';\n const chartMismatch = this.options.expectedChartId !== undefined\n && (message.chartId !== this.options.expectedChartId)\n && (identityRequired || message.chartId !== undefined);\n const workspaceMismatch = this.options.expectedWorkspaceId !== undefined\n && (message.workspaceId !== this.options.expectedWorkspaceId)\n && (identityRequired || message.workspaceId !== undefined);\n if (\n chartMismatch || workspaceMismatch\n ) {\n // A message from our exact iframe carrying the wrong identity is a real\n // session mismatch, not spoofing. Surface it (loading state on) rather than\n // dispatching it to the host callbacks.\n this.showError('mismatch');\n return;\n }\n\n switch (message.type) {\n case 'seatlayer.designer.ready':\n this.identityEstablished = true;\n this.sessionExpiresAt = message.expiresAt;\n this.phase = 'ready';\n this.clearTimeoutTimer();\n this.removeOverlay();\n // A fresh live session: clear the recovery guard and (re)arm proactive\n // renewal from this session's expiry.\n this.autoRecoverUsed = false;\n this.scheduleRenewal(message.expiresAt);\n this.options.onReady?.(message);\n break;\n case 'seatlayer.designer.saved': this.options.onSaved?.(message); break;\n case 'seatlayer.designer.published': this.options.onPublished?.(message); break;\n case 'seatlayer.designer.close': this.options.onClose?.(message); break;\n case 'seatlayer.designer.error': {\n const cause = causeFromCode(message.code);\n // Expiry is recoverable. If the host wired a relaunch hook, make ONE\n // silent auto-relaunch before ever showing the dead-end card — the user\n // never sees an overlay. Guarded (reset only on a fresh `ready`) so a\n // session that keeps failing to load falls through to the card instead of\n // looping the host.\n if (cause === 'expired' && this.autoRenewEnabled() && !this.autoRecoverUsed) {\n this.autoRecoverUsed = true;\n this.clearRenewTimer();\n this.options.onRequestRelaunch!();\n return;\n }\n // Only a dead session justifies tearing the editor down. An operation\n // that failed inside a running editor (autosave hitting a transient 5xx,\n // a thumbnail upload) leaves the session and the user's work intact, so\n // it is reported to the host and surfaced by the Designer's own in-editor\n // banner — replacing the canvas with \"We couldn't load the designer\"\n // would be both wrong and destructive. `fatal` is authoritative when the\n // Designer sends it; otherwise we fall back to the phase, which is the\n // same signal (we already had a `ready`).\n const fatal = typeof message.fatal === 'boolean'\n ? message.fatal\n : (cause !== 'load' || this.phase !== 'ready');\n if (fatal) this.showError(cause);\n this.options.onError?.(message);\n break;\n }\n }\n };\n}\n","/**\n * SeatPicker — the full buyer experience as a widget.\n *\n * Where `SeatingChart` is canvas-only, SeatPicker owns the complete chrome\n * from the canonical UX contract: branded header,\n * live price panel, selection tray with GA steppers, hold countdown, snipe\n * toasts and expiry recovery — all on top of the shared PickerController, so\n * every host gets the whole experience with one mount.\n *\n * Render contexts (owner requirement): the SAME widget adapts to a full-screen\n * takeover, an inline <div> in a content page, or a popup — breakpoints key\n * off the CONTAINER via ResizeObserver, never the viewport. `SeatPicker.open()`\n * mounts a document-level modal (scrim, ESC, focus restore) in one call.\n *\n * Theming (owner requirement): org account customization flows automatically —\n * the chart payload's ChartTheme (accent, accentInk, logoUrl, brand name,\n * fontFamily, …) seeds the look; the host `theme` option overrides any subset;\n * and every value lands as a `--sl-*` CSS custom property on the widget root\n * so plain host CSS can restyle too.\n */\nimport {\n PickerController,\n ACCESSIBILITY_TYPES,\n expandChart,\n // generateSeatPanorama is deliberately NOT here — see loadPanorama().\n generateSeatThumb,\n loadLocale,\n setStringOverrides,\n t,\n tCount,\n type AccessibilityType,\n type ChartTheme,\n type PickerMapTheme,\n type ExpandedSeat,\n type LodRung,\n type PanoramaResult,\n type PickerSeat,\n type PickerTransport,\n type RendererViewMode,\n type SeatCommercialAttributes,\n type SeatHoverDetails,\n type SectionSummary,\n type TableSelectionDetails,\n} from '@seatlayer/core';\nimport type { Venue3DHandle, SeatState3D, SeatView as View3DSeatView } from '@seatlayer/core/view3d';\nimport { isAuthoredSeatView, seatViewDisclosure } from '@seatlayer/core/view3d/crossfade/panorama';\nimport { seatConfidenceDisclosure } from '@seatlayer/core/core/seatConfidence';\nimport {\n browserPanoramaConstraints,\n loadPanoramaImage,\n planPanoramaDelivery,\n schedulePanoramaUpgrade,\n} from '@seatlayer/core/view/panoramaDelivery';\nimport {\n PubApi,\n type HoldLineItem,\n type HoldResult,\n type OrderStatusResult,\n type PaymentOptionsReason,\n type PaymentOptionsResult,\n} from './api';\nimport { BuyerAssetObjectUrls } from './buyerAssets';\n// mountCheckout is deliberately NOT imported here — see loadHostedCheckout().\nimport type { CheckoutHandle, CheckoutState } from './hostedCheckout';\nimport {\n createBuyerAccessContext,\n type BuyerAccessContext,\n type BuyerAccessExpiredEvent,\n type BuyerAccessToken,\n type BuyerAccessTokenProvider,\n type BuyerAccessUnavailableEvent,\n type BuyerAccessUnavailableReason,\n type SelectedObjectUnavailableEvent,\n} from './buyerAccess';\nimport { BuyerRealtimeClient, createControllerSink } from './buyerRealtime';\nimport { SEATLAYER_ATTRIBUTION_MARK_SVG } from './seatLayerBrand';\nimport {\n nextOfferTransitionAt,\n parseTicketOfferAvailability,\n ticketOfferPrices,\n type TicketOfferAvailability,\n type TicketOfferPrice,\n} from './offerAvailability';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n/** Show the \"Need more time?\" prompt when the hold has this long (ms) left. */\nconst EXTEND_PROMPT_MS = 60_000;\n/**\n * Default seat ceiling for offering 3D — see the `max3DSeats` option.\n *\n * 15,000 was calibrated when the largest chart we had evidence for was the\n * 14,142-seat arena, so it read as \"a bit above the biggest venue\" rather than\n * as a measured limit. It silently withheld the 3D toggle from Mega Stadium\n * (53,018) — the chart whose entire purpose is to demonstrate 3D at stadium\n * scale — and did so invisibly, because the control is simply never built.\n *\n * 60,000 is grounded in `docs/phase-b-browser-and-53k-evidence-2026-08-04.md`:\n * the 53,018-seat bowl sustains 60fps on orbit and on the fly-to-seat descent\n * at 3 draw calls idle / 4 in flight — the same draw count as the 14k arena,\n * because the seat cloud is one instanced draw and does not scale with venue\n * size.\n *\n * The halving below is deliberately left to bite. That evidence is a desktop\n * GPU only; mobile at this scale is UNMEASURED. A small or low-core device\n * therefore lands at 30,000 and still refuses 3D for a 53k bowl, which is the\n * conservative side of a gap we have not closed. Raise the half only when a\n * phone has actually been measured.\n */\nconst MAX_3D_SEATS_DEFAULT = 60_000;\n/** Most section pills the 3D navigation rail will offer before it stays quiet. */\nconst MAX_3D_SECTION_PILLS = 12;\n\n/** Minimal shape of a section object read off the ChartDoc for the minimap. */\ninterface SectionLike {\n type: string;\n id: string;\n outline?: { x: number; y: number }[];\n color?: string;\n zone?: string;\n}\n\n/** Even-odd point-in-polygon test in world units (minimap click → section). */\nfunction pointInPolygon(x: number, y: number, poly: { x: number; y: number }[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x, yi = poly[i].y, xj = poly[j].x, yj = poly[j].y;\n if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) inside = !inside;\n }\n return inside;\n}\n\n/** One price band in the F4 filter — a set of category keys within a price range. */\ninterface PriceBand {\n id: string;\n label: string;\n keys: string[];\n min: number;\n max: number;\n}\n\n/**\n * Stable checkout-handoff contract (P4). Passed as the THIRD argument to\n * `onCheckout(hold, seats, handoff)` — additive, so the legacy `(hold, seats)`\n * shape used by DesiPass web-v2 (SDK 0.7.3+) is untouched. This is the object to\n * build your order against: it is self-contained (holdId, expiry, currency, and\n * per-line tier + price) and never changes shape across minor releases.\n */\nexport interface CheckoutLineItem {\n /** Seat label (or GA synthetic-unit label) — the stable booking identity. */\n label: string;\n /**\n * Buyer-facing name (the designer's `displayLabel` override), when set.\n * Show this in YOUR order summary; `label` stays the booking identity you\n * pass to the book call. Absent = no override, fall back to `label`.\n */\n displayLabel?: string;\n /**\n * Buyer-facing type word override (seats.io \"Displayed type\", e.g. \"Table\",\n * \"Bench\", \"Box\"), when the designer set one. Absent = the default word.\n */\n displayType?: string;\n /** Chart object id (row/booth/GA area) the unit belongs to. */\n objectId: string;\n objectType: 'seat' | 'booth' | 'ga' | 'table';\n categoryKey: string;\n /** Chosen ticket tier id (Adult/Child/…), or null when the category has no tiers. */\n tierId: string | null;\n /** Unit price in MAJOR currency units (e.g. 45 = 45.00). Server-authoritative. */\n unitPrice: number;\n /** ISO-4217, resolved server-side (per-event override → org → USD). */\n currency: string;\n quantity: number;\n}\n\nexport interface CheckoutHandoff {\n /** Server hold id — pass this to YOUR book call. */\n holdId: string;\n /** Epoch ms the hold expires (after any extensions). */\n expiresAt: number;\n /** ISO-4217 currency for the whole order. */\n currency: string;\n /** Priced line items (tier + unit price + currency), server-authoritative. */\n lineItems: CheckoutLineItem[];\n /** Convenience total in major units (Σ unitPrice × quantity). */\n total: number;\n}\n\n/** Host-authoritative pricing — see {@link SeatPickerOptions.pricing}. */\nexport interface SeatPickerPricing {\n /** Unit prices by category key: a flat number, or `{ base, tiers: { tierId: price } }`. */\n prices?: Record<string, number | { base?: number; tiers?: Record<string, number> }>;\n /** Custom money renderer (e.g. `(n) => n + '€'`). Defaults to Intl currency formatting. */\n formatter?: (amount: number, currency: string) => string;\n}\n\n/** Optional constraints for the server-authoritative best-available pick. */\nexport interface SeatPickerBestAvailableOptions {\n /** Prefer a contiguous premium block, falling back to the best overall block. */\n preferPremium?: boolean;\n /** Restrict the search to one configured chart zone. */\n zoneId?: string;\n}\n\n/** Buyer-facing surface shown by the full picker widget. */\nexport type SeatPickerBuyerView = 'map' | 'venue3d';\n\n/** Optional camera intent when switching the buyer-facing surface. */\nexport interface SeatPickerBuyerViewOptions {\n /** Enter (or remain in) 3D and fly the camera to this seat id. */\n flyToSeatId?: string;\n /** When already in 3D, return the camera to the venue overview. */\n resetView?: boolean;\n}\n\n/** Host theme overrides — any subset; unset keys fall back to the org's chart theme, then defaults. */\nexport interface SeatPickerTheme {\n /** Brand accent (CTA, active chips, hold pill). */\n accent?: string;\n /** Ink on the accent (button labels). */\n accentInk?: string;\n /** Widget background. */\n background?: string;\n /** Panel/card surface color. */\n surface?: string;\n /** Primary text color. */\n text?: string;\n /** Secondary text color. */\n muted?: string;\n /** Hairline/border color. */\n line?: string;\n /** Font stack for all widget chrome. */\n fontFamily?: string;\n /** Corner radius base (px). */\n radius?: number;\n /** Header logo URL (falls back to the org logo from the chart theme, then a monogram). */\n logoUrl?: string;\n /** Brand/event fallback name for the monogram. */\n brandName?: string;\n /**\n * The DRAWN MAP, which the tokens above deliberately do not reach.\n *\n * Everything else on this interface is CSS: it re-inks panels, buttons and\n * the sidebar. The seat map is a canvas, painted from the chart document's\n * own `ChartTheme`, so a host could re-ink the whole widget and still be\n * looking at somebody else's dark venue in the middle of it (which is exactly\n * what SeatLayer's own light event-page palettes did, found 2026-08-07).\n *\n * Nested rather than flattened because `background` already means the\n * WIDGET's background here and the canvas ground is a different surface —\n * two things one word cannot carry.\n *\n * Set it only when you can vouch for the result: these colours are drawn\n * behind and beside live seat statuses (held, sold, selected), and the map is\n * the one part of this widget a buyer has to be able to read.\n */\n map?: PickerMapTheme;\n}\n\nexport interface SeatPickerOptions {\n /** CSS selector or element to mount into. Omit when using SeatPicker.open(). */\n container?: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /**\n * Custom data transport. Defaults to the CORS-trivial PubApi against\n * `apiBase`. Inject to run the widget against another backend adapter (the\n * SeatLayer dashboard's own transport) or a fully local mock (demos).\n */\n transport?: PickerTransport;\n /** Reserved for future authenticated rendering. NOT the channel-access\n * credential — a buyer access session is a different thing with different\n * authority, and uses the two options below. */\n publicKey?: string;\n /**\n * Buyer access session provider — the recommended way to show private channel\n * inventory (Sales Channels guide §6).\n *\n * Called with a `reason` whenever the widget needs a bearer: first\n * acquisition, a near/actual expiry, a 401 `buyer_access_expired`, a realtime\n * reconnect, or `refreshAccess()`. It should POST to YOUR backend, which\n * mints the session with your secret key and returns `{ token, expiresAt }`.\n *\n * The token lives in memory for the widget's lifetime and nowhere else: never\n * in storage, never in a URL, never in a log or an error message. Refresh\n * returns the same or a narrower scope; the widget never widens to Public\n * sale on its own, and a failed refresh stops the scoped operation rather\n * than retrying it anonymously. Any held seats stay held — a hold is\n * relinquished by its own opaque capability, not by channel access, so\n * losing access never strands inventory (guide §9).\n *\n * Ignored when a custom `transport` is supplied: that host owns its own\n * credentials.\n */\n buyerAccessTokenProvider?: BuyerAccessTokenProvider;\n /**\n * One-shot escape hatch for hosts that already own the session lifecycle.\n * Cannot be renewed — when it lapses the widget reports `onAccessExpired`\n * and then `onAccessUnavailable`. Prefer `buyerAccessTokenProvider`.\n */\n buyerAccessToken?: string | BuyerAccessToken;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** BCP 47 language for the widget UI. Built-in: en, es, de, fr. */\n locale?: string;\n /** Per-key string overrides layered over the active locale. */\n messages?: Record<string, string>;\n /** ISO 4217 currency fallback (the org/event currency on the chart wins). */\n currency?: string;\n /** Colorblind-safe rendering (Okabe-Ito palette, hollow booked seats). */\n colorblindSafe?: boolean;\n /** Initial map projection. Buyers now toggle **Map (flat 2D) + 3D** only; the\n * legacy `perspective` (2.5D) value is still ACCEPTED for source compatibility\n * but is deprecated — it is coerced to `flat` with a one-time console warning.\n * The 3D venue view is entered from the Map/3D control, not this option. */\n initialView?: RendererViewMode;\n /**\n * Offer the interactive 3D venue view (Map | 3D toggle + a \"See it in 3D\"\n * action on the seat-confirm card). Default true. The 3D button is shown only\n * when this is not false AND the browser exposes WebGL2; there are ZERO GL\n * bytes on the wire until the buyer actually opens 3D (the OGL chunk is\n * dynamically imported on first use). Set false for embed hosts that must\n * stay strictly 2D. */\n enable3D?: boolean;\n /**\n * Seat-count ceiling above which 3D is not offered. Default: 60,000 seats on\n * desktop, reduced to 30,000 on a device that reports itself as small/low-core.\n *\n * The 53,018-seat evidence is desktop-only; that scale remains unmeasured on\n * phones, which is why the small-device default stays conservative. The 3D\n * scene holds every seat resident until a streaming rung exists. */\n max3DSeats?: number;\n /**\n * Fires when the buyer enters/leaves 3D or targets a seat there. Hosts can\n * mirror this small, non-sensitive state into a shareable URL.\n */\n onBuyerViewChange?: (state: { view: SeatPickerBuyerView; seatId?: string }) => void;\n /**\n * Optional analytics sink for the widget's own journey events. Currently emits\n * the 3D venue-view journey (`3d_opened`, `3d_orbit_engaged`, `3d_seat_picked`,\n * `3d_cinematic_played`/`_skipped`/`_cancelled`, panorama outcomes, and WebGL\n * context loss/recovery)\n * with `{ surface: 'buyer' }` merged into the props. A throwing sink never\n * breaks the widget. Route it to your product analytics (e.g. PostHog). */\n onAnalytics?: (event: string, props: Record<string, unknown>) => void;\n /**\n * Hide the \"Powered by SeatLayer\" attribution badge in the side panel foot.\n * The chart theme's own `hideBadge` flag (paid orgs) also hides it — the badge\n * is shown only when BOTH this option and the theme flag are unset/false.\n */\n hideBadge?: boolean;\n /**\n * Hide the picker's event identity (logo, event name and venue/date metadata)\n * when the host surface already presents the same event heading. The hold\n * timer, sales status and modal close controls remain available. The identity\n * is restored automatically while the picker is full screen so it never\n * loses context on a small device or an expanded map. Default false.\n *\n * A mounted host can update this through `setEventDetailsHidden()` when its\n * own event chrome arrives asynchronously.\n */\n hideEventDetails?: boolean;\n /**\n * Start the wide-layout ticket panel collapsed so the map owns the full\n * width (map-first hosts, small embeds). The buyer reopens it with the\n * \"Tickets\" pill beside Map|3D, and it opens itself the moment a seat lands\n * in the cart — a collapsed panel must never hide a checkout. Narrow\n * layouts ignore this (the bottom sheet is already the collapse). A mounted\n * host can drive it later through `setPanelCollapsed()`. Default false.\n */\n panelCollapsed?: boolean;\n /** Host theme overrides — see SeatPickerTheme. */\n theme?: SeatPickerTheme;\n /**\n * Host-authoritative pricing. When your shop charges different prices than\n * the chart's stored category prices, pass them here so the buyer sees the\n * price they will actually pay — on the map tooltip, confirm popover, price\n * panel, tray, totals, and in the checkout handoff's line items. Keyed by\n * category key; per-tier overrides nest under `tiers`. Unlisted categories\n * fall back to the chart price.\n */\n pricing?: SeatPickerPricing;\n /**\n * Fires when the server-resolved active offer changes. Hosted event pages use\n * this to keep their headline, sticky bar and the canonical picker on the\n * same live fact. The picker remains fully functional when it is omitted.\n */\n onOfferAvailabilityChange?: (availability: TicketOfferAvailability | null) => void;\n /** Hold TTL in ms passed to hold(); server clamps to its own limits. */\n holdTtlMs?: number;\n /**\n * An opaque hold id supplied by the host to restore after navigation. It is\n * verified against the event and active server state before anything renders\n * as owned by this buyer.\n */\n initialHoldId?: string;\n /**\n * Automatically remember the active hold id in sessionStorage and restore it\n * when this event's picker mounts again. Default true. Set false when the host\n * owns hold persistence and supplies initialHoldId itself.\n */\n restoreHold?: boolean;\n /**\n * Render the real chart and live seat statuses without allowing selection,\n * holds or checkout. This is for venue previews and pre-sale Website pages;\n * it is enforced by the widget even if the event later opens while mounted.\n * Default false.\n */\n readOnly?: boolean;\n /**\n * Confirm mode: tapping a seat shows a confirmation card with section, row,\n * seat, category, price and Select/Cancel before it enters the tray. Default\n * true for the full buyer picker; set false only when the host supplies its\n * own equivalent confirmation UI.\n */\n confirmSelection?: boolean;\n /**\n * Offer a \"View from seat\" 360° preview (confirm popover + tray chips). The\n * panorama is generated from the chart geometry, or the organizer's uploaded\n * photo when a seat carries one. Default true; set false to hide the affordance.\n */\n seatView?: boolean;\n /**\n * WHERE the buyer goes once their seats are held. Default `'handoff'`.\n *\n * 'handoff' (default, and every integration that has ever existed) the\n * widget fires {@link onCheckout} with a holdId and priced line\n * items, and YOUR server takes the money. Nothing about this path\n * changes, and no payment code is even downloaded.\n * 'hosted' the widget takes the money through the gateway the ORGANIZER\n * connected, on their account — the \"sell tickets with no\n * backend\" path. Requires the org to be on hosted checkout and\n * the event to have a gateway assigned; when it does not, this\n * falls back to `'handoff'` for that buyer rather than dead-ending\n * them, and reports why through {@link onCheckoutUnavailable}.\n *\n * Named for the destination rather than as a boolean flag because there is a\n * real third answer coming and `hostedCheckout: true` would have no room for\n * it; spelling the default out also makes a host's intent legible in their own\n * source instead of hiding it in an absent option.\n *\n * TWO THINGS ARE WORTH KNOWING BEFORE YOU SWITCH THIS ON:\n *\n * 1. It needs the widget's own transport. A host-supplied `transport` owns its\n * credentials and its backend, so hosted checkout stays off there (with one\n * console warning) rather than reaching past it to api.seatlayer.io.\n * 2. WHERE A HOSTED GATEWAY RETURNS THE BUYER is settled by {@link returnUrl}\n * and by the organizer. Without one — or from an origin the organizer has\n * not declared — the buyer comes back to SeatLayer's own buyer page and is\n * confirmed THERE, not in this widget. Declare the embedding site under\n * Embed domains in the dashboard and pass `returnUrl`, and the buyer\n * returns to your page instead. In-page gateways never navigate away at\n * all, so they are unaffected either way.\n */\n checkout?: 'handoff' | 'hosted';\n /**\n * Where a redirecting gateway should send the buyer back to, for\n * `checkout: 'hosted'`.\n *\n * The server keeps this URL verbatim — path and query included — and only\n * stamps `?order=…&status=success|cancelled` onto it, so point it at\n * whichever of YOUR pages should confirm the purchase (often just\n * `window.location.href`). Mount a picker on that page and it resumes in\n * place from those parameters.\n *\n * It is validated, not trusted: the organizer declares their embed origins\n * in the dashboard, and an undeclared origin is ignored rather than\n * refused — the sale still completes, the buyer just finishes on\n * SeatLayer's page. Supplying a URL therefore cannot authorize it, which is\n * what stops a copied snippet from redirecting a paid buyer anywhere it\n * likes.\n */\n returnUrl?: string;\n /**\n * Buyer pressed the CTA and the hold succeeded — hand off to YOUR checkout.\n * `hold` and `seats` are the legacy args (unchanged since 0.6). `handoff` (P4)\n * is the stable, self-contained {@link CheckoutHandoff} to build your order\n * against — holdId, expiry, currency and priced line items. Prefer it.\n *\n * Under `checkout: 'hosted'` this fires ONLY when hosted checkout cannot run\n * for this event, so a host can keep one code path for both. It never fires\n * alongside a payment the widget is taking itself.\n */\n onCheckout?: (hold: HoldResult, seats: PickerSeat[], handoff: CheckoutHandoff) => void;\n /**\n * `checkout: 'hosted'` was asked for and this event cannot take money.\n * The seats ARE held — the buyer is mid-journey — so this is a routing\n * decision, not an error, and it is never collapsed into {@link onError}.\n *\n * `reason` carries the server's three-way answer verbatim, because two of the\n * three give opposite advice: `payments_off_for_event` means the organizer\n * deliberately does not sell this event online (nothing is wrong), while\n * `unavailable_for_event` means they switched it on and it is broken. Anything\n * unreadable — a failed lookup, an older worker — reads as `not_configured`,\n * which asserts the least about them.\n *\n * `onCheckout` fires immediately after this with the same hold. Supply either\n * (or both) and you own the next screen; supply NEITHER and the widget shows\n * the buyer an honest card of its own rather than swallowing the press.\n */\n onCheckoutUnavailable?: (event: {\n reason: PaymentOptionsReason;\n handoff: CheckoutHandoff;\n }) => void;\n /**\n * `checkout: 'hosted'` only — the gateway's webhook landed and the order is\n * PAID. The one signal a host with no backend actually needs, and the only\n * place a receipt can come from on a page that has no server of its own.\n *\n * Distinct from {@link onBooked}, which reports the same sale seen from the\n * seat map over the realtime channel and cannot fire at all for a buyer whose\n * widget was torn down by a redirect to the gateway.\n */\n onOrderConfirmed?: (order: OrderStatusResult) => void;\n /**\n * The held seats were BOOKED (P4) — your server completed payment and the\n * booking landed over the realtime channel while the widget was still open.\n * The widget shows a success state; use this to advance your own UI (receipt,\n * redirect). Fires once per hold.\n */\n onBooked?: (handoff: CheckoutHandoff) => void;\n /** Selection changed (tap or best-available). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /**\n * Active hold changed because it was created, restored, extended, partially\n * released, or fully released. Hosts should persist this state for route\n * navigation and clear their checkout cart when `hold` becomes null.\n */\n onHoldChange?: (hold: HoldResult | null, seats: PickerSeat[], handoff: CheckoutHandoff | null) => void;\n /** The open hold expired server-side (widget already reset itself). */\n onHoldExpired?: () => void;\n /** A prior active hold was verified and restored into the tray. */\n onHoldRestored?: (hold: HoldResult, seats: PickerSeat[], handoff: CheckoutHandoff) => void;\n /** Modal only: the buyer closed the picker (ESC / scrim / ✕). */\n onClose?: () => void;\n /**\n * The buyer access session lapsed. `refreshed` says whether the provider\n * already recovered it — false means private inventory is now unavailable and\n * `onAccessUnavailable` follows. Never collapsed into `onError`: an expiry is\n * a recoverable, buyer-explainable state, not a network failure (guide §10).\n */\n onAccessExpired?: (event: BuyerAccessExpiredEvent) => void;\n /**\n * Private inventory is unavailable and refreshing will not fix it — revoked,\n * paused, wrong origin/event/mode, or the provider failed. Carries a reason,\n * never a channel name, id, colour or count. The widget shows its own\n * explanatory panel; return nothing to keep it, or handle the state yourself.\n */\n onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;\n /**\n * Selected-but-unheld units stopped being selectable — someone else took\n * them, or an allocation change moved them out of this buyer's scope. The\n * widget has already dropped them from the tray.\n */\n onSelectedObjectUnavailable?: (event: SelectedObjectUnavailableEvent) => void;\n onError?: (err: unknown) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nfunction escapeOption(value: unknown): string {\n return String(value ?? '').replace(/[&<>\"']/g, (character) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;',\n })[character]!);\n}\n\n// ---- 3D venue view: lazy loader + capability probe -------------------------\n\n/** The full module type for the lazy OGL venue-view chunk (`@seatlayer/core/view3d`). */\ntype Venue3DModule = typeof import('@seatlayer/core/view3d');\n\n/**\n * Injected `true` only in the CDN/IIFE build (see cdn/vite.config.ts `define`).\n * Undefined in the npm/tsup build and the vendored app copy, so the runtime-URL\n * branch below is never taken there and esbuild dead-code-eliminates it in the\n * CDN build once the constant folds to `true`.\n */\ndeclare const __SEATLAYER_CDN__: boolean | undefined;\n\n/**\n * This bundle's own URL, used only in the CDN build to locate its sibling lazy\n * chunks (`./seatlayer-view3d.mjs`, `./seatlayer-panorama.mjs`).\n * `import.meta.url` resolves to the module URL in\n * the ESM CDN output (`…/seatlayer.mjs`), and Rollup auto-shims it to a\n * `document.currentScript.src` expression in the IIFE output (`…/seatlayer.js`),\n * so both CDN formats find the chunk next to them. Guarded so no environment\n * that lacks `import.meta` throws at module init.\n */\nconst SEATLAYER_MODULE_URL: string | undefined = (() => {\n // IIFE/classic-script (CDN seatlayer.js): the tag sets document.currentScript\n // synchronously while this module's top level runs. Resolve from it first —\n // the IIFE build folds `import.meta` to `{}`, so import.meta.url is unusable\n // there anyway.\n if (typeof document !== 'undefined'\n && document.currentScript instanceof HTMLScriptElement\n && document.currentScript.src) {\n return document.currentScript.src;\n }\n // ESM (CDN seatlayer.mjs / bundlers): import.meta.url is the module URL.\n try {\n const u = import.meta.url;\n if (typeof u === 'string' && u) return u;\n } catch {\n /* no import.meta in this environment */\n }\n return undefined;\n})();\n\nlet _webgl2Cache: boolean | null = null;\n/** Whether the browser exposes WebGL2 (cached). Gates the 3D affordances. */\nfunction hasWebGL2(): boolean {\n if (_webgl2Cache !== null) return _webgl2Cache;\n try {\n if (typeof document === 'undefined') return (_webgl2Cache = false);\n const canvas = document.createElement('canvas');\n _webgl2Cache = !!canvas.getContext('webgl2');\n } catch {\n _webgl2Cache = false;\n }\n return _webgl2Cache;\n}\n\n/** Absolute URL of a sibling lazy chunk in this bundle's pinned CDN directory. */\nfunction cdnChunkUrl(fileName: string): string {\n const base = SEATLAYER_MODULE_URL ?? (typeof location !== 'undefined' ? location.href : undefined);\n if (!base) throw new Error(`seatlayer: cannot resolve the ${fileName} chunk URL`);\n return new URL(`./${fileName}`, base).href;\n}\n\n/**\n * Dynamically load the view3d module. Two build targets, one source:\n * - CDN/IIFE (cannot code-split): load the sibling ESM asset by absolute URL\n * derived from this script's own src.\n * - npm/ESM and the vendored app copy (rewritten to `../../view3d`): a bare\n * dynamic import the consumer's bundler chunk-splits automatically.\n * Either way, ZERO GL bytes are fetched until this actually runs.\n */\nasync function loadVenue3d(): Promise<Venue3DModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-view3d.mjs')) as Promise<Venue3DModule>;\n }\n return import('@seatlayer/core/view3d');\n}\n\n/** Just the generator, so the type does not drag the rest of the engine in. */\ntype PanoramaModule = Pick<typeof import('@seatlayer/core'), 'generateSeatPanorama'>;\n\n/**\n * Dynamically load the view-from-seat panorama generator, on exactly the same\n * pattern as {@link loadVenue3d}. It is ~25 KB of drawing code that runs only\n * when a buyer asks to see the view from a seat, so it stays out of the bytes\n * every buyer downloads to look at a seat map.\n *\n * Its own chunk rather than a fold into the 3D one: the 2D \"View from here\"\n * button does not enter 3D, so folding would make that tap pull the whole OGL\n * scene — 74 KB gzipped, unrunnable without WebGL2 — to draw a 2D canvas.\n *\n * On npm and in the vendored app copy this is a dynamic import of a module the\n * widget ALREADY imports statically, so every bundler resolves it out of the\n * chunk that is loaded anyway: same bytes, same behaviour, no extra request.\n */\nasync function loadPanorama(): Promise<PanoramaModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-panorama.mjs')) as Promise<PanoramaModule>;\n }\n return import('@seatlayer/core');\n}\n\n/** Just the mount function, so the type does not drag the module's DOM in. */\ntype HostedCheckoutModule = Pick<typeof import('./hostedCheckout'), 'mountCheckout'>;\n\n/**\n * Dynamically load the hosted-checkout card, on the same pattern as\n * {@link loadVenue3d} and {@link loadPanorama}, and for a stronger reason than\n * either: this is payment UI, and the overwhelming majority of buyers who load\n * a seat map never reach it. Most integrations never enable it at all —\n * `checkout` defaults to `'handoff'`, where these bytes are unreachable code.\n *\n * So there are ZERO payment bytes on the wire until a buyer presses the CTA in\n * a picker whose host opted into `checkout: 'hosted'`. Unlike the panorama\n * chunk, `./hostedCheckout` is NOT imported statically anywhere, so on npm this\n * is a genuine code split rather than a free reference into a module that was\n * loading anyway — which is exactly what we want here.\n */\nasync function loadHostedCheckout(): Promise<HostedCheckoutModule> {\n if (typeof __SEATLAYER_CDN__ !== 'undefined' && __SEATLAYER_CDN__) {\n return import(/* @vite-ignore */ cdnChunkUrl('seatlayer-checkout.mjs')) as Promise<HostedCheckoutModule>;\n }\n return import('./hostedCheckout');\n}\n\n/**\n * Read the wire's reason, failing to the least-accusing one.\n *\n * Anything unrecognised — a failed read, an older worker that sent nothing, a\n * newer one naming a reason this build has never heard of — becomes\n * `not_configured`, which asserts the least about the organizer. A story\n * invented from a missing field is worse than the coarse truth.\n */\nexport function paymentsOffReason(reason: string | null | undefined): PaymentOptionsReason {\n return reason === 'unavailable_for_event' || reason === 'payments_off_for_event'\n ? reason\n : 'not_configured';\n}\n\n/**\n * Widget stylesheet — injected once per document. Every color/font/radius is a\n * --sl-* token.\n *\n * The `@sl-css` marker opts this literal into build-time CSS minification (see\n * cdn/minifyCssLiterals.ts). Keep writing it long-hand and commented: the CDN\n * build strips the comments and the indentation, the source keeps them.\n */\nconst STYLE_ID = 'seatlayer-picker-style';\nconst CSS = /* @sl-css */ `\n.sl-picker{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:420px;overflow:hidden;\n background:var(--sl-bg);color:var(--sl-text);font-family:var(--sl-font);border-radius:var(--sl-radius);\n --sl-r-sm:calc(var(--sl-radius) * .55);\n /* Motion tokens, defined ON the widget root so an embed is self-contained and\n never inherits (or fights) the host page's own timing. Values mirror\n docs/motion-system-2026-08-01.md §2. */\n --slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;\n --slm-mo-out:cubic-bezier(0.2,0.8,0.2,1);--slm-mo-exit:cubic-bezier(0.4,0,1,1);\n /* Semantic palette tokens, defined here (not resolveTokens) because they are\n the WIDGET's meanings, not an org's brand: premium gold, environment\n warning, danger, success. Hosts can still override them with CSS. */\n --sl-premium:#e8c15a;--sl-premium-deep:#c9a24b;--sl-premium-ink:#1c1608;\n --sl-warn:#d8a425;--sl-danger:#e5484d;--sl-success:#22a06b}\n.sl-picker *{box-sizing:border-box;margin:0;padding:0}\n.sl-picker button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}\n\n/* header */\n.sl-head{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--sl-line);flex:none}\n.sl-logo{width:34px;height:34px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:800;font-size:15px;overflow:hidden}\n.sl-logo img{width:100%;height:100%;object-fit:cover;display:block}\n.sl-head-info{min-width:0;flex:1}\n.sl-head-name{font-weight:700;font-size:15px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-head-meta{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);margin-top:3px;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-hold-pill{display:none;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;flex:none;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:700;font-size:12px;font-variant-numeric:tabular-nums;\n transform-origin:right center}\n.sl-hold-pill.on{display:inline-flex;animation:slPillIn .34s cubic-bezier(.2,.8,.2,1) both}\n.sl-hold-dot{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.78;box-shadow:0 0 0 0 currentColor}\n.sl-hold-pill.is-expiring .sl-hold-dot{animation:slHoldPulse 1.4s ease-out infinite}\n.sl-hold-time{min-width:3.35em;text-align:left}\n.sl-close{width:32px;height:32px;border-radius:999px;flex:none;display:none;align-items:center;justify-content:center;\n border:1px solid var(--sl-line);color:var(--sl-muted);transition:color .15s,border-color .15s}\n.sl-close:hover{color:var(--sl-text);border-color:var(--sl-muted)}\n.sl-close.on{display:inline-flex}\n.sl-close svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}\n\n/* A page or popup may already own the event heading — but \"already\" is true at\n load and false thirty seconds later: the buyer scrolls, the sheet opens over\n the map, fullscreen removes the page, and two-tab comparison shopping is\n normal ticket behaviour. So identity DEMOTES instead of disappearing: one\n compact line (thumb + name) that answers \"which event is this money for\"\n without competing with the host's own heading. The hold clock keeps a\n labelled row around it instead of floating in a dark corner. */\n.sl-picker[data-event-details-hidden=\"true\"] .sl-head{padding-block:7px}\n.sl-picker[data-event-details-hidden=\"true\"] .sl-logo{width:22px;height:22px;border-radius:6px;font-size:11px}\n.sl-picker[data-event-details-hidden=\"true\"] .sl-head-name{font-size:12.5px}\n.sl-picker[data-event-details-hidden=\"true\"] .sl-head-meta{display:none}\n\n/* body */\n.sl-body{display:flex;flex:1;min-height:0}\n.sl-map{position:relative;flex:1;min-width:0}\n.sl-map-host{position:absolute;inset:0}\n.sl-side{width:300px;flex:none;border-left:1px solid var(--sl-line);display:flex;flex-direction:column;min-height:0;overflow:hidden}\n/* Wide-layout panel collapse: THE CHART IS THE PRODUCT, and a fixed 300px\n panel holding an empty cart is the map's room spent on nothing. The panel\n slides to zero (children keep their laid-out width so text doesn't rewrap\n mid-slide); the \"Tickets\" pill in the top-right region brings it back, and\n the first seat landing in the cart reopens it automatically — a collapsed\n panel must never hide a checkout. */\n.sl-picker[data-layout=\"wide\"] .sl-side{transition:width var(--slm-mo-slow) var(--slm-mo-out)}\n.sl-picker[data-layout=\"wide\"][data-side-collapsed=\"true\"] .sl-side{width:0;min-width:0;border-left-width:0}\n/* min-width:0 above is load-bearing: the panel is a flex item, and its\n automatic minimum size (from these 300px-wide children) would otherwise\n clamp the explicit width:0 straight back to 300 — verified in-browser. */\n.sl-picker[data-layout=\"wide\"][data-side-collapsed=\"true\"] .sl-side>*{min-width:300px}\n.sl-side-toggle{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:36px;padding:0 12px;\n border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.02em;white-space:nowrap;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}\n.sl-side-toggle:hover{border-color:var(--sl-muted)}\n.sl-side-toggle svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-picker[data-layout=\"narrow\"] .sl-side-toggle{display:none}\n\n/* narrow (container < 640px): map-first — the map claims ~80-85% of the\n container and the side panel becomes a PEEKING bottom sheet (AXS/Ticketmaster\n mobile pattern). data-sheet on the root: \"peek\" (default: grab handle + one\n summary line) / \"open\" (room for rows + checkout, swipe up to open).\n Swipe handling lives on the sheet head ONLY — never the map host, so the\n map's raw-pointer gesture pipeline is untouched. */\n.sl-picker[data-layout=\"narrow\"] .sl-body{flex-direction:column}\n.sl-picker[data-layout=\"narrow\"] .sl-map{min-height:0;flex:1}\n.sl-picker[data-layout=\"narrow\"] .sl-side{width:100%;border-left:0;border-top:1px solid var(--sl-line);\n flex:none;height:min(72%,480px);overflow:hidden;transition:height .3s cubic-bezier(.2,.8,.2,1);overscroll-behavior:contain}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"][data-has-selection=\"false\"] .sl-side{height:min(252px,52%)}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-side{height:76px;overflow:hidden}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-side > :not(.sl-sheet-head){display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-tray{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}\n.sl-picker[data-layout=\"narrow\"] .sl-foot{position:static;background:var(--sl-bg)}\n.sl-picker[data-layout=\"narrow\"] .sl-foot.empty{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-sheet-head{order:0}\n.sl-picker[data-layout=\"narrow\"] .sl-seats-sec{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-tray{order:2}\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec{order:3}\n.sl-picker[data-layout=\"narrow\"] .sl-filters{order:4}\n.sl-picker[data-layout=\"narrow\"] .sl-prices-sec{order:5}\n.sl-picker[data-layout=\"narrow\"] .sl-pricef{order:6}\n.sl-picker[data-layout=\"narrow\"] .sl-prices{order:7}\n.sl-picker[data-layout=\"narrow\"] .sl-foot{order:8}\n.sl-picker[data-layout=\"narrow\"] .sl-tray-hint,\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec,\n.sl-picker[data-layout=\"narrow\"] .sl-filters,\n.sl-picker[data-layout=\"narrow\"] .sl-prices-sec,\n.sl-picker[data-layout=\"narrow\"] .sl-prices{display:none!important}\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filtersec,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filters,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-prices-sec{display:none}\n/* Reclaim the bottom sheet once the cart has anything: the \"Find best seats\"\n panel collapses too. EXCEPT the confirm (\"Replace your current choices?\") and\n in-flight busy states, which legitimately show with a non-empty cart — those\n set data-ba-active=\"true\" (see setAttribute alongside data-has-selection). */\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"]:not([data-ba-active=\"true\"]) .sl-ba{display:none}\n/* touch chrome: pinch-zoom exists — hide +/− on the sheet layout (keep fit) */\n.sl-picker[data-layout=\"narrow\"] .sl-zoom [data-ref=\"zin\"],\n.sl-picker[data-layout=\"narrow\"] .sl-zoom [data-ref=\"zout\"]{display:none}\n\n/* bottom-sheet head: grab handle + one-line summary (narrow only). The WHOLE\n head is the tap/swipe toggle target (min 44px), so it reads as one control. */\n.sl-sheet-head{display:none;flex-direction:column;justify-content:center;padding:6px 12px 8px;min-height:56px;\n cursor:pointer;touch-action:none;user-select:none;-webkit-user-select:none;flex:none}\n.sl-picker[data-layout=\"narrow\"] .sl-sheet-head{display:flex;min-height:64px;padding:4px 10px 6px}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"peek\"] .sl-sheet-head{height:100%}\n.sl-sheet-grab{width:36px;height:4px;border-radius:999px;background:var(--sl-muted);opacity:.55;margin:1px auto 5px}\n.sl-sheet-bar{display:flex;align-items:center;gap:8px;min-height:44px}\n.sl-sheet-peek{display:flex;align-items:center;gap:7px;flex:1;min-width:0;font-size:13px;font-weight:700;color:var(--sl-text);\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-sheet-peek .sub{color:var(--sl-muted);font-weight:600}\n/* collapsed-peek \"Continue\" affordance: a real accent pill, not plain text */\n.sl-sheet-peek .go{margin-left:auto;flex:none;display:inline-flex;align-items:center;min-height:30px;\n padding:6px 13px;border-radius:999px;background:var(--sl-accent);color:var(--sl-accent-ink);\n font-weight:800;font-size:12.5px}\n/* state chevron: points UP while peeking, rotates to point DOWN when open.\n Base keeps an explicit rotate(0) — transitioning to/from a bare 'none' leaves\n the value stuck in some engines, so both endpoints must be real transforms. */\n.sl-sheet-toggle{width:44px;height:44px;margin:-8px -8px -8px 0;border-radius:999px;flex:none;display:flex;\n align-items:center;justify-content:center;color:var(--sl-muted);transition:color .15s,background .15s}\n.sl-sheet-toggle:hover,.sl-sheet-toggle:focus-visible{color:var(--sl-text);background:color-mix(in srgb,var(--sl-line) 44%,transparent)}\n.sl-sheet-toggle svg{width:21px;height:21px;stroke:currentColor;stroke-width:2.4;fill:none;\n stroke-linecap:round;stroke-linejoin:round}\n.sl-sheet-toggle svg{transform:rotate(0deg);transition:transform .24s cubic-bezier(.2,.8,.2,1)}\n.sl-picker[data-sheet=\"open\"] .sl-sheet-toggle svg{transform:rotate(180deg)}\n\n/* consolidated Filters row inside the sheet (a11y chips + colorblind toggle\n dock here on narrow; they live on the map / zoom column on wide) */\n.sl-filtersec{display:none}\n.sl-filters{display:none;gap:6px;flex-wrap:wrap;align-items:center;padding:2px 16px 10px}\n.sl-picker[data-layout=\"narrow\"] .sl-filtersec.has,\n.sl-picker[data-layout=\"narrow\"] .sl-filters.has{display:none}\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filtersec.has,\n.sl-picker[data-layout=\"narrow\"][data-has-selection=\"true\"] .sl-filters.has{display:none}\n/* Accessibility and colour-safety controls must remain reachable on phones.\n Keep them out of the collapsed peek, then reveal their consolidated row whenever\n the buyer explicitly opens the ticket panel. */\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-filtersec.has{display:block!important}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-filters.has{display:flex!important}\n/* The price list is the mobile buyer's ONLY legend — colour → ticket type →\n price → how many are left. Hiding it in the peek state is right (map-first);\n never restoring it forced phone buyers to tap dots to learn prices. The OPEN\n sheet brings it back, exactly like the filters row above. The tray hint comes\n back with it: the first-time buyer on a phone needs the instruction more than\n the desktop buyer, not less. */\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-prices-sec{display:flex!important}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-prices{display:flex!important}\n.sl-picker[data-layout=\"narrow\"][data-sheet=\"open\"] .sl-tray-hint{display:block!important}\n.sl-cbbtn{width:32px;height:32px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-cbbtn:hover{border-color:var(--sl-muted)}\n.sl-cbbtn svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* price panel — one compact filter control replaces the wrapping price-chip row. */\n.sl-offer{display:none;margin:12px 14px 2px;padding:12px;border:1px solid color-mix(in srgb,var(--sl-accent) 34%,var(--sl-line));\n border-radius:12px;background:color-mix(in srgb,var(--sl-accent) 8%,var(--sl-surface));color:var(--sl-text)}\n.sl-offer.has{display:block}.sl-offer-main{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}\n.sl-offer-copy{min-width:0}.sl-offer-kicker{display:block;font-size:10px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-accent)}\n.sl-offer-name{display:block;margin-top:2px;font-size:13px;font-weight:800;line-height:1.3}.sl-offer-line{display:block;margin-top:3px;font-size:11px;line-height:1.35;color:var(--sl-muted)}\n.sl-offer-info{position:relative;flex:none}.sl-offer-info>summary{list-style:none;width:25px;height:25px;border:1px solid var(--sl-line);border-radius:999px;\n display:grid;place-items:center;cursor:pointer;font-size:12px;font-weight:850;color:var(--sl-text);background:var(--sl-surface)}\n.sl-offer-info>summary::-webkit-details-marker{display:none}.sl-offer-info[open]>summary{border-color:var(--sl-accent);color:var(--sl-accent)}\n.sl-offer-detail{margin-top:10px;padding-top:9px;border-top:1px solid var(--sl-line);font-size:10.5px;line-height:1.45;color:var(--sl-muted)}\n.sl-sec{padding:14px 14px 4px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}\n.sl-prices-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}\n.sl-price-select{min-height:32px;max-width:130px;padding:5px 28px 5px 9px;border:1px solid var(--sl-line);border-radius:9px;\n background:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}\n.sl-prices{display:flex;flex-direction:column;padding:4px 14px 8px;border-bottom:1px solid var(--sl-line)}\n.sl-prices-sec,.sl-prices,.sl-seats-sec{flex:none}\n.sl-price-row{display:flex;align-items:center;gap:7px;min-height:28px;font-size:12px;\n padding:0 6px;margin:0 -6px;border-radius:8px;cursor:pointer;transition:background .15s}\n.sl-price-row:hover,.sl-price-row:focus-visible{background:color-mix(in srgb,var(--sl-line) 40%,transparent)}\n.sl-price-row.sl-active{background:color-mix(in srgb,var(--sl-accent) 9%,transparent)}\n.sl-price-was{margin-left:auto;color:var(--sl-muted);font-size:10px;text-decoration:line-through}.sl-price-offer{display:block;color:var(--sl-accent);font-size:10px;font-weight:750}\n.sl-price-row.sl-active .sl-price-label{color:var(--sl-accent)}\n.sl-dot{width:9px;height:9px;border-radius:50%;flex:none}\n.sl-price-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-price-left{font-size:11px;color:var(--sl-muted);font-variant-numeric:tabular-nums}\n.sl-price-amt{font-weight:800;font-variant-numeric:tabular-nums}\n/* long category lists: capped by default, scroll once expanded */\n.sl-prices.sl-expanded{max-height:196px;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}\n.sl-price-more{display:flex;align-items:center;min-height:26px;padding:0;\n color:var(--sl-muted);font-size:11px;font-weight:750;transition:color .15s}\n.sl-price-more:hover,.sl-price-more:focus-visible{color:var(--sl-text)}\n/* held/sold key — one quiet caption line; the map itself teaches these states */\n.sl-status-key{display:flex;gap:11px;flex-wrap:wrap;padding:5px 0 0;margin-top:4px;border-top:1px solid var(--sl-line);color:var(--sl-muted);font-size:10px}\n.sl-status-item{display:inline-flex;align-items:center;gap:5px}\n.sl-status-icon{width:13px;height:13px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;\n color:#fff;background:#6b7280;line-height:1}\n.sl-status-icon svg{width:8px;height:8px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-status-icon.sold{background:#8b93a0}\n.sl-status-icon.sold svg{width:9px;height:9px;stroke-width:2.4}\n\n/* tray */\n.sl-seats-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}\n.sl-seat-summary{font-size:10px;letter-spacing:0;text-transform:none;white-space:nowrap}\n.sl-tray{flex:1;padding:10px 14px 14px;display:flex;flex-direction:column;gap:7px;min-height:0;overflow-y:auto;\n overscroll-behavior:contain;scrollbar-gutter:stable}\n.sl-tray-hint{font-size:12.5px;color:var(--sl-muted);line-height:1.5}\n.sl-chip{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 34px;align-items:stretch;\n flex:none;min-height:53px;border:1px solid var(--sl-line);border-radius:var(--sl-r-sm);overflow:hidden;\n background:var(--sl-surface);font-size:13px;transform-origin:center;transition:border-color .15s,background .15s}\n.sl-chip:hover{border-color:color-mix(in srgb,var(--sl-accent) 38%,var(--sl-line))}\n.sl-chip.sl-enter{animation:slChipIn .38s cubic-bezier(.2,.8,.2,1) both}\n.sl-chip.sl-leave{pointer-events:none;animation:slChipOut .16s ease-in both}\n.sl-chip.sl-held{border-color:var(--sl-line);background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface));\n box-shadow:inset 3px 0 0 color-mix(in srgb,var(--sl-accent) 72%,transparent)}\n.sl-ticket-state{width:17px;height:17px;border-radius:999px;flex:none;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-ticket-state.held{background:color-mix(in srgb,var(--sl-accent) 18%,var(--sl-surface));color:var(--sl-accent)}\n.sl-ticket-state svg{width:10px;height:10px;stroke:currentColor;stroke-width:2.6;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-chip-main{min-width:0;padding:8px 10px 8px 11px;display:flex;flex-direction:column;justify-content:center;gap:5px}\n.sl-chip-id{display:flex;gap:12px;min-width:0}\n.sl-chip-id .fld{min-width:0}\n.sl-chip-id .fld.sec{flex:1}\n.sl-chip-id .fld.mid{flex:none;text-align:center}\n.sl-chip-eb{display:block;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);margin-bottom:1px}\n.sl-chip-id .val{display:block;font-weight:600;font-size:13px;line-height:1.25;white-space:nowrap}\n.sl-chip-id .fld.sec .val{overflow:hidden;text-overflow:ellipsis}\n.sl-chip-sub{display:flex;align-items:center;gap:6px;min-width:0}\n.sl-chip .cat{color:var(--sl-muted);font-size:10.5px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-chip .amt{font-weight:700;font-variant-numeric:tabular-nums;flex:none;white-space:nowrap}\n.sl-chip-rail{display:flex;flex-direction:column;border-left:1px solid var(--sl-line)}\n.sl-chip .rm,.sl-chip .view{flex:1;min-height:26px;border-radius:0;display:flex;align-items:center;justify-content:center;\n color:var(--sl-muted);transition:color .15s,background .15s}\n.sl-chip .view{border-top:1px solid var(--sl-line)}\n.sl-chip .rm:hover,.sl-chip .rm:focus-visible{color:var(--sl-danger);background:color-mix(in srgb,var(--sl-danger) 9%,transparent)}\n.sl-chip .view:hover,.sl-chip .view:focus-visible{color:var(--sl-text);background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n.sl-chip .rm svg{width:11px;height:11px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round}\n.sl-chip .view svg{width:13px;height:13px;stroke:currentColor;stroke-width:1.8;fill:none}\n/* live-activity strip — narrates WS availability deltas (social proof + urgency).\n Hidden until a delta actually happens: a static \"seats update in real time\"\n banner is dead vertical space, a \"2 seats just taken\" flash is a signal. */\n.sl-live{display:none;align-items:center;gap:7px;margin:10px 14px 0;padding:7px 9px;flex:none;\n border:1px solid var(--sl-line);border-radius:8px;background:color-mix(in srgb,var(--sl-accent) 4%,var(--sl-surface));\n font-size:11px;color:var(--sl-muted)}\n.sl-live .dot{width:6px;height:6px;border-radius:999px;background:var(--sl-success);box-shadow:0 0 6px color-mix(in srgb,var(--sl-success) 75%,transparent);flex:none}\n.sl-live span:last-child{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-live.on{display:flex;animation:slNoticeIn .38s cubic-bezier(.2,.8,.2,1) both}\n\n/* GA rows */\n.sl-ga{display:flex;align-items:center;gap:10px;padding:9px 11px;border:1px dashed var(--sl-line);border-radius:var(--sl-r-sm)}\n.sl-ga-info{flex:1;min-width:0}\n.sl-ga-name{font-weight:700;font-size:13px}\n.sl-ga-sub{font-size:11px;color:var(--sl-muted);margin-top:2px}\n.sl-ga-qty{display:flex;align-items:center;gap:8px}\n.sl-ga-qty button{width:26px;height:26px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n font-size:15px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-ga-qty button:hover{border-color:var(--sl-muted)}\n.sl-ga-qty span{min-width:16px;text-align:center;font-weight:800;font-variant-numeric:tabular-nums}\n\n/* footer */\n.sl-foot{position:relative;z-index:2;padding:12px 16px 14px;border-top:1px solid var(--sl-line);flex:none;\n background:var(--sl-bg);box-shadow:0 -10px 24px -22px rgba(0,0,0,.72)}\n.sl-hold-note{display:none;align-items:center;gap:7px;margin-bottom:8px;padding:7px 8px;border-radius:var(--sl-r-sm);\n border:1px solid var(--sl-line);background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface));\n box-shadow:inset 3px 0 0 color-mix(in srgb,var(--sl-accent) 72%,transparent);\n font-size:11.5px;line-height:1.35;color:var(--sl-muted)}\n.sl-hold-note.on{display:flex;animation:slNoticeIn .38s cubic-bezier(.2,.8,.2,1) both}\n.sl-hold-note svg{width:16px;height:16px;flex:none;stroke:var(--sl-accent);stroke-width:2.4;fill:none;\n stroke-linecap:round;stroke-linejoin:round}\n.sl-hold-note b{display:block;color:var(--sl-text);font-size:11.5px;white-space:nowrap}\n.sl-hold-copy{display:block;white-space:nowrap;font-size:10.5px}\n.sl-hold-note>span{flex:1;min-width:0}\n.sl-hold-change{flex:none;min-height:30px;padding:5px 8px;border-radius:8px;border:1px solid var(--sl-line);\n color:var(--sl-text);font-size:10.5px;font-weight:750;white-space:nowrap}\n.sl-hold-change:hover,.sl-hold-change:focus-visible{border-color:var(--sl-accent);color:var(--sl-accent)}\n.sl-hold-change:disabled{opacity:.58;cursor:wait}\n.sl-total{display:flex;justify-content:space-between;align-items:center;font-size:13px;margin-bottom:10px}\n.sl-total b{font-size:17px;font-variant-numeric:tabular-nums}\n.sl-value-pop{animation:slValuePop .32s cubic-bezier(.2,.8,.2,1)}\n/* Primary checkout CTA. Scoped under .sl-picker so it OUTWEIGHS the\n '.sl-picker button' reset (0,1,1) — an unscoped '.sl-cta' (0,1,0) loses to it\n and the button renders as plain text with no accent fill. */\n.sl-picker .sl-cta{display:flex;align-items:center;justify-content:center;width:100%;min-height:44px;\n padding:12px 16px;border-radius:var(--sl-r-sm);font-weight:800;font-size:14px;line-height:1.1;\n background:var(--sl-accent);color:var(--sl-accent-ink);\n transition:filter .15s,background .22s,color .22s,transform .12s,box-shadow .22s;gap:8px}\n.sl-picker .sl-cta:hover{filter:brightness(1.08)}\n.sl-picker .sl-cta:active{transform:translateY(1px);filter:brightness(.94)}\n.sl-picker .sl-cta.sl-ready{animation:slCtaReady .42s cubic-bezier(.2,.8,.2,1)}\n.sl-cta-spin,.sl-ba-spin{width:14px;height:14px;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;\n animation:slspin .7s linear infinite;flex:none}\n/* Disabled (\"Select seats\"): quieter, but still a full-width button shape. */\n.sl-picker .sl-cta:disabled{background:var(--sl-surface);color:var(--sl-muted);opacity:1;\n cursor:not-allowed;filter:none;transform:none}\n\n/* Chrome anchor regions (Feature 6) — every interactive map overlay is APPENDED\n INTO one of these positioned flex containers and flows/stacks within it, so no\n two controls free-float on top of each other. Regions never overlap: the top\n strip splits into left/center/right; rails + corners own their edge. */\n.sl-anchor{position:absolute;z-index:5;display:flex;align-items:center;gap:8px;pointer-events:none}\n.sl-anchor > *{pointer-events:auto}\n.sl-anchor[data-region=\"top-left\"]{top:12px;left:12px;flex-wrap:wrap;max-width:38%}\n.sl-anchor[data-region=\"top-center\"]{top:12px;left:50%;transform:translateX(-50%);flex-direction:column;\n align-items:center;max-width:44%}\n.sl-anchor[data-region=\"top-right\"]{top:12px;right:12px;justify-content:flex-end;flex-wrap:wrap;max-width:38%}\n.sl-anchor[data-region=\"left-rail\"]{top:50%;left:12px;transform:translateY(-50%);flex-direction:column;max-width:42%;gap:6px}\n.sl-anchor[data-region=\"bottom-left\"]{left:12px;bottom:12px;flex-direction:column;align-items:flex-start}\n.sl-anchor[data-region=\"bottom-center\"]{left:50%;bottom:14px;transform:translateX(-50%);z-index:9;\n flex-direction:column;align-items:center;gap:8px;max-width:92%}\n.sl-anchor[data-region=\"bottom-right\"]{right:12px;bottom:12px;flex-direction:column;align-items:flex-end;gap:6px}\n/* narrow: tighten the top strip so left/center can't crowd each other */\n.sl-picker[data-layout=\"narrow\"] .sl-anchor[data-region=\"top-left\"]{max-width:30%}\n.sl-picker[data-layout=\"narrow\"] .sl-anchor[data-region=\"top-center\"]{max-width:44%}\n\n/* TEST MODE is environment context, not an action. A small squared chip that\n flows FIRST in the top-left anchor region: the old rotated corner ribbon sat\n at a negative offset and was clipped by the widget root's rounded\n overflow:hidden (its ends cut mid-word), and its accent fill made an\n environment flag wear the same gold as \"buy\". Amber warning tone, dashed\n border — reads as a tag, never as a control; the a11y chips wrap beside it\n in the same region, so no displacement hack is needed. */\n.sl-testbadge{display:inline-flex;align-items:center;padding:5px 10px;border-radius:7px;pointer-events:none;\n font-size:10px;font-weight:850;letter-spacing:.13em;line-height:1.2;text-transform:uppercase;white-space:nowrap;\n color:var(--sl-warn);background:color-mix(in srgb,var(--sl-warn) 13%,var(--sl-surface));\n border:1px dashed color-mix(in srgb,var(--sl-warn) 55%,transparent)}\n\n/* zoom column (flows within the bottom-right region) */\n.sl-zoom{display:flex;flex-direction:column;gap:6px}\n/* CSS-fallback full screen (iOS Safari has no element fullscreen API) */\n.sl-picker.sl-fs{position:fixed;inset:0;z-index:2147483000;width:auto;height:auto;max-height:none;border-radius:0}\n.sl-zoom button{width:36px;height:36px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-zoom button:hover{border-color:var(--sl-muted)}\n.sl-zoom svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n/* Full-screen promotion on phones: the capability existed (native + iOS overlay\n + framed-host paths) but hid as the 4th unlabelled glyph in a corner stack.\n On narrow layouts dockLayoutChrome moves the SAME button into the top-right\n region beside Map|3D and this class dresses it as a labelled pill — the one\n accelerator with the highest payoff on a small screen gets words. */\n.sl-zfs-lbl{display:none}\n.sl-fs-pill.sl-fs-pill{display:inline-flex;align-items:center;justify-content:center;width:auto;min-height:40px;height:auto;\n padding:0 13px;gap:6px;border-radius:999px;font-size:11px;font-weight:800;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}\n.sl-fs-pill.sl-fs-pill:hover{border-color:var(--sl-muted)}\n.sl-fs-pill svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-fs-pill .sl-zfs-lbl{display:inline;letter-spacing:.02em;white-space:nowrap}\n\n/* toast + boot states (toast flows in the bottom-center region) */\n.sl-toast{transform:translateY(6px) scale(.98);max-width:100%;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);border-radius:999px;padding:9px 16px;\n font-size:12.5px;font-weight:600;opacity:0;pointer-events:none;transition:opacity .22s,transform .22s;white-space:nowrap;\n overflow:hidden;text-overflow:ellipsis}\n.sl-toast.on{opacity:1;transform:translateY(0) scale(1)}\n.sl-toast.has-action{pointer-events:auto;display:flex;align-items:center;gap:12px;padding-right:8px}\n.sl-toast-action{min-height:30px;padding:5px 10px;border-radius:999px;background:var(--sl-accent);color:var(--sl-accent-ink);\n font:inherit;font-weight:800}\n.sl-toast[data-tone=\"error\"]{border-color:var(--sl-danger)}\n.sl-toast[data-tone=\"warning\"]{border-color:var(--sl-accent)}\n.sl-toast[data-tone=\"success\"]{border-color:var(--sl-success)}\n.sl-toast.on[data-tone=\"error\"]{animation:slToastNudge .32s ease-out}\n.sl-boot{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;\n gap:10px;background:var(--sl-bg);font-size:13px;font-weight:600;color:var(--sl-muted)}\n.sl-boot-spin{width:24px;height:24px;border-radius:50%;border:3px solid var(--sl-line);border-top-color:var(--sl-accent);\n animation:slspin .8s linear infinite}\n@keyframes slspin{to{transform:rotate(360deg)}}\n.sl-boot-title{font-weight:800;font-size:15px;color:var(--sl-text)}\n.sl-boot-retry{margin-top:4px;padding:9px 20px;border-radius:var(--sl-r-sm);background:var(--sl-accent);\n color:var(--sl-accent-ink);font-weight:700;font-size:13px}\n\n/* \"Need more time?\" extend prompt (flows in the bottom-center region, above the toast) */\n.sl-extend{transform:translateY(6px);\n display:none;align-items:center;gap:12px;max-width:100%;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);border-radius:14px;padding:10px 12px 10px 16px;box-shadow:0 18px 50px -18px rgba(0,0,0,.6);\n opacity:0;transition:opacity .2s,transform .2s}\n.sl-extend.on{display:flex;opacity:1;transform:translateY(0)}\n.sl-extend-txt{font-size:12.5px;font-weight:600;line-height:1.35}\n.sl-extend-txt b{font-variant-numeric:tabular-nums}\n.sl-extend-btn{flex:none;padding:8px 14px;border-radius:999px;font-weight:800;font-size:12.5px;\n background:var(--sl-accent);color:var(--sl-accent-ink);transition:filter .15s,opacity .15s}\n.sl-extend-btn:hover{filter:brightness(1.08)}\n.sl-extend-btn:disabled{opacity:.5;cursor:not-allowed}\n\n/* booked confirmation overlay (covers the widget once the held seats are sold) */\n.sl-booked{position:absolute;inset:0;z-index:11;display:flex;flex-direction:column;align-items:center;\n justify-content:center;gap:12px;text-align:center;padding:28px;background:var(--sl-bg);opacity:0;visibility:hidden;\n pointer-events:none;transition:opacity .34s ease,visibility 0s linear .34s}\n.sl-booked.on{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .34s ease,visibility 0s}\n.sl-booked-badge{width:60px;height:60px;border-radius:999px;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink);transform:scale(.72)}\n.sl-booked.on .sl-booked-badge{animation:slSuccessPop .58s cubic-bezier(.2,1.25,.3,1) .08s both}\n.sl-booked-badge svg{width:30px;height:30px;stroke:currentColor;stroke-width:2.6;fill:none;stroke-linecap:round;stroke-linejoin:round;\n stroke-dasharray:30;stroke-dashoffset:30}\n.sl-booked.on .sl-booked-badge svg{animation:slCheckDraw .42s ease-out .32s forwards}\n.sl-booked-title{font-weight:800;font-size:19px;color:var(--sl-text)}\n.sl-booked-sub{font-size:13px;color:var(--sl-muted);line-height:1.5;max-width:320px}\n.sl-booked-seats{font-weight:700;color:var(--sl-text)}\n.sl-booked.on .sl-booked-title,.sl-booked.on .sl-booked-sub{animation:slCopyRise .42s ease-out both}\n.sl-booked.on .sl-booked-title{animation-delay:.22s}\n.sl-booked.on .sl-booked-sub{animation-delay:.3s}\n\n/* sold-out overlay — every SEATED category's live availability is 0. This is\n informational only: no waitlist workflow exists. Suppressed when GA areas\n exist (GA capacity isn't seat-counted). Clears live when WS frees a seat. */\n.sl-soldout{position:absolute;inset:0;z-index:10;display:none;flex-direction:column;align-items:center;\n justify-content:center;text-align:center;gap:8px;padding:24px;\n background:color-mix(in srgb,var(--sl-bg) 82%,transparent);backdrop-filter:blur(4px)}\n.sl-soldout.on{display:flex}\n.sl-soldout-eyebrow{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--sl-accent);font-weight:800}\n.sl-soldout-title{font-size:32px;font-weight:800;color:var(--sl-text);line-height:1.05}\n.sl-soldout-copy{max-width:360px;font-size:13px;color:var(--sl-muted);line-height:1.5}\n\n/* sales-closed pill (header) — persistent read-only state when the event's sales\n window is closed at load or closes live mid-session. Neutral (not accent) so it\n reads as \"unavailable\", distinct from the accent hold pill next to it. */\n.sl-closed-pill{display:none;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;flex:none;\n background:color-mix(in srgb,var(--sl-text) 12%,var(--sl-surface));color:var(--sl-text);\n font-weight:700;font-size:12px;white-space:nowrap}\n.sl-closed-pill.on{display:inline-flex}\n.sl-closed-pill svg{width:13px;height:13px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* \"Powered by SeatLayer\" attribution badge (side-panel foot) — the canonical\n Layered Rows mark + wordmark. Hidden when the host opts out or the org's paid\n theme sets hideBadge. */\n.sl-powered{display:flex;align-items:center;justify-content:center;gap:6px;margin-top:10px;\n font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--sl-text);opacity:.72;\n text-decoration:none;padding:6px 10px;border-radius:999px;width:fit-content;margin-inline:auto;\n transition:opacity .15s ease,background-color .15s ease}\n.sl-powered:hover{opacity:1;background:color-mix(in srgb,var(--sl-text) 8%,transparent)}\n.sl-powered:focus-visible{opacity:1;outline:2px solid var(--sl-accent);outline-offset:2px}\n.sl-powered-mark{width:16px;height:16px;border-radius:4px;flex:none;display:flex;align-items:center;justify-content:center;\n background:#0c1220;color:#fcf7ee}\n.sl-powered-mark svg{width:12px;height:11px}\n\n/* a11y filter chips (flow within the top-left region) */\n.sl-chips{display:flex;gap:6px;flex-wrap:wrap}\n.sl-chip-f{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:999px;font-size:12px;font-weight:700;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted);transition:color .15s,border-color .15s}\n.sl-chip-f:hover{color:var(--sl-text)}\n.sl-chip-f.on{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n\n/* confirm card: a candidate is not in the tray until Select. Map gestures and\n floating chrome pause while the card owns focus, keeping the camera stable. */\n.sl-picker[data-confirming=\"true\"] .sl-map-host>:not(.sl-confirm){pointer-events:none}\n.sl-picker[data-confirming=\"true\"] .sl-anchor{pointer-events:none;opacity:.28;transition:opacity .16s}\n.sl-picker[data-confirming=\"true\"] .sl-side{pointer-events:none;opacity:.58;transition:opacity .16s}\n.sl-confirm{position:absolute;z-index:10;width:276px;max-width:calc(100% - 24px);overflow:hidden;pointer-events:auto;\n background:var(--sl-surface);border:1px solid color-mix(in srgb,var(--sl-line) 70%,var(--sl-text));\n border-radius:15px;box-shadow:0 24px 64px -18px rgba(0,0,0,.72);transform:translate(-50%,calc(-100% - 16px));\n animation:slConfirmIn .24s cubic-bezier(.2,.8,.2,1) both}\n.sl-confirm[data-placement=\"below\"]{transform:translate(-50%,16px);animation:slConfirmBelowIn .24s cubic-bezier(.2,.8,.2,1) both}\n.sl-confirm-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(52px,auto) minmax(52px,auto);border-bottom:1px solid var(--sl-line)}\n.sl-confirm-field{min-width:0;padding:12px 11px 10px;border-right:1px solid var(--sl-line)}\n.sl-confirm-field:last-child{border-right:0;text-align:center}\n.sl-confirm-field:nth-child(2){text-align:center}\n.sl-confirm-key{display:block;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-confirm-value{display:block;margin-top:4px;color:var(--sl-text);font-size:17px;line-height:1.1;font-weight:850;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n/* Long venue section names must read in full: smaller type + up to two lines\n beats an ellipsis at identity-confirmation time. Row/seat stay big — they're\n short and they're what the buyer double-checks against the map. */\n.sl-confirm-field:first-child .sl-confirm-value{font-size:13.5px;line-height:1.25;white-space:normal;\n display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}\n.sl-confirm-cat{display:flex;align-items:center;gap:8px;padding:10px 12px;background:color-mix(in srgb,var(--sl-cat) 76%,var(--sl-surface))}\n.sl-confirm-cat .sl-dot{border:2px solid rgba(255,255,255,.78);width:11px;height:11px}\n.sl-confirm-cat-name{font-size:13.5px;font-weight:800;color:#fff;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-confirm-price{font-size:17px;font-weight:850;color:#fff;font-variant-numeric:tabular-nums}\n.sl-confirm-body{padding:11px 12px 12px}\n.sl-confirm-row{display:flex;gap:8px;margin-top:10px}\n.sl-confirm-row button{flex:1;min-height:44px;padding:9px 12px;border-radius:9px;font-weight:800;font-size:13px}\n.sl-confirm-add{background:var(--sl-accent)!important;color:var(--sl-accent-ink)!important;display:flex;align-items:center;justify-content:center;gap:7px}\n.sl-confirm-add svg{width:16px;height:16px;stroke:currentColor;stroke-width:2.8;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.sl-confirm-cancel{background:color-mix(in srgb,var(--sl-line) 44%,transparent)!important;border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}\n.sl-confirm-cancel:hover{color:var(--sl-text)}\n.sl-picker[data-layout=\"narrow\"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(342px,calc(100% - 24px));\n transform:translateX(-50%);animation:slConfirmMobileIn .24s cubic-bezier(.2,.8,.2,1) both}\n\n/* Atomic whole/variable-table chooser. Lives inside the widget so the same\n accessible dialog works in inline, modal, desktop and 390px mobile hosts. */\n.sl-table-scrim{position:absolute;inset:0;z-index:45;display:flex;align-items:center;justify-content:center;padding:18px;\n background:color-mix(in srgb,var(--sl-bg) 66%,transparent);backdrop-filter:blur(3px)}\n.sl-table-dialog{width:min(408px,100%);max-height:calc(100% - 24px);overflow:auto;border:1px solid var(--sl-line);\n border-radius:calc(var(--sl-radius) * 1.15);background:var(--sl-surface);box-shadow:0 28px 70px rgba(0,0,0,.42)}\n.sl-table-head{padding:18px 18px 14px;border-bottom:1px solid var(--sl-line)}\n.sl-table-eyebrow{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-table-title{margin-top:5px;font-size:22px;line-height:1.15;font-weight:850}\n.sl-table-copy{margin-top:7px;color:var(--sl-muted);font-size:13px;line-height:1.45}\n.sl-table-body{padding:16px 18px 18px}\n.sl-table-summary{display:grid;grid-template-columns:1fr auto;gap:8px 16px;padding:12px;border:1px solid var(--sl-line);\n border-radius:var(--sl-r-sm);background:color-mix(in srgb,var(--sl-line) 22%,transparent);font-size:13px}\n.sl-table-summary b{font-size:15px}.sl-table-summary .muted{color:var(--sl-muted)}\n.sl-table-qtylabel{display:block;margin:16px 0 8px;font-size:12px;font-weight:800}\n.sl-table-stepper{display:grid;grid-template-columns:48px 1fr 48px;align-items:center;border:1px solid var(--sl-line);\n border-radius:12px;overflow:hidden;background:var(--sl-bg)}\n.sl-table-stepper button{height:48px;font-size:24px;font-weight:700;background:color-mix(in srgb,var(--sl-line) 34%,transparent)!important}\n.sl-table-stepper button:disabled{opacity:.38;cursor:not-allowed}\n.sl-table-stepper output{text-align:center;font-size:19px;font-weight:850;font-variant-numeric:tabular-nums}\n.sl-table-range{margin-top:7px;color:var(--sl-muted);font-size:11px;text-align:center}\n.sl-table-actions{display:flex;gap:9px;margin-top:17px}.sl-table-actions button{flex:1;min-height:46px;border-radius:10px;font-weight:800}\n.sl-table-cancel{border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}\n.sl-table-confirm{background:var(--sl-accent)!important;color:var(--sl-accent-ink)!important}\n.sl-table-confirm:disabled{opacity:.62;cursor:wait}\n.sl-table-edit{margin-left:4px;padding:2px 7px!important;border:1px solid var(--sl-line)!important;border-radius:999px!important;\n color:var(--sl-muted)!important;font-size:10px!important;font-weight:800!important}\n.sl-picker[data-layout=\"narrow\"] .sl-table-scrim{align-items:flex-end;padding:0;background:rgba(5,7,12,.58)}\n.sl-picker[data-layout=\"narrow\"] .sl-table-dialog{width:100%;max-height:min(78%,620px);border-radius:18px 18px 0 0;border-width:1px 0 0}\n.sl-picker[data-layout=\"narrow\"] .sl-table-head{padding-top:22px}.sl-picker[data-layout=\"narrow\"] .sl-table-body{padding-bottom:max(20px,env(safe-area-inset-bottom))}\n\n/* hover preview — a COMPACT echo of the confirm card (deliberately smaller: it's\n a passing preview on hover, not the click/select action surface). Reuses the\n Section·Row·Seat identity grid so hover, confirm and the cart chip all share\n one visual language, just at three sizes. */\n.sl-tip{position:absolute;z-index:7;pointer-events:none;display:none;width:190px;overflow:hidden;\n background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:11px;\n box-shadow:0 12px 30px -14px rgba(0,0,0,.6)}\n.sl-tip-grid{display:grid;grid-template-columns:1.3fr .85fr .85fr;border-bottom:1px solid var(--sl-line)}\n.sl-tip-grid.one{grid-template-columns:1fr}\n.sl-tip-field{min-width:0;padding:6px 9px;border-right:1px solid var(--sl-line)}\n.sl-tip-field:last-child{border-right:0;text-align:center}\n.sl-tip-grid:not(.one) .sl-tip-field:nth-child(2){text-align:center}\n.sl-tip-key{display:block;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}\n.sl-tip-val{display:block;margin-top:2px;color:var(--sl-text);font-size:13px;line-height:1.1;font-weight:750;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-tip-cat{display:flex;align-items:center;gap:7px;padding:6px 10px;font-size:11px;\n background:color-mix(in srgb,var(--sl-cat) 12%,var(--sl-surface))}\n.sl-tip-dot{width:8px;height:8px;border-radius:50%;flex:none}\n.sl-tip-name{color:var(--sl-muted);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-tip-amt{margin-left:auto;font-weight:800;color:var(--sl-text);font-variant-numeric:tabular-nums;font-size:12px}\n.sl-tip-status{padding:5px 10px 7px;font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;color:var(--sl-muted)}\n\n/* Best available is a first-class shortcut, not an anonymous utility row. */\n.sl-ba{position:relative;flex:none;overflow:hidden;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:7px;\n padding:13px;border:1px solid color-mix(in srgb,var(--sl-accent) 34%,var(--sl-line));border-radius:13px;\n background:linear-gradient(135deg,color-mix(in srgb,var(--sl-accent) 5%,var(--sl-surface)),color-mix(in srgb,var(--sl-accent) 11%,var(--sl-surface)))}\n.sl-ba::after{content:'✦';position:absolute;right:10px;top:3px;color:color-mix(in srgb,var(--sl-accent) 20%,transparent);font-size:42px;line-height:1}\n.sl-ba-title,.sl-ba-copy,.sl-ba select,.sl-ba-qty,.sl-ba-go{position:relative;z-index:1}\n.sl-ba-title{grid-column:1/-1;display:flex;align-items:center;gap:7px;font-size:13px;font-weight:850}\n.sl-ba-title .spark{color:var(--sl-accent);font-size:16px}\n.sl-ba-copy{grid-column:1/-1;margin:-4px 0 2px 23px;color:var(--sl-muted);font-size:10.5px;line-height:1.35}\n.sl-ba-copy .narrow{display:none}\n/* \"★ Best seats\" premium quick-pick — gold accent echoing the ★ Premium pill on\n the confirm popover; deliberately distinct from the accent-toned qty/go. */\n.sl-ba-premium{position:relative;z-index:1;grid-column:1/-1;justify-self:start;display:inline-flex;align-items:center;gap:6px;\n padding:6px 12px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.02em;cursor:pointer;\n color:var(--sl-premium-deep);background:color-mix(in srgb,var(--sl-premium) 10%,var(--sl-surface));\n border:1px solid color-mix(in srgb,var(--sl-premium) 34%,var(--sl-line));transition:filter .15s,background .15s,color .15s}\n.sl-ba-premium .star{font-size:12px;line-height:1;color:var(--sl-premium)}\n.sl-ba-premium:hover{filter:brightness(1.05)}\n.sl-ba-premium.on{color:var(--sl-premium-ink);background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;\n box-shadow:0 6px 16px color-mix(in srgb,var(--sl-premium) 26%,transparent)}\n.sl-ba-premium.on .star{color:#5a4410}\n.sl-ba select{background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;\n font:inherit;font-size:11px;padding:7px 8px;min-width:0;width:100%;max-width:none}\n.sl-ba-qty{display:flex;align-items:center;gap:7px;padding:3px;border:1px solid var(--sl-line);border-radius:9px;background:var(--sl-surface)}\n.sl-ba-qty button{width:25px;height:25px;border-radius:7px;background:color-mix(in srgb,var(--sl-line) 35%,transparent);border:0;\n font-size:14px;font-weight:800;display:flex;align-items:center;justify-content:center}\n.sl-ba-qty span{min-width:14px;text-align:center;font-weight:800}\n.sl-picker .sl-ba-go{grid-column:1/-1;width:100%;min-height:37px;padding:7px 12px;border-radius:9px;background:var(--sl-accent);\n color:var(--sl-accent-ink);font-weight:800;font-size:12px;transition:filter .15s,opacity .15s;display:flex;align-items:center;justify-content:center;gap:6px;\n box-shadow:0 8px 18px color-mix(in srgb,var(--sl-accent) 18%,transparent)}\n.sl-picker .sl-ba-go:hover{filter:brightness(1.06)}\n/* ONE disabled language, shared with the checkout CTA: surface + muted ink +\n not-allowed. A gold button at 62% still reads as gold, and cursor:wait means\n \"working\" — that pairing made a dead control look live. The wait cursor is\n reserved for the genuinely in-flight search, which keeps its accent fill\n via .sl-busy. */\n.sl-picker .sl-ba-go:disabled{background:var(--sl-surface);color:var(--sl-muted);cursor:not-allowed;\n filter:none;box-shadow:none}\n.sl-picker .sl-ba-go.sl-busy:disabled{background:var(--sl-accent);color:var(--sl-accent-ink);opacity:.85;cursor:wait;\n box-shadow:0 8px 18px color-mix(in srgb,var(--sl-accent) 18%,transparent)}\n.sl-ba-replace{grid-column:1/-1;padding:3px 0 1px}\n.sl-ba-replace b{display:block;font-size:12.5px}\n.sl-ba-replace span{display:block;margin-top:3px;color:var(--sl-muted);font-size:10.5px;line-height:1.35}\n.sl-ba-actions{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr;gap:7px}\n.sl-ba-actions button{min-height:36px;border-radius:9px;border:1px solid var(--sl-line);font-size:11.5px;font-weight:800}\n.sl-ba-actions .replace{border-color:var(--sl-accent);background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-picker[data-layout=\"narrow\"] .sl-ba{padding:9px;gap:6px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba::after{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-title{font-size:12.5px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy .wide{display:none}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-copy .narrow{display:inline}\n.sl-picker[data-layout=\"narrow\"] .sl-ba select{min-height:40px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-qty button{width:30px;height:30px}\n.sl-picker[data-layout=\"narrow\"] .sl-ba-go{min-height:40px}\n\n/* Sales-closed is a designed state, not a set of disables: one statement in\n the tray where the buying flow was, carrying the event's own date so the\n buyer knows which night the verdict belongs to. Neutral like the header\n pill — \"unavailable\" never wears the accent. */\n.sl-closed-note{flex:none;display:flex;flex-direction:column;gap:4px;padding:13px;border-radius:13px;\n border:1px solid var(--sl-line);background:color-mix(in srgb,var(--sl-text) 5%,var(--sl-surface))}\n.sl-closed-note b{font-size:13px;font-weight:850}\n.sl-closed-note span{font-size:11.5px;line-height:1.45;color:var(--sl-muted)}\n.sl-closed-note .when{display:block;margin-top:2px;font-size:11.5px;font-weight:700;color:var(--sl-text)}\n\n/* 44px HIT FLOOR ON TOUCH. Visual sizes stay exactly as designed — the target\n grows through an invisible centred pseudo-element, the same grow-the-target-\n not-the-ink pattern the hosted event page documents for its footer links.\n Applied only to controls with clearance around them; tightly stacked pairs\n (the cart chip's remove/view rail) instead get real height on narrow. */\n@media (pointer:coarse){\n .sl-zoom button,.sl-cbbtn,.sl-close,.sl-ga-qty button,.sl-ba-qty button,.sl-price-more,\n .sl-hold-change,.sl-seccard-x,.sl-fs-pill,.sl-side-toggle{position:relative}\n .sl-zoom button::after,.sl-cbbtn::after,.sl-close::after,.sl-ga-qty button::after,.sl-ba-qty button::after,\n .sl-price-more::after,.sl-hold-change::after,.sl-seccard-x::after,.sl-fs-pill::after,.sl-side-toggle::after{\n content:'';position:absolute;top:50%;left:50%;width:max(100%,44px);height:max(100%,44px);\n transform:translate(-50%,-50%)}\n /* The chip rail stacks remove over view in ~53px — pseudo-targets would\n overlap and make a destructive tap ambiguous. Give the pair real height. */\n .sl-picker[data-layout=\"narrow\"] .sl-chip{min-height:64px}\n .sl-picker[data-layout=\"narrow\"] .sl-chip .rm,\n .sl-picker[data-layout=\"narrow\"] .sl-chip .view{min-height:32px}\n}\n\n/* screen-reader live region */\n.sl-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n\n/* per-seat ticket-tier select + view-from-seat button in tray chips */\n.sl-chip .tier{background:var(--sl-bg);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:6px;\n font:inherit;font-size:10px;padding:2px 4px;min-width:0;max-width:100%;cursor:pointer}\n\n/* arena: LOD rung pills (flow within the top-center region) */\n.sl-rungs{display:none;background:var(--sl-surface);border:1px solid var(--sl-line);border-radius:999px;padding:3px}\n.sl-rungs.on{display:inline-flex;gap:2px}\n.sl-rungs button{padding:6px 13px;border-radius:999px;font-size:10.5px;font-weight:800;letter-spacing:.07em;\n color:var(--sl-muted);white-space:nowrap;transition:color .15s}\n.sl-rungs button:hover{color:var(--sl-text)}\n.sl-rungs button.on{background:var(--sl-accent);color:var(--sl-accent-ink)}\n/* narrow: shrink the rung pills so the centered row can't reach the corner regions */\n.sl-picker[data-layout=\"narrow\"] .sl-rungs button{padding:5px 9px;font-size:9px;letter-spacing:.03em}\n\n/* Projection is deliberately a separate control from zoom/LOD. Perspective\n changes geometry; the two choices stay explicit and keyboard-native. */\n.sl-projection{display:inline-flex;align-items:center;gap:2px;padding:3px;border-radius:999px;\n background:var(--sl-surface);border:1px solid var(--sl-line);box-shadow:0 8px 24px -16px rgba(0,0,0,.65)}\n.sl-projection button{min-width:42px;min-height:30px;padding:5px 10px;border-radius:999px;color:var(--sl-muted);\n font-size:10px;font-weight:800;letter-spacing:.04em;white-space:nowrap}\n.sl-projection button:hover,.sl-projection button:focus-visible{color:var(--sl-text)}\n.sl-projection button.on{background:var(--sl-accent);color:var(--sl-accent-ink)}\n.sl-picker[data-layout=\"narrow\"] .sl-projection button{min-width:38px;min-height:32px;padding:5px 8px;font-size:9.5px}\n\n/* 3D venue overlay — mounts over the (paused) Konva stage inside the map host.\n Carries its own gradient so it paints instantly before the scene builds, and\n cross-fades on enter/exit via a compositor-only opacity transition. Sits below\n the anchored chrome (z-index:5) and the confirm card (z-index:10) so the\n Map|3D toggle and the seat confirm both stay usable over it. */\n.sl-view3d{position:absolute;inset:0;z-index:4;opacity:0;touch-action:none;\n transition:opacity .3s ease;background:radial-gradient(120% 120% at 50% 0%,#191f28 0%,#0d1014 70%)}\n.sl-view3d.has-comparison,.sl-view3d.has-passport{z-index:20}\n/* Confirm mode normally disables the entire GL sibling. Modal surfaces live\n inside that sibling, so explicitly restore pointer input only while one is\n open; their own inert contract keeps the venue underneath unavailable. */\n.sl-picker[data-confirming=\"true\"] .sl-view3d.has-comparison,\n.sl-picker[data-confirming=\"true\"] .sl-view3d.has-passport{pointer-events:auto}\n.sl-view3d canvas{display:block;width:100%;height:100%}\n.sl-view3d canvas:focus-visible{outline:2px solid var(--sl-accent);outline-offset:-3px}\n.sl-view3d-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;\n z-index:1;color:#d9e2f2;font-size:13px;font-weight:700;letter-spacing:.02em;pointer-events:none}\n.sl-view3d-loading::before{content:\"\";width:18px;height:18px;border-radius:50%;\n border:2px solid rgba(217,226,242,.28);border-top-color:#d9e2f2;animation:slSpin .8s linear infinite}\n[data-view3d=on] .sl-chips,[data-view3d=on] .sl-rungs{display:none}\n.sl-view3d-back{position:absolute;top:12px;left:12px;z-index:2;display:inline-flex;align-items:center;gap:6px;\n min-height:44px;padding:7px 13px 7px 9px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.03em;\n color:#e6edf3;background:rgba(10,14,20,.62);border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-back:hover,.sl-view3d-back:focus-visible{background:rgba(16,22,30,.82);border-color:rgba(255,255,255,.4)}\n.sl-view3d-back svg{width:15px;height:15px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round;stroke-linejoin:round}\n/* Map|3D already exits an overview to the 2D map. Reserve Back for the one\n state where it adds meaning: returning from an exact seat to the venue. */\n.sl-view3d:not(.is-seat-focused) .sl-view3d-back{display:none}\n.sl-view3d-fs{position:absolute;top:12px;right:12px;z-index:2;min-width:44px;min-height:44px;padding:8px 12px;\n border-radius:999px;font-size:16px;color:#e6edf3;background:rgba(10,14,20,.62);\n border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-fs:hover,.sl-view3d-fs:focus-visible{background:rgba(16,22,30,.82);border-color:rgba(255,255,255,.4)}\n/* Venue navigation inside 3D: levels (isolate a floor) and areas (fly to a zone).\n Bottom-LEFT, clear of the module's own chips (Overview bottom-right, 360\n bottom-centre) and of the bottom-sheeted confirm card. Horizontally scrollable\n so a venue with many zones never pushes the rail off a phone screen.\n\n EVERY WIDTH HERE IS RELATIVE TO THE RAIL, NEVER TO THE WINDOW. These three\n rules used to size off 100vw, which contradicts the one contract this widget\n states about itself: it adapts to a full-screen takeover, an inline div in a\n content page, or a popup, and its breakpoints key off the CONTAINER, never the\n viewport. A 390 px picker embedded in a 1400 px page asked for\n calc(100vw - 180px) = 1220 inside a 390 px rail.\n\n MEASURED, IT DID NOT OVERFLOW: the scroll parent is a flex container, so the\n over-large declaration was shrunk back to the rail and both the old and new\n rules resolve to 364 px in situ. So this is a latent correctness fix, not a\n visible bug -- the numbers were wrong and were being covered for by a\n flex-shrink one level up. Left as 100% because the next person to change that\n parent's display should not inherit a rule that only works by accident. */\n.sl-view3d-nav{position:absolute;left:12px;bottom:16px;z-index:3;display:flex;flex-direction:column;gap:6px;\n max-width:calc(100% - 150px);pointer-events:none}\n.sl-view3d-nav > div{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;pointer-events:auto;\n padding:1px;-webkit-overflow-scrolling:touch}\n.sl-view3d-nav > div::-webkit-scrollbar{display:none}\n.sl-view3d-nav button{flex:0 0 auto;min-height:32px;padding:7px 12px;border-radius:999px;white-space:nowrap;\n font-size:11.5px;font-weight:700;color:#c9d4ea;background:rgba(12,18,32,.72);\n border:1px solid rgba(150,165,205,.35);backdrop-filter:blur(6px);cursor:pointer}\n.sl-view3d-nav button:hover,.sl-view3d-nav button:focus-visible{color:#eef1f8;border-color:rgba(190,205,240,.6)}\n.sl-view3d-nav button[aria-pressed=\"true\"]{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n.sl-view3d-nav button:disabled{opacity:.45;cursor:not-allowed}\n.sl-view3d-nav-toggle{display:none!important}\n.sl-view3d-nav select{min-height:38px;max-width:100%;padding:7px 34px 7px 12px;\n border-radius:999px;font:700 11.5px/1 inherit;color:#eef1f8;background:rgba(12,18,32,.86);\n border:1px solid rgba(150,165,205,.45);backdrop-filter:blur(6px);cursor:pointer}\n.sl-view3d-nav select:focus-visible{outline:2px solid var(--sl-accent);outline-offset:2px}\n.sl-view3d-nav .sl-view3d-locator{display:grid;grid-template-columns:minmax(150px,1.25fr) minmax(110px,.8fr) minmax(105px,.7fr) auto;\n width:min(720px,100%);overflow:visible}\n.sl-view3d-nav.is-seat-focused .sl-view3d-locator{display:none}\n.sl-view3d-locator select{width:100%;min-width:0}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav .sl-view3d-locator{display:flex;width:100%;overflow-x:auto}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-locator select{flex:0 0 155px}\n/* On phones the library owns the bottom edge for seat/panorama/overview actions.\n Keep venue navigation in a separate top rail so those control families never\n stack over one another. */\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav{left:120px;top:12px;bottom:auto;max-width:calc(100% - 132px)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav-toggle{display:inline-flex!important;align-items:center;pointer-events:auto;min-height:44px}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav:not(.is-open)>div{display:none!important}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open{left:12px;top:68px;max-width:calc(100% - 24px);padding:8px;\n border:1px solid rgba(150,165,205,.35);border-radius:14px;background:rgba(8,12,22,.9);backdrop-filter:blur(10px)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open>div{display:flex}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator{display:grid;grid-template-columns:1fr 1fr;width:100%;overflow:visible}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator select{width:100%;min-width:0;flex:auto}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-nav.is-open .sl-view3d-locator button{width:100%}\n/* Seat-eye is a decision state, not another venue-navigation state. Once the\n buyer arrives, clear the floor/area/locator rails and the module's duplicate\n Overview action. The picker-owned Back button becomes the one predictable\n escape: seat -> venue -> 2D map. */\n.sl-view3d.is-seat-focused .sl-view3d-nav,\n.sl-view3d.is-seat-focused .sl-3d-overview-control,\n.sl-view3d.is-seat-focused .sl-view3d-compare-saved{display:none!important}\n/* While immersed, the 2D-only chrome is meaningless — hide it, keep Map|3D. */\n.sl-picker[data-view3d=\"on\"] .sl-rungs,\n.sl-picker[data-view3d=\"on\"] .sl-floors,\n.sl-picker[data-view3d=\"on\"] .sl-zoom,\n.sl-picker[data-view3d=\"on\"] .sl-seccard,\n.sl-picker[data-view3d=\"on\"] .sl-minimap{display:none!important}\n/* The confirm card bottom-sheets over 3D (no 2D screen anchor to track). */\n.sl-picker[data-view3d=\"on\"] .sl-confirm{left:50%!important;top:auto!important;bottom:16px;\n transform:translateX(-50%);width:min(342px,calc(100% - 24px))}\n.sl-picker[data-view3d=\"on\"] .sl-confirm[data-placement]{transform:translateX(-50%)}\n.sl-confirm-inspect-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:9px}\n.sl-confirm-inspect-row .sl-confirm-3d{margin-top:0;min-height:44px}\n.sl-confirm-compare{min-height:44px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:transparent}\n.sl-confirm-compare:hover,.sl-confirm-compare:focus-visible{border-color:var(--sl-accent);\n background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n.sl-confirm-compare:disabled{opacity:.62;cursor:default}\n.sl-confirm-confidence{width:100%;min-height:44px;margin-top:8px;padding:8px 10px;border-radius:9px;\n border:1px solid color-mix(in srgb,var(--sl-accent) 35%,var(--sl-line));display:flex;align-items:center;\n justify-content:space-between;gap:10px;text-align:left;color:var(--sl-text);\n background:color-mix(in srgb,var(--sl-accent) 7%,var(--sl-surface))}\n.sl-confirm-confidence>span{min-width:0}\n.sl-confirm-confidence strong,.sl-confirm-confidence small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.sl-confirm-confidence strong{font-size:11px}.sl-confirm-confidence small{margin-top:2px;color:var(--sl-muted);font-size:9.5px}\n.sl-confirm-confidence em{display:none;font-style:normal}\n.sl-confirm-confidence>b{flex:none;font-size:11px;color:var(--sl-accent)}\n.sl-confirm-confidence:hover,.sl-confirm-confidence:focus-visible{border-color:var(--sl-accent)}\n/* The production 3D decision dock is deliberately denser than the 2D popup:\n the venue remains the main content and the two inspection actions share one\n row. Truth-bearing accessibility/restriction copy is never hidden. */\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm{bottom:10px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-field{padding:8px 9px 7px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-value{font-size:14px;margin-top:2px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-field:first-child .sl-confirm-value{font-size:12px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-cat{padding:7px 10px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-price{font-size:15px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-body{padding:8px 10px 9px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"] .sl-confirm-row{margin-top:7px}\n/* A short embedded/mobile picker cannot afford a full decision sheet over a\n 285px map. Keep three 44px action rows and move all disclosure into the\n passport instead of hiding it without a route back. */\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm{bottom:6px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-grid,\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-cat,\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-body>.sl-cx{display:none}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-body{padding:6px 8px 7px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence{margin-top:0}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence em{display:block;margin-bottom:2px;\n color:var(--sl-text);font-size:12px;font-weight:850;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence strong{font-size:9.5px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-confidence small{display:none}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-inspect-row{margin-top:5px}\n.sl-picker[data-view3d=\"on\"][data-layout=\"narrow\"][data-density=\"compact\"] .sl-confirm-row{margin-top:5px}\n\n/* Saved comparison lives in the top journey row, away from checkout, arrival\n controls and the bottom-right privacy position. */\n.sl-view3d-compare-saved{position:absolute;top:12px;left:136px;z-index:5;display:flex;align-items:stretch;\n max-width:180px;min-height:38px;border-radius:999px;overflow:hidden;color:#e6edf3;\n background:rgba(10,14,20,.72);border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}\n.sl-view3d-compare-saved button{min-width:0;padding:7px 10px;color:inherit;font-size:11px;font-weight:800;white-space:nowrap}\n.sl-view3d-compare-saved .main{overflow:hidden;text-overflow:ellipsis}\n.sl-view3d-compare-saved .clear{width:34px;padding:7px;border-left:1px solid rgba(255,255,255,.18)}\n.sl-view3d-compare-saved button:hover,.sl-view3d-compare-saved button:focus-visible{background:rgba(255,255,255,.1)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-compare-saved{left:126px;max-width:calc(100% - 194px);min-height:44px}\n\n/* An unavailable seat is still inspectable. This compact, non-modal status\n card explains the exact chair the buyer touched without selecting it or\n obscuring the venue with the full purchase confirmation sheet. */\n.sl-view3d-unavailable{position:absolute;left:50%;bottom:18px;z-index:9;display:grid;\n grid-template-columns:minmax(0,1fr) auto;gap:4px 14px;width:min(330px,calc(100% - 24px));\n padding:13px 14px;border:1px solid rgba(255,255,255,.22);border-radius:14px;\n color:#eef3fb;background:rgba(10,14,22,.94);box-shadow:0 18px 48px rgba(0,0,0,.48);\n backdrop-filter:blur(10px);transform:translateX(-50%)}\n.sl-view3d-unavailable[data-state=\"held\"]{border-color:rgba(242,168,56,.7)}\n.sl-view3d-unavailable[data-state=\"sold\"],.sl-view3d-unavailable[data-state=\"dimmed\"]{border-color:rgba(160,170,188,.48)}\n.sl-view3d-unavailable-copy{min-width:0}\n.sl-view3d-unavailable-eyebrow{display:block;font-size:9px;line-height:1.2;letter-spacing:.13em;\n text-transform:uppercase;color:#aab7cc;font-weight:850}\n.sl-view3d-unavailable strong{display:block;margin-top:3px;font-size:17px;line-height:1.2}\n.sl-view3d-unavailable p{grid-column:1/-1;margin:4px 0 0;color:#b9c4d7;font-size:11px;line-height:1.4}\n.sl-view3d-unavailable button{align-self:start;min-width:44px;min-height:44px;margin:-5px -6px 0 0;\n border-radius:999px;color:#eef3fb;font-size:18px;border:1px solid rgba(255,255,255,.18)}\n.sl-view3d-unavailable button:hover,.sl-view3d-unavailable button:focus-visible{background:rgba(255,255,255,.1)}\n.sl-picker[data-layout=\"narrow\"] .sl-view3d-unavailable{bottom:10px;padding-bottom:max(13px,env(safe-area-inset-bottom))}\n\n.sl-view3d-compare-shell{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:16px}\n.sl-view3d-compare-scrim{position:absolute;inset:0;background:rgba(3,6,12,.74);backdrop-filter:blur(5px)}\n.sl-view3d-compare{position:relative;width:min(720px,100%);max-height:min(680px,calc(100% - 20px));overflow:auto;\n border:1px solid rgba(160,177,214,.34);border-radius:18px;background:var(--sl-bg);color:var(--sl-text);\n box-shadow:0 28px 90px rgba(0,0,0,.55);padding:18px}\n.sl-view3d-compare>header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}\n.sl-view3d-compare>header span{display:block;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-compare>header strong{display:block;margin-top:4px;font-size:20px}\n.sl-view3d-compare>header button{min-width:44px;min-height:44px;border-radius:999px;border:1px solid var(--sl-line);color:var(--sl-text)}\n.sl-view3d-compare-note{margin:12px 0;color:var(--sl-muted);font-size:12px;line-height:1.45}\n.sl-view3d-compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n.sl-view3d-compare article{min-width:0;padding:14px;border:1px solid var(--sl-line);border-radius:13px;background:var(--sl-surface)}\n.sl-view3d-compare article>span{font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-compare article>strong{display:block;margin-top:3px;font-size:20px}\n.sl-view3d-compare article>small{display:block;margin-top:3px;color:var(--sl-muted)}\n.sl-view3d-compare dl{margin:12px 0 0}\n.sl-view3d-compare dl div{display:grid;grid-template-columns:minmax(90px,.8fr) minmax(0,1.2fr);gap:10px;padding:8px 0;border-top:1px solid var(--sl-line)}\n.sl-view3d-compare dt{font-size:10.5px;color:var(--sl-muted)}\n.sl-view3d-compare dd{margin:0;text-align:right;font-size:11px;font-weight:750;overflow-wrap:anywhere}\n.sl-view3d-compare-actions{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:12px}\n.sl-view3d-compare-actions button{min-height:44px;border-radius:9px;border:1px solid var(--sl-line);font-size:12px;font-weight:800}\n.sl-view3d-compare-actions .select{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n.sl-view3d-compare-actions button:disabled{opacity:.5;cursor:not-allowed}\n.sl-view3d-passport-shell{position:absolute;inset:0;z-index:40;display:grid;place-items:center;padding:16px}\n.sl-view3d-passport-scrim{position:absolute;inset:0;background:rgba(3,6,12,.8);backdrop-filter:blur(6px)}\n.sl-view3d-passport{position:relative;width:min(540px,100%);max-height:min(700px,calc(100% - 20px));overflow:auto;\n padding:18px;border:1px solid rgba(160,177,214,.38);border-radius:18px;background:var(--sl-bg);color:var(--sl-text);\n box-shadow:0 28px 90px rgba(0,0,0,.6)}\n.sl-view3d-passport>header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}\n.sl-view3d-passport>header span{display:block;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:850}\n.sl-view3d-passport>header strong{display:block;margin-top:4px;font-size:20px}\n.sl-view3d-passport>header button{min-width:44px;min-height:44px;border:1px solid var(--sl-line);border-radius:999px;color:var(--sl-text)}\n.sl-view3d-passport-summary{margin:14px 0;padding:12px;border-radius:12px;background:color-mix(in srgb,var(--sl-accent) 9%,var(--sl-surface));\n border:1px solid color-mix(in srgb,var(--sl-accent) 30%,var(--sl-line))}\n.sl-view3d-passport-summary strong{display:block;font-size:15px}.sl-view3d-passport-summary span{display:block;margin-top:4px;font-size:11px;color:var(--sl-muted)}\n.sl-view3d-passport dl{margin:0}.sl-view3d-passport dl div{display:grid;grid-template-columns:minmax(105px,.75fr) minmax(0,1.25fr);\n gap:12px;padding:9px 0;border-top:1px solid var(--sl-line)}\n.sl-view3d-passport dt{font-size:10.5px;color:var(--sl-muted)}.sl-view3d-passport dd{margin:0;text-align:right;font-size:11px;font-weight:750;overflow-wrap:anywhere}\n.sl-view3d-passport h4{margin:14px 0 6px;font-size:11px}.sl-view3d-passport ul{margin:0;padding-left:18px;color:var(--sl-muted);font-size:10.5px;line-height:1.5}\n.sl-view3d-passport-note{margin:14px 0 0;color:var(--sl-muted);font-size:10.5px;line-height:1.45}\n@media(max-width:640px){\n .sl-view3d-compare-shell{padding:max(10px,env(safe-area-inset-top)) 10px max(10px,env(safe-area-inset-bottom))}\n .sl-view3d-compare{width:100%;max-height:100%;padding:14px 14px max(86px,calc(14px + env(safe-area-inset-bottom)));border-radius:15px}\n .sl-view3d-compare-grid{grid-template-columns:1fr}\n .sl-view3d-compare article{padding:12px}\n .sl-view3d-passport-shell{padding:max(10px,env(safe-area-inset-top)) 10px max(10px,env(safe-area-inset-bottom))}\n .sl-view3d-passport{width:100%;max-height:100%;padding:14px 14px max(24px,calc(14px + env(safe-area-inset-bottom)));border-radius:15px}\n}\n\n/* Plain \"View from here\" action shown when no real photo exists (the synthetic\n thumb is suppressed at card size — full-screen is where it earns its keep). */\n.sl-confirm-viewbtn{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:transparent;transition:border-color .15s,background .15s}\n.sl-confirm-viewbtn:hover,.sl-confirm-viewbtn:focus-visible{border-color:var(--sl-accent);background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}\n/* confirm-card \"See it in 3D\" / \"View from this seat\" action — the purchase-\n moment bridge into the cinematic. Styled like the view-from-seat button. */\n.sl-confirm-3d{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;font-weight:800;\n color:var(--sl-text);background:color-mix(in srgb,var(--sl-accent) 12%,transparent);transition:border-color .15s,background .15s}\n.sl-confirm-3d:hover,.sl-confirm-3d:focus-visible{border-color:var(--sl-accent);background:color-mix(in srgb,var(--sl-accent) 20%,transparent)}\n.sl-confirm-3d svg{width:15px;height:15px;stroke:currentColor;stroke-width:1.9;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* multi-floor switcher (flows within the left-rail region) */\n.sl-floors{display:none;flex-direction:column;gap:6px;max-width:100%}\n.sl-floors.on{display:flex}\n.sl-floors button{padding:7px 13px;border-radius:999px;font-size:12px;font-weight:700;background:var(--sl-surface);\n border:1px solid var(--sl-line);color:var(--sl-muted);white-space:nowrap;max-width:100%;overflow:hidden;\n text-overflow:ellipsis;transition:color .15s,border-color .15s}\n.sl-floors button:hover{color:var(--sl-text)}\n.sl-floors button.on{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}\n\n/* tapped-section summary card — docks INSIDE the top-center anchor region on\n wide (flows below the rung pills, never over them, never floating over the\n seats at the tap point). Auto-collapses to a slim pill once seat-picking\n begins (first seat select, or a pan/zoom after the focus glide); tapping the\n pill re-expands; ✕ closes in both states. On narrow it renders as a compact\n strip inside the bottom sheet's peek head — never over the canvas. */\n.sl-seccard{width:250px;max-width:100%;background:var(--sl-surface);border:1px solid var(--sl-line);border-radius:12px;\n padding:12px 14px;box-shadow:0 18px 50px -18px rgba(0,0,0,.6);display:none}\n.sl-seccard.on{display:block}\n/* collapsed pill (wide) */\n.sl-seccard.mini{width:auto;padding:5px 7px 5px 12px;border-radius:999px;cursor:pointer}\n.sl-seccard.mini.on{display:inline-flex;align-items:center;gap:7px}\n.sl-seccard.mini .sl-seccard-name{font-size:12px;flex:none;max-width:120px}\n.sl-seccard.mini .sl-seccard-left{font-size:11px}\n/* narrow: compact strip inside the sheet head (peek area) */\n.sl-seccard.strip{width:100%;padding:7px 0 0;border:0;border-radius:0;box-shadow:none;background:none;cursor:default}\n.sl-seccard.strip.on{display:flex;align-items:center;gap:7px;font-size:12.5px}\n.sl-seccard.strip .sl-seccard-name{font-size:12.5px}\n.sl-seccard.strip .sl-seccard-price{margin-left:auto}\n.sl-seccard-head{display:flex;align-items:center;gap:8px}\n.sl-seccard-dot{width:10px;height:10px;border-radius:50%;flex:none}\n.sl-seccard-name{font-weight:800;font-size:14px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-seccard-price{font-weight:800;font-size:12.5px;font-variant-numeric:tabular-nums}\n.sl-seccard-x{width:22px;height:22px;border-radius:999px;flex:none;display:flex;align-items:center;justify-content:center;\n color:var(--sl-muted);font-size:12px}\n.sl-seccard-x:hover{color:var(--sl-text)}\n.sl-seccard-zone{font-size:11.5px;color:var(--sl-muted);margin-top:6px}\n.sl-seccard-left{color:var(--sl-text);font-weight:700}\n.sl-seccard-mix{display:flex;flex-wrap:wrap;gap:6px 10px;margin-top:8px}\n.sl-seccard-mix-item{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--sl-muted)}\n.sl-seccard-mix-dot{width:8px;height:8px;border-radius:50%;flex:none}\n.sl-seccard-mix-price{font-weight:700;color:var(--sl-text)}\n.sl-seccard-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:10px}\n.sl-seccard-overview{font-size:12px;font-weight:800;color:var(--sl-accent)}\n.sl-seccard-hint{font-size:10.5px;color:var(--sl-muted)}\n\n/* view-from-seat button on the confirm popover */\n/* Eager sightline preview inside the confirm card */\n.sl-confirm-thumbwrap{position:relative;display:block;width:100%;height:74px;margin:0 0 8px;padding:0!important;\n border-radius:9px;overflow:hidden;border:1px solid var(--sl-line);cursor:pointer}\n.sl-confirm-thumb{display:block;width:100%;height:100%;object-fit:cover}\n.sl-confirm-thumb-badge{position:absolute;right:7px;top:7px;display:inline-flex;align-items:center;gap:5px;\n font-size:10px;font-weight:700;color:#fff;background:rgba(10,14,22,0.72);border-radius:12px;padding:4px 9px;backdrop-filter:blur(3px)}\n.sl-confirm-sight{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--sl-muted);margin-bottom:2px}\n.sl-confirm-view{width:100%;margin-top:9px;padding:8px;border-radius:8px;border:1px solid var(--sl-line);\n color:var(--sl-text);font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center;gap:7px}\n.sl-confirm-view:hover{border-color:var(--sl-muted)}\n.sl-confirm-view svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* commercial seat flags — limited-view caution + premium tag. Amber tone,\n deliberately distinct from the red taken/held state; shown on the confirm\n card, echoed as a small ◐ marker on cart chips and the hover tip. */\n.sl-cx{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}\n.sl-cx-warn{display:flex;align-items:flex-start;gap:7px;padding:8px 10px;border-radius:9px;\n background:color-mix(in srgb,#f4b740 13%,var(--sl-surface));border:1px solid color-mix(in srgb,#f4b740 40%,var(--sl-line));\n animation:slNoticeIn .28s ease both}\n.sl-cx-glyph{flex:none;font-size:14px;line-height:1.2;color:#f4b740}\n.sl-cx-txt{min-width:0;display:flex;flex-direction:column;gap:2px}\n.sl-cx-txt b{font-size:12px;font-weight:800;color:var(--sl-text)}\n.sl-cx-note{font-size:11px;line-height:1.4;color:var(--sl-muted)}\n.sl-cx-premium{display:inline-flex;align-items:center;gap:6px;align-self:flex-start;padding:4px 10px;border-radius:999px;\n font-size:11px;font-weight:800;letter-spacing:.02em;color:#c9a24b;\n background:color-mix(in srgb,#e8c15a 13%,var(--sl-surface));border:1px solid color-mix(in srgb,#e8c15a 38%,var(--sl-line))}\n.sl-cx-star{font-size:12px;line-height:1;color:#e8c15a}\n.sl-cx-mark{flex:none;font-size:12px;line-height:1;color:#f4b740;cursor:help}\n.sl-tip-cx{display:flex;align-items:center;gap:6px;padding:5px 10px 7px;font-size:10.5px;font-weight:700;color:#e8b24a}\n.sl-tip-cx .g{font-size:12px}\n\n/* 360° seat-view modal (fills the widget; drag-to-look-around equirectangular) */\n.sl-view{position:absolute;inset:0;z-index:12;display:flex;flex-direction:column;background:var(--sl-bg)}\n.sl-view-head{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--sl-line);flex:none}\n.sl-view-title{font-weight:800;font-size:15px}\n.sl-view-cap{font-size:11px;color:var(--sl-muted)}\n.sl-view-x{margin-left:auto;width:32px;height:32px;border-radius:999px;border:1px solid var(--sl-line);color:var(--sl-muted);\n flex:none;display:flex;align-items:center;justify-content:center;transition:color .15s,border-color .15s}\n.sl-view-x:hover{color:var(--sl-text);border-color:var(--sl-muted)}\n.sl-view-x svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}\n.sl-view-pano{position:relative;flex:1;min-height:0;overflow:hidden;cursor:grab;background-color:#05070c;\n background-repeat:repeat-x;touch-action:none;user-select:none}\n.sl-view-pano.drag{cursor:grabbing}\n.sl-view-badge{position:absolute;top:12px;left:12px;padding:5px 11px;border-radius:999px;font-size:10px;font-weight:800;\n letter-spacing:.08em;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted)}\n.sl-view-hint{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);padding:6px 14px;border-radius:999px;\n font-size:11.5px;font-weight:600;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-muted);\n white-space:nowrap;pointer-events:none;max-width:90%;overflow:hidden;text-overflow:ellipsis}\n\n/* F3 minimap — venue overview + live viewport rect (flows in the bottom-left region) */\n.sl-minimap{border:1px solid var(--sl-line);border-radius:9px;\n overflow:hidden;background:var(--sl-surface);box-shadow:0 12px 34px -14px rgba(0,0,0,.55);line-height:0;cursor:pointer}\n.sl-minimap canvas{display:block}\n.sl-picker[data-layout=\"narrow\"] .sl-minimap{display:none}\n\n/* F4 legend reflection: rows + counts for out-of-band categories read muted */\n/* Out-of-band rows are exactly the rows a buyer reads while deciding whether\n to widen a filter: whole-row opacity .4 took the label to ~2:1. Dim the\n SWATCH and soften the numerals; the words stay legible muted ink. */\n.sl-price-row.sl-dim .sl-dot{opacity:.35}\n.sl-price-row.sl-dim .sl-price-label,.sl-price-row.sl-dim .sl-price-left,.sl-price-row.sl-dim .sl-price-amt{color:var(--sl-muted)}\n.sl-seccard-mix-item.sl-dim{opacity:.55}\n\n/* Buyer-journey motion: every animation explains a state transition (selected,\n held, checkout handoff, conflict or booked). No decorative infinite motion\n except the expiring-hold pulse and active progress spinners. */\n@keyframes slPillIn{from{opacity:0;transform:translateX(7px) scale(.9)}to{opacity:1;transform:translateX(0) scale(1)}}\n@keyframes slHoldPulse{0%{box-shadow:0 0 0 0 currentColor;opacity:.9}75%,100%{box-shadow:0 0 0 7px transparent;opacity:.55}}\n@keyframes slChipIn{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}\n@keyframes slChipOut{to{opacity:0;transform:translateX(10px) scale(.98)}}\n@keyframes slNoticeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}\n@keyframes slValuePop{0%{opacity:.6;transform:translateY(3px)}55%{transform:translateY(-1px) scale(1.05)}100%{opacity:1;transform:none}}\n@keyframes slCtaReady{0%{transform:scale(.98);box-shadow:0 0 0 0 transparent}55%{transform:scale(1.01);box-shadow:0 0 0 5px color-mix(in srgb,var(--sl-accent) 18%,transparent)}100%{transform:none;box-shadow:none}}\n@keyframes slToastNudge{0%,100%{margin-left:0}30%{margin-left:-4px}60%{margin-left:3px}}\n@keyframes slSuccessPop{0%{opacity:0;transform:scale(.72)}65%{opacity:1;transform:scale(1.08)}100%{opacity:1;transform:scale(1)}}\n@keyframes slCheckDraw{to{stroke-dashoffset:0}}\n@keyframes slCopyRise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n@keyframes slConfirmIn{from{opacity:0;transform:translate(-50%,calc(-100% - 8px)) scale(.96)}to{opacity:1;transform:translate(-50%,calc(-100% - 14px)) scale(1)}}\n@keyframes slConfirmBelowIn{from{opacity:0;transform:translate(-50%,8px) scale(.96)}to{opacity:1;transform:translate(-50%,16px) scale(1)}}\n@keyframes slConfirmMobileIn{from{opacity:0;transform:translate(-50%,10px) scale(.97)}to{opacity:1;transform:translate(-50%,0) scale(1)}}\n\n/* Access state (channels): the panel fades AND rises at --slm-mo-base. It never\n covers the map — inventory is cross-faded to neutral by the canvas in one\n batched pass, so nothing blinks away underneath it. */\n.sl-access{position:absolute;left:50%;bottom:18px;z-index:9;transform:translateX(-50%);\n max-width:min(420px,calc(100% - 24px));display:flex;gap:12px;align-items:flex-start;\n padding:12px 14px;border-radius:var(--sl-r-sm);background:var(--sl-panel,#151b2c);color:var(--sl-text);\n border:1px solid var(--sl-line);box-shadow:0 18px 44px -18px rgba(0,0,0,.6);\n animation:slAccessIn var(--slm-mo-base) var(--slm-mo-out) both}\n.sl-access-title{font-weight:700;font-size:13px}\n.sl-access-body{font-size:12px;line-height:1.5;opacity:.82;margin-top:2px}\n.sl-access-act{margin-top:8px;padding:6px 12px;border-radius:999px;font-size:12px;font-weight:700;\n background:var(--sl-accent);color:var(--sl-accent-ink)}\n@keyframes slAccessIn{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}\n\n@media(prefers-reduced-motion:reduce){\n .sl-picker *,.sl-modal-scrim *{animation-duration:.001ms!important;animation-iteration-count:1!important;\n transition-duration:.001ms!important;scroll-behavior:auto!important}\n .sl-access{animation:none;opacity:1;transform:translate(-50%,0)}\n}\n.sl-ba [data-ba-zone]{grid-column:1/-1;width:100%}\n\n/* modal host */\n.sl-modal-scrim{position:fixed;inset:0;z-index:2147483000;background:rgba(5,7,12,.66);display:flex;align-items:center;justify-content:center;padding:18px}\n.sl-modal-frame{width:min(1200px,100%);height:min(820px,100%);border-radius:16px;overflow:hidden;box-shadow:0 40px 120px -30px rgba(0,0,0,.8)}\n/* The frame already clips to 16px. A picker rounding itself to --sl-radius\n (14px) inside it leaves a sliver of scrim showing at each corner, which\n reads as a rendering fault rather than as a rounded card. One owner of the\n corners, and it is the frame. */\n.sl-modal-frame > .sl-picker{border-radius:0}\n@media(max-width:640px){.sl-modal-scrim{padding:0}.sl-modal-frame{width:100%;height:100%;border-radius:0}}\n`;\n\nfunction ensureStyle(): void {\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\n/**\n * The header's start time, in the EVENT's zone.\n *\n * Exported for the test that pins the one rule this exists for: every surface\n * that prints an event's start time prints the same time. A zone Intl cannot\n * use throws, and the fallback is the reader's own clock — worse than the\n * venue's, far better than a header with a hole in it.\n */\nexport function formatWhen(startsAt: number, timezone: string | null, locale?: string): string {\n const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' };\n const at = new Date(startsAt);\n if (timezone) {\n try {\n return at.toLocaleString(locale, { ...options, timeZone: timezone });\n } catch {\n /* falls through to the reader's own zone */\n }\n }\n return at.toLocaleString(locale, options);\n}\n\n/** Merge order: defaults ← org chart theme ← host overrides. */\nfunction resolveTokens(chart: ChartTheme | undefined, host: SeatPickerTheme | undefined): Record<string, string> {\n const accent = host?.accent ?? chart?.accent ?? '#f4b740';\n const accentInk = host?.accentInk ?? chart?.accentInk ?? '#1a1200';\n return {\n '--sl-accent': accent,\n '--sl-accent-ink': accentInk,\n '--sl-bg': host?.background ?? chart?.background ?? '#0f1522',\n '--sl-surface': host?.surface ?? '#1a2234',\n '--sl-text': host?.text ?? chart?.textColor ?? '#eef1f8',\n '--sl-muted': host?.muted ?? '#8b93a7',\n '--sl-line': host?.line ?? 'rgba(139,147,167,.22)',\n '--sl-font': host?.fontFamily ?? chart?.fontFamily ?? \"-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,sans-serif\",\n '--sl-radius': `${host?.radius ?? 14}px`,\n };\n}\n\n/**\n * Colorblind-safe preference is a SHARED buyer preference across every SeatLayer\n * surface (the bespoke public page persists it too), so the widget reads/writes\n * the SAME localStorage key. All access is guarded — private-mode/SSR safe.\n */\nconst CB_STORAGE_KEY = 'seatmap.a11y.cb';\nfunction readStoredColorblind(): boolean | null {\n try {\n if (typeof window === 'undefined') return null;\n const raw = window.localStorage.getItem(CB_STORAGE_KEY);\n return raw == null ? null : raw === '1';\n } catch {\n return null;\n }\n}\nfunction writeStoredColorblind(on: boolean): void {\n try {\n window.localStorage.setItem(CB_STORAGE_KEY, on ? '1' : '0');\n } catch {\n /* private mode / storage disabled — preference is best-effort */\n }\n}\n\nexport class SeatPicker {\n private readonly opts: SeatPickerOptions;\n private readonly api: PickerTransport;\n /** Authenticated view media, cached only for this picker lifetime. */\n private readonly buyerAssetUrls: BuyerAssetObjectUrls;\n /** Our own public client, or null when the host injected a transport. */\n private readonly pubApi: PubApi | null;\n /** Null for the ordinary public picker — the tokenless path is untouched. */\n private readonly access: BuyerAccessContext | null;\n private realtime: BuyerRealtimeClient | null = null;\n private accessEl: HTMLDivElement | null = null;\n private readonly apiBase: string;\n private readonly controller: PickerController;\n private readonly maxTickets: number;\n /** Original host pricing, kept separate from live server offer overrides. */\n private readonly hostPricing: SeatPickerPricing | undefined;\n\n private root: HTMLDivElement | null = null;\n private mapHost: HTMLDivElement | null = null;\n private rendered = false;\n private destroyed = false;\n\n // chrome refs\n private els: Record<string, HTMLElement> = {};\n /** Feature 6 anchor regions — positioned flex containers over the map. */\n private regions: Record<string, HTMLElement> = {};\n private ro: ResizeObserver | null = null;\n private holdTimer: ReturnType<typeof setInterval> | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private offerRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n /** Armed only when the offer schedule has a known future transition (or as a\n * bounded retry after a failed read) — never a fixed-cadence poll. */\n private offerBoundaryTimer: ReturnType<typeof setTimeout> | null = null;\n private offerVisibilityHandler: (() => void) | null = null;\n /** Short-lived UI motion timers; all are cancelled on destroy. */\n private motionTimers = new Set<ReturnType<typeof setTimeout>>();\n\n // state\n private currency = 'USD';\n private eventTimezone: string | null = null;\n /** The event's formatted date-time (event-zone), reused by the closed-state note. */\n private eventWhenText: string | null = null;\n private offerAvailability: TicketOfferAvailability | null = null;\n private hold: HoldResult | null = null;\n /** Latest server expiry for the open hold (moves on extend). */\n private holdExpiresAt = 0;\n /** True once we handed off to checkout — arms booked-confirmation detection. */\n private handedOff = false;\n /** Guards single onBooked + single success overlay per hold. */\n private bookedShown = false;\n /**\n * `'hosted'` only when the host asked for it AND the widget owns its own\n * transport. Resolved once in the constructor so every later read is a field\n * comparison rather than a re-derivation that could drift.\n */\n private readonly checkoutMode: 'handoff' | 'hosted';\n /**\n * In-flight or settled `payment-options` for this event, started at render in\n * hosted mode. One request, kicked off while the buyer is still choosing, so\n * pressing Pay does not wait on a lookup whose answer never changes mid-session.\n */\n private paymentOptions: Promise<PaymentOptionsResult> | null = null;\n /** The mounted payment card, while one is up. */\n private checkoutPanel: CheckoutHandle | null = null;\n private extendEl: HTMLDivElement | null = null;\n private bookedEl: HTMLDivElement | null = null;\n private gaQty = new Map<string, number>();\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private confirmEl: HTMLDivElement | null = null;\n private confirmSeat: ExpandedSeat | null = null;\n private tableDialogEl: HTMLDivElement | null = null;\n private tableDialog: TableSelectionDetails | null = null;\n private tableDialogHeld = false;\n private tableDialogReturnFocus: HTMLElement | null = null;\n private srEl: HTMLDivElement | null = null;\n private baQty = 2;\n private baCat = '';\n /** Optional navigation-zone scope for buyer best-available. */\n private baZone = '';\n /** \"★ Best seats\" premium quick-pick toggle — biases best-available to premium seats. */\n private baPremium = false;\n private bestAvailableConfirm = false;\n private releasingHold = false;\n /** Event sales window is closed (read-only load state / live close). */\n private salesClosed = false;\n /** Every seated category's live availability is 0 (sold-out overlay is up). */\n private soldOut = false;\n private soldoutEl: HTMLDivElement | null = null;\n /** Resolved colorblind-safe state — stored preference wins over the option. */\n private cbSafe = false;\n\n // arena / multi-floor / seat-view chrome\n private rungsEl: HTMLDivElement | null = null;\n private projectionEl: HTMLDivElement | null = null;\n // --- 3D venue view (Map | 3D) ---\n private buyerView: 'map' | 'venue3d' = 'map';\n private view3dEl: HTMLDivElement | null = null;\n private view3dHandle: Venue3DHandle | null = null;\n /** Monotonic token so a stale async mount (buyer left before OGL finished\n * loading) never installs its handle over a newer state. */\n private view3dGen = 0;\n /** Seat whose 2D confirm card launched \"See it in 3D\"; re-shown on return. */\n private view3dReturnSeat: ExpandedSeat | null = null;\n /** Current premium 3D journey depth. `null` is the venue; a seat id is the\n * fixed seat-eye state. It lets Back unwind one step before leaving 3D. */\n private view3dTargetSeatId: string | null = null;\n /** Inspection-only comparison. These ids never represent cart selection. */\n private view3dCompareSeatIds: string[] = [];\n private view3dCompareChip: HTMLDivElement | null = null;\n private view3dCompareEl: HTMLDivElement | null = null;\n private view3dCompareCleanup: (() => void) | null = null;\n private view3dPassportEl: HTMLDivElement | null = null;\n private view3dPassportCleanup: (() => void) | null = null;\n private floorsEl: HTMLDivElement | null = null;\n private secCardEl: HTMLDivElement | null = null;\n private viewEl: HTMLDivElement | null = null;\n private viewCleanup: (() => void) | null = null;\n /** Supersedes an older authored-view byte request when another seat is opened. */\n private seatViewGen = 0;\n private allSeatsCache: ExpandedSeat[] | null = null;\n\n // F3 minimap\n private miniCanvas: HTMLCanvasElement | null = null;\n private miniBase: HTMLCanvasElement | null = null;\n private miniTf: { scale: number; offX: number; offY: number; dpr: number } | null = null;\n\n // F4 price-band filter — active band's category keys (null = all prices)\n private priceBandKeys: Set<string> | null = null;\n private focusedCatKey: string | null = null;\n /** \"Hide limited-view seats\" — mirrored into 3D by `seatState3dFor`. */\n private limitedViewFilter = false;\n private pricesExpanded = false;\n /** Last surfaced section summary (re-rendered when the price band changes). */\n private lastSection: SectionSummary | null = null;\n /** Section card collapsed to its slim pill (seat-picking has begun). */\n private secCardCollapsed = false;\n /** When the card was (re)shown — the focus glide's own view change must not collapse it. */\n private secCardShownAt = 0;\n /** Previous tray ticket count — first 0→n transition auto-expands the mobile sheet. */\n private lastTrayCount = 0;\n /** Previous computed total — drives a single explanatory value bump. */\n private lastTrayTotal = 0;\n /** Stable item keys prevent tray chips re-animating on unrelated realtime syncs. */\n private lastTrayKeys = new Set<string>();\n private bestAvailableBusy = false;\n private releasingLabels = new Set<string>();\n /** Selected labels awaiting the hold response; their own realtime echo can arrive first. */\n private holdingLabels = new Set<string>();\n private ctaPhase: 'idle' | 'holding' | 'checkout' = 'idle';\n // narrow-layout chrome that docks into the sheet's Filters row on mobile\n private a11yChipsEl: HTMLDivElement | null = null;\n private fsFallback = false;\n private fsChangeHandler: (() => void) | null = null;\n private fsEscHandler: ((e: KeyboardEvent) => void) | null = null;\n /** Host-level event chrome owns the duplicate identity outside full screen. */\n private eventDetailsHidden = false;\n /** Wide-layout ticket panel collapsed (map owns the full width). */\n private sideCollapsed = false;\n private sideToggleEl: HTMLButtonElement | null = null;\n /** True once we've asked the host page to pin us fullscreen (framed, no native). */\n private framedFs = false;\n /** Last height (px) posted to a host frame; dedupes redundant reports. */\n private lastPostedHeight = 0;\n\n /** True when the chart carries a real performance anchor — a stage-kind shape.\n * Every chart has a `focalPoint` (a bare look-at coordinate), so its presence\n * alone never justifies a \"to stage\" claim; only an actual stage does. */\n private chartHasStage(): boolean {\n const doc = this.controller.doc;\n if (!doc) return false;\n const objectSets = doc.floors?.length ? doc.floors.map((f) => f.objects ?? []) : [doc.objects ?? []];\n for (const objects of objectSets) {\n for (const obj of objects) {\n if (obj.type === 'shape' && (obj.role === 'stage' || obj.stageKind)) return true;\n }\n }\n return false;\n }\n\n /**\n * Eager sightline preview for the confirm card: the organizer's real view\n * photo, or — only when the chart has an actual stage to look at — a generated\n * forward view plus an approximate distance-to-stage line. On a stageless\n * chart both the distance claim and the generic stage silhouette are\n * invented promises, so we suppress them; a real attached photo always shows.\n * (OV-52)\n */\n private confirmThumbHtml(seat: ExpandedSeat): string {\n const doc = this.controller.doc;\n if (!doc) return '';\n const realPhoto = seat.viewUrl ?? '';\n const hasStage = this.chartHasStage();\n // No organizer photo AND no stage to measure against → nothing honest to show.\n if (!realPhoto && !hasStage) return '';\n let distance: number | null = null;\n if (!realPhoto) {\n try {\n // Rendered only for its distance figure — the synthetic image itself is\n // deliberately NOT shown at card size, where it reads as a cheap fake\n // photo (owner call 2026-07-24). Full-screen is where generated views\n // earn their keep; the card keeps a plain \"View from here\" button.\n const thumb = generateSeatThumb(seat, seat.focalPoint ?? doc.focalPoint);\n distance = thumb.distanceM ?? null;\n } catch {\n return '';\n }\n }\n // Distance is geometric and defensible. Visibility is not: the procedural\n // model has no columns, rails, overhangs or other obstruction geometry.\n const sightHtml = hasStage && distance != null\n ? `<div class=\"sl-confirm-sight\">${t('picker.sightline', { m: distance })}</div>`\n : '';\n const viewBtn = realPhoto\n ? `<button type=\"button\" class=\"sl-confirm-view sl-confirm-thumbwrap\" aria-label=\"${t('picker.viewFromSeat', { label: seat.label })}\">` +\n // Filled after mount through the binary transport. A direct <img src>\n // cannot attach the Event's buyer bearer.\n `<img class=\"sl-confirm-thumb\" alt=\"\" />` +\n `<span class=\"sl-confirm-thumb-badge\">🔭 ${this.tf('picker.viewFromHere', 'View from here')}</span>` +\n `</button>`\n : `<button type=\"button\" class=\"sl-confirm-view sl-confirm-viewbtn\" aria-label=\"${t('picker.viewFromSeat', { label: seat.label })}\">` +\n `<span aria-hidden=\"true\">🔭</span><span>${this.tf('picker.viewFromHere', 'View from here')}</span>` +\n `</button>`;\n return viewBtn + sightHtml;\n }\n\n /** \"See it in 3D\" (2D) / \"View from this seat\" (already in 3D) action for the\n * confirm card. Only when 3D is available — the purchase-moment bridge into\n * the cinematic that reaches buyers who never press the Map | 3D toggle. */\n private see3dConfirmHtml(): string {\n if (!this.canOffer3d()) return '';\n const label = this.buyerView === 'venue3d'\n ? this.tf('picker.viewFromThisSeat', 'View from this seat')\n : this.tf('picker.seeItIn3d', 'See it in 3D');\n return (\n `<button type=\"button\" class=\"sl-confirm-3d\" aria-label=\"${label}\">`\n + '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 2l9 5v10l-9 5-9-5V7z\"/><path d=\"M12 12l9-5M12 12v10M12 12L3 7\"/></svg>'\n + `<span>${label}</span></button>`\n );\n }\n\n /** Minimal HTML/attribute escaper for buyer-authored commercial text (notes). */\n private escCx(value: unknown): string {\n return String(value ?? '').replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n }\n\n /** Localized \"Restricted view\" / \"Obstructed view\" label for a seat's flags,\n * or '' when neither is set. Restricted takes precedence when both are on. */\n private limitedViewLabel(c: SeatCommercialAttributes | undefined): string {\n if (c?.restrictedView) return this.tf('picker.restrictedView', 'Restricted view');\n if (c?.obstructedView) return this.tf('picker.obstructedView', 'Obstructed view');\n return '';\n }\n\n /**\n * Commercial flags block for the confirm/detail surface: a subtle ★ Premium\n * tag plus an amber ◐ limited-view caution (with the organizer's note when\n * present). '' when the seat carries no surfaced commercial flag.\n */\n private commercialConfirmHtml(c: SeatCommercialAttributes | undefined): string {\n if (!c) return '';\n const rows: string[] = [];\n if (c.premium) {\n rows.push(\n `<div class=\"sl-cx-premium\"><span class=\"sl-cx-star\" aria-hidden=\"true\">★</span>${this.tf('picker.premiumSeat', 'Premium seat')}</div>`,\n );\n }\n const limited = this.limitedViewLabel(c);\n if (limited) {\n rows.push(\n `<div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">◐</span>` +\n `<span class=\"sl-cx-txt\"><b>${limited}</b>${c.note ? `<span class=\"sl-cx-note\">${this.escCx(c.note)}</span>` : ''}</span></div>`,\n );\n } else if (c.note) {\n // A note with no view flag (e.g. seller info) still deserves a calm line.\n rows.push(\n `<div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">ℹ</span>` +\n `<span class=\"sl-cx-txt\"><span class=\"sl-cx-note\">${this.escCx(c.note)}</span></span></div>`,\n );\n }\n return rows.length ? `<div class=\"sl-cx\">${rows.join('')}</div>` : '';\n }\n\n /** Small ◐ limited-view marker for a cart chip; title/aria uses the seat's\n * note when present, else the generic view label. '' for a clear-view seat. */\n private commercialChipMarker(c: SeatCommercialAttributes | undefined): string {\n const limited = this.limitedViewLabel(c);\n if (!limited) return '';\n const title = this.escCx(c?.note ? c.note : limited);\n return `<span class=\"sl-cx-mark\" role=\"img\" aria-label=\"${title}\" title=\"${title}\">◐</span>`;\n }\n\n private wheelchairProvisionLabel(type: 'seat-present' | 'no-seat' | undefined): string {\n if (type === 'no-seat') return 'Empty wheelchair space';\n if (type === 'seat-present') return 'Accessible physical seat';\n return '';\n }\n\n private wheelchairConfirmHtml(type: 'seat-present' | 'no-seat' | undefined): string {\n const label = this.wheelchairProvisionLabel(type);\n return label\n ? `<div class=\"sl-cx\"><div class=\"sl-cx-warn\"><span class=\"sl-cx-glyph\" aria-hidden=\"true\">♿</span><span class=\"sl-cx-txt\"><b>${label}</b></span></div></div>`\n : '';\n }\n\n private wheelchairChipMarker(type: 'seat-present' | 'no-seat' | undefined): string {\n const label = this.wheelchairProvisionLabel(type);\n return label\n ? `<span class=\"sl-cx-mark\" role=\"img\" aria-label=\"${label}\" title=\"${label}\">♿</span>`\n : '';\n }\n\n /** True when the picker is rendered inside an iframe (snippet embed at /e/:key). */\n private isFramed(): boolean {\n return typeof window !== 'undefined' && window.parent !== window;\n }\n\n /**\n * Post a widget→host message when framed. targetOrigin is '*' because the\n * payload carries nothing sensitive (a height number / a fullscreen flag);\n * hosts verify `event.origin` on their side (see `attachPickerFrame`).\n */\n private postToHost(message: { type: string; [key: string]: unknown }): void {\n if (!this.isFramed()) return;\n try {\n window.parent.postMessage(message, '*');\n } catch {\n /* a hostile/cross-origin parent may reject postMessage — nothing to do */\n }\n }\n\n /**\n * Height (px) to advertise to a host frame.\n *\n * The picker fills whatever box it's given: `.sl-picker` is `height:100%;\n * overflow:hidden`, and the /e/:key shell mounts it `position:fixed; inset:0`.\n * So it has no intrinsic *document* height to read — `scrollHeight` just\n * collapses to the current viewport, which for a framed embed would echo the\n * host's own iframe height straight back (a circular value). We therefore\n * report a width-driven *desired* height: a pleasant landscape box on desktop,\n * taller on narrow widths where the bottom sheet needs room, clamped to the\n * widget's `min-height` of 420. Width is host-controlled and never moves in\n * response to the height we report, so this cannot feedback-loop.\n */\n private measureFramedHeight(): number {\n const root = this.root;\n if (!root) return 0;\n const width = root.clientWidth || (typeof window !== 'undefined' ? window.innerWidth : 0) || 0;\n if (width <= 0) return 0;\n const ratio = width < 640 ? 1.2 : 0.62;\n return Math.max(420, Math.round(width * ratio));\n }\n\n /** Post `seatlayer:height` to the host when framed and the value changed. */\n private reportFramedHeight(): void {\n if (!this.isFramed()) return;\n const px = this.measureFramedHeight();\n if (px <= 0 || px === this.lastPostedHeight) return;\n this.lastPostedHeight = px;\n this.postToHost({ type: 'seatlayer:height', px });\n }\n\n /** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */\n private toggleFullscreen(): void {\n const root = this.root;\n if (!root) return;\n const active = !!document.fullscreenElement || this.fsFallback || this.framedFs;\n if (!active) {\n if (root.requestFullscreen) {\n root.requestFullscreen().catch(() => this.enterFsFallback());\n } else {\n this.enterFsFallback();\n }\n } else if (document.fullscreenElement) {\n void document.exitFullscreen().catch(() => {});\n } else if (this.framedFs) {\n this.setFramedFs(false);\n } else {\n this.setFsFallback(false);\n }\n }\n\n private syncFullscreenButtons(): void {\n const active = !!document.fullscreenElement || this.fsFallback || this.framedFs;\n // Full screen removes the surrounding page/popup from view, so the SDK\n // restores the FULL identity row it had demoted while inline. Demoted, not\n // hidden: the compact line survives scroll, sheet-over-map and tab\n // comparison — CSS owns the presentation off this one attribute.\n const hideEventDetails = this.eventDetailsHidden && !active;\n this.root?.setAttribute('data-event-details-hidden', String(hideEventDetails));\n this.els.zfs?.setAttribute('aria-pressed', String(active));\n this.els.zfs?.setAttribute('title', active ? 'Exit full screen' : 'Full screen');\n const zfsLabel = this.els.zfs?.querySelector<HTMLElement>('.sl-zfs-lbl');\n if (zfsLabel) zfsLabel.textContent = active ? 'Exit full screen' : 'Full screen';\n this.view3dEl?.querySelector<HTMLButtonElement>('.sl-view3d-fs')\n ?.setAttribute('aria-pressed', String(active));\n }\n\n /**\n * Native element-fullscreen was unavailable or rejected. When framed, a CSS\n * `.sl-fs` overlay can't escape the iframe, so we ask the host page to pin us\n * (`seatlayer:fullscreen`). Otherwise (iOS Safari, same document) fall back to\n * the `.sl-fs` overlay as before.\n */\n private enterFsFallback(): void {\n if (this.isFramed()) this.setFramedFs(true);\n else this.setFsFallback(true);\n }\n\n /** Toggle host-driven (framed) fullscreen: post the flag + own the Esc key. */\n private setFramedFs(on: boolean): void {\n if (this.framedFs === on) return;\n this.framedFs = on;\n this.syncFullscreenButtons();\n this.postToHost({ type: 'seatlayer:fullscreen', on });\n if (on && !this.fsEscHandler) {\n this.fsEscHandler = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && !document.fullscreenElement) this.setFramedFs(false);\n };\n window.addEventListener('keydown', this.fsEscHandler);\n } else if (!on && this.fsEscHandler) {\n window.removeEventListener('keydown', this.fsEscHandler);\n this.fsEscHandler = null;\n }\n requestAnimationFrame(() => this.controller.zoomToFit());\n }\n\n private setFsFallback(on: boolean): void {\n if (this.fsFallback === on) return;\n this.fsFallback = on;\n this.root?.classList.toggle('sl-fs', on);\n this.syncFullscreenButtons();\n if (on && !this.fsEscHandler) {\n this.fsEscHandler = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && !document.fullscreenElement) this.setFsFallback(false);\n };\n window.addEventListener('keydown', this.fsEscHandler);\n } else if (!on && this.fsEscHandler) {\n window.removeEventListener('keydown', this.fsEscHandler);\n this.fsEscHandler = null;\n }\n requestAnimationFrame(() => this.controller.zoomToFit());\n }\n private cbEl: HTMLButtonElement | null = null;\n\n // modal plumbing (set by open())\n private modalScrim: HTMLElement | null = null;\n private prevFocus: HTMLElement | null = null;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n /** Set by open(): closes the modal (scroll restore + destroy + onClose). */\n private closeModal: (() => void) | null = null;\n\n /**\n * Close the picker. In modal mode (SeatPicker.open()) this dismisses the\n * modal exactly like ESC/scrim/✕ — restores page scroll and fires onClose.\n * For inline mounts it simply destroys the widget.\n */\n close(): void {\n if (this.closeModal) this.closeModal();\n else this.destroy();\n }\n\n /** Mount the full picker as a document-level modal. Resolves after render. */\n static async open(options: Omit<SeatPickerOptions, 'container'>): Promise<SeatPicker> {\n ensureStyle();\n const priorFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const scrim = document.createElement('div');\n scrim.className = 'sl-modal-scrim';\n const frame = document.createElement('div');\n frame.className = 'sl-modal-frame';\n frame.setAttribute('role', 'dialog');\n frame.setAttribute('aria-modal', 'true');\n frame.setAttribute('aria-label', 'Seat selection');\n frame.tabIndex = -1;\n scrim.appendChild(frame);\n document.body.appendChild(scrim);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n const picker = new SeatPicker({ ...options, container: frame });\n picker.modalScrim = scrim;\n picker.prevFocus = priorFocus;\n\n const focusableSelector = [\n 'a[href]', 'area[href]', 'button', 'input', 'select', 'textarea',\n 'iframe', 'object', 'embed', 'summary', 'audio[controls]', 'video[controls]',\n '[contenteditable]:not([contenteditable=\"false\"])', '[tabindex]',\n ].join(',');\n const activeDialog = (): HTMLElement => {\n const nested = [...frame.querySelectorAll<HTMLElement>('[role=\"dialog\"][aria-modal=\"true\"]')]\n .filter((dialog) => dialog.isConnected && !dialog.closest('[hidden], [aria-hidden=\"true\"], [inert]'));\n return nested[nested.length - 1] ?? frame;\n };\n const hiddenWithin = (element: HTMLElement, scope: HTMLElement): boolean => {\n let current: HTMLElement | null = element;\n while (current) {\n const style = window.getComputedStyle(current);\n if (\n current.hidden\n || current.getAttribute('aria-hidden') === 'true'\n || current.hasAttribute('inert')\n || style.display === 'none'\n || style.visibility === 'hidden'\n || style.visibility === 'collapse'\n ) return true;\n if (current === scope) return false;\n current = current.parentElement;\n }\n return true;\n };\n const tabbableWithin = (scope: HTMLElement): HTMLElement[] =>\n [...scope.querySelectorAll<HTMLElement>(focusableSelector)]\n .filter((element) => element.tabIndex >= 0 && !element.matches(':disabled') && !hiddenWithin(element, scope));\n const focusEdge = (scope: HTMLElement, backwards: boolean): void => {\n const tabbable = tabbableWithin(scope);\n const target = backwards ? tabbable[tabbable.length - 1] : tabbable[0];\n if (target) target.focus({ preventScroll: true });\n else {\n if (!scope.hasAttribute('tabindex')) scope.tabIndex = -1;\n scope.focus({ preventScroll: true });\n }\n };\n\n let closing = false;\n const close = (): void => {\n if (closing) return;\n closing = true;\n document.body.style.overflow = prevOverflow;\n // Remove the modal and its document-level keyboard containment immediately,\n // while still letting an abandoned auto-hold finish releasing before the\n // transport is torn down.\n if (picker.escHandler) document.removeEventListener('keydown', picker.escHandler);\n scrim.remove();\n picker.modalScrim = null;\n const restoreTarget = picker.prevFocus;\n picker.prevFocus = null;\n if (restoreTarget?.isConnected) restoreTarget.focus({ preventScroll: true });\n const finish = (): void => {\n picker.destroy();\n options.onClose?.();\n };\n if (picker.hold && !picker.handedOff) void picker.release().finally(finish);\n else finish();\n };\n picker.closeModal = close;\n scrim.addEventListener('mousedown', (e) => {\n if (e.target === scrim) close();\n });\n picker.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n if (e.defaultPrevented) return;\n const scope = activeDialog();\n const tabbable = tabbableWithin(scope);\n const first = tabbable[0];\n const last = tabbable[tabbable.length - 1];\n const active = document.activeElement;\n if (!first || !last) {\n e.preventDefault();\n focusEdge(scope, e.shiftKey);\n } else if (active === scope || !active || !scope.contains(active)) {\n e.preventDefault();\n (e.shiftKey ? last : first).focus({ preventScroll: true });\n } else if (e.shiftKey && active === first) {\n e.preventDefault();\n last.focus({ preventScroll: true });\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus({ preventScroll: true });\n }\n return;\n }\n if (e.key !== 'Escape') return;\n if (picker.tableDialog) {\n e.preventDefault();\n picker.cancelTableDialog();\n } else if (picker.confirmSeat) {\n e.preventDefault();\n picker.cancelConfirm();\n } else if (picker.bestAvailableConfirm) {\n e.preventDefault();\n picker.bestAvailableConfirm = false;\n picker.syncTray();\n } else {\n e.preventDefault();\n close();\n }\n };\n document.addEventListener('keydown', picker.escHandler);\n await picker.render();\n picker.els.close?.classList.add('on');\n picker.els.close?.addEventListener('click', close);\n focusEdge(activeDialog(), false);\n return picker;\n }\n\n constructor(options: SeatPickerOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n if (!options.container) throw new Error('seatmap: `container` is required (or use SeatPicker.open())');\n this.opts = { ...options, confirmSelection: options.confirmSelection ?? true };\n this.eventDetailsHidden = !!options.hideEventDetails;\n this.hostPricing = options.pricing;\n this.apiBase = (options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, '');\n // A host-supplied transport owns its own credentials, so the access context\n // is only built for our own PubApi.\n this.access = options.transport\n ? null\n : createBuyerAccessContext(options, {\n onExpired: (event) => {\n this.opts.onAccessExpired?.(event);\n if (!event.refreshed) this.showAccessPanel({ reason: 'no_token', retryable: false });\n },\n onUnavailable: (event) => {\n this.opts.onAccessUnavailable?.(event);\n this.showAccessPanel(event);\n },\n });\n this.pubApi = options.transport\n ? null\n : new PubApi(this.apiBase, {\n access: this.access ?? undefined,\n onObjectUnavailable: (event) => this.opts.onSelectedObjectUnavailable?.(event),\n });\n this.api = options.transport ?? this.pubApi!;\n this.buyerAssetUrls = new BuyerAssetObjectUrls(\n options.event,\n this.api.asset ? (key, asset) => this.api.asset!(key, asset) : undefined,\n );\n // Hosted checkout talks to OUR /pub routes with OUR client. A host that\n // injected a transport owns its backend and its credentials, and quietly\n // reaching past it to api.seatlayer.io would be the widget deciding where a\n // buyer's money goes. Refuse out loud, once, and stay on the default.\n if (options.checkout === 'hosted' && !this.pubApi) {\n console.warn(\n 'seatlayer: checkout: \"hosted\" needs the widget\\'s own transport — a custom `transport` '\n + 'owns its backend, so the picker is staying on onCheckout for this mount.',\n );\n }\n this.checkoutMode = options.checkout === 'hosted' && this.pubApi ? 'hosted' : 'handoff';\n this.maxTickets = Math.max(1, Math.floor(options.maxSelection ?? DEFAULT_MAX_SELECTION));\n // Colorblind preference: the stored (cross-surface) value wins over the\n // option; the option is only the initial default when nothing is stored.\n this.cbSafe = readStoredColorblind() ?? !!options.colorblindSafe;\n this.controller = new PickerController({\n transport: this.api,\n eventKey: options.event,\n maxSelection: this.maxTickets,\n currency: options.currency,\n flashOnLiveChange: true,\n colorblindSafe: this.cbSafe,\n // The drawn map's own overrides, when the host supplied them up front.\n // Everything else on `theme` is CSS and lands on the root instead.\n mapTheme: options.theme?.map ?? null,\n onSelectionChange: () => {\n this.syncTray();\n // Seat-picking has begun — collapse the section card out of the way.\n if (this.committedSelection().length) this.collapseSectionCard();\n // Keep the 3D overlay's selection highlight in lockstep (both directions).\n this.syncSelectionTo3d();\n },\n onStatusChange: () => {\n this.syncPrices();\n this.scheduleOfferRefresh(true);\n this.evictTakenSelections();\n this.detectBooked();\n // Live open/close of a section repaints the minimap's static overview.\n this.refreshMinimap();\n // Mirror every live availability delta into the 3D view while it's open.\n this.pushAvailabilityTo3d();\n },\n onHoldExpired: () => {\n this.hold = null;\n this.forgetHold();\n this.handedOff = false;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.stopHoldTimer();\n this.gaQty.clear();\n this.toast(t('picker.holdExpired', undefined) || 'Your hold expired — seats released. Pick again.', 'warning');\n this.syncTray();\n this.emitHoldChange();\n this.opts.onHoldExpired?.();\n },\n confirmSelection: this.opts.confirmSelection,\n onSelect: (seat) => {\n // Sales-closed is a read-only state — refuse the pick (the controller\n // doesn't gate tapping; server would 409 the eventual hold anyway).\n if (this.salesClosed) {\n this.controller.deselect([seat.id]);\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n // Grouped tables own a dedicated whole/guest-count dialog. The raw\n // chair callback is retained for compatibility, but must not open the\n // ordinary one-seat confirm card in this full buyer widget.\n if (this.controller.tableSelection(seat.id)) return;\n this.flashPickedSeat(seat.id);\n if (this.opts.confirmSelection) this.showConfirm(seat);\n },\n onTableSelectionRequest: (table) => {\n if (this.salesClosed) {\n this.controller.deselect(table.physicalSeatIds);\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n this.showTableDialog(table, false);\n },\n onDeselect: (seat) => {\n if (this.confirmSeat?.id === seat.id) this.dismissConfirm();\n if (this.tableDialog?.physicalSeatIds.includes(seat.id)) this.dismissTableDialog();\n },\n onSelectionLimit: () => {\n this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, 'warning');\n },\n onViewChange: () => {\n this.reanchorConfirm();\n this.syncRung();\n this.syncProjection();\n this.drawMinimapRect();\n this.sectionCardOnView();\n },\n // Tapped-section glide-in → surface (or clear) the section-summary card.\n onSectionFocus: (summary) => this.showSectionCard(summary),\n onFocusSeat: (seat) => this.announceSeat(seat),\n onSeatHover: (d) => this.updateTooltip(d),\n onHint: (m) => {\n if (m) this.toast(m);\n },\n // Server declared the event closed mid-session (409 event_closed) — keep\n // the toast (raised by handleCta), and add the persistent read-only state.\n onSalesClosed: () => this.setSalesClosed(true),\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n ensureStyle();\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Hosted checkout asks the server what this event can charge through while\n // the buyer is still looking at the map. The answer cannot change mid-\n // session, and asking now means pressing Pay is not gated on a round trip.\n // A rejection is caught at the point of use, not here — a widget must not\n // die because a payment lookup failed.\n if (this.checkoutMode === 'hosted') this.paymentOptions = this.pubApi!.paymentOptions(this.opts.event);\n\n const mount = resolveContainer(this.opts.container!);\n const root = document.createElement('div');\n root.className = 'sl-picker';\n root.tabIndex = -1;\n this.root = root;\n mount.appendChild(root);\n root.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n if (this.tableDialog) {\n e.preventDefault();\n e.stopPropagation();\n this.cancelTableDialog();\n } else if (this.confirmSeat) {\n e.preventDefault();\n e.stopPropagation();\n this.cancelConfirm();\n } else if (this.bestAvailableConfirm) {\n e.preventDefault();\n e.stopPropagation();\n this.bestAvailableConfirm = false;\n this.syncTray();\n }\n });\n\n // skeleton first — tokens get re-applied once the chart theme arrives\n Object.entries(resolveTokens(undefined, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n root.innerHTML = `\n <div class=\"sl-head\">\n <div class=\"sl-logo\" data-ref=\"logo\"></div>\n <div class=\"sl-head-info\" data-ref=\"headInfo\">\n <div class=\"sl-head-name\" data-ref=\"name\"></div>\n <div class=\"sl-head-meta\" data-ref=\"meta\"></div>\n </div>\n <span class=\"sl-hold-pill\" data-ref=\"hold\"></span>\n <span class=\"sl-closed-pill\" data-ref=\"closedPill\" role=\"status\">\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n <span data-ref=\"closedPillText\"></span>\n </span>\n <button type=\"button\" class=\"sl-close\" data-ref=\"close\" aria-label=\"Close\">\n <svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"sl-body\">\n <div class=\"sl-map\">\n <div class=\"sl-map-host\" data-ref=\"map\"></div>\n <div class=\"sl-zoom\" data-ref=\"zoom\">\n <button type=\"button\" aria-label=\"Zoom in\" title=\"Zoom in\" data-ref=\"zin\">+</button>\n <button type=\"button\" aria-label=\"Zoom out\" title=\"Zoom out\" data-ref=\"zout\">−</button>\n <button type=\"button\" aria-label=\"Fit to screen\" title=\"Fit to screen\" data-ref=\"zfit\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3\"/></svg>\n </button>\n <button type=\"button\" aria-label=\"Full screen\" title=\"Full screen\" aria-pressed=\"false\" data-ref=\"zfs\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"/></svg>\n <span class=\"sl-zfs-lbl\" aria-hidden=\"true\">Full screen</span>\n </button>\n </div>\n <div class=\"sl-boot\" data-ref=\"boot\"><span class=\"sl-boot-spin\"></span>Loading seat map…</div>\n <div class=\"sl-toast\" data-ref=\"toast\" role=\"status\" aria-live=\"polite\"></div>\n </div>\n <div class=\"sl-side\" data-ref=\"side\">\n <div class=\"sl-sheet-head\" data-ref=\"sheetHead\">\n <div class=\"sl-sheet-grab\"></div>\n <div class=\"sl-sheet-bar\">\n <div class=\"sl-sheet-peek\" data-ref=\"peek\"></div>\n <button type=\"button\" class=\"sl-sheet-toggle\" data-ref=\"sheetToggle\" aria-label=\"Open ticket panel\" aria-expanded=\"false\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"sl-sec sl-filtersec\" data-ref=\"filtersSec\">Filters</div>\n <div class=\"sl-filters\" data-ref=\"filters\"></div>\n <div class=\"sl-offer\" data-ref=\"offer\" role=\"status\" aria-live=\"polite\"></div>\n <div class=\"sl-sec sl-prices-sec\" data-ref=\"pricesSec\"><span>Ticket prices</span></div>\n <div class=\"sl-prices\" data-ref=\"prices\"></div>\n <div class=\"sl-live\" data-ref=\"live\" role=\"status\" aria-live=\"polite\"><span class=\"dot\" aria-hidden=\"true\"></span><span data-ref=\"liveText\">Live availability — seats update in real time</span></div>\n <div class=\"sl-sec sl-seats-sec\"><span>Your seats</span><span class=\"sl-seat-summary\" data-ref=\"seatSummary\"></span></div>\n <div class=\"sl-tray\" data-ref=\"tray\"></div>\n <div class=\"sl-foot\" data-ref=\"foot\">\n <div class=\"sl-hold-note\" data-ref=\"holdNote\" role=\"status\" aria-live=\"polite\">\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M20 6L9 17l-5-5\"/></svg>\n <span><b data-ref=\"holdTitle\">Seats secured</b><span class=\"sl-hold-copy\" data-ref=\"holdCopy\">Checkout timer is running.</span></span>\n <button type=\"button\" class=\"sl-hold-change\" data-ref=\"holdChange\" aria-label=\"Release held tickets and choose different seats\">Change</button>\n </div>\n <div class=\"sl-total\"><span data-ref=\"count\"></span><b data-ref=\"total\"></b></div>\n <button type=\"button\" class=\"sl-cta\" data-ref=\"cta\" disabled></button>\n </div>\n </div>\n </div>`;\n root.querySelectorAll<HTMLElement>('[data-ref]').forEach((el) => {\n this.els[el.dataset.ref!] = el;\n });\n this.mapHost = this.els.map as HTMLDivElement;\n this.syncFullscreenButtons();\n\n // Offer pricing belongs to the canonical picker, not only SeatLayer's own\n // page wrapper. One cached read at mount, then the picker is entirely\n // event-driven: live seat frames trigger a no-store refresh via\n // `onStatusChange`, a successful read arms a timer for the next SCHEDULED\n // transition (a window opening/closing — the one change no seat frame\n // announces), and regaining visibility re-reads once. There is no fixed\n // cadence — a 10s interval here once made a handful of forgotten tabs the\n // top row of the platform's entire Durable Object bill.\n void this.refreshOfferAvailability(false);\n if (this.api.availability) {\n this.offerVisibilityHandler = (): void => {\n if (!document.hidden && !this.destroyed) void this.refreshOfferAvailability(false);\n };\n document.addEventListener('visibilitychange', this.offerVisibilityHandler);\n }\n\n // container-adaptive layout (breakpoint keys off the CONTAINER, not the viewport)\n const applyLayout = (): void => {\n const w = root.clientWidth;\n if (w <= 0) return;\n // Report our desired height to a host frame on every size change (deduped),\n // not just when the layout breakpoint flips below.\n this.reportFramedHeight();\n const next = w < 640 ? 'narrow' : 'wide';\n const density = root.clientHeight < 560 ? 'compact' : 'comfortable';\n if (root.dataset.layout === next && root.dataset.density === density) return;\n root.dataset.layout = next;\n root.dataset.density = density;\n // Entering the mobile sheet layout: start in the peek state (map-first).\n if (next === 'narrow' && !root.dataset.sheet) root.dataset.sheet = 'peek';\n this.dockLayoutChrome();\n };\n this.ro = new ResizeObserver(applyLayout);\n this.ro.observe(root);\n // Some environments defer the ResizeObserver's initial callback (backgrounded\n // tabs throttle delivery). Seed the layout synchronously + next frame so a\n // container that mounts already-wide gets data-layout=\"wide\" immediately,\n // instead of waiting on a resize that may never arrive.\n applyLayout();\n requestAnimationFrame(applyLayout);\n\n // zoom + tooltip wiring\n this.els.zin.addEventListener('click', () => this.controller.zoomIn());\n this.els.zout.addEventListener('click', () => this.controller.zoomOut());\n this.els.zfit.addEventListener('click', () => this.controller.zoomToFit());\n // Full screen: native API with a CSS-fallback overlay for iOS Safari\n // (which has no element fullscreen). Esc exits both paths; the renderer's\n // ResizeObserver re-fits, plus an explicit zoomToFit for a crisp frame.\n this.els.zfs.addEventListener('click', () => this.toggleFullscreen());\n this.fsChangeHandler = (): void => {\n if (!document.fullscreenElement) this.setFsFallback(false);\n this.syncFullscreenButtons();\n requestAnimationFrame(() => this.controller.zoomToFit());\n };\n document.addEventListener('fullscreenchange', this.fsChangeHandler);\n\n // Mobile bottom sheet: swipe/tap on the sheet HEAD only (never the map host,\n // so the map's raw-pointer gesture pipeline is untouched). Swipe up → open\n // (≤50%); swipe down → peek; a plain tap toggles. The section-card strip's\n // ✕ lives inside the head — taps on the card must not toggle the sheet.\n const head = this.els.sheetHead;\n if (head) {\n const toggle = this.els.sheetToggle as HTMLButtonElement | undefined;\n const setSheet = (open: boolean): void => {\n root.dataset.sheet = open ? 'open' : 'peek';\n toggle?.setAttribute('aria-expanded', String(open));\n toggle?.setAttribute('aria-label', open ? 'Collapse ticket panel' : 'Open ticket panel');\n };\n setSheet(root.dataset.sheet === 'open');\n toggle?.addEventListener('click', (e) => {\n e.stopPropagation();\n setSheet(root.dataset.sheet !== 'open');\n });\n /* Delegated, because the pill is re-rendered on every selection change and\n a listener bound to the node would be lost with it. */\n this.els.peek?.addEventListener('click', (e) => {\n const go = (e.target as HTMLElement).closest<HTMLElement>('.sl-sheet-go');\n if (!go) return;\n e.stopPropagation();\n if (go.dataset.act === 'checkout') void this.handleCta();\n else setSheet(true);\n });\n let startY = 0;\n let swiped = false;\n let tracking = false;\n head.addEventListener('pointerdown', (e: PointerEvent) => {\n /* THE CHEVRON DOUBLE-TOGGLED AND SO APPEARED DEAD.\n This handler captures the pointer, and capture RETARGETS every later\n event for it to the capturing element. So the pointerup below saw\n `e.target === head`, its `closest('.sl-sheet-toggle')` guard returned\n null, and the head toggled the sheet — then the button's own click\n toggled it back. Two toggles, no net change, and an owner reporting\n that tapping the arrow does nothing.\n\n The guard has to run HERE, where the target is still the real hit\n element: capture is set on this very line, so pointerdown is the last\n moment the truth is available. A press that starts on the toggle (or\n on a section card) is left entirely to that control. */\n if ((e.target as HTMLElement).closest?.('.sl-seccard,.sl-sheet-toggle,.sl-sheet-go')) {\n tracking = false;\n return;\n }\n tracking = true;\n swiped = false;\n startY = e.clientY;\n head.setPointerCapture?.(e.pointerId);\n });\n head.addEventListener('pointermove', (e: PointerEvent) => {\n if (!tracking || swiped) return;\n const dy = e.clientY - startY;\n if (dy < -18) {\n setSheet(true);\n swiped = true;\n } else if (dy > 18) {\n setSheet(false);\n swiped = true;\n }\n });\n head.addEventListener('pointerup', (e: PointerEvent) => {\n // The guard now lives in pointerdown, where the target has not been\n // retargeted by capture. Reaching here at all means the press did not\n // start on a control of its own.\n if (tracking && !swiped && Math.abs(e.clientY - startY) < 6) {\n setSheet(root.dataset.sheet !== 'open');\n }\n tracking = false;\n head.releasePointerCapture?.(e.pointerId);\n });\n }\n this.tipEl = document.createElement('div');\n this.tipEl.setAttribute('role', 'tooltip');\n this.tipEl.className = 'sl-tip';\n this.els.map.appendChild(this.tipEl);\n this.els.map.addEventListener('mousemove', (e: MouseEvent) => {\n const r = this.els.map.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n });\n\n this.els.cta.addEventListener('click', () => void this.handleCta());\n this.els.holdChange?.addEventListener('click', () => void this.handleChangeSeats());\n\n const canvasHost = document.createElement('div');\n canvasHost.style.cssText = 'position:absolute;inset:0';\n this.mapHost.appendChild(canvasHost);\n const info = await this.controller.render(canvasHost);\n if (this.destroyed) return this;\n if (!info) {\n this.els.boot.innerHTML =\n '<div class=\"sl-boot-title\">The seat map didn’t load</div>' +\n '<div>Check your connection and try again.</div>' +\n '<button type=\"button\" class=\"sl-boot-retry\">Try again</button>';\n this.els.boot.querySelector('button')!.addEventListener('click', () => {\n // full remount: cheapest reliable recovery\n const container = this.opts.container!;\n const opts = this.opts;\n this.destroy();\n void new SeatPicker({ ...opts, container }).render();\n });\n return this;\n }\n this.els.boot.remove();\n this.startRealtime();\n // Read-only load state: the chart payload is authoritative, while an\n // embedding host may deliberately make an otherwise-open map preview-only.\n this.salesClosed = !!info.salesClosed || !!this.opts.readOnly;\n root.dataset.eventMode = info.mode === 'test' ? 'test' : 'live';\n this.controller.setViewMode(this.normalizeInitialView(this.opts.initialView));\n\n // Feature 6: anchor regions for all persistent map chrome, then move the\n // pre-built zoom column + toast into their regions (both were in the skeleton).\n this.buildRegions();\n this.regions['bottom-right'].appendChild(this.els.zoom);\n this.regions['bottom-center'].appendChild(this.els.toast);\n\n if (info.mode === 'test') {\n // Environment context is a passive chip flowing FIRST in the top-left\n // region — inside the anchor system, so it can never be clipped by the\n // root's rounded overflow and never free-floats over other chrome.\n const badge = document.createElement('div');\n badge.className = 'sl-testbadge';\n badge.textContent = t('picker.testMode');\n badge.setAttribute('aria-label', t('picker.testMode'));\n this.regions['top-left'].appendChild(badge);\n }\n\n // theme: defaults ← org chart theme ← host overrides\n const chartTheme = this.controller.doc?.theme;\n Object.entries(resolveTokens(chartTheme, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n this.currency = info.currency ?? this.opts.currency ?? 'USD';\n this.eventTimezone = info.timezone ?? null;\n\n // header — a host/org brand logo wins; else the EVENT's own poster (the\n // strongest \"which event is this money for\" signal a thumbnail can give);\n // else the first letter as before.\n const logoUrl = this.opts.theme?.logoUrl ?? chartTheme?.logoUrl ?? info.posterUrl ?? null;\n if (logoUrl) this.els.logo.innerHTML = `<img src=\"${logoUrl}\" alt=\"\">`;\n else this.els.logo.textContent = (this.opts.theme?.brandName ?? chartTheme?.brandName ?? info.eventName ?? '?').slice(0, 1).toUpperCase();\n this.els.name.textContent = info.eventName ?? '';\n // THE EVENT'S ZONE, NOT THE READER'S. This line used to format in whatever\n // zone the browser happened to be in, while the hosted landing page around\n // it formatted the same instant in the venue's — so one page showed a gig\n // starting at two different times and gave a buyer no way to tell which one\n // the doors follow. An unusable zone string (a typo, a name this engine has\n // never heard of) throws inside Intl, and a header that cannot render is a\n // worse answer than the reader's own clock, so that case falls through.\n const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : '';\n this.eventWhenText = when || null;\n this.els.meta.textContent = [info.venue, when].filter(Boolean).join(' · ');\n\n // \"Powered by SeatLayer\" attribution badge — hidden when the host opts out\n // OR the org's paid chart theme sets hideBadge (either being true hides it).\n this.buildBadge(chartTheme);\n\n // Accessibility filter chips — only for types actually present in the chart.\n // Same sweep also detects whether ANY seat carries a limited-view (restricted\n // or obstructed) commercial flag, which gates the \"Hide limited-view seats\"\n // toggle that shares this chip row.\n const present = new Set<AccessibilityType>();\n let hasLimitedView = false;\n if (this.controller.doc) {\n for (const seat of expandChart(this.controller.doc)) {\n for (const type of seat.accessibility ?? []) present.add(type);\n if (seat.accessible && !seat.accessibility?.length) present.add('wheelchair');\n if (seat.commercial?.restrictedView || seat.commercial?.obstructedView) hasLimitedView = true;\n }\n }\n // Jump to the seats rung when a dimming filter turns on — the dimming only\n // renders at seat detail; applying it zoomed out would silently dim seats\n // the buyer can't see. Shared by the a11y chips and the limited-view toggle.\n const focusSeatsForFilter = (): void => {\n if (this.rungsEl && this.controller.getRung() !== 'seats') {\n this.controller.setRung('seats');\n this.collapseSectionCard();\n this.syncRung();\n }\n };\n if (present.size || hasLimitedView) {\n const chips = document.createElement('div');\n chips.className = 'sl-chips';\n this.regions['top-left'].appendChild(chips);\n this.a11yChipsEl = chips;\n\n if (present.size) {\n const mk = (key: AccessibilityType | 'all', label: string): string =>\n `<button type=\"button\" class=\"sl-chip-f${key === 'all' ? ' on' : ''}\" data-a11y=\"1\" data-f=\"${key}\">${label}</button>`;\n chips.insertAdjacentHTML('beforeend',\n mk('all', 'All seats') +\n ACCESSIBILITY_TYPES\n .filter(({ key }) => present.has(key))\n .map(({ key, short, icon }) => mk(key, `${icon} ${short}`))\n .join(''));\n // Multi-select OR semantics (parity with the buyer page): each type chip\n // toggles independently; the active filter is the union; \"All seats\"\n // clears. A buyer needing wheelchair AND companion seats combines both.\n const active = new Set<AccessibilityType>();\n const syncChips = (): void => {\n chips.querySelectorAll<HTMLButtonElement>('button[data-a11y]').forEach((b) => {\n const f = b.dataset.f as AccessibilityType | 'all';\n const on = f === 'all' ? active.size === 0 : active.has(f);\n b.classList.toggle('on', on);\n b.setAttribute('aria-pressed', String(on));\n });\n const filter = active.size ? [...active] : null;\n this.controller.setAccessibilityFilter(filter);\n if (filter) focusSeatsForFilter();\n };\n chips.querySelectorAll<HTMLButtonElement>('button[data-a11y]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const f = btn.dataset.f as AccessibilityType | 'all';\n if (f === 'all') active.clear();\n else if (active.has(f)) active.delete(f);\n else active.add(f);\n syncChips();\n });\n });\n }\n\n // \"Hide limited-view seats\" toggle — one independent on/off chip that dims\n // free seats flagged restricted/obstructed view (same chip pattern, sits\n // beside the a11y chips). Isolated from the a11y OR-union above.\n if (hasLimitedView) {\n const limited = document.createElement('button');\n limited.type = 'button';\n limited.className = 'sl-chip-f';\n limited.setAttribute('aria-pressed', 'false');\n limited.innerHTML = `◐ ${this.tf('picker.hideLimitedView', 'Hide limited-view seats')}`;\n chips.appendChild(limited);\n limited.addEventListener('click', () => {\n const limitedOn = !this.limitedViewFilter;\n this.limitedViewFilter = limitedOn;\n limited.classList.toggle('on', limitedOn);\n limited.setAttribute('aria-pressed', String(limitedOn));\n this.controller.setCommercialLimitedFilter(limitedOn);\n // Keep 3D in step — the filter must survive the switch between views.\n this.pushAvailabilityTo3d();\n if (limitedOn) focusSeatsForFilter();\n });\n }\n }\n\n // Colorblind-safe toggle rides in the zoom column (wide) or the sheet's\n // Filters row (narrow) — dockLayoutChrome moves it between the two.\n const cb = document.createElement('button');\n cb.type = 'button';\n cb.className = 'sl-cbbtn';\n this.cbEl = cb;\n cb.setAttribute('aria-label', 'Toggle colorblind-friendly colors');\n // Rehydrated from the shared preference (constructor read stored → this.cbSafe).\n cb.setAttribute('aria-pressed', String(this.cbSafe));\n cb.innerHTML = '<svg viewBox=\"0 0 24 24\"><path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>';\n this.els.zfit.parentElement!.appendChild(cb);\n // Route through the single source of truth so host chrome (e.g. the Designer\n // preview chip) and this in-widget button always agree.\n cb.addEventListener('click', () => { this.setColorblindSafe(!this.cbSafe); });\n\n // Screen-reader announcements for keyboard seat focus.\n this.srEl = document.createElement('div');\n this.srEl.className = 'sl-sr';\n this.srEl.setAttribute('aria-live', 'polite');\n root.appendChild(this.srEl);\n\n // Big-venue chrome: LOD rung pills, multi-floor switcher, section card.\n // Appended AFTER controller.render() — render() wipes the map host's children.\n this.buildArenaChrome();\n\n // F3 minimap (venue overview + viewport rect) and F4 price-band filter.\n // Same post-render append (the map host was wiped by controller.render()).\n this.buildMinimap();\n this.buildPriceFilter();\n\n // \"Need more time?\" prompt (over the map) + booked-confirmation overlay (over\n // the whole widget). Both appended post-render for the same wipe reason.\n this.buildExtendPrompt();\n this.buildBookedOverlay();\n this.buildSoldoutOverlay();\n this.buildPanelToggle();\n if (this.opts.panelCollapsed) this.setPanelCollapsed(true);\n\n // Dock layout-dependent chrome (a11y chips + colorblind toggle) for the\n // CURRENT layout — the initial applyLayout ran before these were built.\n this.dockLayoutChrome();\n\n await this.restoreRememberedHold();\n if (this.destroyed) return this;\n\n // Reflect the read-only load state (pill + disabled CTA/controls) with no\n // toast — a fresh mount into a closed event is not a live \"just closed\" event.\n if (this.salesClosed) this.applySalesClosed();\n this.syncPrices();\n this.syncTray();\n // Last, so a buyer coming back from a gateway sees a finished map behind the\n // confirmation rather than a skeleton.\n this.resumeHostedOrder();\n return this;\n }\n\n /**\n * A hosted gateway returned this buyer to a page that runs the widget, with\n * `?order=…&status=…` in the URL. Pick the order up and finish the story.\n *\n * Only `success` resumes. `cancelled` means the buyer backed out at the\n * gateway and their seats are still held — the map they are looking at IS the\n * right screen, and opening a card to say \"you cancelled\" would be noise.\n *\n * The two parameters are then stripped with `replaceState`, because they are a\n * one-shot instruction: leaving them in place would re-open the confirmation\n * on every later navigation, and would carry an order id into browser history\n * and any Referer this page later sends. `status` is only ever removed\n * alongside an `order` we actually consumed, so a host page that uses a\n * `status` parameter of its own keeps it.\n */\n private resumeHostedOrder(): void {\n if (this.checkoutMode !== 'hosted' || typeof location === 'undefined') return;\n const params = new URLSearchParams(location.search);\n const orderId = params.get('order');\n if (!orderId) return;\n const status = params.get('status');\n params.delete('order');\n params.delete('status');\n try {\n const query = params.toString();\n history.replaceState(history.state, '', `${location.pathname}${query ? `?${query}` : ''}${location.hash}`);\n } catch {\n // A sandboxed frame can refuse replaceState. Losing the tidy-up is not a\n // reason to lose the confirmation.\n }\n if (status !== 'success') return;\n void this.openCheckoutPanel({ kind: 'resume', orderId });\n }\n\n /**\n * Move layout-dependent chrome between its wide dock (map regions / zoom\n * column) and its narrow dock (the sheet's consolidated Filters row), and\n * re-render the section card in the form the layout wants (docked card/pill\n * on wide, sheet strip on narrow). Runs on every layout flip + once post-render.\n */\n /**\n * The wide-layout panel toggle: a labelled pill in the top-right region\n * beside Map|3D. Collapsing gives the map the panel's 300px; the pill's own\n * label is the way back (\"Tickets\"), and syncTray reopens the panel when the\n * first seat lands so the checkout can never be hidden behind a collapse.\n */\n private buildPanelToggle(): void {\n if (!this.regions['top-right']) return;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'sl-side-toggle';\n btn.addEventListener('click', () => this.setPanelCollapsed(!this.sideCollapsed));\n this.sideToggleEl = btn;\n this.regions['top-right'].appendChild(btn);\n this.syncPanelToggle();\n }\n\n private syncPanelToggle(): void {\n const btn = this.sideToggleEl;\n if (!btn) return;\n const collapsed = this.sideCollapsed;\n btn.setAttribute('aria-expanded', String(!collapsed));\n btn.setAttribute('aria-label', collapsed ? 'Show the ticket panel' : 'Hide the ticket panel');\n btn.innerHTML = collapsed\n ? '<svg viewBox=\"0 0 24 24\"><path d=\"M15 6l-6 6 6 6\"/></svg><span>Tickets</span>'\n : '<svg viewBox=\"0 0 24 24\"><path d=\"M9 6l6 6-6 6\"/></svg><span>Hide panel</span>';\n }\n\n /**\n * Collapse or reopen the wide-layout ticket panel in place (host-drivable —\n * a map-first embed can mount collapsed via `panelCollapsed` and reopen on\n * its own cue). Inert while collapsed so a keyboard buyer cannot tab into a\n * zero-width panel; narrow layouts ignore the state entirely (the sheet is\n * already the collapse) but keep it for the next flip back to wide.\n */\n setPanelCollapsed(collapsed: boolean): void {\n if (this.destroyed) return;\n this.sideCollapsed = collapsed;\n this.applyPanelCollapsed();\n // The map gained/lost 300px: re-fit once the width transition settles.\n this.scheduleMotion(() => this.controller.zoomToFit(), 340);\n }\n\n /** Idempotent DOM apply, also run on every layout flip (inert must lift on narrow). */\n private applyPanelCollapsed(): void {\n const wide = this.root?.dataset.layout !== 'narrow';\n this.root?.setAttribute('data-side-collapsed', String(this.sideCollapsed));\n this.els.side?.toggleAttribute('inert', this.sideCollapsed && wide);\n this.syncPanelToggle();\n }\n\n private dockLayoutChrome(): void {\n const narrow = this.root?.dataset.layout === 'narrow';\n this.applyPanelCollapsed();\n /* Full screen is the highest-payoff control on a phone and the map corner\n stack is where controls go to be ignored. Narrow docks the SAME button\n (state, listener and aria travel with the node) into the top-right region\n beside Map|3D as a labelled pill; wide returns it to the zoom column. */\n const zfs = this.els.zfs;\n if (zfs) {\n if (narrow && this.regions['top-right']) {\n zfs.classList.add('sl-fs-pill');\n this.regions['top-right'].appendChild(zfs);\n } else if (!narrow && this.els.zoom && zfs.parentElement !== this.els.zoom) {\n zfs.classList.remove('sl-fs-pill');\n this.els.zoom.appendChild(zfs);\n }\n }\n const filters = this.els.filters;\n if (filters) {\n /* THE COLOURBLIND TOGGLE IS A MAP CONTROL, NOT A CART ROW.\n It used to dock into the sheet on narrow, and the result was a FILTERS\n section heading standing over a single 32 px eye — placed between the\n buyer's tickets and their checkout. Measured on a 390 px phone: 29 px of\n heading plus a 44 px row, 73 of a 252 px sheet, to caption one icon. The\n second ticket of two was pushed out of the tray to pay for it.\n\n It lives with the zoom cluster in BOTH layouts now. Nothing is lost —\n the toggle is where the map it recolours is. */\n if (this.cbEl) this.els.zoom?.appendChild(this.cbEl);\n if (narrow) {\n if (this.a11yChipsEl) filters.appendChild(this.a11yChipsEl);\n } else {\n if (this.a11yChipsEl) this.regions['top-left']?.appendChild(this.a11yChipsEl);\n }\n /* So FILTERS now appears only when there are real accessibility filters to\n show, and never as a caption for chrome that had nowhere else to go. */\n const has = narrow && filters.children.length > 0;\n filters.classList.toggle('has', has);\n this.els.filtersSec?.classList.toggle('has', has);\n }\n if (this.lastSection) this.renderSectionCard(this.lastSection);\n }\n\n /** The \"Need more time?\" prompt shown in the hold's final EXTEND_PROMPT_MS. */\n private buildExtendPrompt(): void {\n const el = document.createElement('div');\n el.className = 'sl-extend';\n el.setAttribute('role', 'status');\n el.innerHTML =\n `<span class=\"sl-extend-txt\" data-ref=\"extendTxt\"></span>` +\n `<button type=\"button\" class=\"sl-extend-btn\" data-ref=\"extendBtn\"></button>`;\n (this.regions['bottom-center'] ?? this.els.map).appendChild(el);\n this.extendEl = el;\n this.els.extendTxt = el.querySelector('[data-ref=\"extendTxt\"]') as HTMLElement;\n this.els.extendBtn = el.querySelector('[data-ref=\"extendBtn\"]') as HTMLElement;\n this.els.extendBtn.textContent = 'Add time';\n this.els.extendBtn.addEventListener('click', () => void this.handleExtend());\n }\n\n /** Success overlay + onBooked fire when the held seats settle to booked. */\n private buildBookedOverlay(): void {\n const el = document.createElement('div');\n el.className = 'sl-booked';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML =\n `<div class=\"sl-booked-badge\"><svg viewBox=\"0 0 24 24\"><path d=\"M20 6L9 17l-5-5\"/></svg></div>` +\n `<div class=\"sl-booked-title\">You're all set</div>` +\n `<div class=\"sl-booked-sub\" data-ref=\"bookedSub\"></div>`;\n this.root!.appendChild(el);\n this.bookedEl = el;\n this.els.bookedSub = el.querySelector('[data-ref=\"bookedSub\"]') as HTMLElement;\n }\n\n /**\n * Localized string with a literal fallback. `t()` returns the key itself for\n * unknown keys, so this collapses that to `fallback` — while still honoring a\n * host `messages` override (which makes `t()` return the override, not the key).\n */\n private tf(key: string, fallback: string): string {\n const v = t(key);\n return v === key ? fallback : v;\n }\n\n /** Sold-out overlay — an informational state with no unavailable action. */\n private buildSoldoutOverlay(): void {\n if (!this.els.map) return;\n const el = document.createElement('div');\n el.className = 'sl-soldout';\n el.setAttribute('role', 'status');\n const name = (this.controller.doc?.theme?.brandName ?? this.opts.theme?.brandName ?? this.els.name?.textContent ?? this.tf('picker.soldOutEyebrow', 'This event')).toUpperCase();\n el.innerHTML =\n `<div class=\"sl-soldout-eyebrow\">${name}</div>` +\n `<div class=\"sl-soldout-title\">${this.tf('picker.soldOutTitle', 'Sold out')}</div>` +\n `<p class=\"sl-soldout-copy\">${this.tf('picker.soldOutCopy', 'No reserved seats are currently available for this event.')}</p>`;\n this.els.map.appendChild(el);\n this.soldoutEl = el;\n }\n\n /**\n * Recompute the sold-out state on every price/availability sync. Sold-out ⇔\n * every SEATED category's live free count is 0. Suppressed when the chart has\n * GA areas (GA capacity isn't per-seat, so seated counts would read 0 and\n * falsely block standing room) — mirrors the public page. Clears live when WS\n * frees a seat up.\n */\n private syncSoldout(categories: Array<{ key: string }>, left: Record<string, number>): void {\n const hasGA = this.controller.getGAAreas().length > 0;\n const soldOut = this.isSoldOut(categories, left, hasGA);\n if (soldOut === this.soldOut) return;\n this.soldOut = soldOut;\n this.soldoutEl?.classList.toggle('on', soldOut);\n }\n\n /**\n * Pure sold-out predicate: every SEATED category's free count is 0, there is at\n * least one seated category, and there are no GA areas (GA capacity isn't\n * per-seat, so seated counts read 0 and would falsely block standing room).\n * `left` is seeded implicitly — a missing key means a fully-booked tier (0 free).\n */\n private isSoldOut(categories: Array<{ key: string }>, left: Record<string, number>, hasGA: boolean): boolean {\n return !hasGA && categories.length > 0 && categories.every((c) => (left[c.key] ?? 0) === 0);\n }\n\n /**\n * Sales-closed read-only state (Gap 3): persistent header pill, disabled CTA\n * with a closed label, and frozen best-available / GA controls. `setSalesClosed`\n * is the reactive entry (live 409 event_closed); `applySalesClosed` is the\n * idempotent DOM apply used at load and on transition.\n */\n private setSalesClosed(closed: boolean): void {\n const next = closed || !!this.opts.readOnly;\n if (this.salesClosed === next) return;\n this.salesClosed = next;\n this.applySalesClosed();\n }\n\n private applySalesClosed(): void {\n if (this.salesClosed && this.tableDialog && !this.tableDialogHeld) this.cancelTableDialog();\n const pill = this.els.closedPill;\n if (pill) {\n pill.classList.toggle('on', this.salesClosed);\n const text = this.els.closedPillText ?? pill;\n text.textContent = this.tf('picker.salesClosedPill', 'Sales are closed');\n }\n this.root?.setAttribute('data-sales-closed', String(this.salesClosed));\n // The pill's role=\"status\" toggles from display:none, and a status region\n // that APPEARS (rather than changes) is unreliably announced. Mirror the\n // fact into the always-present live region so a screen-reader buyer hears\n // it instead of tabbing into silently disabled controls.\n if (this.salesClosed && this.srEl) {\n this.srEl.textContent = this.tf('picker.salesClosedToast', 'Sales are closed for this event.');\n }\n this.syncCta();\n this.syncTray();\n }\n\n /** The badge is hidden when the host opts out OR the org's theme sets hideBadge. */\n private badgeHidden(chartTheme?: ChartTheme): boolean {\n return !!(this.opts.hideBadge || chartTheme?.hideBadge);\n }\n\n /** Attribution badge in the side-panel foot (Gap 7). Hidden per host/theme. */\n private buildBadge(chartTheme: ChartTheme | undefined): void {\n if (this.badgeHidden(chartTheme)) return;\n const foot = this.els.foot;\n if (!foot) return;\n // An anchor, not a div: this badge is the only route from a buyer's seat\n // map back to us, and SeatingChart's equivalent badge has always been a\n // link — the two were inconsistent for no reason. Attribution that cannot\n // be clicked is decoration.\n const el = document.createElement('a');\n el.className = 'sl-powered';\n el.href = 'https://seatlayer.io/?ref=picker';\n el.target = '_blank';\n el.rel = 'noopener noreferrer';\n el.setAttribute('aria-label', this.tf('picker.poweredBy', 'Powered by SeatLayer'));\n el.innerHTML =\n `<span class=\"sl-powered-mark\" aria-hidden=\"true\">` +\n SEATLAYER_ATTRIBUTION_MARK_SVG +\n `</span><span>${this.tf('picker.poweredBy', 'Powered by SeatLayer')}</span>`;\n foot.appendChild(el);\n }\n\n // ---- Feature 6: chrome anchor regions -------------------------------------\n\n /**\n * Create the positioned flex containers that own every persistent map overlay.\n * Appended once after controller.render(); each chrome piece is then appended\n * INTO its region and flows within it, so nothing free-floats over anything\n * else. Regions carve the map into non-overlapping zones (top strip split into\n * left/center/right, left rail, and the three used corners).\n */\n private buildRegions(): void {\n if (!this.els.map) return;\n const REGIONS = ['top-left', 'top-center', 'top-right', 'left-rail', 'bottom-left', 'bottom-center', 'bottom-right'];\n for (const region of REGIONS) {\n const el = document.createElement('div');\n el.className = 'sl-anchor';\n el.dataset.region = region;\n this.els.map.appendChild(el);\n this.regions[region] = el;\n }\n }\n\n // ---- F3 minimap -----------------------------------------------------------\n\n /** Read a resolved --sl-* token value (canvas needs a real color, not var()). */\n private cssVar(name: string): string {\n return this.root ? getComputedStyle(this.root).getPropertyValue(name).trim() : '';\n }\n\n /** Motion is progressive enhancement; all state remains legible when reduced. */\n private reducedMotion(): boolean {\n return typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n }\n\n private scheduleMotion(fn: () => void, delay: number): void {\n const timer = setTimeout(() => {\n this.motionTimers.delete(timer);\n if (!this.destroyed) fn();\n }, delay);\n this.motionTimers.add(timer);\n }\n\n /** Restart one finite CSS animation without leaving a permanent state class. */\n private animateOnce(el: HTMLElement | undefined, className: string, duration = 600): void {\n if (!el || this.reducedMotion()) return;\n el.classList.remove(className);\n void el.offsetWidth;\n el.classList.add(className);\n this.scheduleMotion(() => el.classList.remove(className), duration);\n }\n\n /** Selection feedback belongs on the selected seat, not across the whole map. */\n private flashPickedSeat(id: string): void {\n if (this.reducedMotion()) return;\n this.controller.flashSeat(id, this.cssVar('--sl-accent') || '#f4b740');\n }\n\n /** A completed hold gets one short map ripple per concrete seat. */\n private flashHeldSeats(hold: HoldResult): void {\n if (this.reducedMotion()) return;\n const labels = (hold.items ?? []).filter((item) => item.objectType !== 'ga').map((item) => item.label);\n labels.slice(0, 10).forEach((label, index) => {\n const seat = this.controller.seatByLabel(label);\n if (!seat) return;\n this.scheduleMotion(\n () => this.controller.flashSeat(seat.id, this.cssVar('--sl-accent') || '#f4b740'),\n index * 55,\n );\n });\n }\n\n /** Update only the action affordance; selection callbacks must not refire. */\n private committedSelection(): PickerSeat[] {\n const candidateId = this.confirmSeat?.id;\n const pendingTableId = this.tableDialog && !this.tableDialogHeld ? this.tableDialog.id : null;\n return this.controller.getSelection().filter((seat) => seat.id !== candidateId && seat.id !== pendingTableId);\n }\n\n private pendingSelectionCount(): number {\n const heldItems = this.hold?.items ?? [];\n const heldLabels = new Set(heldItems.map((item) => item.label));\n const pendingSeats = this.committedSelection()\n .filter((seat) => !heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n return pendingSeats + this.pendingGACount();\n }\n\n private heldGACounts(): Map<string, number> {\n const heldGA = new Map<string, number>();\n for (const item of (this.hold?.items ?? []).filter((candidate) => candidate.objectType === 'ga')) {\n heldGA.set(item.objectId, (heldGA.get(item.objectId) ?? 0) + (item.quantity ?? 1));\n }\n return heldGA;\n }\n\n private pendingGACount(): number {\n const heldGA = this.heldGACounts();\n return [...this.gaQty.entries()].reduce(\n (sum, [areaId, qty]) => sum + Math.max(0, qty - (heldGA.get(areaId) ?? 0)),\n 0,\n );\n }\n\n private heldTicketCount(): number {\n return (this.hold?.items ?? []).reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n }\n\n private totalTicketCount(): number {\n const heldLabels = new Set((this.hold?.items ?? []).map((item) => item.label));\n const freshSeats = this.committedSelection()\n .filter((seat) => !heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n return this.heldTicketCount() + freshSeats + this.pendingGACount();\n }\n\n /** Held tickets and standing quantities consume the same order-wide cap. */\n private updateSelectionCapacity(): void {\n const heldLabels = new Set((this.hold?.items ?? []).map((item) => item.label));\n const selectedHeld = this.committedSelection()\n .filter((seat) => heldLabels.has(seat.label))\n .reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n const remaining = Math.max(0, this.maxTickets - this.heldTicketCount() - this.pendingGACount());\n this.controller.setMaxSelection(selectedHeld + remaining);\n }\n\n private canAddTicket(): boolean {\n if (this.totalTicketCount() < this.maxTickets) return true;\n this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, 'warning');\n return false;\n }\n\n private pendingGATotal(gaAreas: ReturnType<PickerController['getGAAreas']>): number {\n const heldGA = new Map<string, number>();\n for (const item of (this.hold?.items ?? []).filter((candidate) => candidate.objectType === 'ga')) {\n heldGA.set(item.objectId, (heldGA.get(item.objectId) ?? 0) + (item.quantity ?? 1));\n }\n return gaAreas.reduce(\n (sum, area) => sum + this.paidPrice(area.categoryKey, null, area.price) * Math.max(0, (this.gaQty.get(area.id) ?? 0) - (heldGA.get(area.id) ?? 0)),\n 0,\n );\n }\n\n private syncCta(count = this.lastTrayCount, pending = this.pendingSelectionCount()): void {\n const cta = this.els.cta as HTMLButtonElement | undefined;\n if (!cta) return;\n if (this.salesClosed) {\n cta.disabled = true;\n cta.textContent = this.tf('picker.salesClosedCta', 'Sales closed');\n return;\n }\n if (this.confirmSeat || (this.tableDialog && !this.tableDialogHeld)) {\n cta.disabled = true;\n cta.textContent = this.tableDialog ? 'Confirm your table' : 'Confirm or cancel this seat';\n return;\n }\n if (this.ctaPhase === 'holding') {\n cta.disabled = true;\n cta.innerHTML = '<span class=\"sl-cta-spin\" aria-hidden=\"true\"></span>Securing seats…';\n return;\n }\n if (this.ctaPhase === 'checkout') {\n cta.disabled = true;\n cta.innerHTML = '<span class=\"sl-cta-spin\" aria-hidden=\"true\"></span>Opening checkout…';\n return;\n }\n cta.disabled = count === 0;\n cta.textContent = this.hold\n ? pending\n ? `Secure ${pending} more & checkout`\n : 'Continue to checkout'\n : count\n ? 'Hold seats & checkout'\n : 'Select seats';\n }\n\n private setCtaPhase(phase: 'idle' | 'holding' | 'checkout'): void {\n this.ctaPhase = phase;\n this.syncCta();\n if (phase === 'checkout') {\n this.scheduleMotion(() => {\n if (this.ctaPhase !== 'checkout') return;\n this.ctaPhase = 'idle';\n this.syncCta();\n }, 1100);\n }\n }\n\n /** Session-scoped capability key: isolated by API origin and event. */\n private holdStorageKey(): string {\n return `@seatlayer/hold/v1/${encodeURIComponent(this.apiBase)}/${encodeURIComponent(this.opts.event)}`;\n }\n\n private rememberedHoldId(): string | null {\n if (this.opts.initialHoldId) return this.opts.initialHoldId;\n if (this.opts.restoreHold === false || typeof window === 'undefined') return null;\n try {\n return window.sessionStorage.getItem(this.holdStorageKey());\n } catch {\n return null;\n }\n }\n\n private rememberHold(hold: HoldResult): void {\n if (this.opts.restoreHold === false || typeof window === 'undefined') return;\n try {\n // Persist only the opaque capability. Labels, prices and expiry are\n // always reloaded from the authoritative server projection.\n window.sessionStorage.setItem(this.holdStorageKey(), hold.holdId);\n } catch {\n // Storage can be unavailable in privacy/sandboxed embeds; the live picker\n // remains fully functional for the current mount.\n }\n }\n\n private forgetHold(): void {\n if (typeof window === 'undefined') return;\n try {\n window.sessionStorage.removeItem(this.holdStorageKey());\n } catch {\n // Best-effort cleanup only.\n }\n }\n\n private async resumeHoldFromServer(holdId: string, automatic: boolean): Promise<HoldResult | null> {\n try {\n const h = await this.controller.resumeHold(holdId);\n if (!h) return null;\n const restored: HoldResult = {\n holdId: h.holdId,\n expiresAt: h.expiresAt,\n seats: h.seats,\n items: h.items,\n };\n this.hold = restored;\n // A resumed capability came from an earlier checkout handoff. Keep it\n // alive if this picker mount is refreshed or torn down before the buyer\n // explicitly removes/releases it.\n this.handedOff = true;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.startHoldTimer(restored.expiresAt);\n this.rememberHold(restored);\n this.syncTray();\n this.emitHoldChange();\n this.opts.onHoldRestored?.(restored, restored.seats ?? [], this.buildHandoff(restored));\n if (automatic) this.toast('Your held tickets have been restored.', 'success');\n return restored;\n } catch (error) {\n const status = (error as { status?: number })?.status;\n if (status === 404 || status === 409) {\n // A stale/foreign/settled capability is expected recovery state, not a\n // picker failure. Drop it and let the buyer choose again.\n this.forgetHold();\n } else {\n this.opts.onError?.(error);\n }\n return null;\n }\n }\n\n private async restoreRememberedHold(): Promise<void> {\n const holdId = this.rememberedHoldId();\n if (holdId) await this.resumeHoldFromServer(holdId, true);\n }\n\n /** Section-bearing objects on the active floor (single-floor → doc.objects). */\n private activeFloorObjects(): SectionLike[] {\n const doc = this.controller.doc;\n if (!doc) return [];\n const floors = doc.floors;\n if (floors?.length) {\n const id = this.controller.getActiveFloorId();\n return ((floors.find((f) => f.id === id) ?? floors[0]).objects as unknown as SectionLike[]) ?? [];\n }\n return (doc.objects as unknown as SectionLike[]) ?? [];\n }\n\n /**\n * Build the overview minimap: a static venue thumbnail (section outlines, or\n * seat dots when the chart has no sections) with the live viewport rectangle\n * drawn on top. The rect tracks pan/zoom via the constructor's onViewChange.\n */\n private buildMinimap(): void {\n const vp = this.controller.getViewport();\n if (!vp || !this.els.map) return;\n const b = vp.bounds;\n if (!(b.width > 0 && b.height > 0)) return;\n\n const MAXW = 158;\n const MAXH = 118;\n const PAD = 6;\n const aspect = b.width / Math.max(1, b.height);\n let w = MAXW;\n let h = Math.round(MAXW / aspect);\n if (h > MAXH) {\n h = MAXH;\n w = Math.round(MAXH * aspect);\n }\n w = Math.max(64, w);\n h = Math.max(48, h);\n const dpr = Math.min(2, window.devicePixelRatio || 1);\n\n const wrap = document.createElement('div');\n wrap.className = 'sl-minimap';\n wrap.setAttribute('aria-hidden', 'true'); // decorative; the map itself is the keyboard surface\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(w * dpr);\n canvas.height = Math.round(h * dpr);\n canvas.style.width = `${w}px`;\n canvas.style.height = `${h}px`;\n wrap.appendChild(canvas);\n (this.regions['bottom-left'] ?? this.els.map).appendChild(wrap);\n this.miniCanvas = canvas;\n\n // world → minimap (device px), contain + centre — matches thumb.ts.\n const scale = Math.min((w - PAD * 2) / Math.max(1, b.width), (h - PAD * 2) / Math.max(1, b.height)) * dpr;\n const offX = (w * dpr - b.width * scale) / 2 - b.x * scale;\n const offY = (h * dpr - b.height * scale) / 2 - b.y * scale;\n this.miniTf = { scale, offX, offY, dpr };\n\n const base = document.createElement('canvas');\n base.width = canvas.width;\n base.height = canvas.height;\n this.miniBase = base;\n\n // Click a section on the minimap → glide the camera into it (existing API).\n wrap.addEventListener('click', (e) => this.minimapJump(e));\n\n this.drawMinimapStatic();\n this.drawMinimapRect();\n }\n\n /** Repaint the static overview + rect (floor switch, live open/close). */\n private refreshMinimap(): void {\n if (!this.miniBase) return;\n this.drawMinimapStatic();\n this.drawMinimapRect();\n }\n\n /** Paint the venue overview into the offscreen base canvas. */\n private drawMinimapStatic(): void {\n const base = this.miniBase;\n const tf = this.miniTf;\n const doc = this.controller.doc;\n if (!base || !tf || !doc) return;\n const ctx = base.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, base.width, base.height);\n const fx = (x: number): number => x * tf.scale + tf.offX;\n const fy = (y: number): number => y * tf.scale + tf.offY;\n const line = this.cssVar('--sl-line') || 'rgba(139,147,167,.5)';\n const muted = this.cssVar('--sl-muted') || '#8b93a7';\n const accent = this.cssVar('--sl-accent') || '#6e7bff';\n const zoneColor = new Map((doc.zones ?? []).map((z) => [z.id, z.color] as const));\n\n let drewSection = false;\n for (const o of this.activeFloorObjects()) {\n if (o.type !== 'section' || !o.outline || o.outline.length < 3) continue;\n drewSection = true;\n const closed = this.controller.isSectionClosed(o.id);\n const fill = closed ? muted : o.color ?? (o.zone && zoneColor.get(o.zone)) ?? accent;\n ctx.beginPath();\n o.outline.forEach((p, i) => (i === 0 ? ctx.moveTo(fx(p.x), fy(p.y)) : ctx.lineTo(fx(p.x), fy(p.y))));\n ctx.closePath();\n ctx.globalAlpha = closed ? 0.26 : 0.42;\n ctx.fillStyle = fill;\n ctx.fill();\n ctx.globalAlpha = 0.85;\n ctx.lineWidth = Math.max(1, tf.dpr);\n ctx.strokeStyle = line;\n ctx.stroke();\n }\n ctx.globalAlpha = 1;\n\n // Section-less charts: fall back to faint category-colored seat dots.\n if (!drewSection) {\n const r = Math.max(1, tf.dpr);\n for (const seat of expandChart(doc)) {\n const cat = doc.categories.find((c) => c.key === seat.categoryKey);\n ctx.fillStyle = cat?.color ?? accent;\n ctx.beginPath();\n ctx.arc(fx(seat.x), fy(seat.y), r, 0, Math.PI * 2);\n ctx.fill();\n }\n }\n }\n\n /** Blit the base overview, then stroke the current viewport rectangle on top. */\n private drawMinimapRect(): void {\n const canvas = this.miniCanvas;\n const base = this.miniBase;\n const tf = this.miniTf;\n if (!canvas || !base || !tf) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(base, 0, 0);\n const vp = this.controller.getViewport();\n if (!vp) return;\n const v = vp.visible;\n const x = v.x * tf.scale + tf.offX;\n const y = v.y * tf.scale + tf.offY;\n const w = v.width * tf.scale;\n const h = v.height * tf.scale;\n const accent = this.cssVar('--sl-accent') || '#f4b740';\n ctx.save();\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = accent;\n ctx.fillRect(x, y, w, h);\n ctx.globalAlpha = 1;\n ctx.lineWidth = Math.max(1.5, tf.dpr * 1.5);\n ctx.strokeStyle = accent;\n ctx.strokeRect(x, y, w, h);\n ctx.restore();\n }\n\n /** Minimap click → focus the section under the point (or overview on a miss). */\n private minimapJump(e: MouseEvent): void {\n const canvas = this.miniCanvas;\n const tf = this.miniTf;\n if (!canvas || !tf) return;\n const r = canvas.getBoundingClientRect();\n const px = (e.clientX - r.left) * (canvas.width / r.width);\n const py = (e.clientY - r.top) * (canvas.height / r.height);\n const wx = (px - tf.offX) / tf.scale;\n const wy = (py - tf.offY) / tf.scale;\n for (const o of this.activeFloorObjects()) {\n if (o.type !== 'section' || !o.outline || o.outline.length < 3) continue;\n if (this.controller.isSectionClosed(o.id)) continue;\n if (pointInPolygon(wx, wy, o.outline)) {\n this.controller.focusSection(o.id);\n return;\n }\n }\n this.controller.overview();\n }\n\n // ---- F4 price-band filter -------------------------------------------------\n\n /** Effective display price of a category: host pricing override → first tier → base. */\n private catPrice(c: { key?: string; price?: number; tiers?: { id?: string; price: number }[] }): number | undefined {\n const chart = c.tiers?.length ? c.tiers[0].price : c.price;\n if (chart === undefined || !c.key) return chart;\n return this.paidPrice(c.key, c.tiers?.[0]?.id ?? null, chart);\n }\n\n /** Derive price bands: one chip per distinct price (≤5), else quantile ranges. */\n private priceBands(): PriceBand[] {\n const doc = this.controller.doc;\n if (!doc) return [];\n const priced = doc.categories\n .map((c) => ({ key: c.key, price: this.catPrice(c) }))\n .filter((x): x is { key: string; price: number } => x.price != null);\n if (!priced.length) return [];\n const distinct = [...new Set(priced.map((p) => p.price))].sort((a, b) => a - b);\n if (distinct.length <= 5) {\n return distinct.map((price) => ({\n id: `p${price}`,\n label: this.money(price),\n keys: priced.filter((p) => p.price === price).map((p) => p.key),\n min: price,\n max: price,\n }));\n }\n // Many distinct prices → ~4 contiguous quantile bands (ranges).\n const chunk = Math.ceil(distinct.length / 4);\n const bands: PriceBand[] = [];\n for (let i = 0; i < distinct.length; i += chunk) {\n const slice = distinct.slice(i, i + chunk);\n const lo = slice[0];\n const hi = slice[slice.length - 1];\n bands.push({\n id: `b${i}`,\n label: lo === hi ? this.money(lo) : `${this.money(lo)}–${this.money(hi)}`,\n keys: priced.filter((p) => p.price >= lo && p.price <= hi).map((p) => p.key),\n min: lo,\n max: hi,\n });\n }\n return bands;\n }\n\n /** Build the compact price selector in the panel header. Choosing a band both\n * filters availability and smoothly frames the matching seats on the map. */\n private buildPriceFilter(): void {\n if (!this.els.prices || !this.els.pricesSec) return;\n const bands = this.priceBands();\n if (bands.length < 2) return;\n const select = document.createElement('select');\n select.className = 'sl-price-select';\n select.setAttribute('aria-label', 'Filter and focus seats by price');\n select.innerHTML = `<option value=\"all\">All prices</option>` + bands\n .map((band) => `<option value=\"${band.id}\">${band.label}</option>`)\n .join('');\n this.els.pricesSec.appendChild(select);\n select.addEventListener('change', () => {\n const band = bands.find((candidate) => candidate.id === select.value);\n const keys = band?.keys ?? null;\n this.focusedCatKey = null; // band filter supersedes any pinned row focus\n this.priceBandKeys = keys ? new Set(keys) : null;\n this.controller.setCategoryFilter(keys);\n this.controller.focusCategoryFilter(keys);\n // The band has to survive a switch into 3D, which paints from its own\n // state snapshot rather than from Konva opacity.\n this.pushAvailabilityTo3d();\n // A band whose seats live on another deck switches floors — mirror it.\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n // Reflect the band in the legend rows + any open section card.\n this.syncPrices();\n if (this.lastSection) this.showSectionCard(this.lastSection);\n });\n }\n\n // ---- arena / multi-floor chrome -------------------------------------------\n\n /** Build projection, rung and floor controls for arena-scale charts. */\n private buildArenaChrome(): void {\n const doc = this.controller.doc;\n if (!doc || !this.els.map) return;\n const hasSections = doc.objects.some((o) => o.type === 'section')\n || (doc.floors ?? []).some((f) => f.objects.some((o) => o.type === 'section'));\n\n // Buyer view toggle: **Map | 3D** (2.5D/perspective is retired from the buyer\n // surface). The 3D button is offered only when 3D is enabled AND the browser\n // exposes WebGL2 — otherwise the picker stays a plain flat map with no toggle\n // at all. Available for ANY chart with a real 3D relief source, not just\n // sectioned venues.\n if (this.canOffer3d()) {\n const projection = document.createElement('div');\n projection.className = 'sl-projection';\n projection.setAttribute('role', 'group');\n projection.setAttribute('aria-label', 'Venue view');\n projection.innerHTML =\n '<button type=\"button\" data-view=\"map\" aria-pressed=\"true\" title=\"Flat 2D map\">Map</button>' +\n '<button type=\"button\" data-view=\"venue3d\" aria-pressed=\"false\" title=\"Interactive 3D venue view\">3D</button>';\n projection.querySelectorAll<HTMLButtonElement>('button').forEach((button) => {\n button.addEventListener('click', () => {\n this.setBuyerView(button.dataset.view as 'map' | 'venue3d');\n });\n });\n this.regions['top-right'].appendChild(projection);\n this.projectionEl = projection;\n this.syncProjection();\n }\n\n // LOD rung pills — jump straight between zones / sections / seats.\n if (hasSections) {\n const RUNGS: LodRung[] = ['zones', 'sections', 'seats'];\n const pills = document.createElement('div');\n pills.className = 'sl-rungs on';\n pills.setAttribute('role', 'group');\n pills.setAttribute('aria-label', t('picker.zoomLevel'));\n const LABEL: Record<LodRung, string> = {\n zones: t('picker.rungLabel.zones'),\n sections: t('picker.rungLabel.sections'),\n seats: t('picker.rungLabel.seats'),\n };\n const TIP: Record<LodRung, string> = {\n zones: t('picker.rungTip.zones'),\n sections: t('picker.rungTip.sections'),\n seats: t('picker.rungTip.seats'),\n };\n pills.innerHTML = RUNGS.map(\n (r) => `<button type=\"button\" data-rung=\"${r}\" title=\"${TIP[r]}\" aria-pressed=\"false\">${LABEL[r]}</button>`,\n ).join('');\n pills.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.addEventListener('click', () => {\n const rung = btn.dataset.rung as LodRung;\n this.controller.setRung(rung);\n if (rung === 'seats') this.collapseSectionCard();\n });\n });\n this.regions['top-center'].appendChild(pills);\n this.rungsEl = pills;\n this.syncRung();\n }\n\n // Multi-floor switcher — only when the chart truly has >1 floor.\n if (this.controller.isMultiFloor()) {\n const floors = this.controller.getFloors();\n const rail = document.createElement('div');\n rail.className = 'sl-floors on';\n rail.setAttribute('role', 'group');\n rail.setAttribute('aria-label', t('picker.floor'));\n rail.innerHTML = floors\n .map((f) => `<button type=\"button\" data-floor=\"${f.id}\">${f.name}</button>`)\n .join('');\n rail.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.controller.setFloor(btn.dataset.floor!);\n this.showSectionCard(null);\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n });\n });\n this.regions['left-rail'].appendChild(rail);\n this.floorsEl = rail;\n this.syncFloors();\n }\n }\n\n /** Reflect the engine's current LOD rung onto the pill group. */\n private syncRung(): void {\n if (!this.rungsEl) return;\n const active = this.controller.getRung();\n this.rungsEl.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n const on = btn.dataset.rung === active;\n btn.classList.toggle('on', on);\n btn.setAttribute('aria-pressed', String(on));\n });\n }\n\n private syncProjection(): void {\n if (!this.projectionEl) return;\n this.projectionEl.querySelectorAll<HTMLButtonElement>('button').forEach((button) => {\n const on = button.dataset.view === this.buyerView;\n button.classList.toggle('on', on);\n button.setAttribute('aria-pressed', String(on));\n });\n }\n\n /** Can this picker offer the 3D venue view? Requires the option (default on),\n * WebGL2, a chart to render, and a chart small enough to render WELL. */\n private canOffer3d(): boolean {\n if (this.opts.enable3D === false || !this.controller.doc || !hasWebGL2()) return false;\n return this.allSeats().length <= this.max3dSeats();\n }\n\n /**\n * The seat ceiling for offering 3D. See `max3DSeats` — an explicit host value\n * always wins; otherwise a small/low-core device gets half the desktop budget,\n * because it is the device that turns \"slow\" into \"stalled\".\n */\n private max3dSeats(): number {\n const authored = this.opts.max3DSeats;\n if (typeof authored === 'number' && authored > 0) return authored;\n const nav = globalThis.navigator as (Navigator & { deviceMemory?: number }) | undefined;\n const small = (nav?.hardwareConcurrency ?? 8) <= 4\n || (nav?.deviceMemory ?? 8) <= 4\n || (globalThis.matchMedia?.('(pointer: coarse)').matches ?? false);\n return small ? MAX_3D_SEATS_DEFAULT / 2 : MAX_3D_SEATS_DEFAULT;\n }\n\n /** Reflect the active floor onto the switcher rail. */\n private syncFloors(): void {\n if (!this.floorsEl) return;\n const active = this.controller.getActiveFloorId();\n this.floorsEl.querySelectorAll<HTMLButtonElement>('button').forEach((btn) => {\n btn.classList.toggle('on', btn.dataset.floor === active);\n });\n }\n\n /** Show (or clear, on null) the tapped-section summary card. */\n private showSectionCard(summary: SectionSummary | null): void {\n this.lastSection = summary;\n this.secCardEl?.remove();\n this.secCardEl = null;\n if (!summary) return;\n // At seat level the summary is context, not a blocking decision surface.\n // Keep it as the compact pill from the first seat-level paint.\n this.secCardCollapsed = this.controller.getRung() === 'seats';\n this.secCardShownAt = Date.now();\n this.renderSectionCard(summary);\n }\n\n /**\n * Render the section card in the form the layout + state want: expanded card\n * or slim pill in the top-center anchor region (wide), or a compact strip in\n * the sheet head (narrow). Never floats over the seats at the tap point.\n */\n private renderSectionCard(summary: SectionSummary): void {\n if (!this.els.map) return;\n this.secCardEl?.remove();\n // min/max over the section's categories at the price the buyer will PAY\n // (host pricing override aware) — not the chart's stored range.\n const paid = summary.categories.length\n ? summary.categories.map((c) => this.paidPrice(c.key, null, c.price))\n : [summary.priceMin, summary.priceMax];\n const paidMin = Math.min(...paid);\n const paidMax = Math.max(...paid);\n const priceLabel =\n paidMin === paidMax\n ? this.money(paidMin)\n : `${this.money(paidMin)}–${this.money(paidMax)}`;\n const leftLabel = tCount('picker.seatsLeftInSection', summary.seatsLeft);\n const xBtn = `<button type=\"button\" class=\"sl-seccard-x\" aria-label=\"${t('picker.closeSectionSummary')}\">✕</button>`;\n const card = document.createElement('div');\n const narrow = this.root?.dataset.layout === 'narrow';\n\n if (narrow) {\n // Compact strip inside the bottom sheet's peek head — never over the map.\n card.className = 'sl-seccard strip on';\n card.setAttribute('role', 'status');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n card.innerHTML =\n `<span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span>` +\n (summary.categories.length ? `<span class=\"sl-seccard-price\">${priceLabel}</span>` : '') +\n xBtn;\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n (this.els.sheetHead ?? this.els.side ?? this.els.map).appendChild(card);\n } else if (this.secCardCollapsed) {\n // Slim pill — seat-picking has begun. Tap to re-expand; ✕ still closes.\n card.className = 'sl-seccard mini on';\n card.setAttribute('role', 'button');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n card.innerHTML =\n `<span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span>` +\n xBtn;\n card.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.sl-seccard-x')) return;\n this.secCardCollapsed = false;\n this.secCardShownAt = Date.now();\n this.renderSectionCard(summary);\n });\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n (this.regions['top-center'] ?? this.els.map).appendChild(card);\n } else {\n card.className = 'sl-seccard on';\n card.setAttribute('role', 'dialog');\n card.setAttribute('aria-label', t('picker.sectionSummaryAria', { label: summary.label }));\n const mix = summary.categories\n .map((c) => {\n const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);\n return (\n `<span class=\"sl-seccard-mix-item${dim ? ' sl-dim' : ''}\"><span class=\"sl-seccard-mix-dot\" style=\"background:${c.color}\"></span>` +\n `${c.label} <span class=\"sl-seccard-mix-price\">${this.money(this.paidPrice(c.key, null, c.price))}</span></span>`\n );\n })\n .join('');\n card.innerHTML =\n `<div class=\"sl-seccard-head\"><span class=\"sl-seccard-dot\" style=\"background:${summary.color}\"></span>` +\n `<span class=\"sl-seccard-name\">${summary.label}</span>` +\n (summary.categories.length ? `<span class=\"sl-seccard-price\">${priceLabel}</span>` : '') +\n xBtn + `</div>` +\n `<div class=\"sl-seccard-zone\">${summary.zoneLabel ? `${summary.zoneLabel} · ` : ''}` +\n `<span class=\"sl-seccard-left\">${leftLabel}</span></div>` +\n (summary.entrance\n ? `<div class=\"sl-seccard-entrance\">${t('picker.entrance')} ${String(summary.entrance).replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!))}</div>`\n : '') +\n (mix ? `<div class=\"sl-seccard-mix\">${mix}</div>` : '') +\n `<div class=\"sl-seccard-foot\">` +\n `<button type=\"button\" class=\"sl-seccard-overview\">← ${t('picker.overview')}</button>` +\n `<span class=\"sl-seccard-hint\">${t('picker.tapSeatHint')}</span></div>`;\n card.querySelector('.sl-seccard-x')!.addEventListener('click', () => this.controller.overview());\n card.querySelector('.sl-seccard-overview')!.addEventListener('click', () => this.controller.overview());\n (this.regions['top-center'] ?? this.els.map).appendChild(card);\n }\n this.secCardEl = card;\n }\n\n /** Collapse the expanded card to its slim pill (seat-picking started). */\n private collapseSectionCard(): void {\n if (!this.secCardEl || this.secCardCollapsed || !this.lastSection) return;\n if (this.root?.dataset.layout === 'narrow') return; // strip is already compact\n this.secCardCollapsed = true;\n this.renderSectionCard(this.lastSection);\n }\n\n /**\n * onViewChange hook for the card. The focus glide's own settle (within the\n * grace window) enforces the ~25% coverage rule with the FINAL viewport; any\n * later pan/zoom means seat-picking has begun → collapse to the pill.\n */\n private sectionCardOnView(): void {\n if (!this.secCardEl || this.secCardCollapsed || !this.lastSection) return;\n if (this.root?.dataset.layout === 'narrow') return;\n if (this.controller.getRung() === 'seats') {\n this.collapseSectionCard();\n return;\n }\n if (Date.now() - this.secCardShownAt < 1400) {\n if (this.sectionCardCoverage() > 0.25) this.collapseSectionCard();\n return;\n }\n this.collapseSectionCard();\n }\n\n /** Fraction of the focused section's on-screen bbox covered by the card. */\n private sectionCardCoverage(): number {\n const card = this.secCardEl;\n const sec = this.lastSection;\n if (!card || !sec || !this.els.map) return 0;\n const outline = this.activeFloorObjects().find((o) => o.type === 'section' && o.id === sec.id)?.outline;\n if (!outline || outline.length < 3) return 0;\n const pts = outline.map((p) => this.controller.worldToScreen(p));\n const xs = pts.map((p) => p.x);\n const ys = pts.map((p) => p.y);\n const bx = Math.min(...xs);\n const by = Math.min(...ys);\n const bw = Math.max(...xs) - bx;\n const bh = Math.max(...ys) - by;\n if (bw <= 0 || bh <= 0) return 0;\n const mapR = this.els.map.getBoundingClientRect();\n const cr = card.getBoundingClientRect();\n const cx = cr.left - mapR.left;\n const cy = cr.top - mapR.top;\n const ox = Math.max(0, Math.min(cx + cr.width, bx + bw) - Math.max(cx, bx));\n const oy = Math.max(0, Math.min(cy + cr.height, by + bh) - Math.max(cy, by));\n return (ox * oy) / (bw * bh);\n }\n\n /** aria-live readout when keyboard focus lands on a seat. */\n private announceSeat(seat: ExpandedSeat | null): void {\n if (!this.srEl) return;\n if (!seat) {\n this.srEl.textContent = '';\n return;\n }\n const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);\n const status = this.controller.getStatus(seat.id) ?? 'free';\n const statusText = status === 'free' ? 'available' : status === 'held' ? 'on hold' : 'taken';\n const price = cat ? this.catPrice(cat) : undefined;\n const table = this.controller.tableSelection(seat.id);\n const details = table ?? this.controller.seatDetails(seat.id);\n const typeWord = this.rowTypeWord(details);\n const buyerName = details?.rowLabel ?? details?.displayLabel ?? seat.displayLabel ?? seat.label;\n const identity = table\n ? `${typeWord} ${buyerName}, ${table.bookingMode === 'variable' ? `${table.minOccupancy} to ${table.maxOccupancy} guests` : `${table.capacity} guests`}`\n : details?.objectType === 'booth'\n ? `${typeWord} ${buyerName}`\n : details?.objectType === 'table'\n ? `${typeWord} ${buyerName}, seat ${details.seatNumber ?? seat.label}`\n : `Seat ${details?.displayLabel ?? seat.displayLabel ?? seat.label}`;\n this.srEl.textContent = `${identity}, ${cat?.label ?? seat.categoryKey}${\n price != null ? `, ${this.money(price)}` : ''\n }, ${statusText}`;\n }\n\n // ---- atomic table confirmation / guest quantity ---------------------------\n\n private showTableDialog(\n table: TableSelectionDetails,\n held: boolean,\n returnFocus?: HTMLElement | null,\n ): void {\n this.dismissTableDialog(false);\n this.tableDialog = { ...table };\n this.tableDialogHeld = held;\n this.tableDialogReturnFocus = returnFocus ?? (document.activeElement as HTMLElement | null);\n const esc = (value: unknown): string => String(value ?? '').replace(/[&<>\"']/g, (ch) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;',\n })[ch]!);\n const cat = this.controller.doc?.categories.find((candidate) => candidate.key === table.categoryKey);\n const variable = table.bookingMode === 'variable';\n const typeWord = this.rowTypeWord(table);\n const el = document.createElement('div');\n el.className = 'sl-table-scrim';\n el.innerHTML =\n `<section class=\"sl-table-dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-table-title\" aria-describedby=\"sl-table-copy\">` +\n `<div class=\"sl-table-head\"><div class=\"sl-table-eyebrow\">${esc(variable ? `Flexible party · ${typeWord}` : `Whole ${typeWord}`)}</div>` +\n `<h2 class=\"sl-table-title\" id=\"sl-table-title\">${esc(table.displayLabel ?? table.label)}</h2>` +\n `<p class=\"sl-table-copy\" id=\"sl-table-copy\">${variable\n ? `Choose how many guests will sit together. This table is held exclusively for your party.`\n : `All ${table.capacity} places are booked together as one exclusive table.`}</p></div>` +\n `<div class=\"sl-table-body\">` +\n `<div class=\"sl-table-summary\"><span>${esc(cat?.label ?? table.categoryKey)}</span><b data-table-unit>${this.money(this.paidPrice(table.categoryKey, table.tierId ?? null, table.price))} per guest</b>` +\n `<span class=\"muted\">Table capacity</span><span>${table.capacity} guests</span>` +\n `<span class=\"muted\">Total</span><b data-table-total></b></div>` +\n (variable\n ? `<label class=\"sl-table-qtylabel\" id=\"sl-table-qty-label\">Number of guests</label>` +\n `<div class=\"sl-table-stepper\" role=\"group\" aria-labelledby=\"sl-table-qty-label\">` +\n `<button type=\"button\" data-table-step=\"-1\" aria-label=\"Fewer guests\">−</button>` +\n `<output aria-live=\"polite\" data-table-qty>${table.quantity}</output>` +\n `<button type=\"button\" data-table-step=\"1\" aria-label=\"More guests\">+</button></div>` +\n `<div class=\"sl-table-range\">Choose ${table.minOccupancy}–${table.maxOccupancy} guests</div>`\n : `<input type=\"hidden\" data-table-qty value=\"${table.capacity}\">`) +\n `<div class=\"sl-table-actions\"><button type=\"button\" class=\"sl-table-cancel\">Cancel</button>` +\n `<button type=\"button\" class=\"sl-table-confirm\">${held ? 'Update table' : variable ? 'Select table' : 'Select whole table'}</button></div>` +\n `</div></section>`;\n this.root!.appendChild(el);\n this.tableDialogEl = el;\n this.renderTableDialogState();\n\n el.querySelectorAll<HTMLButtonElement>('[data-table-step]').forEach((button) => {\n button.addEventListener('click', () => {\n if (!this.tableDialog) return;\n const next = Math.max(\n this.tableDialog.minOccupancy,\n Math.min(this.tableDialog.maxOccupancy, this.tableDialog.quantity + Number(button.dataset.tableStep)),\n );\n this.tableDialog = { ...this.tableDialog, quantity: next };\n this.renderTableDialogState();\n });\n });\n el.querySelector<HTMLButtonElement>('.sl-table-cancel')!.addEventListener('click', () => this.cancelTableDialog());\n el.querySelector<HTMLButtonElement>('.sl-table-confirm')!.addEventListener('click', () => void this.confirmTableDialog());\n el.addEventListener('mousedown', (event) => {\n if (event.target === el) this.cancelTableDialog();\n });\n el.addEventListener('keydown', (event) => {\n if (event.key !== 'Tab') return;\n const focusable = [...el.querySelectorAll<HTMLElement>('button:not(:disabled),[tabindex]:not([tabindex=\"-1\"])')];\n if (!focusable.length) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n });\n requestAnimationFrame(() => (\n el.querySelector<HTMLButtonElement>(variable ? '[data-table-step=\"-1\"]' : '.sl-table-confirm')?.focus()\n ));\n }\n\n private renderTableDialogState(): void {\n const table = this.tableDialog;\n const el = this.tableDialogEl;\n if (!table || !el) return;\n const output = el.querySelector<HTMLOutputElement>('output[data-table-qty]');\n if (output) output.value = String(table.quantity);\n const hidden = el.querySelector<HTMLInputElement>('input[data-table-qty]');\n if (hidden) hidden.value = String(table.quantity);\n el.querySelectorAll<HTMLButtonElement>('[data-table-step]').forEach((button) => {\n const delta = Number(button.dataset.tableStep);\n button.disabled = delta < 0\n ? table.quantity <= table.minOccupancy\n : table.quantity >= table.maxOccupancy;\n });\n const unit = this.paidPrice(table.categoryKey, table.tierId ?? null, table.price);\n const total = el.querySelector<HTMLElement>('[data-table-total]');\n if (total) total.textContent = this.money(unit * table.quantity);\n }\n\n private async confirmTableDialog(): Promise<void> {\n const table = this.tableDialog;\n const held = this.tableDialogHeld;\n if (!table) return;\n const button = this.tableDialogEl?.querySelector<HTMLButtonElement>('.sl-table-confirm');\n if (button) {\n button.disabled = true;\n button.textContent = held ? 'Updating…' : 'Selecting…';\n }\n if (held) {\n try {\n const updated = await this.controller.replaceTableQuantity(table.label, table.quantity, this.opts.holdTtlMs);\n if (!updated) {\n this.toast('That guest count could not be secured. Your current table hold is unchanged.', 'warning');\n this.renderTableDialogState();\n if (button) {\n button.disabled = false;\n button.textContent = 'Update table';\n }\n return;\n }\n this.hold = {\n holdId: updated.holdId,\n expiresAt: updated.expiresAt,\n seats: updated.seats,\n items: updated.items,\n };\n this.startHoldTimer(updated.expiresAt);\n this.dismissTableDialog();\n this.syncTray();\n this.emitHoldChange();\n this.toast(`${table.label} updated for ${table.quantity} guests.`, 'success');\n } catch (error) {\n this.opts.onError?.(error);\n this.toast('That guest count is no longer available. Your current hold is unchanged.', 'error');\n if (button) {\n button.disabled = false;\n button.textContent = 'Update table';\n }\n }\n return;\n }\n\n if (!this.controller.setTableQuantity(table.label, table.quantity)) {\n if (button) {\n button.disabled = false;\n button.textContent = table.bookingMode === 'variable' ? 'Select table' : 'Select whole table';\n }\n return;\n }\n this.dismissTableDialog();\n this.collapseSectionCard();\n this.syncTray();\n }\n\n private cancelTableDialog(): void {\n const table = this.tableDialog;\n const held = this.tableDialogHeld;\n this.dismissTableDialog();\n if (table && !held) this.controller.deselect(table.physicalSeatIds);\n }\n\n private dismissTableDialog(restoreFocus = true): void {\n const focus = this.tableDialogReturnFocus;\n this.tableDialogEl?.remove();\n this.tableDialogEl = null;\n this.tableDialog = null;\n this.tableDialogHeld = false;\n this.tableDialogReturnFocus = null;\n if (restoreFocus) requestAnimationFrame(() => (focus?.isConnected ? focus : this.root)?.focus());\n }\n\n // ---- seat candidate confirmation ------------------------------------------\n\n private showConfirm(seat: ExpandedSeat): void {\n const previousId = this.confirmSeat?.id;\n this.confirmEl?.remove();\n this.confirmEl = null;\n this.confirmSeat = seat;\n this.root?.setAttribute('data-confirming', 'true');\n // The CSS pause (pointer-events:none + dimmed) must be true for keyboards\n // and assistive tech too: inert takes the paused panel and chrome out of\n // the tab order and the accessibility tree while the card is up.\n this.els.side?.toggleAttribute('inert', true);\n Object.values(this.regions).forEach((region) => region.toggleAttribute('inert', true));\n this.controller.setSelectionFocus(seat.id);\n if (previousId && previousId !== seat.id) this.controller.deselect([previousId]);\n if (this.tipEl) this.tipEl.style.display = 'none';\n const details = this.controller.seatDetails(seat.id);\n const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);\n const chartPrice = details?.price ?? (cat?.tiers?.length ? cat.tiers[0].price : cat?.price);\n const price = chartPrice != null\n ? this.paidPrice(seat.categoryKey, details?.tierId ?? cat?.tiers?.[0]?.id ?? null, chartPrice)\n : undefined;\n const safe = (value: unknown): string => String(value ?? '—').replace(/[&<>\"]/g, (char) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\n })[char]!);\n const identityFields = [\n details?.sectionLabel\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">Section</span><span class=\"sl-confirm-value\">${safe(details.sectionLabel)}</span></div>`\n : '',\n details?.rowLabel || details?.objectType === 'booth'\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">${safe(this.rowTypeWord(details))}</span><span class=\"sl-confirm-value\">${safe(this.rowShort(details) ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>`\n : '',\n details?.objectType !== 'booth'\n ? `<div class=\"sl-confirm-field\"><span class=\"sl-confirm-key\">Seat</span><span class=\"sl-confirm-value\">${safe(details?.seatNumber ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>`\n : '',\n ].filter(Boolean).join('');\n const el = document.createElement('div');\n el.className = 'sl-confirm';\n el.setAttribute('role', 'dialog');\n // Deliberately NOT aria-modal: it claimed modality with no focus trap, so a\n // keyboard user tabbed straight out into panels the claim had told screen\n // readers to hide — while CSS had made those same panels unclickable. The\n // paused chrome is made honest with `inert` below instead; the map stays\n // reachable, which is right for a card that refers to a seat on it.\n el.setAttribute('aria-label', `Confirm seat ${seat.label}`);\n el.style.setProperty('--sl-cat', cat?.color ?? '#6e7bff');\n el.innerHTML =\n `<div class=\"sl-confirm-grid\">` +\n identityFields +\n `</div>` +\n `<div class=\"sl-confirm-cat\"><span class=\"sl-dot\" style=\"background:${cat?.color ?? '#6e7bff'}\"></span>` +\n `<span class=\"sl-confirm-cat-name\">${safe(details?.categoryLabel ?? cat?.label ?? seat.categoryKey)}</span>` +\n (price != null ? `<span class=\"sl-confirm-price\">${this.money(price)}</span>` : '') + `</div>` +\n `<div class=\"sl-confirm-body\">` +\n this.wheelchairConfirmHtml(details?.wheelchairSpaceType) +\n this.commercialConfirmHtml(seat.commercial) +\n (this.seatViewEnabled() && this.buyerView !== 'venue3d' ? this.confirmThumbHtml(seat) : '') +\n (this.buyerView === 'venue3d'\n ? `${this.seatConfidenceConfirmHtml(seat, `${details?.displayLabel ?? seat.displayLabel ?? seat.label} · ${price == null ? this.tf('picker.priceNotSupplied', 'Price not supplied') : this.money(price)}`)}<div class=\"sl-confirm-inspect-row\">${this.view3dCompareConfirmHtml(seat)}${this.see3dConfirmHtml()}</div>`\n : this.see3dConfirmHtml()) +\n `<div class=\"sl-confirm-row\">` +\n `<button type=\"button\" class=\"sl-confirm-cancel\">Cancel</button>` +\n `<button type=\"button\" class=\"sl-confirm-add\"><svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M5 12.5l4 4L19 7\"/></svg>Select</button></div></div>`;\n this.els.map.appendChild(el);\n this.confirmEl = el;\n const thumb = el.querySelector<HTMLImageElement>('.sl-confirm-thumb');\n if (thumb && seat.viewUrl) {\n const thumbReference = seat.viewMeta?.previewUrl ?? seat.viewUrl;\n void this.buyerAssetUrls.resolve(thumbReference).then((url) => {\n if (url && el.isConnected && this.confirmEl === el) thumb.src = url;\n }).catch((error) => this.opts.onError?.(error));\n }\n this.reanchorConfirm();\n el.querySelector('.sl-confirm-view')?.addEventListener('click', () => void this.openSeatView(seat));\n el.querySelector('.sl-confirm-confidence')?.addEventListener('click', (event) => {\n this.openSeatConfidencePassport(seat, event.currentTarget instanceof HTMLElement ? event.currentTarget : null);\n });\n el.querySelector('.sl-confirm-compare')?.addEventListener('click', () => this.saveView3dComparisonSeat(seat));\n el.querySelector('.sl-confirm-3d')?.addEventListener('click', () => {\n if (this.buyerView === 'venue3d') {\n // Already immersed — just fly the cinematic to this seat.\n this.dismissConfirm();\n void this.view3dHandle?.flyToSeat(seat.id);\n } else {\n // Enter 3D flying straight to the seat; re-show this card on return.\n this.view3dReturnSeat = seat;\n this.dismissConfirm();\n void this.enter3d(seat.id);\n }\n });\n el.querySelector('.sl-confirm-add')!.addEventListener('click', () => this.commitConfirm());\n el.querySelector('.sl-confirm-cancel')!.addEventListener('click', () => this.cancelConfirm());\n requestAnimationFrame(() => el.querySelector<HTMLButtonElement>('.sl-confirm-add')?.focus());\n }\n\n private reanchorConfirm(): void {\n if (!this.confirmEl || !this.confirmSeat) return;\n // In 3D the seat has no stable 2D screen anchor, so CSS bottom-sheets the\n // card (same treatment as the narrow layout). Nothing to position here.\n if (this.root?.dataset.view3d === 'on') return;\n const p = this.controller.worldToScreen({ x: this.confirmSeat.x, y: this.confirmSeat.y });\n if (this.root?.dataset.layout === 'narrow') return;\n const mapWidth = this.els.map.clientWidth;\n const mapHeight = this.els.map.clientHeight;\n const cardWidth = this.confirmEl.offsetWidth || 276;\n const cardHeight = this.confirmEl.offsetHeight || 230;\n const half = cardWidth / 2 + 12;\n const x = Math.max(half, Math.min(mapWidth - half, p.x));\n const belowFits = p.y + cardHeight + 24 <= mapHeight;\n const placeBelow = p.y < cardHeight + 24 && belowFits;\n this.confirmEl.dataset.placement = placeBelow ? 'below' : 'above';\n this.confirmEl.style.left = `${x}px`;\n this.confirmEl.style.top = `${Math.max(8, Math.min(mapHeight - 8, p.y))}px`;\n }\n\n private dismissConfirm(): void {\n this.confirmEl?.remove();\n this.confirmEl = null;\n this.confirmSeat = null;\n this.root?.removeAttribute('data-confirming');\n Object.values(this.regions).forEach((region) => region.toggleAttribute('inert', false));\n // The side panel's inert is owned by the collapse state too — recompute\n // rather than blindly lifting it.\n this.applyPanelCollapsed();\n this.controller.setSelectionFocus(null);\n }\n\n private commitConfirm(): void {\n if (!this.confirmSeat) return;\n this.dismissConfirm();\n this.collapseSectionCard();\n this.syncTray();\n this.syncSelectionTo3d();\n }\n\n private cancelConfirm(): void {\n const seat = this.confirmSeat;\n if (!seat) return;\n this.controller.deselect([seat.id]);\n if (this.confirmSeat) this.dismissConfirm();\n this.syncSelectionTo3d();\n this.root?.focus({ preventScroll: true });\n }\n\n private closeConfirm(): void {\n this.dismissConfirm();\n }\n\n // ---- 360° view-from-seat modal --------------------------------------------\n\n private seatViewEnabled(): boolean {\n return this.opts.seatView !== false;\n }\n\n /** Every bookable seat (cached) — neighbor heads for the generated panorama. */\n private allSeats(): ExpandedSeat[] {\n if (!this.allSeatsCache) {\n const doc = this.controller.doc;\n this.allSeatsCache = doc ? expandChart(doc) : [];\n }\n return this.allSeatsCache;\n }\n\n /**\n * Open the drag-to-look-around 360° preview for a seat. Uses the organizer's\n * uploaded photo (seat.viewUrl) when present, else a panorama generated from\n * the chart geometry — the stage placed at this seat's true bearing + size.\n * Zero extra dependencies: an equirectangular image panned with `repeat-x`.\n *\n * Async only because the generator is a lazy chunk (see `loadPanorama`); an\n * organizer photo needs no generator and never waits on it. The two callers\n * are click handlers, so nothing observes the promise.\n */\n private async openSeatView(seat: ExpandedSeat): Promise<void> {\n if (!this.root || !this.seatViewEnabled()) return;\n const generation = ++this.seatViewGen;\n\n const doc = this.controller.doc;\n const activeId = this.controller.getActiveFloorId();\n const focal = seat.focalPoint\n ?? doc?.floors?.find((f) => f.id === activeId)?.focalPoint\n ?? doc?.focalPoint\n ?? { x: 0, y: 0 };\n let panoSource: View3DSeatView;\n let caption: string;\n let real = false;\n if (seat.viewUrl) {\n let resolvedUrl: string | null;\n let resolvedPreviewUrl: string | null = null;\n try {\n const previewReference = seat.viewMeta?.previewUrl;\n if (previewReference && previewReference !== seat.viewUrl) {\n // Preserve progressive delivery: fetch only the lightweight first\n // paint now. The sharp source is resolved with Authorization inside\n // the scheduled upgrade below, and is never assigned directly.\n resolvedPreviewUrl = await this.buyerAssetUrls.resolve(previewReference);\n resolvedUrl = seat.viewUrl;\n } else {\n resolvedUrl = await this.buyerAssetUrls.resolve(seat.viewUrl);\n }\n } catch (error) {\n if (generation === this.seatViewGen) this.opts.onError?.(error);\n return;\n }\n if (\n generation !== this.seatViewGen\n || !resolvedUrl\n || (seat.viewMeta?.previewUrl && seat.viewMeta.previewUrl !== seat.viewUrl && !resolvedPreviewUrl)\n || !this.root\n || !this.seatViewEnabled()\n ) return;\n const view: View3DSeatView = {\n url: resolvedUrl,\n ...(resolvedPreviewUrl ? { previewUrl: resolvedPreviewUrl } : {}),\n ...(seat.viewMeta?.sourceWidth !== undefined ? { sourceWidth: seat.viewMeta.sourceWidth } : {}),\n ...(seat.viewMeta?.sourceHeight !== undefined ? { sourceHeight: seat.viewMeta.sourceHeight } : {}),\n ...(seat.viewMeta?.previewWidth !== undefined ? { previewWidth: seat.viewMeta.previewWidth } : {}),\n ...(seat.viewMeta?.previewHeight !== undefined ? { previewHeight: seat.viewMeta.previewHeight } : {}),\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n };\n panoSource = view;\n caption = seatViewDisclosure(view);\n real = isAuthoredSeatView(view);\n } else {\n let pano: PanoramaResult;\n try {\n const { generateSeatPanorama } = await loadPanorama();\n pano = generateSeatPanorama(seat, focal, this.allSeats());\n } catch (err) {\n // The chunk failed to fetch, or the draw threw. Report it and leave the\n // buyer on the map rather than opening an empty viewer.\n if (generation === this.seatViewGen) this.opts.onError?.(err);\n return;\n }\n // Torn down (or another view opened) while the chunk loaded.\n if (generation !== this.seatViewGen || !this.root || !this.seatViewEnabled()) return;\n panoSource = { url: pano.url, generated: true };\n caption = t('picker.illustrationCaption', { m: pano.distanceM });\n }\n\n // Retire any open view HERE, not before the await: two quick taps would\n // otherwise each close nothing and then leave the first viewer orphaned in\n // the DOM. It also means the current view stays up while the chunk loads.\n this.closeSeatView(false);\n\n const el = document.createElement('div');\n el.className = 'sl-view';\n el.setAttribute('role', 'dialog');\n el.setAttribute('aria-label', t('picker.viewFromSeat', { label: seat.label }));\n el.innerHTML =\n `<div class=\"sl-view-head\">` +\n `<span class=\"sl-view-title\">${t('picker.viewFromSeat', { label: seat.label })}</span>` +\n `<span class=\"sl-view-cap\">${caption}</span>` +\n `<button type=\"button\" class=\"sl-view-x\" aria-label=\"Close\">` +\n `<svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg></button></div>` +\n `<div class=\"sl-view-pano\">` +\n `<span class=\"sl-view-badge\">${real ? t('picker.real360') : t('picker.preview')}</span>` +\n `<span class=\"sl-view-hint\">Drag to look around · scroll to zoom</span>` +\n `</div>`;\n this.root.appendChild(el);\n this.viewEl = el;\n\n const pano = el.querySelector<HTMLDivElement>('.sl-view-pano')!;\n const delivery = planPanoramaDelivery(panoSource, browserPanoramaConstraints());\n const loadAbort = new AbortController();\n pano.style.backgroundImage = `url(\"${delivery.initialUrl}\")`;\n let cancelUpgrade = (): void => {};\n if (delivery.upgradeUrl) {\n cancelUpgrade = schedulePanoramaUpgrade(() => {\n void this.buyerAssetUrls.resolve(delivery.upgradeUrl!).then((url) => {\n if (!url || loadAbort.signal.aborted) return null;\n return loadPanoramaImage(url, loadAbort.signal).then(() => url);\n }).then((url) => {\n if (!url || !el.isConnected || loadAbort.signal.aborted) return;\n pano.style.backgroundImage = `url(\"${url}\")`;\n }).catch(() => { /* retain the preview */ });\n });\n }\n\n // Equirectangular pan: repeat-x gives seamless 360° horizontal wrap. The\n // source is a full 180° sphere; showing it raw wastes ~⅔ of the frame on\n // dead sky + black floor. So we WINDOW a ~70° vertical slice (horizon-centred)\n // to fill the viewport height, and clamp the vertical drag to ±35° so the\n // buyer looks around a real seat's field of view, never past the image edge.\n // `zoom` narrows the FOV further (scroll to zoom in); it never widens past 70°.\n const VFOV_DEG = 70;\n const MAX_PITCH_DEG = 35;\n let zoom = 1;\n // The generator draws the STAGE at the image's horizontal centre (yaw 0 =\n // stage). Open with that centre in the middle of the viewport — a view\n // that opens facing away from the stage is disorienting (seat 11G-21\n // owner report). Same default is right for uploaded 360s until Case-1\n // calibration exists. bgW = 2·bgH (2:1 equirect), zoom 1 at open.\n const vh0 = pano.clientHeight || 1;\n const vw0 = pano.clientWidth || 1;\n let posX = -(vh0 * (180 / VFOV_DEG) * 2 / 2 - vw0 / 2);\n let posY = 0;\n const apply = (): void => {\n const h = pano.clientHeight || 1;\n const bgH = h * (180 / VFOV_DEG) * zoom;\n const overV = Math.max(0, bgH - h);\n // Clamp pitch to ±35° of image travel (bgH px map the full 180°), and never\n // past the image edge (overV/2).\n const pitchLimit = Math.min(overV / 2, (MAX_PITCH_DEG / 180) * bgH);\n posY = Math.min(pitchLimit, Math.max(-pitchLimit, posY));\n pano.style.backgroundSize = `auto ${bgH}px`;\n // Horizon-centred: -overV/2 places the image's vertical centre at the\n // viewport centre; `posY` (drag, clamped ±35°) tilts up/down from there.\n pano.style.backgroundPosition = `${posX}px ${posY - overV / 2}px`;\n };\n apply();\n\n let dragging = false;\n let lastX = 0;\n let lastY = 0;\n const onDown = (e: PointerEvent): void => {\n dragging = true;\n lastX = e.clientX;\n lastY = e.clientY;\n pano.classList.add('drag');\n pano.setPointerCapture?.(e.pointerId);\n };\n const onMove = (e: PointerEvent): void => {\n if (!dragging) return;\n posX += e.clientX - lastX;\n posY += e.clientY - lastY;\n lastX = e.clientX;\n lastY = e.clientY;\n apply();\n };\n const onUp = (e: PointerEvent): void => {\n dragging = false;\n pano.classList.remove('drag');\n pano.releasePointerCapture?.(e.pointerId);\n };\n const onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n zoom = Math.min(2.4, Math.max(1, zoom + (e.deltaY < 0 ? 0.12 : -0.12)));\n apply();\n };\n pano.addEventListener('pointerdown', onDown);\n pano.addEventListener('pointermove', onMove);\n pano.addEventListener('pointerup', onUp);\n pano.addEventListener('pointercancel', onUp);\n pano.addEventListener('wheel', onWheel, { passive: false });\n\n const closeBtn = el.querySelector<HTMLButtonElement>('.sl-view-x')!;\n closeBtn.addEventListener('click', () => this.closeSeatView());\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n this.closeSeatView();\n }\n };\n el.addEventListener('keydown', onKey);\n closeBtn.focus();\n\n this.viewCleanup = () => {\n cancelUpgrade();\n loadAbort.abort();\n pano.removeEventListener('pointerdown', onDown);\n pano.removeEventListener('pointermove', onMove);\n pano.removeEventListener('pointerup', onUp);\n pano.removeEventListener('pointercancel', onUp);\n pano.removeEventListener('wheel', onWheel);\n el.removeEventListener('keydown', onKey);\n };\n }\n\n private closeSeatView(cancelPending = true): void {\n if (cancelPending) this.seatViewGen += 1;\n this.viewCleanup?.();\n this.viewCleanup = null;\n this.viewEl?.remove();\n this.viewEl = null;\n }\n\n // ---- chrome sync ----------------------------------------------------------\n\n private money(n: number): string {\n const formatter = this.opts.pricing?.formatter;\n if (formatter) return formatter(n, this.currency);\n try {\n return new Intl.NumberFormat(this.opts.locale, { style: 'currency', currency: this.currency }).format(n);\n } catch {\n return `${n} ${this.currency}`;\n }\n }\n\n /**\n * Sleep until the offer schedule's next known transition, then re-read.\n *\n * A far-away boundary is capped: the wake re-reads, learns the (unchanged)\n * schedule, and re-arms — so a picker left open for days still tracks an\n * organizer's schedule edits at a cost of one request every few hours. No\n * future transition means no timer at all; an event with no releases does\n * zero background traffic. A wake in a hidden tab fetches nothing — the\n * visibilitychange handler owns catching that tab up.\n */\n private scheduleOfferBoundary(availability: TicketOfferAvailability | null): void {\n if (this.offerBoundaryTimer) clearTimeout(this.offerBoundaryTimer);\n this.offerBoundaryTimer = null;\n if (!this.api.availability || this.destroyed) return;\n const now = Date.now();\n const boundary = nextOfferTransitionAt(availability, now);\n if (boundary == null) return;\n // +1s past the boundary so the server's clock has provably crossed it.\n const MAX_SLEEP_MS = 6 * 3600_000;\n const delay = Math.min(Math.max(boundary - now + 1_000, 1_000), MAX_SLEEP_MS);\n this.offerBoundaryTimer = setTimeout(() => {\n this.offerBoundaryTimer = null;\n if (document.hidden) return;\n void this.refreshOfferAvailability(false);\n }, delay);\n }\n\n /** Debounce the no-store offer read behind a burst of seat-status frames. */\n private scheduleOfferRefresh(live: boolean): void {\n if (!this.api.availability || this.destroyed) return;\n if (this.offerRefreshTimer) clearTimeout(this.offerRefreshTimer);\n this.offerRefreshTimer = setTimeout(() => {\n this.offerRefreshTimer = null;\n void this.refreshOfferAvailability(live);\n }, live ? 180 : 0);\n }\n\n /**\n * Pull the server's resolved answer. A failed refresh keeps the last truthful\n * answer: flashing back to a chart price while checkout still charges an\n * offer is worse than a temporarily stale remaining count.\n */\n private async refreshOfferAvailability(live: boolean): Promise<void> {\n if (!this.api.availability || this.destroyed) return;\n try {\n const body = await this.api.availability(this.opts.event, live);\n if (this.destroyed) return;\n const availability = parseTicketOfferAvailability(body);\n if (!availability) return;\n this.offerAvailability = availability;\n this.scheduleOfferBoundary(availability);\n\n // Server offers win for the categories they resolve; an unrelated host\n // override remains the fallback for every category the server omitted.\n const server = ticketOfferPrices(availability);\n const merged = { ...(this.hostPricing?.prices ?? {}), ...server };\n const pricing = Object.keys(merged).length > 0 || this.hostPricing?.formatter\n ? { prices: merged, ...(this.hostPricing?.formatter ? { formatter: this.hostPricing.formatter } : {}) }\n : undefined;\n this.setPricing(pricing);\n this.syncOffer();\n this.opts.onOfferAvailabilityChange?.(availability);\n } catch {\n // The seat map and an open hold remain usable, and the last truthful\n // answer stays on screen. One bounded, visible-only retry so a fault at\n // a price boundary cannot strand a stale card — a persistent outage\n // costs one request per 30s, not a different price on screen.\n if (!this.destroyed && !this.offerBoundaryTimer && !document.hidden) {\n this.offerBoundaryTimer = setTimeout(() => {\n this.offerBoundaryTimer = null;\n if (document.hidden) return;\n void this.refreshOfferAvailability(false);\n }, 30_000);\n }\n }\n }\n\n private offerPrice(categoryKey: string | undefined): TicketOfferPrice | null {\n if (!categoryKey) return null;\n return this.offerAvailability?.prices.find((entry) => entry.categoryKey === categoryKey) ?? null;\n }\n\n /** The compact current/upcoming offer card above Ticket prices. */\n private syncOffer(): void {\n const host = this.els.offer;\n if (!host) return;\n const availability = this.offerAvailability;\n const active = availability?.release ?? null;\n const upcoming = !active ? availability?.upcoming ?? null : null;\n if (!availability || availability.state === 'closed' || availability.state === 'sold-out'\n || (!active && !upcoming)) {\n host.classList.remove('has');\n host.replaceChildren();\n return;\n }\n\n const offer = active ?? upcoming!;\n const main = document.createElement('div');\n main.className = 'sl-offer-main';\n const copy = document.createElement('div');\n copy.className = 'sl-offer-copy';\n const kicker = document.createElement('span');\n kicker.className = 'sl-offer-kicker';\n kicker.textContent = active ? 'Current ticket offer' : 'Upcoming ticket offer';\n const name = document.createElement('strong');\n name.className = 'sl-offer-name';\n name.textContent = offer.name || (active ? 'Current offer' : 'Scheduled offer');\n const line = document.createElement('span');\n line.className = 'sl-offer-line';\n const facts: string[] = [];\n if (active && availability.fromPrice != null) facts.push(this.money(availability.fromPrice / 100));\n if (active && offer.remaining != null) facts.push(`${offer.remaining} available`);\n if (active && offer.endsAt != null) facts.push(`until ${formatWhen(offer.endsAt, this.eventTimezone, this.opts.locale)}`);\n if (upcoming?.startsAt != null) facts.push(`starts ${formatWhen(upcoming.startsAt, this.eventTimezone, this.opts.locale)}`);\n line.textContent = facts.join(' · ');\n copy.append(kicker, name, line);\n\n const info = document.createElement('details');\n info.className = 'sl-offer-info';\n const summary = document.createElement('summary');\n summary.setAttribute('aria-label', `How the ${name.textContent} offer works`);\n summary.textContent = 'i';\n const detail = document.createElement('div');\n detail.className = 'sl-offer-detail';\n detail.textContent = active\n ? `This price applies automatically to eligible seats. Tickets in active carts temporarily reduce the available quantity; released or expired holds return it. When the offer ends, the next matching offer or normal ticket price takes over.`\n : `Tickets are available at their normal price now. This scheduled offer will apply automatically to eligible seats when it starts.`;\n info.append(summary, detail);\n main.append(copy, info);\n host.replaceChildren(main);\n host.classList.add('has');\n }\n\n /**\n * The price the buyer will actually pay for a category (+tier): the host's\n * `pricing` override when present, else the chart's stored price. Every\n * price the widget DISPLAYS or hands off must flow through here — a map\n * that shows one price while checkout charges another destroys trust.\n */\n private paidPrice(categoryKey: string | undefined, tierId: string | null | undefined, fallback: number): number {\n const entry = categoryKey ? this.opts.pricing?.prices?.[categoryKey] : undefined;\n if (entry === undefined) return fallback;\n if (typeof entry === 'number') return entry;\n if (tierId && entry.tiers?.[tierId] !== undefined) return entry.tiers[tierId];\n return entry.base ?? fallback;\n }\n\n private syncPrices(): void {\n const doc = this.controller.doc;\n if (!doc || !this.els.prices) return;\n const left = this.controller.categoryAvailability();\n this.narrateAvailability(doc.categories, left);\n this.syncSoldout(doc.categories, left);\n // Big events ship 10–20 ticket types; an uncapped list shoves \"Your seats\"\n // and the CTA below the fold. Cap the closed list and expand on demand\n // (never hide a single row behind a toggle — that costs more than it saves).\n const PRICE_LIMIT = 5;\n const overflow = doc.categories.length - PRICE_LIMIT;\n const collapsed = overflow > 1 && !this.pricesExpanded;\n const shown = collapsed ? doc.categories.slice(0, PRICE_LIMIT) : doc.categories;\n this.els.prices.classList.toggle('sl-expanded', overflow > 1 && this.pricesExpanded);\n this.els.prices.innerHTML = shown\n .map((c) => {\n const price = this.catPrice(c);\n const offer = this.offerPrice(c.key);\n const previous = offer?.previousPrice != null && offer.previousPrice > offer.price\n ? offer.previousPrice\n : null;\n const active = this.focusedCatKey === c.key;\n const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);\n return (\n `<div class=\"sl-price-row${dim ? ' sl-dim' : ''}${active ? ' sl-active' : ''}\" data-cat=\"${escapeOption(c.key)}\"` +\n ` role=\"button\" tabindex=\"0\" aria-pressed=\"${active}\"` +\n ` title=\"${escapeOption(active ? 'Show all seats' : `Show ${c.label} seats on the map`)}\">` +\n `<span class=\"sl-dot\" style=\"background:${escapeOption(c.color)}\"></span>` +\n `<span class=\"sl-price-label\">${escapeOption(c.label)}` +\n (offer?.offerName ? `<small class=\"sl-price-offer\">${escapeOption(offer.offerName)}</small>` : '') +\n `</span>` +\n `<span class=\"sl-price-left\">${left[c.key] ?? 0} left</span>` +\n (previous != null ? `<span class=\"sl-price-was\">${escapeOption(this.money(previous))}</span>` : '') +\n (price != null ? `<span class=\"sl-price-amt\">${this.money(price)}</span>` : '') +\n `</div>`\n );\n })\n .join('') +\n (overflow > 1\n ? `<button type=\"button\" class=\"sl-price-more\" aria-expanded=\"${!collapsed}\">` +\n (collapsed ? `Show all ${doc.categories.length} ticket types` : 'Show fewer') +\n `</button>`\n : '') +\n `<div class=\"sl-status-key\" aria-label=\"Seat status legend\">` +\n `<span class=\"sl-status-item\"><i class=\"sl-status-icon\" aria-hidden=\"true\">` +\n `<svg viewBox=\"0 0 24 24\"><rect x=\"5\" y=\"10\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 10V7a4 4 0 0 1 8 0v3\"/></svg>` +\n `</i>Temporarily held</span>` +\n `<span class=\"sl-status-item\"><i class=\"sl-status-icon sold\" aria-hidden=\"true\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M7 17L17 7\"/></svg>` +\n `</i>Sold</span>` +\n `</div>`;\n // Legend-hover highlight: dim other categories on the map while hovering a row.\n // Click (or Enter/Space) pins that focus — filter + frame the category on\n // the map; a second click clears it.\n this.els.prices.querySelectorAll<HTMLElement>('.sl-price-row').forEach((row) => {\n row.addEventListener('mouseenter', () => this.controller.getRenderer()?.setCategoryHighlight?.(row.dataset.cat ?? null));\n row.addEventListener('mouseleave', () => this.controller.getRenderer()?.setCategoryHighlight?.(null));\n const toggle = () => this.focusCategory(row.dataset.cat ?? '');\n row.addEventListener('click', toggle);\n row.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle();\n }\n });\n });\n this.els.prices.querySelector<HTMLButtonElement>('.sl-price-more')?.addEventListener('click', () => {\n this.pricesExpanded = !this.pricesExpanded;\n this.syncPrices();\n });\n }\n\n /** Tap a price row → filter + frame that category on the map; tap again to\n * clear. Shares `priceBandKeys` with the band selector so the row-dim state\n * has one source of truth (and each control resets the other). */\n private focusCategory(key: string): void {\n if (!key) return;\n const next = this.focusedCatKey === key ? null : key;\n this.focusedCatKey = next;\n this.priceBandKeys = next ? new Set([next]) : null;\n const select = this.els.pricesSec?.querySelector<HTMLSelectElement>('.sl-price-select');\n if (select) select.value = 'all';\n this.controller.setCategoryFilter(next ? [next] : null);\n this.controller.focusCategoryFilter(next ? [next] : null);\n this.pushAvailabilityTo3d();\n // Focusing a category on another deck switches floors — mirror that onto\n // the floor pills / rung pills / minimap, same as a manual deck switch.\n this.syncFloors();\n this.syncRung();\n this.refreshMinimap();\n this.syncPrices();\n if (this.lastSection) this.showSectionCard(this.lastSection);\n }\n\n /**\n * Live-activity strip: turn WS availability deltas into one quiet line of\n * social proof (\"2 seats just taken in VIP · 118 left\"). Diffs per-category\n * counts on every status change — no per-seat payload needed. Skips the very\n * first computation (initial load is not \"activity\").\n */\n private narrateAvailability(\n categories: Array<{ key: string; label: string }>,\n left: Record<string, number>,\n ): void {\n const textEl = this.els.liveText;\n const prev = this.lastCatAvail;\n this.lastCatAvail = { ...left };\n // A floor switch re-baselines availability (counts are per-rendered-floor,\n // and the post-switch status snapshot lands asynchronously a beat later).\n // Narrating across that window produces a phantom \"N seats just taken\", so\n // stay quiet until the new floor settles — only genuine WS deltas after\n // that are news.\n const floorId = this.controller.getActiveFloorId();\n if (floorId !== this.lastAvailFloorId) {\n this.lastAvailFloorId = floorId;\n this.availQuietUntil = performance.now() + 2000;\n }\n if (!textEl || !prev || performance.now() < this.availQuietUntil) return;\n for (const cat of categories) {\n const before = prev[cat.key];\n const now = left[cat.key] ?? 0;\n if (before === undefined || now >= before) continue;\n const taken = before - now;\n textEl.textContent = `${taken} seat${taken === 1 ? '' : 's'} just taken in ${cat.label} · ${now} left`;\n // Surface the strip only while it carries news, then give the space back.\n this.els.live?.classList.remove('on');\n // Reflow between remove/add restarts the entrance animation on repeats.\n void (this.els.live as HTMLElement | undefined)?.offsetWidth;\n this.els.live?.classList.add('on');\n if (this.liveTimer) clearTimeout(this.liveTimer);\n this.liveTimer = setTimeout(() => this.els.live?.classList.remove('on'), 8000);\n return;\n }\n }\n private lastCatAvail: Record<string, number> | null = null;\n private lastAvailFloorId = '';\n private availQuietUntil = 0;\n private liveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** A live delta took one of OUR selected (not yet held) seats — evict + tell the buyer. */\n private evictTakenSelections(): void {\n // Our own hold's WS echo paints our seats 'held' — never treat those as sniped.\n const ownLabels = new Set<string>([\n ...(this.controller.currentHold()?.labels ?? []),\n ...this.holdingLabels,\n ]);\n const gone = this.controller\n .getSelection()\n .filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? 'free') !== 'free');\n if (!gone.length) return;\n this.controller.deselect(gone.map((s) => s.id));\n this.toast(`Seat ${gone[0].label} was just taken by another buyer.`, 'error');\n }\n\n private syncTray(): void {\n if (!this.els.tray) return;\n this.updateSelectionCapacity();\n const seats = this.committedSelection();\n const gaAreas = this.controller.getGAAreas();\n const heldItems = this.hold?.items ?? [];\n const parts: string[] = [];\n const nextTrayKeys = new Set<string>();\n\n if (this.salesClosed && !seats.length && !heldItems.length) {\n // Closed is a DESIGNED state, not a set of disables. The open-for-business\n // hint and the best-seats card would invite actions that cannot succeed —\n // pressing a live-looking gold button that does nothing reads as \"the site\n // is broken\", not \"this event is over\". One statement, with the event's\n // own date, where the buying flow was.\n const closedWhen = this.eventWhenText\n ? `<span class=\"when\">${String(this.eventWhenText).replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c]!)}</span>`\n : '';\n parts.push(\n `<div class=\"sl-closed-note\" role=\"status\">` +\n `<b>${this.tf('picker.salesClosedPill', 'Sales are closed')}</b>` +\n `<span>${this.tf('picker.salesClosedCopy', 'Ticket sales for this event have ended.')}${closedWhen}</span>` +\n `</div>`,\n );\n } else if (!seats.length && !heldItems.length && !gaAreas.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map, or let us pick the best available for you.</div>`);\n } else if (!seats.length && !heldItems.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map — or grab standing tickets below.</div>`);\n }\n\n // Best available is the fastest path for buyers who haven't picked yet —\n // but the moment a seat lands in the tray, the ticket cards own this space.\n // (Busy/confirm states stay visible so an in-flight search isn't cut off.)\n // Never while sales are closed: bestAvailable() refuses closed events, and a\n // card whose CTA cannot succeed has no business rendering.\n const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();\n if (!this.salesClosed && !this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {\n const cats = this.controller.doc?.categories ?? [];\n const zones = this.controller.getBestAvailableZones();\n if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = '';\n parts.push(this.bestAvailableConfirm\n ? `<div class=\"sl-ba\" role=\"alert\">` +\n `<div class=\"sl-ba-title\"><span class=\"spark\" aria-hidden=\"true\">✦</span>Replace your current choices?</div>` +\n `<div class=\"sl-ba-replace\"><b>We’ll find ${this.baQty} seats together.</b>` +\n `<span>Your manually selected tickets will be removed only after a new group is secured.</span></div>` +\n `<div class=\"sl-ba-actions\"><button type=\"button\" data-ba-cancel>Keep mine</button>` +\n `<button type=\"button\" class=\"replace\" data-ba-replace>Find new seats</button></div></div>`\n : `<div class=\"sl-ba\">` +\n `<div class=\"sl-ba-title\"><span class=\"spark\" aria-hidden=\"true\">✦</span>Find the best seats together</div>` +\n `<div class=\"sl-ba-copy\"><span class=\"wide\">We’ll choose the closest available group for you.</span>` +\n `<span class=\"narrow\">Closest available group, chosen instantly.</span></div>` +\n // Premium quick-pick — present only when the chart actually has premium\n // seats (same present-only philosophy as the a11y filter chips).\n (this.controller.hasPremiumSeats()\n ? `<button type=\"button\" class=\"sl-ba-premium${this.baPremium ? ' on' : ''}\" data-ba-premium aria-pressed=\"${this.baPremium ? 'true' : 'false'}\">` +\n `<span class=\"star\" aria-hidden=\"true\">★</span>${this.tf('picker.bestSeatsPremium', 'Best seats')}</button>`\n : '') +\n (cats.length > 1\n ? `<select aria-label=\"Preferred ticket type\" data-ba-cat>` +\n `<option value=\"\">Any ticket type</option>` +\n cats.map((c) => `<option value=\"${c.key}\"${this.baCat === c.key ? ' selected' : ''}>${c.label}</option>`).join('') +\n `</select>`\n : `<span aria-hidden=\"true\"></span>`) +\n (zones.length\n ? `<select aria-label=\"Preferred venue zone\" data-ba-zone>` +\n `<option value=\"\">Any venue zone</option>` +\n zones.map((zone) => `<option value=\"${escapeOption(zone.id)}\"${this.baZone === zone.id ? ' selected' : ''}>${escapeOption(zone.label)}</option>`).join('') +\n `</select>`\n : '') +\n `<div class=\"sl-ba-qty\">` +\n `<button type=\"button\" data-ba=\"-1\" aria-label=\"Fewer seats\">−</button><span>${this.baQty}</span>` +\n `<button type=\"button\" data-ba=\"1\" aria-label=\"More seats\">+</button></div>` +\n `<button type=\"button\" class=\"sl-ba-go${this.bestAvailableBusy ? ' sl-busy' : ''}\"${this.bestAvailableBusy ? ' disabled' : ''}>` +\n (this.bestAvailableBusy\n ? `<span class=\"sl-ba-spin\" aria-hidden=\"true\"></span>Finding the best seats…`\n : `Find ${this.baQty} best ${this.baQty === 1 ? 'seat' : 'seats'}`) +\n `</button></div>`);\n }\n\n // Held line items (best-available, completed, or restored). Tier is\n // server-committed, but each item can be released without discarding the\n // rest of the hold.\n // Ticket-card identity grid: SECTION | ROW | SEAT, echoing the confirm\n // popover so the buyer meets the same identity pattern at confirm and in\n // the cart. Falls back to the raw label when spatial context is missing\n // (GA lines, legacy labels).\n const idGrid = (\n seatId: string | null,\n label: string,\n objectType?: HoldLineItem['objectType'] | PickerSeat['objectType'],\n quantity = 1,\n objectId?: string,\n identity?: Partial<PickerSeat>,\n ): string => {\n const esc = (value: unknown): string => String(value ?? '—').replace(/[&<>\"]/g, (char) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\n })[char]!);\n const d = seatId ? this.controller.seatDetails(seatId) : null;\n const area = objectType === 'ga' ? gaAreas.find((candidate) => candidate.id === objectId) : undefined;\n const effectiveType = objectType === 'ga' ? 'ga' : d?.objectType ?? objectType;\n const typeWord = identity?.displayType?.trim()\n || d?.displayType?.trim()\n || area?.displayType?.trim()\n || (effectiveType === 'table' ? 'Table' : effectiveType === 'booth' ? 'Booth' : effectiveType === 'ga' ? 'General admission' : 'Row');\n const buyerName = identity?.rowLabel\n ?? identity?.displayLabel\n ?? d?.rowLabel\n ?? d?.displayLabel\n ?? area?.displayLabel\n ?? area?.label\n ?? label;\n if (effectiveType === 'table' && identity?.bookingMode) {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span>` +\n `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Guests</span><span class=\"val\">${quantity}</span></span></div>`;\n }\n if (effectiveType === 'ga') {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span>` +\n (quantity > 1 ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Tickets</span><span class=\"val\">${quantity}</span></span>` : '') + `</div>`;\n }\n if (effectiveType === 'booth') {\n return `<div class=\"sl-chip-id\">` +\n (d?.sectionLabel ? `<span class=\"fld sec\"><span class=\"sl-chip-eb\">Section</span><span class=\"val\">${esc(d.sectionLabel)}</span></span>` : '') +\n `<span class=\"fld mid\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(buyerName)}</span></span></div>`;\n }\n if (!d?.sectionLabel && !d?.rowLabel && !d?.seatNumber) {\n return `<div class=\"sl-chip-id\"><span class=\"fld sec\"><span class=\"sl-chip-eb\">Seat</span><span class=\"val\">${esc(buyerName)}</span></span></div>`;\n }\n return (\n `<div class=\"sl-chip-id\">` +\n (d.sectionLabel ? `<span class=\"fld sec\"><span class=\"sl-chip-eb\">Section</span><span class=\"val\">${esc(d.sectionLabel)}</span></span>` : '') +\n (d.rowLabel ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">${esc(typeWord)}</span><span class=\"val\">${esc(this.rowShort(d))}</span></span>` : '') +\n (d.seatNumber ? `<span class=\"fld mid\"><span class=\"sl-chip-eb\">Seat</span><span class=\"val\">${esc(d.seatNumber)}</span></span>` : '') +\n `</div>`\n );\n };\n // Right icon rail per the canonical mock: remove on top, seat view below.\n const iconRail = (rmAria: string, viewLabel: string | null): string =>\n `<div class=\"sl-chip-rail\">` +\n `<button type=\"button\" class=\"rm\" aria-label=\"${rmAria}\">` +\n `<svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg></button>` +\n (viewLabel\n ? `<button type=\"button\" class=\"view\" data-view-label=\"${viewLabel}\" aria-label=\"${t('picker.viewFromSeat', { label: viewLabel })}\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg></button>`\n : '') +\n `</div>`;\n\n for (const item of heldItems) {\n const itemKey = `held:${item.label}`;\n nextTrayKeys.add(itemKey);\n const cat = this.controller.doc?.categories.find((c) => c.key === item.categoryKey);\n const tierName = item.tierId ? cat?.tiers?.find((ti) => ti.id === item.tierId)?.name : undefined;\n const heldSeat = item.objectType !== 'ga' ? this.controller.seatByLabel(item.label) : null;\n const table = item.objectType === 'table' ? this.controller.tableSelection(item.label) : null;\n const canView = this.seatViewEnabled() && !!heldSeat && item.objectType !== 'table';\n parts.push(\n `<div class=\"sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? '' : ' sl-enter'}\" data-key=\"${itemKey}\" data-held=\"${encodeURIComponent(item.label)}\"${heldSeat ? ` data-locate=\"${heldSeat.id}\"` : ''}>` +\n `<div class=\"sl-chip-main\">` +\n idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? undefined) +\n `<div class=\"sl-chip-sub\">` +\n `<span class=\"sl-ticket-state held\" aria-label=\"Held for you\" title=\"Held for you\">` +\n `<svg viewBox=\"0 0 24 24\"><rect x=\"5\" y=\"10\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 10V7a4 4 0 0 1 8 0v3\"/></svg></span>` +\n `<span class=\"cat\">${cat?.label ?? item.categoryKey}${tierName ? ` · ${tierName}` : ''}</span>` +\n (table?.bookingMode === 'variable'\n ? `<button type=\"button\" class=\"sl-table-edit\" data-table-edit=\"${encodeURIComponent(item.label)}\">${item.quantity ?? 1} guests · Edit</button>`\n : '') +\n this.wheelchairChipMarker(heldSeat?.wheelchairSpaceType) +\n this.commercialChipMarker(heldSeat?.commercial) +\n `<span class=\"amt\">${this.money(this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1))}</span>` +\n `</div></div>` +\n iconRail(`Remove held ticket ${item.label}`, canView ? item.label : null) +\n `</div>`,\n );\n }\n\n const heldLabels = new Set(heldItems.map((item) => item.label));\n const canView = this.seatViewEnabled();\n for (const s of seats.filter((seat) => !heldLabels.has(seat.label))) {\n const itemKey = `seat:${s.id}`;\n nextTrayKeys.add(itemKey);\n const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);\n const tierSelect =\n s.tiers && s.tiers.length\n ? `<select class=\"tier\" data-tier=\"${s.id}\" aria-label=\"${t('picker.ticketTierFor', { label: s.label })}\">` +\n s.tiers\n .map((ti) => `<option value=\"${ti.id}\"${ti.id === s.tierId ? ' selected' : ''}>${ti.name} · ${this.money(this.paidPrice(s.categoryKey, ti.id, ti.price))}</option>`)\n .join('') +\n `</select>`\n : '';\n parts.push(\n `<div class=\"sl-chip${this.lastTrayKeys.has(itemKey) ? '' : ' sl-enter'}\" data-key=\"${itemKey}\" data-seat=\"${s.id}\" data-locate=\"${s.id}\">` +\n `<div class=\"sl-chip-main\">` +\n idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) +\n `<div class=\"sl-chip-sub\">` +\n `<span class=\"sl-ticket-state\" aria-label=\"Selected\" title=\"Selected\">` +\n `<svg viewBox=\"0 0 24 24\"><path d=\"M5 12l4 4L19 6\"/></svg></span>` +\n `<span class=\"cat\">${cat?.label ?? s.categoryKey}</span>` +\n (s.objectType === 'table' && s.bookingMode === 'variable'\n ? `<button type=\"button\" class=\"sl-table-edit\" data-table-edit=\"${encodeURIComponent(s.label)}\">${s.quantity ?? 1} guests · Edit</button>`\n : '') +\n `${this.wheelchairChipMarker(s.wheelchairSpaceType)}${this.commercialChipMarker(s.commercial)}${tierSelect}` +\n `<span class=\"amt\">${this.money(this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1))}</span>` +\n `</div></div>` +\n iconRail(`Remove ${s.label}`, canView && s.objectType !== 'table' ? s.label : null) +\n `</div>`,\n );\n }\n\n for (const area of gaAreas) {\n const qty = this.gaQty.get(area.id) ?? 0;\n parts.push(\n `<div class=\"sl-ga\" data-ga=\"${area.id}\"><div class=\"sl-ga-info\">` +\n `<div class=\"sl-ga-name\">${area.displayLabel ?? area.label}</div>` +\n `<div class=\"sl-ga-sub\">${area.displayType ?? 'General admission'} · ${this.money(this.paidPrice(area.categoryKey, null, area.price))} · ${area.available} left</div></div>` +\n `<div class=\"sl-ga-qty\">` +\n `<button type=\"button\" data-d=\"-1\" aria-label=\"Fewer\">−</button><span>${qty}</span>` +\n `<button type=\"button\" data-d=\"1\" aria-label=\"More\">+</button></div></div>`,\n );\n }\n\n this.els.tray.innerHTML = parts.join('');\n this.lastTrayKeys = nextTrayKeys;\n this.els.tray.querySelectorAll<HTMLButtonElement>('[data-ba]').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.baQty = Math.max(1, Math.min(this.maxTickets, this.baQty + Number(btn.dataset.ba)));\n this.syncTray();\n });\n });\n this.els.tray.querySelector<HTMLSelectElement>('[data-ba-cat]')?.addEventListener('change', (e) => {\n this.baCat = (e.target as HTMLSelectElement).value;\n });\n this.els.tray.querySelector<HTMLSelectElement>('[data-ba-zone]')?.addEventListener('change', (e) => {\n this.baZone = (e.target as HTMLSelectElement).value;\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-premium]')?.addEventListener('click', () => {\n this.baPremium = !this.baPremium;\n this.syncTray();\n });\n this.els.tray.querySelector<HTMLButtonElement>('.sl-ba-go')?.addEventListener('click', () => {\n if (this.pendingSelectionCount() > 0) {\n this.bestAvailableConfirm = true;\n this.syncTray();\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-replace]')?.focus();\n return;\n }\n void this.bestAvailable(this.baQty, this.baCat || undefined, { preferPremium: this.baPremium, zoneId: this.baZone || undefined });\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-cancel]')?.addEventListener('click', () => {\n this.bestAvailableConfirm = false;\n this.syncTray();\n this.els.tray.querySelector<HTMLButtonElement>('.sl-ba-go')?.focus();\n });\n this.els.tray.querySelector<HTMLButtonElement>('[data-ba-replace]')?.addEventListener('click', () => {\n this.bestAvailableConfirm = false;\n void this.bestAvailable(this.baQty, this.baCat || undefined, { preferPremium: this.baPremium, zoneId: this.baZone || undefined });\n });\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip .rm').forEach((btn) => {\n btn.addEventListener('click', () => {\n const chip = btn.closest('.sl-chip') as HTMLElement;\n if (chip.dataset.held) {\n void this.removeHeldLabel(decodeURIComponent(chip.dataset.held), chip);\n return;\n }\n const id = chip.dataset.seat!;\n const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? 'Seat';\n const remove = (): void => {\n this.controller.deselect([id]);\n this.toast(`${label} removed.`, 'neutral', {\n label: 'Undo',\n onClick: () => {\n const restored = this.controller.select([id]);\n this.toast(\n restored.length ? `${label} restored.` : `${label} is no longer available.`,\n restored.length ? 'success' : 'warning',\n );\n },\n });\n };\n if (this.reducedMotion()) {\n remove();\n return;\n }\n chip.classList.add('sl-leave');\n this.scheduleMotion(remove, 150);\n });\n });\n this.els.tray.querySelectorAll<HTMLButtonElement>('[data-table-edit]').forEach((button) => {\n button.addEventListener('click', (event) => {\n event.stopPropagation();\n const label = decodeURIComponent(button.dataset.tableEdit ?? '');\n const details = this.controller.tableSelection(label);\n if (!details) return;\n const heldItem = heldItems.find((item) => item.label === label && item.objectType === 'table');\n this.showTableDialog(\n { ...details, quantity: heldItem?.quantity ?? details.quantity },\n !!heldItem,\n button,\n );\n });\n });\n // Per-seat ticket-tier pick (Adult/Child/…) — updates price via onSelectionChange.\n this.els.tray.querySelectorAll<HTMLSelectElement>('.sl-chip .tier').forEach((sel) => {\n sel.addEventListener('change', () => this.controller.setSeatTier(sel.dataset.tier!, sel.value || null));\n });\n // View-from-seat button (data-view-label = seat label) on fresh + held chips.\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip .view[data-view-label]').forEach((btn) => {\n btn.addEventListener('click', () => {\n const seat = this.controller.seatByLabel(btn.dataset.viewLabel!);\n if (seat) void this.openSeatView(seat);\n });\n });\n // Card ↔ map linkage: hovering (or keyboard-focusing) a ticket card pulses\n // its seat on the map so the buyer can locate what they picked.\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip[data-locate]').forEach((chip) => {\n const locate = (): void => this.controller.flashSeat(chip.dataset.locate!, this.cssVar('--sl-accent') || '#f4b740');\n chip.addEventListener('mouseenter', locate);\n chip.addEventListener('focusin', locate);\n });\n this.els.tray.querySelectorAll<HTMLElement>('.sl-ga button').forEach((btn) => {\n btn.addEventListener('click', () => {\n const areaEl = btn.closest('.sl-ga') as HTMLElement;\n const id = areaEl.dataset.ga!;\n const area = gaAreas.find((a) => a.id === id);\n const delta = Number(btn.dataset.d);\n if (delta > 0 && !this.canAddTicket()) return;\n const next = Math.max(0, Math.min(area?.available ?? 0, (this.gaQty.get(id) ?? 0) + delta));\n this.gaQty.set(id, next);\n this.syncTray();\n });\n });\n\n // Sales closed: freeze the best-available + GA controls (read-only state).\n if (this.salesClosed) {\n this.els.tray\n .querySelectorAll<HTMLButtonElement | HTMLSelectElement>('.sl-ba-go,[data-ba],[data-ba-cat],[data-ba-zone],[data-ba-replace],.sl-ga button')\n .forEach((el) => {\n el.disabled = true;\n });\n }\n\n // totals + CTA (held lines + fresh selections + GA)\n const gaTotal = this.pendingGATotal(gaAreas);\n const gaCount = this.pendingGACount();\n const heldTotal = heldItems.reduce((sum, item) => sum + this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1), 0);\n const heldCount = heldItems.reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n const freshSeats = seats.filter((seat) => !heldLabels.has(seat.label));\n const total = freshSeats.reduce(\n (sum, s) => sum + this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1),\n 0,\n ) + gaTotal + heldTotal;\n const count = freshSeats.reduce((sum, seat) => sum + (seat.quantity ?? 1), 0) + gaCount + heldCount;\n const pendingCount = this.pendingSelectionCount();\n const previousCount = this.lastTrayCount;\n const previousTotal = this.lastTrayTotal;\n this.els.count.textContent = count\n ? `${count} ${count === 1 ? 'ticket' : 'tickets'}`\n : 'No seats selected';\n this.els.total.textContent = count ? this.money(total) : '';\n this.root?.setAttribute('data-has-selection', String(count > 0));\n // The best-available panel's confirm (\"Replace your current choices?\") and\n // in-flight busy states must survive the narrow-layout collapse that hides\n // .sl-ba once the cart is non-empty. Mark them so the CSS keeps them shown.\n this.root?.setAttribute(\n 'data-ba-active',\n String(this.bestAvailableConfirm || this.bestAvailableBusy),\n );\n this.els.foot?.classList.toggle('empty', count === 0);\n if (this.els.seatSummary) {\n this.els.seatSummary.textContent = count ? `${count} selected` : '';\n }\n this.syncCta(count, pendingCount);\n if (this.hold) {\n const securedCount = heldCount || this.hold.seats?.length || 0;\n if (this.els.holdTitle) {\n this.els.holdTitle.textContent = `${securedCount} secured`;\n }\n if (this.els.holdCopy) {\n this.els.holdCopy.textContent = pendingCount\n ? `${pendingCount} more selected`\n : 'Checkout timer running';\n }\n const change = this.els.holdChange as HTMLButtonElement | undefined;\n if (change) {\n change.disabled = this.releasingHold;\n change.textContent = this.releasingHold ? 'Releasing…' : 'Change';\n }\n }\n if (count !== previousCount) this.animateOnce(this.els.count, 'sl-value-pop', 380);\n if (total !== previousTotal) this.animateOnce(this.els.total, 'sl-value-pop', 380);\n if (previousCount === 0 && count > 0) {\n this.animateOnce(this.els.cta, 'sl-ready', 520);\n // A seat just landed in a collapsed panel: reopen it. The cart, total and\n // checkout CTA all live in the panel — a collapse must never hide money.\n if (this.sideCollapsed && this.root?.dataset.layout !== 'narrow') this.setPanelCollapsed(false);\n }\n\n // Mobile sheet: one-line peek summary. Selected → \"N tickets · $X · Continue\";\n // empty → \"From $min · Best available\". Tap (sheet head) expands the sheet.\n if (this.els.peek) {\n if (count) {\n // Sheet state is shown by the persistent chevron in the head; the pill is\n // the action affordance (\"Continue\"/\"Review\") — no inline text arrow.\n /* THE PILL IS A BUTTON, AND IT DOES WHAT IT SAYS.\n It was a <span class=\"go\"> — role null, tabIndex -1, cursor:pointer.\n Dressed as a control and reachable by neither keyboard nor assistive\n tech, its taps fell through to the sheet head, which merely toggled the\n panel. So \"Continue\" closed the sheet and \"Best seats\" did nothing,\n which is exactly what the owner reported.\n\n With a hold and nothing pending, \"Continue\" IS the checkout — the same\n handleCta the footer button runs. That also answers the second half of\n the report: the footer lives inside the sheet and is hidden at peek, so\n a buyer with seats held had no visible way to pay. Now the collapsed\n bar is the way to pay. */\n const holding = !!this.hold && !pendingCount;\n this.els.peek.innerHTML =\n `<span>${count} ${count === 1 ? 'ticket' : 'tickets'} · ${this.money(total)}</span>` +\n `<button type=\"button\" class=\"go sl-sheet-go\" data-act=\"${holding ? 'checkout' : 'open'}\">` +\n `${this.hold ? (pendingCount ? 'Secure more' : 'Continue') : 'Review'}</button>`;\n } else if (this.salesClosed) {\n // The peek line is the closed state's ONLY voice while the sheet is\n // collapsed on a phone — \"From $18 · ✦ Best seats\" would be an\n // invitation to a flow that cannot start.\n this.els.peek.innerHTML = `<span>${this.tf('picker.salesClosedPill', 'Sales are closed')}</span>`;\n } else {\n const prices = (this.controller.doc?.categories ?? [])\n .map((c) => this.catPrice(c))\n .filter((p): p is number => p != null);\n /* Best-available is a FORM, not a verb — quantity, ticket type and zone\n are chosen first — so this opens the sheet at those controls rather\n than guessing a pick on the buyer's behalf. */\n this.els.peek.innerHTML =\n (prices.length ? `<span>From ${this.money(Math.min(...prices))}</span>` : '<span>Pick your seats</span>') +\n `<button type=\"button\" class=\"go sl-sheet-go\" data-act=\"open\">✦ Best seats</button>`;\n }\n }\n // Keep the mobile map stable after selection. The persistent Review pill\n // exposes the updated count/total without covering the seat the buyer just\n // confirmed; opening the sheet remains an explicit tap or swipe.\n this.lastTrayCount = count;\n this.lastTrayTotal = total;\n\n this.opts.onSelectionChange?.(seats);\n }\n\n private async removeHeldLabel(label: string, chip?: HTMLElement): Promise<boolean> {\n if (!label || this.releasingLabels.has(label)) return false;\n this.releasingLabels.add(label);\n chip?.setAttribute('aria-busy', 'true');\n const button = chip?.querySelector<HTMLButtonElement>('.rm');\n if (button) button.disabled = true;\n try {\n const preserveAcrossNavigation = this.handedOff;\n const released = await this.controller.releaseLabels([label]);\n if (!released) {\n this.toast(`Couldn't remove ${label}. Your hold is unchanged.`, 'error');\n return false;\n }\n const remaining = this.controller.currentHold();\n this.hold = remaining\n ? { holdId: remaining.holdId, expiresAt: remaining.expiresAt, seats: remaining.seats, items: remaining.items }\n : null;\n this.handedOff = !!this.hold && preserveAcrossNavigation;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n if (this.hold) {\n this.startHoldTimer(this.hold.expiresAt);\n } else {\n this.stopHoldTimer();\n this.forgetHold();\n }\n this.syncTray();\n this.emitHoldChange();\n this.toast(`${label} removed from your hold.`, 'success');\n return true;\n } finally {\n this.releasingLabels.delete(label);\n chip?.removeAttribute('aria-busy');\n if (button?.isConnected) button.disabled = false;\n }\n }\n\n private async handleChangeSeats(): Promise<void> {\n if (!this.hold || this.releasingHold) return;\n this.releasingHold = true;\n const button = this.els.holdChange as HTMLButtonElement | undefined;\n if (button) {\n button.disabled = true;\n button.textContent = 'Releasing…';\n }\n try {\n await this.release();\n if (!this.hold) this.toast('Held tickets released. Choose your new seats.', 'success');\n } finally {\n this.releasingHold = false;\n if (button?.isConnected) {\n button.disabled = false;\n button.textContent = 'Change';\n }\n }\n }\n\n private async handleCta(): Promise<void> {\n if (this.salesClosed) return;\n if (this.totalTicketCount() > this.maxTickets) {\n this.toast(`Remove tickets until your order has ${this.maxTickets} or fewer.`, 'warning');\n return;\n }\n // Best-available (or a prior CTA press) already holds the seats — hand off.\n // Held seats are NOT in the client selection (the server holds them), so\n // pass the hold's own seat list to the host.\n const committed = this.committedSelection();\n if (this.hold && !committed.some((s) => !(this.hold!.items ?? []).some((i) => i.label === s.label))) {\n const seats = this.hold.seats ?? committed;\n this.handedOff = true;\n this.setCtaPhase('checkout');\n this.checkoutHandoff(this.hold, seats);\n return;\n }\n this.holdingLabels = new Set(committed.map((seat) => seat.label));\n this.setCtaPhase('holding');\n try {\n // seats first (controller.hold covers selected seats); GA quantities ride along\n let hold: HoldResult | null = null;\n const gaEntries = [...this.gaQty.entries()].filter(([, q]) => q > 0);\n // Snapshot before hold — the hold's own WS echo repaints these seats.\n const chosenSeats = this.committedSelection();\n if (chosenSeats.length) {\n const h = await this.controller.hold(undefined, this.opts.holdTtlMs);\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n for (const [areaId, qty] of gaEntries) {\n const h = await this.controller.holdGA(areaId, qty, { ttlMs: this.opts.holdTtlMs });\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;\n }\n if (!hold) {\n this.toast('One or more seats were just taken. Please pick again.', 'error');\n this.setCtaPhase('idle');\n this.syncTray();\n return;\n }\n this.hold = hold;\n this.handedOff = true;\n this.startHoldTimer(hold.expiresAt);\n this.flashHeldSeats(hold);\n this.setCtaPhase('checkout');\n this.emitHoldChange();\n // The replacement hold can combine an earlier best-available set with\n // newly selected seats. Hand the host the complete held seat set; the\n // server-priced line items remain authoritative for GA and totals.\n this.checkoutHandoff(hold, hold.seats ?? chosenSeats);\n } catch (err) {\n this.opts.onError?.(err);\n const problem = err as { reason?: string; conflicts?: Array<{ label?: string }> };\n const labels = (problem.conflicts ?? []).map((conflict) => conflict.label).filter(Boolean).slice(0, 3);\n // The CTA's controller.hold() path doesn't surface onSalesClosed — apply the\n // persistent read-only state here (the toast below stays). book/bestAvailable\n // paths reach it via the onSalesClosed callback.\n if (problem.reason === 'event_closed') this.setSalesClosed(true);\n const message = problem.reason === 'event_closed'\n ? 'Seat sales have closed for this event.'\n : labels.length\n ? `${labels.join(', ')} ${labels.length === 1 ? 'is' : 'are'} no longer available. Choose another ${labels.length === 1 ? 'seat' : 'group'}.`\n : 'One or more seats were just taken. Please pick again.';\n this.toast(message, 'error');\n this.setCtaPhase('idle');\n } finally {\n this.holdingLabels.clear();\n if (this.ctaPhase === 'holding') this.ctaPhase = 'idle';\n this.syncTray();\n }\n }\n\n private startHoldTimer(expiresAt: number): void {\n this.stopHoldTimer();\n this.holdExpiresAt = expiresAt;\n if (this.hold) this.rememberHold(this.hold);\n const pill = this.els.hold;\n pill.innerHTML =\n '<span class=\"sl-hold-dot\" aria-hidden=\"true\"></span><span>Held</span><span class=\"sl-hold-time\" data-ref=\"holdTime\"></span>';\n const time = pill.querySelector<HTMLElement>('[data-ref=\"holdTime\"]');\n this.els.holdNote?.classList.add('on');\n const tick = (): void => {\n const ms = Math.max(0, this.holdExpiresAt - Date.now());\n const m = Math.floor(ms / 60000);\n const s = String(Math.floor((ms % 60000) / 1000)).padStart(2, '0');\n if (time) time.textContent = `${m}:${s}`;\n pill.classList.add('on');\n pill.classList.toggle('is-expiring', ms > 0 && ms <= EXTEND_PROMPT_MS);\n // Offer an extension in the final stretch (but not once it's booked/expired).\n this.setExtendPrompt(ms > 0 && ms <= EXTEND_PROMPT_MS, ms);\n if (ms <= 0) this.stopHoldTimer();\n };\n tick();\n this.holdTimer = setInterval(tick, 500);\n }\n\n private stopHoldTimer(): void {\n if (this.holdTimer) clearInterval(this.holdTimer);\n this.holdTimer = null;\n this.els.hold?.classList.remove('on', 'is-expiring');\n this.els.holdNote?.classList.remove('on');\n this.setExtendPrompt(false, 0);\n }\n\n /** Show/refresh (or hide) the \"Need more time?\" prompt with the live seconds left. */\n private setExtendPrompt(show: boolean, ms: number): void {\n if (!this.extendEl) return;\n if (show && this.controller.currentHold() && !this.bookedShown) {\n const secs = Math.ceil(ms / 1000);\n this.els.extendTxt.innerHTML = `Your seats are held for <b>0:${String(secs).padStart(2, '0')}</b>. Need more time?`;\n this.extendEl.classList.add('on');\n } else {\n this.extendEl.classList.remove('on');\n }\n }\n\n private async handleExtend(): Promise<void> {\n const btn = this.els.extendBtn as HTMLButtonElement;\n btn.disabled = true;\n const prev = btn.textContent;\n btn.textContent = 'Adding…';\n try {\n const h = await this.controller.extendHold(this.opts.holdTtlMs);\n if (h) {\n // The controller re-armed its own expiry; sync ours + the pill, hide prompt.\n this.hold = { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items };\n this.holdExpiresAt = h.expiresAt;\n this.extendEl?.classList.remove('on');\n this.rememberHold(this.hold);\n this.emitHoldChange();\n this.toast('More time added — your seats are still held.', 'success');\n } else {\n this.toast(\"Couldn't add more time — please head to checkout now.\", 'warning');\n }\n } catch (err) {\n this.opts.onError?.(err);\n this.toast(\"Couldn't add more time — please head to checkout now.\", 'warning');\n } finally {\n btn.disabled = false;\n btn.textContent = prev;\n }\n }\n\n /**\n * Fire the booked-confirmation state once the buyer's held seats settle to\n * booked. The controller clears its own hold the moment every held label reads\n * 'booked' over the realtime channel (clearBookedHoldIfSettled), and this runs\n * on the same onStatusChange — so `currentHold() === null` while we still hold\n * a checkout handoff means \"sold\", not expired (expiry clears via onHoldExpired\n * on a different path, which nulls this.hold first).\n */\n private detectBooked(): void {\n if (this.bookedShown || !this.handedOff || !this.hold) return;\n if (this.controller.currentHold() !== null) return; // hold still open\n this.showBooked();\n }\n\n private showBooked(): void {\n if (this.bookedShown || !this.hold) return;\n this.bookedShown = true;\n const handoff = this.buildHandoff(this.hold);\n this.stopHoldTimer();\n this.forgetHold();\n const n = handoff.lineItems.reduce((sum, i) => sum + i.quantity, 0);\n if (this.els.bookedSub) {\n this.els.bookedSub.innerHTML =\n `<span class=\"sl-booked-seats\">${n} ${n === 1 ? 'ticket' : 'tickets'}</span> confirmed. ` +\n `A confirmation is on its way.`;\n }\n this.bookedEl?.classList.add('on');\n this.opts.onBooked?.(handoff);\n }\n\n /**\n * The seats are held. Send the buyer wherever this picker's `checkout` option\n * says they go.\n *\n * The default branch is the literal call that stood here before hosted\n * checkout existed, unchanged, so nothing about an existing integration moves.\n */\n private checkoutHandoff(hold: HoldResult, seats: PickerSeat[]): void {\n if (this.checkoutMode === 'hosted') {\n void this.startHostedCheckout(hold, seats);\n return;\n }\n this.opts.onCheckout?.(hold, seats, this.buildHandoff(hold));\n }\n\n /**\n * Take the money ourselves, through the organizer's own gateway.\n *\n * Order of operations matters: ASK FIRST, load second. `payment-options` is\n * already in flight from render, and its answer decides whether any payment\n * code is fetched at all — an event that cannot charge never downloads the\n * card that would have charged it.\n *\n * An empty list is not a failure and never dead-ends the buyer. It routes them\n * to whatever the host has: `onCheckoutUnavailable` (with the server's reason,\n * so the host can say the right one of three very different sentences), then\n * `onCheckout` with the ordinary handoff. A host that supplied neither gets\n * the widget's own honest card instead of a press that did nothing.\n */\n private async startHostedCheckout(hold: HoldResult, seats: PickerSeat[]): Promise<void> {\n const handoff = this.buildHandoff(hold);\n let options: PaymentOptionsResult | null = null;\n try {\n options = await (this.paymentOptions ??= this.pubApi!.paymentOptions(this.opts.event));\n } catch (err) {\n // A failed lookup is not evidence about the organizer's setup, so it falls\n // through to the reason that asserts the least about them.\n this.opts.onError?.(err);\n }\n if (this.destroyed) return;\n\n const provider = options?.providers?.[0];\n if (!provider) {\n const reason = paymentsOffReason(options?.reason);\n const handled = !!this.opts.onCheckoutUnavailable || !!this.opts.onCheckout;\n this.opts.onCheckoutUnavailable?.({ reason, handoff });\n this.opts.onCheckout?.(hold, seats, handoff);\n if (!handled) {\n void this.openCheckoutPanel({\n kind: 'unavailable',\n reason,\n seatCount: handoff.lineItems.reduce((sum, item) => sum + item.quantity, 0),\n });\n }\n return;\n }\n\n await this.openCheckoutPanel({\n kind: 'pay',\n provider,\n order: {\n holdId: handoff.holdId,\n expiresAt: handoff.expiresAt,\n currency: handoff.currency,\n total: handoff.total,\n labels: handoff.lineItems.map((item) => item.displayLabel ?? item.label),\n },\n });\n }\n\n /**\n * Fetch the checkout chunk and put its card over the map.\n *\n * Every failure here lands the buyer back on a map with their seats still\n * held, which is a place they can act from — a blocked chunk request must not\n * leave them staring at a CTA that no longer does anything.\n */\n private async openCheckoutPanel(state: CheckoutState): Promise<void> {\n let mountCheckout: HostedCheckoutModule['mountCheckout'];\n try {\n ({ mountCheckout } = await loadHostedCheckout());\n } catch (err) {\n this.opts.onError?.(err);\n this.toast('Checkout could not be opened. Your seats are still held — please try again.', 'error');\n this.setCtaPhase('idle');\n return;\n }\n if (this.destroyed || !this.root) return;\n this.closeCheckoutPanel();\n this.checkoutPanel = mountCheckout({\n root: this.root,\n state,\n // `returnUrl` rides along so a redirecting gateway can come back to the\n // HOST's page. The server validates its origin against the organizer's\n // declared embed domains and silently falls back to our own buyer page\n // when it does not match, so passing one can never redirect a paid buyer\n // somewhere the organizer did not sanction.\n startSession: (input) => this.pubApi!.startCheckout(this.opts.event, {\n ...input,\n ...(this.opts.returnUrl ? { returnUrl: this.opts.returnUrl } : {}),\n }),\n orderStatus: (orderId) => this.pubApi!.orderStatus(orderId),\n onCancel: () => {\n this.checkoutPanel = null;\n // The hold is untouched by cancelling — the buyer goes back to a map\n // that still has their seats, and the CTA still says checkout.\n if (!this.hold) this.setCtaPhase('idle');\n },\n onConfirmed: (order) => {\n this.opts.onOrderConfirmed?.(order);\n // The seats are sold. Re-read the map so they repaint as booked for this\n // buyer immediately rather than whenever the next realtime frame lands.\n void this.controller.refresh();\n },\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n private closeCheckoutPanel(): void {\n this.checkoutPanel?.destroy();\n this.checkoutPanel = null;\n }\n\n /** Assemble the stable {@link CheckoutHandoff} from a hold's server line items. */\n private buildHandoff(hold: HoldResult): CheckoutHandoff {\n const items = hold.items ?? [];\n // Host `pricing` overrides win in the handoff too — the host gets back the\n // prices it will actually charge, so map display and order total agree.\n const lineItems: CheckoutLineItem[] = items.map((it: HoldLineItem) => {\n const display = this.controller.lineItemDisplay(it);\n return {\n label: it.label,\n ...(display.displayLabel ? { displayLabel: display.displayLabel } : {}),\n ...(display.displayType ? { displayType: display.displayType } : {}),\n objectId: it.objectId,\n objectType: it.objectType,\n categoryKey: it.categoryKey,\n tierId: it.tierId,\n unitPrice: this.paidPrice(it.categoryKey, it.tierId, it.unitPrice),\n currency: it.currency ?? this.currency,\n quantity: it.quantity ?? 1,\n };\n });\n const currency = lineItems[0]?.currency ?? this.currency;\n const total = lineItems.reduce((sum, i) => sum + i.unitPrice * i.quantity, 0);\n return { holdId: hold.holdId, expiresAt: hold.expiresAt, currency, lineItems, total };\n }\n\n private emitHoldChange(): void {\n const hold = this.hold;\n this.scheduleOfferRefresh(true);\n this.opts.onHoldChange?.(\n hold,\n hold?.seats ?? [],\n hold ? this.buildHandoff(hold) : null,\n );\n }\n\n private toast(\n msg: string,\n tone: 'neutral' | 'success' | 'warning' | 'error' = 'neutral',\n action?: { label: string; onClick: () => void },\n ): void {\n const el = this.els.toast;\n if (!el) return;\n el.replaceChildren();\n const copy = document.createElement('span');\n copy.textContent = msg;\n el.appendChild(copy);\n el.classList.toggle('has-action', !!action);\n if (action) {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'sl-toast-action';\n button.textContent = action.label;\n button.addEventListener('click', action.onClick, { once: true });\n el.appendChild(button);\n }\n el.dataset.tone = tone;\n el.classList.add('on');\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toastTimer = setTimeout(() => {\n el.classList.remove('on');\n el.classList.remove('has-action');\n el.dataset.tone = 'neutral';\n }, 4200);\n }\n\n private placeTooltip(): void {\n if (!this.tipEl) return;\n const hw = this.els.map.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n /**\n * Row label without the redundant section prefix. Charts commonly name row\n * objects \"104-A\" while the Section column already shows \"104\" — so the Row\n * cell repeats the section and, in the compact hover card, truncates to\n * \"10…\". Strip a leading \"<section><sep>\" so Row reads a clean \"A\". Only when\n * the prefix is exact (won't touch \"1040-A\" under section \"104\"); otherwise\n * the label is shown verbatim.\n */\n /** Buyer-facing type word for the row/table key label — the designer's\n * per-object \"Displayed type\" override, or the default \"Row\". */\n private rowTypeWord(details: { displayType?: string; rowType?: string; objectType?: PickerSeat['objectType'] } | null | undefined): string {\n const authored = details?.displayType?.trim() || details?.rowType?.trim();\n if (authored) return authored;\n if (details?.objectType === 'table') return 'Table';\n if (details?.objectType === 'booth') return 'Booth';\n return 'Row';\n }\n\n private rowShort(details: { sectionLabel?: string; rowLabel?: string } | null | undefined): string | undefined {\n const row = details?.rowLabel;\n const sec = details?.sectionLabel;\n if (!row || !sec) return row;\n for (const sep of ['-', ' ', '·', '/', '_']) {\n const prefix = `${sec}${sep}`;\n if (row.startsWith(prefix) && row.length > prefix.length) return row.slice(prefix.length);\n }\n return row;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const esc = (v: unknown): string =>\n String(v ?? '—').replace(/[&<>\"]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[ch]!));\n const price = this.money(this.paidPrice(details.categoryKey, details.tierId ?? null, details.price));\n // Identity grid — the same Section·Row·Seat card the buyer meets on confirm\n // and in the cart, just smaller. Falls back to a single field for a bare\n // label (GA / legacy seats with no spatial context).\n const isGroupedTable = details.objectType === 'table' && !!details.bookingMode;\n const isBooth = details.objectType === 'booth';\n const hasLoc = details.sectionLabel || details.rowLabel || details.seatNumber;\n const grid = isGroupedTable\n ? `<div class=\"sl-tip-grid\">` +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div>` +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Guests</span><span class=\"sl-tip-val\">${details.bookingMode === 'variable' ? `${details.minOccupancy}–${details.maxOccupancy}` : details.capacity}</span></div>` +\n `</div>`\n : isBooth\n ? `<div class=\"sl-tip-grid\">` +\n (details.sectionLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Section</span><span class=\"sl-tip-val\">${esc(details.sectionLabel)}</span></div>` : '') +\n `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div>` +\n `</div>`\n : hasLoc\n ? `<div class=\"sl-tip-grid\">` +\n (details.sectionLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Section</span><span class=\"sl-tip-val\">${esc(details.sectionLabel)}</span></div>` : '') +\n (details.rowLabel ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">${esc(this.rowTypeWord(details))}</span><span class=\"sl-tip-val\">${esc(this.rowShort(details))}</span></div>` : '') +\n (details.seatNumber ? `<div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Seat</span><span class=\"sl-tip-val\">${esc(details.seatNumber)}</span></div>` : '') +\n `</div>`\n : `<div class=\"sl-tip-grid one\"><div class=\"sl-tip-field\"><span class=\"sl-tip-key\">Seat</span><span class=\"sl-tip-val\">${esc(details.displayLabel ?? details.label)}</span></div></div>`;\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div class=\"sl-tip-status\">${details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')}</div>`;\n const limited = this.limitedViewLabel(details.commercial);\n const cxLine = limited\n ? `<div class=\"sl-tip-cx\"><span class=\"g\" aria-hidden=\"true\">◐</span>${esc(limited)}</div>`\n : '';\n const wheelchair = this.wheelchairProvisionLabel(details.wheelchairSpaceType);\n const wheelchairLine = wheelchair\n ? `<div class=\"sl-tip-cx\"><span class=\"g\" aria-hidden=\"true\">♿</span>${esc(wheelchair)}</div>`\n : '';\n this.tipEl.style.setProperty('--sl-cat', details.categoryColor);\n this.tipEl.innerHTML =\n grid +\n `<div class=\"sl-tip-cat\"><span class=\"sl-tip-dot\" style=\"background:${details.categoryColor}\"></span>` +\n `<span class=\"sl-tip-name\">${esc(details.categoryLabel)}</span>` +\n `<span class=\"sl-tip-amt\">${price}</span></div>` +\n wheelchairLine +\n cxLine +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n // ---- public conveniences ----------------------------------------------------\n\n getSelection(): PickerSeat[] {\n return this.committedSelection();\n }\n\n /**\n * Re-ink the DRAWN MAP after mount, so the canvas can follow a page palette\n * the host did not know at construction time.\n *\n * Deliberately narrower than the `theme` option: it takes only the map half.\n * The chrome half is CSS custom properties, which a host restyles from its\n * own stylesheet without asking the widget for anything — and a host that\n * used both mechanisms at once would have two things writing one token. This\n * method exists for the half CSS genuinely cannot reach: pixels Konva draws.\n *\n * The rebuild is the controller's (`setMapTheme`), which repaints statuses\n * from the map already in memory and restores the selection, so a buyer\n * mid-pick keeps their seats and no round trip is spent. A no-op when the\n * colours have not changed; safe to call on every render.\n */\n setMapTheme(map: PickerMapTheme | null): void {\n if (this.destroyed) return;\n this.opts.theme = { ...(this.opts.theme ?? {}), map: map ?? undefined };\n this.controller.setMapTheme(map);\n }\n\n /**\n * Let a host suppress duplicate event identity after mount without remounting\n * the live picker (and therefore without disturbing a selection or hold).\n * Full-screen mode still restores the identity until the buyer exits it.\n */\n setEventDetailsHidden(hidden: boolean): void {\n this.eventDetailsHidden = hidden;\n this.syncFullscreenButtons();\n }\n\n /**\n * Replace the host pricing override AFTER mount, and repaint everything that\n * shows a price.\n *\n * WHY IT CANNOT JUST BE A MOUNT OPTION. The prices a host knows are often not\n * the prices it knows AT MOUNT: SeatLayer's own event page learns them from\n * `GET /pub/events/:key/availability`, a separate cached read that lands a\n * round trip after the map does — deliberately, because the map is not\n * allowed to wait on it. Remounting the widget to hand it new options would\n * tear down a live hold, so the override is settable in place.\n *\n * The prices themselves are still the SERVER'S. This method takes an answer;\n * it never derives one. Nothing here re-reads a release, a window or a quota\n * — see `paidPrice`, the one funnel every displayed price flows through, and\n * note that the checkout handoff's line items do not come from here at all:\n * they are priced by the worker from its own hold. So the worst a wrong call\n * to this method can do is misprint a price, never mischarge one.\n *\n * A no-op when the map is unchanged, so a host may call it on every poll.\n */\n setPricing(pricing: SeatPickerPricing | undefined): void {\n const before = JSON.stringify(this.opts.pricing ?? null);\n const after = JSON.stringify(pricing ?? null);\n if (before === after) return;\n this.opts.pricing = pricing;\n if (this.destroyed || !this.els.prices) return;\n // The band selector is DERIVED from prices, so a repriced chart can have a\n // different set of bands (or stop having enough distinct prices to warrant\n // one at all). Rebuild it rather than leaving a stale chip list behind.\n this.els.pricesSec?.querySelector('.sl-price-select')?.remove();\n this.buildPriceFilter();\n this.syncPrices();\n this.syncTray();\n // An open section card and an open confirm popover both print a price.\n if (this.lastSection) this.showSectionCard(this.lastSection);\n }\n\n /** Current colorblind-safe render state, resolved from the stored buyer\n * preference at mount. Host chrome (e.g. the Designer preview) reads this to\n * surface the state rather than rendering colorblind colors silently. */\n isColorblindSafe(): boolean {\n return this.cbSafe;\n }\n\n /** Single source of truth for the colorblind-safe toggle — used by both the\n * in-widget button and host chrome. Updates the renderer, the persisted\n * cross-surface preference, and the in-widget button's pressed state together\n * so the two controls never diverge. */\n setColorblindSafe(on: boolean): void {\n if (on === this.cbSafe) return;\n this.cbSafe = on;\n this.cbEl?.setAttribute('aria-pressed', String(on));\n this.controller.setColorblindSafe(on);\n // Persist under the SAME key the public page uses (cross-surface preference).\n writeStoredColorblind(on);\n }\n\n /** Switch the underlying 2D renderer projection (flat / isometric). The buyer\n * UI no longer exposes `perspective`; it is coerced to `flat`. */\n setViewMode(mode: RendererViewMode): void {\n this.controller.setViewMode(this.normalizeInitialView(mode));\n this.syncProjection();\n this.dismissConfirm();\n }\n\n /** Current buyer canvas projection. */\n getViewMode(): RendererViewMode {\n return this.controller.getViewMode();\n }\n\n /** `perspective` (2.5D) is retired from the buyer surface — accept it for\n * source compatibility but coerce to `flat` with a one-time deprecation warn. */\n private perspectiveWarned = false;\n private normalizeInitialView(mode: RendererViewMode | undefined): RendererViewMode {\n if (mode === 'perspective') {\n if (!this.perspectiveWarned) {\n this.perspectiveWarned = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[seatlayer] initialView:'perspective' (2.5D) is deprecated for the buyer picker and \"\n + \"was coerced to 'flat'. Use the Map | 3D control for the immersive view.\",\n );\n }\n return 'flat';\n }\n return mode ?? 'flat';\n }\n\n // ---- 3D venue view ---------------------------------------------------------\n\n /** Current buyer view: the flat map, or the interactive 3D venue. */\n getBuyerView(): SeatPickerBuyerView {\n return this.buyerView;\n }\n\n /**\n * Switch between the flat seat **Map** and the interactive **3D venue** view —\n * the same control the buyer's on-widget `Map | 3D` toggle drives.\n *\n * Entering `'venue3d'` with `opts.flyToSeatId` runs the cinematic tour: the\n * camera flies to the seat and holds in the live scene (a chip offers the\n * 360° view-from-seat). When the widget is **already** in the 3D\n * view, the camera simply flies to the requested seat — the GL scene is not\n * torn down or rebuilt, so there is no flash or re-entry.\n *\n * No-op when the view is unchanged and no `flyToSeatId` is given, or when 3D is\n * unavailable for this chart.\n *\n * @param view `'map'` for the flat picker, `'venue3d'` for the 3D venue.\n * @param opts.flyToSeatId When entering (or already in) `'venue3d'`, the seat\n * id to fly the camera to — cinematic → live seat view.\n * Ignored when `view` is `'map'`.\n *\n * @example\n * // Public 3D tour entry — enter 3D and fly straight to the buyer's seat:\n * picker.setBuyerView('venue3d', { flyToSeatId: 'A-12' });\n */\n setBuyerView(view: SeatPickerBuyerView, opts?: SeatPickerBuyerViewOptions): void {\n if (view === 'map') {\n this.exit3d();\n return;\n }\n const flyToSeatId = opts?.flyToSeatId;\n if (this.buyerView === 'venue3d') {\n // Already immersed — just fly the cinematic to the requested seat (if any),\n // without a jarring teardown/rebuild of the GL scene.\n if (flyToSeatId) {\n this.opts.onBuyerViewChange?.({ view: 'venue3d', seatId: flyToSeatId });\n void this.view3dHandle?.flyToSeat(flyToSeatId);\n } else if (opts?.resetView) {\n this.view3dHandle?.focusOverview();\n }\n return;\n }\n // Enter 3D; when a seat is given, the cinematic flies straight to it.\n void this.enter3d(flyToSeatId);\n }\n\n /** SeatStatus → the view3d palette state. Selection is layered separately. */\n private seatState3dFor(seat: ExpandedSeat): 'available' | 'held' | 'sold' | 'dimmed' {\n switch (this.controller.getStatus(seat.id)) {\n case 'held': return 'held';\n case 'booked': return 'sold';\n case 'not_for_sale': return 'dimmed';\n default: break;\n }\n // A filter that dims a seat on the map has to dim it in 3D too. 2D applies\n // these as Konva opacity, which the GL view never saw — so a buyer who\n // filtered to one price band and then switched to 3D got the unfiltered\n // venue back with no indication the filter was still on. The 'dimmed' state\n // already exists for held-back inventory and is exactly this treatment.\n if (this.priceBandKeys != null && !this.priceBandKeys.has(seat.categoryKey)) return 'dimmed';\n if (this.limitedViewFilter && (seat.commercial?.restrictedView || seat.commercial?.obstructedView)) {\n return 'dimmed';\n }\n return 'available';\n }\n\n /** Push the full live availability snapshot into the 3D handle (selection is\n * preserved inside the module). Cheap enough per status delta. */\n private pushAvailabilityTo3d(): void {\n if (!this.view3dHandle) return;\n const updates = this.allSeats().map((s) => ({ seatId: s.id, state: this.seatState3dFor(s) }));\n this.view3dHandle.setAvailability(updates);\n }\n\n /** Mirror the authoritative widget selection into the 3D handle. */\n private syncSelectionTo3d(): void {\n if (!this.view3dHandle) return;\n this.view3dHandle.setSelection(this.controller.getSelection().map((s) => s.id));\n }\n\n /** Build the view-from-seat panorama the cinematic dissolves into — reuses the\n * exact input path as the 2D `openSeatView` (organizer photo, else generated). */\n private async seatViewFor3d(seatId: string): Promise<View3DSeatView | null> {\n const seat = this.allSeats().find((s) => s.id === seatId);\n if (!seat) return null;\n if (seat.viewUrl) {\n try {\n const previewReference = seat.viewMeta?.previewUrl;\n const progressive = !!previewReference && previewReference !== seat.viewUrl;\n const previewUrl = progressive\n ? await this.buyerAssetUrls.resolve(previewReference)\n : null;\n const url = progressive\n ? seat.viewUrl\n : await this.buyerAssetUrls.resolve(seat.viewUrl);\n if (!url) return null;\n if (progressive && !previewUrl) return null;\n return {\n url,\n ...(previewUrl ? { previewUrl } : {}),\n ...(progressive ? { resolveUrl: (reference: string) => this.buyerAssetUrls.resolve(reference) } : {}),\n ...(seat.viewMeta?.sourceWidth !== undefined ? { sourceWidth: seat.viewMeta.sourceWidth } : {}),\n ...(seat.viewMeta?.sourceHeight !== undefined ? { sourceHeight: seat.viewMeta.sourceHeight } : {}),\n ...(seat.viewMeta?.previewWidth !== undefined ? { previewWidth: seat.viewMeta.previewWidth } : {}),\n ...(seat.viewMeta?.previewHeight !== undefined ? { previewHeight: seat.viewMeta.previewHeight } : {}),\n ...(seat.viewMeta?.initialBearingDeg !== undefined ? { initialBearingDeg: seat.viewMeta.initialBearingDeg } : {}),\n ...(seat.viewMeta?.initialPitchDeg !== undefined ? { initialPitchDeg: seat.viewMeta.initialPitchDeg } : {}),\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n };\n } catch (error) {\n this.opts.onError?.(error);\n return null;\n }\n }\n // No authored panorama: keep the buyer in the resolution-independent live\n // venue at the selected seat-eye. The old path eagerly generated a 2048px\n // bitmap only so view3d could discard it and render this same scene again.\n return {\n url: '',\n generated: true,\n mediaKind: 'model',\n coverage: 'exact-seat',\n sourceLabel: this.tf('picker.chartDerivedModel', 'Chart-derived model'),\n };\n }\n\n /** Route the module's decoupled analytics into the host callback, tagged buyer. */\n private emit3dAnalytics(event: string, props?: Record<string, unknown>): void {\n try {\n this.opts.onAnalytics?.(event, { ...props, surface: 'buyer' });\n } catch {\n /* a throwing host sink never breaks the widget */\n }\n }\n\n /** A 3D seat tap runs the SAME selection path as a 2D tap: toggle through the\n * controller, then raise the shared confirm card (bottom-sheeted in 3D). */\n private onView3dSeatPick(seatId: string): void {\n if (this.salesClosed) {\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n this.syncSelectionTo3d();\n return;\n }\n const seat = this.allSeats().find((s) => s.id === seatId);\n if (!seat) return;\n const table = this.controller.tableSelection(seatId);\n // Tapping an already-committed seat clears it (mirrors the 2D toggle).\n const already = this.committedSelection().some((s) => table ? s.label === table.label : s.id === seatId);\n if (already) {\n this.controller.deselect([seatId]);\n this.dismissConfirm();\n this.syncSelectionTo3d();\n return;\n }\n const visualState = this.seatState3dFor(seat);\n if (visualState !== 'available') {\n this.showUnavailable3dSeat(seat, visualState);\n this.syncSelectionTo3d();\n return;\n }\n this.dismissUnavailable3dSeat();\n const added = this.controller.select([seatId]); // programmatic select is silent\n if (!added.length) {\n // The GL picker optimistically highlighted the instance. Restore the\n // controller's authoritative state when inventory rejects the tap.\n this.syncSelectionTo3d();\n this.dismissConfirm();\n return;\n }\n this.opts.onBuyerViewChange?.({ view: 'venue3d', seatId });\n this.flashPickedSeat(seatId);\n if (table) {\n this.showTableDialog(table, false);\n this.syncSelectionTo3d();\n return;\n }\n if (this.opts.confirmSelection !== false) this.showConfirm(seat);\n else this.syncTray();\n // Replace the renderer's one-seat optimistic preview with the controller's\n // complete authoritative selection after the host mutation. Otherwise a\n // newly tapped blue chair can disagree with the committed \"Your seats\" list.\n this.syncSelectionTo3d();\n }\n\n /** Explain a visible-but-unselectable 3D seat without entering the booking\n * flow. Category colour remains visible in the venue; this card names the\n * availability state explicitly so yellow never has to carry both meanings. */\n private showUnavailable3dSeat(seat: ExpandedSeat, visualState: SeatState3D): void {\n const overlay = this.view3dEl;\n if (!overlay) return;\n this.dismissUnavailable3dSeat();\n const status = this.controller.getStatus(seat.id);\n const details = this.controller.seatDetails(seat.id);\n const identity = details?.displayLabel ?? seat.displayLabel ?? seat.label;\n const section = details?.sectionLabel;\n const row = this.rowShort(details);\n const location = [section, row ? `Row ${row}` : null, identity].filter(Boolean).join(' · ');\n const copy = status === 'held'\n ? {\n title: this.tf('picker.temporarilyHeld', 'Temporarily held'),\n message: this.tf('picker.heldSeatExplanation', 'Another buyer is holding this seat. It may become available again.'),\n }\n : status === 'booked'\n ? {\n title: this.tf('picker.sold', 'Sold'),\n message: this.tf('picker.soldSeatExplanation', 'This seat has already been booked.'),\n }\n : status === 'not_for_sale'\n ? {\n title: this.tf('picker.notForSale', 'Not for sale'),\n message: this.tf('picker.notForSaleExplanation', 'This seat is not included in the current sale.'),\n }\n : {\n title: this.tf('picker.filteredSeat', 'Unavailable with current filters'),\n message: this.tf('picker.filteredSeatExplanation', 'Change the active price or view filters to make this seat selectable.'),\n };\n const card = document.createElement('div');\n card.className = 'sl-view3d-unavailable';\n card.dataset.state = visualState;\n card.setAttribute('role', 'status');\n card.setAttribute('aria-live', 'polite');\n const eyebrow = document.createElement('span');\n eyebrow.className = 'sl-view3d-unavailable-eyebrow';\n eyebrow.textContent = location || identity;\n const title = document.createElement('strong');\n title.textContent = copy.title;\n const content = document.createElement('div');\n content.className = 'sl-view3d-unavailable-copy';\n content.append(eyebrow, title);\n const close = document.createElement('button');\n close.type = 'button';\n close.setAttribute('aria-label', this.tf('picker.closeSeatStatus', 'Close seat status'));\n close.textContent = '×';\n const message = document.createElement('p');\n message.textContent = copy.message;\n card.append(content, close, message);\n close.addEventListener('click', () => card.remove());\n overlay.appendChild(card);\n this.announceSeat(seat);\n }\n\n private dismissUnavailable3dSeat(): void {\n this.view3dEl?.querySelector('.sl-view3d-unavailable')?.remove();\n }\n\n /** Comparison belongs to inspection, never selection. The confirm candidate\n * remains excluded from checkout until Select; saving it releases that\n * candidate before any comparison state is created. */\n private view3dCompareConfirmHtml(seat: ExpandedSeat): string {\n if (this.buyerView !== 'venue3d') return '';\n const saved = this.view3dCompareSeatIds;\n const included = saved.includes(seat.id);\n const label = included\n ? saved.length > 1\n ? this.tf('picker.openComparison', 'Open comparison')\n : this.tf('picker.savedForComparison', 'Saved for comparison')\n : saved.length\n ? this.tf('picker.compareWithSaved', 'Compare with saved')\n : this.tf('picker.saveToCompare', 'Save to compare');\n return `<button type=\"button\" class=\"sl-confirm-compare\"${included && saved.length === 1 ? ' disabled' : ''}>`\n + `<span aria-hidden=\"true\">⇄</span><span>${this.escCx(label)}</span></button>`;\n }\n\n private seatConfidenceConfirmHtml(seat: ExpandedSeat, compactSummary: string): string {\n if (this.buyerView !== 'venue3d') return '';\n const disclosure = seatConfidenceDisclosure(seat.confidenceEvidence);\n const detail = disclosure.modeledTarget ?? disclosure.reality;\n return `<button type=\"button\" class=\"sl-confirm-confidence\" aria-label=\"Open seat confidence passport for ${this.escCx(seat.displayLabel ?? seat.label)}\">`\n + `<span><em>${this.escCx(compactSummary)}</em><strong>${this.escCx(disclosure.headline)}</strong><small>${this.escCx(detail)}</small></span>`\n + `<b>Passport</b></button>`;\n }\n\n private saveView3dComparisonSeat(seat: ExpandedSeat): void {\n if (this.buyerView !== 'venue3d') return;\n const previous = this.view3dCompareSeatIds;\n if (!previous.includes(seat.id)) {\n this.view3dCompareSeatIds = previous.length === 0\n ? [seat.id]\n : [previous[0]!, seat.id];\n }\n // A confirm candidate is an optimistic renderer/controller selection. A\n // saved comparison seat must not survive as a cart line or checkout total.\n if (this.confirmSeat?.id === seat.id) {\n this.controller.deselect([seat.id]);\n this.dismissConfirm();\n this.syncSelectionTo3d();\n this.syncTray();\n }\n this.syncView3dCompareChip();\n this.emit3dAnalytics('3d_comparison_saved', {\n seatId: seat.id,\n count: this.view3dCompareSeatIds.length,\n });\n if (this.view3dCompareSeatIds.length > 1) this.openView3dComparison();\n else this.toast(this.tf('picker.chooseAnotherToCompare', 'Seat saved. Choose another seat to compare.'), 'success');\n }\n\n private clearView3dComparison(): void {\n this.closeView3dComparison(false);\n this.view3dCompareSeatIds = [];\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n this.emit3dAnalytics('3d_comparison_cleared');\n }\n\n private syncView3dCompareChip(): void {\n const overlay = this.view3dEl;\n if (!overlay || this.view3dCompareSeatIds.length === 0) {\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n return;\n }\n let chip = this.view3dCompareChip;\n if (!chip) {\n chip = document.createElement('div');\n chip.className = 'sl-view3d-compare-saved';\n chip.setAttribute('role', 'group');\n chip.setAttribute('aria-label', 'Saved seat comparison');\n const main = document.createElement('button');\n main.type = 'button';\n main.className = 'main';\n main.addEventListener('click', () => {\n if (this.view3dCompareSeatIds.length > 1) this.openView3dComparison();\n else this.toast(this.tf('picker.chooseAnotherToCompare', 'Choose another seat to compare.'), 'neutral');\n });\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'clear';\n clear.textContent = '×';\n clear.setAttribute('aria-label', 'Clear saved seat comparison');\n clear.addEventListener('click', () => this.clearView3dComparison());\n chip.append(main, clear);\n overlay.appendChild(chip);\n this.view3dCompareChip = chip;\n }\n const count = this.view3dCompareSeatIds.length;\n const main = chip.querySelector<HTMLButtonElement>('.main');\n if (main) {\n main.textContent = count > 1 ? `Compare ${count}` : '1 seat saved';\n main.setAttribute('aria-label', count > 1 ? `Open comparison of ${count} seats` : 'One seat saved; choose another to compare');\n }\n }\n\n private view3dComparisonSnapshot(seatId: string) {\n const seat = this.allSeats().find((candidate) => candidate.id === seatId);\n if (!seat) return null;\n const details = this.controller.seatDetails(seat.id);\n const cat = this.controller.doc?.categories.find((candidate) => candidate.key === seat.categoryKey);\n const chartPrice = details?.price ?? (cat?.tiers?.length ? cat.tiers[0].price : cat?.price);\n const price = chartPrice != null\n ? this.paidPrice(seat.categoryKey, details?.tierId ?? cat?.tiers?.[0]?.id ?? null, chartPrice)\n : undefined;\n const status = this.controller.getStatus(seat.id);\n const availability = status === 'held'\n ? this.tf('picker.temporarilyHeld', 'Temporarily held')\n : status === 'booked'\n ? this.tf('picker.sold', 'Sold')\n : status === 'not_for_sale'\n ? this.tf('picker.notForSale', 'Not for sale')\n : this.tf('picker.available', 'Available');\n const viewSource = seat.viewUrl\n ? seatViewDisclosure({\n url: seat.viewUrl,\n ...(seat.viewMeta?.coverage ? { coverage: seat.viewMeta.coverage } : {}),\n ...(seat.viewMeta?.capturedAt ? { capturedAt: seat.viewMeta.capturedAt } : {}),\n ...(seat.viewMeta?.sourceLabel ? { sourceLabel: seat.viewMeta.sourceLabel } : {}),\n })\n : this.tf('picker.chartDerivedSeatEye', 'Live 3D · chart-derived seat-eye · not surveyed');\n const limited = this.limitedViewLabel(seat.commercial)\n || this.tf('picker.noAuthoredRestriction', 'No organizer-authored restriction');\n const accessibility = details?.wheelchairSpaceType\n ? `${this.wheelchairProvisionLabel(details.wheelchairSpaceType)} · metadata, not access certification`\n : this.tf('picker.noAccessibilityMetadata', 'No accessibility metadata supplied');\n const confidence = seatConfidenceDisclosure(seat.confidenceEvidence);\n return {\n seat,\n label: details?.displayLabel ?? seat.displayLabel ?? seat.label,\n section: details?.sectionLabel ?? seat.sectionId ?? '—',\n row: this.rowShort(details) ?? details?.rowLabel ?? '—',\n category: details?.categoryLabel ?? cat?.label ?? seat.categoryKey,\n price: price == null ? this.tf('picker.priceNotSupplied', 'Not supplied') : this.money(price),\n availability,\n selectable: status == null || status === 'free',\n viewSource,\n limited,\n accessibility,\n confidence,\n };\n }\n\n private openSeatConfidencePassport(seat: ExpandedSeat, returnFocus: HTMLElement | null = null): void {\n const overlay = this.view3dEl;\n if (!overlay) return;\n this.closeSeatConfidencePassport(false);\n const disclosure = seatConfidenceDisclosure(seat.confidenceEvidence);\n const evidence = seat.confidenceEvidence;\n const details = this.controller.seatDetails(seat.id);\n const safe = (value: unknown): string => this.escCx(value);\n const limitations = disclosure.limitations.length\n ? `<h4>Known limits</h4><ul>${disclosure.limitations.map((item) => `<li>${safe(item)}</li>`).join('')}</ul>`\n : '';\n const modeledTarget = disclosure.modeledTarget\n ? `<div><dt>Modeled target</dt><dd>${safe(disclosure.modeledTarget)}</dd></div>`\n : '';\n const evidenceRows = evidence\n ? `<div><dt>Evidence ID</dt><dd>${safe(evidence.evidenceId)}</dd></div>`\n + `<div><dt>Model version</dt><dd>${safe(evidence.modelVersion)}</dd></div>`\n + `<div><dt>Event configuration</dt><dd>${safe(evidence.eventConfigurationId ?? 'Not configuration-specific')}</dd></div>`\n + `<div><dt>Approval</dt><dd>${safe(evidence.approvedByRole ?? 'No external approval supplied')}</dd></div>`\n + (evidence.validUntil ? `<div><dt>Valid until</dt><dd>${safe(evidence.validUntil.slice(0, 10))}</dd></div>` : '')\n : `<div><dt>Evidence ID</dt><dd>None supplied</dd></div>`;\n const restriction = this.limitedViewLabel(seat.commercial)\n || this.tf('picker.noAuthoredRestriction', 'No organizer-authored restriction');\n const commercialRows = `<div><dt>View restriction</dt><dd>${safe(restriction)}</dd></div>`\n + (seat.commercial?.note ? `<div><dt>Organizer note</dt><dd>${safe(seat.commercial.note)}</dd></div>` : '');\n const shell = document.createElement('div');\n shell.className = 'sl-view3d-passport-shell';\n shell.innerHTML = `<div class=\"sl-view3d-passport-scrim\" aria-hidden=\"true\"></div>`\n + `<section class=\"sl-view3d-passport\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-view3d-passport-title\">`\n + `<header><div><span>Seat confidence passport</span><strong id=\"sl-view3d-passport-title\">${safe(details?.displayLabel ?? seat.displayLabel ?? seat.label)}</strong></div>`\n + `<button type=\"button\" data-close aria-label=\"Close seat confidence passport\">×</button></header>`\n + `<div class=\"sl-view3d-passport-summary\"><strong>${safe(disclosure.headline)}</strong>`\n + `<span>${safe(disclosure.coverage)} · ${safe(disclosure.freshness)}</span></div>`\n + `<dl><div><dt>Model status</dt><dd>${safe(disclosure.model)}</dd></div>`\n + `<div><dt>Reality evidence</dt><dd>${safe(disclosure.reality)}</dd></div>`\n + `<div><dt>Source</dt><dd>${safe(disclosure.provenance)}</dd></div>`\n + commercialRows + modeledTarget + evidenceRows + `</dl>${limitations}`\n + `<p class=\"sl-view3d-passport-note\">This passport describes supplied evidence and known limits. It does not guarantee that every temporary obstruction or real-world condition is knowable before the event build.</p></section>`;\n const background = [...new Set([\n ...overlay.children,\n ...[...this.els.map.children].filter((element) => element !== overlay),\n ])].filter((element): element is HTMLElement => element instanceof HTMLElement);\n const prior = background.map((element) => ({\n element,\n inert: element.inert,\n ariaHidden: element.getAttribute('aria-hidden'),\n }));\n for (const element of background) {\n element.inert = true;\n element.setAttribute('aria-hidden', 'true');\n }\n overlay.appendChild(shell);\n overlay.classList.add('has-passport');\n this.view3dPassportEl = shell;\n const dialog = shell.querySelector<HTMLElement>('.sl-view3d-passport')!;\n const controls = (): HTMLElement[] => [...dialog.querySelectorAll<HTMLElement>('button:not(:disabled),[href],[tabindex]:not([tabindex=\"-1\"])')];\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n this.closeSeatConfidencePassport();\n return;\n }\n if (event.key !== 'Tab') return;\n const focusable = controls();\n if (!focusable.length) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n // Capture before the picker's ordinary Escape handler. Closing this nested\n // disclosure must return to the same seat decision, not also cancel it.\n window.addEventListener('keydown', onKey, true);\n this.view3dPassportCleanup = () => {\n window.removeEventListener('keydown', onKey, true);\n for (const state of prior) {\n state.element.inert = state.inert;\n if (state.ariaHidden === null) state.element.removeAttribute('aria-hidden');\n else state.element.setAttribute('aria-hidden', state.ariaHidden);\n }\n const returnCandidate = returnFocus?.isConnected\n ? returnFocus\n : this.confirmEl?.querySelector<HTMLElement>('.sl-confirm-confidence')\n ?? this.view3dCompareEl?.querySelector<HTMLElement>('[data-passport-seat]')\n ?? null;\n const returnSurface = returnCandidate?.closest<HTMLElement>('.sl-confirm,.sl-view3d-compare');\n if (returnSurface?.isConnected) {\n returnSurface.inert = false;\n returnSurface.removeAttribute('aria-hidden');\n }\n shell.remove();\n overlay.classList.remove('has-passport');\n if (this.view3dPassportEl === shell) this.view3dPassportEl = null;\n const fallback = returnCandidate\n ?? this.view3dCompareEl?.querySelector<HTMLElement>('[data-passport-seat]')\n ?? this.confirmEl?.querySelector<HTMLElement>('.sl-confirm-confidence')\n ?? this.view3dCompareChip?.querySelector<HTMLElement>('.main');\n (returnFocus?.isConnected ? returnFocus : fallback)?.focus();\n };\n shell.addEventListener('click', (event) => {\n const target = event.target instanceof HTMLElement ? event.target : null;\n if (target?.closest('[data-close]') || target?.classList.contains('sl-view3d-passport-scrim')) {\n this.closeSeatConfidencePassport();\n }\n });\n requestAnimationFrame(() => controls()[0]?.focus());\n this.emit3dAnalytics('3d_confidence_passport_opened', {\n seatId: seat.id,\n evidenceId: evidence?.evidenceId ?? null,\n eventConfigurationId: evidence?.eventConfigurationId ?? null,\n modelLevel: evidence?.modelLevel ?? 'unverified',\n realityLevel: evidence?.realityLevel ?? 'none',\n });\n }\n\n private closeSeatConfidencePassport(restoreFocus = true): void {\n const cleanup = this.view3dPassportCleanup;\n this.view3dPassportCleanup = null;\n if (!cleanup) {\n this.view3dPassportEl?.remove();\n this.view3dPassportEl = null;\n this.view3dEl?.classList.remove('has-passport');\n return;\n }\n if (!restoreFocus) (document.activeElement instanceof HTMLElement ? document.activeElement : null)?.blur();\n cleanup();\n if (!restoreFocus) this.root?.focus({ preventScroll: true });\n }\n\n private openView3dComparison(): void {\n const overlay = this.view3dEl;\n if (!overlay || this.view3dCompareSeatIds.length < 2) return;\n this.closeView3dComparison(false);\n const snapshots = this.view3dCompareSeatIds\n .map((seatId) => this.view3dComparisonSnapshot(seatId))\n .filter((value): value is NonNullable<ReturnType<SeatPicker['view3dComparisonSnapshot']>> => !!value);\n if (snapshots.length < 2) {\n this.clearView3dComparison();\n return;\n }\n const safe = (value: unknown): string => this.escCx(value);\n const shell = document.createElement('div');\n shell.className = 'sl-view3d-compare-shell';\n const cards = snapshots.map((snapshot, index) => (\n `<article><span>Seat ${index === 0 ? 'A' : 'B'}</span><strong>${safe(snapshot.label)}</strong>`\n + `<small>Section ${safe(snapshot.section)} · Row ${safe(snapshot.row)}</small><dl>`\n + `<div><dt>Current price</dt><dd>${safe(snapshot.price)}</dd></div>`\n + `<div><dt>Ticket type</dt><dd>${safe(snapshot.category)}</dd></div>`\n + `<div><dt>Availability</dt><dd>${safe(snapshot.availability)}</dd></div>`\n + `<div><dt>View source</dt><dd>${safe(snapshot.viewSource)}</dd></div>`\n + `<div><dt>View restriction</dt><dd>${safe(snapshot.limited)}</dd></div>`\n + `<div><dt>Seat confidence</dt><dd>${safe(snapshot.confidence.headline)}</dd></div>`\n + `<div><dt>Reality check</dt><dd>${safe(snapshot.confidence.reality)}</dd></div>`\n + `<div><dt>Accessibility</dt><dd>${safe(snapshot.accessibility)}</dd></div></dl>`\n + `<div class=\"sl-view3d-compare-actions\">`\n + `<button type=\"button\" data-passport-seat=\"${safe(snapshot.seat.id)}\">Passport</button>`\n + `<button type=\"button\" data-view-seat=\"${safe(snapshot.seat.id)}\">View seat</button>`\n + `<button type=\"button\" class=\"select\" data-select-seat=\"${safe(snapshot.seat.id)}\"${snapshot.selectable ? '' : ' disabled'}>Select seat</button>`\n + `</div></article>`\n )).join('');\n shell.innerHTML = `<div class=\"sl-view3d-compare-scrim\" aria-hidden=\"true\"></div>`\n + `<section class=\"sl-view3d-compare\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sl-view3d-compare-title\">`\n + `<header><div><span>Seat inspection</span><strong id=\"sl-view3d-compare-title\">Compare disclosed attributes</strong></div>`\n + `<button type=\"button\" data-close aria-label=\"Close seat comparison\">×</button></header>`\n + `<p class=\"sl-view3d-compare-note\">Current price and availability come from this picker. Modeled views are chart-derived unless organizer media is labeled; SeatLayer does not invent why a seat has its price.</p>`\n + `<div class=\"sl-view3d-compare-grid\">${cards}</div></section>`;\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const background = [...overlay.children].filter((element): element is HTMLElement => element instanceof HTMLElement);\n const prior = background.map((element) => ({\n element,\n inert: element.inert,\n ariaHidden: element.getAttribute('aria-hidden'),\n }));\n for (const element of background) {\n element.inert = true;\n element.setAttribute('aria-hidden', 'true');\n }\n overlay.appendChild(shell);\n overlay.classList.add('has-comparison');\n this.view3dCompareEl = shell;\n const dialog = shell.querySelector<HTMLElement>('.sl-view3d-compare')!;\n const controls = (): HTMLElement[] => [...dialog.querySelectorAll<HTMLElement>('button:not(:disabled),[href],[tabindex]:not([tabindex=\"-1\"])')];\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closeView3dComparison();\n return;\n }\n if (event.key !== 'Tab') return;\n const focusable = controls();\n if (!focusable.length) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n window.addEventListener('keydown', onKey);\n this.view3dCompareCleanup = () => {\n window.removeEventListener('keydown', onKey);\n for (const state of prior) {\n state.element.inert = state.inert;\n if (state.ariaHidden === null) state.element.removeAttribute('aria-hidden');\n else state.element.setAttribute('aria-hidden', state.ariaHidden);\n }\n shell.remove();\n overlay.classList.remove('has-comparison');\n if (this.view3dCompareEl === shell) this.view3dCompareEl = null;\n if (previousFocus?.isConnected) previousFocus.focus();\n else this.view3dCompareChip?.querySelector<HTMLButtonElement>('.main')?.focus();\n };\n shell.querySelector<HTMLButtonElement>('[data-close]')?.addEventListener('click', () => this.closeView3dComparison());\n shell.querySelectorAll<HTMLButtonElement>('[data-passport-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.passportSeat;\n const seat = seatId ? this.allSeats().find((candidate) => candidate.id === seatId) : undefined;\n if (seat) this.openSeatConfidencePassport(seat, button);\n }));\n shell.querySelectorAll<HTMLButtonElement>('[data-view-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.viewSeat;\n this.closeView3dComparison(false);\n if (seatId) void this.view3dHandle?.flyToSeat(seatId);\n }));\n shell.querySelectorAll<HTMLButtonElement>('[data-select-seat]').forEach((button) => button.addEventListener('click', () => {\n const seatId = button.dataset.selectSeat;\n if (seatId) this.selectComparedSeat(seatId);\n }));\n requestAnimationFrame(() => controls()[0]?.focus());\n this.emit3dAnalytics('3d_comparison_opened', { seatIds: this.view3dCompareSeatIds.slice() });\n }\n\n private closeView3dComparison(restoreFocus = true): void {\n const cleanup = this.view3dCompareCleanup;\n this.view3dCompareCleanup = null;\n if (!cleanup) {\n this.view3dCompareEl?.remove();\n this.view3dCompareEl = null;\n this.view3dEl?.classList.remove('has-comparison');\n return;\n }\n if (!restoreFocus) {\n const active = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n active?.blur();\n }\n cleanup();\n if (!restoreFocus) this.root?.focus({ preventScroll: true });\n }\n\n private selectComparedSeat(seatId: string): void {\n if (this.salesClosed) {\n this.toast(this.tf('picker.salesClosedToast', 'Sales are closed for this event.'), 'warning');\n return;\n }\n const seat = this.allSeats().find((candidate) => candidate.id === seatId);\n if (!seat) return;\n this.closeView3dComparison(false);\n const added = this.controller.select([seatId]);\n if (!added.length) {\n this.syncSelectionTo3d();\n this.toast(this.tf('picker.seatNoLongerAvailable', 'That seat is no longer available.'), 'warning');\n return;\n }\n this.syncSelectionTo3d();\n this.showConfirm(seat);\n this.emit3dAnalytics('3d_comparison_selected', { seatId });\n }\n\n /**\n * The venue-navigation rail inside 3D: levels and areas.\n *\n * In 2D a buyer moves through the venue by floor switcher and by the LOD\n * rungs. Both are hidden while immersed, and the 3D module's own chips only\n * cover \"go home\" and \"see the 360\" — so on a multi-floor or multi-zone chart\n * the buyer entered 3D and LOST the ability to reach the level or area they\n * were booking. The camera moves for both already exist on the handle\n * (`focusFloor` / `focusZone`); this is the surface that offers them.\n *\n * Levels are a TOGGLE (a floor stays isolated until you pick another), areas\n * are an ACTION (the camera flies there and you are then free to orbit), which\n * is why only the level pills carry a pressed state.\n */\n private buildView3dNav(overlay: HTMLElement, handle: Venue3DHandle): void {\n const floors = handle.floors();\n // An empty zone has nothing to frame and `focusZone` refuses it — offering\n // a pill that cannot move the camera is worse than offering nothing.\n // Some multi-floor charts also expose each floor as a same-named zone. That\n // is one venue concept represented twice, not two useful navigation rungs.\n // Keep the level toggle and suppress its duplicate area action.\n const floorLabels = new Set(floors.map((floor) => floor.label.trim().toLocaleLowerCase()));\n const zones = handle.zones().filter((zone) => (\n zone.seatCount > 0\n && !floorLabels.has(zone.label.trim().toLocaleLowerCase())\n ));\n // Zones are optional; sections are not. A chart that authors no zones (or\n // one) still needs a way to move around the venue, so the rail falls back to\n // the rung below. A long section list becomes one native jump control rather\n // than being truncated or rendered as dozens of pills.\n const allSections = handle.sections().filter((s) => s.seatCount > 0);\n const sections = zones.length > 1\n ? []\n : allSections;\n // One of anything is not a choice — a single-floor, single-zone venue gets\n // no rail rather than a rail that does nothing.\n const wantFloors = floors.length > 1;\n const wantZones = zones.length > 1;\n const wantSections = sections.length > 1;\n const wantLocator = allSections.length > 0 && handle.rows().length > 0;\n if (!wantFloors && !wantZones && !wantSections && !wantLocator) return;\n\n const nav = document.createElement('div');\n nav.className = 'sl-view3d-nav';\n const finderToggle = document.createElement('button');\n finderToggle.type = 'button';\n finderToggle.className = 'sl-view3d-nav-toggle';\n finderToggle.setAttribute('aria-expanded', 'false');\n const setFinderOpen = (open: boolean): void => {\n nav.classList.toggle('is-open', open);\n finderToggle.setAttribute('aria-expanded', String(open));\n finderToggle.textContent = open ? 'Close seat finder' : 'Find a seat';\n };\n finderToggle.addEventListener('click', () => setFinderOpen(!nav.classList.contains('is-open')));\n nav.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape' || !nav.classList.contains('is-open')) return;\n event.preventDefault();\n event.stopPropagation();\n setFinderOpen(false);\n finderToggle.focus();\n });\n setFinderOpen(false);\n nav.appendChild(finderToggle);\n\n if (wantFloors) {\n const row = document.createElement('div');\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', this.tf('picker.levels', 'Levels'));\n const pills: HTMLButtonElement[] = [];\n const select = (index: number | null): void => {\n if (!handle.focusFloor(index)) return;\n pills.forEach((p) => {\n p.setAttribute('aria-pressed', String((p.dataset.floor === '' ? null : Number(p.dataset.floor)) === index));\n });\n };\n const add = (label: string, index: number | null): void => {\n const b = document.createElement('button');\n b.type = 'button';\n b.textContent = label;\n b.dataset.floor = index === null ? '' : String(index);\n b.setAttribute('aria-pressed', String(index === null));\n b.addEventListener('click', () => {\n select(index);\n setFinderOpen(false);\n });\n pills.push(b);\n row.appendChild(b);\n };\n add(this.tf('picker.allLevels', 'All levels'), null);\n for (const f of floors) add(f.label || `Level ${f.index + 1}`, f.index);\n nav.appendChild(row);\n }\n\n if (wantZones || wantSections) {\n const row = document.createElement('div');\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', this.tf('picker.areas', 'Areas'));\n const entries: Array<{ id: string; label: string; go: () => void }> = wantZones\n ? zones.map((z) => ({ id: z.id, label: z.label || z.id, go: () => { handle.focusZone(z.id); } }))\n : sections.map((s) => ({ id: s.id, label: s.label || s.id, go: () => { handle.focusSection(s.id); } }));\n if (!wantZones && entries.length > MAX_3D_SECTION_PILLS) {\n const select = document.createElement('select');\n select.setAttribute('aria-label', this.tf('picker.jumpToSection', 'Jump to section'));\n const placeholder = document.createElement('option');\n placeholder.value = '';\n placeholder.textContent = this.tf('picker.jumpToSection', 'Jump to section');\n select.appendChild(placeholder);\n for (const entry of entries) {\n const option = document.createElement('option');\n option.value = entry.id;\n option.textContent = entry.label;\n select.appendChild(option);\n }\n select.addEventListener('change', () => {\n entries.find((entry) => entry.id === select.value)?.go();\n });\n row.appendChild(select);\n } else {\n for (const e of entries) {\n const b = document.createElement('button');\n b.type = 'button';\n b.textContent = e.label;\n b.addEventListener('click', () => {\n e.go();\n setFinderOpen(false);\n });\n row.appendChild(b);\n }\n }\n nav.appendChild(row);\n }\n\n if (wantLocator) {\n const locator = document.createElement('div');\n locator.className = 'sl-view3d-locator';\n locator.setAttribute('role', 'group');\n locator.setAttribute('aria-label', 'Find an exact seat in 3D');\n\n const sectionSelect = document.createElement('select');\n sectionSelect.setAttribute('aria-label', 'Choose section in 3D');\n const rowSelect = document.createElement('select');\n rowSelect.setAttribute('aria-label', 'Choose row in 3D');\n const seatSelect = document.createElement('select');\n seatSelect.setAttribute('aria-label', 'Choose seat in 3D');\n const view = document.createElement('button');\n view.type = 'button';\n view.textContent = 'Inspect seat';\n view.disabled = true;\n\n const fill = (\n select: HTMLSelectElement,\n placeholder: string,\n entries: Array<{ id: string; label: string }>,\n ): void => {\n select.replaceChildren();\n const first = document.createElement('option');\n first.value = '';\n first.textContent = placeholder;\n select.appendChild(first);\n for (const entry of entries) {\n const option = document.createElement('option');\n option.value = entry.id;\n option.textContent = entry.label;\n select.appendChild(option);\n }\n select.value = '';\n };\n\n fill(sectionSelect, '1. Section', allSections.map((section) => ({\n id: section.id,\n label: `${section.label} · ${section.seatCount.toLocaleString()} seats`,\n })));\n fill(rowSelect, '2. Row', []);\n fill(seatSelect, '3. Seat', []);\n rowSelect.disabled = true;\n seatSelect.disabled = true;\n\n sectionSelect.addEventListener('change', () => {\n const sectionId = sectionSelect.value;\n view.disabled = true;\n fill(seatSelect, '3. Seat', []);\n seatSelect.disabled = true;\n if (!sectionId || !handle.focusSection(sectionId)) {\n fill(rowSelect, '2. Row', []);\n rowSelect.disabled = true;\n return;\n }\n const rows = handle.rows(sectionId);\n fill(rowSelect, '2. Row', rows.map((row) => ({\n id: row.id,\n label: `${row.label} · ${row.seatCount} seats`,\n })));\n rowSelect.disabled = rows.length === 0;\n });\n\n rowSelect.addEventListener('change', () => {\n const rowId = rowSelect.value;\n view.disabled = true;\n if (!rowId || !handle.focusRow(rowId)) {\n fill(seatSelect, '3. Seat', []);\n seatSelect.disabled = true;\n return;\n }\n const seats = handle.seatsInRow(rowId);\n fill(seatSelect, '3. Seat', seats);\n seatSelect.disabled = seats.length === 0;\n });\n\n seatSelect.addEventListener('change', () => {\n const seatId = seatSelect.value;\n view.disabled = !seatId;\n });\n view.addEventListener('click', () => {\n const seatId = seatSelect.value;\n // Keyboard and screen-reader users must reach the same candidate\n // decision surface as a canvas tap. This creates only the existing\n // temporary confirm candidate; it is excluded from checkout until the\n // buyer explicitly selects it, and saving to compare releases it.\n if (seatId) {\n setFinderOpen(false);\n this.onView3dSeatPick(seatId);\n }\n });\n\n locator.append(sectionSelect, rowSelect, seatSelect, view);\n nav.appendChild(locator);\n }\n\n overlay.appendChild(nav);\n }\n\n private async enter3d(flySeatId?: string): Promise<void> {\n if (this.view3dEl || !this.canOffer3d() || !this.els.map) return;\n const doc = this.controller.doc;\n if (!doc) return;\n this.buyerView = 'venue3d';\n this.view3dTargetSeatId = null;\n this.opts.onBuyerViewChange?.({ view: 'venue3d', ...(flySeatId ? { seatId: flySeatId } : {}) });\n this.root?.setAttribute('data-view3d', 'on');\n this.dismissConfirm();\n this.syncProjection();\n\n const overlay = document.createElement('div');\n overlay.className = 'sl-view3d';\n overlay.setAttribute('role', 'group');\n overlay.setAttribute('aria-label', 'Interactive 3D venue view');\n const back = document.createElement('button');\n back.type = 'button';\n back.className = 'sl-view3d-back';\n back.innerHTML =\n '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M15 18l-6-6 6-6\"/></svg>'\n + `<span>${this.tf('picker.backToMap', 'Back to map')}</span>`;\n const backLabel = back.querySelector<HTMLSpanElement>('span');\n const setJourneyTarget = (seatId: string | null): void => {\n this.view3dTargetSeatId = seatId;\n const atSeat = !!seatId;\n overlay.classList.toggle('is-seat-focused', atSeat);\n const label = atSeat\n ? this.tf('picker.backToVenue', 'Back to venue')\n : this.tf('picker.backToMap', 'Back to map');\n if (backLabel) backLabel.textContent = label;\n back.setAttribute('aria-label', label);\n };\n back.addEventListener('click', () => {\n if (this.view3dTargetSeatId && this.view3dHandle) {\n this.view3dHandle.focusOverview();\n return;\n }\n this.exit3d();\n });\n overlay.appendChild(back);\n const fullscreen = document.createElement('button');\n fullscreen.type = 'button';\n fullscreen.className = 'sl-view3d-fs';\n fullscreen.textContent = '⛶';\n fullscreen.setAttribute('aria-label', 'Full screen');\n fullscreen.setAttribute('aria-pressed', String(!!document.fullscreenElement || this.fsFallback || this.framedFs));\n fullscreen.addEventListener('click', () => this.toggleFullscreen());\n overlay.appendChild(fullscreen);\n const loading = document.createElement('div');\n loading.className = 'sl-view3d-loading';\n loading.setAttribute('role', 'status');\n loading.setAttribute('aria-live', 'polite');\n loading.textContent = this.tf('picker.loading3d', 'Building the 3D venue…');\n overlay.appendChild(loading);\n this.els.map.appendChild(overlay);\n this.view3dEl = overlay;\n this.syncView3dCompareChip();\n requestAnimationFrame(() => { overlay.style.opacity = '1'; });\n\n const gen = ++this.view3dGen;\n try {\n const seats = expandChart(doc);\n const mod = await loadVenue3d();\n // Left 3D (or was torn down) while the OGL chunk loaded → abandon.\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n const prepared = await mod.prepareVenue3D({ doc, seats });\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n const handle = mod.mountVenue3D(overlay, { doc, seats, prepared }, {\n // A strict contain fit turns a wide bowl into a postage stamp inside a\n // phone. The bounded portrait fit was validated against every UX-lab\n // fixture; keep editor previews strict while making buyer seats legible.\n portraitOverviewCrop: true,\n // Premium buyer mode lands at the modeled seated-eye and locks the\n // venue orbit there. Explicit look-around rotates at that same origin;\n // zooming cannot escape through the shell or reveal backstage geometry.\n arriveAtSeatEye: true,\n seatViewActionLabel: (seatId) => this.allSeats().find((seat) => seat.id === seatId)?.viewUrl\n ? this.tf('picker.openAuthored360', 'Open venue 360°')\n : this.tf('picker.lookAroundLive3d', 'Look around in live 3D'),\n onSeatPick: (id) => this.onView3dSeatPick(id),\n onSeatInspect: (id) => this.onView3dSeatPick(id),\n onSectionFocusChange: (sectionId) => {\n // A stand clicked directly in the 3D overview must drive the same\n // Section → Row → Seat ladder as the exact-seat control. Dispatching\n // change populates the row list; the equality guard prevents the\n // callback from looping when that handler re-focuses the camera.\n const select = overlay.querySelector<HTMLSelectElement>(\n 'select[aria-label=\"Choose section in 3D\"]',\n );\n const next = sectionId ?? '';\n if (!select || select.value === next) return;\n select.value = next;\n select.dispatchEvent(new Event('change'));\n },\n onViewTargetChange: (seatId) => {\n overlay.querySelector('.sl-view3d-nav')?.classList.toggle('is-seat-focused', !!seatId);\n setJourneyTarget(seatId);\n this.opts.onBuyerViewChange?.({\n view: 'venue3d',\n ...(seatId ? { seatId } : {}),\n });\n },\n // Deferred off the tap gesture: generateSeatPanorama walks every seat\n // (O(n) on a 13k chart), and the module prefetches at pick — by the\n // time the flight lands (~2.5s) the idle render has long finished. A\n // null view REJECTS so the module's no-panorama path keeps the buyer\n // in orbit instead of dissolving into an empty overlay.\n getSeatView: (id) =>\n new Promise((resolve, reject) => {\n const run = () => {\n void this.seatViewFor3d(id).then((view) => {\n if (view) resolve(view);\n else reject(new Error('seat_view_unavailable'));\n });\n };\n const ric = (globalThis as { requestIdleCallback?: (cb: () => void, opts?: { timeout: number }) => void }).requestIdleCallback;\n if (typeof ric === 'function') ric(run, { timeout: 1500 });\n else setTimeout(run, 50);\n }),\n onAnalytics: (event, props) => this.emit3dAnalytics(event, props),\n });\n this.view3dHandle = handle;\n loading.remove();\n this.pushAvailabilityTo3d();\n this.syncSelectionTo3d();\n this.buildView3dNav(overlay, handle);\n if (flySeatId) void handle.flyToSeat(flySeatId);\n } catch (err) {\n if (gen !== this.view3dGen || this.buyerView !== 'venue3d' || this.view3dEl !== overlay) return;\n this.opts.onError?.(err);\n this.toast(this.tf('picker.unavailable3d', '3D could not start. The seat map is still available.'), 'warning');\n this.exit3d();\n }\n }\n\n private exit3d(): void {\n if (this.buyerView !== 'venue3d' && !this.view3dEl) return;\n this.view3dGen++; // supersede any in-flight mount\n this.buyerView = 'map';\n this.view3dTargetSeatId = null;\n this.opts.onBuyerViewChange?.({ view: 'map' });\n this.root?.removeAttribute('data-view3d');\n this.closeSeatConfidencePassport(false);\n this.closeView3dComparison(false);\n this.view3dCompareChip?.remove();\n this.view3dCompareChip = null;\n try { this.view3dHandle?.dispose(); } catch { /* GL teardown best-effort */ }\n this.view3dHandle = null;\n const overlay = this.view3dEl;\n this.view3dEl = null;\n if (overlay) {\n overlay.style.opacity = '0';\n setTimeout(() => overlay.remove(), 320);\n }\n this.syncProjection();\n // Zoom/pan of the underlying 2D stage was never touched, so the map is\n // restored exactly. Re-offer the confirm the buyer left via \"See it in 3D\".\n const seat = this.view3dReturnSeat;\n this.view3dReturnSeat = null;\n if (seat && this.committedSelection().some((s) => s.id === seat.id)\n && this.opts.confirmSelection !== false) {\n this.showConfirm(seat);\n }\n }\n\n /** Current active/restored hold reflected in the tray. */\n getCurrentHold(): HoldResult | null {\n return this.hold;\n }\n\n /** Explicit host-driven hold restore (automatic session restore is on by default). */\n async resumeHold(holdId: string): Promise<HoldResult | null> {\n return this.resumeHoldFromServer(holdId, false);\n }\n\n /** Remove one server-held ticket while keeping the rest of the hold active. */\n async removeHeldTicket(label: string): Promise<boolean> {\n return this.removeHeldLabel(label);\n }\n\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: SeatPickerBestAvailableOptions = {},\n ): Promise<HoldResult | null> {\n if (this.salesClosed || this.bestAvailableBusy) return null;\n qty = Math.max(1, Math.min(this.maxTickets, Math.floor(qty)));\n if (this.confirmSeat) this.cancelConfirm();\n this.bestAvailableConfirm = false;\n this.bestAvailableBusy = true;\n const button = this.els.tray?.querySelector<HTMLButtonElement>('.sl-ba-go');\n if (button) {\n button.disabled = true;\n // .sl-busy keeps the accent fill + wait cursor: this disabled means\n // \"working\", not \"unavailable\" (which renders surface + not-allowed).\n button.classList.add('sl-busy');\n button.innerHTML = '<span class=\"sl-ba-spin\" aria-hidden=\"true\"></span>Finding…';\n }\n try {\n // Same checkout window as a clicked selection — see the CTA's hold() call.\n const h = await this.controller.bestAvailable(qty, categoryKey, { ...opts, ttlMs: this.opts.holdTtlMs });\n if (h) {\n this.hold = { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items };\n this.handedOff = false;\n this.bookedShown = false;\n this.gaQty.clear();\n this.startHoldTimer(h.expiresAt);\n this.flashHeldSeats(this.hold);\n this.syncTray();\n this.emitHoldChange();\n // Premium quick-pick asked for a premium block but no full block of\n // `qty` existed → we held the best overall instead. Surface a subtle note.\n if (opts.preferPremium && h.seats.length && !h.seats.every((s) => s.commercial?.premium)) {\n this.toast(t('picker.premiumFallbackNote', { count: qty }), 'neutral');\n }\n return this.hold;\n }\n return null;\n } catch (err) {\n this.opts.onError?.(err);\n const reason = (err as { reason?: string })?.reason;\n const message = reason === 'not_enough_together'\n ? `We couldn't find ${qty} seats together. Try fewer seats or another ticket type.`\n : reason === 'sold_out'\n ? 'That ticket type is sold out. Try another ticket type.'\n : reason === 'event_closed'\n ? 'Seat sales have closed for this event.'\n : 'Those seats are no longer available. Try another quantity or ticket type.';\n this.toast(message, 'error');\n return null;\n } finally {\n this.bestAvailableBusy = false;\n this.syncTray();\n }\n }\n\n async release(): Promise<void> {\n const tracked = this.hold;\n const controllerHold = this.controller.currentHold();\n let released = true;\n if (controllerHold) {\n released = await this.controller.release();\n } else if (tracked) {\n // The live controller can legitimately settle/clear its local hold before\n // the shell finishes dismissing. The shell still owns the server handoff,\n // so release from that authoritative copy instead of silently no-oping.\n const labels = [...new Set([\n ...(tracked.items ?? []).map((item) => item.label),\n ...(tracked.seats ?? []).map((seat) => seat.label),\n ])];\n if (labels.length) {\n try {\n await this.api.release(this.opts.event, labels, tracked.holdId);\n } catch (error) {\n this.opts.onError?.(error);\n released = false;\n }\n }\n }\n if (!released) {\n this.toast(\"Couldn't release your tickets. Your hold is unchanged.\", 'error');\n return;\n }\n this.hold = null;\n this.forgetHold();\n this.handedOff = false;\n this.bookedShown = false;\n this.ctaPhase = 'idle';\n this.stopHoldTimer();\n this.gaQty.clear();\n this.syncTray();\n this.emitHoldChange();\n }\n\n // ---- buyer access (Sales Channels) ---------------------------------------\n\n /**\n * Realtime for an access-scoped picker.\n *\n * A tokenless picker never gets here: `access` is null, `PubApi.socketUrl()`\n * returns the URL it always has, and PickerController keeps its own socket\n * and its own legacy frames. Nothing about the public path changes.\n */\n private startRealtime(): void {\n if (!this.access?.configured || !this.pubApi || this.realtime) return;\n const event = this.opts.event;\n this.realtime = new BuyerRealtimeClient({\n url: this.pubApi.subscribeUrl(event),\n mintTicket: () => this.pubApi!.subscribeTicket(event),\n onAccessUnavailable: (state) => {\n this.opts.onAccessUnavailable?.(state);\n this.showAccessPanel(state);\n },\n sink: createControllerSink(this.controller, {\n flashOnLiveChange: true,\n onStatusChange: () => {\n this.syncPrices();\n this.scheduleOfferRefresh(true);\n this.detectBooked();\n this.refreshMinimap();\n this.pushAvailabilityTo3d();\n },\n onSelectedObjectUnavailable: (labels, reason) => {\n this.opts.onSelectedObjectUnavailable?.({ labels, reason });\n this.syncTray();\n this.toast(\n reason === 'ineligible'\n ? this.tf(\n 'picker.seatNoLongerYours',\n 'Some seats are no longer available to you. They have been removed from your order.',\n )\n : this.tf(\n 'picker.seatTaken',\n 'Someone else took a seat you had picked. It has been removed from your order.',\n ),\n 'warning',\n );\n },\n }),\n });\n this.realtime.start();\n }\n\n /**\n * Re-acquire the buyer access session — call after your app has re-authorized\n * the buyer. A revoked session cannot recover any other way. Resolves true\n * when a fresh bearer is held; the map and the realtime feed resume with it.\n */\n async refreshAccess(): Promise<boolean> {\n if (!this.access?.configured) return false;\n const ok = await this.access.refresh('manual');\n if (!ok) return false;\n this.dismissAccessPanel();\n await this.controller.refresh();\n if (this.realtime) this.realtime.restart();\n else this.startRealtime();\n return true;\n }\n\n /**\n * The buyer-facing access state. Plain language, no internal vocabulary, and\n * never a channel name, id or count — the buyer is told what happened and\n * what to do, not which allocation they missed (guide §7, §10).\n *\n * Held seats are deliberately left alone: a hold is relinquished by its own\n * opaque capability, not by channel access, so losing access never strands\n * inventory and never silently drops a buyer's cart (guide §9).\n */\n private showAccessPanel(state: { reason: BuyerAccessUnavailableReason; retryable: boolean }): void {\n if (this.destroyed || !this.root) return;\n const copy = this.accessCopy(state.reason);\n this.dismissAccessPanel();\n const panel = document.createElement('div');\n panel.className = 'sl-access';\n panel.setAttribute('role', 'status');\n panel.setAttribute('aria-live', 'polite');\n const text = document.createElement('div');\n const title = document.createElement('div');\n title.className = 'sl-access-title';\n title.textContent = copy.title;\n const body = document.createElement('div');\n body.className = 'sl-access-body';\n body.textContent = copy.body;\n text.appendChild(title);\n text.appendChild(body);\n if (copy.action) {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'sl-access-act';\n button.textContent = copy.action;\n button.addEventListener('click', () => {\n void this.refreshAccess();\n });\n text.appendChild(button);\n }\n panel.appendChild(text);\n (this.regions?.['bottom-center'] ?? this.root).appendChild(panel);\n this.accessEl = panel;\n }\n\n private dismissAccessPanel(): void {\n this.accessEl?.remove();\n this.accessEl = null;\n }\n\n private accessCopy(reason: BuyerAccessUnavailableReason): {\n title: string;\n body: string;\n action?: string;\n } {\n switch (reason) {\n case 'paused':\n return {\n title: this.tf('picker.accessPausedTitle', 'These seats are on hold right now'),\n body: this.tf(\n 'picker.accessPausedBody',\n 'The organizer has paused this selection. Try again in a few minutes.',\n ),\n action: this.tf('picker.accessRetry', 'Try again'),\n };\n case 'revoked':\n return {\n title: this.tf('picker.accessRevokedTitle', 'This access link is no longer active'),\n body: this.tf(\n 'picker.accessRevokedBody',\n 'Ask whoever sent you here for a new link to keep booking these seats.',\n ),\n };\n case 'no_token':\n case 'provider_failed':\n return {\n title: this.tf('picker.accessExpiredTitle', 'Your access session has ended'),\n body: this.tf(\n 'picker.accessExpiredBody',\n 'Sign in again, or reload the page, to keep browsing these seats. Anything you are already holding stays yours.',\n ),\n action: this.tf('picker.accessRetry', 'Try again'),\n };\n default:\n return {\n title: this.tf('picker.accessInvalidTitle', 'We couldn’t verify your access'),\n body: this.tf(\n 'picker.accessInvalidBody',\n 'You can still book anything shown as available. Contact whoever sent you here for access to the rest.',\n ),\n };\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.realtime?.stop();\n this.realtime = null;\n this.dismissAccessPanel();\n this.access?.clear();\n // Closing/tearing down before checkout means the buyer abandoned any\n // best-available hold. Release it server-side; a handed-off checkout keeps\n // its hold alive across the host's route transition.\n if (this.hold && !this.handedOff) void this.controller.release();\n this.closeConfirm();\n this.dismissTableDialog(false);\n this.closeSeatView();\n // A payment card outlives its own mount node (it listens on the document for\n // ESC), so it is torn down explicitly rather than left to root.remove().\n this.closeCheckoutPanel();\n this.exit3d(); // dispose GL + remove the 3D overlay if it's up\n this.buyerAssetUrls.dispose();\n this.stopHoldTimer();\n if (this.toastTimer) clearTimeout(this.toastTimer);\n if (this.liveTimer) clearTimeout(this.liveTimer);\n if (this.offerRefreshTimer) clearTimeout(this.offerRefreshTimer);\n if (this.offerBoundaryTimer) clearTimeout(this.offerBoundaryTimer);\n this.offerRefreshTimer = null;\n this.offerBoundaryTimer = null;\n if (this.offerVisibilityHandler) {\n document.removeEventListener('visibilitychange', this.offerVisibilityHandler);\n this.offerVisibilityHandler = null;\n }\n for (const timer of this.motionTimers) clearTimeout(timer);\n this.motionTimers.clear();\n this.ro?.disconnect();\n this.ro = null;\n // Don't strand a host frame pinned fullscreen across a route teardown.\n if (this.framedFs) this.setFramedFs(false);\n if (this.escHandler) document.removeEventListener('keydown', this.escHandler);\n if (this.fsChangeHandler) document.removeEventListener('fullscreenchange', this.fsChangeHandler);\n if (this.fsEscHandler) window.removeEventListener('keydown', this.fsEscHandler);\n this.controller.destroy();\n this.projectionEl = null;\n this.root?.remove();\n this.root = null;\n if (this.modalScrim) {\n this.modalScrim.remove();\n this.modalScrim = null;\n if (this.prevFocus?.isConnected) this.prevFocus.focus({ preventScroll: true });\n this.prevFocus = null;\n }\n }\n}\n","/**\n * Token-safe delivery for Event-scoped buyer media.\n *\n * The chart document contains an ordinary URL so it remains portable JSON, but\n * the browser must not assign that URL directly to <img>/CSS: private and\n * Platform events need an Authorization header, which those element requests\n * cannot attach. The picker asks its transport for bytes, creates an in-memory\n * object URL, and revokes every URL when the picker is destroyed.\n */\n\nconst SAFE_ASSET = /^[a-zA-Z0-9._-]+$/;\n\nexport interface BuyerEventAssetReference {\n eventKey: string;\n asset: string;\n}\n\n/** Parse only SeatLayer's event-scoped buyer-asset path. */\nexport function buyerEventAssetReference(value: string): BuyerEventAssetReference | null {\n let url: URL;\n try {\n // A fixed dummy base also supports a future relative chart projection\n // without trusting the embedding page's current location.\n url = new URL(value, 'https://seatlayer.invalid');\n } catch {\n return null;\n }\n if (url.search || url.hash) return null;\n const match = /^\\/pub\\/events\\/([^/]+)\\/assets\\/([^/]+)$/.exec(url.pathname);\n if (!match) return null;\n try {\n const eventKey = decodeURIComponent(match[1]);\n const asset = decodeURIComponent(match[2]);\n if (!eventKey || !SAFE_ASSET.test(asset)) return null;\n return { eventKey, asset };\n } catch {\n return null;\n }\n}\n\nfunction looksLikeBuyerAsset(value: string): boolean {\n try {\n return /^\\/pub\\/events\\/[^/]+\\/assets(?:\\/|$)/.test(\n new URL(value, 'https://seatlayer.invalid').pathname,\n );\n } catch {\n return false;\n }\n}\n\nexport type BuyerAssetLoader = (eventKey: string, asset: string) => Promise<Blob>;\n\n/**\n * One picker-lifetime cache. Reusing a blob URL avoids downloading an 8K\n * panorama again when a buyer opens the same row/venue view from another seat.\n */\nexport class BuyerAssetObjectUrls {\n private readonly pending = new Map<string, Promise<string | null>>();\n private readonly created = new Set<string>();\n private disposed = false;\n\n constructor(\n private readonly eventKey: string,\n private readonly load?: BuyerAssetLoader,\n ) {}\n\n /**\n * External organizer/CDN URLs pass through unchanged. SeatLayer event assets\n * never do: they require the transport, and a reference for another Event is\n * refused instead of being loaded anonymously.\n */\n resolve(reference: string): Promise<string | null> {\n const parsed = buyerEventAssetReference(reference);\n if (!parsed) {\n // A malformed SeatLayer buyer-media path is never passed to <img>/CSS,\n // where it would bypass the authenticated byte transport.\n return Promise.resolve(looksLikeBuyerAsset(reference) ? null : reference);\n }\n if (parsed.eventKey !== this.eventKey || !this.load || this.disposed) return Promise.resolve(null);\n\n const existing = this.pending.get(reference);\n if (existing) return existing;\n\n const task = this.load(this.eventKey, parsed.asset).then((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n if (this.disposed) {\n URL.revokeObjectURL(objectUrl);\n return null;\n }\n this.created.add(objectUrl);\n return objectUrl;\n }).catch((error) => {\n // A transient load can be retried on the buyer's next explicit open.\n this.pending.delete(reference);\n throw error;\n });\n this.pending.set(reference, task);\n return task;\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const url of this.created) URL.revokeObjectURL(url);\n this.created.clear();\n this.pending.clear();\n }\n}\n","/**\n * Buyer-safe ticket-offer availability shared by the canonical picker and the\n * hosted event-page templates.\n *\n * This module intentionally owns the wire parser. A hosted page, iframe, popup\n * and SDK mount must refuse or accept the same payload; duplicating this reader\n * is how one surface eventually prints a price another surface will not charge.\n */\n\nexport type SaleState = 'on-sale' | 'low' | 'sold-out' | 'presale' | 'closed';\n\nexport interface TicketOfferSummary {\n /** Legacy ordering fields kept for older page templates and payloads. */\n index: number;\n count: number;\n /** Units currently available at this offer price; null means unlimited. */\n remaining: number | null;\n /** Buyer-facing fields added by the offers UX. Absent on older workers. */\n id?: string;\n name?: string;\n categoryKey?: string | null;\n startsAt?: number | null;\n endsAt?: number | null;\n}\n\nexport interface TicketOfferPrice {\n categoryKey: string;\n /** Major units. What a hold on this category is charged right now. */\n price: number;\n /** Major units, or null. Printed only when genuinely higher. */\n previousPrice: number | null;\n /** Offer provenance for the price row. Absent on older workers. */\n offerId?: string;\n offerName?: string;\n remaining?: number | null;\n startsAt?: number | null;\n endsAt?: number | null;\n}\n\nexport interface TicketOfferAvailability {\n state: SaleState;\n /** Currently advertised offer price, in minor units. */\n fromPrice: number | null;\n previousPrice: number | null;\n currency: string | null;\n /** The highest-priority active buy offer, when one exists. */\n release: TicketOfferSummary | null;\n /** The next scheduled price offer. It does not close ordinary ticket sales. */\n upcoming: TicketOfferSummary | null;\n /** Server-resolved active offer prices by category, in major units. */\n prices: TicketOfferPrice[];\n}\n\nexport const SALE_STATES: readonly SaleState[] = [\n 'on-sale', 'low', 'sold-out', 'presale', 'closed',\n];\n\nfunction money(value: unknown): number | null | undefined {\n if (value === null || value === undefined) return null;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction timestamp(value: unknown): number | null | undefined {\n if (value === null || value === undefined) return null;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction parseSummary(value: unknown): TicketOfferSummary | null | undefined {\n if (value == null) return null;\n if (typeof value !== 'object' || Array.isArray(value)) return undefined;\n const source = value as Record<string, unknown>;\n const count = source.count;\n const index = source.index;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 1) return undefined;\n if (typeof count !== 'number' || !Number.isInteger(count) || count < index) return undefined;\n const remaining = source.remaining;\n if (remaining != null && (typeof remaining !== 'number' || !Number.isInteger(remaining) || remaining < 0)) {\n return undefined;\n }\n\n const result: TicketOfferSummary = {\n index,\n count,\n remaining: remaining == null ? null : remaining,\n };\n if (source.id !== undefined) {\n if (typeof source.id !== 'string' || !source.id.trim()) return undefined;\n result.id = source.id.trim();\n }\n if (source.name !== undefined) {\n if (typeof source.name !== 'string' || !source.name.trim()) return undefined;\n result.name = source.name.trim();\n }\n if (source.categoryKey !== undefined) {\n if (source.categoryKey !== null && (typeof source.categoryKey !== 'string' || !source.categoryKey.trim())) {\n return undefined;\n }\n result.categoryKey = source.categoryKey == null ? null : source.categoryKey.trim();\n }\n for (const key of ['startsAt', 'endsAt'] as const) {\n if (source[key] === undefined) continue;\n const parsed = timestamp(source[key]);\n if (parsed === undefined) return undefined;\n result[key] = parsed;\n }\n return result;\n}\n\n/** Parse a public offer payload without repairing a half-understood price. */\nexport function parseTicketOfferAvailability(body: unknown): TicketOfferAvailability | null {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null;\n const raw = body as Record<string, unknown>;\n const state = SALE_STATES.find((candidate) => candidate === raw.state);\n if (!state) return null;\n\n const fromPrice = money(raw.fromPrice);\n const previousPrice = money(raw.previousPrice);\n if (fromPrice === undefined || previousPrice === undefined) return null;\n const currency = raw.currency == null ? null\n : typeof raw.currency === 'string' && raw.currency.trim() ? raw.currency.trim() : undefined;\n if (currency === undefined) return null;\n\n const release = parseSummary(raw.release);\n if (release === undefined) return null;\n const upcoming = raw.upcoming === undefined ? null : parseSummary(raw.upcoming);\n if (upcoming === undefined) return null;\n\n let prices: TicketOfferPrice[] = [];\n if (raw.prices != null) {\n if (!Array.isArray(raw.prices)) return null;\n const parsed: TicketOfferPrice[] = [];\n for (const entry of raw.prices) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;\n const row = entry as Record<string, unknown>;\n const categoryKey = typeof row.categoryKey === 'string' ? row.categoryKey.trim() : '';\n if (!categoryKey) return null;\n const price = money(row.price);\n const previous = money(row.previousPrice);\n if (price === undefined || price === null || previous === undefined) return null;\n const item: TicketOfferPrice = { categoryKey, price, previousPrice: previous };\n if (row.offerId !== undefined) {\n if (typeof row.offerId !== 'string' || !row.offerId.trim()) return null;\n item.offerId = row.offerId.trim();\n }\n if (row.offerName !== undefined) {\n if (typeof row.offerName !== 'string' || !row.offerName.trim()) return null;\n item.offerName = row.offerName.trim();\n }\n if (row.remaining !== undefined) {\n if (row.remaining !== null && (typeof row.remaining !== 'number'\n || !Number.isInteger(row.remaining) || row.remaining < 0)) return null;\n item.remaining = row.remaining == null ? null : row.remaining;\n }\n for (const key of ['startsAt', 'endsAt'] as const) {\n if (row[key] === undefined) continue;\n const at = timestamp(row[key]);\n if (at === undefined) return null;\n item[key] = at;\n }\n parsed.push(item);\n }\n prices = parsed;\n }\n\n return { state, fromPrice, previousPrice, currency, release, upcoming, prices };\n}\n\n/**\n * The earliest FUTURE instant at which the advertised offer schedule changes\n * on its own — a window opening or closing — or null when nothing scheduled\n * lies ahead. This is what lets the picker sleep until the transition instead\n * of asking the server every few seconds whether the clock has moved: every\n * other way the answer changes (a purchase, a hold expiring, an organizer\n * edit that touches seats) already arrives as a live seat frame.\n */\nexport function nextOfferTransitionAt(\n availability: TicketOfferAvailability | null,\n now: number,\n): number | null {\n if (!availability) return null;\n let next: number | null = null;\n const consider = (at: number | null | undefined): void => {\n if (at != null && at > now && (next === null || at < next)) next = at;\n };\n for (const summary of [availability.release, availability.upcoming]) {\n consider(summary?.startsAt);\n consider(summary?.endsAt);\n }\n for (const price of availability.prices) {\n consider(price.startsAt);\n consider(price.endsAt);\n }\n return next;\n}\n\n/** Translate the server-resolved category map into SeatPicker pricing. */\nexport function ticketOfferPrices(\n availability: TicketOfferAvailability | null,\n): Record<string, number> {\n const map: Record<string, number> = {};\n for (const entry of availability?.prices ?? []) map[entry.categoryKey] = entry.price;\n return map;\n}\n","/**\n * Host-side helper for embedding the SeatLayer picker as an iframe.\n *\n * The picker (the /e/:key page, mounted `position:fixed; inset:0`) reports its\n * desired height and fullscreen intent to whatever page frames it, using the\n * picker wire contract:\n *\n * • `{ type: 'seatlayer:height', px:number }` — grow the iframe to `px`.\n * • `{ type: 'seatlayer:fullscreen', on:boolean }` — pin/unpin over the host.\n *\n * A framed picker cannot escape its own iframe with CSS, so it delegates both\n * concerns to the host. `attachPickerFrame` wires those two behaviours onto a\n * picker iframe and returns a detach function that tears everything back down.\n */\nexport interface AttachPickerFrameOptions {\n /**\n * Origin to accept messages from. Defaults to the origin parsed from\n * `iframe.src`. Messages from any other origin (or any other window) are\n * ignored — the picker posts with `targetOrigin:'*'`, so the host is the side\n * that must verify `event.origin`.\n */\n origin?: string;\n}\n\n/**\n * Attach the picker resize + fullscreen protocol to a picker iframe.\n *\n * ```ts\n * const iframe = document.querySelector('iframe#seatlayer')!;\n * const detach = attachPickerFrame(iframe);\n * // …later, when removing the embed:\n * detach();\n * ```\n *\n * @param iframe The `<iframe>` element pointing at a SeatLayer picker embed.\n * @param opts Optional `{ origin }` override for the accepted message origin.\n * @returns A detach function: removes the listener and restores any pinned state.\n */\nexport function attachPickerFrame(\n iframe: HTMLIFrameElement,\n opts: AttachPickerFrameOptions = {},\n): () => void {\n let expectedOrigin = opts.origin ?? '';\n if (!expectedOrigin) {\n try {\n expectedOrigin = new URL(iframe.src, window.location.href).origin;\n } catch {\n expectedOrigin = '';\n }\n }\n\n let pinned = false;\n let frameStyleBeforeFs: string | null = null;\n let docOverflowBeforeFs: string | null = null;\n let bodyOverflowBeforeFs: string | null = null;\n let lastAutoHeight = '';\n let keyHandler: ((event: KeyboardEvent) => void) | null = null;\n\n const pin = (): void => {\n if (pinned) return;\n pinned = true;\n frameStyleBeforeFs = iframe.getAttribute('style');\n Object.assign(iframe.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n border: '0',\n zIndex: '2147483000',\n background: '#101625',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const docEl = document.documentElement;\n docOverflowBeforeFs = docEl.style.overflow;\n docEl.style.overflow = 'hidden';\n if (document.body) {\n bodyOverflowBeforeFs = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') unpin();\n };\n window.addEventListener('keydown', keyHandler);\n };\n\n const unpin = (): void => {\n if (!pinned) return;\n pinned = false;\n if (frameStyleBeforeFs === null) iframe.removeAttribute('style');\n else iframe.setAttribute('style', frameStyleBeforeFs);\n frameStyleBeforeFs = null;\n // Re-apply any height reported while we were pinned.\n if (lastAutoHeight) iframe.style.height = lastAutoHeight;\n\n if (docOverflowBeforeFs !== null) {\n document.documentElement.style.overflow = docOverflowBeforeFs;\n docOverflowBeforeFs = null;\n }\n if (bodyOverflowBeforeFs !== null && document.body) {\n document.body.style.overflow = bodyOverflowBeforeFs;\n bodyOverflowBeforeFs = null;\n }\n if (keyHandler) {\n window.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n }\n };\n\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.source !== iframe.contentWindow) return;\n if (expectedOrigin && event.origin !== expectedOrigin) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n\n if (data.type === 'seatlayer:height') {\n if (typeof data.px === 'number' && Number.isFinite(data.px) && data.px > 0) {\n lastAutoHeight = `${Math.round(data.px)}px`;\n // While pinned the iframe fills the viewport; the height is re-applied on unpin.\n if (!pinned) iframe.style.height = lastAutoHeight;\n }\n return;\n }\n if (data.type === 'seatlayer:fullscreen') {\n if (data.on === true) pin();\n else if (data.on === false) unpin();\n }\n };\n\n window.addEventListener('message', onMessage);\n\n return (): void => {\n window.removeEventListener('message', onMessage);\n unpin();\n };\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["el","back","t","el","money","resolveContainer","target","import_core","DEFAULT_API_BASE","DEFAULT_MAX_SELECTION","resolveContainer","el","STYLE_ID","CSS","ensureStyle","pano","canView","mountCheckout","location","main"]}