{
  "version": 3,
  "sources": ["/cdn/shop/t/66/assets/summit-800-modal.js?cb=20260314v1"],
  "sourcesContent": ["/**\n * Product Configurator JavaScript\n * Handles variant selection, step transitions, and configuration options\n * Reusable across different products (Summit, Studio Shed, etc.)\n */\n\nconst DEBUG = false;\nconst log = (...args) => DEBUG && console.log(...args);\nconst log800 = (...args) => DEBUG && console.log('[Summit800]', ...args);\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\nconst $ = (sel, ctx = document) => ctx.querySelector(sel);\nconst $$ = (sel, ctx = document) => ctx.querySelectorAll(sel);\n\n/** Query with data-attribute fallback to class selector */\nconst q = (dataAttr, classSelector, ctx = document) =>\n  $(dataAttr, ctx) || $(classSelector, ctx);\n\nconst qa = (dataAttr, classSelector, ctx = document) => {\n  const result = $$(dataAttr, ctx);\n  return result.length > 0 ? result : $$(classSelector, ctx);\n};\n\n// DRY: shared in `assets/configurator-shared.js`\nconst normalizeNumber = (...args) => window.ConfiguratorShared.normalizeNumber(...args);\nconst formatPrice = (dollars) => window.ConfiguratorShared.formatMoneyFromDollars(dollars, { noDecimals: true });\n\n/** Format option value for display (kebab-case to Title Case) */\nconst formatOptionValue = (value) => value ? value.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(' ') : '';\n\n/** Format section key to display name */\nconst formatSectionName = (key) => key.split(/[-_]/).map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(' ');\n\n/** Extract mesh groups array from various formats */\nconst extractMeshGroups = (mg) => {\n  if (!mg) return [];\n  if (Array.isArray(mg)) return mg;\n  if (mg.enabled) return mg.enabled;\n  return [];\n};\n\n// ============================================================================\n// PRODUCT CONFIGURATOR CLASS\n// ============================================================================\n\nclass Summit800ProductConfigurator {\n  static DISPLAY_NAME_OVERRIDES = {\n    exterior: 'Glass', roof: 'Roof', siding: 'Siding',\n    layout: 'Layout', kitchen: 'Kitchen', orientation: 'Orientation'\n  };\n\n  static SECTION_GROUPS = {\n    'Flooring': ['mainFloorFinish', 'bathFloorFinish', 'flooring'],\n    'Finishes': ['fixtureFinish', 'counterFinish', 'cabinetFinish', 'finishes']\n  };\n\n  // NOTE: Installation options and FAQ should be configured in theme customization or variant metafield JSON\n  // Access via: this.modelConfig?.services?.installation?.options or this.modelConfig?.faq\n\n  constructor() {\n    this.step1Section = q('[data-configurator-step=\"1\"]', '.summit-800-step-1');\n    this.step2Section = q('[data-configurator-step=\"2\"]', '[data-summit-800-step-2]');\n\n    if (!this.step1Section) return;\n\n    this.variantCards = qa('[data-variant-card]', '.summit-variant-card', this.step1Section);\n    this.priceDisplay = $('[data-product-price]', this.step1Section);\n    this.thumbnails = qa('[data-product-thumbnail]', '.summit-thumbnail', this.step1Section);\n\n    // Get main image from Swiper structure or fallback to original selector\n    const mainSwiperEl = this.step1Section?.querySelector('[data-product-main-swiper]');\n    if (mainSwiperEl) {\n      const firstSlide = mainSwiperEl.querySelector('swiper-slide');\n      this.mainImage = firstSlide?.querySelector('[data-product-main-image]') ||\n        q('[data-product-main-image]', '.summit-main-image', this.step1Section);\n    } else {\n      this.mainImage = q('[data-product-main-image]', '.summit-main-image', this.step1Section);\n    }\n\n    this.radioButtons = $$('input[type=\"radio\"][name=\"variant-selection\"]', this.step1Section);\n    this.designOwnBtn = $('[data-design-your-own]', this.step1Section);\n\n    this.currentConfig = {};\n    this.basePrice = 0;\n    this.configPrice = 0;\n    this.permitPlanSelected = 'include';\n    this.permitPlanPrice = 0;\n    this.foundationTypeSelected = 'wood-frame';\n    this.userFormData = null;\n    this.finalPriceData = null;\n    this.finalPriceFetchTimer = null;\n    this.finalPriceAbort = null;\n    this.finalPriceLastPayloadKey = null;\n    this.steps = [];\n    this.currentStep = 1;\n    this.selectedVariant = null;\n    this.disableAutoMtl = true;\n\n    if (this.variantCards.length === 0) return;\n    this.init();\n  }\n\n  init() {\n    this.setupVariantSelection();\n    this.setupRadioChangeEvents();\n    this.setupThumbnailSwitching();\n    this.setupDesignOwnButton();\n    this.setupPermitPlansDrawer();\n    this.setupFoundationTypeDrawer();\n\n    // Initialize slider \u2014 start on 2nd image (index 1) on page load\n    // Variant-specific image only shown when user clicks a variant card\n    const selectedCard = this.step1Section?.querySelector('[data-variant-card].selected, .summit-variant-card.selected');\n    if (selectedCard) {\n      const { variantId, variantImageId, variantImageSrc, variantPrice } = selectedCard.dataset;\n\n      this.selectedVariant = { id: variantId, imageId: variantImageId, imageSrc: variantImageSrc };\n      this.basePrice = parseInt(variantPrice, 10) || 0;\n\n      this.waitForSwiperReady().then(() => {\n        const mainSwiperEl = this.step1Section?.querySelector('[data-product-main-swiper]');\n        if (mainSwiperEl?.swiper && mainSwiperEl.swiper.slides.length > 1) {\n          mainSwiperEl.swiper.slideTo(1, 0);\n        }\n      });\n    }\n\n    if (this.step2Section) this.setupStep2();\n  }\n\n  // Wait for Swiper to be ready using event-driven approach\n  waitForSwiperReady() {\n    return new Promise((resolve) => {\n      const mainSwiperEl = this.step1Section?.querySelector('[data-product-main-swiper]');\n      if (!mainSwiperEl) {\n        resolve();\n        return;\n      }\n\n      // Check if already initialized\n      if (mainSwiperEl.swiper) {\n        resolve();\n        return;\n      }\n\n      // Use efficient checking with maximum attempts to prevent infinite loops\n      let attempts = 0;\n      const maxAttempts = 60; // ~1 second at 60fps\n\n      const checkReady = () => {\n        if (mainSwiperEl.swiper) {\n          resolve();\n        } else if (attempts < maxAttempts) {\n          attempts++;\n          requestAnimationFrame(checkReady);\n        } else {\n          // Swiper didn't initialize, resolve anyway to prevent blocking\n          resolve();\n        }\n      };\n\n      // Start checking on next frame\n      requestAnimationFrame(checkReady);\n    });\n  }\n\n  // ============================================================================\n  // STEP 1: VARIANT SELECTION\n  // ============================================================================\n\n  setupVariantSelection() {\n    this.variantCards.forEach(card => {\n      card.addEventListener('click', (e) => {\n        if (e.target.type === 'radio') return;\n        this.handleVariantSelection(card);\n      });\n    });\n  }\n\n  setupRadioChangeEvents() {\n    this.radioButtons.forEach(radio => {\n      radio.addEventListener('change', (e) => {\n        if (e.target.checked) {\n          const card = e.target.closest('[data-variant-card], .summit-variant-card');\n          if (card) this.handleVariantSelection(card);\n        }\n      });\n    });\n  }\n\n  handleVariantSelection(card) {\n    this.variantCards.forEach(c => c.classList.remove('selected'));\n    card.classList.add('selected');\n\n    const radio = card.querySelector('input[type=\"radio\"]');\n    if (radio && !radio.checked) radio.checked = true;\n\n    const { variantId, variantPriceFormatted, variantPrice, variantImageId, variantImageSrc } = card.dataset;\n    this.basePrice = parseInt(variantPrice, 10);\n    this.selectedVariant = { id: variantId, imageId: variantImageId, imageSrc: variantImageSrc };\n\n    if (this.priceDisplay && variantPriceFormatted) {\n      this.priceDisplay.textContent = variantPriceFormatted;\n    }\n\n    // Update Swiper slider with variant image if available\n    if (variantImageId && variantImageSrc) {\n      this.updateSliderForVariant(variantImageId, variantImageSrc);\n    }\n\n    if (variantId) {\n      this.updateURL(variantId);\n      this.dispatchVariantChange(variantId, this.basePrice);\n    }\n  }\n\n  updateSliderForVariant(variantImageId, variantImageSrc) {\n    const mainSwiperEl = this.step1Section?.querySelector('[data-product-main-swiper]');\n    if (!mainSwiperEl) return;\n\n    // Check if Swiper is ready, if not wait using requestAnimationFrame with limit\n    let attempts = 0;\n    const maxAttempts = 60; // ~1 second at 60fps\n\n    const updateSlider = () => {\n      if (mainSwiperEl.swiper) {\n        const mainSwiper = mainSwiperEl.swiper;\n\n        // Find the slide that matches the variant image ID\n        let targetSlideIndex = -1;\n        mainSwiper.slides.forEach((slide, index) => {\n          const img = slide.querySelector('[data-product-main-image]');\n          if (img && img.dataset.mediaId === variantImageId) {\n            targetSlideIndex = index;\n          }\n        });\n\n        if (targetSlideIndex >= 0) {\n          // Navigate to the existing slide with variant image\n          mainSwiper.slideTo(targetSlideIndex);\n\n          // Update thumbnail active state and position\n          const thumbnailsSwiperEl = this.step1Section?.querySelector('[data-product-thumbnails-swiper]');\n\n          if (thumbnailsSwiperEl && thumbnailsSwiperEl.swiper) {\n            const thumbnailsSwiper = thumbnailsSwiperEl.swiper;\n\n            // Remove all active classes\n            this.thumbnails.forEach(t => t.classList.remove('active'));\n\n            // Add active class to the thumbnail at the same index\n            if (this.thumbnails[targetSlideIndex]) {\n              this.thumbnails[targetSlideIndex].classList.add('active');\n            }\n\n            // Navigate thumbnail slider to show the active thumbnail\n            thumbnailsSwiper.slideTo(targetSlideIndex);\n          }\n        } else {\n          // Variant image not found in slider, update the first slide\n          const firstSlide = mainSwiper.slides[0];\n          if (firstSlide) {\n            const firstImg = firstSlide.querySelector('[data-product-main-image]');\n            if (firstImg) {\n              firstImg.src = variantImageSrc;\n              firstImg.dataset.mediaId = variantImageId;\n              firstImg.dataset.mediaSrc = variantImageSrc;\n\n              // Update main image reference\n              this.mainImage = firstImg;\n\n              // Navigate to first slide\n              mainSwiper.slideTo(0);\n\n              // Update thumbnail active state\n              const thumbnailsSwiperEl = this.step1Section?.querySelector('[data-product-thumbnails-swiper]');\n              if (thumbnailsSwiperEl && thumbnailsSwiperEl.swiper) {\n                const thumbnailsSwiper = thumbnailsSwiperEl.swiper;\n\n                // Remove all active classes\n                this.thumbnails.forEach(t => t.classList.remove('active'));\n\n                // Add active class to first thumbnail\n                if (this.thumbnails[0]) {\n                  this.thumbnails[0].classList.add('active');\n                }\n\n                // Navigate thumbnail slider to first slide\n                thumbnailsSwiper.slideTo(0);\n              }\n            }\n          }\n        }\n      } else if (attempts < maxAttempts) {\n        attempts++;\n        requestAnimationFrame(updateSlider);\n      }\n    };\n\n    updateSlider();\n  }\n\n  setupDesignOwnButton() {\n    if (!this.designOwnBtn) {\n      const buttons = $$('button, a', this.step1Section);\n      buttons.forEach(btn => {\n        if (btn.textContent.toLowerCase().includes('design your own')) {\n          this.designOwnBtn = btn;\n        }\n      });\n    }\n\n    if (this.designOwnBtn) {\n      this.designOwnBtn.addEventListener('click', (e) => {\n        e.preventDefault();\n        this.hideHeader();\n        this.showStep2();\n      });\n    }\n  }\n\n  hideHeader() {\n    const topbar = document.querySelector('[data-top-bar], .topbar');\n    if (topbar) {\n      // Add transition for smooth animation with longer delay\n      topbar.style.setProperty('transition', 'opacity 0.5s ease-out, transform 0.5s ease-out, max-height 0.5s ease-out', 'important');\n      topbar.style.setProperty('opacity', '0', 'important');\n      topbar.style.setProperty('transform', 'translateY(-100%)', 'important');\n      topbar.style.setProperty('max-height', '0', 'important');\n      topbar.style.setProperty('overflow', 'hidden', 'important');\n      // Hide completely after animation\n      setTimeout(() => {\n        topbar.style.setProperty('display', 'none', 'important');\n      }, 500);\n    }\n  }\n\n  showHeader() {\n    const topbar = document.querySelector('[data-top-bar], .topbar');\n    if (topbar) {\n      // Show element first\n      topbar.style.setProperty('display', '', 'important');\n      // Get original height for smooth transition\n      const originalHeight = topbar.scrollHeight;\n      topbar.style.setProperty('max-height', originalHeight + 'px', 'important');\n      // Add transition for smooth animation with longer delay\n      topbar.style.setProperty('transition', 'opacity 0.5s ease-in, transform 0.5s ease-in, max-height 0.5s ease-in', 'important');\n      // Trigger reflow to ensure initial state is applied\n      void topbar.offsetHeight;\n      // Animate in\n      requestAnimationFrame(() => {\n        topbar.style.setProperty('opacity', '1', 'important');\n        topbar.style.setProperty('transform', 'translateY(0)', 'important');\n        topbar.style.setProperty('overflow', '', 'important');\n      });\n    }\n  }\n\n  setupThumbnailSwitching() {\n    const mainSwiperEl = this.step1Section?.querySelector('[data-product-main-swiper]');\n    const thumbnailsSwiperEl = this.step1Section?.querySelector('[data-product-thumbnails-swiper]');\n\n    // Check if Swiper is available, otherwise fallback to original implementation\n    if (!mainSwiperEl || !thumbnailsSwiperEl) {\n      // Fallback to original implementation if Swiper not available\n      if (!this.thumbnails.length || !this.mainImage) return;\n      this.thumbnails.forEach(thumb => {\n        thumb.addEventListener('click', () => {\n          this.thumbnails.forEach(t => t.classList.remove('active'));\n          thumb.classList.add('active');\n          const newSrc = thumb.dataset.mediaSrc;\n          if (this.mainImage && newSrc) this.mainImage.src = newSrc;\n        });\n      });\n      return;\n    }\n\n    // Wait for Swiper to initialize using requestAnimationFrame with limit\n    let attempts = 0;\n    const maxAttempts = 60; // ~1 second at 60fps\n\n    const initializeSwipers = () => {\n      if (mainSwiperEl.swiper && thumbnailsSwiperEl.swiper) {\n        const mainSwiper = mainSwiperEl.swiper;\n        const thumbnailsSwiper = thumbnailsSwiperEl.swiper;\n\n        // Sync main slider with thumbnail clicks\n        this.thumbnails.forEach((thumb, index) => {\n          thumb.addEventListener('click', () => {\n            // Update active state\n            this.thumbnails.forEach(t => t.classList.remove('active'));\n            thumb.classList.add('active');\n\n            // Get slide index from data attribute or index\n            const slideIndex = parseInt(thumb.dataset.slideIndex || index, 10);\n\n            // Navigate main swiper to corresponding slide\n            mainSwiper.slideTo(slideIndex);\n\n            // Navigate thumbnail swiper to show clicked thumbnail\n            thumbnailsSwiper.slideTo(index);\n\n            // Update main image reference for backward compatibility\n            const mainSlide = mainSwiper.slides[slideIndex];\n            const mainImg = mainSlide?.querySelector('[data-product-main-image]');\n            if (mainImg) {\n              this.mainImage = mainImg; // Update reference\n            }\n          });\n        });\n\n        // Sync thumbnail slider when main slider changes (swipe/arrow navigation)\n        mainSwiper.on('slideChange', () => {\n          const activeIndex = mainSwiper.activeIndex;\n\n          // Update thumbnail active states\n          this.thumbnails.forEach((thumb, index) => {\n            const slideIndex = parseInt(thumb.dataset.slideIndex || index, 10);\n            if (slideIndex === activeIndex) {\n              this.thumbnails.forEach(t => t.classList.remove('active'));\n              thumb.classList.add('active');\n              thumbnailsSwiper.slideTo(index);\n            }\n          });\n\n          // Update main image reference\n          const activeSlide = mainSwiper.slides[activeIndex];\n          const mainImg = activeSlide?.querySelector('[data-product-main-image]');\n          if (mainImg) {\n            this.mainImage = mainImg;\n          }\n        });\n\n        // Sync main slider when thumbnail slider changes (if user swipes thumbnails)\n        thumbnailsSwiper.on('slideChange', () => {\n          const activeThumbIndex = thumbnailsSwiper.activeIndex;\n          const thumb = this.thumbnails[activeThumbIndex];\n          if (thumb) {\n            const slideIndex = parseInt(thumb.dataset.slideIndex || activeThumbIndex, 10);\n            mainSwiper.slideTo(slideIndex);\n          }\n        });\n      } else if (attempts < maxAttempts) {\n        attempts++;\n        requestAnimationFrame(initializeSwipers);\n      }\n    };\n\n    initializeSwipers();\n  }\n\n  // ============================================================================\n  // STEP 2: CONFIGURATOR\n  // ============================================================================\n\n  async showStep2() {\n    const selectedVariantId = this.getSelectedVariantId();\n    if (!selectedVariantId) return;\n\n    this.showLoadingState();\n\n    try {\n      const sectionHTML = await this.fetchStep2Section(selectedVariantId);\n      if (sectionHTML) {\n        this.updateStep2Content(sectionHTML);\n        document.body.classList.add('configurator-active');\n        this.toggleStep2HiddenSections(false); // Hide extra sections in step 2\n        this.setupStep2();\n        this.loadStep2Data();\n        this.hideLoadingState();\n        window.scrollTo({ top: 0, behavior: 'smooth' });\n        ConfiguratorShared.StepHistoryManager.pushStep2(this);\n      } else {\n        this.hideLoadingState();\n      }\n    } catch (error) {\n      console.error('Error loading Step 2:', error);\n      this.hideLoadingState();\n    }\n  }\n\n  /**\n   * Toggle visibility of sections that should be hidden in step 2\n   * @param {boolean} show - true to show sections, false to hide\n   */\n  toggleStep2HiddenSections(show) {\n    const footerForm = document.querySelector('div.newsletter-wrapper');\n    \n    if (footerForm) {\n      footerForm.style.display = show ? '' : 'none';\n    }\n\n    const globalFooterSection = document.getElementById('shopify-section-sections--27394207908134__footer');\n    if (globalFooterSection) {\n      globalFooterSection.style.display = show ? '' : 'none';\n    }\n    \n    const mainContent = document.getElementById('MainContent');\n    if (!mainContent) return;\n    mainContent.style.marginBottom = show ? '' : '120px';\n\n    // Find all Shopify sections\n    const allSections = mainContent.querySelectorAll('[id^=\"shopify-section-\"]');\n\n    allSections.forEach(section => {\n      const sectionId = section.id;\n\n      // Only keep step 2 sections visible, hide everything else\n      // Exclude FAQ section - it's controlled separately by toggleFaqSection\n      const isStep2Section = sectionId.includes('summit_800_step_2') || sectionId.includes('summit-800-step-2');\n      const isFaqSection = sectionId.includes('global_modal_faq') || sectionId.includes('global-modal-faq');\n      \n      if (!isStep2Section && !isFaqSection) {\n        section.style.display = show ? '' : 'none';\n      }\n    });\n  }\n\n  async fetchStep2Section(variantId) {\n    let sectionId = this.step2Section?.dataset?.sectionId;\n    if (!sectionId) {\n      const wrapper = this.step2Section?.closest('[id^=\"shopify-section-\"]');\n      sectionId = wrapper?.id?.replace('shopify-section-', '') || 'summit_step_2';\n    }\n\n    const url = new URL(window.location.href);\n    url.searchParams.set('variant', variantId);\n    url.searchParams.set('section_id', sectionId);\n\n    const response = await fetch(url.toString(), {\n      method: 'GET',\n      headers: { 'X-Requested-With': 'XMLHttpRequest' }\n    });\n\n    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n    return response.text();\n  }\n\n  updateStep2Content(html) {\n    if (!html || !this.step2Section) return;\n\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(html, 'text/html');\n\n    const newSection = doc.querySelector('[data-configurator-step=\"2\"]') ||\n      doc.querySelector('[data-summit-800-step-2]') ||\n      doc.querySelector('.summit-800-step-2') ||\n      doc.querySelector('section');\n\n    if (newSection) {\n      this.step2Section.innerHTML = newSection.innerHTML;\n      if (newSection.dataset.sectionId) {\n        this.step2Section.dataset.sectionId = newSection.dataset.sectionId;\n      }\n      this.step2Section.style.display = 'block';\n    } else {\n      const bodyContent = doc.body.innerHTML;\n      if (bodyContent) {\n        this.step2Section.innerHTML = bodyContent;\n        this.step2Section.style.display = 'block';\n      }\n    }\n  }\n\n  showLoadingState() {\n    if (this.designOwnBtn) {\n      this.designOwnBtn.dataset.originalText = this.designOwnBtn.textContent;\n      this.designOwnBtn.textContent = 'Loading...';\n      this.designOwnBtn.disabled = true;\n    }\n  }\n\n  hideLoadingState() {\n    if (this.designOwnBtn) {\n      this.designOwnBtn.textContent = this.designOwnBtn.dataset.originalText || 'Design Your Own';\n      this.designOwnBtn.disabled = false;\n    }\n  }\n\n  hideStep2({ fromPopstate = false } = {}) {\n    if (!fromPopstate) {\n      ConfiguratorShared.StepHistoryManager.exitStep2();\n      return;\n    }\n\n    document.body.classList.remove('configurator-active');\n    this.toggleStep2HiddenSections(true); // Show extra sections when leaving step 2\n    if (this.viewer3D) {\n      this.viewer3D.dispose();\n      this.viewer3D = null;\n    }\n\n    // Remove product-summary-tab class when closing configurator (Summit-800-specific)\n    const configuratorMain = $('[data-configurator-main]', this.step2Section);\n    if (configuratorMain) {\n      configuratorMain.classList.remove('product-summary-tab');\n    }\n\n    if (this.step2Section) this.step2Section.style.display = 'none';\n    this.hideLoadingState();\n    this.showHeader();\n    this.toggleFaqSection(false);\n    window.scrollTo({ top: 0, behavior: 'smooth' });\n  }\n\n  toggleFaqSection(show) {\n    const faqSectionWrapper = document.querySelector('[id^=\"shopify-section-\"][id*=\"global_modal_faq\"], [id^=\"shopify-section-\"][id*=\"global-modal-faq\"]');\n    const faqSection = document.querySelector('.global-modal-faq-section');\n    const faqFooter = document.querySelector('.modal-faq-footer');\n    const siteFooter = document.querySelector('.site-footer');\n    if (show) {\n      if (faqSectionWrapper) faqSectionWrapper.style.setProperty('display', 'block', 'important');\n      if (faqSection) faqSection.style.setProperty('display', 'block', 'important');\n      if (faqFooter) faqFooter.style.setProperty('display', 'block', 'important');\n      if (siteFooter) siteFooter.style.setProperty('display', 'none', 'important');\n    } else {\n      if (faqSectionWrapper) faqSectionWrapper.style.removeProperty('display');\n      if (faqSection) faqSection.style.removeProperty('display');\n      if (faqFooter) faqFooter.style.removeProperty('display');\n      if (siteFooter) siteFooter.style.removeProperty('display');\n    }\n  }\n\n  setupStep2() {\n    if (!this.step2Section) return;\n\n    if (this.step2ClickHandler) {\n      this.step2Section.removeEventListener('click', this.step2ClickHandler);\n    }\n\n    this.step2ClickHandler = (e) => {\n      // Click on configurator title to go back to step 1\n      if (e.target.closest('[data-configurator-title]')) {\n        e.preventDefault();\n        this.hideStep2();\n        return;\n      }\n\n      const tab = e.target.closest('[data-tab-btn], .tab-btn');\n      if (tab?.dataset.tab) {\n        // Prevent navigation to disabled tabs (e.g., Summary when form not filled)\n        if (tab.disabled || tab.classList.contains('disabled')) {\n          e.preventDefault();\n          return;\n        }\n        this.switchTab(tab.dataset.tab);\n        return;\n      }\n\n      if (e.target.closest('[data-back-step]')) {\n        e.preventDefault();\n        this.goToPreviousTab();\n        return;\n      }\n\n      if (e.target.closest('[data-next-step]')) {\n        e.preventDefault();\n        this.goToNextTab();\n        return;\n      }\n\n      // Handle Save Design button click\n      const saveDesignBtn = e.target.closest('[data-save-design]');\n      if (saveDesignBtn) {\n        e.preventDefault();\n        \n        // Handle Start Over button click\n        if (saveDesignBtn?.dataset.startOver === 'true') {\n          this.handleStartOver();\n          return;\n        }\n        \n        // Get current tab\n        const currentTab = q('[data-tab-btn].active', '.tab-btn.active', this.step2Section)?.dataset.tab;\n        \n        // If already on services tab, try to submit the form\n        if (currentTab === 'services') {\n          if (!this.hasValidUserFormData()) {\n            // Try to submit the form programmatically\n            const form = $('[data-summary-form]', this.step2Section);\n            if (form) {\n              if (form.checkValidity()) {\n                // Form is valid - submit it\n                form.requestSubmit();\n              } else {\n                // Form is invalid - show validation messages and focus first invalid field\n                form.reportValidity();\n                this.focusSaveDesignForm();\n              }\n            } else {\n              this.focusSaveDesignForm();\n            }\n          } else {\n            // Form already submitted, go to summary\n            this.switchTab('summary');\n          }\n          return;\n        }\n        \n        // If not on services tab, redirect to services tab\n        this.switchTab('services');\n        \n        // Scroll to form or installation options after a short delay to ensure content is rendered\n        setTimeout(() => {\n          const form = $('[data-summary-form]', this.step2Section);\n          if (form && form.offsetParent !== null) {\n            // Form is visible, focus on it\n            this.focusSaveDesignForm();\n          } else {\n            // Form not visible yet (user needs to select installation first), focus on installation options\n            this.focusInstallationOptions();\n          }\n        }, 150);\n        \n        return;\n      }\n    };\n\n    this.step2Section.addEventListener('click', this.step2ClickHandler);\n  }\n\n  // ============================================================================\n  // DATA LOADING & INITIALIZATION\n  // ============================================================================\n\n  loadStep2Data() {\n    const modelConfigEl = $('[data-model-config]', this.step2Section);\n    const variantFallbackEl = $('[data-variant-fallback]', this.step2Section);\n    const sectionSettingsEl = $('[data-section-settings]', this.step2Section);\n\n    let modelConfig = null, variantFallback = null, sectionSettings = null;\n\n    try {\n      if (modelConfigEl?.textContent.trim()) {\n        const rawData = modelConfigEl.textContent.trim();\n        modelConfig = rawData.startsWith('\"') && rawData.endsWith('\"')\n          ? JSON.parse(JSON.parse(rawData))\n          : JSON.parse(rawData);\n      }\n    } catch (e) { console.error('Error parsing model config:', e); }\n\n    try {\n      if (variantFallbackEl?.textContent.trim()) {\n        variantFallback = JSON.parse(variantFallbackEl.textContent);\n      }\n    } catch (e) { console.error('Error parsing variant fallback:', e); }\n\n    try {\n      if (sectionSettingsEl?.textContent.trim()) {\n        sectionSettings = JSON.parse(sectionSettingsEl.textContent);\n      }\n    } catch (e) { console.error('Error parsing section settings:', e); }\n\n    // Merge section settings with model config (section settings take priority for services, pricing)\n    this.modelConfig = {\n      ...(modelConfig || {}),\n      ...(sectionSettings || {}),\n      services: {\n        ...(modelConfig?.services || {}),\n        ...(sectionSettings?.services || {})\n      }\n    };\n\n    // Initialize pricing config for combination pricing support\n    this.pricingConfig = modelConfig?.pricing || null;\n    log800('[Summit800] Pricing config loaded:', this.pricingConfig);\n\n    // Normalize model file structures so both legacy (orientation-based) and new Summit formats work\n    this.modelConfig.modelFiles = this.normalizeModelFiles(this.modelConfig.modelFiles);\n    this.modelConfig.models = this.normalizeModelsMap(this.modelConfig.models);\n\n    // Normalize steps\n    this.steps = (modelConfig?.steps || []).map(step => {\n      const normalized = { ...step };\n      if (normalized.options) {\n        Object.keys(normalized.options).forEach(key => {\n          const opt = normalized.options[key];\n          if (opt.choices && !opt.options) {\n            normalized.options[key] = { ...opt, options: opt.choices };\n          }\n        });\n      }\n      return normalized;\n    });\n\n    // Setup model data\n    const topLevelModelFiles = this.modelConfig?.modelFiles;\n    const normalizedModelsMap = this.modelConfig?.models;\n\n    if (topLevelModelFiles && Object.keys(topLevelModelFiles).length) {\n      this.modelsData = {\n        name: this.modelConfig?.name || 'summit-1',\n        size: this.modelConfig?.size,\n        depth: this.modelConfig?.depth,\n        length: this.modelConfig?.length,\n        squareFootage: this.modelConfig?.squareFootage,\n        basePrice: this.modelConfig?.basePrice,\n        description: this.modelConfig?.description,\n        modelFiles: topLevelModelFiles\n      };\n    } else if (normalizedModelsMap && Object.keys(normalizedModelsMap).length) {\n      this.modelsData = normalizedModelsMap;\n    } else {\n      this.modelsData = {};\n    }\n\n    this.texturesData = modelConfig?.textures || {};\n    this.colorsData = modelConfig?.colors || {};\n    this.meshGroupsData = modelConfig?.meshGroups || {};\n    this.defaultConfig = modelConfig?.defaultConfiguration || {};\n\n    const variantInfo = modelConfig?.variantInfo || variantFallback || {};\n    this.basePrice = this.modelsData?.basePrice || variantInfo.price || variantFallback?.price || 0;\n\n    // Store variant documents for downloads section\n    this.variantDocuments = variantFallback?.documents || [];\n\n    // Permit plan price is set to 0 by default (excluded)\n    // User can choose to include it via the permit plans drawer\n\n    this.initializeDefaultConfig();\n    this.updateStep2Header(variantInfo);\n    this.generateTabs();\n    // Disable Summary tab by default until form is submitted\n    this.updateSummaryTabState();\n    this.populateStepOptions(1);\n\n    if (this.modelsData?.modelFiles) {\n      // Use requestAnimationFrame for better performance\n      requestAnimationFrame(() => this.init3DViewer());\n    }\n  }\n\n  initializeDefaultConfig() {\n    this.currentConfig = { ...this.defaultConfig };\n    this.currentStep = 1;\n  }\n\n  /**\n   * Check if Shell package is selected (skip Interior step).\n   * @returns {boolean} True if interiorOptions is \"shell-only\"\n   */\n  isShellPackage() {\n    const interiorOptions = this.currentConfig?.interiorOptions || '';\n    return /shell-only|shell_only|shellonly/i.test(interiorOptions);\n  }\n\n  /**\n   * Get the visible steps based on package type.\n   * Shell packages skip the Interior step.\n   * @returns {Array} Array of visible steps\n   */\n  getVisibleSteps() {\n    if (this.isShellPackage()) {\n      return this.steps.filter(step => {\n        const stepName = (step.name || step.id || '').toLowerCase();\n        return stepName !== 'interior';\n      });\n    }\n    return this.steps;\n  }\n\n  // ============================================================================\n  // TABS & NAVIGATION\n  // ============================================================================\n\n  generateTabs() {\n    const tabsContainer = $('[data-configurator-tabs]', this.step2Section);\n    if (!tabsContainer || !this.steps.length) return;\n\n    tabsContainer.innerHTML = '';\n\n    // Use visible steps (filters out Interior for Shell packages)\n    const visibleSteps = this.getVisibleSteps();\n\n    visibleSteps.forEach((step, index) => {\n      tabsContainer.appendChild(this.createTabButton(step.name, step.step, index === 0));\n    });\n\n    // Services and Summary step numbers should be based on total steps\n    tabsContainer.appendChild(this.createTabButton('Services', this.steps.length + 1, false));\n    tabsContainer.appendChild(this.createTabButton('Summary', this.steps.length + 2, false));\n  }\n\n  createTabButton(name, step, isActive) {\n    const btn = document.createElement('button');\n    btn.className = `tab-btn${isActive ? ' active' : ''}`;\n    btn.setAttribute('data-tab-btn', '');\n    btn.dataset.tab = name.toLowerCase();\n    btn.dataset.step = step;\n    btn.textContent = name;\n    return btn;\n  }\n\n  /**\n   * Enable or disable the Summary tab based on form completion state.\n   * Disabled tabs cannot be clicked and show visual feedback.\n   */\n  updateSummaryTabState() {\n    const summaryTab = q('[data-tab-btn][data-tab=\"summary\"]', '.tab-btn[data-tab=\"summary\"]', this.step2Section);\n    if (!summaryTab) return;\n\n    const isEnabled = this.hasValidUserFormData();\n    summaryTab.disabled = !isEnabled;\n    summaryTab.classList.toggle('disabled', !isEnabled);\n    summaryTab.setAttribute('aria-disabled', String(!isEnabled));\n    \n    if (!isEnabled) {\n      summaryTab.title = 'Complete the installation form to view summary';\n    } else {\n      summaryTab.removeAttribute('title');\n    }\n  }\n\n  switchTab(tabName) {\n    const tabLower = tabName.toLowerCase();\n    \n    // Prevent navigation to Interior step for Shell packages\n    if (tabLower === 'interior' && this.isShellPackage()) return;\n    \n    const step = this.steps.find(s => s.name.toLowerCase() === tabLower);\n    const stepNumber = step?.step;\n\n    // Restore default 8-4 layout when NOT switching to summary (summary uses 6-6 layout)\n    if (tabLower !== 'summary') {\n      this.restoreDefaultLayout();\n    }\n\n    // Update tab buttons\n    qa('[data-tab-btn]', '.tab-btn', this.step2Section).forEach(tab => {\n      tab.classList.toggle('active', tab.dataset.tab === tabLower);\n    });\n\n    // Show/hide FAQ section and footer based on current tab\n    this.toggleFaqSection(tabLower === 'summary');\n\n    // Add/remove product-summary-tab class based on current tab (Summit-800-specific)\n    const configuratorMain = $('[data-configurator-main]', this.step2Section);\n    if (configuratorMain) {\n      if (tabLower === 'summary') {\n        configuratorMain.classList.add('product-summary-tab');\n      } else {\n        configuratorMain.classList.remove('product-summary-tab');\n      }\n    }\n\n    // Reset footer visibility when not on summary\n    if (tabLower !== 'summary') {\n      const panelFooter = q('[data-panel-footer]', '.panel-footer', this.step2Section);\n      if (panelFooter) panelFooter.style.display = '';\n\n      const saveDesignBtn = $('[data-save-design]', this.step2Section);\n      if (saveDesignBtn?.dataset.startOver === 'true') {\n        saveDesignBtn.textContent = 'SAVE DESIGN';\n        delete saveDesignBtn.dataset.startOver;\n      }\n\n      // Show header Save Design button when not on services form (will be hidden again in populateServicesOptions if needed)\n      if (tabLower !== 'services' && saveDesignBtn) {\n        saveDesignBtn.style.display = '';\n      }\n\n      // Pass skipQueueUpdate=true to prevent API calls on tab switch - API should only be called on Services step form submission\n      this.updateTotalPrice(true);\n    }\n\n    // Route to appropriate content\n    if (stepNumber) {\n      this.populateStepOptions(stepNumber);\n      this.update3DViewForStep(tabLower);\n    } else if (tabLower === 'services') {\n      this.populateServicesOptions();\n      this.viewer3D?.setViewForStep(2);\n    } else if (tabLower === 'summary') {\n      this.showSummary();\n      this.viewer3D?.setViewForStep(5);\n    }\n\n    // Scroll to top when switching tabs\n    window.scrollTo({ top: 0, behavior: 'smooth' });\n  }\n\n  update3DViewForStep(stepName) {\n    if (!this.viewer3D) return;\n    // Show top-down view (roof hidden) only for interior and finishes steps (to see inside)\n    // Entry/Window Options, Siding, Services, Summary use front view\n    const isTopDownView = ['interior', 'finishes'].includes(stepName);\n    this.viewer3D.setViewForStep(isTopDownView ? 1 : 2);\n  }\n\n  goToNextTab() {\n    const currentTab = q('[data-tab-btn].active', '.tab-btn.active', this.step2Section)?.dataset.tab;\n\n    if (currentTab === 'services') {\n      if (!this.hasValidUserFormData()) {\n        // Try to submit the form programmatically when clicking SAVE DESIGN button\n        const form = $('[data-summary-form]', this.step2Section);\n        if (form) {\n          if (form.checkValidity()) {\n            // Form is valid - submit it\n            form.requestSubmit();\n          } else {\n            // Form is invalid - show validation messages and focus first invalid field\n            form.reportValidity();\n            this.focusSaveDesignForm();\n          }\n        } else {\n          this.focusSaveDesignForm();\n        }\n        return;\n      }\n      this.switchTab('summary');\n      return;\n    }\n\n    // Use visible steps to skip Interior for Shell packages\n    const visibleSteps = this.getVisibleSteps();\n    const currentVisibleIndex = visibleSteps.findIndex(s => s.step === this.currentStep);\n    const nextVisibleStep = visibleSteps[currentVisibleIndex + 1];\n    this.switchTab(nextVisibleStep?.name || 'services');\n  }\n\n  goToPreviousTab() {\n    const currentTab = q('[data-tab-btn].active', '.tab-btn.active', this.step2Section)?.dataset.tab;\n\n    if (currentTab === 'summary') {\n      this.switchTab('services');\n      return;\n    }\n\n    // Use visible steps to skip Interior for Shell packages\n    const visibleSteps = this.getVisibleSteps();\n\n    if (currentTab === 'services') {\n      const lastVisibleStep = visibleSteps[visibleSteps.length - 1];\n      if (lastVisibleStep) this.switchTab(lastVisibleStep.name);\n      return;\n    }\n\n    if (this.currentStep > 1) {\n      const currentVisibleIndex = visibleSteps.findIndex(s => s.step === this.currentStep);\n      const prevVisibleStep = visibleSteps[currentVisibleIndex - 1];\n      if (prevVisibleStep) this.switchTab(prevVisibleStep.name);\n    }\n  }\n\n  // ============================================================================\n  // STEP OPTIONS RENDERING\n  // ============================================================================\n\n  populateStepOptions(stepNumber) {\n    const step = this.steps.find(s => s.step === stepNumber);\n    if (!step) return;\n\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n\n    contentWrapper.innerHTML = '';\n\n    const panelContent = document.createElement('div');\n    panelContent.className = 'panel-content';\n    panelContent.dataset.tabContent = step.name.toLowerCase();\n\n    const sectionsContainer = document.createElement('div');\n    sectionsContainer.className = 'config-sections-container';\n    sectionsContainer.dataset.configSections = '';\n\n    const stepNameLower = step.name.toLowerCase();\n    const useGrouping = ['interior', 'finishes'].includes(stepNameLower);\n\n    if (step.options) {\n      if (useGrouping) {\n        this.renderGroupedSections(step.options, sectionsContainer);\n      } else {\n        this.renderFlatSections(step.options, sectionsContainer);\n      }\n    }\n\n    // Add Lifestyle interior package info AFTER config sections\n    // Show ONLY on floorplan step (not on exterior or other steps)\n    const isFloorplanStep = stepNameLower.includes('floorplan');\n    if (isFloorplanStep && this.modelConfig?.interiorPackageInfo?.show) {\n      const items = this.modelConfig.interiorPackageInfo.items;\n      // Check if items exists and is not empty (after trimming whitespace)\n      if (items && typeof items === 'string' && items.trim().length > 0) {\n        const infoDiv = document.createElement('div');\n        infoDiv.className = 'portland-interior-package-info';\n        infoDiv.innerHTML = items;\n        sectionsContainer.appendChild(infoDiv);\n        console.log('[Summit-800] Interior package info displayed:', {\n          stepNumber,\n          stepName: stepNameLower,\n          isFloorplanStep,\n          show: this.modelConfig.interiorPackageInfo.show,\n          itemsLength: items.length\n        });\n      } else {\n        console.log('[Summit-800] Interior package info NOT displayed - items empty:', {\n          stepNumber,\n          stepName: stepNameLower,\n          isFloorplanStep,\n          show: this.modelConfig.interiorPackageInfo.show,\n          items: items,\n          itemsType: typeof items,\n          itemsLength: items ? items.length : 0\n        });\n      }\n    } else if (isFloorplanStep) {\n      console.log('[Summit-800] Interior package info NOT displayed - config issue:', {\n        stepNumber,\n        stepName: stepNameLower,\n        isFloorplanStep,\n        hasConfig: !!this.modelConfig?.interiorPackageInfo,\n        show: this.modelConfig?.interiorPackageInfo?.show\n      });\n    }\n\n    panelContent.appendChild(sectionsContainer);\n    contentWrapper.appendChild(panelContent);\n    this.updateNextButtonText(stepNumber);\n    this.currentStep = stepNumber;\n    // Pass skipQueueUpdate=true to prevent API calls on tab switch\n    this.updateTotalPrice(true);\n    \n    // After rendering, update siding color visibility based on current siding type\n    // This ensures cedar types hide the siding color section\n    const currentSidingType = this.currentConfig.siding || this.currentConfig.sidingType || this.defaultConfig.siding;\n    if (currentSidingType) {\n      // Use setTimeout to ensure DOM is fully rendered\n      setTimeout(() => this.updateSidingColorVisibility(currentSidingType), 0);\n    }\n  }\n\n  renderGroupedSections(options, container) {\n    const processedSections = new Set();\n\n    Object.entries(Summit800ProductConfigurator.SECTION_GROUPS).forEach(([groupName, groupKeys]) => {\n      const groupSections = groupKeys\n        .filter(key => options[key] && !this.isHidden(options[key]) && this.hasValidOptions(options[key]))\n        .map(key => ({ key, data: options[key] }));\n\n      if (groupSections.length > 0) {\n        const groupContainer = document.createElement('div');\n        groupContainer.className = 'config-group mb-6';\n\n        const groupHeader = document.createElement('p');\n        groupHeader.className = 'config-group-header fw-medium text-black mb-lg-4 mb-2';\n        groupHeader.textContent = `${groupName}:`;\n        groupContainer.appendChild(groupHeader);\n\n        groupSections.forEach(({ key, data }) => {\n          groupContainer.appendChild(this.createConfigSection(key, data, true));\n          processedSections.add(key);\n        });\n\n        container.appendChild(groupContainer);\n      }\n    });\n\n    // Render remaining sections\n    Object.keys(options).forEach(key => {\n      if (processedSections.has(key)) return;\n      const data = options[key];\n      if (!data || this.isHidden(data, key) || !this.hasValidOptions(data)) return;\n      container.appendChild(this.createConfigSection(key, data));\n    });\n  }\n\n  renderFlatSections(options, container) {\n    Object.keys(options).forEach(key => {\n      const data = options[key];\n      log800(`[Summit800] renderFlatSections checking ${key}:`, {\n        hasData: !!data,\n        isHidden: data ? this.isHidden(data, key) : 'N/A',\n        hasValidOptions: data ? this.hasValidOptions(data) : 'N/A',\n        showWhen: data?.showWhen,\n        optionsCount: data?.options?.length\n      });\n      if (!data || this.isHidden(data, key) || !this.hasValidOptions(data)) return;\n      container.appendChild(this.createConfigSection(key, data));\n    });\n  }\n\n  isHidden(data, sectionKey = '') {\n    if (data.hide === true || data.hide === 'true') return true;\n    \n    // NOTE: Don't check showWhen here - sections with showWhen should be created\n    // but hidden via CSS initially. They will be shown/hidden dynamically by\n    // updateConditionalOptionsVisibility() when conditions change.\n    // This allows the DOM elements to exist so they can be toggled later.\n    \n    return false;\n  }\n  \n  /**\n   * Check if an option should be initially hidden based on showWhen\n   * Used to set initial CSS display state, NOT to prevent DOM creation\n   */\n  shouldBeInitiallyHidden(data) {\n    if (!data.showWhen) return false;\n    return !this.checkShowWhenCondition(data.showWhen);\n  }\n\n  /**\n   * Check if showWhen condition is met\n   * @param {Object} showWhen - Condition object like { \"entryOptions\": \"front-door\" }\n   * @returns {boolean} True if condition is met, false otherwise\n   */\n  checkShowWhenCondition(showWhen) {\n    if (!showWhen || typeof showWhen !== 'object') return true;\n    \n    // All conditions must be met\n    for (const [configKey, expectedValue] of Object.entries(showWhen)) {\n      const currentValue = this.currentConfig?.[configKey];\n      log800(`[Summit800] checkShowWhenCondition: ${configKey} = \"${currentValue}\" (expected: \"${expectedValue}\")`);\n      if (currentValue !== expectedValue) {\n        return false;\n      }\n    }\n    \n    return true;\n  }\n\n  hasValidOptions(data) {\n    return (Array.isArray(data.options) && data.options.length > 0) || this.sectionHasNestedOptions(data);\n  }\n\n  sectionHasNestedOptions(data) {\n    if (!data || typeof data !== 'object') return false;\n    return Object.keys(data).some(key => {\n      if (['meshGroups', 'displayName', 'textureScale'].includes(key)) return false;\n      const sub = data[key];\n      return sub && Array.isArray(sub.options) && sub.options.length > 0;\n    });\n  }\n\n  createConfigSection(sectionKey, sectionData, isGrouped = false) {\n    if (this.isHidden(sectionData)) return document.createDocumentFragment();\n\n    const section = document.createElement('div');\n    section.className = 'config-section mb-6';\n    section.dataset.configSection = sectionKey;\n    \n    // Set initial visibility based on showWhen condition\n    if (this.shouldBeInitiallyHidden(sectionData)) {\n      section.style.display = 'none';\n      log800(`[Summit800] Section ${sectionKey} initially hidden due to showWhen condition`);\n    }\n\n    const hasNestedSections = !sectionData.options && this.sectionHasNestedOptions(sectionData);\n\n    if (hasNestedSections) {\n      this.renderNestedSection(section, sectionKey, sectionData);\n    } else if (sectionData.options) {\n      this.renderFlatSection(section, sectionKey, sectionData, isGrouped);\n    }\n\n    return section;\n  }\n\n  renderNestedSection(section, sectionKey, sectionData) {\n    const displayName = sectionData.displayName || formatSectionName(sectionKey);\n    const header = document.createElement('h3');\n    header.className = 'config-group-header';\n    header.textContent = `${displayName}:`;\n    section.appendChild(header);\n\n    Object.keys(sectionData).forEach(subKey => {\n      if (['meshGroups', 'pricePerSqFt', 'hide', 'displayName', 'textureScale'].includes(subKey)) return;\n\n      const subSection = sectionData[subKey];\n      if (!subSection?.options?.length || this.isHidden(subSection)) return;\n\n      const subSectionEl = document.createElement('div');\n      subSectionEl.className = 'config-subsection';\n\n      const subDisplayName = Summit800ProductConfigurator.DISPLAY_NAME_OVERRIDES[subKey] || subSection.displayName || formatSectionName(subKey);\n\n      // Get current value from config, or use first option as default\n      let defaultValue = this.currentConfig[sectionKey]?.[subKey];\n      const selectedOption = subSection.options.find(opt => opt.value === defaultValue) || subSection.options[0];\n\n      // Initialize config value if not set\n      if (!defaultValue && selectedOption) {\n        if (!this.currentConfig[sectionKey]) this.currentConfig[sectionKey] = {};\n        this.currentConfig[sectionKey][subKey] = selectedOption.value;\n        defaultValue = selectedOption.value;\n      }\n\n      // Get the display name with fallback\n      const selectedDisplayName = selectedOption?.displayName || formatOptionValue(selectedOption?.value) || '';\n\n      const title = document.createElement('h4');\n      title.className = 'config-subtitle';\n      title.dataset.configTitle = `${sectionKey}.${subKey}`;\n      title.innerHTML = `<span class=\"config-title-label\">${subDisplayName}:</span> <span class=\"config-title-value\">${selectedDisplayName}</span>`;\n      subSectionEl.appendChild(title);\n\n      const optionsContainer = this.createOptionsContainer(`${sectionKey}.${subKey}`, sectionKey, subKey);\n      this.populateOptions(optionsContainer, `${sectionKey}.${subKey}`, subSection.options, defaultValue);\n\n      if (optionsContainer.children.length > 0) {\n        subSectionEl.appendChild(optionsContainer);\n        section.appendChild(subSectionEl);\n      }\n    });\n  }\n\n  renderFlatSection(section, sectionKey, sectionData, isGrouped) {\n    const displayName = Summit800ProductConfigurator.DISPLAY_NAME_OVERRIDES[sectionKey] || sectionData.displayName || formatSectionName(sectionKey);\n\n    const optionsContainer = this.createOptionsContainer(sectionKey, sectionKey);\n\n    // Get current value from config, or use first option as default\n    let defaultValue = this.currentConfig[sectionKey];\n    this.populateOptions(optionsContainer, sectionKey, sectionData.options, defaultValue);\n\n    if (optionsContainer.children.length === 0) return;\n\n    // Find the currently selected option to display next to the label\n    const selectedOption = sectionData.options?.find(opt => opt.value === defaultValue) || sectionData.options[0];\n\n    // Initialize config value if not set\n    if (!defaultValue && selectedOption) {\n      this.currentConfig[sectionKey] = selectedOption.value;\n      defaultValue = selectedOption.value;\n    }\n\n    const selectedDisplayName = selectedOption?.displayName || formatOptionValue(selectedOption?.value) || '';\n\n    const title = document.createElement(isGrouped ? 'div' : 'div');\n    title.className = isGrouped ? 'config-subtitle d-flex align-items-center gap-2 mb-2' : 'config-title d-flex align-items-center gap-1 mb-2';\n    title.dataset.configTitle = sectionKey;\n    title.innerHTML = `<p class=\"config-title-label fs-sm fw-medium text-black mb-0\">${displayName}:</p> <span class=\"config-title-value fs-sm\" style=\"letter-spacing: -0.01em;\">${selectedDisplayName}</span>`;\n\n    section.appendChild(title);\n    section.appendChild(optionsContainer);\n  }\n\n  createOptionsContainer(key, sectionKey, subKey) {\n    const container = document.createElement('div');\n    const checkKey = (subKey || sectionKey).toLowerCase();\n\n    let className = 'config-options';\n    if (checkKey.includes('color') || ['main', 'accent'].includes(checkKey)) {\n      className += ' config-options--colors';\n    } else if (/floor|counter|cabinet|fixture|flooring/i.test(checkKey) && !/color/i.test(checkKey)) {\n      // Swatches/textures for floor, counter, cabinet, fixture options\n      className += ' config-options--swatches';\n    }\n\n    container.className = className;\n    container.dataset.configOptions = key;\n    return container;\n  }\n\n  populateOptions(container, sectionKey, options, defaultValue) {\n    const isPackageSection = options.some(opt => {\n      const name = String(opt.displayName || opt.value || '').toLowerCase().replace(/[\\s_-]/g, '');\n      return name.includes('shellonly') || name.includes('lifestyleinterior') || name.includes('fullyequip');\n    });\n\n    if (isPackageSection) {\n      options.sort((a, b) => {\n        const getScore = (opt) => {\n          const name = String(opt.displayName || opt.value || '').toLowerCase().replace(/[\\s_-]/g, '');\n          if (name.includes('fullyequip')) return 1;\n          if (name.includes('lifestyleinterior')) return 1;\n          if (name.includes('shellonly')) return 2;\n          return 3;\n        };\n        return getScore(a) - getScore(b);\n      });\n      // Force default assignment to the top-ranked package if not manually selected by user\n      if (typeof this.hasForcedPackageDefault === 'undefined' || !defaultValue) {\n        if (sectionKey.includes('.')) {\n          const [parentKey, childKey] = sectionKey.split('.');\n          if (!this.currentConfig[parentKey]) this.currentConfig[parentKey] = {};\n          this.currentConfig[parentKey][childKey] = options[0].value;\n        } else {\n          this.currentConfig[sectionKey] = options[0].value;\n        }\n        defaultValue = options[0].value;\n        this.hasForcedPackageDefault = true;\n      }\n    }\n\n    let firstVisibleIndex = 0;\n    options.forEach(option => {\n      if (this.isHidden(option)) return;\n      const isSelected = defaultValue ? option.value === defaultValue : firstVisibleIndex === 0;\n      firstVisibleIndex++;\n      container.appendChild(this.createOptionCard(sectionKey, option, isSelected));\n    });\n  }\n\n  createOptionCard(sectionKey, option, isSelected) {\n    const card = document.createElement('div');\n    const isColor = option.hex || option.rgb;\n    const sectionLower = sectionKey.toLowerCase();\n    \n    // Categorize section types\n    const isSidingOption = /siding/i.test(sectionKey) && !sectionLower.includes('color');\n    const isSidingColorOption = /sidingcolor/i.test(sectionKey);\n    const isFloorOption = /floor|flooring/i.test(sectionKey);\n    const isCounterOption = /counter/i.test(sectionKey);\n    // Finishes (fixtures, cabinets) show as ICON images - counters show as textures/swatches like Aspect\n    const isFinishOption = /fixture|cabinet|finishes/i.test(sectionKey) && !isCounterOption;\n    \n    // Resolve texture URL - check option properties and fallback to texturesData lookup\n    let textureUrl = option.texture || option.thumbnail || option.swatch;\n    \n    // Resolve texture reference if it's a key (not a URL)\n    if (textureUrl) {\n      textureUrl = this.resolveTextureReference(textureUrl);\n    }\n    \n    // For siding TYPE options (not color), try to find texture in texturesData\n    if (isSidingOption && !textureUrl && this.texturesData) {\n      textureUrl = this.texturesData[option.value] \n        || this.texturesData[`siding-${option.value}`]\n        || this.texturesData[`${option.value}-siding`];\n    }\n    \n    // For counter options, try to find texture in texturesData\n    if (isCounterOption && !textureUrl && this.texturesData) {\n      textureUrl = this.texturesData[option.value] \n        || this.texturesData[`counter-${option.value}`]\n        || this.texturesData[`countertop-${option.value}`]\n        || this.texturesData[`${option.value}-counter`];\n    }\n    \n    // Get image URL for icon display (finishes use this)\n    const imageUrl = option.iconImage || option.image;\n    \n    // Fallback textureUrl to image only for non-finish options\n    if (!textureUrl && !isFinishOption) {\n      textureUrl = imageUrl;\n      if (textureUrl) {\n        textureUrl = this.resolveTextureReference(textureUrl);\n      }\n    }\n    \n    // Determine if this should show as texture swatch\n    // Finishes should NOT show as texture - they show as icons (except counters which show like Aspect)\n    const isTexture = !isFinishOption && ((option.texture || option.thumbnail) || (isSidingOption && textureUrl) || (isFloorOption && textureUrl) || (isCounterOption && textureUrl));\n\n    let classes = 'option-card';\n    if (isSelected) classes += ' selected';\n    if (isColor) classes += ' option-card--color';\n    if (isTexture) classes += ' option-card--texture';\n\n    card.className = classes;\n    card.setAttribute('data-option-card', '');\n    card.dataset.section = sectionKey;\n    card.dataset.value = option.value;\n    card.dataset.price = option.price || 0;\n\n    if (option.meshGroups) card.dataset.meshGroups = JSON.stringify(option.meshGroups);\n    if (option.hex) card.dataset.hex = option.hex;\n    if (option.rgb) card.dataset.rgb = option.rgb;\n    if (option.texture) card.dataset.texture = option.texture;\n    if (option.textureScale) card.dataset.textureScale = JSON.stringify(option.textureScale);\n\n    let html = `<span class=\"aspect-variant-check\">\n                  <svg viewBox=\"0 0 8 7\" fill=\"none\" style=\"width: 11px; height: 6px; margin-bottom: -1px;\">\n                    <path d=\"M0.5 3.35714L2.77027 5.5L7.5 0.5\" stroke=\"currentColor\" stroke-linecap=\"round\"/>\n                  </svg>\n                </span>`;\n\n    // Determine what to render:\n    // 1. Siding COLOR options \u2192 color swatches\n    // 2. Siding TYPE options \u2192 texture images\n    // 3. Floor options \u2192 texture swatches\n    // 4. Counter options \u2192 texture/color swatches (like Aspect)\n    // 5. Finish options (fixtures, cabinets) \u2192 ICON images\n    // 6. Other color options \u2192 color swatches\n    // 7. Fallback \u2192 icon\n    \n    if (isSidingColorOption && isColor) {\n      // Siding color options: show color swatch\n      html += `<div class=\"option-card-swatch\" style=\"background-color: ${option.hex || option.rgb};\"></div>`;\n    } else if (isSidingOption && textureUrl) {\n      // Siding type options: show texture image\n      html += `<div class=\"option-card-thumbnail\"><img src=\"${textureUrl}\" alt=\"${option.displayName}\" loading=\"lazy\" class=\"w-100 h-100 object-fit-cover\"></div>`;\n    } else if (isFloorOption && textureUrl) {\n      // Floor options: show texture swatch\n      html += `<div class=\"option-card-thumbnail\"><img src=\"${textureUrl}\" alt=\"${option.displayName}\" loading=\"lazy\" class=\"w-100 h-100 object-fit-cover\"></div>`;\n    } else if (isCounterOption && textureUrl) {\n      // Counter options: show texture swatch (like Aspect)\n      html += `<div class=\"option-card-thumbnail\"><img src=\"${textureUrl}\" alt=\"${option.displayName}\" loading=\"lazy\" class=\"w-100 h-100 object-fit-cover\"></div>`;\n    } else if (isCounterOption && isColor) {\n      // Counter options: show color swatch if no texture (like Aspect)\n      html += `<div class=\"option-card-swatch\" style=\"background-color: ${option.hex || option.rgb};\"></div>`;\n    } else if (isFinishOption && imageUrl) {\n      // Finish options (fixtures, cabinets): show as ICON image\n      html += `<div class=\"option-card-icon\"><img src=\"${imageUrl}\" alt=\"${option.displayName}\" width=\"48\" height=\"48\" loading=\"lazy\"></div>`;\n    } else if (isColor) {\n      // Color swatch for color options\n      html += `<div class=\"option-card-swatch\" style=\"background-color: ${option.hex || option.rgb};\"></div>`;\n    } else if (isTexture && textureUrl) {\n      // Other texture options\n      html += `<div class=\"option-card-thumbnail\"><img src=\"${textureUrl}\" alt=\"${option.displayName}\" loading=\"lazy\" class=\"w-100 h-100 object-fit-contain\"></div>`;\n    } else {\n      // Fallback to icon\n      const icon = imageUrl\n        ? `<img src=\"${imageUrl}\" alt=\"${option.displayName}\" width=\"48\" height=\"48\" loading=\"lazy\">`\n        : '<svg viewBox=\"0 0 48 48\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\"><rect x=\"8\" y=\"8\" width=\"32\" height=\"32\" rx=\"4\"/><circle cx=\"24\" cy=\"24\" r=\"8\"/></svg>';\n      html += `<div class=\"option-card-icon\">${icon}</div>`;\n    }\n\n    html += `<div class=\"option-card-content\">`;\n    html += `<p class=\"option-card-label fw-medium mb-0 text-black\">${option.displayName}</p>`;\n    // Don't show prices/included for combination pricing options - show normally for all other options\n    const hidePriceKeys = ['sideOptions', 'doorOptions', 'entryOptions', 'bedroomOptions', 'frontOptions', 'entryLocation', 'windowOptions', 'bathOptions'];\n    const sectionKeyLower = sectionKey.toLowerCase();\n    // Get base key (before any dot for nested keys)\n    const baseKey = sectionKeyLower.split('.')[0];\n    const shouldHidePrice = hidePriceKeys.some(key => {\n      const keyLower = key.toLowerCase();\n      return sectionKeyLower === keyLower || baseKey === keyLower;\n    });\n    if (!shouldHidePrice) {\n      html += option.price > 0\n        ? `<span class=\"option-card-price text-gray-600 d-block\">${formatPrice(option.price)}</span>`\n        : '<p class=\"option-card-included text-gray-600 mb-0\">Included</p>';\n    }\n    html += `</div>`;\n\n    // Add eye icon button if modelImage exists\n    if (option.modelImage) {\n      html += `<button class=\"summit-model-image-btn position-absolute border-0 bottom-0 rounded d-flex align-items-center justify-content-center\" type=\"button\" aria-label=\"View ${option.displayName} model image\" data-model-image=\"${option.modelImage}\" data-option-name=\"${option.displayName}\">\n                <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"width: 18px; height: 18px;\">\n                  <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"></path>\n                  <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n                </svg>\n              </button>`;\n    }\n\n    card.innerHTML = html;\n    card.addEventListener('click', (e) => {\n      // Don't trigger selection if clicking the eye icon\n      if (e.target.closest('.summit-model-image-btn')) {\n        e.stopPropagation();\n        const btn = e.target.closest('.summit-model-image-btn');\n        const imageUrl = btn.dataset.modelImage;\n        const optionName = btn.dataset.optionName;\n        this.showModelImagePopup(imageUrl, optionName);\n        return;\n      }\n      this.selectOption(sectionKey, card, option);\n    });\n    return card;\n  }\n\n  // ============================================================================\n  // MODEL IMAGE POPUP (uses global modal CSS from component-modal.css)\n  // ============================================================================\n\n  showModelImagePopup(imageUrl, optionName) {\n    // Create or get existing modal container\n    let modalContainer = document.getElementById('SummitModelImagePopup');\n    \n    if (!modalContainer) {\n      // Create container using global modal structure\n      modalContainer = document.createElement('div');\n      modalContainer.id = 'SummitModelImagePopup';\n      modalContainer.setAttribute('role', 'dialog');\n      modalContainer.setAttribute('aria-modal', 'true');\n      modalContainer.setAttribute('aria-hidden', 'true');\n      \n      modalContainer.innerHTML = `\n        <div class=\"modal\" id=\"SummitModelImageModal\">\n          <div class=\"modal-dialog modal-dialog-centered\">\n            <div class=\"modal-content bg-white\">\n              <div class=\"modal-head d-flex align-items-center justify-content-between p-3 border-bottom\">\n                <h5 class=\"h4 mb-0\" id=\"summit-model-image-title\"></h5>\n                <button type=\"button\" class=\"p-0 text-black d-flex align-items-center bg-transparent border-0\" id=\"ModalClose-SummitModelImagePopup\" aria-label=\"Close\">\n                  <span class=\"visually-hidden\">Close</span>\n                  <svg aria-hidden=\"true\" focusable=\"false\" style=\"width: 18px; height: 18px;\">\n                    <use href=\"#icon-close\"></use>\n                  </svg>\n                </button>\n              </div>\n              <div class=\"modal-body p-4 text-center\">\n                <img src=\"\" alt=\"\" class=\"summit-model-image-popup-img w-100 h-100 object-fit-contain rounded\" width=\"\" height=\"\" loading=\"lazy\">\n              </div>\n            </div>\n          </div>\n        </div>\n      `;\n      \n      document.body.appendChild(modalContainer);\n      \n      // Setup close handlers\n      const closeBtn = modalContainer.querySelector('#ModalClose-SummitModelImagePopup');\n      const modal = modalContainer.querySelector('.modal');\n      \n      const hideModal = () => {\n        modal.classList.remove('open');\n        modalContainer.setAttribute('aria-hidden', 'true');\n        if (typeof SiteOverlay !== 'undefined' && SiteOverlay.hideOverlay) {\n          SiteOverlay.hideOverlay();\n        }\n      };\n      \n      closeBtn.addEventListener('click', hideModal);\n      \n      // Close on overlay click\n      modal.addEventListener('click', (e) => {\n        if (e.target === modal) hideModal();\n      });\n      \n      // Close on ESC key\n      modalContainer.addEventListener('keyup', (e) => {\n        if (e.key === 'Escape') hideModal();\n      });\n    }\n    \n    // Update content\n    const title = modalContainer.querySelector('#summit-model-image-title');\n    const img = modalContainer.querySelector('.summit-model-image-popup-img');\n    const modal = modalContainer.querySelector('.modal');\n    \n    title.textContent = optionName || 'Model Image';\n    img.src = imageUrl;\n    img.alt = optionName || 'Model image';\n    \n    // Show modal using global CSS\n    modal.classList.add('open');\n    modalContainer.setAttribute('aria-hidden', 'false');\n    if (typeof SiteOverlay !== 'undefined' && SiteOverlay.showOverlay) {\n      SiteOverlay.showOverlay();\n    }\n    \n    // Focus close button for accessibility\n    setTimeout(() => {\n      modalContainer.querySelector('#ModalClose-SummitModelImagePopup').focus();\n    }, 100);\n  }\n\n  // ============================================================================\n  // OPTION SELECTION\n  // ============================================================================\n\n  selectOption(section, card, option) {\n    console.log('selectOption called - section:', section, 'option:', option);\n    // Update UI\n    const container = card.parentElement;\n    qa('[data-option-card]', '.option-card', container).forEach(c => c.classList.remove('selected'));\n    card.classList.add('selected');\n\n    // Update title\n    const titleEl = $(`[data-config-title=\"${section}\"]`, this.step2Section);\n    if (titleEl) {\n      const valueEl = titleEl.querySelector('.config-title-value, [data-config-title-value]');\n      if (valueEl) valueEl.textContent = option.displayName || option.value;\n    }\n\n    // Update config state\n    if (section.includes('.')) {\n      const [parentKey, childKey] = section.split('.');\n      if (!this.currentConfig[parentKey]) this.currentConfig[parentKey] = {};\n      this.currentConfig[parentKey][childKey] = option.value;\n    } else {\n      this.currentConfig[section] = option.value;\n    }\n\n    // STATE RESET: If form was already submitted and user changes options,\n    // invalidate the form data (requires re-submission before accessing Summary).\n    // \u26A0\uFE0F DO NOT call the installation API here - only clear form state.\n    if (this.hasValidUserFormData()) {\n      this.userFormData = null;\n      window.studioShedUserData = null;\n      this.finalPriceData = null;\n      this._finalPriceDataZip = null; // Clear cached ZIP so API is called again on next form submit\n      // Disable Summary tab immediately\n      this.updateSummaryTabState();\n    }\n\n    // Handle siding type change - show/hide siding color options\n    if (/^siding$|^sidingType$|^sidingOptions$/i.test(section)) {\n      this.updateSidingColorVisibility(option.value);\n    }\n\n    // Handle interiorOptions change - regenerate tabs to show/hide Interior step\n    if (section === 'interiorOptions') {\n      this.handleInteriorOptionsChange(option.value);\n    }\n\n    // Handle entryOptions change - show/hide sideOptions and frontOptions based on selection\n    if (section === 'entryOptions') {\n      this.updateConditionalOptionsVisibility();\n    }\n\n    if (/floor|flooring/.test(section.toLowerCase())) {\n      console.log('Summit UI \u25BA floor selection', {\n        section,\n        value: option.value,\n        texture: option.texture || option.thumbnail || null\n      });\n    }\n\n    // Update price display (skipQueueUpdate=true to prevent API call)\n    this.updateTotalPrice(true);\n    this.update3DViewer(section, option);\n\n    document.dispatchEvent(new CustomEvent('config:changed', {\n      detail: { section, value: option.value, meshGroups: extractMeshGroups(option.meshGroups), texture: this.resolveTextureReference(option.texture), config: this.currentConfig }\n    }));\n  }\n\n  /**\n   * Show/hide siding color section based on selected siding type\n   * Cedar options don't use siding color (they have fixed white base)\n   */\n  updateSidingColorVisibility(sidingType) {\n    // Cedar types don't use siding color - hide the color section\n    const isCedarType = /cedar/i.test(sidingType);\n    \n    // Find sidingColor section element\n    const sidingColorSection = $('[data-config-section=\"sidingColor\"]', this.step2Section);\n    if (sidingColorSection) {\n      sidingColorSection.style.display = isCedarType ? 'none' : '';\n      console.log(`[Summit UI] Siding color section ${isCedarType ? 'hidden' : 'shown'} for ${sidingType}`);\n    }\n    \n    // Also try alternate selectors\n    const altSelectors = [\n      '[data-config-section=\"siding.color\"]',\n      '[data-config-section=\"sidingColor.main\"]',\n      '.config-section[data-config-section*=\"sidingColor\"]'\n    ];\n    \n    altSelectors.forEach(selector => {\n      const el = $(selector, this.step2Section);\n      if (el) {\n        el.style.display = isCedarType ? 'none' : '';\n      }\n    });\n  }\n\n  /**\n   * Update visibility of conditional options based on showWhen conditions\n   * Called when entryOptions changes to show/hide sideOptions and frontOptions\n   */\n  updateConditionalOptionsVisibility() {\n    // Get the current step's options from the step data\n    const currentStep = this.steps.find(s => s.step === this.currentStep);\n    if (!currentStep?.options) return;\n\n    // Check each option for showWhen conditions\n    log800(`[Summit800] updateConditionalOptionsVisibility called`, {\n      currentStep: this.currentStep,\n      entryOptions: this.currentConfig?.entryOptions,\n      availableOptions: Object.keys(currentStep.options)\n    });\n\n    Object.entries(currentStep.options).forEach(([optionKey, optionData]) => {\n      if (!optionData.showWhen) return;\n      \n      const shouldShow = this.checkShowWhenCondition(optionData.showWhen);\n      const sectionEl = $(`[data-config-section=\"${optionKey}\"]`, this.step2Section);\n      \n      log800(`[Summit800] Checking ${optionKey}:`, {\n        showWhen: optionData.showWhen,\n        shouldShow,\n        elementFound: !!sectionEl\n      });\n      \n      if (sectionEl) {\n        sectionEl.style.display = shouldShow ? '' : 'none';\n        log800(`[Summit800] Conditional visibility: ${optionKey} = ${shouldShow ? 'shown' : 'hidden'}`);\n      } else {\n        log800(`[Summit800] WARNING: Section element not found for ${optionKey}`);\n      }\n    });\n  }\n\n  /**\n   * Handle interiorOptions change - regenerate tabs to show/hide Interior step\n   * @param {string} value - The selected interiorOptions value\n   */\n  handleInteriorOptionsChange(value) {\n    const isNowShell = /shell-only|shell_only|shellonly/i.test(value);\n    const currentTab = q('[data-tab-btn].active', '.tab-btn.active', this.step2Section)?.dataset.tab;\n    \n    // Regenerate tabs to show/hide Interior step\n    this.generateTabs();\n    \n    // IMPORTANT: Re-apply Summary tab disabled state after regenerating tabs\n    // generateTabs() creates fresh tabs without preserving the disabled state\n    this.updateSummaryTabState();\n    \n    // If currently on Interior step and Shell is selected, navigate to Exterior\n    if (isNowShell && currentTab === 'interior') {\n      const visibleSteps = this.getVisibleSteps();\n      const exteriorStep = visibleSteps.find(s => s.name.toLowerCase() === 'exterior');\n      if (exteriorStep) {\n        this.switchTab('exterior');\n      } else if (visibleSteps.length > 0) {\n        this.switchTab(visibleSteps[0].name);\n      }\n    }\n    \n    // Re-activate the current tab button after regeneration\n    if (!isNowShell || currentTab !== 'interior') {\n      const tabBtn = $(`[data-tab-btn][data-tab=\"${currentTab}\"]`, this.step2Section);\n      if (tabBtn) tabBtn.classList.add('active');\n    }\n  }\n\n  update3DViewer(section, option) {\n    console.log('update3DViewer called - section:', section, 'option:', option);\n    if (!this.viewer3D) {\n      console.log('update3DViewer - no viewer3D, returning');\n      return;\n    }\n\n    const currentStepData = this.steps.find(s => s.step === this.currentStep);\n    let sectionData = null, allOptions = [], sectionMeshGroups = [];\n\n    if (section.includes('.')) {\n      const [parentKey, childKey] = section.split('.');\n      const parentSection = currentStepData?.options?.[parentKey];\n      sectionMeshGroups = parentSection?.meshGroups || [];\n      sectionData = parentSection?.[childKey];\n      allOptions = sectionData?.options || [];\n    } else {\n      sectionData = currentStepData?.options?.[section];\n      allOptions = sectionData?.options || [];\n      sectionMeshGroups = sectionData?.meshGroups || [];\n    }\n\n    const optionMeshGroups = extractMeshGroups(option.meshGroups);\n    const sectionMeshGroupsArray = extractMeshGroups(sectionMeshGroups);\n    const meshGroupsToUse = optionMeshGroups.length > 0 ? optionMeshGroups : sectionMeshGroupsArray;\n\n    const configPayload = {\n      section,\n      value: option.value,\n      orientation: section === 'orientation' ? option.value : this.currentConfig.orientation,\n      meshGroups: meshGroupsToUse,\n      allOptions,\n      hex: option.hex,\n      rgb: option.rgb,\n      texture: this.resolveTextureReference(option.texture),\n      textureScale: option.textureScale || sectionData?.textureScale\n    };\n    console.log('update3DViewer - calling updateConfiguration with:', configPayload);\n    this.viewer3D.updateConfiguration(configPayload);\n  }\n\n  // ============================================================================\n  // 3D VIEWER\n  // ============================================================================\n\n  init3DViewer() {\n    const viewerContainer = $('[data-model-viewer]', this.step2Section);\n    if (!viewerContainer) return;\n\n    const placeholder = viewerContainer.querySelector('[data-model-placeholder], .model-placeholder');\n    if (placeholder) {\n      // Use visibility/opacity to maintain layout stability on mobile (Summit-800-specific fix)\n      placeholder.style.visibility = 'visible';\n      placeholder.style.opacity = '1';\n      placeholder.style.pointerEvents = 'auto';\n      // Position placeholder absolutely to overlay without affecting layout\n      placeholder.style.position = 'absolute';\n      placeholder.style.top = '0';\n      placeholder.style.left = '0';\n      placeholder.style.right = '0';\n      placeholder.style.bottom = '0';\n      placeholder.style.zIndex = '10';\n      // Hide the placeholder image during loading - only show spinner\n      const placeholderImg = placeholder.querySelector('[data-placeholder-image], .placeholder-image');\n      if (placeholderImg) placeholderImg.style.display = 'none';\n      const loading = placeholder.querySelector('[data-loading-indicator], .loading-indicator');\n      if (loading) loading.style.display = 'flex';\n    }\n    \n    // Ensure the viewer container has relative/sticky positioning for absolute placeholder\n    const currentPosition = getComputedStyle(viewerContainer).position;\n    if (currentPosition !== 'sticky') {\n      viewerContainer.style.position = 'relative';\n    }\n\n    if (this.viewer3D) {\n      this.viewer3D.dispose();\n      this.viewer3D = null;\n    }\n\n    const configData = this.buildConfigForViewer();\n    if (!configData) {\n      this.showPlaceholderOnError(placeholder);\n      return;\n    }\n\n    // Helper to hide the 3D canvas during loading (Summit-800-specific fix)\n    const hideCanvas = () => {\n      const canvas = viewerContainer.querySelector('canvas');\n      if (canvas) {\n        canvas.style.opacity = '0';\n        canvas.style.visibility = 'hidden';\n      }\n    };\n\n    // Helper to show the 3D canvas after loading completes (Summit-800-specific fix)\n    const showCanvas = () => {\n      const canvas = viewerContainer.querySelector('canvas');\n      if (canvas) {\n        canvas.style.opacity = '1';\n        canvas.style.visibility = 'visible';\n        canvas.style.transition = 'opacity 0.3s ease-in-out';\n      }\n    };\n\n    // Helper to show loading state without layout shift (Summit-800-specific mobile fix)\n    const showLoadingState = () => {\n      if (placeholder) {\n        placeholder.style.visibility = 'visible';\n        placeholder.style.opacity = '1';\n        placeholder.style.pointerEvents = 'auto';\n        const loading = placeholder.querySelector('[data-loading-indicator], .loading-indicator');\n        if (loading) loading.style.display = 'flex';\n        const img = placeholder.querySelector('[data-placeholder-image], .placeholder-image');\n        if (img) img.style.display = 'none';\n      }\n    };\n\n    // Helper to hide loading state without layout shift (Summit-800-specific mobile fix)\n    const hideLoadingState = () => {\n      if (placeholder) {\n        placeholder.style.visibility = 'hidden';\n        placeholder.style.opacity = '0';\n        placeholder.style.pointerEvents = 'none';\n        placeholder.style.transition = 'opacity 0.3s ease-in-out, visibility 0.3s ease-in-out';\n        const loading = placeholder.querySelector('[data-loading-indicator], .loading-indicator');\n        if (loading) loading.style.display = 'none';\n        const img = placeholder.querySelector('[data-placeholder-image], .placeholder-image');\n        if (img) img.style.display = 'none';\n      }\n    };\n\n    this.waitFor3DModule().then(() => {\n      const Configurator3D = window.Summit800Configurator3D || window.Summit800Configurator3D;\n      this.viewer3D = new Configurator3D(viewerContainer, configData);\n      this.viewer3D.init();\n\n      // Initially hide the canvas until model is loaded\n      hideCanvas();\n\n      viewerContainer.addEventListener('configurator:modelLoading', () => {\n        // Hide canvas during loading to prevent visible model shift\n        hideCanvas();\n        // Show loading state without causing layout shift on mobile\n        showLoadingState();\n      });\n\n      viewerContainer.addEventListener('configurator:modelLoaded', () => {\n        // Apply configuration and set view BEFORE showing canvas\n        this.applyConfigTo3D(this.currentConfig);\n        this.setViewForCurrentStep();\n        \n        // Small delay to ensure model is fully positioned before revealing\n        requestAnimationFrame(() => {\n          requestAnimationFrame(() => {\n            // Hide loading state without layout shift, then show canvas\n            hideLoadingState();\n            showCanvas();\n          });\n        });\n      });\n\n      const defaultOrientation = this.currentConfig.orientation || this.defaultConfig.orientation || 'left';\n      this.viewer3D.loadModel(defaultOrientation).catch(() => this.showPlaceholderOnError(placeholder));\n    }).catch(() => this.showPlaceholderOnError(placeholder));\n  }\n\n  deriveMtlUrl(objUrl) {\n    if (!objUrl || typeof objUrl !== 'string') return null;\n    const idx = objUrl.toLowerCase().lastIndexOf('.obj');\n    if (idx === -1) return null;\n    return `${objUrl.slice(0, idx)}.mtl${objUrl.slice(idx + 4)}`;\n  }\n\n  normalizeFileEntry(entry) {\n    if (!entry) return null;\n    if (typeof entry === 'string') {\n      const normalized = {\n        obj: entry,\n        mtl: this.deriveMtlUrl(entry),\n        __derivedMtl: true\n      };\n      if (this.disableAutoMtl) normalized.__skipMtl = true;\n      return normalized;\n    }\n    if (entry.obj) {\n      const normalized = { obj: entry.obj };\n      if (entry.mtl) {\n        normalized.mtl = entry.mtl;\n      } else {\n        const derived = this.deriveMtlUrl(entry.obj);\n        if (derived) {\n          normalized.mtl = derived;\n          normalized.__derivedMtl = true;\n        }\n      }\n      if (this.disableAutoMtl) normalized.__skipMtl = true;\n      return normalized;\n    }\n    return null;\n  }\n\n  buildOrientationGroup(entry, fallbackEntry) {\n    const result = {};\n    const source = entry && typeof entry === 'object' && !Array.isArray(entry) ? entry : null;\n\n    if (source) {\n      Object.entries(source).forEach(([key, value]) => {\n        if (key === 'obj' || key === 'mtl') {\n          result[key] = value;\n          return;\n        }\n        const normalizedValue = this.normalizeFileEntry(value);\n        if (normalizedValue) {\n          result[key] = normalizedValue;\n        }\n      });\n\n      if (source.obj && !result.obj) result.obj = source.obj;\n      if (source.mtl && !result.mtl) result.mtl = source.mtl;\n    }\n\n    const defaultEntry = this.normalizeFileEntry(fallbackEntry != null ? fallbackEntry : entry);\n    if (defaultEntry) {\n      if (!result.left) result.left = { ...defaultEntry };\n      if (!result.right) result.right = { ...defaultEntry };\n      if (!result.obj) result.obj = defaultEntry.obj;\n      if (!result.mtl && defaultEntry.mtl) result.mtl = defaultEntry.mtl;\n    }\n\n    if (!result.left && result.right) result.left = { ...result.right };\n    if (!result.right && result.left) result.right = { ...result.left };\n    if (!result.obj && result.left?.obj) result.obj = result.left.obj;\n    if (!result.mtl && result.left?.mtl) result.mtl = result.left.mtl;\n\n    return Object.keys(result).length ? result : null;\n  }\n\n  normalizeRoofFiles(roof) {\n    if (!roof) return null;\n    const result = {};\n    const fallback = this.normalizeFileEntry(roof?.obj ? roof : (typeof roof === 'string' ? roof : null));\n\n    if (fallback) {\n      result.obj = fallback.obj;\n      if (fallback.mtl) result.mtl = fallback.mtl;\n    }\n\n    if (roof && typeof roof === 'object') {\n      Object.entries(roof).forEach(([key, value]) => {\n        if (key === 'obj' || key === 'mtl') {\n          result[key] = value;\n          return;\n        }\n        const group = this.buildOrientationGroup(value, fallback || this.normalizeFileEntry(value));\n        if (group) result[key] = group;\n      });\n    }\n\n    if (fallback && !result.standard) {\n      result.standard = this.buildOrientationGroup(fallback, fallback);\n    }\n\n    return Object.keys(result).length ? result : null;\n  }\n\n  normalizeComponents(components) {\n    if (!components || typeof components !== 'object') return null;\n    const normalized = {};\n    Object.entries(components).forEach(([key, value]) => {\n      const entry = this.normalizeFileEntry(value);\n      if (entry) normalized[key] = entry;\n    });\n    return Object.keys(normalized).length ? normalized : null;\n  }\n\n  normalizeModelFiles(modelFiles) {\n    if (!modelFiles || typeof modelFiles !== 'object') return modelFiles || null;\n    const normalized = {};\n\n    const baseGroup = this.buildOrientationGroup(modelFiles.base);\n    if (baseGroup) normalized.base = baseGroup;\n\n    const roofGroup = this.normalizeRoofFiles(modelFiles.roof);\n    if (roofGroup) normalized.roof = roofGroup;\n\n    const componentGroup = this.normalizeComponents(modelFiles.components);\n    if (componentGroup) normalized.components = componentGroup;\n\n    Object.keys(modelFiles).forEach(key => {\n      if (!['base', 'roof', 'components'].includes(key)) {\n        normalized[key] = modelFiles[key];\n      }\n    });\n\n    return normalized;\n  }\n\n  normalizeModelsMap(models) {\n    if (!models || typeof models !== 'object') return models || null;\n    const normalized = {};\n    Object.entries(models).forEach(([key, value]) => {\n      normalized[key] = {\n        ...value,\n        modelFiles: this.normalizeModelFiles(value?.modelFiles)\n      };\n    });\n    return normalized;\n  }\n\n  buildConfigForViewer() {\n    if (!this.modelConfig) {\n      console.error('Summit-800 Configurator: modelConfig is missing');\n      return null;\n    }\n\n    const modelName = this.modelsData?.name || this.modelConfig?.name || 'summit-1';\n    const resolvedModelKeyRaw = this.defaultConfig?.model || this.modelConfig?.model || modelName;\n    const modelKey = resolvedModelKeyRaw ? resolvedModelKeyRaw.toLowerCase().replace(/\\s+/g, '-') : 'summit-1';\n\n    // Get modelFiles from various possible locations and normalize them\n    const rawModelFiles =\n      this.modelsData?.modelFiles ||\n      this.modelConfig?.modelFiles ||\n      this.modelConfig?.models?.[modelKey]?.modelFiles ||\n      {};\n    const modelFiles = this.normalizeModelFiles(rawModelFiles) || {};\n\n    // Validate modelFiles structure\n    if (!modelFiles || Object.keys(modelFiles).length === 0) {\n      console.error('Summit-800 Configurator: modelFiles is missing or empty', {\n        modelKey,\n        modelsData: this.modelsData,\n        modelConfig: this.modelConfig\n      });\n    } else {\n      // Log structure for debugging (supports both old and new structures)\n      const hasBaseObj = !!modelFiles.base?.obj;\n      const hasBaseLeft = !!modelFiles.base?.left;\n      const hasRoofObj = !!modelFiles.roof?.obj;\n      const hasComponents = !!modelFiles.components;\n\n      console.log('Summit-800 Configurator: modelFiles structure', {\n        modelKey,\n        hasBaseObj,\n        hasBaseLeft,\n        hasRoofObj,\n        hasComponents,\n        componentKeys: modelFiles.components ? Object.keys(modelFiles.components) : [],\n        structure: hasBaseObj ? 'new (base.obj)' : hasBaseLeft ? 'old (base[left].obj)' : 'unknown'\n      });\n\n      // Warn if neither structure is found\n      if (!hasBaseObj && !hasBaseLeft) {\n        console.warn('Summit-800 Configurator: modelFiles.base structure not recognized', {\n          modelKey,\n          modelFiles\n        });\n      }\n    }\n\n    const models = {\n      [modelKey]: {\n        name: modelName,\n        squareFootage: this.modelsData?.squareFootage || this.modelConfig?.squareFootage,\n        bedBath: this.modelsData?.bedBath || this.modelConfig?.bedBath,\n        description: this.modelsData?.description || this.modelConfig?.description,\n        basePrice: this.modelsData?.basePrice || this.modelConfig?.basePrice,\n        modelFiles: modelFiles\n      }\n    };\n\n    const configurationOptions = {};\n    const interiorFinishes = {};\n    const interiorFinishKeys = ['mainFloorFinish', 'flooring', 'bathFloorFinish', 'counterFinish', 'countertop', 'cabinetFinish', 'cabinets', 'fixtureFinish', 'fixture'];\n\n    this.steps.forEach(step => {\n      if (!step.options) return;\n      Object.keys(step.options).forEach(optionKey => {\n        const optionData = step.options[optionKey];\n        const sectionMeshGroups = Array.isArray(optionData.meshGroups) ? optionData.meshGroups : [];\n\n        configurationOptions[optionKey] = {\n          displayName: optionData.displayName || formatSectionName(optionKey),\n          options: optionData.options || [],\n          meshGroups: sectionMeshGroups\n        };\n\n        if (interiorFinishKeys.includes(optionKey)) {\n          interiorFinishes[optionKey] = configurationOptions[optionKey];\n        }\n\n        // Handle nested options\n        const nestedKeys = ['main', 'accent', 'bath', 'fixture', 'countertop', 'cabinets'];\n        nestedKeys.forEach(subKey => {\n          if (optionData[subKey]?.options) {\n            const subData = optionData[subKey];\n            const subMeshGroups = Array.isArray(subData.meshGroups) ? subData.meshGroups : [];\n            configurationOptions[`${optionKey}.${subKey}`] = {\n              displayName: subData.displayName || formatSectionName(subKey),\n              options: subData.options || [],\n              meshGroups: subMeshGroups,\n              textureScale: subData.textureScale\n            };\n          }\n        });\n      });\n    });\n\n    const defaultConfiguration = {\n      ...(this.defaultConfig || {}),\n      model: modelKey\n    };\n\n    // Get componentCodeMapping from the model config\n    const componentCodeMapping = \n      this.modelsData?.componentCodeMapping || \n      this.modelConfig?.componentCodeMapping || \n      null;\n    \n    console.log('Summit-800 Configurator: componentCodeMapping', componentCodeMapping);\n\n    return {\n      models,\n      textures: this.texturesData || {},\n      colors: this.colorsData || {},\n      configurationOptions,\n      defaultConfiguration,\n      meshGroups: this.meshGroupsData || {},\n      interiorFinishes: this.modelConfig.interiorFinishes || interiorFinishes,\n      steps: this.steps,\n      disableMtl: true,\n      componentCodeMapping,  // Pass the component code mapping to the 3D viewer\n      // Pass model dimensions for floor plane calculation\n      depth: this.modelsData?.depth || this.modelConfig?.depth,\n      length: this.modelsData?.length || this.modelConfig?.length\n    };\n  }\n\n  applyConfigTo3D(config) {\n    if (!this.viewer3D || !config) return;\n\n    const applyValue = (sectionKey, value, optionData, fallbackMeshGroups = []) => {\n      if (!optionData?.options?.length) return;\n      const selectedOption = optionData.options.find(o => o.value === value);\n      if (!selectedOption) return;\n\n      const optionMeshGroups = extractMeshGroups(selectedOption.meshGroups);\n      const sectionMeshGroups = extractMeshGroups(optionData.meshGroups);\n      const meshGroupsToUse = optionMeshGroups.length > 0 ? optionMeshGroups : (sectionMeshGroups.length > 0 ? sectionMeshGroups : extractMeshGroups(fallbackMeshGroups));\n\n      this.viewer3D.updateConfiguration({\n        section: sectionKey,\n        value,\n        meshGroups: meshGroupsToUse,\n        hex: selectedOption.hex,\n        rgb: selectedOption.rgb,\n        texture: this.resolveTextureReference(selectedOption.texture),\n        textureScale: selectedOption.textureScale || optionData.textureScale,\n        allOptions: optionData.options,\n        skipFocus: true\n      });\n    };\n\n    Object.keys(config).forEach(key => {\n      const value = config[key];\n      if (value === undefined || value === null) return;\n\n      if (typeof value === 'object' && !Array.isArray(value)) {\n        Object.keys(value).forEach(subKey => {\n          const subValue = value[subKey];\n          if (subValue === undefined || subValue === null) return;\n          let subOptionData = null, parentMeshGroups = [];\n          this.steps.some(step => {\n            if (step.options?.[key]?.[subKey]) {\n              subOptionData = step.options[key][subKey];\n              parentMeshGroups = extractMeshGroups(step.options[key].meshGroups);\n              return true;\n            }\n          });\n          if (subOptionData) applyValue(`${key}.${subKey}`, subValue, subOptionData, parentMeshGroups);\n        });\n      } else {\n        let optionData = null;\n        this.steps.some(step => {\n          if (step.options?.[key]) {\n            optionData = step.options[key];\n            return true;\n          }\n        });\n        if (optionData) applyValue(key, value, optionData);\n      }\n    });\n  }\n\n  setViewForCurrentStep() {\n    if (!this.viewer3D) return;\n    const currentStepData = this.steps.find(s => s.step === this.currentStep);\n    const stepName = currentStepData?.name?.toLowerCase() || '';\n    // Show top-down view (roof hidden) only for interior and finishes steps\n    const isTopDown = ['interior', 'finishes'].includes(stepName);\n    this.viewer3D.setViewForStep(isTopDown ? 1 : 2);\n  }\n\n  showPlaceholderOnError(placeholder) {\n    if (!placeholder) return;\n    // Show placeholder image only on error as fallback (Summit-800-specific fix)\n    placeholder.style.visibility = 'visible';\n    placeholder.style.opacity = '1';\n    placeholder.style.pointerEvents = 'auto';\n    const img = placeholder.querySelector('[data-placeholder-image], .placeholder-image');\n    if (img) img.style.display = 'block';\n    const loading = placeholder.querySelector('[data-loading-indicator], .loading-indicator');\n    if (loading) loading.style.display = 'none';\n  }\n\n  waitFor3DModule(timeout = 10000) {\n    return new Promise((resolve, reject) => {\n      if (window.Summit800Configurator3D || window.Summit800Configurator3D) {\n        resolve();\n        return;\n      }\n      const startTime = Date.now();\n      const checkInterval = setInterval(() => {\n        if (window.Summit800Configurator3D || window.Summit800Configurator3D) {\n          clearInterval(checkInterval);\n          resolve();\n        } else if (Date.now() - startTime > timeout) {\n          clearInterval(checkInterval);\n          reject(new Error('Timeout waiting for 3D module'));\n        }\n      }, 100);\n    });\n  }\n\n  // ============================================================================\n  // HEADER & PRICING\n  // ============================================================================\n\n  updateStep2Header(variantInfo = {}) {\n    const titleEl = $('[data-configurator-title]', this.step2Section);\n    const specsEl = $('[data-configurator-specs]', this.step2Section);\n    // Get ALL price elements (header and mobile footer)\n    const priceEls = $$('[data-configurator-price]', this.step2Section);\n\n    const modelName = this.modelsData?.name || variantInfo.title || '';\n    const sqFt = this.modelsData?.squareFootage || variantInfo.sqFt;\n    const bedBath = this.modelsData?.bedBath || variantInfo.bedBath;\n    const description = this.modelsData?.description;\n\n    if (titleEl) titleEl.textContent = modelName;\n    if (specsEl) {\n      const specs = [sqFt && `${sqFt} sq ft`, bedBath, description].filter(Boolean);\n      specsEl.textContent = specs.slice(0, 2).join(' | ');\n    }\n\n    // Set static base price from model config\n    // Note: Combination pricing is handled in updateTotalPrice() which overrides this\n    this.basePrice = this.modelsData?.basePrice || variantInfo.price || 0;\n    \n    // Check if combination pricing is available and get initial price\n    const combinationPrice = this.getCombinationPrice();\n    const displayPrice = combinationPrice !== null ? combinationPrice : this.basePrice;\n    \n    // Update ALL price elements\n    priceEls.forEach(el => el.textContent = formatPrice(displayPrice));\n  }\n\n  updateNextButtonText(currentStepNumber) {\n    const nextBtnText = $('[data-next-step-text]', this.step2Section);\n    if (nextBtnText) {\n      // Use visible steps to get correct next step (skips Interior for Shell packages)\n      const visibleSteps = this.getVisibleSteps();\n      const currentVisibleIndex = visibleSteps.findIndex(s => s.step === currentStepNumber);\n      const nextVisibleStep = visibleSteps[currentVisibleIndex + 1];\n      nextBtnText.textContent = nextVisibleStep ? nextVisibleStep.name : 'Services';\n    }\n\n    // Hide back button on first step (Floorplan)\n    const backBtn = $('[data-back-step]', this.step2Section);\n    if (backBtn) {\n      backBtn.style.display = currentStepNumber === 1 ? 'none' : '';\n    }\n  }\n\n  // NOTE: updateTotalPrice is defined later in the file with full matrix pricing support\n\n  /**\n   * Get the elevation key for looking up elevation images\n   * Builds a combination key like \"front-entry|more-glass\" from current config\n   * @returns {string|null} The elevation key or null if not available\n   */\n  /**\n   * Detect the combination keys used in pricing by analyzing the JSON structure\n   * Supports: single keys, 2-part combinations, 3-part combinations, matrix format, etc.\n   * @returns {string[]} Array of config keys to use for combination lookup\n   */\n  detectCombinationKeys() {\n    const pricing = this.pricingConfig;\n    \n    // For matrix pricing format - dynamically detect keys and include interiorOptions\n    if (pricing?.matrix) {\n      const availableKeys = Object.keys(pricing.matrix);\n      if (availableKeys.length === 0) return ['interiorOptions'];\n      \n      // Analyze the first matrix key to find which config keys are used\n      const sampleKey = availableKeys[0];\n      const keyParts = sampleKey.split('|');\n      let detectedKeys = this.detectMatrixConfigKeys(keyParts);\n      \n      // If detection didn't find all keys, try to find config keys whose values appear in any matrix key\n      if (detectedKeys.length < keyParts.length) {\n        detectedKeys = this.detectConfigKeysFromMatrixValues(availableKeys);\n      }\n      \n      // Always include interiorOptions as it affects the final price in matrix format\n      if (!detectedKeys.includes('interiorOptions')) {\n        detectedKeys.push('interiorOptions');\n      }\n      \n      return detectedKeys;\n    }\n    \n    if (!pricing?.combinations) return [];\n    \n    // If explicitly configured, use those\n    if (pricing.combinationKeys?.length) {\n      return pricing.combinationKeys;\n    }\n    \n    const availableKeys = Object.keys(pricing.combinations);\n    if (availableKeys.length === 0) return [];\n    \n    // Check if keys contain \"|\" separator\n    const sampleKey = availableKeys[0];\n    const numParts = sampleKey.split('|').length;\n    \n    if (numParts === 1) {\n      return ['sideOptions'];\n    } else if (numParts === 2) {\n      return ['entryLocation', 'windowOptions'];\n    } else if (numParts === 3) {\n      return ['bathOptions', 'entryLocation', 'sideOptions'];\n    } else {\n      return [];\n    }\n  }\n\n  /**\n   * Detect config keys by checking which config options have values that appear in matrix keys\n   * This is a fallback when direct key part matching fails\n   * @param {string[]} matrixKeys - Array of matrix keys (e.g., [\"more-operable|side-window\", ...])\n   * @returns {string[]} Array of config option keys\n   */\n  detectConfigKeysFromMatrixValues(matrixKeys) {\n    const matchedKeys = new Set();\n    \n    // Summit 800 specific: Map config values to matrix key values\n    const configToMatrixMap = {\n      'side-slider-door': 'side-slider',\n      'front-slider-door': 'front-slider',\n      'single-bathroom': 'single-bath'\n    };\n    \n    // Collect all unique values from matrix keys\n    const allMatrixValues = new Set();\n    matrixKeys.forEach(key => {\n      key.split('|').forEach(part => allMatrixValues.add(part));\n    });\n    \n    // Build a map of config option keys to their possible values\n    const configOptionsMap = {};\n    this.steps.forEach(step => {\n      if (!step.options) return;\n      Object.keys(step.options).forEach(optionKey => {\n        const optionData = step.options[optionKey];\n        const choices = optionData.choices || optionData.options || [];\n        configOptionsMap[optionKey] = choices.map(c => c.value);\n      });\n    });\n    \n    // For each config option, check if any of its values appear in matrix keys\n    // Apply the value mapping to handle config/matrix value mismatches\n    for (const [optionKey, values] of Object.entries(configOptionsMap)) {\n      for (const value of values) {\n        // Check both the original value and its mapped equivalent\n        const mappedValue = configToMatrixMap[value] || value;\n        if (allMatrixValues.has(value) || allMatrixValues.has(mappedValue)) {\n          matchedKeys.add(optionKey);\n          break;\n        }\n      }\n    }\n    \n    log800('[Summit800] Detected config keys from matrix values:', Array.from(matchedKeys));\n    return Array.from(matchedKeys);\n  }\n\n  /**\n   * Calculate combination price based on selected options\n   * Supports:\n   * - Matrix format: pricing.matrix[\"key1|key2|key3\"][\"shell-only\"|\"lifestyle-adu\"]\n   * - Combinations format: pricing.combinations[\"key\"].price or pricing.combinations[\"key\"][\"interior\"]\n   * @returns {number|null} The combination price in cents, or null if not applicable\n   */\n  getCombinationPrice() {\n    const pricing = this.pricingConfig;\n    \n    // Check for matrix format first (new pricing structure)\n    if (pricing?.matrix) {\n      return this.getMatrixPrice();\n    }\n    \n    // Fall back to combinations format\n    if (!pricing?.combinations) return null;\n    \n    const availableCombinationKeys = Object.keys(pricing.combinations);\n    if (availableCombinationKeys.length === 0) return null;\n    \n    // Detect the number of parts in combination keys\n    const sampleKey = availableCombinationKeys[0];\n    const numParts = sampleKey.split('|').length;\n    \n    let lookupKey = null;\n    \n    if (numParts === 1) {\n      const singleKeyOptions = ['sideOptions', 'exterior', 'windowOption', 'entryLocation', 'windowOptions', 'bathOptions'];\n      for (const configKey of singleKeyOptions) {\n        const configValue = this.currentConfig[configKey];\n        if (configValue && availableCombinationKeys.includes(configValue)) {\n          lookupKey = configValue;\n          break;\n        }\n      }\n    } else {\n      const combinationKeys = this.detectCombinationKeys();\n      const keyParts = combinationKeys.map(key => this.currentConfig[key]).filter(Boolean);\n      \n      log800('[Summit800] Building combination key:', { \n        combinationKeys, \n        configValues: combinationKeys.map(k => this.currentConfig[k]),\n        keyParts,\n        numParts\n      });\n      \n      if (keyParts.length === numParts) {\n        lookupKey = keyParts.join('|');\n      }\n    }\n    \n    if (!lookupKey) {\n      log800('[Summit800] No matching combination price key found');\n      return null;\n    }\n    \n    const combinationData = pricing.combinations[lookupKey];\n    \n    // Check for nested interior options format first\n    const interiorOptions = this.currentConfig.interiorOptions;\n    if (combinationData && interiorOptions && combinationData[interiorOptions] !== undefined) {\n      log800('[Summit800] Combination price found (nested):', { key: lookupKey, interior: interiorOptions, price: combinationData[interiorOptions] });\n      return combinationData[interiorOptions];\n    }\n    \n    // Fall back to direct price property (older format)\n    if (combinationData?.price !== undefined) {\n      log800('[Summit800] Combination price found:', { key: lookupKey, price: combinationData.price });\n      return combinationData.price;\n    }\n    \n    // Try alternative key orders if exact match not found\n    if (numParts > 1) {\n      log800('[Summit800] Trying alternative key orders for:', lookupKey);\n      const parts = lookupKey.split('|');\n      const permutations = this.getPermutations(parts);\n      for (const perm of permutations) {\n        const altKey = perm.join('|');\n        const altData = pricing.combinations[altKey];\n        \n        // Check nested format first\n        if (altData && interiorOptions && altData[interiorOptions] !== undefined) {\n          log800('[Summit800] Found alternative key (nested):', altKey);\n          return altData[interiorOptions];\n        }\n        \n        // Fall back to direct price\n        if (altData?.price !== undefined) {\n          log800('[Summit800] Found alternative key:', altKey);\n          return altData.price;\n        }\n      }\n    }\n    \n    log800('[Summit800] No price for combination key:', lookupKey);\n    return null;\n  }\n\n  /**\n   * Calculate price from matrix format pricing\n   * Supports single-key, 2-key, and 3-key matrix (e.g. \"standard|front-door|side-window\")\n   * @returns {number|null} The price, or null if not applicable\n   */\n  getMatrixPrice() {\n    const pricing = this.pricingConfig;\n    console.log('[Summit800] getMatrixPrice called, pricingConfig:', pricing);\n    \n    if (!pricing?.matrix) {\n      console.log('[Summit800] No matrix in pricing config');\n      return null;\n    }\n    \n    const availableKeys = Object.keys(pricing.matrix);\n    if (availableKeys.length === 0) return null;\n    \n    const interiorOptions = this.currentConfig.interiorOptions;\n    \n    console.log('[Summit800] Matrix price lookup - current config:', this.currentConfig);\n    \n    // Method 1: Try direct matching - find a matrix key where all parts are in current config values\n    let matchedKey = this.buildMatrixLookupKey();\n    let matrixEntry = matchedKey ? pricing.matrix[matchedKey] : null;\n    \n    // Method 2: If direct match failed, try the config key detection approach\n    if (!matrixEntry) {\n      // Analyze the first matrix key to understand the format\n      const sampleKey = availableKeys[0];\n      const keyParts = sampleKey.split('|');\n      \n      log800('[Summit800] Matrix price lookup - analyzing key format:', { sampleKey, keyParts });\n      \n      // Dynamically find which config keys have values matching the matrix key parts\n      const configKeysToUse = this.detectMatrixConfigKeys(keyParts);\n      \n      log800('[Summit800] Detected config keys for matrix:', configKeysToUse);\n      \n      if (configKeysToUse.length === keyParts.length) {\n        // Build the lookup key from detected config values\n        const lookupParts = configKeysToUse.map(key => this.currentConfig[key]).filter(Boolean);\n        \n        if (lookupParts.length === keyParts.length) {\n          // Build list of possible key combinations to try (original order and reversed)\n          const keyCombinations = [\n            lookupParts.join('|'),\n            [...lookupParts].reverse().join('|'),\n          ];\n          \n          // For 3-part keys, try all permutations\n          if (lookupParts.length === 3) {\n            const perms = this.getPermutations(lookupParts);\n            perms.forEach(p => keyCombinations.push(p.join('|')));\n          }\n          \n          log800('[Summit800] Trying key combinations:', keyCombinations);\n          \n          // Try each combination\n          for (const key of keyCombinations) {\n            if (pricing.matrix[key]) {\n              matrixEntry = pricing.matrix[key];\n              matchedKey = key;\n              break;\n            }\n          }\n        }\n      }\n    }\n    \n    if (!matrixEntry) {\n      log800('[Summit800] No matrix entry found. Available:', availableKeys);\n      return null;\n    }\n    \n    log800('[Summit800] Found matrix entry with key:', matchedKey);\n    \n    // Get the interior option (default to lifestyle-adu if not set)\n    const interior = interiorOptions || 'lifestyle-adu';\n    const price = matrixEntry[interior];\n    \n    if (price !== undefined) {\n      log800('[Summit800] Matrix price found:', { key: matchedKey, interior, price });\n      return price;\n    }\n    \n    log800('[Summit800] No price found for interior option:', interior);\n    return null;\n  }\n\n  /**\n   * Build the matrix lookup key by finding config values that match matrix key parts\n   * Handles single-key, 2-key, and 3-key matrix formats\n   * Includes Summit 800 specific value mappings for slider options\n   * @returns {string|null} The matrix lookup key, or null if not found\n   */\n  buildMatrixLookupKey() {\n    const pricing = this.pricingConfig;\n    if (!pricing?.matrix) return null;\n    \n    const availableKeys = Object.keys(pricing.matrix);\n    if (availableKeys.length === 0) return null;\n    \n    // Summit 800 specific: Map config values to matrix key values\n    // Config uses different values than matrix keys in some cases\n    const summit800ValueMap = {\n      'side-slider-door': 'side-slider',\n      'front-slider-door': 'front-slider',\n      'single-bathroom': 'single-bath'  // Summit 800-B uses \"single-bathroom\" in config but \"single-bath\" in matrix\n    };\n    \n    // Get all current config values and apply mapping\n    const rawConfigValues = Object.values(this.currentConfig).filter(v => typeof v === 'string');\n    const currentConfigValues = rawConfigValues.map(v => summit800ValueMap[v] || v);\n    \n    console.log('[Summit800] Building matrix key from config values:', { \n      raw: rawConfigValues, \n      mapped: currentConfigValues,\n      availableKeys\n    });\n    \n    // Try to find a matrix key where all parts match current config values\n    for (const matrixKey of availableKeys) {\n      const keyParts = matrixKey.split('|');\n      const allPartsMatch = keyParts.every(part => currentConfigValues.includes(part));\n      \n      console.log('[Summit800] Checking matrix key:', { \n        matrixKey, \n        keyParts, \n        allPartsMatch,\n        checkDetails: keyParts.map(part => ({ part, inConfig: currentConfigValues.includes(part) }))\n      });\n      \n      if (allPartsMatch) {\n        console.log('[Summit800] Found matching matrix key:', matrixKey);\n        return matrixKey;\n      }\n    }\n    \n    console.log('[Summit800] No direct matrix key match found');\n    return null;\n  }\n\n  /**\n   * Dynamically detect which config keys match the matrix key parts\n   * Includes Summit 800 specific reverse value mappings\n   * @param {string[]} keyParts - The parts of a matrix key (e.g., [\"standard\", \"front-door\", \"side-window\"])\n   * @returns {string[]} Array of config option keys that match the key parts\n   */\n  detectMatrixConfigKeys(keyParts) {\n    const matchedKeys = [];\n    \n    // Summit 800 specific: Reverse map matrix key values to config values\n    // Matrix uses different values than config in some cases\n    const matrixToConfigMap = {\n      'side-slider': 'side-slider-door',\n      'front-slider': 'front-slider-door',\n      'single-bath': 'single-bathroom'  // Summit 800-B matrix uses \"single-bath\" but config uses \"single-bathroom\"\n    };\n    \n    // Build a map of config option keys to their possible values\n    const configOptionsMap = {};\n    this.steps.forEach(step => {\n      if (!step.options) return;\n      Object.keys(step.options).forEach(optionKey => {\n        const optionData = step.options[optionKey];\n        const choices = optionData.choices || optionData.options || [];\n        configOptionsMap[optionKey] = choices.map(c => c.value);\n      });\n    });\n    \n    log800('[Summit800] Config options map:', configOptionsMap);\n    \n    // For each key part, find which config option contains that value\n    for (const part of keyParts) {\n      let found = false;\n      // Try the part directly, or its mapped equivalent\n      const valuesToCheck = [part, matrixToConfigMap[part]].filter(Boolean);\n      \n      for (const [optionKey, values] of Object.entries(configOptionsMap)) {\n        if (valuesToCheck.some(v => values.includes(v)) && !matchedKeys.includes(optionKey)) {\n          matchedKeys.push(optionKey);\n          found = true;\n          break;\n        }\n      }\n      if (!found) {\n        log800('[Summit800] Could not find config option for matrix key part:', part);\n      }\n    }\n    \n    return matchedKeys;\n  }\n\n  /**\n   * Get all permutations of an array (for trying different key orders)\n   * @param {string[]} arr - Array of strings\n   * @returns {string[][]} Array of permutations\n   */\n  getPermutations(arr) {\n    if (arr.length <= 1) return [arr];\n    const result = [];\n    for (let i = 0; i < arr.length; i++) {\n      const rest = [...arr.slice(0, i), ...arr.slice(i + 1)];\n      const restPerms = this.getPermutations(rest);\n      for (const perm of restPerms) {\n        result.push([arr[i], ...perm]);\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Get the effective base price (combination price if available, otherwise static basePrice)\n   * @returns {number} The effective base price\n   */\n  getEffectiveBasePrice() {\n    const combinationPrice = this.getCombinationPrice();\n    return combinationPrice !== null ? combinationPrice : this.basePrice;\n  }\n\n  /**\n   * Check if a section key is part of combination pricing\n   * @param {string} sectionKey - The section/option key to check\n   * @returns {boolean} True if this option is part of combination pricing\n   */\n  isCombinationPricingKey(sectionKey) {\n    const pricing = this.pricingConfig;\n    \n    // For matrix pricing, dynamically detect which keys determine the price\n    if (pricing?.matrix) {\n      const combinationKeys = this.detectCombinationKeys();\n      return combinationKeys.includes(sectionKey);\n    }\n    \n    if (!pricing?.combinations) return false;\n    \n    const combinationKeys = this.detectCombinationKeys();\n    return combinationKeys.includes(sectionKey);\n  }\n\n  /**\n   * Detect the combination keys used in elevations by analyzing the JSON structure\n   * @returns {string[]} Array of config keys to use for elevation lookup\n   */\n  detectElevationCombinationKeys() {\n    const elevations = this.modelConfig?.images?.elevations;\n    if (!elevations) return [];\n    \n    if (this.modelConfig?.images?.combinationKeys?.length) {\n      return this.modelConfig.images.combinationKeys;\n    }\n    \n    if (this.pricingConfig?.combinationKeys?.length) {\n      return this.pricingConfig.combinationKeys;\n    }\n    \n    const availableKeys = Object.keys(elevations);\n    if (availableKeys.length === 0) return [];\n    \n    const sampleKey = availableKeys[0];\n    const numParts = sampleKey.split('|').length;\n    \n    if (numParts === 1) {\n      return [];\n    } else if (numParts === 2) {\n      return ['entryLocation', 'windowOptions'];\n    } else if (numParts === 3) {\n      return ['bathOptions', 'entryLocation', 'sideOptions'];\n    } else {\n      return [];\n    }\n  }\n\n  /**\n   * Get the elevation key for looking up elevation images\n   * Automatically detects whether to use combination keys or single keys based on JSON structure\n   * @returns {string|null} The elevation key or null if not available\n   */\n  getElevationKey() {\n    const elevations = this.modelConfig?.images?.elevations;\n    if (!elevations) {\n      log800('[Summit800] No elevations in modelConfig');\n      return null;\n    }\n    \n    const availableKeys = Object.keys(elevations);\n    if (availableKeys.length === 0) {\n      log800('[Summit800] No elevation keys found');\n      return null;\n    }\n    \n    const sampleKey = availableKeys[0];\n    const numParts = sampleKey.split('|').length;\n    \n    log800('[Summit800] Elevation detection:', { \n      availableKeys, \n      numParts,\n      sampleKey \n    });\n    \n    if (numParts > 1) {\n      const combinationKeys = this.detectElevationCombinationKeys();\n      const keyParts = combinationKeys.map(key => this.currentConfig[key]).filter(Boolean);\n      \n      log800('[Summit800] Building elevation key:', { \n        combinationKeys, \n        configValues: combinationKeys.map(k => this.currentConfig[k]),\n        keyParts,\n        numParts\n      });\n      \n      if (keyParts.length === numParts) {\n        const elevationKey = keyParts.join('|');\n        \n        if (availableKeys.includes(elevationKey)) {\n          log800('[Summit800] Combination elevation key:', elevationKey);\n          return elevationKey;\n        }\n        \n        log800('[Summit800] Trying alternative elevation key orders for:', elevationKey);\n        const permutations = this.getPermutations(keyParts);\n        for (const perm of permutations) {\n          const altKey = perm.join('|');\n          if (availableKeys.includes(altKey)) {\n            log800('[Summit800] Found alternative elevation key:', altKey);\n            return altKey;\n          }\n        }\n      }\n    }\n    \n    // Single key: try common config keys that match elevation keys\n    const singleKeyOptions = [\n      'sideOptions',\n      'exterior', \n      'windowOption',\n      'glass',\n      'exteriorGlassOption',\n      'entryLocation',\n      'windowOptions',\n      'bathOptions'\n    ];\n    \n    for (const configKey of singleKeyOptions) {\n      const configValue = this.currentConfig[configKey];\n      if (configValue && availableKeys.includes(configValue)) {\n        log800('[Summit800] Single elevation key matched:', { configKey, configValue });\n        return configValue;\n      }\n    }\n    \n    log800('[Summit800] No matching elevation key found');\n    return null;\n  }\n\n  updateTotalPrice(skipQueueUpdate = false) {\n    // Prevent infinite loops by allowing callers to skip the queue update\n    if (this._updatingPrice) return; // Guard against recursive calls\n    this._updatingPrice = true;\n\n    try {\n      let additionalPrice = 0;\n      \n      // Check for combination-based pricing (matrix or combinations)\n      // If combination pricing exists and matches, use it as the effective base price\n      const combinationPrice = this.getCombinationPrice();\n      const useCombinationPricing = combinationPrice !== null;\n      \n      // Calculate the effective base price\n      // If combination pricing is active, use it; otherwise use the static basePrice\n      const effectiveBasePrice = useCombinationPricing ? combinationPrice : this.basePrice;\n      \n      log800('[Summit800] Price calculation:', {\n        useCombinationPricing,\n        combinationPrice,\n        staticBasePrice: this.basePrice,\n        effectiveBasePrice\n      });\n\n      this.steps.forEach(step => {\n        if (!step.options) return;\n        Object.keys(step.options).forEach(sectionKey => {\n          // Skip options that are part of combination pricing (their price is already in combinationPrice)\n          if (useCombinationPricing && this.isCombinationPricingKey(sectionKey)) {\n            log800('[Summit800] Skipping combination pricing key:', sectionKey);\n            return;\n          }\n          if (sectionKey === 'installation') return;\n          \n          const sectionData = step.options[sectionKey];\n          const nestedKeys = ['main', 'bath', 'fixture', 'accent', 'countertop', 'cabinets'];\n\n          if (nestedKeys.some(k => sectionData[k])) {\n            nestedKeys.forEach(subKey => {\n              if (!sectionData[subKey]?.options) return;\n              const configValue = this.currentConfig[sectionKey]?.[subKey];\n              const selectedOption = sectionData[subKey].options.find(opt => opt.value === configValue);\n              if (selectedOption?.price) additionalPrice += selectedOption.price;\n            });\n          } else if (sectionData.options) {\n            const configValue = this.currentConfig[sectionKey];\n            const selectedOption = sectionData.options.find(opt => opt.value === configValue);\n            if (selectedOption?.price) additionalPrice += selectedOption.price;\n          }\n        });\n      });\n\n      // Base product option price (excludes shipping/installation/permit)\n      this.configPrice = additionalPrice;\n\n      // Add installation + shipping costs from API (only after ZIP is known)\n      let servicesPrice = 0;\n      if (this.hasValidUserFormData()) {\n        const apiShipping = normalizeNumber(this.finalPriceData?.shipping_cost, 0);\n        const apiInstall = window.ConfiguratorShared.computeInstallationCost(\n          this.finalPriceData?.breakdown?.installation,\n          this.currentConfig?.installation\n        );\n        servicesPrice = apiShipping + apiInstall;\n      }\n\n      const totalPrice = effectiveBasePrice + additionalPrice + servicesPrice + (this.permitPlanPrice || 0);\n\n      // Update ALL price elements (header and mobile footer)\n      const priceEls = $$('[data-configurator-price]', this.step2Section);\n      priceEls.forEach(el => el.textContent = formatPrice(totalPrice));\n\n      // Update ALL monthly price elements\n      const monthlyEls = $$('[data-monthly-price]', this.step2Section);\n      monthlyEls.forEach(el => el.textContent = formatPrice(Math.round(totalPrice / 180)));\n\n      // Only queue update if explicitly requested and not already in progress\n      // This prevents infinite loops - queueFinalPriceUpdate will call updateTotalPrice with skipQueueUpdate=true\n      if (!skipQueueUpdate && this.hasValidUserFormData() && !this._priceUpdateQueued) {\n        this._priceUpdateQueued = true;\n        // Use requestAnimationFrame to defer the API call and prevent blocking\n        requestAnimationFrame(() => {\n          this._priceUpdateQueued = false;\n          this.queueFinalPriceUpdate();\n        });\n      }\n    } finally {\n      this._updatingPrice = false;\n    }\n  }\n\n  resolveTextureReference(textureValue) {\n    if (!textureValue || typeof textureValue !== 'string') return textureValue;\n    const trimmed = textureValue.trim();\n    if (trimmed.startsWith('http://') || trimmed.startsWith('https://') || trimmed.startsWith('//')) return trimmed;\n    return this.texturesData?.[trimmed] || trimmed;\n  }\n\n  // ============================================================================\n  // SERVICES TAB (Data-Driven)\n  // ============================================================================\n\n  hasValidUserFormData() {\n    return Boolean(\n      this.userFormData &&\n      this.userFormData.firstName &&\n      this.userFormData.email &&\n      this.userFormData.zipCode\n    );\n  }\n\n  getModelSlug() {\n    const modelName = this.modelsData?.name || this.modelConfig?.model?.name || this.modelConfig?.name || this.modelConfig?.model || 'summit';\n    return window.ConfiguratorShared.canonicalModel(modelName);\n  }\n\n  buildFinalPricePayload(installationTypeOverride) {\n    const zip = String(this.userFormData?.zipCode || '').trim();\n\n    const pick = (...keys) => window.ConfiguratorShared.pickFirst(this.currentConfig, keys);\n\n    const depth = normalizeNumber(this.modelsData?.depth ?? this.modelConfig?.depth ?? this.modelConfig?.model?.dimensions?.depth, null);\n    const length = normalizeNumber(this.modelsData?.length ?? this.modelConfig?.length ?? this.modelConfig?.model?.dimensions?.length, null);\n\n    return window.ConfiguratorShared.buildInstallationCostPayload({\n      zip,\n      model: this.getModelSlug(),\n      depth,\n      length,\n      interior: pick('interior', 'interiorFinish', 'mainFloorFinish', 'flooring'),\n      kitchen: pick('kitchen') || '',\n      roofStyle: pick('roofStyle', 'roof', 'roofType'),\n    });\n  }\n\n  async fetchFinalPrice(payload) {\n    // DRY: moved to `assets/configurator-shared.js` installation cost client.\n    return payload;\n  }\n\n  queueFinalPriceUpdate(servicesContainer) {\n    if (!this.hasValidUserFormData()) return;\n\n    if (!this.installationCostClient) {\n      this.installationCostClient = window.ConfiguratorShared.createInstallationCostClient();\n    }\n\n    const selectedType = String(this.currentConfig.installation || 'shell');\n    const depth = normalizeNumber(this.modelsData?.depth ?? this.modelConfig?.depth ?? this.modelConfig?.model?.dimensions?.depth, null);\n    const length = normalizeNumber(this.modelsData?.length ?? this.modelConfig?.length ?? this.modelConfig?.model?.dimensions?.length, null);\n    \n    // Use effective base price which handles combination/matrix pricing\n    const base_product_price = this.getEffectiveBasePrice() + this.configPrice;\n\n    window.ConfiguratorShared.queueInstallationPricing({\n      client: this.installationCostClient,\n      zip: this.userFormData?.zipCode,\n      modelRaw: this.getModelSlug(),\n      depth,\n      length,\n      currentConfig: this.currentConfig,\n      selectedType,\n      base_product_price\n    })\n      .then((out) => {\n        if (!out?.installation) return;\n        this.finalPriceData = out.finalPriceData;\n\n        window.ConfiguratorShared.applyInstallationCostsToServiceOptions({\n          container: servicesContainer || this.step2Section,\n          installation: out.installation,\n          formatPrice,\n          prefixPlus: false,\n        });\n\n        // Pass skipQueueUpdate=true to prevent infinite loop\n        this.updateTotalPrice(true);\n\n        // Notify only when we actually fetched new pricing (avoid spam on cached recalcs).\n        if (out?.meta?.didFetch && out?.meta?.payloadKey) {\n          if (this._lastInstallPricingToastKey !== out.meta.payloadKey) {\n            this._lastInstallPricingToastKey = out.meta.payloadKey;\n            window.ConfiguratorShared.showSuccess('Installation pricing updated.', 'Pricing');\n          }\n        }\n      })\n      .catch((e) => {\n        const msg = e?.message || String(e || 'Installation pricing request failed');\n        window.ConfiguratorShared.showError(msg, 'Installation pricing');\n      });\n  }\n\n  applyFinalPriceToServicesUI(container) {\n    if (!container || !this.finalPriceData) return;\n\n    const install = this.finalPriceData?.breakdown?.installation;\n    if (!install) return;\n\n    window.ConfiguratorShared.applyInstallationCostsToServiceOptions({\n      container,\n      installation: install,\n      formatPrice,\n      prefixPlus: false,\n    });\n  }\n\n  focusSaveDesignForm() {\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n    const firstInput =\n      contentWrapper.querySelector('[data-summary-form] input[name=\"firstName\"]') ||\n      contentWrapper.querySelector('[data-summary-form] input') ||\n      null;\n    if (firstInput) {\n      firstInput.scrollIntoView({ behavior: 'smooth', block: 'center' });\n      firstInput.focus({ preventScroll: true });\n    }\n  }\n\n  focusInstallationOptions() {\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n    const installSection =\n      contentWrapper.querySelector('[data-config-section=\"installation\"]') ||\n      contentWrapper.querySelector('[data-services-options]') ||\n      null;\n    if (installSection) installSection.scrollIntoView({ behavior: 'smooth', block: 'start' });\n  }\n\n  getSaveDesignFormHTML() {\n    return `\n      <div class=\"config-section summary-form-view\" data-save-design-form>\n        <div class=\"text-center mb-md-5 mb-3 pe-xl-1\">\n          <h2 class=\"h3 mb-md-3 mb-2\">You're almost done!</h2>\n          <p class=\"mb-0\">Your build is ready. Save your design by completing the form and get access to information about pricing, shipping, professional assembly, local permits, and financing options.</p>\n        </div>\n        <form class=\"summary-contact-form\" data-summary-form>\n          <div class=\"input-group mb-2\"><input type=\"text\" name=\"firstName\" placeholder=\"First Name *\" class=\"form-control\" required></div>\n          <div class=\"input-group mb-2\"><input type=\"text\" name=\"lastName\" placeholder=\"Last Name *\" class=\"form-control\" required></div>\n          <div class=\"input-group mb-2\"><input type=\"email\" name=\"email\" placeholder=\"Email *\" class=\"form-control\" required></div>\n          <div class=\"input-group mb-2\"><input type=\"text\" name=\"zipCode\" placeholder=\"ZIP code *\" class=\"form-control\" required></div>\n          <div class=\"input-group mb-2\"><input type=\"tel\" name=\"phone\" placeholder=\"Phone Number\" class=\"form-control\"></div>\n          <p class=\"form-disclaimer mb-xl-13 mb-md-7 mb-4\">By providing a telephone number and when scheduling your consultation you are consenting to be contacted by SMS text message. Message & data rates may apply. You can reply STOP to opt-out of further messaging.</p>\n          <button type=\"submit\" class=\"visually-hidden\" aria-hidden=\"true\" tabindex=\"-1\">Submit</button>\n        </form>\n      </div>\n    `;\n  }\n\n  attachSaveDesignFormHandlers(container) {\n    const form = $('[data-summary-form]', container);\n    if (!form) return;\n\n    // Create and attach form validator for real-time validation\n    const validator = window.ConfiguratorShared?.createFormValidator?.(form);\n    if (validator) {\n      validator.attachListeners();\n      this._formValidator = validator;\n    }\n\n    form.addEventListener('submit', async (e) => {\n      e.preventDefault();\n      \n      // Validate form using our custom validator first\n      if (this._formValidator) {\n        const { valid, firstInvalid } = this._formValidator.validateAll();\n        if (!valid) {\n          firstInvalid?.focus();\n          firstInvalid?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n          return;\n        }\n      }\n      \n      // Prevent double submission\n      if (this._isValidatingZip) return;\n      \n      const formData = new FormData(form);\n      const pendingUserData = {\n        firstName: String(formData.get('firstName') || ''),\n        lastName: String(formData.get('lastName') || ''),\n        email: String(formData.get('email') || ''),\n        zipCode: String(formData.get('zipCode') || ''),\n        phone: String(formData.get('phone') || '')\n      };\n\n      // Show loading state on submit button\n      const submitBtn = form.querySelector('[data-next-step], button[type=\"submit\"], .next-step-btn');\n      const footerBtn = $('[data-next-step]', this.step2Section);\n      const btnToDisable = submitBtn || footerBtn;\n      const nextBtnTextSpan = $('[data-next-step-text]', this.step2Section);\n      const originalBtnText = nextBtnTextSpan?.textContent || 'SAVE DESIGN';\n      \n      try {\n        this._isValidatingZip = true;\n        if (btnToDisable) {\n          btnToDisable.disabled = true;\n        }\n        // Show \"Loading...\" text on button (similar to Design Your Own button)\n        if (nextBtnTextSpan) {\n          nextBtnTextSpan.textContent = 'Loading...';\n        }\n\n        // Build payload for validation\n        const depth = normalizeNumber(this.modelsData?.depth ?? this.modelConfig?.depth ?? this.modelConfig?.model?.dimensions?.depth, null);\n        const length = normalizeNumber(this.modelsData?.length ?? this.modelConfig?.length ?? this.modelConfig?.model?.dimensions?.length, null);\n        const pick = (...keys) => window.ConfiguratorShared.pickFirst(this.currentConfig, keys);\n\n        // CRITICAL: Validate ZIP code with API BEFORE allowing step progression\n        const result = await window.ConfiguratorShared.validateZipCodeWithAPI({\n          zip: pendingUserData.zipCode,\n          model: this.getModelSlug(),\n          depth,\n          length,\n          interior: pick('interior', 'interiorFinish', 'mainFloorFinish', 'flooring'),\n          kitchen: pick('kitchen') || '',\n          roofStyle: pick('roofStyle', 'roof', 'roofType'),\n          base_product_price: this.getEffectiveBasePrice() + this.configPrice,\n        });\n\n        // API returned 200 and valid data - NOW we can proceed\n        this.userFormData = pendingUserData;\n        window.studioShedUserData = this.userFormData;\n        \n        // Store the validated API data (new format from final-price API)\n        if (result?.data) {\n          const apiData = result.data;\n          const breakdownInstallation = apiData.breakdown?.installation || {};\n          const breakdownShipping = apiData.breakdown?.shipping || {};\n          const selectedType = String(this.currentConfig.installation || 'shell');\n          \n          // Build installation object with prices from breakdown\n          const installationWithPrices = {\n            shell: normalizeNumber(breakdownInstallation.shell, 0),\n            lifestyle: normalizeNumber(breakdownInstallation.lifestyle, 0),\n            kitchenbath: normalizeNumber(breakdownInstallation.kitchenbath, 0),\n            selected_type: breakdownInstallation.selected_type || selectedType,\n            selected_cost: normalizeNumber(breakdownInstallation.selected_cost || apiData.installation_cost, 0),\n            state_code: breakdownInstallation.state_code,\n            zone: breakdownInstallation.zone,\n          };\n          \n          this.finalPriceData = {\n            breakdown: { \n              installation: installationWithPrices,\n              installationPrices: {\n                shell: normalizeNumber(breakdownInstallation.shell, 0),\n                lifestyle: normalizeNumber(breakdownInstallation.lifestyle, 0),\n                kitchenbath: normalizeNumber(breakdownInstallation.kitchenbath, 0),\n              },\n              shipping: {\n                base_subtotal: normalizeNumber(breakdownShipping.base_subtotal, 0),\n                depth_surcharge: normalizeNumber(breakdownShipping.depth_surcharge, 0),\n                interior_surcharge: normalizeNumber(breakdownShipping.interior_surcharge, 0),\n                inflation_surcharge: normalizeNumber(breakdownShipping.inflation_surcharge, 0),\n              },\n            },\n            installation_cost: normalizeNumber(apiData.installation_cost, 0),\n            shipping_cost: normalizeNumber(apiData.shipping_cost, 0),\n            total_price: normalizeNumber(apiData.total_price, 0),\n            product_price: normalizeNumber(apiData.product_price, 0),\n            city: apiData.city || '',\n            state_code: apiData.state_code || '',\n          };\n          // Track the ZIP code used to fetch this data to prevent duplicate API calls\n          this._finalPriceDataZip = pendingUserData.zipCode;\n        }\n\n        // Call Save Design API (non-blocking - don't wait for it)\n        // This runs in parallel with the UI update\n        window.ConfiguratorShared.saveDesignToAPI(this, pendingUserData)\n          .then((saveResult) => {\n            if (saveResult?.success) {\n              console.log('[Summit-800] Design saved successfully:', saveResult.design_id);\n            } else if (saveResult?.error) {\n              console.warn('[Summit-800] Save Design API:', saveResult.error);\n            }\n          })\n          .catch((error) => {\n            // Log error but don't block user flow\n            console.error('[Summit-800] Save Design API error:', error);\n          });\n\n        // SUCCESS: Show installation options\n        this.populateServicesOptions(true);\n        \n        setTimeout(() => {\n          this.focusInstallationOptions();\n          // Update total price after switching tabs\n          this.updateTotalPrice(true);\n        }, 50);\n        \n      } catch (error) {\n        // FAILURE: Stay on current step and show error\n        const errorMessage = error?.message || 'ZIP code validation failed. Please try again.';\n        window.ConfiguratorShared.showError(errorMessage, 'Invalid ZIP Code');\n        \n        // Show contact link below the Save Design button\n        window.ConfiguratorShared.showContactLinkOnError(this.step2Section);\n        \n        // Focus the ZIP code input for correction\n        const zipInput = form.querySelector('input[name=\"zipCode\"]');\n        if (zipInput) {\n          zipInput.focus();\n          zipInput.select();\n        }\n        \n        // Do NOT switch tabs - stay on current step\n        // Restore button text only on error (success case will have already switched to installation options with SUMMARY)\n        if (btnToDisable) {\n          btnToDisable.disabled = false;\n        }\n        // Also re-enable the footer button if it's different from btnToDisable\n        if (footerBtn && footerBtn !== btnToDisable) {\n          footerBtn.disabled = false;\n        }\n        // Also re-enable submit button if it's different\n        if (submitBtn && submitBtn !== btnToDisable) {\n          submitBtn.disabled = false;\n        }\n        // Restore the span text, not the entire button (to preserve button structure with arrow)\n        if (nextBtnTextSpan) {\n          nextBtnTextSpan.textContent = originalBtnText;\n        }\n      } finally {\n        this._isValidatingZip = false;\n        // Re-enable ALL buttons that might have been disabled\n        if (btnToDisable) {\n          btnToDisable.disabled = false;\n        }\n        if (footerBtn && footerBtn !== btnToDisable) {\n          footerBtn.disabled = false;\n        }\n        if (submitBtn && submitBtn !== btnToDisable) {\n          submitBtn.disabled = false;\n        }\n      }\n    });\n  }\n\n  populateServicesOptions(showInstallationOptions = false) {\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n\n    contentWrapper.innerHTML = '';\n    const installationOptions = this.modelConfig?.services?.installation?.options || [];\n    const panelContent = document.createElement('div');\n    panelContent.className = 'panel-content';\n    panelContent.dataset.tabContent = 'services';\n\n    // Show installation options if:\n    // 1. Explicitly requested (after form submission), OR\n    // 2. User already has valid form data and price data (returning to Services tab)\n    const hasValidData = this.hasValidUserFormData() && this.finalPriceData;\n    if (showInstallationOptions || hasValidData) {\n      if (this.hasValidUserFormData()) {\n        this.showInstallationOptionsContent(contentWrapper, panelContent, installationOptions);\n        return;\n      }\n    }\n\n    this.userFormData = null;\n    window.studioShedUserData = null;\n    this.finalPriceData = null;\n    this._finalPriceDataZip = null;\n\n    panelContent.innerHTML = this.getSaveDesignFormHTML();\n    contentWrapper.appendChild(panelContent);\n    this.attachSaveDesignFormHandlers(panelContent);\n\n    const nextBtnText = $('[data-next-step-text]', this.step2Section);\n    if (nextBtnText) nextBtnText.textContent = 'SAVE DESIGN';\n    const backBtn = $('[data-back-step]', this.step2Section);\n    if (backBtn) backBtn.style.display = '';\n    this.updateSummaryTabState();\n    const headerSaveBtn = $('[data-save-design]', this.step2Section);\n    if (headerSaveBtn) headerSaveBtn.style.display = 'none';\n    this.updateTotalPrice(true);\n  }\n\n  showInstallationOptionsContent(contentWrapper, panelContent, installationOptions) {\n    installationOptions = [...installationOptions].sort((a, b) => {\n      const valA = (a.value || '').toLowerCase();\n      const valB = (b.value || '').toLowerCase();\n      \n      const getOrder = (val) => {\n        if (val.includes('lifestyle')) return 1;\n        if (val === 'shell' || val.includes('shell')) return 2;\n        if (val.includes('product') || val.includes('diy') || val === 'none') return 3;\n        return 99;\n      };\n      \n      return getOrder(valA) - getOrder(valB);\n    });\n\n    const rawInteriorValue = String(\n      this.currentConfig.interiorOptions || \n      this.currentConfig.interiorPackage || \n      this.currentConfig.layout || \n      this.currentConfig.interior ||\n      window.ConfiguratorShared?.pickFirst?.(this.currentConfig, ['interiorFinish', 'mainFloorFinish', 'flooring']) || \n      ''\n    ).toLowerCase().replace(/[\\s_-]/g, '');\n\n    const isShellOnly = rawInteriorValue.includes('shellonly') || rawInteriorValue === 'shell' || rawInteriorValue === 'none';\n\n    if (isShellOnly) {\n      installationOptions = installationOptions.filter(o => !/lifestyle/i.test(o.value));\n    }\n\n    let defaultVal;\n    if (isShellOnly) {\n      // For shell-only interiors, look for \"shell-only\" or \"shell\" installation options\n      defaultVal = installationOptions.find(o => o.value === 'shell-only' || o.value === 'shell')?.value;\n    } else {\n      // For lifestyle interiors, look for \"lifestyle\" options\n      defaultVal = installationOptions.find(o => /lifestyle/i.test(o.value))?.value;\n    }\n    \n    if (!defaultVal) {\n      defaultVal = installationOptions.find(o => o.isDefault)?.value || installationOptions[0]?.value;\n    }\n\n    const currentValue = this.currentConfig.installation || defaultVal;\n    if (currentValue) this.currentConfig.installation = currentValue;\n\n    panelContent.innerHTML = `\n      <div class=\"config-section services-section\" data-config-section=\"installation\">\n        <p class=\"services-header fw-medium mb-1\" data-services-header>Installation</p>\n        <div class=\"services-options\" data-services-options>\n          ${installationOptions.map(option => this.renderServiceOption(option, option.value === currentValue)).join('')}\n        </div>\n      </div>\n    `;\n    contentWrapper.appendChild(panelContent);\n\n    qa('[data-service-option]', '.service-option-card', panelContent).forEach(card => {\n      card.addEventListener('click', () => {\n        const { section, value } = card.dataset;\n        qa('[data-service-option]', '.service-option-card', card.closest('[data-services-options], .services-options')).forEach(c => c.classList.remove('selected'));\n        card.classList.add('selected');\n        this.currentConfig[section] = value;\n        this.updateTotalPrice(true);\n        if (typeof this.recalculateSummaryTotal === 'function') this.recalculateSummaryTotal();\n      });\n    });\n\n    this.currentStep = this.steps.length + 1;\n    const nextBtnText = $('[data-next-step-text]', this.step2Section);\n    if (nextBtnText) nextBtnText.textContent = 'Summary';\n    const backBtn = $('[data-back-step]', this.step2Section);\n    if (backBtn) backBtn.style.display = '';\n    const headerSaveBtn = $('[data-save-design]', this.step2Section);\n    if (headerSaveBtn) { headerSaveBtn.style.display = ''; headerSaveBtn.textContent = 'START OVER'; headerSaveBtn.dataset.startOver = 'true'; }\n    this.updateTotalPrice(true);\n    this.updateSummaryTabState();\n    const installation = this.finalPriceData?.breakdown?.installation;\n    if (installation) {\n      window.ConfiguratorShared.applyInstallationCostsToServiceOptions({\n        container: panelContent, installation, formatPrice: (val) => window.ConfiguratorShared.formatPriceSmart(val, { noDecimals: true }), prefixPlus: false,\n      });\n    }\n  }\n\n  renderServiceOption(option, isSelected) {\n    const priceDisplay = option.price > 0 ? `<span class=\"service-price\" data-service-price style=\"letter-spacing: -0.02em;\">${formatPrice(option.price)}</span>` : '';\n    const noteHTML = option.note ? `<p class=\"fs-sm fw-medium mt-4 mb-0\" data-service-note>${option.note}</p>` : '';\n    return `\n      <div class=\"service-option-card${isSelected ? ' selected' : ''}\" data-service-option data-section=\"installation\" data-value=\"${option.value}\" data-display-name=\"${option.displayName}\" data-price=\"${option.price || 0}\">\n        <div class=\"service-option-header d-flex align-items-center justify-content-between mb-2\" data-service-header>\n          <p class=\"service-option-title fw-medium mb-0\" data-service-title style=\"letter-spacing: -0.02em;\">${option.displayName}</p>\n          ${priceDisplay}\n          <span class=\"aspect-variant-check\" data-service-checkmark>\n            <svg viewBox=\"0 0 8 7\" fill=\"none\" style=\"width: 11px; height: 6px; margin-bottom: -1px;\">\n              <path d=\"M0.5 3.35714L2.77027 5.5L7.5 0.5\" stroke=\"currentColor\" stroke-linecap=\"round\"></path>\n            </svg>\n          </span>\n        </div>\n        <p class=\"fs-sm mb-0\" data-service-description style=\"letter-spacing: -0.01em;\">${option.description}</p>\n        ${noteHTML}\n      </div>\n    `;\n  }\n\n  // ============================================================================\n  // SUMMARY TAB (Data-Driven)\n  // ============================================================================\n\n  showSummary() {\n    // Summary tab should be disabled when form is invalid.\n    // Do NOT redirect - just prevent display if somehow accessed.\n    if (!this.hasValidUserFormData()) {\n      // Ensure Summary tab is disabled\n      this.updateSummaryTabState();\n      return;\n    }\n\n    this.showThankYouSummary();\n\n    this.currentStep = this.steps.length + 2;\n\n    const panelFooter = q('[data-panel-footer]', '.panel-footer', this.step2Section);\n    if (panelFooter) panelFooter.style.display = 'none';\n\n    const saveDesignBtn = $('[data-save-design]', this.step2Section);\n    if (saveDesignBtn) {\n      saveDesignBtn.textContent = 'START OVER';\n      saveDesignBtn.dataset.startOver = 'true';\n    }\n\n    // Add product-summary-tab class to data-configurator-main element (Summit-800-specific)\n    const configuratorMain = $('[data-configurator-main]', this.step2Section);\n    if (configuratorMain) {\n      configuratorMain.classList.add('product-summary-tab');\n    }\n  }\n\n  showThankYouSummary() {\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n\n    // Change layout to 6-6 columns on thank you page\n    const viewer = $('.configurator-viewer', this.step2Section);\n    const panel = $('.configurator-panel', this.step2Section);\n    if (viewer) {\n      viewer.classList.remove('col-lg-8');\n      viewer.classList.add('col-lg-6');\n      const modelContainer = $('[data-model-viewer], .model-viewer-container', viewer);\n      if (modelContainer) {\n        modelContainer.style.setProperty('max-width', '100%', 'important');\n        modelContainer.style.setProperty('margin', '0 auto', 'important');\n      }\n    }\n    if (panel) {\n      panel.classList.remove('col-lg-4');\n      panel.classList.add('col-lg-6');\n    }\n\n    // Trigger 3D viewer resize after layout change\n    setTimeout(() => {\n      if (this.viewer3D?.sceneManager?.onResize) {\n        this.viewer3D.sceneManager.onResize();\n      }\n    }, 50);\n\n    contentWrapper.innerHTML = '';\n\n    const panelContent = document.createElement('div');\n    panelContent.className = 'panel-content summary-panel';\n    panelContent.dataset.tabContent = 'summary';\n    panelContent.innerHTML = this.buildThankYouHTML();\n    contentWrapper.appendChild(panelContent);\n\n    this.setupThankYouEventListeners(panelContent);\n  }\n\n  buildThankYouHTML() {\n    const variantTitle = this.selectedVariant?.title || this.modelsData?.name || '';\n    const orientation = this.currentConfig.orientation;\n    // Use effective base price which handles combination/matrix pricing\n    const productPrice = this.getEffectiveBasePrice() + this.configPrice;\n\n    const installationOptions = this.modelConfig?.services?.installation?.options || [];\n    const selectedInstallation = installationOptions.find(opt => opt.value === this.currentConfig.installation);\n    \n    // Get installation price from API breakdown\n    // Use computeInstallationCost for consistency with updateTotalPrice\n    let installationPrice = 0;\n    const installationValue = this.currentConfig.installation || '';\n    \n    if (this.finalPriceData?.breakdown?.installation) {\n      // const breakdown = this.finalPriceData.breakdown.installation;\n      \n      // // If user selected \"shell-lifestyle\", use lifestyle price from API breakdown\n      // if (installationValue.toLowerCase().includes('lifestyle')) {\n      //   installationPrice = normalizeNumber(breakdown.lifestyle, 0);\n      // } else {\n      //   // For other options, use the computed installation cost\n        const computedCents = window.ConfiguratorShared.computeInstallationCost(\n          this.finalPriceData.breakdown.installation,\n          installationValue\n        );\n        installationPrice = computedCents > 0 ? computedCents : normalizeNumber(selectedInstallation?.price, 0);\n      //}\n    } else {\n      // Fallback if no API data available\n      installationPrice = normalizeNumber(selectedInstallation?.price, 0);\n    }\n    \n    const installationName = selectedInstallation?.displayName || '';\n\n    const shippingPrice = normalizeNumber(this.finalPriceData?.shipping_cost, this.modelConfig?.shippingPrice || 0);\n    const estimatedTotal = productPrice + shippingPrice + this.permitPlanPrice + installationPrice;\n    const zipCode = this.userFormData?.zipCode || '';\n    const configSummary = this.buildConfigSummaryString();\n\n    // Build product title with optional orientation\n    const productTitleParts = [variantTitle];\n    if (orientation) productTitleParts.push(`(${formatOptionValue(orientation)})`);\n    const productTitle = productTitleParts.filter(Boolean).join(' ');\n\n    // Build shipping label with city and state_code from API\n    const city = this.finalPriceData?.city || '';\n    const stateCode = this.finalPriceData?.state_code || '';\n    const shippingLocation = this.modelConfig?.shippingLocation || '';\n    \n    let shippingLabel = 'Shipping';\n    if (city && stateCode && zipCode) {\n      shippingLabel = `Shipping to ${city}, ${stateCode} (${zipCode})`;\n    } else if (city && stateCode) {\n      shippingLabel = `Shipping to ${city}, ${stateCode}`;\n    } else if (shippingLocation && zipCode) {\n      shippingLabel = `Shipping to ${shippingLocation} (${zipCode})`;\n    } else if (zipCode) {\n      shippingLabel = `Shipping (${zipCode})`;\n    }\n\n    return `\n      <div class=\"summary-content summary-thankyou\">\n        <div class=\"thank-you-header-box mb-md-6 mb-4\">\n          <h2 class=\"h3 mb-3 thank-you-title\">Thank you!</h2>\n          <p class=\"thank-you-description mb-0\" style=\"letter-spacing: -0.02em;\">Your order summary has been emailed, and a dedicated team member will contact you shortly to guide you through the next steps and help you understand the entire process, ensuring everything is handled seamlessly.</p>\n        </div>\n        \n        <div class=\"summary-product-section mb-2\">\n          <div class=\"d-flex align-items-end justify-content-between mb-2\">\n            <h3 class=\"h4 mb-0 summary-product-title\">${productTitle}</h3>\n            <span class=\"fw-medium\" style=\"line-height: 1.4; letter-spacing: -0.02em;\">${formatPrice(productPrice)}</span>\n          </div>\n          ${configSummary ? `\n          <div class=\"d-flex align-items-center justify-content-between gap-lg-4 gap-3\">\n            <p class=\"fs-sm text-gray-600 mb-0\" style=\"letter-spacing: -0.01em;\">${configSummary}</p>\n            <a href=\"#\" class=\"text-decoration-underline text-nowrap\" data-edit-design>Edit Design</a>\n          </div>\n          ` : ''}\n        </div>\n        \n        <div class=\"summary-price-details-box mb-md-4 mb-3\" data-price-details-box>\n          <button class=\"price-details-toggle d-flex align-items-center justify-content-between\" data-toggle-price-details>\n            <span>Price details</span>\n            <span class=\"d-flex align-items-center\" data-toggle-icon>\n              <svg aria-hidden=\"true\" focusable=\"false\" style=\"width:15px; height:15px;\">\n                <use href=\"#icon-modal-plus\"></use>\n              </svg>\n            </span>\n          </button>\n          <div data-price-details-content>\n            <div class=\"price-details-content\">${this.buildPriceDetailsHTML()}</div>\n          </div>\n        </div>\n        \n        <div class=\"summary-line-items\" data-summary-line-items>\n          <div class=\"summary-line-item d-flex align-items-center justify-content-between gap-2 py-md-4 py-3\" data-summary-line-item=\"shipping\">\n            <span data-line-item-label>${shippingLabel}</span>\n            <span class=\"fw-medium\" data-line-item-price>${shippingPrice > 0 ? formatPrice(shippingPrice) : 'Included'}</span>\n          </div>\n          ${installationPrice > 0 && installationName ? `\n          <div class=\"summary-line-item d-flex align-items-center justify-content-between gap-2 py-md-4 py-3\" data-summary-line-item=\"installation\">\n            <span class=\"line-item-label\" data-line-item-label>${installationName} <span class=\"line-item-note\" data-line-item-note>(subject to availability)</span></span>\n            <span class=\"line-item-price fw-medium\" data-line-item-price>${formatPrice(installationPrice)}</span>\n          </div>` : ''}\n          <div class=\"summary-line-item py-md-4 py-3\" data-summary-line-item=\"permit\">\n            <div class=\"d-flex align-items-center justify-content-between gap-2 mb-2\" data-line-item-main>\n              <span data-line-item-label>${this.permitPlanSelected === 'include' ? 'Include Permit Plans' : 'No Permit Plans'}</span>\n              <span class=\"fw-medium\" data-permit-price-display>${this.permitPlanPrice > 0 ? formatPrice(this.permitPlanPrice) : 'No charge'}</span>\n            </div>\n            <button class=\"bg-transparent border-0 fw-light text-decoration-underline p-0\" style=\"letter-spacing: -0.02em;\" data-change-permit-plans>Change permit plans</button>\n          </div>\n          <div class=\"summary-line-item py-md-4 py-3\" data-summary-line-item=\"foundation\">\n            <div class=\"d-flex align-items-center justify-content-between gap-2 mb-2\" data-line-item-main>\n              <span class=\"line-item-label\" data-foundation-label>Foundation TBD</span>\n              <span class=\"fw-medium\" data-line-item-price>Cost not included</span>\n            </div>\n            <button class=\"bg-transparent border-0 fw-light text-decoration-underline p-0\" style=\"letter-spacing: -0.02em;\" data-change-foundation-type>Change foundation type</button>\n          </div>\n        </div>\n        \n        <div class=\"pt-lg-4 pb-lg-5 py-3\" data-summary-total>\n          <div class=\"d-flex justify-content-between mb-2\" data-summary-total-row>\n            <h5 class=\"mb-0\" data-total-label>Estimated Total</h5>\n            <h5 class=\"mb-0\" data-summary-total-price>${formatPrice(estimatedTotal)}</h5>\n          </div>\n          <p class=\"fs-sm mb-0\" data-total-note style=\"letter-spacing: -0.01em;\">${this.getTotalNoteText()}</p>\n        </div>\n        \n        ${this.buildCTASectionHTML()}\n        ${this.buildDesignDetailsHTML(variantTitle)}\n      </div>\n    `;\n  }\n\n  buildCTASectionHTML() {\n    // Get CTA config from modelConfig or use Summit-specific defaults\n    const productName = this.modelsData?.name || this.selectedVariant?.title || 'Summit';\n    \n    // Summit-specific default configuration\n    const defaultCta = {\n      calculator: {\n        icon: `<svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n          <rect width=\"40\" height=\"40\" rx=\"8\" fill=\"#FDB913\" fill-opacity=\"0.15\"/>\n          <path d=\"M13 14h14v12H13V14z\" stroke=\"#FDB913\" stroke-width=\"1.5\" fill=\"none\"/>\n          <path d=\"M16 18h8M16 21h8M16 24h4\" stroke=\"#FDB913\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n        </svg>`,\n        title: 'Need A Quick Estimate?',\n        link: '/pages/project-cost-calculator',\n        linkText: 'TRY PROJECT COST CALCULATOR'\n      },\n      financing: {\n        logos: [\n          `<img src=\"https://cdn.shopify.com/s/files/1/0969/5304/1190/files/acorn-finance-logo.png?v=1735000000\" alt=\"Acorn Finance\" style=\"height: 24px; width: auto;\">`,\n          `<img src=\"https://cdn.shopify.com/s/files/1/0969/5304/1190/files/renofi-logo.png?v=1735000000\" alt=\"RenoFi\" style=\"height: 24px; width: auto;\">`\n        ],\n        title: 'Monthly Financing Available!',\n        subtitle: 'Plan smarter with the right financing',\n        link: '/pages/financing',\n        linkText: 'EXPLORE FINANCING OPTIONS'\n      },\n      consultation: {\n        title: 'Schedule a FREE Online Consultation',\n        description: 'Select the available time that works for you to explore your project goals, budget, build site, and initial design.',\n        link: '/pages/consultation',\n        buttonText: 'BOOK A FREE CONSULTATION'\n      }\n    };\n    \n    // PDF icon SVG for downloads\n    const pdfIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" style=\"width: 24px; height: 24px;\">\n      <g clip-path=\"url(#clip0_1618_10352)\">\n        <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M0.67107 22.95C-1.00893 20.91 0.77757 18.48 2.60607 17.445C3.62157 16.8735 4.88607 16.476 6.25107 16.101C5.84487 16.8749 5.3967 17.6261 4.90857 18.351C4.50698 18.5122 4.11573 18.6981 3.73707 18.9075C2.77407 19.4505 1.48707 20.4 2.27757 21.5925C3.04707 22.7535 4.28757 21.477 4.87257 20.8035C5.61957 20.0415 6.46257 18.8385 7.21257 17.5185C8.00607 16.1235 8.72757 14.5485 9.41757 12.8835C10.0401 11.3835 10.5936 9.83855 11.0076 8.39855C11.4276 6.95855 11.7111 5.62505 11.8161 4.50005C11.9016 3.56555 11.8611 2.19005 10.6311 2.37005C9.40107 2.55005 9.41607 3.99005 9.70857 5.11505C9.79457 5.45005 9.90257 5.79755 10.0326 6.15755C9.94057 6.58855 9.82907 7.04355 9.69807 7.52255C9.58807 7.91855 9.46807 8.32405 9.33807 8.73905C8.80876 7.706 8.38995 6.61999 8.08857 5.49905C7.56357 3.47405 7.54107 0.654046 10.2636 0.0690461C12.9861 -0.515954 13.6686 2.57405 13.4886 4.55405C13.3386 6.15905 12.8931 8.12405 12.2181 10.149C12.6501 10.8645 13.1211 11.5815 13.6206 12.279C14.1456 13.0155 14.8356 13.7685 15.4056 14.424C17.4156 14.274 19.3956 14.373 20.8806 14.6535C22.9206 15.039 24.7656 16.3185 23.6856 18.7635C22.6041 21.2085 19.9356 20.8485 18.1656 19.71C16.6893 18.7558 15.3942 17.5471 14.3406 16.14H14.3361C13.2173 14.4622 12.1907 12.7246 11.2611 10.935C10.8171 12.2745 10.1661 14.07 9.61107 15.27C10.3206 15.105 11.0661 14.97 11.8011 14.8575C12.1026 15.3645 12.3906 15.8595 12.6861 16.3395C12.4511 16.3745 12.2061 16.4135 11.9511 16.4565C11.0281 16.6135 10.1231 16.8015 9.23607 17.0205C9.01207 17.4505 8.79507 17.8745 8.58507 18.2925C7.83657 19.7745 7.14657 21.1425 6.29007 22.1175C4.92057 23.6775 2.36007 24.9525 0.68007 22.9125L0.67107 22.95ZM16.4211 15.93C17.3196 16.848 18.1611 17.55 18.9861 18.09C19.9881 18.735 21.1461 19.1115 21.6861 17.985C22.2366 16.8555 21.2196 16.29 20.1561 16.08C19.1076 15.8805 17.8611 15.8715 16.4061 15.924L16.4211 15.93Z\" fill=\"black\"/>\n      </g>\n      <defs>\n        <clipPath id=\"clip0_1618_10352\">\n          <rect width=\"24\" height=\"24\" fill=\"white\"/>\n        </clipPath>\n      </defs>\n    </svg>`;\n    \n    // Build downloads from variant metafield documents\n    const variantDocs = (this.variantDocuments || []).map(doc => ({\n      icon: pdfIcon,\n      title: doc.alt || doc.filename || `${productName} Document`,\n      url: doc.url\n    }));\n    \n    const ctaConfig = this.modelConfig?.cta || defaultCta;\n    const downloads = variantDocs.length ? variantDocs : (this.modelConfig?.downloads || []);\n\n    let html = '';\n\n    // CTA Cards section\n    const calculator = ctaConfig.calculator || defaultCta.calculator;\n    const financing = ctaConfig.financing || defaultCta.financing;\n    \n    html += `<div class=\"d-flex flex-column gap-2 pb-5\" data-summary-cta-section>`;\n    \n    // Consultation section\n    const consultation = ctaConfig.consultation || defaultCta.consultation;\n    html += `\n      <div class=\"py-4 border-top border-gray-200\" data-summary-consultation>\n        <h5 class=\"mb-2 d-none\" data-consultation-title>${consultation.title}</h5>\n        <p class=\"mb-lg-5 mb-3 pe-xl-6\" style=\"letter-spacing: -0.02em;\" data-consultation-description>${consultation.description}</p>\n        <a href=\"${consultation.link}\" class=\"btn btn-primary w-100\" data-consultation-btn target=\"_blank\">${consultation.buttonText}</a>\n      </div>\n    `;\n    // Calculator card\n    html += `\n      <div class=\"calculator-card position-relative overflow-hidden d-flex flex-wrap align-items-center justify-content-between bg-primary-100 rounded gap-2\" data-cta-card=\"calculator\">\n        <div class=\"d-flex align-items-center gap-lg-6 gap-3 me-3\" data-cta-content>\n          <div class=\"calculator-icon position-absolute\">\n            <img src=\"https://cdn.shopify.com/s/files/1/0969/5304/1190/files/calculator.svg?v=1767594243\" alt=\"Calculator\" title=\"Calculator\" class=\"w-100 h-100\"/>\n          </div>\n          <span class=\"fw-medium\" data-cta-text>${calculator.title}</span>\n        </div>\n        <a href=\"${calculator.link}\" class=\"d-flex align-items-center gap-2 text-decoration-none fw-medium\" data-cta-link target=\"_blank\">\n          ${calculator.linkText}\n          <svg viewBox=\"0 0 11 11\" fill=\"none\" style=\"width: 11px; height: 11px;\">\n            <path d=\"M5.5 0.5L10.5 5.5M10.5 5.5L5.5 10.5M10.5 5.5L0.5 5.5\" stroke=\"black\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n          </svg>\n        </a>\n      </div>\n    `;\n\n     \n\n    // Financing card (hidden by default like Aspect)\n    html += `\n      <div class=\"financing-card d-flex flex-wrap align-items-center justify-content-between bg-secondary rounded gap-2 d-none\" data-cta-card=\"financing\">\n        <div class=\"d-flex align-items-center gap-lg-6 gap-3 me-3\" data-cta-content>\n          <div class=\"d-flex flex-column gap-2\" data-financing-logos>\n            <img src=\"https://cdn.shopify.com/s/files/1/0969/5304/1190/files/acorn.png?v=1767596474\" class=\"acorn-logo\" alt=\"Acorn Finance\" title=\"Acorn Finance\"/>\n            <img src=\"https://cdn.shopify.com/s/files/1/0969/5304/1190/files/renofi.png?v=1767596473\" class=\"renofi-logo\" alt=\"RenoFi\" title=\"RenoFi\"/>\n          </div>\n          <div class=\"d-flex flex-column\" data-financing-text>\n            <p class=\"fw-medium mb-1\">${financing.title}</p>\n            <span class=\"fs-sm\" style=\"letter-spacing: -0.01em;\">${financing.subtitle}</span>\n          </div>\n        </div>\n        <a href=\"${financing.link}\" class=\"d-flex align-items-center gap-2 text-decoration-none text-black fw-medium\" data-cta-link target=\"_blank\">\n          ${financing.linkText}\n          <svg viewBox=\"0 0 11 11\" fill=\"none\" style=\"width: 11px; height: 11px;\">\n            <path d=\"M5.5 0.5L10.5 5.5M10.5 5.5L5.5 10.5M10.5 5.5L0.5 5.5\" stroke=\"black\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n          </svg>\n        </a>\n      </div>\n    `;\n\n    html += `</div>`;\n\n    // Downloads section\n    if (downloads.length) {\n      html += `\n        <div class=\"py-4 border-top border-gray-200\" data-summary-downloads>\n          <h5 class=\"mb-3\" data-downloads-title>Downloads</h5>\n          ${downloads.map(dl => `\n            <a href=\"${dl.url || '#'}\" class=\"d-flex align-items-center gap-3 text-decoration-none text-black\" data-download-link target=\"_blank\">\n              <span data-download-icon>${dl.icon}</span>\n              <span class=\"text-decoration-underline\">${dl.title || ''}</span>\n            </a>\n          `).join('')}\n        </div>\n      `;\n    }\n\n    return html;\n  }\n\n  buildConfigSummaryString() {\n    const parts = [];\n    // Keys to exclude from summary (internal/system keys)\n    const excludeKeys = ['installation', 'permitPlan', 'foundationType', 'zipCode'];\n    \n    // Add all selected config values that exist\n    // First check hardcoded common keys\n    const summaryKeys = ['layout', 'kitchenConfig', 'kitchen', 'exterior', 'windowOption', 'roofType', 'roof', \n                         'doorOptions', 'interiorOptions', 'siding', 'sidingType', 'sidingOptions', \n                         'windowConfig', 'orientation'];\n    summaryKeys.forEach(key => {\n      const value = this.currentConfig[key];\n      if (value && typeof value === 'string' && !parts.includes(formatOptionValue(value))) {\n        parts.push(formatOptionValue(value));\n      }\n    });\n    \n    // Also check all other keys in currentConfig (for nested objects, check nested values)\n    Object.keys(this.currentConfig).forEach(key => {\n      if (excludeKeys.includes(key)) return; // Skip excluded keys\n      if (summaryKeys.includes(key)) return; // Already processed above\n      \n      const value = this.currentConfig[key];\n      if (value && typeof value === 'object' && !Array.isArray(value)) {\n        // Handle nested objects (e.g., { flooring: { mainFloorFinish: 'value' } })\n        Object.values(value).forEach(nestedValue => {\n          if (nestedValue && typeof nestedValue === 'string' && !parts.includes(formatOptionValue(nestedValue))) {\n            parts.push(formatOptionValue(nestedValue));\n          }\n        });\n      } else if (value && typeof value === 'string' && !parts.includes(formatOptionValue(value))) {\n        parts.push(formatOptionValue(value));\n      }\n    });\n    \n    return parts.join(' | ');\n  }\n\n  buildPriceDetailsHTML() {\n    const variantTitle = this.selectedVariant?.title || this.modelsData?.name || '';\n    const sqFt = this.selectedVariant?.sqFt || this.modelsData?.squareFootage || '';\n\n    // Check if interior package is \"Shell Only\" - normalize the value for comparison\n    const interiorPackageValue = this.currentConfig.interiorOptions || this.currentConfig.interiorPackage || '';\n    const isShellOnly = interiorPackageValue && \n      String(interiorPackageValue).toLowerCase().replace(/[\\s_-]/g, '').includes('shellonly');\n\n    // Build features from actual config values (exclude interior features if Shell Only)\n    const configFeatures = [\n      !isShellOnly ? this.currentConfig.layout : null,\n      this.currentConfig.exterior || this.currentConfig.windowConfig,\n      this.currentConfig.roof || this.currentConfig.roofType\n    ].filter(Boolean).map(formatOptionValue);\n\n    // Build label with optional sqFt\n    const labelParts = [variantTitle];\n    if (sqFt) labelParts.push(`(${sqFt} sq. ft.)`);\n    const mainLabel = labelParts.filter(Boolean).join(' ');\n\n    let html = '';\n\n    // Only show main section if we have a label\n    if (mainLabel) {\n      html += `\n        <div class=\"price-detail-item price-detail-main\">\n          <div class=\"price-detail-info\">\n            <span class=\"d-inline-block mb-2\">${mainLabel}</span>\n            ${configFeatures.map(f => `<span class=\"price-detail-feature fs-sm text-gray-600 mb-1 d-block\" style=\"letter-spacing: -0.01em;\">${f}</span>`).join('')}\n          </div>\n          <span>${formatPrice(this.getEffectiveBasePrice())}</span>\n        </div>\n      `;\n    }\n\n    // Get option display name from steps\n    const getOptionDisplayName = (sectionKey, value) => {\n      const option = this.findOptionInSteps(sectionKey, value);\n      return option?.displayName || formatOptionValue(value);\n    };\n\n    // Add price details for selected options that have prices\n    // Filter out interior-related options if Shell Only is selected\n    const allDetailKeys = [\n      { key: 'interiorOptions', alt: 'interiorPackage', label: 'Interior Package', isInterior: true },\n      { key: 'sideOptions', label: 'Side Options', isInterior: true },\n      { key: 'layout', label: 'Interior Layout', isInterior: true },\n      { key: 'kitchen', alt: 'kitchenConfig', label: 'Kitchen', isInterior: true },\n      { key: 'orientation', label: 'Orientation', isInterior: false },\n      { key: 'exterior', alt: 'windowConfig', label: 'Exterior', isInterior: false },\n      { key: 'roof', alt: 'roofType', label: 'Roof', isInterior: false },\n      { key: 'roofAddon', label: 'Roof Addon', isInterior: false },\n      { key: 'siding', alt: 'sidingType', label: 'Siding', isInterior: false },\n      { key: 'mainFloorFinish', nested: ['flooring', 'main'], label: 'Main Floor', isInterior: true },\n      { key: 'bathFloorFinish', nested: ['flooring', 'bath'], label: 'Bath Floor', isInterior: true },\n      { key: 'fixtureFinish', nested: ['finishes', 'fixture'], label: 'Fixtures', isInterior: true },\n      { key: 'counterFinish', nested: ['finishes', 'countertop'], label: 'Counter', isInterior: true },\n      { key: 'cabinetFinish', nested: ['finishes', 'cabinets'], label: 'Cabinets', isInterior: true },\n      { key: 'sidingColor', label: 'Siding Color', isInterior: false },\n      { key: 'trimColor', label: 'Trim', isInterior: false },\n      { key: 'doorColor', label: 'Door', isInterior: false },\n      { key: 'fasciaColor', label: 'Fascia', isInterior: false },\n      { key: 'soffitColor', label: 'Soffit', isInterior: false },\n      { key: 'eavesColor', label: 'Eaves', isInterior: false },\n      { key: 'exteriorAddon', label: 'Exterior Addon', isInterior: false }\n    ];\n\n    // Filter out interior options if Shell Only\n    const detailKeys = isShellOnly \n      ? allDetailKeys.filter(item => !item.isInterior)\n      : allDetailKeys;\n\n    detailKeys.forEach(({ key, alt, nested, label }) => {\n      const value = this.currentConfig[key] || (alt && this.currentConfig[alt]) || (nested && this.currentConfig[nested[0]]?.[nested[1]]);\n      if (!value) return;\n\n      // Try multiple section keys to find the option\n      let option = null;\n      if (nested) {\n        option = this.findNestedOptionInSteps(nested[0], nested[1], value);\n      } else {\n        option = this.findOptionInSteps(key, value);\n        if (!option && alt) {\n          option = this.findOptionInSteps(alt, value);\n        }\n        if (!option && /siding/i.test(key)) {\n          const sidingKeys = ['sidingType', 'siding', 'sidingOptions', 'sidingStyle'];\n          for (const skey of sidingKeys) {\n            option = this.findOptionInSteps(skey, value);\n            if (option) break;\n          }\n        }\n      }\n      \n      const displayName = option?.displayName || formatOptionValue(value);\n      const price = option?.price || 0;\n\n      html += `\n        <div class=\"price-detail-item\">\n          <span class=\"price-detail-label\">${label}: ${displayName}</span>\n          <span class=\"price-detail-price\">${formatPrice(price)}</span>\n        </div>\n      `;\n    });\n\n    return html;\n  }\n\n  buildDesignDetailsHTML(variantTitle) {\n    const config = this.currentConfig || {};\n    const variant = this.selectedVariant || {};\n    const modelData = this.modelsData || {};\n\n    // Helper to get option data (including hex, displayName, texture) from steps\n    const getOptionData = (sectionKey, value) => {\n      if (!value) return null;\n      for (const step of this.steps) {\n        // Check panel-based sections (like Signature model)\n        if (step.sections) {\n          const section = step.sections.find(s => s.id === sectionKey);\n          if (section) {\n            const option = section.options?.find(o => o.value === value);\n            if (option) return option;\n          }\n        }\n        // Check direct options\n        const option = step.options?.[sectionKey]?.options?.find(o => o.value === value);\n        if (option) return option;\n        // Check nested options (e.g., sidingColor.main)\n        if (sectionKey.includes('.')) {\n          const [parent, child] = sectionKey.split('.');\n          const nested = step.options?.[parent]?.[child]?.options?.find(o => o.value === value);\n          if (nested) return nested;\n        }\n      }\n      return null;\n    };\n\n    // Helper to get config value (handles nested like flooring.main)\n    const getConfigValue = (key, nestedKey) => {\n      if (nestedKey) {\n        return config[key]?.[nestedKey] || config[`${key}${nestedKey.charAt(0).toUpperCase()}${nestedKey.slice(1)}`];\n      }\n      return config[key];\n    };\n\n    // Helper to render material item with texture image preview (for flooring and siding)\n    const renderTextureItem = (label, value, sectionKey) => {\n      if (!value) return '';\n      const option = getOptionData(sectionKey, value);\n      const displayName = option?.displayName || formatOptionValue(value);\n      \n      // Check if this is a siding, floor, or counter section\n      const isSidingSection = /siding/i.test(sectionKey) && !sectionKey.toLowerCase().includes('color');\n      const isFloorSection = /floor|flooring/i.test(sectionKey);\n      const isCounterSection = /counter/i.test(sectionKey);\n      const isFinishOption = /fixture|cabinet|finishes/i.test(sectionKey) && !isCounterSection;\n      \n      // Step 1: Check option properties\n      let textureImage = option?.texture || option?.thumbnail || option?.swatch;\n      \n      // Step 2: Resolve texture reference if it's a key\n      if (textureImage && this.resolveTextureReference) {\n        textureImage = this.resolveTextureReference(textureImage);\n      }\n      \n      // Step 3: For siding options, try to find texture in texturesData\n      if (isSidingSection && !textureImage && this.texturesData) {\n        textureImage = this.texturesData[value] \n          || this.texturesData[`siding-${value}`]\n          || this.texturesData[`${value}-siding`];\n      }\n      \n      // Step 4: For counter options, try to find texture in texturesData\n      if (isCounterSection && !textureImage && this.texturesData) {\n        textureImage = this.texturesData[value] \n          || this.texturesData[`counter-${value}`]\n          || this.texturesData[`countertop-${value}`]\n          || this.texturesData[`${value}-counter`];\n      }\n      \n      // Step 5: Fallback to image/iconImage for non-finish options\n      if (!textureImage && !isFinishOption) {\n        const imageUrl = option?.iconImage || option?.image;\n        if (imageUrl) {\n          textureImage = imageUrl;\n          if (textureImage && this.resolveTextureReference) {\n            textureImage = this.resolveTextureReference(textureImage);\n          }\n        }\n      }\n      \n      // Step 6: Additional fallback for flooring\n      if (isFloorSection && !textureImage && this.texturesData) {\n        textureImage = this.texturesData[value]\n          || this.texturesData[`floor-${value}`]\n          || this.texturesData[`flooring-${value}`];\n      }\n      \n      if (textureImage) {\n        return `\n          <div class=\"material-item d-flex align-items-center gap-2 mb-3\">\n            <div class=\"material-swatch material-swatch--texture overflow-hidden\">\n              <img src=\"${textureImage}\" alt=\"${displayName}\" loading=\"lazy\" style=\"width: 100%; height: 100%; object-fit: cover;\">\n            </div>\n            <div class=\"material-info\">\n              <span class=\"d-block mb-1 fs-sm\" style=\"letter-spacing: -0.01em;\">${label}</span>\n              <span class=\"d-block\">${displayName}</span>\n            </div>\n          </div>\n        `;\n      } else {\n        const hex = option?.hex || option?.color?.hex || '#888888';\n        return `\n          <div class=\"material-item d-flex align-items-center gap-2 mb-3\">\n            <div class=\"material-swatch overflow-hidden\" style=\"background: ${hex};\"></div>\n            <div class=\"material-info\">\n              <span class=\"d-block mb-1 fs-sm\" style=\"letter-spacing: -0.01em;\">${label}</span>\n              <span class=\"d-block\">${displayName}</span>\n            </div>\n          </div>\n        `;\n      }\n    };\n\n    // Helper to render material item only if value exists (with solid color)\n    const renderMaterialItem = (label, value, sectionKey) => {\n      if (!value) return '';\n      const option = getOptionData(sectionKey, value);\n      const hex = option?.hex || option?.color || '#888888';\n      return `\n        <div class=\"material-item d-flex align-items-center gap-2 mb-3\">\n          <div class=\"material-swatch overflow-hidden\" style=\"background: ${hex};\"></div>\n          <div class=\"material-info\">\n            <span class=\"d-block mb-1 fs-sm\">${label}</span>\n            <span class=\"d-block\">${option?.displayName || formatOptionValue(value)}</span>\n          </div>\n        </div>\n      `;\n    };\n\n    // Helper to render color item only if value exists\n    const renderColorItem = (label, sectionKey, value) => {\n      if (!value) return '';\n      const option = getOptionData(sectionKey, value);\n      const hex = option?.hex || '#888888';\n      return `\n        <div class=\"color-item d-flex align-items-center gap-2\">\n          <div class=\"color-swatch overflow-hidden\" style=\"background: ${hex};\"></div>\n          <div class=\"color-info\">\n            <span class=\"d-block mb-1 fs-sm\">${label}</span>\n            <span class=\"d-block\">${option?.displayName || formatOptionValue(value)}</span>\n          </div>\n        </div>\n      `;\n    };\n\n    // Helper to render detail row only if value exists\n    const renderDetailRow = (label, value) => {\n      if (!value) return '';\n      return `\n        <div class=\"design-detail-col\">\n          <h6 class=\"mb-3\">${label}</h6>\n          <p>${formatOptionValue(value)}</p>\n        </div>\n      `;\n    };\n\n    // Build model specs line\n    const specParts = [];\n    if (modelData.depth) specParts.push(`Depth: ${modelData.depth}`);\n    if (modelData.length) specParts.push(`Length: ${modelData.length}`);\n    if (modelData.squareFootage) specParts.push(`${modelData.squareFootage} sq. ft.`);\n    const specsLine = specParts.length ? `<p>${specParts.join(' | ')}</p>` : '';\n\n    // Build model features line\n    const featureParts = [];\n    if (config.windowOption || config.exterior) featureParts.push(formatOptionValue(config.windowOption || config.exterior));\n    if (config.roofType || config.roof) featureParts.push(`${formatOptionValue(config.roofType || config.roof)} Roof`);\n    const featuresLine = featureParts.length ? `<p>${featureParts.join(' | ')}</p>` : '';\n\n    // Build interior line\n    const interiorParts = [];\n    if (config.layout) interiorParts.push(formatOptionValue(config.layout));\n    if (config.kitchenConfig || config.kitchen) interiorParts.push(formatOptionValue(config.kitchenConfig || config.kitchen));\n    const interiorLine = interiorParts.length ? `<p>${interiorParts.join(' | ')}</p>` : '';\n\n    // Check if interior package is \"Shell Only\" - normalize the value for comparison\n    const interiorPackageValue = config.interiorOptions || config.interiorPackage || '';\n    const isShellOnly = interiorPackageValue && \n      String(interiorPackageValue).toLowerCase().replace(/[\\s_-]/g, '').includes('shellonly');\n\n    // Get material values\n    const mainFloor = getConfigValue('mainFloorFinish') || getConfigValue('flooring', 'main');\n    const bathFloor = getConfigValue('bathFloorFinish') || getConfigValue('flooring', 'bath');\n    const fixture = getConfigValue('fixtureFinish') || getConfigValue('finishes', 'fixture');\n    const counter = getConfigValue('counterFinish') || getConfigValue('finishes', 'countertop');\n    const cabinet = getConfigValue('cabinetFinish') || getConfigValue('finishes', 'cabinets');\n    const siding = getConfigValue('sidingType') || getConfigValue('siding');\n    const trim = getConfigValue('trimColor');\n\n    // Get color values\n    const sidingColorValue = typeof config.sidingColor === 'string' ? config.sidingColor : config.sidingColor?.main;\n    const accentColorValue = typeof config.sidingColor === 'object' ? config.sidingColor?.accent : config.accentColor;\n\n    // Build flooring section - only if NOT Shell Only\n    let flooringItems = '';\n    if (!isShellOnly) {\n      const flooringItemsArray = [\n        renderTextureItem('Main Flooring', mainFloor, 'mainFloorFinish'),\n        renderTextureItem('Bath Flooring', bathFloor, 'bathFloorFinish')\n      ].filter(Boolean);\n      flooringItems = flooringItemsArray.join('');\n    }\n\n    // Build finishes section - only if NOT Shell Only\n    let finishItems = '';\n    if (!isShellOnly) {\n      const finishItemsArray = [\n        renderMaterialItem('Fixtures', fixture, 'fixtureFinish'),\n        renderTextureItem('Countertop', counter, 'counterFinish'),\n        renderMaterialItem('Cabinets', cabinet, 'cabinetFinish')\n      ].filter(Boolean);\n      finishItems = finishItemsArray.join('');\n    }\n\n    // Build colors section\n    const colorItems = [\n      renderColorItem('Siding Color', 'sidingColor', sidingColorValue),\n      renderColorItem('Door', 'doorColor', config.doorColor),\n      renderColorItem('Trim', 'trimColor', config.trimColor),\n      renderColorItem('Accent', 'sidingColor.accent', accentColorValue),\n      renderColorItem('Fascia', 'fasciaColor', config.fasciaColor),\n      renderColorItem('Soffit', 'soffitColor', config.soffitColor),\n      renderColorItem('Eaves', 'eavesColor', config.eavesColor)\n    ].filter(Boolean).join('');\n\n    // Find wainscot value - check exteriorAddon or keys containing \"wainscot\"\n    let wainscotValue = null;\n    \n    if (config.exteriorAddon) {\n      const addonValue = String(config.exteriorAddon).toLowerCase();\n      if (addonValue.includes('wainscot')) {\n        wainscotValue = config.exteriorAddon;\n      }\n    }\n    \n    if (!wainscotValue) {\n      for (const key of Object.keys(config)) {\n        if (key.toLowerCase().includes('wainscot')) {\n          wainscotValue = config[key];\n          break;\n        }\n      }\n    }\n\n    // Build detail options rows\n    const detailRows = [\n      { label: 'INTERIOR PACKAGE', value: config.interiorOptions },\n      { label: 'SIDE OPTIONS', value: config.sideOptions },\n      { label: 'INTERIOR LAYOUT', value: config.layout },\n      { label: 'EXTERIOR WINDOW OPTION', value: config.windowOption || config.exterior },\n      { label: 'KITCHEN LAYOUT', value: config.kitchenConfig || config.kitchen },\n      { label: 'ROOF OPTION', value: config.roofType || config.roof },\n      { label: 'ROOF ADDON', value: config.roofAddon },\n      { label: 'WAINSCOT', value: wainscotValue },\n      { label: 'EXTERIOR ADDON', value: config.exteriorAddon && !String(config.exteriorAddon).toLowerCase().includes('wainscot') ? config.exteriorAddon : null },\n      { label: 'ORIENTATION', value: config.orientation }\n    ].filter(r => r.value);\n\n    // Get includes/excludes from modelConfig or use defaults\n    const includes = this.modelConfig?.includes || [\n      'Exterior Shell with Lap Siding',\n      'Interior Framing',\n      'Interior Insulation and flooring',\n      'Electrical, lighting, appliance package',\n      'Complete kitchen and/or bathroom package',\n      'Door and window hardware'\n    ];\n    const excludes = this.modelConfig?.excludes || [\n      'Foundation and site utilities',\n      'Drywall (included with ProAssembly service)',\n      'Permit fees',\n      'Sales tax as applicable'\n    ];\n\n    let html = `<div class=\"summary-design-details\"><h5 class=\"mb-md-5 mb-3\">Design Details</h5>`;\n\n    // MODEL & INTERIOR section\n    html += `\n      <div class=\"design-details-grid\">\n        <div class=\"design-detail-col\">\n          <h6 class=\"mb-md-3 mb-2\">MODEL</h6>\n          ${variantTitle ? `<p class=\"mb-2\">${variantTitle}</p>` : ''}\n          ${featuresLine}\n          ${specsLine}\n        </div>\n        ${(interiorLine || variant.bedBath) ? `\n        <div class=\"design-detail-col\">\n          <h6 class=\"mb-md-3 mb-2\">INTERIOR</h6>\n          ${interiorLine}\n          ${variant.bedBath ? `<p class=\"mb-2\">${variant.bedBath}</p>` : ''}\n        </div>\n        ` : ''}\n      </div>\n    `;\n\n    // Detail options rows (in pairs)\n    if (detailRows.length > 0) {\n      for (let i = 0; i < detailRows.length; i += 2) {\n        html += `<div class=\"design-details-grid design-details-options\">`;\n        html += renderDetailRow(detailRows[i].label, detailRows[i].value);\n        if (detailRows[i + 1]) {\n          html += renderDetailRow(detailRows[i + 1].label, detailRows[i + 1].value);\n        }\n        html += `</div>`;\n      }\n    }\n\n    html += `</div>`;\n\n    // Flooring & Finishes section\n    if (flooringItems || finishItems) {\n      html += `<div class=\"summary-section-divider\"></div><div class=\"summary-materials-section\"><div class=\"design-details-grid\">`;\n      if (flooringItems) {\n        html += `<div class=\"design-detail-col\"><h6 class=\"mb-3\">FLOORING</h6>${flooringItems}</div>`;\n      }\n      if (finishItems) {\n        html += `<div class=\"design-detail-col\"><h6 class=\"mb-3\">FINISHES</h6>${finishItems}</div>`;\n      }\n      html += `</div></div>`;\n    }\n\n    // Build siding section with texture preview\n    let sidingItem = '';\n    if (siding) {\n      const sidingSectionKeys = ['sidingType', 'siding', 'sidingOptions', 'sidingStyle'];\n      for (const key of sidingSectionKeys) {\n        const result = renderTextureItem('Siding', siding, key);\n        if (result && result.includes('<img')) {\n          sidingItem = result;\n          break;\n        } else if (result && !sidingItem) {\n          sidingItem = result;\n        }\n      }\n      if (!sidingItem) {\n        sidingItem = renderTextureItem('Siding', siding, 'siding');\n      }\n    }\n\n    // Exterior section - Siding with texture preview\n    if (sidingItem || trim) {\n      html += `<div class=\"summary-section-divider\"></div><div class=\"summary-materials-section\"><div class=\"design-details-grid\">`;\n      if (sidingItem) {\n        html += `<div class=\"design-detail-col\"><h6 class=\"mb-3\">SIDING</h6>${sidingItem}</div>`;\n      }\n      if (trim) {\n        html += `<div class=\"design-detail-col\"><h6 class=\"mb-3\">TRIM</h6>${renderMaterialItem('Trim', trim, 'trimColor')}</div>`;\n      }\n      html += `</div></div>`;\n    }\n\n    // Colors section\n    if (colorItems) {\n      html += `\n        <div class=\"summary-section-divider\"></div>\n        <div class=\"summary-colors-section\">\n          <h6 class=\"mb-3\">COLORS</h6>\n          <div class=\"colors-grid\">${colorItems}</div>\n        </div>\n      `;\n    }\n\n    // Elevations section - show images based on selected options\n    // For summit models with combination-based elevations (e.g., \"front-entry|more-glass\")\n    const elevationKey = this.getElevationKey();\n    const elevationImages = this.modelConfig?.images?.elevations?.[elevationKey];\n    \n    log800('[Summit800] Elevation lookup:', { elevationKey, hasImages: !!elevationImages });\n\n    if (elevationImages) {\n      html += `\n        <div class=\"summary-elevations-section d-flex flex-column gap-4\">\n          ${elevationImages.front ? `\n          <div class=\"elevation-view\">\n            <h6 class=\"mb-3\">FRONT</h6>\n            <div class=\"elevation-image\"><img src=\"${elevationImages.front}\" alt=\"Front elevation\" loading=\"lazy\"></div>\n          </div>\n          ` : ''}\n          ${elevationImages.back ? `\n          <div class=\"elevation-view\">\n            <h6 class=\"mb-3\">BACK</h6>\n            <div class=\"elevation-image\"><img src=\"${elevationImages.back}\" alt=\"Back elevation\" loading=\"lazy\"></div>\n          </div>\n          ` : ''}\n          ${elevationImages.left ? `\n          <div class=\"elevation-view\">\n            <h6 class=\"mb-3\">LEFT</h6>\n            <div class=\"elevation-image\"><img src=\"${elevationImages.left}\" alt=\"Left elevation\" loading=\"lazy\"></div>\n          </div>\n          ` : ''}\n          ${elevationImages.right ? `\n          <div class=\"elevation-view\">\n            <h6 class=\"mb-3\">RIGHT</h6>\n            <div class=\"elevation-image\"><img src=\"${elevationImages.right}\" alt=\"Right elevation\" loading=\"lazy\"></div>\n          </div>\n          ` : ''}\n        </div>\n      `;\n    }\n\n    // Dimensions section - show specs image (static, same for all options)\n    const specsImage = this.modelConfig?.images?.specs;\n    if (specsImage) {\n      html += `\n        <div class=\"summary-dimensions-section d-flex flex-column gap-4\">\n          <div class=\"dimension-view\">\n            <h6 class=\"mb-3\">DIMENSIONS</h6>\n            <div class=\"dimension-image\"><img src=\"${specsImage}\" alt=\"Dimensions\" loading=\"lazy\"></div>\n          </div>\n        </div>\n      `;\n    }\n\n    // Additional options (only if exists)\n    if (config.exteriorOptions || config.interiorOptions) {\n      html += `\n        <div class=\"summary-section-divider\"></div>\n        <div class=\"summary-additional-options\">\n          <h6 class=\"mb-4\">ADDITIONAL OPTIONS</h6>\n          ${config.exteriorOptions ? `<p class=\"mb-3\">Exterior: ${config.exteriorOptions}</p>` : ''}\n          ${config.interiorOptions ? `<p class=\"mb-0\">Interior: ${config.interiorOptions}</p>` : ''}\n        </div>\n      `;\n    }\n\n    // Includes/Excludes section (only if data exists)\n    if (includes.length || excludes.length) {\n      html += `\n        <div class=\"summary-section-divider\"></div>\n        <div class=\"summary-includes-excludes\">\n          <div class=\"includes-excludes-grid\">\n            ${includes.length ? `\n            <div class=\"includes-col mb-sm-0 mb-5\">\n              <h6 class=\"mb-3\">INCLUDES</h6>\n              <ul class=\"ps-xl-5 mb-0\">${includes.map(item => `<li>${item}</li>`).join('')}</ul>\n            </div>\n            ` : ''}\n            ${excludes.length ? `\n            <div class=\"excludes-col\">\n              <h6 class=\"mb-3\">EXCLUDES</h6>\n              <ul class=\"ps-xl-5 mb-0\">${excludes.map(item => `<li>${item}</li>`).join('')}</ul>\n            </div>\n            ` : ''}\n          </div>\n        </div>\n      `;\n    }\n\n    return html;\n  }\n\n  findOptionInSteps(sectionKey, value) {\n    for (const step of this.steps) {\n      const option = step.options?.[sectionKey]?.options?.find(opt => opt.value === value);\n      if (option) return option;\n    }\n    return null;\n  }\n\n  findNestedOptionInSteps(parentKey, childKey, value) {\n    for (const step of this.steps) {\n      const option = step.options?.[parentKey]?.[childKey]?.options?.find(opt => opt.value === value);\n      if (option) return option;\n    }\n    return null;\n  }\n\n  setupThankYouEventListeners(panel) {\n    const editLink = $('[data-edit-design]', panel);\n    if (editLink) {\n      editLink.addEventListener('click', (e) => {\n        e.preventDefault();\n        // Restore default col-8/col-4 layout before switching tab\n        this.restoreDefaultLayout();\n        this.switchTab('floorplan');\n        const footer = q('[data-panel-footer]', '.panel-footer', this.step2Section);\n        if (footer) footer.style.display = '';\n      });\n    }\n\n    const priceToggle = $('[data-toggle-price-details]', panel);\n    const priceContent = $('[data-price-details-content]', panel);\n    if (priceToggle && priceContent) {\n      // Setup smooth dropdown animation styles (Summit-800-specific)\n      priceContent.style.overflow = 'hidden';\n      priceContent.style.transition = 'max-height 0.35s ease-in-out, opacity 0.3s ease-in-out';\n      priceContent.style.maxHeight = '0';\n      priceContent.style.opacity = '0';\n      priceContent.style.display = 'block'; // Always block, control visibility via max-height\n      \n      priceToggle.addEventListener('click', () => {\n        const isCollapsed = priceContent.style.maxHeight === '0px' || priceContent.style.maxHeight === '0';\n        \n        if (isCollapsed) {\n          // Expand: measure content height and animate to it\n          priceContent.style.maxHeight = priceContent.scrollHeight + 'px';\n          priceContent.style.opacity = '1';\n        } else {\n          // Collapse: animate to 0\n          priceContent.style.maxHeight = '0';\n          priceContent.style.opacity = '0';\n        }\n        \n        const icon = priceToggle.querySelector('[data-toggle-icon], .toggle-icon');\n        if (icon) {\n          // Handle SVG icon (Summit-800 uses SVG with use element)\n          const svg = icon.querySelector('svg');\n          if (svg) {\n            icon.innerHTML = isCollapsed ? `<svg aria-hidden=\"true\" focusable=\"false\" style=\"width:15px; height:15px;\">\n                  <use href=\"#icon-modal-minus\"></use>\n                </svg>` : `<svg aria-hidden=\"true\" focusable=\"false\" style=\"width:15px; height:15px;\">\n                  <use href=\"#icon-modal-plus\"></use>\n                </svg>`;\n          } else {\n            icon.textContent = isCollapsed ? '\u2212' : '+';\n          }\n        }\n      });\n    }\n\n    const changePermit = $('[data-change-permit-plans]', panel);\n    if (changePermit) changePermit.addEventListener('click', (e) => { e.preventDefault(); this.openPermitPlansDrawer(); });\n\n    const changeFoundation = $('[data-change-foundation-type]', panel);\n    if (changeFoundation) changeFoundation.addEventListener('click', (e) => { e.preventDefault(); this.openFoundationTypeDrawer(); });\n  }\n\n  // ============================================================================\n  // FAQ SECTION (Data-Driven)\n  // ============================================================================\n\n  appendFullWidthFAQ() {\n    const existingFAQ = q('[data-faq-container]', '.full-width-faq-container');\n    if (existingFAQ) existingFAQ.remove();\n\n    let faqConfig = null;\n    try {\n      const faqConfigEl = $('[data-faq-config]', this.step2Section);\n      if (faqConfigEl) faqConfig = JSON.parse(faqConfigEl.textContent);\n    } catch (e) { /* use defaults */ }\n\n    const faqTitle = faqConfig?.title || this.modelConfig?.faq?.title || 'Frequently Asked Questions';\n    const faqItems = faqConfig?.items || this.modelConfig?.faq?.items || [];\n\n    // Don't show FAQ section if no items configured\n    if (!faqItems.length) {\n      log('No FAQ items configured');\n      return;\n    }\n\n    const faqContainer = document.createElement('div');\n    faqContainer.className = 'full-width-faq-container';\n    faqContainer.setAttribute('data-faq-container', '');\n    faqContainer.innerHTML = `\n      <div class=\"summary-section-divider summary-section-divider--full\" data-section-divider></div>\n      <div class=\"summary-faq-section\" data-faq-section>\n        <h3 class=\"faq-title\" data-faq-title>${faqTitle}</h3>\n        ${faqItems.map(item => `\n          <div class=\"faq-item\" data-faq-item>\n            <button class=\"faq-question\" data-faq-toggle>\n              <span data-faq-question-text>${item.question}</span>\n              <span class=\"faq-icon\" data-faq-icon>+</span>\n            </button>\n            <div class=\"faq-answer\" data-faq-answer style=\"display: none;\">${item.answer}</div>\n          </div>\n        `).join('')}\n      </div>\n    `;\n\n    const configuratorLayout = q('[data-configurator-layout]', '.configurator-layout', this.step2Section);\n    if (configuratorLayout) {\n      configuratorLayout.parentNode.insertBefore(faqContainer, configuratorLayout.nextSibling);\n    } else {\n      this.step2Section.appendChild(faqContainer);\n    }\n\n    // Setup FAQ toggles\n    faqContainer.querySelectorAll('[data-faq-toggle]').forEach(toggle => {\n      toggle.addEventListener('click', () => {\n        const content = toggle.nextElementSibling;\n        const icon = toggle.querySelector('[data-faq-icon], .faq-icon');\n        const isOpen = content.style.display !== 'none';\n        content.style.display = isOpen ? 'none' : 'block';\n        if (icon) icon.textContent = isOpen ? '+' : '\u2212';\n        toggle.classList.toggle('open', !isOpen);\n      });\n    });\n  }\n\n  // ============================================================================\n  // PERMIT PLANS DRAWER - Using shared PermitManager\n  // ============================================================================\n\n  setupPermitPlansDrawer() {\n    const defaultPermit = 'include';\n    \n    if (this.permitManager) {\n      // Reuse existing to prevent overwriting user selection\n      this.permitManager.defaultSelected = defaultPermit;\n      this.permitManager.basePrice = this.modelConfig?.permitPlanPrice || 6995;\n      this.permitManager.reset();\n      return;\n    }\n\n    this.permitManager = new window.ConfiguratorShared.PermitManager({\n      configurator: this,\n      drawerId: 'permit-plans-drawer',\n      basePrice: this.modelConfig?.permitPlanPrice || 6995,\n      defaultSelected: defaultPermit,\n      formatPrice: formatPrice,\n      onSelect: () => this.recalculateSummaryTotal(),\n      step2Section: this.step2Section\n    });\n    this.permitManager.setup();\n  }\n\n  openPermitPlansDrawer() {\n    this.permitManager?.open();\n  }\n\n  updateSummaryPermitDisplay() {\n    this.permitManager?.updateSummaryDisplay();\n  }\n\n  // ============================================================================\n  // FOUNDATION TYPE DRAWER\n  // ============================================================================\n\n  setupFoundationTypeDrawer() {\n    this.foundationManager = new window.ConfiguratorShared.FoundationManager({\n      configurator: this,\n      drawerId: 'foundation-type-drawer',\n      step2Section: this.step2Section\n    });\n    this.foundationManager.setup();\n  }\n\n  openFoundationTypeDrawer() {\n    this.foundationManager?.open();\n  }\n\n  updateFoundationDrawerSelection() {\n    this.foundationManager?.updateSelection();\n  }\n\n  handleFoundationOptionSelect(card) {\n    this.foundationManager?.handleSelect(card);\n  }\n\n  updateSummaryFoundationDisplay() {\n    this.foundationManager?.updateSummaryDisplay();\n  }\n\n  recalculateSummaryTotal() {\n    // Use effective base price which handles combination/matrix pricing\n    const productPrice = this.getEffectiveBasePrice() + this.configPrice;\n    const shippingPrice = normalizeNumber(this.finalPriceData?.shipping_cost, this.modelConfig?.shippingPrice || 0);\n    const installationOptions = this.modelConfig?.services?.installation?.options || [];\n    const selectedInstallation = installationOptions.find(opt => opt.value === this.currentConfig.installation);\n    \n    // Get installation price from API breakdown\n    // Use computeInstallationCost for consistency with updateTotalPrice\n    let installationPrice = 0;\n    const installationValue = this.currentConfig.installation || ''; \n    \n    if (this.finalPriceData?.breakdown?.installation) {\n      // const breakdown = this.finalPriceData.breakdown.installation;\n      \n      // // If user selected \"shell-lifestyle\", use lifestyle price from API breakdown\n      // if (installationValue.toLowerCase().includes('lifestyle')) {\n      //   installationPrice = normalizeNumber(breakdown.lifestyle, 0);\n      // } else {\n      //   // For other options, use the computed installation cost\n        const computedCents = window.ConfiguratorShared.computeInstallationCost(\n          this.finalPriceData.breakdown.installation,\n          installationValue\n        );\n        installationPrice = computedCents > 0 ? computedCents : normalizeNumber(selectedInstallation?.price, 0);\n      //}\n    } else {\n      // Fallback if no API data available\n      installationPrice = normalizeNumber(selectedInstallation?.price, 0);\n    }\n    const estimatedTotal = productPrice + shippingPrice + this.permitPlanPrice + installationPrice;\n\n    const contentWrapper = $('[data-panel-content-wrapper]', this.step2Section);\n    if (!contentWrapper) return;\n\n    const totalDisplay = $('[data-summary-total-price]', contentWrapper);\n    if (totalDisplay) totalDisplay.textContent = formatPrice(estimatedTotal);\n\n    const totalNote = q('[data-total-note]', '.total-note', contentWrapper);\n    if (totalNote) {\n      totalNote.innerHTML = this.getTotalNoteText();\n    }\n\n    // Update ALL price elements (header and mobile footer)\n    const headerPrices = $$('[data-configurator-price]', this.step2Section);\n    headerPrices.forEach(el => el.textContent = formatPrice(estimatedTotal));\n  }\n\n  // ============================================================================\n  // UTILITIES\n  // ============================================================================\n\n  /**\n   * Generate the total note text based on installation selection\n   * Installation options:\n   * - \"shell\" or \"product-only\" = Product Only (no assembly)\n   * - \"lifestyle\" = ProAssembly: Shell Only (has assembly)\n   * - \"kitchenbath\" = ProAssembly: Shell + Lifestyle Interior (has assembly)\n   * @returns {string} HTML string for the total note\n   */\n  getTotalNoteText() {\n    const installation = (this.currentConfig?.installation || '').toLowerCase();\n    // \"shell\" and \"product-only\" mean no assembly, anything else means assembly is included\n    const noAssemblyValues = ['shell', 'product-only', 'product_only', 'productonly', ''];\n    const hasAssembly = !noAssemblyValues.includes(installation);\n    const hasPermitPlans = this.permitPlanSelected === 'include';\n    \n    let includes = ['product', 'delivery'];\n    if (hasAssembly) includes.push('assembly');\n    if (hasPermitPlans) includes.push('permit plans');\n    \n    // Format the includes list with proper grammar\n    let includesText;\n    if (includes.length === 2) {\n      includesText = includes.join(' and ');\n    } else {\n      const last = includes.pop();\n      includesText = includes.join(', ') + ', and ' + last;\n    }\n    \n    return `Includes ${includesText}.<br>Excludes foundation, site utilities, HVAC, decks, upgrades, permitting, local taxes.`;\n  }\n\n  updateURL(variantId) {\n    const url = new URL(window.location.href);\n    url.searchParams.set('variant', variantId);\n    window.history.replaceState({}, '', url);\n  }\n\n  dispatchVariantChange(variantId, price) {\n    document.dispatchEvent(new CustomEvent('variant:changed', { detail: { variantId, price } }));\n  }\n\n  getSelectedVariantId() {\n    const selectedCard = this.step1Section.querySelector('[data-variant-card].selected, .summit-variant-card.selected');\n    return selectedCard?.dataset.variantId || null;\n  }\n\n  getConfiguration() {\n    return {\n      ...this.currentConfig,\n      basePrice: this.basePrice,\n      configPrice: this.configPrice,\n      totalPrice: this.getEffectiveBasePrice() + this.configPrice,\n      permitPlan: this.permitPlanSelected,\n      permitPlanPrice: this.permitPlanPrice\n    };\n  }\n\n  /**\n   * Clean up resources and event listeners\n   */\n  dispose() {\n    // Remove event listeners\n    if (this.step2ClickHandler && this.step2Section) {\n      this.step2Section.removeEventListener('click', this.step2ClickHandler);\n    }\n\n    // Dispose 3D viewer\n    if (this.viewer3D) {\n      this.viewer3D.dispose();\n      this.viewer3D = null;\n    }\n\n    // Clear references\n    this.variantCards = [];\n    this.thumbnails = [];\n    this.steps = [];\n    this.currentConfig = {};\n    this.modelConfig = null;\n    this.modelsData = null;\n    this.userFormData = null;\n\n    log('ProductConfigurator disposed');\n  }\n\n  /**\n   * Reset configurator to initial state\n   */\n  reset() {\n    this.currentConfig = { ...this.defaultConfig };\n    this.configPrice = 0;\n    this.currentStep = 1;\n    this.permitManager?.reset();\n    this.foundationManager?.reset();\n    this.userFormData = null;\n\n    // Use visible steps to start on correct first step\n    const visibleSteps = this.getVisibleSteps();\n    if (visibleSteps.length > 0) {\n      this.switchTab(visibleSteps[0].name);\n    }\n  }\n\n  /**\n   * Restore default 8-4 column layout (from 6-6 thank you page layout)\n   */\n  restoreDefaultLayout() {\n    const viewer = $('.configurator-viewer', this.step2Section);\n    const panel = $('.configurator-panel', this.step2Section);\n    if (viewer) {\n      viewer.classList.remove('col-lg-6');\n      viewer.classList.add('col-lg-8');\n      const modelContainer = $('[data-model-viewer], .model-viewer-container', viewer);\n      if (modelContainer) {\n        modelContainer.style.removeProperty('max-width');\n        modelContainer.style.removeProperty('margin');\n      }\n    }\n    if (panel) {\n      panel.classList.remove('col-lg-6');\n      panel.classList.add('col-lg-4');\n    }\n\n    // Trigger 3D viewer resize after layout change\n    setTimeout(() => {\n      if (this.viewer3D?.sceneManager?.onResize) {\n        this.viewer3D.sceneManager.onResize();\n      }\n    }, 50);\n  }\n\n  /**\n   * Handle Start Over button click - reset and go to first step\n   */\n  handleStartOver() {\n    this.restoreDefaultLayout();\n    this.reset();\n\n    // Disable Summary tab immediately since form data is cleared\n    this.updateSummaryTabState();\n\n    // Reset the button text\n    const saveDesignBtn = $('[data-save-design]', this.step2Section);\n    if (saveDesignBtn) {\n      saveDesignBtn.textContent = 'SAVE DESIGN';\n      delete saveDesignBtn.dataset.startOver;\n    }\n\n    // Show the panel footer again\n    const panelFooter = q('[data-panel-footer]', '.panel-footer', this.step2Section);\n    if (panelFooter) panelFooter.style.display = '';\n\n    // Remove FAQ section if exists\n    const faqContainer = q('[data-faq-container]', '.full-width-faq-container');\n    if (faqContainer) faqContainer.remove();\n\n    // Apply default config to 3D viewer\n    if (this.viewer3D) {\n      this.applyConfigTo3D(this.currentConfig);\n    }\n  }\n}\n\n// ============================================================================\n// INITIALIZATION\n// ============================================================================\n\nfunction initSummit800Configurator() {\n  if (!window.summit800Configurator) {\n    window.summit800Configurator = new Summit800ProductConfigurator();\n    window.summit800Modal = window.summit800Configurator; // Backward compatibility\n  }\n}\n\nif (document.readyState === 'loading') {\n  document.addEventListener('DOMContentLoaded', initSummit800Configurator);\n} else {\n  initSummit800Configurator();\n}\n"],
  "mappings": "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",
  "names": ["imageUrl", "modal", "availableKeys", "option"]
}
