{
  "version": 3,
  "sources": ["/cdn/shop/t/9/assets/instant-quoter.js?cb=aa3b976"],
  "sourcesContent": ["(() => {\n  // A versioned namespace prevents retired preview access from surviving a launch.\n  const accessStorageKey = 'ep-instant-quoter-access-v1';\n  const quoteSessionStorageKey = 'ep-instant-quoter-session';\n  const journeyStorageKey = 'ep-instant-quoter-journey-v1';\n  const analyticsQueueStorageKey = 'ep-instant-quoter-analytics-queue';\n  const salesChatFeatureStorageKey = 'ep-instant-quoter-sales-chat-enabled';\n  const assistantStorageKey = `ep-instant-quoter-assistant-v1:${window.location.pathname}`;\n  const consentStorageKey = 'ep-cookie-consent';\n  const consentTimestampStorageKey = 'ep-cookie-consent-updated-at';\n  const consentChangedEvent = 'ep:cookie-consent-changed';\n\n  const serviceDefinitions = {\n    drop_off: {\n      label: 'Drop Off Booth',\n      detail: 'All-day use, setup, teardown, custom artwork, and digital sharing are already included.',\n    },\n    photo_booth: {\n      label: 'Photo Booth',\n      detail: 'Your attendant, custom artwork, a standard backdrop, and digital sharing are included.',\n      runtime: { standard: 3, wedding: 4, maximum: 6 },\n    },\n    360: {\n      label: '360 Booth',\n      detail: 'Your attendant, custom artwork, and digital sharing are included.',\n      runtime: { standard: 3, wedding: 4, maximum: 6 },\n    },\n    classic: {\n      label: 'Classic Booth',\n      detail: 'Six hours, printing, custom artwork, setup, teardown, and digital sharing are included.',\n      runtime: { standard: 6, wedding: 6, maximum: 10 },\n    },\n    red_carpet: {\n      label: 'Red Carpet / Step & Repeat',\n      detail: 'A photographer, carpet, sharing attendant, sharing station, and lighting are included.',\n      runtime: { standard: 2, wedding: 2, maximum: 6 },\n    },\n    teleportrait_existing: {\n      label: 'Teleportrait',\n      detail: 'The set, director, assistants, and the full interactive production experience are included.',\n    },\n    teleportrait_custom: {\n      label: 'Custom Teleportrait',\n      detail: 'We\u2019ll use this estimate as the starting point for a one-of-one creative production call.',\n    },\n  };\n\n  const readSessionJson = (key) => {\n    try {\n      return JSON.parse(sessionStorage.getItem(key) || 'null');\n    } catch {\n      return null;\n    }\n  };\n\n  const writeSessionJson = (key, value) => {\n    try {\n      sessionStorage.setItem(key, JSON.stringify(value));\n    } catch {\n      // Strict privacy contexts can disable storage. The current render still\n      // works; idempotent retries simply cannot survive a refresh.\n    }\n  };\n\n  const removeSessionValue = (key) => {\n    try {\n      sessionStorage.removeItem(key);\n    } catch {\n      // Storage is optional for the private beta.\n    }\n  };\n\n  const readAccess = () => {\n    const value = readSessionJson(accessStorageKey);\n    if (!value?.token || !value?.expiresAt || value.expiresAt <= Math.floor(Date.now() / 1000)) {\n      removeSessionValue(accessStorageKey);\n      return null;\n    }\n    return value;\n  };\n\n  const writeAccess = (value) => writeSessionJson(accessStorageKey, value);\n\n  const readQuoteSession = () => {\n    const value = readSessionJson(quoteSessionStorageKey);\n    if (!value?.startIdempotencyKey) return null;\n    if (value.token && (!value.expiresAt || Date.parse(value.expiresAt) <= Date.now())) {\n      removeSessionValue(quoteSessionStorageKey);\n      removeSessionValue(analyticsQueueStorageKey);\n      return null;\n    }\n    return value;\n  };\n\n  const writeQuoteSession = (value) => writeSessionJson(quoteSessionStorageKey, value);\n\n  const readAnalyticsQueue = () => {\n    const value = readSessionJson(analyticsQueueStorageKey);\n    return Array.isArray(value) ? value.slice(-50) : [];\n  };\n\n  const writeAnalyticsQueue = (value) => {\n    if (value.length === 0) {\n      removeSessionValue(analyticsQueueStorageKey);\n      return;\n    }\n    writeSessionJson(analyticsQueueStorageKey, value.slice(-50));\n  };\n\n  const randomId = () => {\n    if (window.crypto?.randomUUID) return window.crypto.randomUUID();\n    return `ep-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 14)}`;\n  };\n\n  const readLocalStorage = (key) => {\n    try {\n      return window.localStorage.getItem(key);\n    } catch {\n      return null;\n    }\n  };\n\n  const readLocalJson = (key) => {\n    try {\n      return JSON.parse(window.localStorage.getItem(key) || 'null');\n    } catch {\n      return null;\n    }\n  };\n\n  const writeLocalJson = (key, value) => {\n    try {\n      window.localStorage.setItem(key, JSON.stringify(value));\n    } catch {\n      // The assistant still works when private browsing disables persistence.\n    }\n  };\n\n  const removeLocalValue = (key) => {\n    try {\n      window.localStorage.removeItem(key);\n    } catch {\n      // Local persistence is optional.\n    }\n  };\n\n  /** True only when Shopify reports no consent banner is required for this visitor. */\n  const consentNotRequired = () => {\n    try {\n      const privacy = window.Shopify?.customerPrivacy;\n      if (typeof privacy?.shouldShowBanner !== 'function') return false;\n      return privacy.shouldShowBanner() === false;\n    } catch {\n      return false;\n    }\n  };\n\n  /**\n   * Consent for FIRST-PARTY measurement \u2014 funnel events sent to EP's own API\n   * and to nobody else.\n   *\n   * An explicit choice always wins, in either direction. Absent a choice we\n   * follow Shopify's regional model: where a banner is legally required we\n   * stay silent until the visitor decides; where it isn't, first-party\n   * measurement runs by default. Third-party tags never use this \u2014 anything\n   * published to Shopify's analytics bus (which advertising pixels subscribe\n   * to) requires an explicit opt-in. See assets/booking-attribution.js.\n   */\n  const readAnalyticsConsent = () => {\n    const currentVisitorConsent = window.Shopify?.customerPrivacy?.currentVisitorConsent?.();\n    if (currentVisitorConsent?.analytics === 'no') return { allowed: false, capturedAt: null };\n\n    const storedChoice = readLocalStorage(consentStorageKey);\n    if (storedChoice === 'essential-only') return { allowed: false, capturedAt: null };\n\n    const allowed =\n      currentVisitorConsent?.analytics === 'yes' ||\n      storedChoice === 'accepted' ||\n      consentNotRequired();\n    if (!allowed) return { allowed: false, capturedAt: null };\n\n    return {\n      allowed: true,\n      capturedAt: readLocalStorage(consentTimestampStorageKey) || new Date().toISOString(),\n    };\n  };\n\n  const safeAttributionValue = (value, maxLength) => {\n    const normalized = value?.trim() || '';\n    return new RegExp(`^[A-Za-z0-9._~-]{1,${maxLength}}$`).test(normalized)\n      ? normalized\n      : undefined;\n  };\n\n  const buildAttribution = () => {\n    const params = new URLSearchParams(window.location.search);\n    let referrerHost;\n    try {\n      referrerHost = document.referrer ? new URL(document.referrer).hostname.toLowerCase() : undefined;\n    } catch {\n      referrerHost = undefined;\n    }\n\n    const attribution = {\n      source: safeAttributionValue(params.get('utm_source'), 100),\n      medium: safeAttributionValue(params.get('utm_medium'), 100),\n      campaign: safeAttributionValue(params.get('utm_campaign'), 150),\n      content: safeAttributionValue(params.get('utm_content'), 150),\n      term: safeAttributionValue(params.get('utm_term'), 150),\n      referrerHost,\n      landingPath: /^[A-Za-z0-9/_-]+$/.test(window.location.pathname)\n        ? window.location.pathname\n        : undefined,\n    };\n    return Object.fromEntries(Object.entries(attribution).filter(([, value]) => value));\n  };\n\n  const createElement = (tag, className, text) => {\n    const element = document.createElement(tag);\n    if (className) element.className = className;\n    if (text !== undefined) element.textContent = text;\n    return element;\n  };\n\n  const initializeQuoter = (root) => {\n    if (root.dataset.instantQuoterReady === 'true') return;\n    root.dataset.instantQuoterReady = 'true';\n\n    const model = window.EPInstantQuoterModel;\n    // Fresh partner links open the Experience Finder \u2014 the quiz is the\n    // referral front door, and the deal rides its handoff back here. Old\n    // `?ep_ref=` links shared before the switch keep working through this\n    // forward, so partners never need their links reissued.\n    const finderForward = model?.referralFinderForwardUrl?.({\n      search: window.location.search,\n      finderUrl: root.dataset.finderUrl || '/pages/book',\n      origin: window.location.origin,\n    });\n    if (finderForward) {\n      window.location.replace(finderForward);\n      return;\n    }\n    const accessPanel = root.querySelector('[data-quote-access-panel]');\n    const accessStatus = root.querySelector('[data-quote-access-status]');\n    const accessRetry = root.querySelector('[data-quote-access-retry]');\n    const workspace = root.querySelector('[data-quote-workspace]');\n    const message = root.querySelector('[data-quote-message]');\n    const modeStatus = root.querySelector('[data-quote-mode-status]');\n    const steps = Array.from(root.querySelectorAll('[data-quote-step]'));\n    const locationInput = root.querySelector('[name=\"event_location\"]');\n    const dateInput = root.querySelector('[name=\"event_date\"]');\n    const locationStatus = root.querySelector('[data-quote-location-status]');\n    const locationSubmitLabel = root.querySelector('[data-quote-location-submit]');\n    const locationSubmitButton = locationSubmitLabel?.closest('button');\n    const validatedAddressConfirmation = root.querySelector('[data-quote-validated-address]');\n    const validatedAddressValue = root.querySelector('[data-quote-validated-address-value]');\n    const validatedAddressCorrection = root.querySelector('[data-quote-location-correct]');\n    const progress = Array.from(root.querySelectorAll('[data-quote-progress]'));\n    const summary = root.querySelector('[data-quote-summary]');\n    const servicesContainer = root.querySelector('[data-quote-services]');\n    const serviceInputs = () => Array.from(root.querySelectorAll('[name=\"service\"]'));\n    const serviceSelectionNote = root.querySelector('[data-service-selection-note]');\n    const configurations = root.querySelector('[data-quote-configurations]');\n    const calculateButton = root.querySelector('[data-calculate-quote]');\n    const quoteOutcome = root.querySelector('[data-quote-outcome]');\n    const quoteOptionCards = root.querySelector('[data-quote-options]');\n    const quoteTitle = root.querySelector('[data-quote-title]');\n    const quoteLineItems = root.querySelector('[data-quote-line-items]');\n    const quoteTotalLabel = root.querySelector('[data-quote-total-label]');\n    const quoteTotal = root.querySelector('[data-quote-total]');\n    const quoteRetainer = root.querySelector('[data-quote-retainer]');\n    const quoteTotalNote = root.querySelector('[data-quote-total-note]');\n    const quoteReasons = root.querySelector('[data-quote-reasons]');\n    const quoteNextNote = root.querySelector('[data-quote-next-note]');\n    const saveContactButton = root.querySelector('[data-save-quote-contact]');\n    const quoteActionButton = root.querySelector('[data-quote-action]');\n    const quoteActionNote = root.querySelector('[data-quote-action-note]');\n    const restartButton = root.querySelector('[data-quote-restart]');\n    const assistantPortal = root.querySelector('[data-quote-assistant-portal]');\n    const assistantTrigger = root.querySelector('[data-quote-assistant-trigger]');\n    const assistantContextualTriggers = Array.from(root.querySelectorAll('[data-quote-assistant-contextual]'));\n    const assistantFab = root.querySelector('[data-quote-assistant-fab]');\n    const assistantDialog = root.querySelector('[data-quote-assistant-dialog]');\n    const assistantCloseButtons = Array.from(root.querySelectorAll('[data-quote-assistant-close]'));\n    const assistantKicker = root.querySelector('[data-quote-assistant-kicker]');\n    const assistantTitle = root.querySelector('[data-quote-assistant-title]');\n    const assistantDisclosure = root.querySelector('[data-quote-assistant-disclosure]');\n    const assistantParticipants = root.querySelector('[data-quote-assistant-participants]');\n    const assistantMessages = root.querySelector('[data-quote-assistant-messages]');\n    const assistantTyping = root.querySelector('[data-quote-assistant-typing]');\n    const assistantSuggestions = root.querySelector('[data-quote-assistant-suggestions]');\n    const assistantForm = root.querySelector('[data-quote-assistant-form]');\n    const assistantInputLabel = root.querySelector('[data-quote-assistant-input-label]');\n    const assistantInput = root.querySelector('[data-quote-assistant-input]');\n    const assistantSend = root.querySelector('[data-quote-assistant-send]');\n    const assistantStatus = root.querySelector('[data-quote-assistant-status]');\n    const assistantEmail = root.querySelector('[data-quote-assistant-email]');\n    const assistantCall = root.querySelector('[data-quote-assistant-call]');\n    const assistantHandoffs = root.querySelector('.instant-quoter__assistant-handoffs');\n    const liveSalesCallouts = Array.from(root.querySelectorAll('[data-quote-sales-help-callout]'));\n    const liveSalesStarts = Array.from(root.querySelectorAll('[data-quote-live-sales-start]'));\n    const liveSalesLabels = Array.from(root.querySelectorAll('[data-quote-live-sales-label]'));\n    const liveSalesStatuses = Array.from(root.querySelectorAll('[data-quote-live-sales-status]'));\n    const liveSalesEmailFallback = root.querySelector('[data-quote-live-sales-email-fallback]');\n    const assistantMobileMedia = window.matchMedia('(max-width: 760px)');\n    if (assistantPortal) document.body.append(assistantPortal);\n    const proxyPath = (root.dataset.appProxyPath || '/apps/instant-quote').replace(/\\/$/, '');\n    const reviewConfirmationUrl = root.dataset.reviewConfirmationUrl || '/pages/instant-quote-review';\n    const checkoutHosts = (() => {\n      try {\n        const hosts = JSON.parse(root.dataset.checkoutHosts || '[]');\n        return Array.isArray(hosts) ? hosts : [];\n      } catch {\n        return [];\n      }\n    })();\n    const accessEndpoint = `${proxyPath}/access`;\n    const sessionEndpoint = `${proxyPath}/sessions`;\n    const stepIds = ['where_when', 'contact', 'event_type', 'attendance', 'recommendation', 'configuration', 'review', 'checkout'];\n    let currentStep = 1;\n    let stepEnteredAt = Date.now();\n    let activeAccess = null;\n    let quoteSessionPromise = null;\n    let flushingAnalytics = false;\n    let savedConfigurations = new Map();\n    let latestQuote = null;\n    let serverRevision = 0;\n    let validatedEventLocation = null;\n    let hasRestoredJourney = false;\n    /** The campaign package driving this session (`?ep_package=`), or null. */\n    let activePackage = null;\n    let packageBanner = null;\n    /** The referral partner driving this session (`?ep_ref=`), or null. */\n    let activeReferral = readQuoteSession()?.referral || null;\n    /**\n     * True when this session is a staff-built quote opened from its emailed\n     * link (docs on the platform: STAFF_QUOTES_DESIGN.md). The review step\n     * renders view-and-checkout only \u2014 no back navigation, no funnel rail \u2014\n     * and changes route back through EP.\n     */\n    let staffQuoteLocked = false;\n    // Pay-by-invoice: the quote shows what the deal costs and says an invoice\n    // is coming, instead of offering card checkout. Staff set this on ANY\n    // quote \u2014 a staff-built one or a cart the client built here \u2014 so it is\n    // deliberately NOT gated on the staff-quote lock. The platform is the only\n    // authority; there is no client-facing control. The terms stay EP's\n    // business and the client sees the real figures on the invoice itself.\n    let payByInvoice = false;\n    // \"Invoice only\": an invoice deal staff set to skip the contract, so the\n    // invoice copy must not promise one comes \"once your agreement is\n    // signed\". Only meaningful beside `payByInvoice`; the platform sends it\n    // nowhere else, and while it is absent the copy is unchanged.\n    let invoiceWithoutAgreement = false;\n    /**\n     * Community Partner sessions only: the client's own \"pay by card\" vs\n     * \"get an invoice\" pick ('checkout' | 'invoice' | null). Null means they\n     * have not touched the picker \u2014 the effective path then follows\n     * `payByInvoice` (a staff- or previously-chosen invoice session) and\n     * otherwise defaults to card.\n     */\n    let paymentPathPick = null;\n    /**\n     * Quote Options: 2+ named sibling quotes on a locked staff session. The\n     * client compares the cards, and the active option's quote IS\n     * `latestQuote` \u2014 checkout targets whichever card they picked.\n     */\n    let quoteOptions = [];\n    let selectedQuoteOptionKey = null;\n    /**\n     * True while the client has been offered real alternatives and has not\n     * picked one yet \u2014 checkout stays closed until they do, so nobody buys\n     * without registering that there were choices.\n     */\n    let optionChoicePending = false;\n    let referralBanner = null;\n    let referralPicker = null;\n    /** True once the guest chooses \"Somewhere else\" over the partner venues. */\n    let referralCustomAddressMode = false;\n    let activeCatalog = readQuoteSession()?.catalog || null;\n    let assistantState = (() => {\n      const saved = readLocalJson(assistantStorageKey);\n      return saved && typeof saved === 'object'\n        ? {\n            mode: saved.mode === 'sales' ? 'sales' : 'assistant',\n            conversationId: typeof saved.conversationId === 'string' ? saved.conversationId : null,\n            salesConversationId: typeof saved.salesConversationId === 'string' ? saved.salesConversationId : null,\n            salesStatus: typeof saved.salesStatus === 'string' ? saved.salesStatus : 'idle',\n            salesCursor: typeof saved.salesCursor === 'string' ? saved.salesCursor : null,\n            salesRequestedAt: typeof saved.salesRequestedAt === 'string' ? saved.salesRequestedAt : null,\n            salesFallbackAt: typeof saved.salesFallbackAt === 'string' ? saved.salesFallbackAt : null,\n            salesAgentJoinedAt: typeof saved.salesAgentJoinedAt === 'string' ? saved.salesAgentJoinedAt : null,\n            salesParticipants: Array.isArray(saved.salesParticipants) ? saved.salesParticipants.slice(0, 12) : [],\n            salesStaffTyping: false,\n            salesStartIdempotencyKey: typeof saved.salesStartIdempotencyKey === 'string'\n              ? saved.salesStartIdempotencyKey\n              : randomId(),\n            messages: Array.isArray(saved.messages) ? saved.messages.slice(-30) : [],\n          }\n        : {\n            mode: 'assistant',\n            conversationId: null,\n            salesConversationId: null,\n            salesStatus: 'idle',\n            salesCursor: null,\n            salesRequestedAt: null,\n            salesFallbackAt: null,\n            salesAgentJoinedAt: null,\n            salesParticipants: [],\n            salesStaffTyping: false,\n            salesStartIdempotencyKey: randomId(),\n            messages: [],\n          };\n    })();\n    let assistantReturnFocus = null;\n    let assistantBodyOverflow = null;\n    let liveSalesPollTimer = null;\n    let liveSalesFallbackTimer = null;\n    let liveSalesPollInFlight = false;\n    let liveSalesTypingStopTimer = null;\n    let liveSalesTypingLastSentAt = 0;\n    let liveSalesRemoteTypingTimer = null;\n    let assistantHistorySignature = null;\n    let assistantParticipantsSignature = null;\n\n    const setMessage = (text = '') => {\n      message.textContent = text;\n    };\n\n    const setLocationStatus = (text = '', tone = '') => {\n      if (!locationStatus) return;\n      locationStatus.textContent = text;\n      if (tone) locationStatus.dataset.tone = tone;\n      else delete locationStatus.dataset.tone;\n      locationStatus.setAttribute('aria-busy', tone === 'checking' ? 'true' : 'false');\n    };\n\n    const renderValidatedAddressConfirmation = () => {\n      const formattedAddress = validatedEventLocation?.formattedAddress?.trim() || '';\n      if (validatedAddressValue) validatedAddressValue.textContent = formattedAddress;\n      if (validatedAddressConfirmation) validatedAddressConfirmation.hidden = !formattedAddress;\n    };\n\n    if (!model) {\n      setMessage('The quote builder did not load. Refresh the page and try again.');\n      return;\n    }\n\n    const salesChatQueryValue = new URLSearchParams(window.location.search).get('sales_chat');\n    if (salesChatQueryValue === '1') writeSessionJson(salesChatFeatureStorageKey, '1');\n    else if (salesChatQueryValue === '0') writeSessionJson(salesChatFeatureStorageKey, '0');\n    else if (salesChatQueryValue !== null) removeSessionValue(salesChatFeatureStorageKey);\n    const salesChatEnabled = model.salesChatFeatureEnabled({\n      search: window.location.search,\n      storedValue: readSessionJson(salesChatFeatureStorageKey),\n    });\n    liveSalesCallouts.forEach((callout) => {\n      callout.hidden = !salesChatEnabled;\n    });\n\n    const refreshEventDateWindow = () => {\n      if (!dateInput) return;\n      const { min, max } = model.eventDateWindow();\n      dateInput.min = min;\n      dateInput.max = max;\n    };\n\n    const validateEventDateInput = () => {\n      if (!dateInput) return;\n      refreshEventDateWindow();\n      const error = model.eventDateError(dateInput.value);\n      const messages = {\n        date_required: 'Choose your event date.',\n        date_invalid: 'Choose a valid event date.',\n        date_in_past: 'Choose today or a future date.',\n        date_too_far: 'Choose a date within the next two years.',\n      };\n      dateInput.setCustomValidity(messages[error] || '');\n    };\n\n    refreshEventDateWindow();\n\n    const viewportClass = () => {\n      if (window.matchMedia('(max-width: 47.99rem)').matches) return 'mobile';\n      if (window.matchMedia('(max-width: 74.99rem)').matches) return 'tablet';\n      return 'desktop';\n    };\n\n    const stepDescriptor = (number = currentStep) => ({\n      id: stepIds[number - 1],\n      number,\n    });\n\n    /**\n     * The prominent deal ribbon on an experience card when the session's\n     * referral deal touches its price (override, percent-off, or both):\n     * struck-through standard price, the dominant deal price, an explicit\n     * savings line, and the partner attribution. It disappears once a custom\n     * address forfeits the deal; all math lives in the model and the server\n     * reprices authoritatively either way \u2014 this is display only.\n     */\n    const renderDealRibbon = (card, pricing) => {\n      const existing = card.querySelector('[data-service-referral-price]');\n      if (!pricing || model.referralDealLost(activeReferral, validatedEventLocation)) {\n        existing?.remove();\n        return;\n      }\n      const ribbon = existing || createElement('span', 'instant-quoter__experience-deal');\n      if (!existing) {\n        ribbon.setAttribute('data-service-referral-price', '');\n        (card.querySelector('span') || card).append(ribbon);\n      }\n      const prices = createElement('span', 'instant-quoter__experience-deal-prices');\n      prices.append(\n        ...(pricing.standardCents !== undefined\n          ? [createElement('s', '', model.formatMoney(pricing.standardCents)), document.createTextNode(' ')]\n          : []),\n        createElement('strong', '', model.formatMoney(pricing.dealCents)),\n      );\n      ribbon.replaceChildren(\n        prices,\n        ...(pricing.savingsCents !== undefined\n          ? [createElement('em', 'instant-quoter__experience-deal-save', `Save ${model.formatMoney(pricing.savingsCents)}`)]\n          : []),\n        createElement('small', 'instant-quoter__experience-deal-partner', `${activeReferral.name} offer`),\n      );\n    };\n\n    const renderReferralCardPricing = (card, service, offering, wedding = false) => {\n      renderDealRibbon(card, model.referralCardPricing(activeReferral, service, offering, { wedding }));\n    };\n\n    /** Comps apply only while the deal is live at a partner venue. */\n    const addOnComped = (code) => Boolean(\n      activeReferral\n      && !model.referralDealLost(activeReferral, validatedEventLocation)\n      && model.referralAddOnComped(activeReferral, code),\n    );\n\n    const compBadgeElement = () => {\n      const badge = createElement('span', 'instant-quoter__addon-comp', `FREE with ${activeReferral.name}`);\n      badge.setAttribute('data-quote-comped-addon', '');\n      return badge;\n    };\n\n    /** A comped add-on displays as free; the server prices its line at $0. */\n    const addOnPriceLabel = (label, cents, comped) => (\n      comped ? `${label} \u00B7 Free` : `${label} \u00B7 ${model.formatMoney(cents)}`\n    );\n\n    const renderCatalogServices = () => {\n      if (!activeCatalog) return;\n      const mode = selectedEventType() === 'wedding' ? 'wedding' : 'standard';\n      const packages = Object.entries(activeCatalog.packages?.[mode] || {})\n        .filter(([service, offering]) => model.isCatalogOfferingAvailableAtDistance(\n          offering,\n          validatedEventLocation?.travelMiles,\n        ) && model.referralOfferingAllowed(activeReferral, service));\n      const packageCodes = new Set(packages.map(([service]) => service));\n\n      servicesContainer.querySelectorAll('[data-catalog-service=\"true\"]').forEach((card) => {\n        if (!packageCodes.has(card.dataset.serviceCard)) card.remove();\n      });\n\n      for (const [service, offering] of packages) {\n        let card = root.querySelector(`[data-service-card=\"${service}\"]`);\n        if (!card) {\n          card = createElement('label', 'instant-quoter__experience');\n          card.dataset.serviceCard = service;\n          card.dataset.catalogService = 'true';\n          const input = document.createElement('input');\n          input.type = 'checkbox';\n          input.name = 'service';\n          input.value = service;\n          const copy = document.createElement('span');\n          copy.append(\n            createElement('small', '', 'Build your lineup'),\n            createElement('strong'),\n            createElement('em'),\n          );\n          card.append(input, copy);\n          servicesContainer.append(card);\n        }\n        card.hidden = false;\n        card.querySelector('strong').textContent = offering.label;\n        card.querySelector('em').textContent = offering.description;\n        renderReferralCardPricing(card, service, offering, mode === 'wedding');\n\n        const definition = serviceDefinitions[service] || {};\n        definition.label = offering.label;\n        definition.detail = offering.description;\n        if (\n          Number.isInteger(offering.includedRuntimeHours)\n          && Number.isInteger(offering.maximumOnlineRuntimeHours)\n        ) {\n          definition.runtime = definition.runtime || {};\n          definition.runtime[mode] = offering.includedRuntimeHours;\n          definition.runtime.maximum = offering.maximumOnlineRuntimeHours;\n        } else {\n          delete definition.runtime;\n        }\n        serviceDefinitions[service] = definition;\n      }\n\n      for (const service of ['drop_off', 'photo_booth', '360', 'classic', 'red_carpet']) {\n        const card = root.querySelector(`[data-service-card=\"${service}\"]`);\n        if (card) {\n          card.hidden = !packageCodes.has(service);\n          const input = card.querySelector('input');\n          if (card.hidden && input) input.checked = false;\n        }\n      }\n    };\n\n    const applyCatalogPresentation = () => {\n      if (!activeCatalog) return;\n      renderCatalogServices();\n      for (const [service, kind] of [\n        ['teleportrait_existing', 'existing'],\n        ['teleportrait_custom', 'custom'],\n      ]) {\n        const offering = activeCatalog.teleportrait?.[kind];\n        const card = root.querySelector(`[data-service-card=\"${service}\"]`);\n        if (!card) continue;\n        card.hidden = !model.isCatalogOfferingAvailableAtDistance(\n          offering,\n          validatedEventLocation?.travelMiles,\n        ) || !model.referralOfferingAllowed(activeReferral, service);\n        if (card.hidden) {\n          const input = card.querySelector('input');\n          if (input) input.checked = false;\n          continue;\n        }\n        card.querySelector('strong').textContent = offering.label;\n        card.querySelector('em').textContent = offering.description;\n        // A teleportrait_existing override is a FLAT deal price for any\n        // existing set; teleportrait_custom is never overridden.\n        renderDealRibbon(card, service === 'teleportrait_existing'\n          ? model.referralTeleportraitCardPricing(activeReferral, activeCatalog)\n          : null);\n        serviceDefinitions[service].label = offering.label;\n        serviceDefinitions[service].detail = offering.description;\n      }\n    };\n\n    const ensureQuoteSession = async () => {\n      const existing = readQuoteSession();\n      if (existing?.token) {\n        activeCatalog = existing.catalog || activeCatalog;\n        activeReferral = existing.referral || activeReferral;\n        applyCatalogPresentation();\n        return existing;\n      }\n      if (!activeAccess?.token) throw new Error('Quote access is unavailable');\n      if (quoteSessionPromise) return quoteSessionPromise;\n\n      const pending = existing || { startIdempotencyKey: randomId() };\n      writeQuoteSession(pending);\n      quoteSessionPromise = (async () => {\n        const response = await fetch(sessionEndpoint, {\n          method: 'POST',\n          headers: {\n            authorization: `Bearer ${activeAccess.token}`,\n            'content-type': 'application/json',\n            'idempotency-key': pending.startIdempotencyKey,\n          },\n          body: JSON.stringify({\n            ...(pending.packageCode\n              ? { entryPoint: 'package', packageCode: pending.packageCode }\n              : { entryPoint: 'instant_booking' }),\n            ...(pending.referralCode ? { referralCode: pending.referralCode } : {}),\n          }),\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.sessionToken || !payload.expiresAt) {\n          throw new Error('Unable to start the quote session');\n        }\n        const session = {\n          ...pending,\n          token: payload.sessionToken,\n          expiresAt: payload.expiresAt,\n          catalog: payload.catalog,\n          ...(pending.packageCode\n            ? { package: model.normalizePackageOffer(payload.package) }\n            : {}),\n          // Resume replays of a referral session also return `referral`, so\n          // every session start captures it \u2014 null means no live partner.\n          referral: model.normalizeReferralOffer(payload.referral),\n        };\n        activeCatalog = payload.catalog || null;\n        activeReferral = session.referral;\n        applyCatalogPresentation();\n        applyReferralPresentation();\n        writeQuoteSession(session);\n        return session;\n      })();\n\n      try {\n        return await quoteSessionPromise;\n      } finally {\n        quoteSessionPromise = null;\n      }\n    };\n\n    const flushAnalyticsQueue = async () => {\n      if (flushingAnalytics || !readAnalyticsConsent().allowed || !activeAccess?.token) return;\n      flushingAnalytics = true;\n      try {\n        const session = await ensureQuoteSession();\n        let queue = readAnalyticsQueue();\n        while (queue.length > 0 && readAnalyticsConsent().allowed) {\n          const queuedEvent = queue[0];\n          const response = await fetch(`${sessionEndpoint}/${encodeURIComponent(session.token)}/events`, {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n              'idempotency-key': queuedEvent.eventId,\n            },\n            body: JSON.stringify(queuedEvent.body),\n            keepalive: true,\n          });\n\n          if (!response.ok && ![400, 409].includes(response.status)) break;\n          queue = model.removeSentAnalyticsEvent(\n            readAnalyticsQueue(),\n            queuedEvent.eventId,\n          );\n          writeAnalyticsQueue(queue);\n\n          if (response.ok && queuedEvent.body.eventName === 'quote_started') {\n            const latestSession = readQuoteSession();\n            if (latestSession) {\n              writeQuoteSession({\n                ...latestSession,\n                analyticsStartedAt: queuedEvent.body.occurredAt,\n              });\n            }\n          }\n        }\n      } catch {\n        // Telemetry must never block the quote experience.\n      } finally {\n        flushingAnalytics = false;\n      }\n    };\n\n    const enqueueFunnelEvent = (eventName, { step, properties, attribution } = {}) => {\n      const consent = readAnalyticsConsent();\n      // Queue on consent alone. Access is required to SEND, not to record:\n      // flushAnalyticsQueue holds events until a token exists, so anything a\n      // visitor does between granting consent and unlocking still counts.\n      if (!consent.allowed) return;\n\n      const body = {\n        eventName,\n        occurredAt: new Date().toISOString(),\n        ...(step ? { step } : {}),\n        ...(properties && Object.keys(properties).length > 0 ? { properties } : {}),\n        ...(attribution && Object.keys(attribution).length > 0 ? { attribution } : {}),\n        consent: {\n          analytics: true,\n          capturedAt: consent.capturedAt,\n        },\n      };\n      const queue = readAnalyticsQueue();\n      queue.push({ eventId: randomId(), body });\n      writeAnalyticsQueue(queue);\n      void flushAnalyticsQueue();\n    };\n\n    const queueQuoteStarted = () => {\n      if (!readAnalyticsConsent().allowed) return;\n      const session = readQuoteSession();\n      const queue = readAnalyticsQueue();\n      if (session?.analyticsStartedAt || queue.some((event) => event.body?.eventName === 'quote_started')) return;\n\n      enqueueFunnelEvent('quote_started', {\n        properties: { viewportClass: viewportClass(), interactionSource: 'initial' },\n        attribution: buildAttribution(),\n      });\n    };\n\n    const trackStepEvent = (eventName, number, properties = {}) => {\n      enqueueFunnelEvent(eventName, {\n        step: stepDescriptor(number),\n        properties: {\n          viewportClass: viewportClass(),\n          ...properties,\n        },\n      });\n    };\n\n    const selectedEventType = () => root.querySelector('[name=\"event_type\"]:checked')?.value;\n    const selectedServices = () => serviceInputs().filter((input) => input.checked).map((input) => input.value);\n\n    const persistAssistant = () => {\n      writeLocalJson(assistantStorageKey, {\n        mode: assistantState.mode,\n        conversationId: assistantState.conversationId,\n        salesConversationId: assistantState.salesConversationId,\n        salesStatus: assistantState.salesStatus,\n        salesCursor: assistantState.salesCursor,\n        salesRequestedAt: assistantState.salesRequestedAt,\n        salesFallbackAt: assistantState.salesFallbackAt,\n        salesAgentJoinedAt: assistantState.salesAgentJoinedAt,\n        salesParticipants: assistantState.salesParticipants.slice(0, 12),\n        salesStartIdempotencyKey: assistantState.salesStartIdempotencyKey,\n        messages: assistantState.messages.slice(-30),\n      });\n    };\n\n    const assistantMessageElement = (entry) => {\n      const bubble = createElement('div', `instant-quoter__assistant-message is-${entry.role}`);\n      if (entry.role === 'assistant') bubble.setAttribute('aria-label', 'Electric Photoland assistant');\n      if (entry.role === 'sales') bubble.setAttribute('aria-label', 'Electric Photoland team');\n      if (entry.role === 'system') {\n        bubble.textContent = entry.content;\n        return bubble;\n      }\n\n      if (entry.role === 'sales') {\n        const avatar = entry.author?.imageUrl\n          ? createElement('img', 'instant-quoter__assistant-avatar')\n          : createElement('span', 'instant-quoter__assistant-avatar is-fallback', (entry.author?.name || 'EP').charAt(0));\n        if (avatar.tagName === 'IMG') {\n          avatar.src = entry.author.imageUrl;\n          avatar.alt = entry.author.name || 'EP team member';\n          avatar.loading = 'lazy';\n        } else {\n          avatar.setAttribute('aria-label', entry.author?.name || 'EP team member');\n        }\n        bubble.append(avatar);\n      }\n\n      const body = createElement('div', 'instant-quoter__assistant-message-body');\n      if (entry.role === 'sales' && entry.author?.name) {\n        body.append(createElement('span', 'instant-quoter__assistant-author', entry.author.name));\n      }\n      (Array.isArray(entry.attachments) ? entry.attachments : []).forEach((attachment) => {\n        if (!attachment?.url || !['image', 'video'].includes(attachment.type)) return;\n        let media;\n        if (attachment.type === 'video') {\n          media = createElement('video', 'instant-quoter__assistant-media');\n          media.controls = true;\n          media.playsInline = true;\n          media.preload = 'metadata';\n          media.setAttribute('aria-label', attachment.filename || 'Video from Electric Photoland');\n        } else {\n          media = createElement('img', 'instant-quoter__assistant-media');\n          media.alt = attachment.filename || 'Photo from Electric Photoland';\n          media.loading = 'lazy';\n        }\n        media.src = attachment.url;\n        body.append(media);\n      });\n      if (entry.content) body.append(createElement('p', 'instant-quoter__assistant-message-copy', entry.content));\n\n      if (assistantState.mode === 'sales' && entry.id) {\n        const reactions = createElement('div', 'instant-quoter__assistant-reactions');\n        const groups = new Map();\n        (Array.isArray(entry.reactions) ? entry.reactions : []).forEach((reaction) => {\n          if (!['\u2764\uFE0F', '\uD83D\uDC4D', '\uD83C\uDF89', '\uD83D\uDC40'].includes(reaction?.emoji)) return;\n          const current = groups.get(reaction.emoji) || { count: 0, names: [], customerReacted: false };\n          current.count += 1;\n          if (reaction.actorName) current.names.push(reaction.actorName);\n          if (reaction.actorRole === 'customer') current.customerReacted = true;\n          groups.set(reaction.emoji, current);\n        });\n        groups.forEach((group, emoji) => {\n          const button = createElement(\n            'button',\n            `instant-quoter__assistant-reaction${group.customerReacted ? ' is-active' : ''}`,\n            `${emoji}${group.count > 1 ? ` ${group.count}` : ''}`,\n          );\n          button.type = 'button';\n          button.title = group.names.join(', ');\n          button.setAttribute('aria-label', `React ${emoji}`);\n          button.setAttribute('aria-pressed', group.customerReacted ? 'true' : 'false');\n          button.addEventListener('click', () => void toggleLiveSalesReaction(entry.id, emoji));\n          reactions.append(button);\n        });\n        ['\u2764\uFE0F', '\uD83D\uDC4D', '\uD83C\uDF89', '\uD83D\uDC40'].filter((emoji) => !groups.has(emoji)).forEach((emoji) => {\n          const button = createElement('button', 'instant-quoter__assistant-reaction', emoji);\n          button.type = 'button';\n          button.setAttribute('aria-label', `React ${emoji}`);\n          button.setAttribute('aria-pressed', 'false');\n          button.addEventListener('click', () => void toggleLiveSalesReaction(entry.id, emoji));\n          reactions.append(button);\n        });\n        body.append(reactions);\n      }\n      bubble.append(body);\n      return bubble;\n    };\n\n    const liveSalesStatusCopy = {\n      idle: 'We\u2019ll bring your event details and selected services into the conversation.',\n      connecting: 'Finding the on-call EP person\u2026',\n      waiting: 'We pinged the team. Keep this open and someone will join here.',\n      connected: 'Someone from the EP team picked up your conversation. You\u2019re chatting live.',\n      email_fallback: 'The team is away, but this chat is still open. Leave a message and we\u2019ll email them so they can reply.',\n      closed: 'This conversation is wrapped up. Start another whenever you need us.',\n      unavailable: 'Live chat could not open just now. Ask EP instantly or schedule a call and we\u2019ll take it from there.',\n    };\n\n    const participantFirstName = (participant = {}) => {\n      const name = typeof participant.name === 'string' ? participant.name.trim() : '';\n      return name ? name.split(/\\s+/)[0] : 'EP';\n    };\n\n    const liveSalesStatusText = (status) => {\n      if (status !== 'connected' || assistantState.salesParticipants.length === 0) {\n        return liveSalesStatusCopy[status] || liveSalesStatusCopy.waiting;\n      }\n      const names = assistantState.salesParticipants.map(participantFirstName);\n      const readableNames = names.length === 1\n        ? names[0]\n        : `${names.slice(0, -1).join(', ')} and ${names.at(-1)}`;\n      return `${readableNames} ${names.length === 1 ? 'is' : 'are'} here and chatting with you live.`;\n    };\n\n    const renderSalesParticipants = () => {\n      if (!assistantParticipants) return;\n      const visible = assistantState.mode === 'sales' && assistantState.salesParticipants.length > 0;\n      assistantParticipants.hidden = !visible;\n      if (!visible) return;\n      const signature = JSON.stringify(assistantState.salesParticipants);\n      if (assistantParticipantsSignature === signature) return;\n      assistantParticipantsSignature = signature;\n      assistantParticipants.replaceChildren(\n        createElement('span', 'instant-quoter__assistant-participants-label', 'Your EP team'),\n      );\n      assistantState.salesParticipants.forEach((participant) => {\n        const item = createElement('span', 'instant-quoter__assistant-participant');\n        const avatar = participant.imageUrl\n          ? createElement('img', 'instant-quoter__assistant-avatar')\n          : createElement('span', 'instant-quoter__assistant-avatar is-fallback', participantFirstName(participant).charAt(0));\n        if (avatar.tagName === 'IMG') {\n          avatar.src = participant.imageUrl;\n          avatar.alt = participant.name;\n          avatar.loading = 'lazy';\n        } else {\n          avatar.setAttribute('aria-label', participant.name);\n        }\n        item.append(\n          avatar,\n          createElement('span', 'instant-quoter__assistant-participant-name', participantFirstName(participant)),\n        );\n        assistantParticipants.append(item);\n      });\n    };\n\n    const updateLiveSalesPresentation = () => {\n      const status = assistantState.salesStatus || 'idle';\n      const copy = liveSalesStatusText(status);\n      liveSalesStatuses.forEach((element) => {\n        element.textContent = copy;\n      });\n      liveSalesLabels.forEach((element) => {\n        element.textContent = status === 'connected'\n          ? 'Return to live chat'\n          : assistantState.salesConversationId\n            ? 'Open my conversation'\n            : status === 'connecting' ? 'Connecting\u2026' : 'Chat with a real person';\n      });\n      liveSalesStarts.forEach((button) => {\n        button.disabled = status === 'connecting';\n      });\n    };\n\n    const updateAssistantPresentation = () => {\n      const isSales = assistantState.mode === 'sales';\n      if (assistantKicker) assistantKicker.textContent = isSales ? 'Talk with the team' : 'Questions welcome';\n      if (assistantTitle) assistantTitle.textContent = isSales ? 'Chat with EP' : 'Ask EP';\n      if (assistantDisclosure) {\n        assistantDisclosure.textContent = isSales\n          ? liveSalesStatusText(assistantState.salesStatus)\n          : 'AI-powered assistant here to help with Electric Photoland questions. It can explain options, but it won\u2019t calculate your event quote.';\n      }\n      if (assistantInputLabel) {\n        assistantInputLabel.textContent = isSales ? 'Message the EP team' : 'What would you like to know?';\n      }\n      if (assistantInput) {\n        assistantInput.placeholder = isSales ? 'Tell us what you\u2019re deciding between\u2026' : 'Is printing included?';\n        assistantInput.disabled = isSales && !assistantState.salesConversationId;\n      }\n      if (assistantSend) {\n        assistantSend.querySelector('span').textContent = isSales\n          ? assistantState.salesStatus === 'email_fallback' ? 'Send + email' : 'Send'\n          : 'Ask';\n        assistantSend.disabled = isSales && !assistantState.salesConversationId;\n      }\n      if (liveSalesEmailFallback) {\n        const status = assistantState.salesStatus || 'idle';\n        liveSalesEmailFallback.hidden = status !== 'email_fallback' || !isSales;\n      }\n      if (assistantSuggestions) assistantSuggestions.hidden = isSales;\n      if (assistantEmail) assistantEmail.hidden = isSales;\n      if (assistantHandoffs) assistantHandoffs.hidden = isSales;\n      if (assistantTyping) {\n        const staffIsTyping = isSales && assistantState.salesStaffTyping;\n        assistantTyping.hidden = !staffIsTyping;\n        assistantTyping.textContent = staffIsTyping ? 'EP is typing\u2026' : '';\n      }\n      renderSalesParticipants();\n      updateLiveSalesPresentation();\n    };\n\n    const renderAssistantHistory = () => {\n      if (!assistantMessages) return;\n      const nextSignature = JSON.stringify({\n        mode: assistantState.mode,\n        messages: assistantState.messages,\n      });\n      if (assistantHistorySignature === nextSignature) {\n        updateAssistantPresentation();\n        return;\n      }\n      assistantHistorySignature = nextSignature;\n      assistantMessages.replaceChildren();\n      if (assistantState.messages.length === 0) {\n        assistantMessages.append(assistantMessageElement({\n          role: assistantState.mode === 'sales' ? 'system' : 'assistant',\n          content: assistantState.mode === 'sales'\n            ? 'Your quote details are coming with you. Add a message so the team knows what you\u2019re deciding between.'\n            : 'Ask me what\u2019s included, how an experience works, or which option fits the kind of moment you want to make.',\n        }));\n      } else {\n        assistantState.messages.forEach((entry) => {\n          if (!entry || !['customer', 'assistant', 'sales', 'system'].includes(entry.role) || typeof entry.content !== 'string') return;\n          assistantMessages.append(assistantMessageElement(entry));\n        });\n      }\n      assistantMessages.scrollTop = assistantMessages.scrollHeight;\n      if (assistantEmail && assistantState.mode !== 'sales') assistantEmail.disabled = !assistantState.conversationId;\n      updateAssistantPresentation();\n    };\n\n    const addAssistantMessage = (role, content, metadata = {}) => {\n      assistantState.messages.push({\n        role,\n        content: String(content).slice(0, 1500),\n        ...(metadata.id ? { id: metadata.id } : {}),\n        ...(metadata.clientMessageId ? { clientMessageId: metadata.clientMessageId } : {}),\n      });\n      assistantState.messages = assistantState.messages.slice(-30);\n      persistAssistant();\n      renderAssistantHistory();\n    };\n\n    const trackAssistantInteraction = (eventName, properties = {}) => {\n      if (!readAnalyticsConsent().allowed) return;\n      window.dataLayer = window.dataLayer || [];\n      window.dataLayer.push({\n        event: eventName,\n        quote_step: stepDescriptor().id,\n        ...properties,\n      });\n    };\n\n    const assistantContext = () => ({\n      eventClass: selectedEventType()\n        ? selectedEventType() === 'wedding' ? 'wedding' : 'non_wedding'\n        : undefined,\n      serviceCodes: selectedServices().slice(0, 3),\n      quoteStep: stepDescriptor().id,\n    });\n\n    const setAssistantBodyLock = (locked) => {\n      if (locked) {\n        if (assistantBodyOverflow === null) assistantBodyOverflow = document.body.style.overflow;\n        document.body.style.overflow = 'hidden';\n        return;\n      }\n      if (assistantBodyOverflow === null) return;\n      document.body.style.overflow = assistantBodyOverflow;\n      assistantBodyOverflow = null;\n    };\n\n    const syncAssistantViewport = () => {\n      if (!assistantPortal) return;\n      if (!assistantMobileMedia.matches || assistantDialog?.hidden) {\n        assistantPortal.style.removeProperty('--quote-assistant-viewport-height');\n        assistantPortal.style.removeProperty('--quote-assistant-viewport-offset-top');\n        return;\n      }\n      const visualViewport = window.visualViewport;\n      const viewportHeight = visualViewport?.height || window.innerHeight;\n      const viewportOffsetTop = visualViewport?.offsetTop || 0;\n      assistantPortal.style.setProperty(\n        '--quote-assistant-viewport-height',\n        `${Math.round(viewportHeight)}px`,\n      );\n      assistantPortal.style.setProperty(\n        '--quote-assistant-viewport-offset-top',\n        `${Math.round(viewportOffsetTop)}px`,\n      );\n      window.requestAnimationFrame(() => {\n        if (assistantMessages) assistantMessages.scrollTop = assistantMessages.scrollHeight;\n      });\n    };\n\n    const syncAssistantModality = () => {\n      if (!assistantDialog) return;\n      const isMobile = assistantMobileMedia.matches;\n      assistantDialog.setAttribute('aria-modal', isMobile ? 'true' : 'false');\n      setAssistantBodyLock(isMobile && !assistantDialog.hidden);\n      syncAssistantViewport();\n    };\n\n    const openAssistant = (mode) => {\n      if (!assistantDialog) return;\n      if (mode === 'assistant' || mode === 'sales') assistantState.mode = mode;\n      persistAssistant();\n      assistantReturnFocus = document.activeElement;\n      assistantDialog.hidden = false;\n      assistantPortal?.classList.add('is-open');\n      assistantFab?.setAttribute('aria-expanded', 'true');\n      syncAssistantModality();\n      renderAssistantHistory();\n      if (!assistantInput?.disabled) assistantInput?.focus();\n      window.requestAnimationFrame(syncAssistantViewport);\n      void ensureQuoteSession().catch(() => {\n        assistantStatus.textContent = 'The assistant is taking a minute to connect. You can still keep building your quote.';\n      });\n    };\n\n    const closeAssistant = () => {\n      if (!assistantDialog) return;\n      assistantDialog.hidden = true;\n      assistantPortal?.classList.remove('is-open');\n      assistantFab?.setAttribute('aria-expanded', 'false');\n      setAssistantBodyLock(false);\n      syncAssistantViewport();\n      if (assistantState.mode === 'sales') {\n        if (liveSalesTypingStopTimer !== null) window.clearTimeout(liveSalesTypingStopTimer);\n        liveSalesTypingLastSentAt = 0;\n        void sendLiveSalesTyping(false, { keepalive: true });\n      }\n      assistantReturnFocus?.focus?.();\n    };\n\n    const submitAssistantQuestion = async (question) => {\n      const normalizedQuestion = question.trim();\n      if (normalizedQuestion.length < 2) return;\n      const session = await ensureQuoteSession();\n      const consent = readAnalyticsConsent();\n      addAssistantMessage('customer', normalizedQuestion);\n      assistantStatus.textContent = '';\n      assistantSend.disabled = true;\n      assistantSend.querySelector('span').textContent = 'Thinking\u2026';\n      trackAssistantInteraction('assistant_question_submitted', {\n        service_count: selectedServices().length,\n      });\n\n      try {\n        const response = await fetch(\n          `${sessionEndpoint}/${encodeURIComponent(session.token)}/assistant/messages`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n            },\n            body: JSON.stringify({\n              question: normalizedQuestion,\n              ...(assistantState.conversationId\n                ? { conversationId: assistantState.conversationId }\n                : {}),\n              context: assistantContext(),\n              ...(consent.allowed\n                ? { consent: { analytics: true, capturedAt: consent.capturedAt } }\n                : {}),\n            }),\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.answer || !payload.conversationId) {\n          throw new Error('Ask that one again\u2014or send it to our team and we\u2019ll pick it up.');\n        }\n        assistantState.conversationId = payload.conversationId;\n        addAssistantMessage('assistant', payload.answer);\n        assistantEmail.disabled = false;\n        trackAssistantInteraction('assistant_answer_received', {\n          answer_mode: payload.answerMode,\n          action: payload.action,\n        });\n      } catch (error) {\n        assistantStatus.textContent = error.message || 'The assistant could not answer just now.';\n      } finally {\n        assistantSend.disabled = false;\n        assistantSend.querySelector('span').textContent = 'Ask';\n      }\n    };\n\n    const submitAssistantHandoff = async (handoffType, { keepalive = false } = {}) => {\n      if (!assistantState.conversationId) return false;\n      const session = await ensureQuoteSession();\n      const response = await fetch(\n        `${sessionEndpoint}/${encodeURIComponent(session.token)}/assistant/handoffs`,\n        {\n          method: 'POST',\n          headers: {\n            authorization: `Bearer ${activeAccess.token}`,\n            'content-type': 'application/json',\n          },\n          body: JSON.stringify({\n            conversationId: assistantState.conversationId,\n            handoffType,\n          }),\n          keepalive,\n        },\n      );\n      const payload = await response.json().catch(() => ({}));\n      if (!response.ok) {\n        throw new Error(\n          payload.code === 'contact_required'\n            ? 'Save your full name and email in the quote first, then send this to our team.'\n            : 'We couldn\u2019t send that handoff yet. Try again in a moment.',\n        );\n      }\n      return true;\n    };\n\n    const salesConversationEndpoint = (sessionToken, conversationId = '') => (\n      `${sessionEndpoint}/${encodeURIComponent(sessionToken)}/sales/conversations${\n        conversationId ? `/${encodeURIComponent(conversationId)}` : ''\n      }`\n    );\n\n    const liveSalesHeaders = (additional = {}) => ({\n      authorization: `Bearer ${activeAccess.token}`,\n      'x-ep-sales-chat-resume-key': assistantState.salesStartIdempotencyKey,\n      ...additional,\n    });\n\n    const normalizeLiveSalesStatus = (payload = {}) => {\n      if (payload.availability === 'offline' || payload.status === 'offline') return 'email_fallback';\n      return ['waiting', 'connected', 'email_fallback', 'closed'].includes(payload.status)\n        ? payload.status\n        : 'waiting';\n    };\n\n    const normalizeSalesParticipants = (participants = []) => {\n      if (!Array.isArray(participants)) return [];\n      const seen = new Set();\n      return participants.flatMap((participant) => {\n        if (\n          !participant ||\n          typeof participant.userId !== 'string' ||\n          typeof participant.name !== 'string' ||\n          seen.has(participant.userId)\n        ) return [];\n        seen.add(participant.userId);\n        return [{\n          userId: participant.userId,\n          name: participant.name.trim() || 'EP Team',\n          imageUrl: typeof participant.imageUrl === 'string' ? participant.imageUrl : null,\n          joinedAt: typeof participant.joinedAt === 'string' ? participant.joinedAt : null,\n        }];\n      }).slice(0, 12);\n    };\n\n    const mergeLiveSalesMessages = (messages = []) => {\n      if (!Array.isArray(messages)) return;\n      messages.forEach((entry) => {\n        const content = typeof entry?.content === 'string'\n          ? entry.content\n          : typeof entry?.message === 'string' ? entry.message : '';\n        const messageId = typeof entry?.id === 'string' ? entry.id : null;\n        const clientMessageId = typeof entry?.clientMessageId === 'string' ? entry.clientMessageId : null;\n        const attachments = Array.isArray(entry?.attachments)\n          ? entry.attachments.filter((attachment) => (\n            attachment?.url && ['image', 'video'].includes(attachment.type)\n          )).slice(0, 4)\n          : [];\n        if (!content.trim() && attachments.length === 0) return;\n        const sender = entry.role || entry.sender || entry.authorRole;\n        const role = sender === 'customer'\n          ? 'customer'\n          : ['sales', 'agent', 'staff'].includes(sender) ? 'sales' : 'system';\n        const normalized = {\n          role,\n          content: content.slice(0, 1500),\n          ...(messageId ? { id: messageId } : {}),\n          ...(clientMessageId ? { clientMessageId } : {}),\n          author: entry?.author && typeof entry.author === 'object'\n            ? {\n                userId: entry.author.userId,\n                name: entry.author.name || 'EP Team',\n                imageUrl: entry.author.imageUrl || null,\n              }\n            : null,\n          attachments,\n          reactions: Array.isArray(entry?.reactions) ? entry.reactions.slice(0, 40) : [],\n          ...(typeof entry?.createdAt === 'string' ? { createdAt: entry.createdAt } : {}),\n        };\n        const existing = assistantState.messages.find((message) => (\n          (messageId && message.id === messageId) ||\n          (clientMessageId && message.clientMessageId === clientMessageId)\n        ));\n        if (existing) Object.assign(existing, normalized);\n        else assistantState.messages.push(normalized);\n      });\n      assistantState.messages = assistantState.messages.slice(-30);\n    };\n\n    const toggleLiveSalesReaction = async (messageId, emoji) => {\n      if (\n        !assistantState.salesConversationId ||\n        !activeAccess?.token ||\n        !['\u2764\uFE0F', '\uD83D\uDC4D', '\uD83C\uDF89', '\uD83D\uDC40'].includes(emoji)\n      ) return;\n      try {\n        const session = await ensureQuoteSession();\n        const response = await fetch(\n          `${salesConversationEndpoint(session.token, assistantState.salesConversationId)}/messages/${encodeURIComponent(messageId)}/reactions`,\n          {\n            method: 'PUT',\n            headers: liveSalesHeaders({\n              'content-type': 'application/json',\n            }),\n            body: JSON.stringify({ emoji }),\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok) throw new Error(payload.error || 'That reaction did not save.');\n        applyLiveSalesPayload(payload);\n      } catch (error) {\n        assistantStatus.textContent = error.message || 'That reaction did not save.';\n      }\n    };\n\n    const clearLiveSalesFallbackTimer = () => {\n      if (liveSalesFallbackTimer !== null) window.clearTimeout(liveSalesFallbackTimer);\n      liveSalesFallbackTimer = null;\n    };\n\n    const scheduleLiveSalesFallback = () => {\n      clearLiveSalesFallbackTimer();\n      if (!salesChatEnabled || !['connecting', 'waiting'].includes(assistantState.salesStatus)) return;\n      const fallbackAt = Date.parse(assistantState.salesFallbackAt || '');\n      if (!Number.isFinite(fallbackAt)) return;\n      liveSalesFallbackTimer = window.setTimeout(() => {\n        if (!['connecting', 'waiting'].includes(assistantState.salesStatus)) return;\n        assistantState.salesStatus = 'email_fallback';\n        persistAssistant();\n        renderAssistantHistory();\n        void pollLiveSalesConversation();\n      }, Math.max(0, fallbackAt - Date.now()));\n    };\n\n    const scheduleLiveSalesPoll = (delayMs = 3000) => {\n      if (liveSalesPollTimer !== null) window.clearTimeout(liveSalesPollTimer);\n      liveSalesPollTimer = null;\n      if (\n        !salesChatEnabled\n        || !assistantState.salesConversationId\n        || ['closed', 'unavailable'].includes(assistantState.salesStatus)\n      ) return;\n      const safeDelay = Math.max(1500, Math.min(Number(delayMs) || 3000, 10000));\n      liveSalesPollTimer = window.setTimeout(() => void pollLiveSalesConversation(), safeDelay);\n    };\n\n    const applyLiveSalesPayload = (payload = {}) => {\n      const joinedAt = typeof payload.acceptedAt === 'string' ? payload.acceptedAt : null;\n      const agentJoined = payload.agentJoined === true || Boolean(joinedAt);\n      const previousParticipantIds = new Set(\n        assistantState.salesParticipants.map((participant) => participant.userId),\n      );\n      const participants = normalizeSalesParticipants(payload.participants);\n      if (participants.length > 0) {\n        participants.forEach((participant) => {\n          const joinedMessageId = `sales-joined:${participant.userId}`;\n          if (\n            !previousParticipantIds.has(participant.userId) &&\n            !assistantState.messages.some((entry) => entry.id === joinedMessageId)\n          ) {\n            assistantState.messages.push({\n              id: joinedMessageId,\n              role: 'system',\n              content: `${participantFirstName(participant)} joined the conversation.`,\n            });\n          }\n        });\n        assistantState.salesParticipants = participants;\n        assistantState.salesAgentJoinedAt ||= participants[0].joinedAt || joinedAt || new Date().toISOString();\n      } else if (agentJoined && !assistantState.salesAgentJoinedAt) {\n        assistantState.salesAgentJoinedAt = joinedAt || new Date().toISOString();\n        const joinedMessageId = `sales-joined:${assistantState.salesAgentJoinedAt}`;\n        if (!assistantState.messages.some((entry) => entry.id === joinedMessageId)) {\n          assistantState.messages.push({\n            id: joinedMessageId,\n            role: 'system',\n            content: 'Someone from the EP team joined the conversation.',\n          });\n        }\n      }\n      if (typeof payload.conversationId === 'string') assistantState.salesConversationId = payload.conversationId;\n      if (typeof payload.cursor === 'string') assistantState.salesCursor = payload.cursor;\n      if (typeof payload.fallbackAt === 'string') assistantState.salesFallbackAt = payload.fallbackAt;\n      assistantState.salesStatus = normalizeLiveSalesStatus(payload);\n      assistantState.salesStaffTyping = payload.typing?.staff === true;\n      if (liveSalesRemoteTypingTimer !== null) {\n        window.clearTimeout(liveSalesRemoteTypingTimer);\n        liveSalesRemoteTypingTimer = null;\n      }\n      const staffTypingUntil = Date.parse(payload.typing?.staffUntil || '');\n      if (assistantState.salesStaffTyping && Number.isFinite(staffTypingUntil)) {\n        liveSalesRemoteTypingTimer = window.setTimeout(() => {\n          liveSalesRemoteTypingTimer = null;\n          assistantState.salesStaffTyping = false;\n          updateAssistantPresentation();\n        }, Math.max(0, staffTypingUntil - Date.now()));\n      }\n      mergeLiveSalesMessages(payload.messages);\n      persistAssistant();\n      renderAssistantHistory();\n      scheduleLiveSalesFallback();\n      scheduleLiveSalesPoll(payload.pollAfterMs);\n    };\n\n    const pollLiveSalesConversation = async () => {\n      if (\n        !salesChatEnabled\n        || liveSalesPollInFlight\n        || !assistantState.salesConversationId\n        || !activeAccess?.token\n      ) return;\n      liveSalesPollInFlight = true;\n      try {\n        const session = await ensureQuoteSession();\n        const endpoint = new URL(\n          salesConversationEndpoint(session.token, assistantState.salesConversationId),\n          window.location.origin,\n        );\n        if (assistantState.salesCursor) endpoint.searchParams.set('after', assistantState.salesCursor);\n        const response = await fetch(endpoint.toString(), {\n          headers: liveSalesHeaders(),\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok) throw new Error('Live sales updates are temporarily unavailable.');\n        applyLiveSalesPayload(payload);\n      } catch {\n        scheduleLiveSalesPoll(5000);\n      } finally {\n        liveSalesPollInFlight = false;\n      }\n    };\n\n    const startLiveSalesChat = async () => {\n      if (!salesChatEnabled) return;\n      assistantState.mode = 'sales';\n      if (assistantState.salesConversationId) {\n        persistAssistant();\n        openAssistant('sales');\n        scheduleLiveSalesPoll(0);\n        return;\n      }\n\n      assistantState.salesStatus = 'connecting';\n      assistantState.salesRequestedAt = new Date().toISOString();\n      assistantState.salesFallbackAt = new Date(Date.now() + 180000).toISOString();\n      persistAssistant();\n      openAssistant('sales');\n      updateLiveSalesPresentation();\n      trackAssistantInteraction('live_sales_help_requested', {\n        service_count: selectedServices().length,\n      });\n\n      try {\n        const session = await ensureQuoteSession();\n        const response = await fetch(salesConversationEndpoint(session.token), {\n          method: 'POST',\n          headers: {\n            authorization: `Bearer ${activeAccess.token}`,\n            'content-type': 'application/json',\n            'idempotency-key': assistantState.salesStartIdempotencyKey,\n          },\n          body: JSON.stringify({\n            ...(assistantState.conversationId\n              ? { assistantConversationId: assistantState.conversationId }\n              : {}),\n            context: assistantContext(),\n            fallbackAfterSeconds: 180,\n          }),\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.conversationId) {\n          throw new Error(\n            payload.code === 'contact_required'\n              ? 'Save your contact details in the quote first, then try the chat again.'\n              : 'Live chat could not open just now.',\n          );\n        }\n        applyLiveSalesPayload(payload);\n        trackAssistantInteraction('live_sales_help_queued', {\n          availability: payload.availability,\n          status: assistantState.salesStatus,\n        });\n      } catch (error) {\n        assistantState.salesStatus = 'unavailable';\n        persistAssistant();\n        renderAssistantHistory();\n        assistantStatus.textContent = error.message;\n      }\n    };\n\n    const sendLiveSalesTyping = async (isTyping, { keepalive = false } = {}) => {\n      if (!assistantState.salesConversationId || !activeAccess?.token) return;\n      try {\n        const session = await ensureQuoteSession();\n        await fetch(\n          `${salesConversationEndpoint(session.token, assistantState.salesConversationId)}/typing`,\n          {\n            method: 'PUT',\n            headers: liveSalesHeaders({\n              'content-type': 'application/json',\n            }),\n            body: JSON.stringify({ isTyping }),\n            keepalive,\n          },\n        );\n      } catch {\n        // Typing is best effort; sending the message remains authoritative.\n      }\n    };\n\n    const updateLiveSalesTypingFromDraft = () => {\n      if (assistantState.mode !== 'sales' || !assistantState.salesConversationId) return;\n      if (liveSalesTypingStopTimer !== null) window.clearTimeout(liveSalesTypingStopTimer);\n      if (!assistantInput.value.trim()) {\n        liveSalesTypingLastSentAt = 0;\n        void sendLiveSalesTyping(false);\n        return;\n      }\n      const now = Date.now();\n      if (now - liveSalesTypingLastSentAt >= 3000) {\n        liveSalesTypingLastSentAt = now;\n        void sendLiveSalesTyping(true);\n      }\n      liveSalesTypingStopTimer = window.setTimeout(() => {\n        liveSalesTypingLastSentAt = 0;\n        void sendLiveSalesTyping(false);\n      }, 5000);\n    };\n\n    const submitLiveSalesMessage = async (messageText) => {\n      const normalizedMessage = messageText.trim();\n      if (\n        !salesChatEnabled\n        || normalizedMessage.length < 2\n        || !assistantState.salesConversationId\n      ) return;\n      const clientMessageId = randomId();\n      addAssistantMessage('customer', normalizedMessage, { clientMessageId });\n      assistantStatus.textContent = assistantState.salesStatus === 'email_fallback'\n        ? 'Saving your message and emailing the team\u2026'\n        : '';\n      assistantSend.disabled = true;\n      liveSalesTypingLastSentAt = 0;\n      void sendLiveSalesTyping(false);\n      assistantSend.querySelector('span').textContent = 'Sending\u2026';\n\n      try {\n        const session = await ensureQuoteSession();\n        const response = await fetch(\n          `${salesConversationEndpoint(session.token, assistantState.salesConversationId)}/messages`,\n          {\n            method: 'POST',\n            headers: liveSalesHeaders({\n              'content-type': 'application/json',\n              'idempotency-key': clientMessageId,\n            }),\n            body: JSON.stringify({ message: normalizedMessage, clientMessageId }),\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok) throw new Error('That message did not send. Your text is still here\u2014try again.');\n        applyLiveSalesPayload(payload);\n        assistantStatus.textContent = assistantState.salesStatus === 'email_fallback'\n          ? 'Message saved. We emailed the team, and their reply will appear here.'\n          : 'Message sent.';\n        trackAssistantInteraction('live_sales_message_sent', {\n          delivery_mode: assistantState.salesStatus === 'email_fallback' ? 'email' : 'chat',\n        });\n      } catch (error) {\n        assistantStatus.textContent = error.message;\n      } finally {\n        updateAssistantPresentation();\n      }\n    };\n\n    const updateServiceAvailability = () => {\n      const isWedding = selectedEventType() === 'wedding';\n      const dropOffInput = serviceInputs().find((input) => input.value === 'drop_off');\n      if (dropOffInput) {\n        dropOffInput.disabled = isWedding;\n        if (isWedding) dropOffInput.checked = false;\n        dropOffInput.closest('[data-service-card]')?.classList.toggle('is-unavailable', isWedding);\n      }\n      const count = selectedServices().length;\n      const notes = [];\n      if (count > 0) notes.push(`${count} experience${count === 1 ? '' : 's'} selected.`);\n      if (count === 2) notes.push('Your eligible experience charges get the 10% two-service discount.');\n      if (count > 2) notes.push('This lineup gets a useful estimate and a custom planning call.');\n      if (isWedding) notes.push('Drop Off takes weddings off; attended experiences include the extra polish.');\n      if (Number.isFinite(validatedEventLocation?.travelMiles)) {\n        notes.push('Showing experiences offered at this location.');\n      }\n      serviceSelectionNote.textContent = notes.join(' ');\n    };\n\n    // A package deep link pre-answers event type (3), experiences (5), and\n    // configuration (6); the guest walks 1 \u2192 2 \u2192 4 \u2192 7.\n    const packageSkippedSteps = new Set([3, 5, 6]);\n\n    const packageDateNote = () => {\n      const start = activePackage.eventDateStart;\n      const end = activePackage.eventDateEnd;\n      if (!start && !end) return activePackage.priceNote || '';\n      const formatDate = (value) => new Intl.DateTimeFormat('en-US', {\n        month: 'long',\n        day: 'numeric',\n        year: 'numeric',\n        timeZone: 'UTC',\n      }).format(new Date(`${value}T12:00:00Z`));\n      const windowLabel = start && end\n        ? `events ${formatDate(start)} \u2013 ${formatDate(end)}`\n        : start\n          ? `events from ${formatDate(start)}`\n          : `events through ${formatDate(end)}`;\n      const chosenDate = dateInput?.value || '';\n      if (chosenDate && !model.packageEventDateEligible(activePackage, chosenDate)) {\n        return `Heads up: this package price covers ${windowLabel}. Other dates get regular pricing on the quote page.`;\n      }\n      return [activePackage.priceNote, `Package pricing covers ${windowLabel}.`]\n        .filter(Boolean)\n        .join(' ');\n    };\n\n    const applyPackagePresentation = () => {\n      progress.forEach((item) => {\n        const owner = item.closest('li') || item;\n        owner.style.display = activePackage\n          && packageSkippedSteps.has(Number(item.dataset.quoteProgress))\n          ? 'none'\n          : '';\n      });\n      progress[0]?.closest('ol')?.classList.toggle('is-package', Boolean(activePackage));\n      if (!activePackage) {\n        packageBanner?.remove();\n        packageBanner = null;\n        return;\n      }\n      if (!packageBanner) {\n        packageBanner = createElement('aside', 'instant-quoter__package-banner');\n        packageBanner.append(\n          createElement('strong', 'instant-quoter__package-banner-name'),\n          createElement('span', 'instant-quoter__package-banner-price'),\n          createElement('small', 'instant-quoter__package-banner-note'),\n        );\n        workspace.prepend(packageBanner);\n      }\n      packageBanner.querySelector('strong').textContent = activePackage.name;\n      packageBanner.querySelector('span').textContent = `${model.formatMoney(activePackage.flatPriceCents)} package`;\n      packageBanner.querySelector('small').textContent = packageDateNote();\n    };\n\n    const renderPackageFallbackNotice = () => {\n      const notice = createElement(\n        'aside',\n        'instant-quoter__package-banner instant-quoter__package-banner--ended',\n      );\n      notice.append(\n        createElement('strong', 'instant-quoter__package-banner-name', 'That package offer has ended'),\n        createElement('small', 'instant-quoter__package-banner-note', 'No problem \u2014 build your own quote below and we\u2019ll price it live.'),\n      );\n      workspace.prepend(notice);\n    };\n\n    // A dead referral link (unknown code or deactivated partner) boots the\n    // standard funnel with a notice instead of a dead end.\n    const renderReferralFallbackNotice = () => {\n      const notice = createElement(\n        'aside',\n        'instant-quoter__package-banner instant-quoter__package-banner--ended',\n      );\n      notice.setAttribute('data-quote-referral-fallback', '');\n      notice.append(\n        createElement('strong', 'instant-quoter__package-banner-name', 'That referral offer isn\u2019t available'),\n        createElement('small', 'instant-quoter__package-banner-note', 'Build your own quote below.'),\n      );\n      workspace.prepend(notice);\n    };\n\n    const renderReferralBanner = () => {\n      if (!referralBanner) {\n        referralBanner = createElement(\n          'aside',\n          'instant-quoter__package-banner instant-quoter__referral-banner',\n        );\n        referralBanner.setAttribute('data-quote-referral-banner', '');\n        referralBanner.append(\n          createElement('strong', 'instant-quoter__package-banner-name'),\n          createElement('span', 'instant-quoter__package-banner-price'),\n          createElement('small', 'instant-quoter__package-banner-note'),\n        );\n        workspace.prepend(referralBanner);\n      }\n      const badge = model.referralDealBadge(activeReferral);\n      const isCommunityPartner = activeReferral.partnerType === 'nonprofit';\n      referralBanner.querySelector('strong').textContent = isCommunityPartner\n        ? `${activeReferral.name} \u2014 Community Partner`\n        : `${activeReferral.name} guest offer`;\n      const badgeElement = referralBanner.querySelector('span');\n      badgeElement.textContent = badge || '';\n      badgeElement.hidden = !badge;\n      const pickedLocation = activeReferral.locations.find(\n        (location) => location.id === validatedEventLocation?.referralLocationId,\n      );\n      referralBanner.querySelector('small').textContent = isCommunityPartner\n        ? model.referralTierNote(activeReferral)\n        : model.referralDealLost(activeReferral, validatedEventLocation)\n          ? `Booking at a different venue \u2014 the ${activeReferral.name} offer won\u2019t apply.`\n          : pickedLocation\n            ? `Partner pricing applies at ${pickedLocation.label}.`\n            : `Partner pricing applies when your event is at a ${activeReferral.name} venue.`;\n    };\n\n    /**\n     * Picking one of the partner's venues skips the map lookup: the server\n     * answers instantly from its stored locations and applies the deal.\n     * A 422 `referral_location_not_found` means the venue was deactivated\n     * mid-session \u2014 drop the dead option and free the address input.\n     */\n    const selectReferralLocation = async (location) => {\n      setLocationStatus('Confirming the venue\u2026', 'checking');\n      setMessage();\n      try {\n        const session = await ensureQuoteSession();\n        const response = await fetch(\n          `${sessionEndpoint}/${encodeURIComponent(session.token)}/location`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n            },\n            body: JSON.stringify({ referralLocationId: location.id }),\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.location?.formattedAddress) {\n          if (response.status === 422 && payload.code === 'referral_location_not_found') {\n            activeReferral = {\n              ...activeReferral,\n              locations: activeReferral.locations.filter(\n                (candidate) => candidate.id !== location.id,\n              ),\n            };\n            const stored = readQuoteSession();\n            if (stored) writeQuoteSession({ ...stored, referral: activeReferral });\n            referralCustomAddressMode = true;\n            applyReferralPresentation();\n            throw new Error('That venue is no longer available. Pick another\u2014or type your event address.');\n          }\n          if (response.status === 401 || response.status === 410) {\n            removeSessionValue(quoteSessionStorageKey);\n            throw new Error('Your quote session expired. Refresh the page and try again.');\n          }\n          throw new Error('We couldn\u2019t confirm that venue right now. Try again\u2014or type your event address.');\n        }\n\n        referralCustomAddressMode = false;\n        validatedEventLocation = {\n          input: payload.location.formattedAddress,\n          ...payload.location,\n          ...(payload.referral?.dealApplied === true\n            ? { referralLocationId: payload.referral.locationId || location.id }\n            : {}),\n        };\n        if (locationInput) locationInput.value = payload.location.formattedAddress;\n        applyCatalogPresentation();\n        updateServiceAvailability();\n        applyReferralPresentation();\n        persistJourney();\n        setLocationStatus(`Found it \u00B7 ${payload.location.formattedAddress}`, 'success');\n      } catch (error) {\n        setLocationStatus(\n          error.name === 'AbortError'\n            ? 'That took too long. Give the venue another tap.'\n            : error.message,\n          'error',\n        );\n      }\n    };\n\n    const renderReferralLocationPicker = () => {\n      const stepOne = steps.find((step) => Number(step.dataset.quoteStep) === 1);\n      const fieldGrid = stepOne?.querySelector('.instant-quoter__field-grid');\n      const locationField = locationInput?.closest('.instant-quoter__field');\n      if (!stepOne || !fieldGrid || !locationField) return;\n\n      if (activeReferral.locations.length === 0) {\n        referralPicker?.remove();\n        referralPicker = null;\n        locationField.hidden = false;\n        if (locationInput) locationInput.required = true;\n        return;\n      }\n\n      if (!referralPicker) {\n        referralPicker = createElement('fieldset', 'instant-quoter__referral-locations');\n        referralPicker.setAttribute('data-quote-referral-locations', '');\n        stepOne.insertBefore(referralPicker, fieldGrid);\n      }\n      // The list is small and selection state lives outside the DOM, so a\n      // full rebuild keeps every render path identical.\n      referralPicker.replaceChildren(\n        createElement('legend', '', `Pick your ${activeReferral.name} venue`),\n      );\n      activeReferral.locations.forEach((location) => {\n        const option = createElement('button', 'instant-quoter__referral-location');\n        option.type = 'button';\n        option.setAttribute('data-quote-referral-location', location.id);\n        option.setAttribute(\n          'aria-pressed',\n          validatedEventLocation?.referralLocationId === location.id ? 'true' : 'false',\n        );\n        const copy = createElement('span');\n        copy.append(\n          createElement('strong', '', location.label),\n          createElement('small', '', location.formattedAddress),\n        );\n        option.append(copy);\n        option.addEventListener('click', () => void selectReferralLocation(location));\n        referralPicker.append(option);\n      });\n      const elsewhere = createElement(\n        'button',\n        'instant-quoter__referral-location instant-quoter__referral-location--custom',\n      );\n      elsewhere.type = 'button';\n      elsewhere.setAttribute('data-quote-referral-somewhere-else', '');\n      elsewhere.setAttribute('aria-pressed', referralCustomAddressMode ? 'true' : 'false');\n      const elsewhereCopy = createElement('span');\n      elsewhereCopy.append(\n        createElement('strong', '', 'Somewhere else'),\n        createElement('small', '', 'Type any venue or address \u2014 standard pricing applies there.'),\n      );\n      elsewhere.append(elsewhereCopy);\n      elsewhere.addEventListener('click', () => {\n        referralCustomAddressMode = true;\n        applyReferralPresentation();\n        locationInput?.focus();\n      });\n      referralPicker.append(elsewhere);\n\n      // The free-text input stays tucked away until the guest asks for it (or\n      // already priced a custom address); `required` follows visibility so a\n      // hidden empty input can never block the form.\n      const hideAddressInput = !referralCustomAddressMode\n        && !model.referralDealLost(activeReferral, validatedEventLocation);\n      locationField.hidden = hideAddressInput;\n      if (locationInput) locationInput.required = !hideAddressInput;\n    };\n\n    const applyReferralPresentation = () => {\n      if (!activeReferral) {\n        referralBanner?.remove();\n        referralBanner = null;\n        referralPicker?.remove();\n        referralPicker = null;\n        const locationField = locationInput?.closest('.instant-quoter__field');\n        if (locationField) locationField.hidden = false;\n        if (locationInput) locationInput.required = true;\n        return;\n      }\n      renderReferralBanner();\n      renderReferralLocationPicker();\n    };\n\n    const showStep = (number, interactionSource = 'next') => {\n      currentStep = Math.max(1, Math.min(number, steps.length));\n      if (currentStep === 2) renderValidatedAddressConfirmation();\n      if (currentStep === 5) updateServiceAvailability();\n      steps.forEach((step) => {\n        const isCurrent = Number(step.dataset.quoteStep) === currentStep;\n        step.hidden = !isCurrent;\n        if (isCurrent) {\n          requestAnimationFrame(() => {\n            step.querySelector('[data-quote-focus], input:not([disabled]), select:not([disabled]), button:not([disabled])')?.focus();\n          });\n        }\n      });\n      progress.forEach((item) => {\n        const itemStep = Number(item.dataset.quoteProgress);\n        item.toggleAttribute('aria-current', itemStep === currentStep);\n        if (itemStep === currentStep) item.setAttribute('aria-current', 'step');\n        item.classList.toggle('is-complete', itemStep < currentStep);\n      });\n      setMessage();\n      stepEnteredAt = Date.now();\n      persistJourney();\n      trackStepEvent('quote_step_viewed', currentStep, { interactionSource });\n    };\n\n    const displayMode = (mode) => {\n      modeStatus.hidden = mode === 'checkout';\n      modeStatus.textContent = mode === 'checkout' ? '' : 'Preview mode \u00B7 payments are off';\n    };\n\n    const formatDueDate = (value) => {\n      if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return value || '';\n      return new Intl.DateTimeFormat('en-US', {\n        month: 'long',\n        day: 'numeric',\n        year: 'numeric',\n        timeZone: 'UTC',\n      }).format(new Date(`${value}T12:00:00Z`));\n    };\n\n    const isCents = (value) => Number.isSafeInteger(value) && value >= 0;\n\n    const renderPaymentSchedule = (rows = []) => {\n      quoteRetainer.replaceChildren();\n      quoteRetainer.classList.toggle('has-rows', rows.length > 0);\n      rows.forEach(({ amount, label, emphasis }) => {\n        const row = createElement('span', 'instant-quoter__payment-row');\n        row.classList.toggle('is-due-today', emphasis === 'due-today');\n        row.append(\n          createElement('small', '', label),\n          createElement('strong', '', amount),\n        );\n        quoteRetainer.append(row);\n      });\n    };\n\n    const applyHandoffPresentation = (handoff) => {\n      // A fully discounted ($0) quote books without Shopify: nothing to pay,\n      // no secure checkout \u2014 though the agreement still needs signing.\n      const freeBooking = handoff?.freeCheckout === true;\n      // A Community Partner client chose the invoice over card checkout:\n      // nothing is paid on this page, the invoice arrives by email.\n      const invoicePath = handoff?.invoicePath === true;\n      const hasShopifyTotal = handoff?.taxStatus === 'shopify_calculated'\n        && isCents(handoff.grandTotalCents);\n      if (hasShopifyTotal) {\n        quoteTotalLabel.textContent = 'Total including sales tax';\n        quoteTotal.textContent = model.formatMoney(handoff.grandTotalCents);\n        quoteTotalNote.textContent = freeBooking\n          ? 'Your discount covers the full price \u2014 there is nothing to pay. Final availability still comes after venue verification.'\n          : invoicePath\n            ? 'Travel and sales tax are included using your event address. Everything is billed on the invoice we email \u2014 nothing is paid on this page. Final availability still comes after venue verification.'\n            : 'Travel and sales tax are included using your event address. Billing details are entered separately at secure checkout. Final availability still comes after venue verification.';\n      }\n\n      if (invoicePath && isCents(handoff.invoiceFirstAmountCents)) {\n        const rows = [{\n          amount: model.formatMoney(handoff.invoiceFirstAmountCents),\n          label: handoff.paymentKind === 'retainer'\n            ? 'First invoice \u2014 due on receipt'\n            : 'Invoiced in full \u2014 due on receipt',\n          emphasis: 'due-today',\n        }];\n        if (handoff.paymentKind === 'retainer' && isCents(handoff.invoiceBalanceAmountCents)) {\n          rows.push({\n            amount: model.formatMoney(handoff.invoiceBalanceAmountCents),\n            label: handoff.balanceDueDate\n              ? `Balance invoiced separately \u2014 due ${formatDueDate(handoff.balanceDueDate)}`\n              : 'Balance invoiced separately, closer to your event',\n          });\n        }\n        renderPaymentSchedule(rows);\n      } else if (isCents(handoff?.amountDueNowCents)) {\n        const dueNow = model.formatMoney(handoff.amountDueNowCents);\n        if (handoff.paymentKind === 'retainer' && isCents(handoff.balanceCents)) {\n          const balance = model.formatMoney(handoff.balanceCents);\n          const dueDate = formatDueDate(handoff.balanceDueDate);\n          renderPaymentSchedule([\n            {\n              amount: dueNow,\n              label: handoff.status === 'checkout_ready'\n                ? 'Retainer due today'\n                : 'Estimated retainer due today',\n              emphasis: 'due-today',\n            },\n            {\n              amount: balance,\n              label: handoff.status === 'checkout_ready'\n                ? `Remaining balance due ${dueDate}`\n                : `Estimated remaining balance due ${dueDate}`,\n            },\n          ]);\n        } else {\n          renderPaymentSchedule([{\n            amount: dueNow,\n            label: freeBooking\n              ? 'Nothing to pay \u2014 fully discounted'\n              : handoff.status === 'checkout_ready'\n                ? 'Full payment due today'\n                : 'Estimated full payment',\n            emphasis: handoff.status === 'checkout_ready' ? 'due-today' : undefined,\n          }]);\n        }\n      }\n\n      if (handoff?.status === 'preview_ready') {\n        if (activeAccess?.mode === 'checkout') {\n          quoteActionNote.textContent = 'Sales tax is ready. Continue when you\u2019re ready to create the secure checkout.';\n          quoteActionButton.querySelector('span').textContent = 'Continue to secure checkout';\n          quoteActionButton.disabled = false;\n          return null;\n        }\n        quoteActionNote.textContent = handoff.taxStatus === 'shopify_calculated'\n          ? 'Preflight passed. Sales tax is included above; payments remain off in preview mode.'\n          : 'Preflight passed. Payments remain off in preview mode.';\n        quoteActionButton.querySelector('span').textContent = 'Preflight passed';\n        quoteActionButton.disabled = true;\n        return null;\n      }\n\n      if (handoff?.status === 'sales_follow_up_requested') {\n        quoteActionNote.textContent = 'Follow-up saved. The EP team has the quote details needed to take it from here.';\n        quoteActionButton.querySelector('span').textContent = 'Follow-up saved';\n        quoteActionButton.disabled = true;\n        return null;\n      }\n\n      if (handoff?.status === 'checkout_ready' && handoff.paymentCreationAllowed) {\n        if (activeAccess?.mode !== 'checkout') {\n          quoteActionNote.textContent = 'Payments are off in the current preview session.';\n          quoteActionButton.querySelector('span').textContent = 'Payments are off';\n          quoteActionButton.disabled = true;\n          return null;\n        }\n        const checkoutUrl = model.validatedCheckoutUrl(handoff.checkoutUrl, checkoutHosts);\n        // Sign-first bookings: the platform hands us its agreement page (on the\n        // app host) instead of the Shopify invoice; the client signs there and\n        // is then sent on to checkout. Say so, rather than promising checkout.\n        const signFirst = (() => {\n          try {\n            return Boolean(checkoutUrl) && /^app\\./.test(new URL(checkoutUrl, window.location.href).hostname);\n          } catch {\n            return false;\n          }\n        })();\n        quoteActionNote.textContent = !checkoutUrl\n          ? 'We saved the booking, but its secure checkout link needs to be refreshed.'\n          : invoicePath && signFirst\n            ? 'Almost there \u2014 review and sign your agreement, and your invoice follows by email. Nothing is paid on this page, and your saved link will still be here if you refresh.'\n            : invoicePath\n              ? 'You\u2019re booked! Your invoice is on its way by email \u2014 payable by check or card. Continue to your confirmation.'\n              : freeBooking && signFirst\n                ? 'Your total is $0 \u2014 nothing to pay. Review and sign the agreement to complete your free booking. Your saved link will still be here if you refresh.'\n                : freeBooking\n                  ? 'Your total is $0 \u2014 nothing to pay today. Your booking is in, and we\u2019ll follow up with your event agreement to sign. Your saved link will still be here if you refresh.'\n                  : signFirst\n                    ? 'Your agreement and secure checkout are ready. First you\u2019ll review and sign the agreement, then pay your retainer. Your saved link will still be here if you refresh.'\n                    : 'Your secure Shopify checkout is ready. Your saved link will still be here if you refresh.';\n        quoteActionButton.querySelector('span').textContent = !checkoutUrl\n          ? 'Refresh secure checkout'\n          : invoicePath && signFirst\n            ? 'Review agreement & get my invoice'\n            : invoicePath\n              ? 'Continue \u2014 invoice on the way'\n              : freeBooking && signFirst\n                ? 'Review agreement & complete free booking'\n                : freeBooking\n                  ? 'Complete free booking'\n                  : signFirst\n                    ? 'Review agreement & continue to checkout'\n                    : 'Continue to secure checkout';\n        quoteActionButton.disabled = false;\n        return checkoutUrl;\n      }\n\n      return null;\n    };\n\n    const unlock = (access) => {\n      const isResume = hasRestoredJourney || Boolean(readQuoteSession()?.token);\n      activeAccess = access;\n      accessPanel.hidden = true;\n      workspace.hidden = false;\n      if (assistantPortal) assistantPortal.hidden = false;\n      displayMode(access.mode);\n      void ensureQuoteSession().catch(() => {\n        // Session creation is retried by the next quote or analytics action.\n      });\n      queueQuoteStarted();\n      showStep(currentStep, isResume ? 'resume' : 'initial');\n      if (salesChatEnabled && assistantState.salesConversationId) {\n        scheduleLiveSalesFallback();\n        scheduleLiveSalesPoll(0);\n      }\n    };\n\n    const recapLabels = {\n      event_location: 'Location',\n      event_date: 'Date',\n      name: 'Name',\n      email: 'Email',\n      event_type: 'Event Type',\n      attendance: 'People',\n    };\n\n    const appendSummaryItem = (label, value) => {\n      const wrapper = document.createElement('div');\n      const term = document.createElement('dt');\n      const description = document.createElement('dd');\n      term.textContent = label;\n      description.textContent = value;\n      wrapper.append(term, description);\n      summary.append(wrapper);\n    };\n\n    const renderSummary = () => {\n      summary.replaceChildren();\n      Object.entries(recapLabels).forEach(([name, label]) => {\n        const input = root.querySelector(`[name=\"${name}\"]:checked`) || root.querySelector(`[name=\"${name}\"]`);\n        const value = input?.value || 'Not answered';\n        appendSummaryItem(\n          label,\n          name === 'event_type' ? model.eventTypeLabel(value) : value.replaceAll('_', ' '),\n        );\n      });\n      appendSummaryItem(\n        'Experience',\n        activePackage\n          ? activePackage.name\n          : selectedServices().map((service) => serviceDefinitions[service]?.label || service).join(' + '),\n      );\n    };\n\n    const validationErrorCodes = (step) => {\n      const codes = Array.from(step.querySelectorAll(':invalid')).map((input) => {\n        if (input.name === 'event_location') return 'location_required';\n        if (input.name === 'event_date') return input.validity.valueMissing ? 'date_required' : 'date_invalid';\n        if (input.name === 'name') return 'name_required';\n        if (input.name === 'email') return input.validity.valueMissing ? 'email_required' : 'email_invalid';\n        if (input.name === 'event_type') return 'event_type_required';\n        if (input.name === 'attendance') return input.validity.valueMissing ? 'attendance_required' : 'attendance_invalid';\n        if (input.name === 'service' || input.dataset.configResource !== undefined) return 'service_required';\n        return null;\n      });\n      return [...new Set(codes.filter(Boolean))];\n    };\n\n    const configurationValues = () => Array.from(configurations.querySelectorAll('[data-quote-configuration]')).map((card) => {\n      const configuration = { service: card.dataset.service };\n      const runtime = card.querySelector('[data-config-runtime]')?.value;\n      if (runtime) configuration.runtimeHours = Number(runtime);\n      for (const [selector, key] of [\n        ['[data-config-printing]', 'printing'],\n        ['[data-config-backdrop]', 'premiumBackdrop'],\n        ['[data-config-branding]', 'customBranding'],\n      ]) {\n        if (card.querySelector(selector)?.checked) configuration[key] = true;\n      }\n      const selectedAddOns = Array.from(\n        card.querySelectorAll('[data-config-custom-addon]:checked'),\n        (input) => input.dataset.configCustomAddon,\n      );\n      if (selectedAddOns.length > 0) configuration.selectedAddOns = selectedAddOns;\n      const customBackdropSize = card.querySelector('[data-config-custom-backdrop-size]')?.value;\n      if (customBackdropSize) configuration.customBackdropSize = customBackdropSize;\n      if (card.querySelector('[data-config-keep-custom-backdrop-frame]')?.checked) {\n        configuration.keepCustomBackdropFrame = true;\n      }\n      const resource = card.querySelector('[data-config-resource]:checked')?.value;\n      const teleportraitSet = card.querySelector('[data-config-teleportrait-set]:checked')?.value;\n      const setupTime = card.querySelector('[data-config-setup]')?.value;\n      const teardownTime = card.querySelector('[data-config-teardown]')?.value;\n      if (resource) configuration.classicResource = resource;\n      if (teleportraitSet) configuration.teleportraitSet = teleportraitSet;\n      if (setupTime) configuration.setupTime = setupTime;\n      if (teardownTime) configuration.teardownTime = teardownTime;\n      return configuration;\n    });\n\n    const captureConfigurations = () => {\n      const captured = configurationValues();\n      if (captured.length > 0) {\n        savedConfigurations = new Map(\n          captured.map((configuration) => [configuration.service, configuration]),\n        );\n      }\n    };\n\n    const appendRuntimeField = (card, service, definition, previous, isWedding) => {\n      const included = isWedding ? definition.runtime.wedding : definition.runtime.standard;\n      const runtimeComped = addOnComped('extra_runtime');\n      const field = createElement('div', 'instant-quoter__field');\n      const label = createElement('label', '', 'Runtime');\n      if (runtimeComped) label.append(compBadgeElement());\n      const select = document.createElement('select');\n      select.name = `runtime_${service}`;\n      select.dataset.configRuntime = '';\n      for (let hours = included; hours <= definition.runtime.maximum; hours += 1) {\n        const option = document.createElement('option');\n        option.value = String(hours);\n        option.textContent = `${hours} hours${hours === included\n          ? ' \u00B7 included'\n          : runtimeComped ? ' \u00B7 free' : ''}`;\n        option.selected = Number(previous?.runtimeHours || included) === hours;\n        select.append(option);\n      }\n      label.htmlFor = `${root.id || 'instant-quote'}-${service}-runtime`;\n      select.id = label.htmlFor;\n      field.append(label, select);\n      card.append(field);\n    };\n\n    const appendOption = (container, service, key, title, detail, checked = false, comped = false) => {\n      const label = createElement('label', 'instant-quoter__option');\n      const input = document.createElement('input');\n      input.type = 'checkbox';\n      input.name = `${key}_${service}`;\n      input.checked = checked;\n      input.dataset[key === 'printing' ? 'configPrinting' : key === 'backdrop' ? 'configBackdrop' : 'configBranding'] = '';\n      const copy = createElement('span');\n      copy.append(\n        createElement('strong', '', title),\n        createElement('small', '', detail),\n        ...(comped ? [compBadgeElement()] : []),\n      );\n      label.append(input, copy);\n      container.append(label);\n    };\n\n    const appendCustomAddOnOption = (container, service, code, offering, checked = false) => {\n      const comped = addOnComped(code);\n      const label = createElement('label', 'instant-quoter__option');\n      const input = document.createElement('input');\n      input.type = 'checkbox';\n      input.name = `${code}_${service}`;\n      input.checked = checked;\n      input.setAttribute('data-config-custom-addon', code);\n      const copy = createElement('span');\n      copy.append(\n        createElement('strong', '', addOnPriceLabel(offering.label, offering.priceCents, comped)),\n        createElement('small', '', offering.description),\n        ...(comped ? [compBadgeElement()] : []),\n      );\n      label.append(input, copy);\n      container.append(label);\n    };\n\n    // Oak is the house default. A Classic quote cannot price without a booth,\n    // and the old \"Choose Sky or Oak\" placeholder let seeded journeys (the\n    // Experience Finder, packages) reach the review step with none \u2014 every\n    // one of those priced \"unavailable\" until staff rebuilt the quote. The\n    // server fills the same default when a configuration arrives blank.\n    const DEFAULT_CLASSIC_RESOURCE = 'oak';\n    const classicBooths = () => [\n      {\n        value: 'oak',\n        label: 'Oak',\n        caption: root.dataset.classicOakCaption || '',\n        image: root.dataset.classicOakImage || '',\n      },\n      {\n        value: 'sky',\n        label: 'Sky',\n        caption: root.dataset.classicSkyCaption || '',\n        image: root.dataset.classicSkyImage || '',\n      },\n    ];\n\n    const appendClassicBoothPicker = (card, previous) => {\n      const field = createElement('fieldset', 'instant-quoter__field instant-quoter__booths');\n      field.append(createElement('legend', '', 'Which Classic booth?'));\n      const cards = createElement('div', 'instant-quoter__booth-cards');\n      const selected = ['sky', 'oak'].includes(previous?.classicResource)\n        ? previous.classicResource\n        : DEFAULT_CLASSIC_RESOURCE;\n      classicBooths().forEach((booth) => {\n        const label = createElement('label', 'instant-quoter__booth-card');\n        const input = document.createElement('input');\n        input.type = 'radio';\n        input.name = 'resource_classic';\n        input.value = booth.value;\n        input.required = true;\n        input.dataset.configResource = '';\n        input.checked = booth.value === selected;\n        input.id = `${root.id || 'instant-quote'}-classic-resource-${booth.value}`;\n        let media;\n        if (booth.image) {\n          media = document.createElement('img');\n          media.className = 'instant-quoter__booth-media';\n          media.src = booth.image;\n          media.alt = `The ${booth.label} Classic photo booth`;\n          media.loading = 'lazy';\n        } else {\n          media = createElement('span', 'instant-quoter__booth-media instant-quoter__booth-media--empty', booth.label);\n          media.setAttribute('aria-hidden', 'true');\n        }\n        const copy = createElement('span', 'instant-quoter__booth-copy');\n        copy.append(createElement('strong', '', booth.label));\n        if (booth.caption) copy.append(createElement('small', '', booth.caption));\n        label.append(input, media, copy);\n        label.classList.toggle('is-selected', input.checked);\n        cards.append(label);\n      });\n      cards.addEventListener('change', () => {\n        cards.querySelectorAll('.instant-quoter__booth-card').forEach((boothCard) => {\n          boothCard.classList.toggle('is-selected', Boolean(boothCard.querySelector('input')?.checked));\n        });\n      });\n      field.append(cards);\n      card.append(field);\n    };\n\n    const appendClassicFields = (card, previous, allowedAddOns) => {\n      appendClassicBoothPicker(card, previous);\n      const grid = createElement('div', 'instant-quoter__field-grid');\n\n      const makeTimeField = (kind, labelText, value) => {\n        const field = createElement('div', 'instant-quoter__field');\n        const label = createElement('label', '', labelText);\n        const input = document.createElement('input');\n        input.type = 'time';\n        input.name = `${kind}_classic`;\n        input.id = `${root.id || 'instant-quote'}-classic-${kind}`;\n        input.dataset[kind === 'setup' ? 'configSetup' : 'configTeardown'] = '';\n        input.value = value || '';\n        label.htmlFor = input.id;\n        field.append(label, input);\n        return field;\n      };\n\n      grid.append(\n        makeTimeField('setup', 'Planned setup begins', previous?.setupTime),\n        makeTimeField('teardown', 'Booth closes / pickup begins', previous?.teardownTime),\n      );\n      card.append(grid);\n      if (allowedAddOns.includes('classic_branding')) {\n        const options = createElement('div', 'instant-quoter__option-list');\n        const brandingComped = addOnComped('classic_branding');\n        appendOption(\n          options,\n          'classic',\n          'branding',\n          addOnPriceLabel(\n            activeCatalog?.addOnPresentation?.classicBrandingCents?.label || 'Full custom branding',\n            activeCatalog?.addOns?.classicBrandingCents ?? 50000,\n            brandingComped,\n          ),\n          activeCatalog?.addOnPresentation?.classicBrandingCents?.description || 'Brand the outside of the Classic booth\u2014not just the photo artwork.',\n          previous?.customBranding,\n          brandingComped,\n        );\n        card.append(options);\n      }\n    };\n\n    const appendTeleportraitSetFields = (card, previous) => {\n      const activeSets = Object.entries(\n        activeCatalog.teleportrait?.existingSets || {},\n      ).filter(([, set]) => set && set.active);\n      if (activeSets.length === 0) return;\n\n      const fieldset = createElement('fieldset', 'instant-quoter__teleportrait-sets');\n      const legend = createElement('legend', '', 'Choose your Teleportrait set');\n      fieldset.append(legend);\n\n      activeSets.forEach(([code, set], index) => {\n        const label = createElement('label', 'instant-quoter__teleportrait-set');\n        const input = document.createElement('input');\n        input.type = 'radio';\n        input.name = 'teleportrait_set_teleportrait_existing';\n        input.value = code;\n        input.required = true;\n        input.checked = previous?.teleportraitSet === code || (\n          !previous?.teleportraitSet && activeSets.length === 1 && index === 0\n        );\n        input.setAttribute('data-config-teleportrait-set', '');\n\n        const cardBody = createElement('span');\n        const image = createElement('img');\n        image.src = set.imageUrl;\n        image.alt = set.label;\n        image.loading = 'lazy';\n        image.decoding = 'async';\n        const copy = createElement('span', 'instant-quoter__teleportrait-set-copy');\n        // A flat teleportrait_existing override (or the percent-off) prices\n        // every set at the deal \u2014 strike this set's own price beside it.\n        const setPricing = model.referralDealLost(activeReferral, validatedEventLocation)\n          ? null\n          : model.referralTeleportraitSetPricing(activeReferral, set);\n        const setPrice = createElement(\n          'small',\n          setPricing ? 'instant-quoter__teleportrait-set-deal' : '',\n        );\n        if (setPricing) {\n          setPrice.append(\n            ...(setPricing.standardCents !== undefined\n              ? [createElement('s', '', model.formatMoney(setPricing.standardCents)), document.createTextNode(' ')]\n              : []),\n            createElement('strong', '', model.formatMoney(setPricing.dealCents)),\n            document.createTextNode(` \u00B7 ${activeReferral.name} offer`),\n          );\n        } else {\n          setPrice.textContent = model.formatMoney(set.priceCents);\n        }\n        copy.append(\n          createElement('strong', '', set.label),\n          createElement('em', '', set.description),\n          setPrice,\n        );\n        cardBody.append(image, copy);\n        label.append(input, cardBody);\n        fieldset.append(label);\n      });\n      card.append(fieldset);\n    };\n\n    const appendCustomBackdropFields = (card, service, previous) => {\n      // The custom_backdrop comp covers the size AND the keep-the-frame line\n      // (both price under backdrop.custom.* server-side).\n      const backdropComped = addOnComped('custom_backdrop');\n      const grid = createElement('div', 'instant-quoter__field-grid instant-quoter__custom-backdrop');\n      const sizeField = createElement('div', 'instant-quoter__field');\n      const sizeLabel = createElement('label', '', 'Custom dual-sided backdrop');\n      if (backdropComped) sizeLabel.append(compBadgeElement());\n      const size = document.createElement('select');\n      size.id = `${root.id || 'instant-quote'}-${service}-custom-backdrop`;\n      size.name = `custom_backdrop_${service}`;\n      size.dataset.configCustomBackdropSize = '';\n      sizeLabel.htmlFor = size.id;\n      for (const [value, text] of [\n        ['', 'No custom backdrop'],\n        ['7.5ft', addOnPriceLabel('7.5 ft', activeCatalog?.addOns?.customBackdrop7_5FtCents ?? 50000, backdropComped)],\n        ['10ft', addOnPriceLabel('10 ft', activeCatalog?.addOns?.customBackdrop10FtCents ?? 70000, backdropComped)],\n        ['15ft', addOnPriceLabel('15 ft', activeCatalog?.addOns?.customBackdrop15FtCents ?? 95000, backdropComped)],\n      ]) {\n        const option = document.createElement('option');\n        option.value = value;\n        option.textContent = text;\n        option.selected = previous?.customBackdropSize === value;\n        size.append(option);\n      }\n      sizeField.append(sizeLabel, size);\n\n      const keepLabel = createElement('label', 'instant-quoter__option');\n      const keep = document.createElement('input');\n      keep.type = 'checkbox';\n      keep.name = `keep_custom_backdrop_frame_${service}`;\n      keep.dataset.configKeepCustomBackdropFrame = '';\n      keep.checked = previous?.keepCustomBackdropFrame === true;\n      keep.disabled = !previous?.customBackdropSize;\n      const keepCopy = createElement('span');\n      keepCopy.append(\n        createElement('strong', '', addOnPriceLabel(\n          activeCatalog?.addOnPresentation?.customBackdropKeepFrameCents?.label || 'Keep the custom frame',\n          activeCatalog?.addOns?.customBackdropKeepFrameCents ?? 20000,\n          backdropComped,\n        )),\n        createElement('small', '', activeCatalog?.addOnPresentation?.customBackdropKeepFrameCents?.description || 'The custom backdrop frame is yours after the event.'),\n        ...(backdropComped ? [compBadgeElement()] : []),\n      );\n      keepLabel.append(keep, keepCopy);\n      size.addEventListener('change', () => {\n        keep.disabled = !size.value;\n        if (!size.value) keep.checked = false;\n      });\n      grid.append(sizeField, keepLabel);\n      card.append(grid);\n    };\n\n    const renderConfigurations = () => {\n      captureConfigurations();\n      configurations.replaceChildren();\n      const isWedding = selectedEventType() === 'wedding';\n\n      selectedServices().forEach((service) => {\n        const definition = serviceDefinitions[service];\n        const previous = savedConfigurations.get(service);\n        const allowedAddOns = model.allowedAddOnsFor(activeCatalog, selectedEventType(), service);\n        const card = createElement('section', 'instant-quoter__configuration');\n        card.dataset.quoteConfiguration = '';\n        card.dataset.service = service;\n        const head = createElement('div', 'instant-quoter__configuration-head');\n        head.append(createElement('h3', '', definition.label), createElement('span', '', definition.detail));\n        card.append(head);\n\n        if (definition.runtime && allowedAddOns.includes('extra_runtime')) {\n          appendRuntimeField(card, service, definition, previous, isWedding);\n        }\n\n        if (service === 'teleportrait_existing') {\n          appendTeleportraitSetFields(card, previous);\n        }\n\n        if (\n          allowedAddOns.includes('printing')\n          || allowedAddOns.includes('premium_backdrop')\n        ) {\n          const options = createElement('div', 'instant-quoter__option-list');\n          if (allowedAddOns.includes('printing')) {\n            const printingComped = addOnComped('printing');\n            appendOption(\n              options,\n              service,\n              'printing',\n              addOnPriceLabel(\n                activeCatalog?.addOnPresentation?.standardPrintingCents?.label || 'Add printing',\n                activeCatalog?.addOns?.standardPrintingCents ?? 30000,\n                printingComped,\n              ),\n              activeCatalog?.addOnPresentation?.standardPrintingCents?.description || 'A physical photo in hand changes the whole gravity of the booth.',\n              previous?.printing,\n              printingComped,\n            );\n          }\n          if (allowedAddOns.includes('premium_backdrop')) {\n            const backdropComped = addOnComped('premium_backdrop');\n            appendOption(\n              options,\n              service,\n              'backdrop',\n              addOnPriceLabel(\n                activeCatalog?.addOnPresentation?.premiumBackdropCents?.label || 'Premium backdrop tier',\n                activeCatalog?.addOns?.premiumBackdropCents ?? 30000,\n                backdropComped,\n              ),\n              activeCatalog?.addOnPresentation?.premiumBackdropCents?.description || 'Unlock floral and shimmer options; choose the exact available backdrop later.',\n              previous?.premiumBackdrop,\n              backdropComped,\n            );\n          }\n          card.append(options);\n        }\n        const customAddOns = allowedAddOns\n          .map((code) => [code, activeCatalog.customAddOns?.[code]])\n          .filter(([, offering]) => offering);\n        if (customAddOns.length > 0) {\n          const options = createElement('div', 'instant-quoter__option-list');\n          customAddOns.forEach(([code, offering]) => {\n            appendCustomAddOnOption(\n              options,\n              service,\n              code,\n              offering,\n              previous?.selectedAddOns?.includes(code),\n            );\n          });\n          card.append(options);\n        }\n        if (allowedAddOns.includes('classic_branding') && service !== 'classic') {\n          const options = createElement('div', 'instant-quoter__option-list');\n          const brandingComped = addOnComped('classic_branding');\n          appendOption(\n            options,\n            service,\n            'branding',\n            addOnPriceLabel(\n              activeCatalog?.addOnPresentation?.classicBrandingCents?.label || 'Full custom branding',\n              activeCatalog?.addOns?.classicBrandingCents ?? 50000,\n              brandingComped,\n            ),\n            activeCatalog?.addOnPresentation?.classicBrandingCents?.description || 'Carry your brand through the physical guest experience.',\n            previous?.customBranding,\n            brandingComped,\n          );\n          card.append(options);\n        }\n        if (service === 'photo_booth' && isWedding) {\n          card.append(createElement('p', 'instant-quoter__selection-note', 'Wedding Photo Booth packages already include printing and local early setup.'));\n        }\n\n        if (service === 'classic') appendClassicFields(card, previous, allowedAddOns);\n        if (allowedAddOns.includes('custom_backdrop')) {\n          appendCustomBackdropFields(card, service, previous);\n        }\n        configurations.append(card);\n      });\n    };\n\n    const attendanceBand = (attendance) => {\n      if (attendance <= 100) return '1_100';\n      if (attendance <= 250) return '101_250';\n      if (attendance <= 400) return '251_400';\n      if (attendance <= 1000) return '401_1000';\n      return 'over_1000';\n    };\n\n    const amountBand = (cents) => {\n      if (cents < 100000) return 'under_1000';\n      if (cents < 200000) return '1000_1999';\n      if (cents < 350000) return '2000_3499';\n      if (cents < 550000) return '3500_5499';\n      if (cents < 750000) return '5500_7499';\n      return '7500_plus';\n    };\n\n    const distanceBand = (travelTier) => ({\n      included: '0_40',\n      over_40_to_100: '41_100',\n      over_100_to_200: '101_200',\n      over_200_to_400: '201_400',\n      sales_required: 'over_400',\n    })[travelTier] || 'unresolved';\n\n    const applyStaffQuoteLockPresentation = () => {\n      if (!staffQuoteLocked) return;\n      const reviewStep = steps.find((step) => Number(step.dataset.quoteStep) === 7);\n      if (!reviewStep) return;\n      const kicker = reviewStep.querySelector('.instant-quoter__kicker');\n      if (kicker) {\n        kicker.textContent = quoteOptions.length > 1\n          ? 'Your Electric Photoland quote \u2014 pick the option that fits'\n          : 'Your Electric Photoland quote \u2014 prepared for you';\n      }\n      const back = reviewStep.querySelector('[data-quote-back]');\n      if (back) back.hidden = true;\n      const rail = root.querySelector('.instant-quoter__progress');\n      if (rail) rail.hidden = true;\n    };\n\n    /**\n     * Applied independently of the staff-quote lock, because a funnel cart on\n     * the invoice path never goes through the locked presentation at all \u2014\n     * gating this on the lock would leave those clients a checkout button for\n     * a deal that has no checkout.\n     */\n    const applyPayByInvoiceIfSet = () => {\n      if (!payByInvoice) return;\n      // Community Partner sessions render the card-vs-invoice picker instead:\n      // the client may switch back, so the checkout button has to survive.\n      if (model.paymentChoiceOffered(activeReferral)) return;\n      const reviewStep = steps.find((step) => Number(step.dataset.quoteStep) === 7);\n      if (reviewStep) applyPayByInvoicePresentation(reviewStep);\n    };\n\n    /**\n     * Replace card checkout with an invoice explanation.\n     *\n     * The button is REMOVED rather than disabled: a greyed-out \"Check\n     * reservation readiness\" reads as something broken, when in fact nothing\n     * is wrong and there is simply nothing for the client to click.\n     */\n    const applyPayByInvoicePresentation = (reviewStep) => {\n      if (!payByInvoice) return;\n      if (model.paymentChoiceOffered(activeReferral)) return;\n      const action = reviewStep.querySelector('[data-quote-action]');\n      if (action) action.remove();\n\n      const note = reviewStep.querySelector('[data-quote-action-note]');\n      if (note) {\n        note.textContent =\n          'No card needed \u2014 we\u2019ll email you an invoice you can pass straight to accounts payable.';\n      }\n\n      const totalNote = reviewStep.querySelector('[data-quote-total-note]');\n      if (totalNote) {\n        totalNote.textContent =\n          'Travel is calculated from our Spokane studio. Your event address is used for sales tax, which is added on the invoice.';\n      }\n\n      const actions = reviewStep.querySelector('.instant-quoter__actions');\n      if (actions && !actions.querySelector('[data-quote-invoice-panel]')) {\n        const panel = createElement('div', 'instant-quoter__invoice-panel');\n        panel.setAttribute('data-quote-invoice-panel', '');\n        panel.append(\n          createElement('strong', '', 'We\u2019ll invoice you for this'),\n          createElement(\n            'p',\n            '',\n            invoiceWithoutAgreement\n              ? 'We\u2019ll email your invoice shortly, payable by check or card. Your date is held from that moment \u2014 nothing to pay right now.'\n              : 'Once your agreement is signed we\u2019ll email your invoice, payable by check or card. Your date is held from that moment \u2014 nothing to pay right now.',\n          ),\n        );\n        actions.append(panel);\n      }\n    };\n\n    /**\n     * Community Partner sessions: the path the checkout call will ask for.\n     * Null everywhere the client gets no choice \u2014 the body then omits\n     * `paymentPath` and the platform behaves exactly as it always has. An\n     * untouched picker follows the session (a staff- or previously-picked\n     * invoice path), otherwise defaults to card.\n     */\n    const effectivePaymentPath = () => {\n      if (!model.paymentChoiceOffered(activeReferral)) return null;\n      return paymentPathPick || (payByInvoice ? 'invoice' : 'checkout');\n    };\n\n    /**\n     * A saved handoff only replays when it was built for the path the client\n     * currently has picked \u2014 a card checkout link must never re-open after\n     * they switched to the invoice, nor the reverse.\n     */\n    const savedHandoffMatchesChoice = (handoff) => {\n      const path = effectivePaymentPath();\n      if (!path) return true;\n      return (handoff?.invoicePath === true) === (path === 'invoice');\n    };\n\n    const selectPaymentPath = (pick) => {\n      if (pick !== 'checkout' && pick !== 'invoice') return;\n      const changed = effectivePaymentPath() !== pick;\n      paymentPathPick = pick;\n      payByInvoice = pick === 'invoice';\n      if (changed) {\n        // The other path's saved handoff \u2014 and the idempotency key that\n        // would replay it \u2014 went stale the moment they changed their mind.\n        const stored = readQuoteSession();\n        if (stored?.checkoutHandoff && !savedHandoffMatchesChoice(stored.checkoutHandoff)) {\n          writeQuoteSession({\n            ...stored,\n            checkoutHandoff: null,\n            checkoutPreflightFingerprint: null,\n            checkoutPreflightIdempotencyKey: null,\n          });\n        }\n      }\n      persistJourney();\n      if (latestQuote) renderQuote(latestQuote);\n    };\n\n    /**\n     * The card-vs-invoice picker on the review step (Community Partner\n     * sessions with a bookable quote only). Full rebuild, like the venue\n     * picker: the list is two buttons and selection state lives in JS.\n     */\n    const renderPaymentChoice = () => {\n      const reviewStep = steps.find((step) => Number(step.dataset.quoteStep) === 7);\n      if (!reviewStep) return;\n      const existing = reviewStep.querySelector('[data-quote-payment-choice]');\n      const offered = model.paymentChoiceOffered(activeReferral)\n        && latestQuote?.checkoutEnabled === true;\n      if (!offered) {\n        existing?.remove();\n        return;\n      }\n      const note = reviewStep.querySelector('[data-quote-action-note]');\n      let picker = existing;\n      if (!picker) {\n        picker = createElement('fieldset', 'instant-quoter__payment-choice');\n        picker.setAttribute('data-quote-payment-choice', '');\n        if (note?.parentElement) note.parentElement.insertBefore(picker, note);\n        else reviewStep.append(picker);\n      }\n      const selected = effectivePaymentPath();\n      picker.replaceChildren(createElement('legend', '', 'How would you like to pay?'));\n      [\n        {\n          pick: 'checkout',\n          title: 'Pay by card today',\n          copy: 'Reserve your date now through secure checkout.',\n        },\n        {\n          pick: 'invoice',\n          title: 'Get an invoice',\n          copy: 'Sign the agreement and we\u2019ll email an invoice \u2014 payable by check or card, easy to hand to accounts payable.',\n        },\n      ].forEach(({ pick, title, copy }) => {\n        const option = createElement('button', 'instant-quoter__payment-option');\n        option.type = 'button';\n        option.setAttribute('data-quote-payment-option', pick);\n        option.setAttribute('aria-pressed', selected === pick ? 'true' : 'false');\n        const body = createElement('span');\n        body.append(createElement('strong', '', title), createElement('small', '', copy));\n        option.append(body);\n        option.addEventListener('click', () => selectPaymentPath(pick));\n        picker.append(option);\n      });\n      // With the invoice picked and nothing booked yet, the action copy says\n      // what actually happens next \u2014 a handoff that already applied (same\n      // quote, same path) owns the button instead.\n      const savedHandoff = readQuoteSession()?.checkoutHandoff;\n      const handoffApplied = savedHandoff?.quoteId === latestQuote?.id\n        && savedHandoff?.quoteRevision === latestQuote?.revision\n        && savedHandoffMatchesChoice(savedHandoff);\n      if (selected === 'invoice' && !handoffApplied && !optionChoicePending) {\n        const label = quoteActionButton?.querySelector('span');\n        if (label) label.textContent = 'Continue \u2014 sign & get my invoice';\n        if (quoteActionNote) {\n          quoteActionNote.textContent =\n            'No card needed today. We\u2019ll confirm availability, you sign the agreement, and your invoice arrives by email.';\n        }\n      }\n    };\n\n    /**\n     * Quote Options: record the client's card pick on the platform. Pure\n     * preference signal \u2014 never binding (checkout re-validates against the\n     * chosen option's quote), so failures are silently ignored.\n     */\n    const notifyQuoteOptionSelected = (optionKey) => {\n      void (async () => {\n        try {\n          const session = await ensureQuoteSession();\n          await fetch(\n            `${sessionEndpoint}/${encodeURIComponent(session.token)}/option`,\n            {\n              method: 'POST',\n              headers: {\n                authorization: `Bearer ${activeAccess.token}`,\n                'content-type': 'application/json',\n              },\n              body: JSON.stringify({ optionKey }),\n              keepalive: true,\n            },\n          );\n        } catch {\n          // The pick still holds locally; checkout is the binding signal.\n        }\n      })();\n    };\n\n    const selectQuoteOption = (optionKey, { notify = true } = {}) => {\n      const option = quoteOptions.find((entry) => entry.key === optionKey);\n      if (!option) return;\n      const changed = selectedQuoteOptionKey !== option.key;\n      selectedQuoteOptionKey = option.key;\n      optionChoicePending = false;\n      renderQuote(option.quote);\n      renderQuoteOptionCards();\n      persistJourney();\n      if (notify && changed) notifyQuoteOptionSelected(option.key);\n    };\n\n    /**\n     * The comparison cards above the review step: one per option, the active\n     * card pressed, Recommended badged, and the client free to switch until\n     * they pay \u2014 tapping a card swaps the itemized quote and the checkout\n     * target below it. On a cart the client built themselves their own option\n     * is labelled as theirs, so \"yours\" and \"what EP suggested\" stay legible.\n     */\n    const renderQuoteOptionCards = () => {\n      if (!quoteOptionCards) return;\n      if (quoteOptions.length < 2) {\n        quoteOptionCards.hidden = true;\n        quoteOptionCards.replaceChildren();\n        return;\n      }\n      const activeOption = model.activeStaffQuoteOption(\n        quoteOptions,\n        selectedQuoteOptionKey,\n      );\n      quoteOptionCards.replaceChildren();\n      if (optionChoicePending) {\n        const prompt = createElement(\n          'p',\n          'instant-quoter__option-prompt',\n          'We put together a few ways to do this \u2014 pick the one you want to book.',\n        );\n        quoteOptionCards.append(prompt);\n      }\n      quoteOptions.forEach((option) => {\n        const card = createElement('button', 'instant-quoter__option-card');\n        card.type = 'button';\n        card.setAttribute('data-quote-option-card', option.key);\n        card.setAttribute('aria-pressed', String(option.key === activeOption?.key));\n        if (option.recommended) {\n          card.append(createElement('span', 'instant-quoter__option-flag', 'Recommended'));\n        } else if (option.origin === 'client') {\n          card.append(createElement('span', 'instant-quoter__option-flag is-yours', 'Your build'));\n        }\n        card.append(createElement('strong', '', option.name));\n        if (option.description) {\n          card.append(createElement('small', '', option.description));\n        }\n        const presentation = model.presentQuote(option.quote, {\n          referralPartnerName: activeReferral?.name,\n          referralPartnerType: activeReferral?.partnerType,\n        });\n        const price = createElement('span', 'instant-quoter__option-price', presentation.total);\n        price.append(createElement('small', '', ' before tax'));\n        card.append(price);\n        card.addEventListener('click', () => selectQuoteOption(option.key));\n        quoteOptionCards.append(card);\n      });\n      quoteOptionCards.hidden = false;\n    };\n\n    const renderQuote = (quote) => {\n      latestQuote = quote;\n      const presentation = model.presentQuote(quote, {\n        referralPartnerName: activeReferral?.name,\n        referralPartnerType: activeReferral?.partnerType,\n      });\n      quoteTitle.textContent = presentation.title;\n      quoteOutcome.textContent = quote.outcome === 'instant_estimate_sales_required'\n        ? 'Estimate \u00B7 team verification'\n        : quote.outcome === 'unavailable'\n          ? 'Let\u2019s find another route'\n          : 'Instant quote';\n      quoteLineItems.replaceChildren();\n      presentation.lineItems.forEach((lineItem) => {\n        const row = document.createElement('li');\n        row.append(createElement('span', '', lineItem.label), createElement('strong', '', lineItem.amount));\n        if (Array.isArray(lineItem.details) && lineItem.details.length > 0) {\n          const details = createElement('ul', 'instant-quoter__package-details');\n          lineItem.details.forEach((value) => {\n            const detail = createElement('li', '', value);\n            detail.setAttribute('data-quote-package-detail', '');\n            details.append(detail);\n          });\n          row.append(details);\n        }\n        quoteLineItems.append(row);\n      });\n      // One row per applied discount, in application order \u2014 a stacked quote\n      // (e.g. a sponsorship then a partner percent) itemizes; older quotes\n      // present their single combined discount as a one-row list.\n      presentation.discountRows.forEach((discountRow) => {\n        const discount = createElement('li', 'is-discount');\n        discount.append(\n          createElement('span', '', discountRow.label),\n          createElement('strong', '', `\u2212${discountRow.amount}`),\n        );\n        quoteLineItems.append(discount);\n      });\n      quoteTotal.textContent = presentation.total;\n      quoteTotalLabel.textContent = presentation.totalLabel;\n      renderPaymentSchedule();\n      quoteRetainer.textContent = presentation.retainerLabel;\n      quoteTotalNote.textContent = 'Your service price includes travel and location logistics from our Spokane studio. Your event address is used for sales tax. Billing details are entered separately at secure checkout.';\n      quoteReasons.replaceChildren();\n      presentation.reasonMessages.forEach((reason) => quoteReasons.append(createElement('li', '', reason)));\n      quoteNextNote.hidden = presentation.reasonMessages.length === 0;\n      const actionCopy = {\n        instant_bookable: {\n          label: 'Check reservation readiness',\n          note: 'We\u2019ll recheck the saved quote. No card, no charge, no surprise checkout.',\n        },\n        instant_bookable_consultation: {\n          label: 'Check reservation + planning',\n          note: 'We\u2019ll confirm the reservation path and flag the planning call that comes with it.',\n        },\n        instant_estimate_sales_required: {\n          label: 'Save for EP follow-up',\n          note: 'This one deserves a human. We\u2019ll save the handoff with your quote details attached.',\n        },\n        unavailable: {\n          label: 'Ask EP for another route',\n          note: 'That exact setup is not ready for online booking, but the saved quote gives us a useful place to start.',\n        },\n      }[quote.outcome];\n      quoteActionButton.querySelector('span').textContent = actionCopy.label;\n      quoteActionNote.textContent = actionCopy.note;\n      quoteActionButton.disabled = false;\n      // Quote Options: a deliberate pick comes before checkout, so nobody\n      // buys without registering that they were offered choices.\n      if (optionChoicePending) {\n        quoteActionButton.disabled = true;\n        quoteActionNote.textContent = 'Choose one of the options above to continue.';\n      }\n      const savedHandoff = readQuoteSession()?.checkoutHandoff;\n      if (\n        savedHandoff?.quoteId === quote.id\n        && savedHandoff?.quoteRevision === quote.revision\n        && savedHandoffMatchesChoice(savedHandoff)\n      ) {\n        applyHandoffPresentation(savedHandoff);\n      }\n      renderSummary();\n      renderPaymentChoice();\n    };\n\n    const journeyAnswerNames = [\n      'event_location',\n      'event_date',\n      'name',\n      'email',\n      'event_type',\n      'attendance',\n    ];\n\n    const journeyAnswerValue = (name) => {\n      const inputs = Array.from(root.querySelectorAll(`[name=\"${name}\"]`));\n      const input = inputs.some((candidate) => candidate.type === 'radio')\n        ? inputs.find((candidate) => candidate.checked)\n        : inputs[0];\n      return input?.value || '';\n    };\n\n    const journeyAnswers = () => Object.fromEntries(\n      journeyAnswerNames.map((name) => [name, journeyAnswerValue(name)]),\n    );\n\n    const journeyConfigurations = () => {\n      const renderedConfigurations = configurationValues();\n      return renderedConfigurations.length > 0\n        ? renderedConfigurations\n        : Array.from(savedConfigurations.values());\n    };\n\n    const persistJourney = () => {\n      writeSessionJson(journeyStorageKey, {\n        version: 1,\n        currentStep,\n        serverRevision,\n        answers: journeyAnswers(),\n        services: selectedServices(),\n        configurations: journeyConfigurations(),\n        validatedLocation: validatedEventLocation,\n        ...(activePackage ? { package: activePackage } : {}),\n        ...(staffQuoteLocked ? { staffQuoteLocked: true } : {}),\n        ...(payByInvoice ? { payByInvoice: true } : {}),\n        ...(invoiceWithoutAgreement ? { invoiceWithoutAgreement: true } : {}),\n        ...(paymentPathPick ? { paymentPathPick } : {}),\n        ...(quoteOptions.length > 1\n          ? {\n              quoteOptions,\n              ...(selectedQuoteOptionKey\n                ? { selectedOptionKey: selectedQuoteOptionKey }\n                : {}),\n            }\n          : {}),\n        quote: latestQuote,\n      });\n    };\n\n    const operationalJourneyAnswers = (completedStep) => {\n      const answers = journeyAnswers();\n      return Object.fromEntries([\n        ['eventLocation', answers.event_location || undefined],\n        ['eventDate', answers.event_date || undefined],\n        ['eventType', completedStep >= 3 || activePackage\n          ? answers.event_type || undefined\n          : undefined],\n        ['attendance', completedStep >= 4 && answers.attendance\n          ? Number(answers.attendance)\n          : undefined],\n      ].filter(([, value]) => value !== undefined));\n    };\n\n    const saveJourneySnapshot = async (completedStep) => {\n      try {\n        const session = await ensureQuoteSession();\n        const body = {\n          step: stepDescriptor(completedStep),\n          answers: operationalJourneyAnswers(completedStep),\n          ...(validatedEventLocation?.formattedAddress\n            ? {\n                validatedLocation: {\n                  formattedAddress: validatedEventLocation.formattedAddress,\n                  ...(validatedEventLocation.city ? { city: validatedEventLocation.city } : {}),\n                  ...(validatedEventLocation.provinceCode\n                    ? { provinceCode: validatedEventLocation.provinceCode }\n                    : {}),\n                  ...(validatedEventLocation.zip ? { zip: validatedEventLocation.zip } : {}),\n                },\n              }\n            : {}),\n          selectedServices: completedStep >= 5 || activePackage ? selectedServices() : [],\n          configurations: completedStep >= 6 || activePackage ? journeyConfigurations() : [],\n          // The server relaxes its step-order guards for pre-seeded package\n          // selections only when the snapshot names the package.\n          ...(activePackage ? { packageCode: activePackage.code } : {}),\n        };\n        await fetch(\n          `${sessionEndpoint}/${encodeURIComponent(session.token)}/snapshot`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n              'idempotency-key': randomId(),\n            },\n            body: JSON.stringify(body),\n            keepalive: true,\n          },\n        );\n      } catch {\n        // Operational capture must never block the customer journey. The\n        // calculated quote and contact save remain authoritative fallbacks.\n      }\n    };\n\n    const restoreJourney = () => {\n      const restored = model.normalizeJourneyState(readSessionJson(journeyStorageKey));\n      if (!restored) return false;\n\n      for (const [name, value] of Object.entries(restored.answers)) {\n        const inputs = Array.from(root.querySelectorAll(`[name=\"${name}\"]`));\n        if (inputs.some((input) => input.type === 'radio')) {\n          inputs.forEach((input) => { input.checked = input.value === value; });\n        } else if (inputs[0]) {\n          inputs[0].value = value;\n        }\n      }\n      validatedEventLocation = restored.validatedLocation || null;\n      applyCatalogPresentation();\n      serviceInputs().forEach((input) => {\n        input.checked = restored.services.includes(input.value);\n      });\n      updateServiceAvailability();\n\n      savedConfigurations = new Map(\n        restored.configurations.map((configuration) => [configuration.service, configuration]),\n      );\n      serverRevision = restored.serverRevision;\n      activePackage = restored.package || null;\n      applyPackagePresentation();\n      currentStep = restored.currentStep;\n      // A staff-assigned package can be the whole quote (a custom product\n      // line with no standard services beside it) \u2014 a priced review step\n      // with a package stays put instead of bouncing back to service picks.\n      const packageOnlyQuote = Boolean(\n        restored.quote\n        && (\n          restored.package\n          || (Array.isArray(restored.quote.lineItems)\n            && restored.quote.lineItems.some((lineItem) => (\n              typeof lineItem?.code === 'string' && lineItem.code.startsWith('bundle.')\n            )))\n        ),\n      );\n      if (currentStep >= 6 && selectedServices().length === 0 && !packageOnlyQuote) currentStep = 5;\n      if (currentStep >= 6) renderConfigurations();\n\n      // The lock only holds while there is a quote to show \u2014 a stale flag\n      // with nothing to render degrades to the normal editable funnel.\n      staffQuoteLocked = restored.staffQuoteLocked === true && Boolean(restored.quote);\n      payByInvoice = restored.payByInvoice === true;\n      invoiceWithoutAgreement = restored.invoiceWithoutAgreement === true;\n      paymentPathPick = restored.paymentPathPick || null;\n      // Quote Options survive reloads with the client's pick; the active\n      // option's quote becomes the rendered (and checkout-targeted) one.\n      quoteOptions = restored.quoteOptions || [];\n      selectedQuoteOptionKey = restored.selectedOptionKey || null;\n      optionChoicePending = quoteOptions.length > 1 && !selectedQuoteOptionKey;\n      applyStaffQuoteLockPresentation();\n      applyPayByInvoiceIfSet();\n\n      latestQuote = restored.quote;\n      if (quoteOptions.length > 1) {\n        const activeOption = model.activeStaffQuoteOption(\n          quoteOptions,\n          selectedQuoteOptionKey,\n        );\n        if (activeOption) latestQuote = activeOption.quote;\n      }\n      if (currentStep === 7) {\n        if (latestQuote) {\n          renderQuote(latestQuote);\n          renderQuoteOptionCards();\n        } else currentStep = activePackage ? 4 : 6;\n      }\n\n      return currentStep > 1\n        || restored.services.length > 0\n        || Object.values(restored.answers).some(Boolean);\n    };\n\n    const trackRecommendationViewed = (quote, facts) => {\n      enqueueFunnelEvent('recommendation_viewed', {\n        step: stepDescriptor(7),\n        properties: {\n          viewportClass: viewportClass(),\n          eventClass: facts.eventType === 'wedding' ? 'wedding' : 'non_wedding',\n          attendanceBand: attendanceBand(facts.attendance),\n          distanceBand: distanceBand(quote.calculationTrace.travelTier),\n          activationCount: quote.calculationTrace.activationCount,\n          serviceCodes: [...new Set(facts.activations.map((activation) => activation.service))].slice(0, 3),\n          outcome: quote.outcome,\n          complexityCodes: quote.complexityReasons,\n          catalogVersion: quote.catalogVersion,\n          amountBand: amountBand(quote.taxableSubtotalCents),\n        },\n      });\n    };\n\n    const saveQuoteContact = async () => {\n      const session = await ensureQuoteSession();\n      const body = {\n        contact: {\n          name: root.querySelector('[name=\"name\"]').value.trim(),\n          email: root.querySelector('[name=\"email\"]').value.trim(),\n        },\n        purpose: 'requested_quote',\n      };\n      const contactFingerprint = JSON.stringify(body);\n      const latestSession = readQuoteSession() || session;\n      const idempotencyKey = latestSession.contactFingerprint === contactFingerprint\n        && latestSession.contactIdempotencyKey\n        ? latestSession.contactIdempotencyKey\n        : randomId();\n      writeQuoteSession({\n        ...latestSession,\n        contactFingerprint,\n        contactIdempotencyKey: idempotencyKey,\n      });\n\n      const label = saveContactButton.querySelector('span');\n      const controller = new AbortController();\n      const timeout = window.setTimeout(() => controller.abort(), 10_000);\n      saveContactButton.disabled = true;\n      label.textContent = 'Saving your quote\u2026';\n      setMessage();\n\n      try {\n        const response = await fetch(`${sessionEndpoint}/${encodeURIComponent(session.token)}`, {\n          method: 'PATCH',\n          headers: {\n            authorization: `Bearer ${activeAccess.token}`,\n            'content-type': 'application/json',\n            'idempotency-key': idempotencyKey,\n          },\n          body: JSON.stringify(body),\n          signal: controller.signal,\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.contact) {\n          if (payload.code === 'quote_contact_full_name_required') {\n            const nameInput = root.querySelector('[name=\"name\"]');\n            nameInput.setCustomValidity('Enter your first and last name');\n            nameInput.reportValidity();\n            nameInput.addEventListener('input', () => nameInput.setCustomValidity(''), { once: true });\n            throw new Error('Enter your first and last name so we can save your quote.');\n          }\n          if (response.status === 401 || response.status === 410) {\n            removeSessionValue(accessStorageKey);\n            removeSessionValue(quoteSessionStorageKey);\n            throw new Error('Your quote session expired. Refresh and try again.');\n          }\n          throw new Error('We couldn\u2019t save your quote yet. Your answers are safe in this tab\u2014try again.');\n        }\n        const stored = readQuoteSession();\n        if (stored) {\n          writeQuoteSession({\n            ...stored,\n            contactSavedAt: payload.contact.savedAt,\n          });\n        }\n      } finally {\n        window.clearTimeout(timeout);\n        saveContactButton.disabled = false;\n        label.textContent = 'Save my quote';\n      }\n    };\n\n    const validateEventLocation = async () => {\n      const eventLocation = locationInput?.value.trim() || '';\n      if (\n        validatedEventLocation?.input === eventLocation &&\n        validatedEventLocation.formattedAddress\n      ) {\n        setLocationStatus(`Found it \u00B7 ${validatedEventLocation.formattedAddress}`, 'success');\n        return validatedEventLocation;\n      }\n\n      const controller = new AbortController();\n      const timeout = window.setTimeout(() => controller.abort(), 12_000);\n      const previousLabel = locationSubmitLabel?.textContent || 'Keep going';\n      if (locationSubmitLabel) locationSubmitLabel.textContent = 'Checking the map\u2026';\n      if (locationSubmitButton) locationSubmitButton.disabled = true;\n      locationInput.disabled = true;\n      setLocationStatus('Checking the map\u2026', 'checking');\n      setMessage();\n\n      try {\n        const session = await ensureQuoteSession();\n        const response = await fetch(\n          `${sessionEndpoint}/${encodeURIComponent(session.token)}/location`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n            },\n            body: JSON.stringify({ eventLocation }),\n            signal: controller.signal,\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.location?.formattedAddress) {\n          if (response.status === 422 && payload.code === 'full_event_address_required') {\n            throw new Error('Add a complete street address or venue so we can confirm travel and sales tax.');\n          }\n          if (response.status === 422) {\n            throw new Error('We couldn\u2019t find that location. Add the venue\u2019s city and state\u2014or use the full street address.');\n          }\n          if (response.status === 401 || response.status === 410) {\n            removeSessionValue(quoteSessionStorageKey);\n            throw new Error('Your quote session expired. Refresh the page and try again.');\n          }\n          throw new Error('We couldn\u2019t check the map right now. Your answers are safe\u2014try again.');\n        }\n\n        validatedEventLocation = {\n          input: eventLocation,\n          ...payload.location,\n        };\n        // A custom address on a referral session keeps standard pricing \u2014\n        // the response's referral.dealApplied === false and the banner shows\n        // the deal-lost notice.\n        if (activeReferral && payload.referral?.dealApplied === false) {\n          referralCustomAddressMode = true;\n        }\n        applyCatalogPresentation();\n        updateServiceAvailability();\n        applyReferralPresentation();\n        persistJourney();\n        setLocationStatus(`Found it \u00B7 ${payload.location.formattedAddress}`, 'success');\n        return validatedEventLocation;\n      } finally {\n        window.clearTimeout(timeout);\n        locationInput.disabled = false;\n        if (locationSubmitButton) locationSubmitButton.disabled = false;\n        if (locationSubmitLabel) locationSubmitLabel.textContent = previousLabel;\n      }\n    };\n\n    const restartQuote = () => {\n      if (!window.confirm('Restart this quote and clear the answers in this tab?')) return;\n      removeSessionValue(journeyStorageKey);\n      removeSessionValue(quoteSessionStorageKey);\n      removeSessionValue(analyticsQueueStorageKey);\n      removeLocalValue(assistantStorageKey);\n      window.location.reload();\n    };\n\n    const submitQuoteHandoff = async ({ recoveryAttempted = false } = {}) => {\n      if (!latestQuote) throw new Error('Build the quote before checking the handoff.');\n      const savedHandoff = readQuoteSession()?.checkoutHandoff;\n      if (\n        savedHandoff?.quoteId === latestQuote.id\n        && savedHandoff?.quoteRevision === latestQuote.revision\n        && savedHandoffMatchesChoice(savedHandoff)\n      ) {\n        if (savedHandoff.status === 'sales_follow_up_requested') {\n          window.location.assign(reviewConfirmationUrl);\n          return;\n        }\n        const savedCheckoutUrl = applyHandoffPresentation(savedHandoff);\n        if (savedCheckoutUrl) {\n          window.location.assign(savedCheckoutUrl);\n          return;\n        }\n      }\n      const session = await ensureQuoteSession();\n      // Community Partner sessions send their explicit card-vs-invoice pick;\n      // everywhere else the body is exactly what it always was.\n      const paymentPath = effectivePaymentPath();\n      const body = {\n        sessionToken: session.token,\n        ...(paymentPath ? { paymentPath } : {}),\n      };\n      const checkoutPreflightFingerprint = `${latestQuote.id}:${latestQuote.revision}:${activeAccess?.mode || 'preview'}${paymentPath ? `:${paymentPath}` : ''}`;\n      const latestSession = readQuoteSession() || session;\n      const idempotencyKey = latestSession.checkoutPreflightFingerprint === checkoutPreflightFingerprint\n        && latestSession.checkoutPreflightIdempotencyKey\n        ? latestSession.checkoutPreflightIdempotencyKey\n        : randomId();\n      writeQuoteSession({\n        ...latestSession,\n        checkoutPreflightFingerprint,\n        checkoutPreflightIdempotencyKey: idempotencyKey,\n      });\n\n      const label = quoteActionButton.querySelector('span');\n      const previousLabel = label.textContent;\n      const controller = new AbortController();\n      const timeout = window.setTimeout(() => controller.abort(), 15_000);\n      quoteActionButton.disabled = true;\n      label.textContent = latestQuote.checkoutEnabled\n        ? activeAccess?.mode === 'checkout'\n          ? latestQuote.taxableSubtotalCents === 0\n            ? 'Completing your free booking\u2026'\n            : paymentPath === 'invoice'\n              ? 'Setting up your invoice\u2026'\n              : 'Preparing secure checkout\u2026'\n          : 'Calculating sales tax\u2026'\n        : 'Saving the handoff\u2026';\n      setMessage();\n      trackStepEvent('quote_step_completed', 7, { interactionSource: 'next' });\n      trackStepEvent('quote_step_viewed', 8, { interactionSource: 'next' });\n      trackStepEvent('checkout_preflight_started', 8, {\n        interactionSource: 'next',\n        outcome: latestQuote.outcome,\n      });\n\n      try {\n        const response = await fetch(\n          `${proxyPath}/quotes/${encodeURIComponent(latestQuote.id)}/checkout`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${activeAccess.token}`,\n              'content-type': 'application/json',\n              'idempotency-key': idempotencyKey,\n            },\n            body: JSON.stringify(body),\n            signal: controller.signal,\n          },\n        );\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.handoff) {\n          if (response.status === 401 || response.status === 410) {\n            removeSessionValue(accessStorageKey);\n            removeSessionValue(quoteSessionStorageKey);\n            throw new Error('That quote session expired. Refresh and rebuild it.');\n          }\n          const conflict = model.checkoutConflictResolution(response.status, payload);\n          if (conflict?.action === 'recalculate' && !recoveryAttempted) {\n            setMessage(conflict.message);\n            await calculateServerQuote({ forceFresh: true });\n            return submitQuoteHandoff({ recoveryAttempted: true });\n          }\n          if (conflict?.action === 'retry' && !recoveryAttempted) {\n            const retrySession = readQuoteSession();\n            if (retrySession) {\n              writeQuoteSession({\n                ...retrySession,\n                checkoutPreflightFingerprint: null,\n                checkoutPreflightIdempotencyKey: null,\n              });\n            }\n            setMessage(conflict.message);\n            return submitQuoteHandoff({ recoveryAttempted: true });\n          }\n          if (conflict) {\n            throw new Error(conflict.message);\n          }\n          throw new Error('We couldn\u2019t save that handoff yet. Your quote is still safe in this tab\u2014try again.');\n        }\n        const stored = readQuoteSession();\n        if (stored) {\n          writeQuoteSession({ ...stored, checkoutHandoff: payload.handoff });\n        }\n        const checkoutUrl = applyHandoffPresentation(payload.handoff);\n        trackStepEvent('quote_step_completed', 8, { interactionSource: 'next' });\n        trackStepEvent(\n          payload.handoff.status === 'sales_follow_up_requested'\n            ? 'sales_handoff_requested'\n            : 'checkout_preflight_completed',\n          8,\n          { interactionSource: 'next', outcome: latestQuote.outcome },\n        );\n        if (payload.handoff.status === 'sales_follow_up_requested') {\n          window.location.assign(reviewConfirmationUrl);\n          return;\n        }\n        if (payload.handoff.status === 'checkout_ready' && !checkoutUrl) {\n          throw new Error('We saved the booking, but couldn\u2019t verify its secure Shopify checkout link. Try again.');\n        }\n      } catch (error) {\n        label.textContent = previousLabel;\n        quoteActionButton.disabled = false;\n        trackStepEvent('checkout_preflight_failed', 8, {\n          interactionSource: 'next',\n          outcome: latestQuote.outcome,\n        });\n        throw error;\n      } finally {\n        window.clearTimeout(timeout);\n      }\n    };\n\n    const calculateServerQuote = async ({ forceFresh = false } = {}) => {\n      const session = await ensureQuoteSession();\n      const facts = model.buildPreviewFacts({\n        eventType: selectedEventType(),\n        eventDate: root.querySelector('[name=\"event_date\"]').value,\n        eventLocation: root.querySelector('[name=\"event_location\"]').value,\n        eventTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'America/Los_Angeles',\n        attendance: Number(root.querySelector('[name=\"attendance\"]').value),\n        // Present only when the guest picked one of the partner's venues;\n        // custom addresses omit it and price standard.\n        referralLocationId: validatedEventLocation?.referralLocationId,\n        // Package sessions never render configuration cards (step 6 is\n        // skipped), so fall back to the seeded configurations.\n        configurations: journeyConfigurations(),\n      });\n      const body = { previewFacts: facts };\n      const fingerprint = JSON.stringify(body);\n      const latestSession = readQuoteSession() || session;\n      const idempotencyKey = !forceFresh && latestSession.calculationFingerprint === fingerprint\n        ? latestSession.calculationIdempotencyKey\n        : randomId();\n      writeQuoteSession({\n        ...latestSession,\n        calculationFingerprint: fingerprint,\n        calculationIdempotencyKey: idempotencyKey,\n      });\n\n      const controller = new AbortController();\n      const timeout = window.setTimeout(() => controller.abort(), 20_000);\n      const label = calculateButton.querySelector('span');\n      calculateButton.disabled = true;\n      label.textContent = 'Measuring the miles\u2026';\n      setMessage();\n\n      try {\n        const response = await fetch(`${sessionEndpoint}/${encodeURIComponent(session.token)}/calculate`, {\n          method: 'POST',\n          headers: {\n            authorization: `Bearer ${activeAccess.token}`,\n            'content-type': 'application/json',\n            'idempotency-key': idempotencyKey,\n          },\n          body: JSON.stringify(body),\n          signal: controller.signal,\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.quote) {\n          if (response.status === 422) {\n            throw new Error('We couldn\u2019t place that location. Add the city and state\u2014or use the full venue address.');\n          }\n          if (response.status === 401 || response.status === 410) {\n            removeSessionValue(accessStorageKey);\n            removeSessionValue(quoteSessionStorageKey);\n            throw new Error('Your quote session expired. Refresh and try again.');\n          }\n          throw new Error('We couldn\u2019t build that estimate yet. Check the details and give it another try.');\n        }\n        const stored = readQuoteSession();\n        if (stored) {\n          writeQuoteSession({\n            ...stored,\n            quoteId: payload.quote.id,\n            quoteRevision: payload.quote.revision,\n            quoteExpiresAt: payload.quote.expiresAt,\n          });\n        }\n        // A Community Partner's quote can lift them into the next rung\n        // (their own booking counts toward it), so the server reports the\n        // tier that actually priced. Adopt it before re-rendering, or the\n        // banner would name a rung that disagrees with the discount shown.\n        if (activeReferral && payload.referralTier) {\n          const lifted = model.normalizeReferralOffer({\n            ...activeReferral,\n            tier: payload.referralTier,\n            deal: {\n              ...activeReferral.deal,\n              percentOffBps: payload.referralTier.rateBps,\n            },\n          });\n          if (lifted) {\n            activeReferral = lifted;\n            renderReferralBanner();\n          }\n        }\n        // Quote Options: the client's edit forked onto THEIR card server-side,\n        // so refresh that card's price in place \u2014 otherwise the comparison\n        // keeps showing the pre-edit figure while the detail pane shows the\n        // new one. Their edit also counts as choosing their own build.\n        if (quoteOptions.length > 1) {\n          const owned = quoteOptions.find((option) => option.origin === 'client');\n          if (owned) {\n            owned.quote = payload.quote;\n            selectedQuoteOptionKey = owned.key;\n            optionChoicePending = false;\n            renderQuoteOptionCards();\n          }\n        }\n        renderQuote(payload.quote);\n        return { quote: payload.quote, facts };\n      } finally {\n        window.clearTimeout(timeout);\n        calculateButton.disabled = false;\n        label.textContent = 'Build my quote';\n      }\n    };\n\n    const requestPublicAccess = async () => {\n      setMessage();\n      const controller = new AbortController();\n      const timeout = window.setTimeout(() => controller.abort(), 10_000);\n      accessStatus.textContent = 'Opening the quote builder\u2026';\n      accessRetry.hidden = true;\n      accessRetry.disabled = true;\n\n      try {\n        const response = await fetch(accessEndpoint, {\n          method: 'POST',\n          headers: { 'content-type': 'application/json' },\n          body: JSON.stringify({}),\n          signal: controller.signal,\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.token || !payload.mode || !payload.expiresAt) {\n          throw new Error('We couldn\u2019t open the quote builder. Try again in a moment.');\n        }\n\n        const access = {\n          token: payload.token,\n          mode: payload.mode,\n          expiresAt: payload.expiresAt,\n        };\n        writeAccess(access);\n        unlock(access);\n      } catch (error) {\n        accessStatus.textContent = error.name === 'AbortError'\n          ? 'That took too long. Give it another try.'\n          : error.message;\n        accessRetry.hidden = false;\n      } finally {\n        window.clearTimeout(timeout);\n        accessRetry.disabled = false;\n      }\n    };\n\n    window.addEventListener('pageshow', (event) => {\n      if (event.persisted) void requestPublicAccess();\n    });\n\n    accessRetry.addEventListener('click', requestPublicAccess);\n\n    servicesContainer.addEventListener('change', (event) => {\n      if (!event.target.matches('[name=\"service\"]')) return;\n      serviceInputs()[0]?.setCustomValidity('');\n      updateServiceAvailability();\n    });\n    root.querySelectorAll('[name=\"event_type\"]').forEach((input) => {\n      input.addEventListener('change', () => {\n        applyCatalogPresentation();\n        updateServiceAvailability();\n      });\n    });\n    restartButton?.addEventListener('click', restartQuote);\n    validatedAddressCorrection?.addEventListener('click', () => {\n      trackStepEvent('quote_step_backtracked', currentStep, {\n        elapsedMs: Date.now() - stepEnteredAt,\n        interactionSource: 'address_correction',\n      });\n      showStep(1, 'address_correction');\n      locationInput?.focus();\n    });\n    const openGlobalSupport = (mode) => {\n      const detail = { mode, context: assistantContext() };\n      if (window.EPSupportChat?.open) {\n        window.EPSupportChat.open(detail);\n      } else {\n        window.dispatchEvent(new CustomEvent('ep:open-support-chat', { detail }));\n      }\n    };\n    assistantTrigger?.addEventListener('click', () => openGlobalSupport('assistant'));\n    assistantContextualTriggers.forEach((button) => {\n      button.addEventListener('click', () => openGlobalSupport('assistant'));\n    });\n    liveSalesStarts.forEach((button) => {\n      button.addEventListener('click', () => openGlobalSupport('sales'));\n    });\n    assistantCloseButtons.forEach((button) => button.addEventListener('click', closeAssistant));\n    if (typeof assistantMobileMedia.addEventListener === 'function') {\n      assistantMobileMedia.addEventListener('change', syncAssistantModality);\n    } else {\n      assistantMobileMedia.addListener(syncAssistantModality);\n    }\n    if (window.visualViewport) {\n      window.visualViewport.addEventListener('resize', syncAssistantViewport);\n      window.visualViewport.addEventListener('scroll', syncAssistantViewport);\n    }\n    assistantDialog?.addEventListener('keydown', (event) => {\n      if (event.key === 'Escape') {\n        event.preventDefault();\n        closeAssistant();\n        return;\n      }\n      if (!assistantMobileMedia.matches || event.key !== 'Tab') return;\n      const focusable = Array.from(assistantDialog.querySelectorAll(\n        'button:not([disabled]), a[href], textarea:not([disabled]), input:not([disabled])',\n      )).filter((element) => !element.hidden && element.tabIndex >= 0);\n      if (focusable.length === 0) 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    assistantSuggestions?.addEventListener('click', (event) => {\n      const suggestion = event.target.closest('[data-assistant-suggestion]');\n      if (!suggestion) return;\n      assistantInput.value = suggestion.dataset.assistantSuggestion;\n      assistantInput.focus();\n    });\n    assistantForm?.addEventListener('submit', async (event) => {\n      event.preventDefault();\n      if (!assistantForm.reportValidity()) return;\n      const question = assistantInput.value;\n      assistantInput.value = '';\n      if (assistantState.mode === 'sales') await submitLiveSalesMessage(question);\n      else await submitAssistantQuestion(question);\n    });\n    assistantInput?.addEventListener('input', updateLiveSalesTypingFromDraft);\n    assistantInput?.addEventListener('blur', () => {\n      if (assistantState.mode !== 'sales') return;\n      liveSalesTypingLastSentAt = 0;\n      void sendLiveSalesTyping(false);\n    });\n    assistantEmail?.addEventListener('click', async () => {\n      assistantStatus.textContent = '';\n      assistantEmail.disabled = true;\n      try {\n        await submitAssistantHandoff('email');\n        assistantStatus.textContent = 'Sent. Our team has your saved contact and this conversation.';\n        assistantEmail.textContent = 'Sent to our team';\n        trackAssistantInteraction('assistant_email_handoff_submitted');\n      } catch (error) {\n        assistantEmail.disabled = false;\n        assistantStatus.textContent = error.message;\n      }\n    });\n    assistantCall?.addEventListener('click', () => {\n      trackAssistantInteraction('assistant_call_handoff_clicked');\n      void submitAssistantHandoff('call', { keepalive: true }).catch(() => {\n        // The scheduling link remains useful even when handoff telemetry fails.\n      });\n    });\n    quoteActionButton.addEventListener('click', async () => {\n      try {\n        await submitQuoteHandoff();\n      } catch (error) {\n        setMessage(error.name === 'AbortError'\n          ? 'That check took too long. Your quote is safe\u2014try again.'\n          : error.message);\n      }\n    });\n    workspace.addEventListener('input', persistJourney);\n    workspace.addEventListener('change', persistJourney);\n    locationInput?.addEventListener('input', () => {\n      if (validatedEventLocation?.input !== locationInput.value.trim()) {\n        validatedEventLocation = null;\n        renderValidatedAddressConfirmation();\n        applyCatalogPresentation();\n        updateServiceAvailability();\n        setLocationStatus();\n      }\n    });\n    dateInput?.addEventListener('focus', refreshEventDateWindow);\n    dateInput?.addEventListener('input', () => {\n      dateInput.setCustomValidity('');\n      if (activePackage) applyPackagePresentation();\n    });\n\n    steps.forEach((step) => {\n      if (step.tagName === 'FORM') {\n        step.addEventListener('submit', async (event) => {\n          event.preventDefault();\n          const submittedStep = Number(step.dataset.quoteStep);\n          if (submittedStep === 5) {\n            serviceInputs()[0]?.setCustomValidity(selectedServices().length ? '' : 'Choose at least one experience.');\n          }\n          if (submittedStep === 1) validateEventDateInput();\n          if (!step.reportValidity()) {\n            trackStepEvent('quote_validation_failed', submittedStep, {\n              elapsedMs: Date.now() - stepEnteredAt,\n              validationErrorCodes: validationErrorCodes(step),\n            });\n            return;\n          }\n\n          if (submittedStep === 1) {\n            // With the partner picker up and the address input tucked away,\n            // an untouched form has nothing to validate \u2014 point at the picker.\n            if (\n              activeReferral\n              && !validatedEventLocation?.formattedAddress\n              && !locationInput?.value.trim()\n            ) {\n              setLocationStatus(\n                `Pick a ${activeReferral.name} venue \u2014 or tap \u201CSomewhere else\u201D to type your address.`,\n                'error',\n              );\n              trackStepEvent('quote_validation_failed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                validationErrorCodes: ['location_required'],\n              });\n              return;\n            }\n            try {\n              await validateEventLocation();\n              await saveJourneySnapshot(submittedStep);\n              trackStepEvent('quote_step_completed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                interactionSource: 'next',\n              });\n              showStep(2);\n            } catch (error) {\n              setLocationStatus(\n                error.name === 'AbortError'\n                  ? 'The map check took too long. Try that address again.'\n                  : error.message,\n                'error',\n              );\n              trackStepEvent('quote_validation_failed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                validationErrorCodes: ['location_unverified'],\n              });\n              locationInput.focus();\n            }\n            return;\n          }\n\n          if (submittedStep === 6) {\n            try {\n              const result = await calculateServerQuote();\n              await saveJourneySnapshot(submittedStep);\n              trackStepEvent('quote_step_completed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                interactionSource: 'next',\n              });\n              showStep(7);\n              trackRecommendationViewed(result.quote, result.facts);\n            } catch (error) {\n              setMessage(error.name === 'AbortError' ? 'Mileage took too long to answer. Try that location again.' : error.message);\n            }\n            return;\n          }\n\n          if (submittedStep === 2) {\n            try {\n              await saveQuoteContact();\n              await saveJourneySnapshot(submittedStep);\n              trackStepEvent('quote_step_completed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                interactionSource: 'next',\n              });\n              trackStepEvent('contact_saved', submittedStep, { interactionSource: 'next' });\n              showStep(activePackage ? 4 : 3);\n            } catch (error) {\n              setMessage(error.name === 'AbortError'\n                ? 'Saving took too long. Your answers are safe in this tab\u2014try again.'\n                : error.message);\n            }\n            return;\n          }\n\n          if (submittedStep === 4 && activePackage) {\n            // Package sessions skip experiences + configuration: guest count\n            // was the last question, so price the seeded package and land on\n            // the review step \u2014 same path step 6 takes in the full funnel.\n            try {\n              const result = await calculateServerQuote();\n              await saveJourneySnapshot(submittedStep);\n              trackStepEvent('quote_step_completed', submittedStep, {\n                elapsedMs: Date.now() - stepEnteredAt,\n                interactionSource: 'next',\n              });\n              showStep(7);\n              trackRecommendationViewed(result.quote, result.facts);\n            } catch (error) {\n              setMessage(error.name === 'AbortError' ? 'Mileage took too long to answer. Try that location again.' : error.message);\n            }\n            return;\n          }\n\n          trackStepEvent('quote_step_completed', submittedStep, {\n            elapsedMs: Date.now() - stepEnteredAt,\n            interactionSource: 'next',\n          });\n          await saveJourneySnapshot(submittedStep);\n          if (submittedStep === 5) renderConfigurations();\n          showStep(submittedStep + 1);\n        });\n      }\n      step.querySelector('[data-quote-back]')?.addEventListener('click', () => {\n        const previousStep = currentStep;\n        if (previousStep === 6) captureConfigurations();\n        trackStepEvent('quote_step_backtracked', previousStep, {\n          elapsedMs: Date.now() - stepEnteredAt,\n          interactionSource: 'back',\n        });\n        const packageBackTargets = { 7: 4, 4: 2 };\n        showStep(\n          activePackage\n            ? packageBackTargets[previousStep] ?? previousStep - 1\n            : previousStep - 1,\n          'back',\n        );\n      });\n    });\n\n    window.addEventListener(consentChangedEvent, (event) => {\n      if (!event.detail?.analytics) {\n        writeAnalyticsQueue([]);\n        return;\n      }\n      queueQuoteStarted();\n      trackStepEvent('quote_step_viewed', currentStep, {\n        interactionSource: 'consent_granted',\n      });\n      void flushAnalyticsQueue();\n    });\n\n    hasRestoredJourney = false;\n    const epResumeKey = (() => {\n      try {\n        const params = new URLSearchParams(window.location.search);\n        const value = params.get('ep_resume');\n        if (!value || !/^[A-Za-z0-9][A-Za-z0-9._:-]{15,127}$/.test(value)) return null;\n\n        params.delete('ep_resume');\n        const query = params.toString();\n        window.history.replaceState(\n          null,\n          '',\n          `${window.location.pathname}${query ? `?${query}` : ''}${window.location.hash}`,\n        );\n        return value;\n      } catch {\n        return null;\n      }\n    })();\n\n    // A campaign page's package deep link. `ep_resume` wins when both are\n    // present, but the parameter is always stripped from the URL.\n    const epPackageCode = (() => {\n      try {\n        const params = new URLSearchParams(window.location.search);\n        const value = params.get('ep_package');\n        if (value === null) return null;\n\n        params.delete('ep_package');\n        const query = params.toString();\n        window.history.replaceState(\n          null,\n          '',\n          `${window.location.pathname}${query ? `?${query}` : ''}${window.location.hash}`,\n        );\n        if (epResumeKey) return null;\n        return /^[a-z][a-z0-9_]{2,47}$/.test(value) ? value : null;\n      } catch {\n        return null;\n      }\n    })();\n\n    // A referral partner's venue link. Composes with `ep_package` (both may\n    // start the same session); `ep_resume` still wins because the resumed\n    // session's replay already carries its own referral.\n    const epReferralCode = (() => {\n      try {\n        const params = new URLSearchParams(window.location.search);\n        const value = params.get('ep_ref');\n        if (value === null) return null;\n\n        params.delete('ep_ref');\n        const query = params.toString();\n        window.history.replaceState(\n          null,\n          '',\n          `${window.location.pathname}${query ? `?${query}` : ''}${window.location.hash}`,\n        );\n        if (epResumeKey) return null;\n        const normalized = value.trim().toLowerCase();\n        return /^[a-z][a-z0-9_-]{2,47}$/.test(normalized) ? normalized : null;\n      } catch {\n        return null;\n      }\n    })();\n\n    // The finder's \"skip the quiz\" exits tag their referral link with\n    // `ep_direct=1` so the forward at boot lets them through; strip it from\n    // the address bar like the other ep_* params once boot has read it.\n    (() => {\n      try {\n        const params = new URLSearchParams(window.location.search);\n        if (!params.has('ep_direct')) return;\n        params.delete('ep_direct');\n        const query = params.toString();\n        window.history.replaceState(\n          null,\n          '',\n          `${window.location.pathname}${query ? `?${query}` : ''}${window.location.hash}`,\n        );\n      } catch {\n        // Malformed URLs boot normally.\n      }\n    })();\n\n    const ensureBootAccess = async () => {\n      let access = readAccess();\n      if (!access) {\n        const response = await fetch(accessEndpoint, {\n          method: 'POST',\n          headers: { 'content-type': 'application/json' },\n          body: JSON.stringify({}),\n        });\n        const payload = await response.json().catch(() => ({}));\n        if (!response.ok || !payload.token || !payload.mode || !payload.expiresAt) return null;\n        access = {\n          token: payload.token,\n          mode: payload.mode,\n          expiresAt: payload.expiresAt,\n        };\n        writeAccess(access);\n      }\n      activeAccess = access;\n      return access;\n    };\n\n    const seedPackageJourney = async () => {\n      try {\n        // A reload mid-funnel must not reset progress: keep the existing\n        // journey when it already belongs to this same package (and, when a\n        // referral rides along, the same partner).\n        const existingJourney = model.normalizeJourneyState(readSessionJson(journeyStorageKey));\n        const existingSession = readQuoteSession();\n        if (\n          existingJourney?.package?.code === epPackageCode\n          && existingSession?.token\n          && (!epReferralCode || existingSession.referralCode === epReferralCode)\n        ) return;\n\n        const access = await ensureBootAccess();\n        if (!access) return;\n\n        removeSessionValue(journeyStorageKey);\n        removeSessionValue(quoteSessionStorageKey);\n        removeSessionValue(analyticsQueueStorageKey);\n        writeQuoteSession({\n          startIdempotencyKey: randomId(),\n          packageCode: epPackageCode,\n          ...(epReferralCode ? { referralCode: epReferralCode } : {}),\n        });\n        const session = await ensureQuoteSession();\n        if (epReferralCode && !session.referral) renderReferralFallbackNotice();\n        const offer = session.package || null;\n        if (!offer) {\n          // Dead link (campaign over, unknown code): boot the normal funnel\n          // with a notice instead of a dead end.\n          renderPackageFallbackNotice();\n          return;\n        }\n\n        const { eventType, services, configurations, ...display } = offer;\n        writeSessionJson(journeyStorageKey, {\n          version: 1,\n          currentStep: 1,\n          serverRevision: 0,\n          answers: { event_type: eventType },\n          services,\n          configurations,\n          package: display,\n          quote: null,\n        });\n      } catch {\n        // An unreachable package lookup falls through to the normal\n        // fresh-funnel boot below.\n      }\n    };\n\n    const seedReferralSession = async () => {\n      try {\n        // A reload mid-funnel must not reset progress: keep the existing\n        // session when it already belongs to this same partner link.\n        const existingSession = readQuoteSession();\n        if (existingSession?.referralCode === epReferralCode && existingSession?.token) return;\n\n        const access = await ensureBootAccess();\n        if (!access) return;\n\n        removeSessionValue(journeyStorageKey);\n        removeSessionValue(quoteSessionStorageKey);\n        removeSessionValue(analyticsQueueStorageKey);\n        writeQuoteSession({ startIdempotencyKey: randomId(), referralCode: epReferralCode });\n        const session = await ensureQuoteSession();\n        if (!session.referral) {\n          // Dead link (unknown code or deactivated partner): boot the normal\n          // funnel with a notice instead of a dead end.\n          renderReferralFallbackNotice();\n        }\n      } catch {\n        // An unreachable referral lookup falls through to the normal\n        // fresh-funnel boot below.\n      }\n    };\n\n    const refreshJourneyFromServer = async () => {\n      try {\n        const access = await ensureBootAccess();\n        if (!access) return;\n\n        if (epResumeKey) {\n          removeSessionValue(journeyStorageKey);\n          removeSessionValue(quoteSessionStorageKey);\n          removeSessionValue(analyticsQueueStorageKey);\n          writeQuoteSession({ startIdempotencyKey: epResumeKey });\n        } else if (!readQuoteSession()?.token) {\n          return;\n        }\n\n        const session = await ensureQuoteSession();\n        const response = await fetch(\n          `${sessionEndpoint}/${encodeURIComponent(session.token)}/resume`,\n          {\n            method: 'POST',\n            headers: {\n              authorization: `Bearer ${access.token}`,\n              'content-type': 'application/json',\n            },\n          },\n        );\n        if (!response.ok) return;\n\n        const payload = await response.json().catch(() => ({}));\n        const latestServerQuote = payload.latestQuote || null;\n        // Staff-built quote: the platform flags the resume payload so the\n        // review step renders locked (view and checkout only).\n        const resumedStaffQuoteLocked = payload.staffQuote?.locked === true;\n        // Top-level now that any quote can take the path; the staffQuote\n        // location is read too so this works either side of the platform\n        // deploy that moved it.\n        const resumedPayByInvoice =\n          (payload.paymentPath ?? payload.staffQuote?.paymentPath) === 'invoice';\n        // \"Invoice only\" deals skip the contract. Read only beside the invoice\n        // path; a platform that predates the field simply leaves it absent.\n        const resumedInvoiceWithoutAgreement =\n          resumedPayByInvoice && payload.invoiceWithoutAgreement === true;\n        // Quote Options: every option's head rides in the payload, now on a\n        // top-level block because a funnel cart carries them too. The older\n        // `staffQuote.options` mirror is still read so a theme deployed ahead\n        // of the platform keeps working. The blob stores them raw;\n        // normalizeJourneyState validates on read, so a malformed entry\n        // degrades to the single representative quote.\n        const resumedOptions = Array.isArray(payload.quoteOptions?.options)\n          ? payload.quoteOptions.options\n          : resumedStaffQuoteLocked && Array.isArray(payload.staffQuote?.options)\n            ? payload.staffQuote.options\n            : [];\n        const resumedSelectedOptionKey = typeof payload.quoteOptions?.selectedOptionKey === 'string'\n          ? payload.quoteOptions.selectedOptionKey\n          : resumedOptions.find((option) => option?.selected === true)?.key;\n        const nextServerRevision = Number(payload.serverRevision) || 0;\n        const snapshot = payload.journeyLatestSnapshot || {};\n        const answers = snapshot.answers || {};\n        const eventInput = payload.eventInput || {};\n        const clamp = (value) => String(value ?? '').slice(0, 500);\n        const completedStep = Number(snapshot.step?.number) || 0;\n        const travelMiles = Number(eventInput.travelMiles);\n        // A referral session resumes with its partner attached (the replay\n        // returns `referral` again); when the saved address is one of the\n        // partner's venues the pick \u2014 and the deal \u2014 survives the resume.\n        const resumedReferralLocation = (readQuoteSession()?.referral?.locations || []).find(\n          (location) => location.formattedAddress\n            && location.formattedAddress === snapshot.validatedLocation?.formattedAddress,\n        );\n        const validatedLocation = snapshot.validatedLocation?.formattedAddress\n          && Number.isFinite(travelMiles)\n          && travelMiles >= 0\n          ? {\n              input: clamp(snapshot.validatedLocation.formattedAddress),\n              formattedAddress: clamp(snapshot.validatedLocation.formattedAddress),\n              ...(snapshot.validatedLocation.city\n                ? { city: snapshot.validatedLocation.city }\n                : {}),\n              ...(snapshot.validatedLocation.provinceCode\n                ? { provinceCode: snapshot.validatedLocation.provinceCode }\n                : {}),\n              ...(snapshot.validatedLocation.zip\n                ? { zip: snapshot.validatedLocation.zip }\n                : {}),\n              ...(resumedReferralLocation\n                ? { referralLocationId: resumedReferralLocation.id }\n                : {}),\n              travelMiles,\n            }\n          : null;\n\n        const storedSession = readQuoteSession() || session;\n        writeQuoteSession({\n          ...storedSession,\n          serverRevision: nextServerRevision,\n          quoteId: latestServerQuote?.id || null,\n          quoteRevision: latestServerQuote?.revision || null,\n          quoteExpiresAt: latestServerQuote?.expiresAt || null,\n        });\n\n        writeSessionJson(journeyStorageKey, {\n          version: 1,\n          currentStep: latestServerQuote && validatedLocation\n            ? 7\n            : validatedLocation\n              ? Math.max(1, Math.min(6, completedStep + 1))\n            : 1,\n          serverRevision: nextServerRevision,\n          answers: {\n            event_location: clamp(answers.eventLocation || eventInput.eventLocation),\n            event_date: clamp(answers.eventDate || eventInput.eventDate),\n            name: clamp(payload.contact?.name),\n            email: clamp(payload.contact?.email),\n            event_type: clamp(answers.eventType || eventInput.eventType),\n            attendance: clamp(answers.attendance ?? eventInput.attendance ?? ''),\n          },\n          services: Array.isArray(snapshot.selectedServices) ? snapshot.selectedServices : [],\n          configurations: Array.isArray(snapshot.configurations) ? snapshot.configurations : [],\n          ...(validatedLocation ? { validatedLocation } : {}),\n          ...(resumedPayByInvoice && latestServerQuote && validatedLocation\n            ? { payByInvoice: true }\n            : {}),\n          ...(resumedInvoiceWithoutAgreement && latestServerQuote && validatedLocation\n            ? { invoiceWithoutAgreement: true }\n            : {}),\n          // Community Partner sessions: the platform's own record of the\n          // card-vs-invoice choice, so the picker resumes where it was left.\n          ...(payload.paymentPathChoice?.invoiceAvailable === true\n            && latestServerQuote\n            && validatedLocation\n            ? {\n                paymentPathPick: payload.paymentPathChoice.selected === 'invoice'\n                  ? 'invoice'\n                  : 'checkout',\n              }\n            : {}),\n          ...(resumedStaffQuoteLocked && latestServerQuote && validatedLocation\n            ? { staffQuoteLocked: true }\n            : {}),\n          // Options are independent of the lock: a funnel cart the client\n          // built carries them too, and the client keeps editing there.\n          ...(resumedOptions.length > 1 && latestServerQuote && validatedLocation\n            ? {\n                quoteOptions: resumedOptions,\n                ...(typeof resumedSelectedOptionKey === 'string'\n                  ? { selectedOptionKey: resumedSelectedOptionKey }\n                  : {}),\n              }\n            : {}),\n          // The session's package \u2014 deep-linked at start OR assigned by staff\n          // mid-quote. Without it a resumed cart shows a package price with no\n          // package to explain it. normalizeJourneyState validates the shape\n          // and drops anything unusable, so a null/dead package is safe here.\n          ...(payload.package\n            ? {\n                package: {\n                  ...payload.package,\n                  priceNote: payload.package.content?.priceNote,\n                },\n              }\n            : {}),\n          quote: payload.latestQuote || null,\n        });\n      } catch {\n        // Invalid, expired, or unreachable resume links fall through to the\n        // normal fresh-funnel boot below.\n      }\n    };\n\n    const finishBoot = () => {\n      hasRestoredJourney = restoreJourney();\n      activeReferral = readQuoteSession()?.referral || activeReferral;\n      referralCustomAddressMode = model.referralDealLost(activeReferral, validatedEventLocation);\n      applyReferralPresentation();\n      renderAssistantHistory();\n      if (!hasRestoredJourney) updateServiceAvailability();\n      const savedAccess = readAccess();\n      if (savedAccess) unlock(savedAccess);\n      else void requestPublicAccess();\n    };\n\n    if (epResumeKey || (!epPackageCode && !epReferralCode && readQuoteSession()?.token)) {\n      void refreshJourneyFromServer().finally(finishBoot);\n    } else if (epPackageCode) {\n      // A package link replaces any in-progress session \u2014 the guest clicked\n      // a campaign offer and expects that offer.\n      void seedPackageJourney().finally(finishBoot);\n    } else if (epReferralCode) {\n      // Same for a bare referral link: the guest expects the partner offer.\n      void seedReferralSession().finally(finishBoot);\n    }\n    else finishBoot();\n  };\n\n  const initializeAll = (scope = document) => {\n    scope.querySelectorAll('[data-instant-quoter]').forEach(initializeQuoter);\n  };\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', () => initializeAll(), { once: true });\n  } else {\n    initializeAll();\n  }\n\n  document.addEventListener('shopify:section:load', (event) => initializeAll(event.target));\n})();\n"],
  "mappings": "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",
  "names": ["message", "configurations"]
}
