{
  "version": 3,
  "sources": ["/cdn/shop/t/66/assets/summit-608-configurator-3d.js?cb=20260314v1"],
  "sourcesContent": ["/**\n * Product Configurator 3D Viewer\n * Reusable 3D viewer wrapper for step-by-step configurator.\n * Works with any product that has 3D model configuration.\n */\nimport * as THREE from 'three';\nimport { SceneManager } from './SceneManager.js?v=20251217';\nimport { ModelLoader } from './ModelLoader.js?v=20251217';\nimport { MaterialManager } from './MaterialManager.js?v=20251217';\nimport { CameraControls } from './CameraControls.js?v=20251217';\n\nconst DEBUG = false;  // Set to true for verbose debugging\nconst log = (...args) => DEBUG && console.log('[Summit608-3D]', ...args);\n\n/** Extract mesh groups array from various formats */\nconst getMeshGroups = (mg) => {\n  if (!mg) return [];\n  if (Array.isArray(mg)) return mg;\n  if (mg.enabled) return mg.enabled;\n  return [];\n};\n\n/** Extract disabled mesh groups */\nconst getDisabledMeshGroups = (mg) => mg?.disabled || [];\n\nclass Summit608Configurator3D {\n  // Texture fallbacks - can be overridden via configData.textureFallbacks\n  static DEFAULT_TEXTURE_BASE_URL = 'https://cdn.shopify.com/s/files/1/0969/5304/1190/files/';\n  static DEFAULT_FLOOR_TEXTURES = [\n    'ashlar-oak', 'sandcastle-oak', 'fawn-chestnut', 'knotted-chestnut',\n    'natural-hickory', 'fumed-hickory', 'ice-fog', 'stone-grey', 'gothic-arch'\n  ];\n\n  // Summit camera configuration by model size\n  static SUMMIT_CAMERA_RADIUS = {\n    'summit-608': 500,\n    'default': 450\n  };\n\n  constructor(container, configData) {\n    if (!container) {\n      throw new Error('Summit608Configurator3D: Container element is required');\n    }\n\n    this.container = container;\n    this.configData = configData || {};\n    this.sceneManager = null;\n    this.modelLoader = null;\n    this.materialManager = null;\n    this.cameraControls = null;\n    this.currentOrientation = 'left';\n    this.currentStep = 2; // Start with front view when step 2 loads\n    this.isInitialized = false;\n    this.isLoading = false;\n    this.currentLayout = configData?.defaultConfiguration?.layout || 'more-living';\n    this.currentFloorConfig = null;\n    this.floorMeshCache = {};\n    this.loadedComponent = null;           // For models without defaultComponents (legacy behavior)\n    this.loadedDefaultComponent = null;    // The defaultComponents - stays loaded, never swapped\n    this.loadedSideComponent = null;       // Side options component - can be swapped\n    this.loadedFurniture = null;\n    this.currentComponentKey = null;\n    this.currentSideComponentKey = null;   // Track current side component key\n    this.currentModelKey = configData?.defaultConfiguration?.model || null;\n    \n    // Store component option values dynamically (supports different models with different option structures)\n    this.componentOptionValues = {};\n    // Initialize from default configuration\n    if (configData?.defaultConfiguration) {\n      const defaults = configData.defaultConfiguration;\n      // Common options that might affect components\n      // Support both old (Summit 308) and new (Summit 800) option keys\n      ['entryLocation', 'windowOptions', 'sideOptions', 'frontOptions', 'bathOptions', 'entryOptions'].forEach(key => {\n        if (defaults[key]) {\n          this.componentOptionValues[key] = defaults[key];\n        }\n      });\n    }\n    this.disableMtl = !!configData?.disableMtl;\n    this.cachedConfigurations = {};\n    \n    // Programmatic floor plane for models without floor mesh\n    this.floorPlane = null;\n    this.floorPlaneMaterial = null;\n\n    // Build texture fallbacks map from config or defaults\n    this.textureFallbacks = this.buildTextureFallbacks();\n  }\n\n  /**\n   * Build texture fallbacks map from config or defaults\n   */\n  buildTextureFallbacks() {\n    const fallbacks = {};\n    const baseUrl = this.configData?.textureBaseUrl || Summit608Configurator3D.DEFAULT_TEXTURE_BASE_URL;\n    const textures = this.configData?.textureFallbacks || Summit608Configurator3D.DEFAULT_FLOOR_TEXTURES;\n\n    textures.forEach(texture => {\n      if (typeof texture === 'string') {\n        fallbacks[texture] = `${baseUrl}${texture}.jpg`;\n      } else if (texture.name && texture.url) {\n        fallbacks[texture.name] = texture.url;\n      }\n    });\n\n    return fallbacks;\n  }\n\n  /**\n   * Setup optimal camera for Summit model\n   * Provides a 3/4 exterior view angle\n   */\n  setupSummitCamera(modelKey) {\n    if (!this.sceneManager?.camera || !this.sceneManager?.controls) return;\n    \n    const camera = this.sceneManager.camera;\n    const controls = this.sceneManager.controls;\n    \n    const radius = Summit608Configurator3D.SUMMIT_CAMERA_RADIUS[modelKey] || \n                   Summit608Configurator3D.SUMMIT_CAMERA_RADIUS['default'];\n    \n    const elevationDegrees = 30;\n    const rotationDegrees = 45;\n    \n    const elevationRad = elevationDegrees * Math.PI / 180;\n    const rotationRad = rotationDegrees * Math.PI / 180;\n    \n    const cameraX = radius * Math.cos(elevationRad) * Math.sin(rotationRad);\n    const cameraY = radius * Math.sin(elevationRad);\n    const cameraZ = radius * Math.cos(elevationRad) * Math.cos(rotationRad);\n    \n    camera.position.set(cameraX, cameraY, cameraZ);\n    controls.target.set(0, 25, 0);\n    controls.update();\n    \n    log(`Summit-608 Camera Setup: radius=${radius}`);\n  }\n\n  /**\n   * Create a programmatic floor plane based on the loaded model's dimensions\n   * This is used when the OBJ model doesn't have a separate floor mesh\n   * \n   * PRIORITY ORDER for floor dimensions:\n   * 1. Use depth/length from JSON config (most accurate)\n   * 2. Calculate from WALL meshes only (excludes roof overhang)\n   * 3. Fallback to model bounding box with larger inset\n   */\n  createProgrammaticFloor() {\n    // Remove existing floor plane if any\n    if (this.floorPlane) {\n      this.sceneManager?.scene?.remove(this.floorPlane);\n      this.floorPlane.geometry?.dispose();\n      this.floorPlaneMaterial?.dispose();\n      this.floorPlane = null;\n      this.floorPlaneMaterial = null;\n    }\n\n    // Get all meshes\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    if (allMeshes.length === 0) {\n      log('Summit-608 Floor \u25BA No meshes found to calculate floor dimensions');\n      return null;\n    }\n\n    // Filter to get WALL meshes only (exclude roof, eave, fascia which have overhangs)\n    const wallMeshes = allMeshes.filter(mesh => {\n      const name = (mesh.name || '').toLowerCase();\n      // Exclude roof-related meshes\n      if (/roof|eave|fascia|sheathing|corrugated|lifestyle/i.test(name)) {\n        return false;\n      }\n      // Include wall/siding meshes\n      if (/wall|siding|wood_texture|plank|trim|drywall|baseboard/i.test(name)) {\n        return true;\n      }\n      // Include by default if mesh is within building height (below roof line)\n      if (mesh.geometry) {\n        mesh.geometry.computeBoundingBox();\n        const bbox = mesh.geometry.boundingBox;\n        const maxY = bbox ? bbox.max.y : 0;\n        // Typical building walls are below 100 units (roof starts higher)\n        return maxY < 100;\n      }\n      return true;\n    });\n\n    console.log(`Summit-608 Floor \u25BA Using ${wallMeshes.length} wall meshes (of ${allMeshes.length} total) for floor calculation`);\n\n    // Calculate bounding box from wall meshes for more accurate floor size\n    const wallBox = new THREE.Box3();\n    const meshesToUse = wallMeshes.length > 10 ? wallMeshes : allMeshes;\n    \n    meshesToUse.forEach(mesh => {\n      if (mesh.geometry) {\n        mesh.geometry.computeBoundingBox();\n        const meshBox = mesh.geometry.boundingBox.clone();\n        meshBox.applyMatrix4(mesh.matrixWorld);\n        wallBox.union(meshBox);\n      }\n    });\n\n    // Also calculate full model box for center position\n    const modelBox = new THREE.Box3();\n    allMeshes.forEach(mesh => {\n      if (mesh.geometry) {\n        mesh.geometry.computeBoundingBox();\n        const meshBox = mesh.geometry.boundingBox.clone();\n        meshBox.applyMatrix4(mesh.matrixWorld);\n        modelBox.union(meshBox);\n      }\n    });\n\n    const wallSize = wallBox.getSize(new THREE.Vector3());\n    const modelSize = modelBox.getSize(new THREE.Vector3());\n    const modelCenter = modelBox.getCenter(new THREE.Vector3());\n    \n    console.log(`Summit-608 Floor \u25BA Wall bounds: ${wallSize.x.toFixed(1)} x ${wallSize.z.toFixed(1)}, Model bounds: ${modelSize.x.toFixed(1)} x ${modelSize.z.toFixed(1)}`);\n\n    let floorWidth, floorDepth, floorCenterX, floorCenterZ;\n    let usedConfigDimensions = false;\n\n    // PRIORITY 1: Use depth/length from JSON config (most accurate)\n    // Check for dimensions in: root configData, model-specific config, or defaultConfiguration\n    try {\n      const modelKey = this.currentModelKey || this.configData?.defaultConfiguration?.model;\n      const modelConfigData = this.configData?.models?.[modelKey];\n      const rawDepth = this.configData?.depth ?? modelConfigData?.depth ?? this.configData?.defaultConfiguration?.depth;\n      const rawLength = this.configData?.length ?? modelConfigData?.length ?? this.configData?.defaultConfiguration?.length;\n      \n      // Validate and parse dimensions (ensure numeric values)\n      const configDepth = typeof rawDepth === 'number' ? rawDepth : parseFloat(rawDepth);\n      const configLength = typeof rawLength === 'number' ? rawLength : parseFloat(rawLength);\n\n      if (!isNaN(configDepth) && !isNaN(configLength) && configDepth > 0 && configLength > 0) {\n        // Use config dimensions: convert feet to inches (multiply by 12)\n        floorWidth = configLength * 12;  // Length in feet \u00D7 12 = inches\n        floorDepth = configDepth * 12;   // Depth in feet \u00D7 12 = inches\n        floorCenterX = modelCenter.x;\n        floorCenterZ = modelCenter.z;\n        \n        usedConfigDimensions = true;\n        if (DEBUG) {\n          console.log(`Summit-608 Floor \u25BA Using CONFIG dimensions: ${configLength}ft x ${configDepth}ft \u2192 ${floorWidth} x ${floorDepth} inches`);\n        }\n      }\n    } catch (configError) {\n      // Config parsing failed, will fall back to mesh-based calculation\n      if (DEBUG) {\n        console.warn('Summit-608 Floor \u25BA Config dimension parsing failed:', configError);\n      }\n    }\n\n    if (!usedConfigDimensions) {\n      // PRIORITY 2-3: Fall back to mesh-based calculation\n      if (DEBUG) {\n        console.log(`Summit-608 Floor \u25BA No config dimensions found, falling back to mesh-based calculation`);\n      }\n      \n      // Apply small inset for wall thickness\n      const wallInsetX = Math.max(wallSize.x * 0.03, 4);\n      const wallInsetZ = Math.max(wallSize.z * 0.03, 4);\n      \n      // Use wall bounds if significantly smaller than model bounds (roof overhang detected)\n      const useWallBounds = wallSize.x < modelSize.x * 0.95 || wallSize.z < modelSize.z * 0.95;\n      \n      if (useWallBounds && wallMeshes.length > 10) {\n        floorWidth = Math.max(wallSize.x - wallInsetX * 2, 50);\n        floorDepth = Math.max(wallSize.z - wallInsetZ * 2, 50);\n        if (DEBUG) {\n          console.log(`Summit-608 Floor \u25BA Using wall bounds (roof overhang excluded)`);\n        }\n      } else {\n        // Fallback: Use model bounds with larger inset for roof overhang\n        const roofOverhangX = Math.max(modelSize.x * 0.12, 20);\n        const roofOverhangZ = Math.max(modelSize.z * 0.12, 15);\n        \n        floorWidth = Math.max(modelSize.x - roofOverhangX * 2, 50);\n        floorDepth = Math.max(modelSize.z - roofOverhangZ * 2, 50);\n        if (DEBUG) {\n          console.log(`Summit-608 Floor \u25BA Using model bounds with roof overhang inset`);\n        }\n      }\n      \n      floorCenterX = modelCenter.x;\n      floorCenterZ = modelCenter.z;\n\n      if (DEBUG) {\n        console.log(`Summit-608 Floor \u25BA Wall bounds: ${wallSize.x.toFixed(1)} x ${wallSize.z.toFixed(1)}`);\n        console.log(`Summit-608 Floor \u25BA Model bounds: ${modelSize.x.toFixed(1)} x ${modelSize.z.toFixed(1)}`);\n        console.log(`Summit-608 Floor \u25BA Floor dimensions: ${floorWidth.toFixed(1)} x ${floorDepth.toFixed(1)}`);\n      }\n    }\n\n    // Ensure minimum dimensions\n    floorWidth = Math.max(floorWidth, 50);\n    floorDepth = Math.max(floorDepth, 50);\n\n    // Floor Y position - BELOW bathroom floor mesh (Y=0) so bathroom mesh renders on top\n    // Bathroom floor mesh is at Y=0 with height ~0.1, so we place main floor at Y=-0.2\n    const floorY = -0.2;\n\n    console.log(`Summit-608 Floor \u25BA Creating programmatic floor: ${floorWidth.toFixed(1)} x ${floorDepth.toFixed(1)} at Y=${floorY}, center: (${floorCenterX.toFixed(1)}, ${floorCenterZ.toFixed(1)})`);\n\n    // Create floor geometry\n    const floorGeometry = new THREE.PlaneGeometry(floorWidth, floorDepth);\n    \n    // Create initial material (will be replaced with texture)\n    // Use polygonOffset to prevent z-fighting with other floor elements\n    this.floorPlaneMaterial = new THREE.MeshStandardMaterial({\n      color: 0xcccccc,\n      side: THREE.DoubleSide,\n      polygonOffset: true,\n      polygonOffsetFactor: 1,\n      polygonOffsetUnits: 1,\n      roughness: 0.8,\n      metalness: 0.0\n    });\n\n    // Create floor mesh\n    this.floorPlane = new THREE.Mesh(floorGeometry, this.floorPlaneMaterial);\n    \n    // Rotate to horizontal and position\n    this.floorPlane.rotation.x = -Math.PI / 2; // Rotate to horizontal\n    this.floorPlane.position.set(floorCenterX, floorY, floorCenterZ);\n    this.floorPlane.receiveShadow = true;\n    this.floorPlane.name = 'programmatic_floor';\n\n    // Add to scene\n    this.sceneManager?.scene?.add(this.floorPlane);\n\n    console.log(`Summit-608 Floor \u25BA Programmatic floor created and added to scene`);\n    return this.floorPlane;\n  }\n\n  /**\n   * Apply texture to the programmatic floor plane\n   */\n  async applyTextureToFloorPlane(textureUrl, textureScale) {\n    if (!this.floorPlane) {\n      console.warn('Summit-608 Floor \u25BA No floor plane to apply texture to');\n      return false;\n    }\n\n    // THREE is imported at the top of this file\n\n    try {\n      const textureLoader = new THREE.TextureLoader();\n      const texture = await new Promise((resolve, reject) => {\n        textureLoader.load(\n          textureUrl,\n          resolve,\n          undefined,\n          reject\n        );\n      });\n\n      // Configure texture\n      texture.wrapS = THREE.RepeatWrapping;\n      texture.wrapT = THREE.RepeatWrapping;\n      \n      // Calculate texture scale based on floor size\n      const floorGeom = this.floorPlane.geometry;\n      const params = floorGeom.parameters;\n      const floorWidth = params?.width || 100;\n      const floorDepth = params?.height || 100;\n      \n      // Each texture tile represents ~48 inches (4 feet) of flooring\n      const TEXTURE_TILE_SIZE = 48;\n      const uRepeat = textureScale?.uScale || (floorWidth / TEXTURE_TILE_SIZE);\n      const vRepeat = textureScale?.vScale || (floorDepth / TEXTURE_TILE_SIZE);\n      \n      texture.repeat.set(uRepeat, vRepeat);\n      texture.colorSpace = THREE.SRGBColorSpace;\n\n      // Create new material with texture\n      // Use polygonOffset to ensure bathroom floor renders on top when they overlap\n      const newMaterial = new THREE.MeshStandardMaterial({\n        map: texture,\n        side: THREE.DoubleSide,\n        roughness: 0.7,\n        polygonOffset: true,\n        polygonOffsetFactor: 1,\n        polygonOffsetUnits: 1,\n        metalness: 0.0\n      });\n\n      // Dispose old material and apply new one\n      this.floorPlaneMaterial?.dispose();\n      this.floorPlaneMaterial = newMaterial;\n      this.floorPlane.material = newMaterial;\n\n      console.log(`Summit-608 Floor \u25BA Applied texture to programmatic floor: ${textureUrl} (${uRepeat.toFixed(2)} x ${vRepeat.toFixed(2)} repeat)`);\n      return true;\n    } catch (error) {\n      console.error('Summit-608 Floor \u25BA Failed to apply texture to floor plane:', error);\n      return false;\n    }\n  }\n\n  init() {\n    if (this.isInitialized) {\n      log('Summit608Configurator3D already initialized');\n      return this;\n    }\n\n    if (!this.container) {\n      console.error('Summit608Configurator3D: Cannot initialize without container');\n      return this;\n    }\n\n    try {\n      this.sceneManager = new SceneManager(this.container);\n      this.modelLoader = new ModelLoader(this.sceneManager, this.configData);\n      this.materialManager = new MaterialManager(this.modelLoader, this.configData, this.sceneManager);\n      this.cameraControls = new CameraControls(this.sceneManager);\n      this.applyMtlBypass();\n      this.setupLoadingIndicator();\n      this.isInitialized = true;\n      log('Summit608Configurator3D initialized');\n    } catch (error) {\n      console.error('Failed to initialize 3D viewer:', error);\n      this.isInitialized = false;\n      this.dispatchError('initialization', error);\n    }\n\n    return this;\n  }\n\n  applyMtlBypass() {\n    if (!this.disableMtl || !this.modelLoader) return;\n\n    // Summit models have NO MTL files - always skip MTL loading\n    if (typeof this.modelLoader.normalizeFileReference === 'function') {\n      const originalNormalize = this.modelLoader.normalizeFileReference.bind(this.modelLoader);\n      this.modelLoader.normalizeFileReference = (entry) => {\n        const normalized = originalNormalize(entry);\n        if (!normalized) return normalized;\n        \n        // Always remove MTL for Summit models\n        delete normalized.mtl;\n        return normalized;\n      };\n    }\n  }\n\n  /**\n   * Setup loading indicator overlay\n   */\n  setupLoadingIndicator() {\n    // Add CSS for spinner if not present\n    if (!document.getElementById('summit-608-loader-css')) {\n      const style = document.createElement('style');\n      style.id = 'summit-608-loader-css';\n      style.textContent = `\n        @keyframes summit-608-spin { to { transform: rotate(360deg); } }\n        .summit-608-loader { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; background:rgba(255,255,255,0.9); z-index:100; }\n        .summit-608-loader-spinner { width:40px; height:40px; border:3px solid #e0e0e0; border-top-color:#333; border-radius:50%; animation:summit-608-spin 0.8s linear infinite; }\n        .summit-608-loader-text { margin-top:12px; font-size:14px; color:#666; }\n      `;\n      document.head.appendChild(style);\n    }\n\n    // Create loader element\n    this.loaderEl = document.createElement('div');\n    this.loaderEl.className = 'summit-608-loader';\n    this.loaderEl.style.display = 'none';\n    this.loaderEl.innerHTML = '<div class=\"summit-608-loader-spinner\"></div><div class=\"summit-608-loader-text\">Loading...</div>';\n    this.container.style.position = 'relative';\n    this.container.appendChild(this.loaderEl);\n  }\n\n  /**\n   * Show loading indicator\n   */\n  showLoader() {\n    if (this.loaderEl) this.loaderEl.style.display = 'flex';\n  }\n\n  /**\n   * Hide loading indicator\n   */\n  hideLoader() {\n    if (this.loaderEl) this.loaderEl.style.display = 'none';\n  }\n\n  /**\n   * Dispatch error event for external handling\n   */\n  dispatchError(type, error) {\n    this.container?.dispatchEvent(new CustomEvent('configurator:error', {\n      detail: { type, error: error.message || error, timestamp: Date.now() }\n    }));\n  }\n\n  /**\n   * Get the option keys that affect component selection\n   * Reads from componentCodeMapping or uses defaults\n   */\n  getComponentOptionKeys() {\n    const mapping = this.configData.componentCodeMapping;\n    if (mapping) {\n      // Get option keys from the mapping (e.g., windowOptions, sideOptions, entryLocation)\n      const keys = Object.keys(mapping).filter(key => \n        key !== 'description' && key !== 'format' && typeof mapping[key] === 'object'\n      );\n      return keys;\n    }\n    // Default for Summit 308 models\n    return ['entryLocation', 'windowOptions'];\n  }\n\n  /**\n   * Check if a section affects component selection\n   * NOTE: Models with ONLY defaultComponents (no components mapping) have fixed components.\n   * Models with BOTH defaultComponents AND components mapping can still swap components.\n   */\n  isComponentOption(section) {\n    const modelKey = this.currentModelKey || this.configData.defaultConfiguration?.model;\n    const modelConfig = this.configData.models?.[modelKey];\n    \n    // Check if there's a component mapping at all\n    const hasComponentMapping = modelConfig?.modelFiles?.components && Object.keys(modelConfig.modelFiles.components).length > 0;\n    \n    // If no component mapping exists, no section affects component selection\n    // (even if defaultComponents exists, we can't swap to anything)\n    if (!hasComponentMapping) {\n      return false;\n    }\n    \n    // If there IS a component mapping, this section can affect component selection\n    const optionKeys = this.getComponentOptionKeys();\n    \n    // Direct match with mapping keys\n    if (optionKeys.includes(section)) {\n      return true;\n    }\n    \n    // Check for conditional options that map to thirdOptions\n    // sideOptions and frontOptions are conditional third options based on entry selection\n    if (optionKeys.includes('thirdOptions') && \n        (section === 'sideOptions' || section === 'frontOptions')) {\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * Get component key dynamically based on current option selections\n   * Reads mappings from componentCodeMapping in JSON if available\n   */\n  getComponentKey() {\n    // Get model letter from the current model key or default config\n    let modelLetter = 'A';\n    const modelKey = this.currentModelKey || this.configData.defaultConfiguration?.model;\n    if (modelKey) {\n      const match = modelKey.match(/-([a-z])$/i);\n      if (match) {\n        modelLetter = match[1].toUpperCase();\n      }\n    }\n    \n    // Also check summitNxCode if available (e.g., \"B-1-a\" means model B)\n    const summitNxCode = this.configData.defaultConfiguration?.summitNxCode;\n    if (summitNxCode) {\n      const codeMatch = summitNxCode.match(/^([A-Z])-/i);\n      if (codeMatch) {\n        modelLetter = codeMatch[1].toUpperCase();\n      }\n    }\n\n    const mapping = this.configData.componentCodeMapping;\n    \n    if (mapping) {\n      // Use dynamic mapping from JSON (Summit 440/800 style)\n      // mapping structure: { bathOptions: { \"single-bathroom\": \"1\" }, entryOptions: { \"front-door\": \"a\" }, thirdOptions: { \"side-window\": \"i\" } }\n      const optionKeys = this.getComponentOptionKeys();\n      const codeParts = [];\n      \n      console.log(`[Component Key] Model: ${modelLetter}, Option keys:`, optionKeys);\n      console.log(`[Component Key] Current componentOptionValues:`, this.componentOptionValues);\n      console.log(`[Component Key] Default config:`, this.configData.defaultConfiguration);\n      \n      optionKeys.forEach(optionKey => {\n        const optionMapping = mapping[optionKey];\n        if (optionMapping) {\n          // Get current value for this option from stored state or defaults\n          let currentValue = this.componentOptionValues[optionKey] || \n                              this.configData.defaultConfiguration?.[optionKey];\n          \n          // Handle conditional options like \"thirdOptions\" which may come from \"sideOptions\" or \"frontOptions\"\n          // based on the entry selection\n          if (!currentValue && optionKey === 'thirdOptions') {\n            // Determine which actual option to use based on entry selection\n            const entryValue = this.componentOptionValues.entryOptions || \n                              this.configData.defaultConfiguration?.entryOptions || 'front-door';\n            \n            if (entryValue === 'front-door' || entryValue === 'front-entry') {\n              // When front door is selected, use sideOptions for the third option\n              currentValue = this.componentOptionValues.sideOptions || \n                            this.configData.defaultConfiguration?.sideOptions;\n            } else {\n              // When side door is selected, use frontOptions for the third option\n              currentValue = this.componentOptionValues.frontOptions || \n                            this.configData.defaultConfiguration?.frontOptions;\n            }\n            \n            console.log(`[Component Key] thirdOptions resolved from entry \"${entryValue}\" to value \"${currentValue}\"`);\n          }\n          \n          const codeValue = optionMapping[currentValue];\n          console.log(`[Component Key] ${optionKey}: \"${currentValue}\" \u2192 code \"${codeValue}\"`);\n          \n          if (codeValue) {\n            codeParts.push(codeValue);\n          } else if (currentValue) {\n            console.warn(`[Component Key] No mapping found for \"${optionKey}\" value \"${currentValue}\"`);\n          }\n        }\n      });\n      \n      // Build component key: format varies by model\n      // Summit 476: A-1 format (1 option: sideOptions)\n      // Summit 308: A-1-a format (2 options: entryLocation + windowOptions)\n      // Summit 800: A-1-a-i format (3+ options)\n      if (codeParts.length >= 1) {\n        const componentKey = `${modelLetter}-${codeParts.join('-')}`;\n        console.log(`[Component Key] \u2705 Generated \"${componentKey}\" from ${codeParts.length} parts:`, codeParts);\n        return componentKey;\n      } else {\n        console.error(`[Component Key] \u274C No code parts generated, check componentCodeMapping and current option values`);\n      }\n    }\n    \n    // Fallback: Summit 308 style mapping (entryLocation + windowOptions)\n    const entryMap = { 'front-entry': '1', 'side-entry': '2' };\n    const windowMap = { 'more-glass': 'a', 'more-privacy': 'b' };\n    \n    const entryValue = this.componentOptionValues.entryLocation || \n                       this.configData.defaultConfiguration?.entryLocation || 'front-entry';\n    const windowValue = this.componentOptionValues.windowOptions || \n                        this.configData.defaultConfiguration?.windowOptions || 'more-glass';\n    \n    const entryNum = entryMap[entryValue] || '1';\n    const windowLetter = windowMap[windowValue] || 'a';\n\n    return `${modelLetter}-${entryNum}-${windowLetter}`;\n  }\n\n  /**\n   * Whether the shared ModelLoader already implements component helpers\n   */\n  supportsComponentLoader() {\n    return typeof this.modelLoader?.loadComponent === 'function';\n  }\n\n  supportsComponentRemoval() {\n    return typeof this.modelLoader?.removeComponent === 'function';\n  }\n\n  /**\n   * Normalize Summit component file entry into { obj, mtl }\n   */\n  normalizeComponentFile(entry) {\n    if (!entry) return null;\n\n    if (typeof this.modelLoader?.normalizeFileReference === 'function') {\n      return this.modelLoader.normalizeFileReference(entry);\n    }\n\n    if (typeof entry === 'string') {\n      return this.disableMtl ? { obj: entry } : { obj: entry, mtl: entry.replace(/\\.obj(\\?.*)?$/i, '.mtl$1') };\n    }\n\n    if (entry.obj) {\n      const result = { obj: entry.obj };\n      if (entry.mtl) {\n        result.mtl = entry.mtl;\n      } else if (!this.disableMtl) {\n        result.mtl = entry.obj.replace(/\\.obj(\\?.*)?$/i, '.mtl$1');\n      }\n      return result;\n    }\n\n    return null;\n  }\n\n  /**\n   * Load Summit component even if ModelLoader lacks helper (fallback path)\n   */\n  async loadSummitComponent(modelKey, componentKey) {\n    if (!componentKey) return null;\n\n    if (this.supportsComponentLoader()) {\n      return this.modelLoader.loadComponent(modelKey, componentKey);\n    }\n\n    const modelConfig = this.configData.models?.[modelKey];\n    if (!modelConfig?.modelFiles?.components?.[componentKey]) {\n      throw new Error(`Component ${componentKey} not configured for model ${modelKey}`);\n    }\n\n    const normalized = this.normalizeComponentFile(modelConfig.modelFiles.components[componentKey]);\n    if (!normalized?.obj) {\n      throw new Error(`Component files missing OBJ for ${componentKey}`);\n    }\n\n    const component = await this.modelLoader.loadObjWithMtl(normalized.obj, normalized.mtl);\n\n    if (typeof this.modelLoader.registerMeshes === 'function') {\n      this.modelLoader.registerMeshes(component, `component_${componentKey}_`);\n    }\n\n    this.sceneManager?.scene?.add(component);\n    return component;\n  }\n\n  /**\n   * Remove loaded component with graceful fallback\n   */\n  removeSummitComponent(componentKey) {\n    if (!componentKey || !this.loadedComponent) return;\n\n    if (this.supportsComponentRemoval()) {\n      try {\n        this.modelLoader.removeComponent(componentKey);\n      } catch (error) {\n        console.warn('Summit-608 Configurator: removeComponent failed, using fallback removal', error);\n        this.forceRemoveLoadedComponent();\n        return;\n      }\n      this.loadedComponent = null;\n      this.currentComponentKey = null;\n      return;\n    }\n\n    this.forceRemoveLoadedComponent();\n  }\n\n  forceRemoveLoadedComponent() {\n    if (!this.loadedComponent) return;\n\n    if (this.loadedComponent.parent?.remove) {\n      this.loadedComponent.parent.remove(this.loadedComponent);\n    } else if (this.sceneManager?.scene?.remove) {\n      this.sceneManager.scene.remove(this.loadedComponent);\n    }\n\n    // Dispose geometry/materials to avoid leaks\n    this.loadedComponent.traverse?.((child) => {\n      child.geometry?.dispose?.();\n      if (Array.isArray(child.material)) {\n        child.material.forEach(mat => mat?.dispose?.());\n      } else {\n        child.material?.dispose?.();\n      }\n    });\n\n    this.loadedComponent = null;\n    this.currentComponentKey = null;\n  }\n\n  async loadModel(orientation = 'left') {\n    if (!this.isInitialized || this.isLoading) return;\n\n    this.isLoading = true;\n    this.currentOrientation = orientation;\n    // Note: Don't show internal loader here - the modal's placeholder handles initial loading UI\n    // The internal loader is used for component swaps (handleComponentChange) instead\n\n    try {\n      // Prefer explicit model from default configuration, fallback to first available\n      const availableModels = Object.keys(this.configData.models || {});\n      let modelKey = this.configData.defaultConfiguration?.model;\n      if (!modelKey || !this.configData.models?.[modelKey]) {\n        modelKey = availableModels[0] || 'summit-1';\n      }\n      \n      // Store current model key for component key generation\n      this.currentModelKey = modelKey;\n\n      log('Loading model', modelKey);\n\n      // Validate that model files exist for this key\n      const modelConfig = this.configData.models?.[modelKey];\n      if (!modelConfig) {\n        throw new Error(`Model configuration not found: ${modelKey}`);\n      }\n\n      if (!modelConfig.modelFiles) {\n        throw new Error(`Model files not configured for: ${modelKey}`);\n      }\n\n      // Validate modelFiles structure\n      const hasNewStructure = modelConfig.modelFiles.base?.obj;\n      const hasOldStructure = modelConfig.modelFiles.base?.[orientation];\n\n      if (!hasNewStructure && !hasOldStructure) {\n        throw new Error(`Model files not found for ${modelKey}/${orientation}`);\n      }\n\n      this.modelLoader.clearModels();\n      this.floorMeshCache = {};\n\n      // Load base model (ModelLoader.loadModel internally calls sceneManager.addModel which centers the model)\n      await this.modelLoader.loadModel(modelKey, orientation);\n\n      // Load roof (supports both old and new structures)\n      const roofType = this.configData.defaultConfiguration?.roof || 'standard';\n      const extended = roofType === '4-front-eaves' || roofType === 'extended';\n      try {\n        await this.modelLoader.loadRoof(modelKey, orientation, extended);\n      } catch (e) {\n        log('Could not load roof:', e);\n      }\n\n      // Load component - Priority order:\n      // 1. defaultComponents.obj - Load as initial component (if exists)\n      // 2. components[key] - Only used when user changes options (component swapping)\n      // 3. Skip component loading if neither exists\n      \n      const defaultComponents = modelConfig.modelFiles?.defaultComponents || this.configData.defaultComponents;\n      const hasDefaultComponent = !!(defaultComponents?.obj);\n      const componentsObj = modelConfig.modelFiles?.components;\n      const hasComponentMapping = componentsObj && typeof componentsObj === 'object' && Object.keys(componentsObj).length > 0;\n      \n      console.log('Summit-608 Configurator: Component loading check:', {\n        hasDefaultComponent,\n        defaultComponentUrl: defaultComponents?.obj,\n        hasComponentMapping,\n        componentKeys: componentsObj ? Object.keys(componentsObj) : []\n      });\n      \n      const previousComponentKey = this.currentComponentKey;\n\n      // Remove any existing component first\n      if (this.loadedComponent && previousComponentKey) {\n        try {\n          this.removeSummitComponent(previousComponentKey);\n        } catch (e) {\n          log('Could not remove existing component:', e);\n        }\n      }\n\n      let defaultComponentLoaded = false;\n      let sideComponentLoaded = false;\n      \n      // STEP 1: Load defaultComponents if exists (this is the BASE that stays)\n      if (hasDefaultComponent) {\n        console.log('Summit-608 Configurator: Loading defaultComponents (base):', defaultComponents.obj);\n        try {\n          const normalized = this.normalizeComponentFile(defaultComponents);\n          if (normalized?.obj) {\n            const component = await this.modelLoader.loadObjWithMtl(normalized.obj, normalized.mtl || null);\n            if (component) {\n              // Register meshes with ModelLoader so getAllMeshes() includes them\n              if (typeof this.modelLoader.registerMeshes === 'function') {\n                this.modelLoader.registerMeshes(component, `component_default_`);\n              }\n              // Store in ModelLoader's loadedComponents\n              if (!this.modelLoader.loadedComponents) {\n                this.modelLoader.loadedComponents = {};\n              }\n              this.modelLoader.loadedComponents['default'] = component;\n              \n              this.sceneManager?.scene?.add(component);\n              this.loadedDefaultComponent = component;\n              this.loadedComponent = component; // For backward compatibility\n              this.currentComponentKey = 'default';\n              defaultComponentLoaded = true;\n              \n              console.log('Summit-608 Configurator: Loaded defaultComponents (base) successfully');\n              \n              // Debug: Log mesh names\n              let meshCount = 0;\n              const meshNames = [];\n              component.traverse((child) => {\n                if (child.isMesh) {\n                  meshCount++;\n                  if (meshNames.length < 30) meshNames.push(child.name || 'unnamed');\n                }\n              });\n              console.log(`Summit-608 Configurator: defaultComponents has ${meshCount} meshes:`, meshNames.join(', '));\n            }\n          }\n        } catch (e) {\n          console.warn(`Summit-608 Configurator: Could not load defaultComponents:`, e.message);\n        }\n      }\n      \n      // STEP 2: If model has component mapping, load the appropriate component\n      if (hasComponentMapping) {\n        const componentKey = this.getComponentKey();\n        console.log('Summit-608 Configurator: Loading component, key:', componentKey);\n        console.log('Summit-608 Configurator: componentOptionValues:', this.componentOptionValues);\n\n        try {\n          const component = await this.loadSummitComponent(modelKey, componentKey);\n          if (component) {\n            // Store in ModelLoader's loadedComponents\n            if (!this.modelLoader.loadedComponents) {\n              this.modelLoader.loadedComponents = {};\n            }\n            \n            if (defaultComponentLoaded) {\n              // MODEL HAS defaultComponents: This is a SIDE OPTIONS component (loaded in addition)\n              this.modelLoader.loadedComponents['sideOptions'] = component;\n              this.loadedSideComponent = component;\n              this.currentSideComponentKey = componentKey;\n              sideComponentLoaded = true;\n              console.log('Summit-608 Configurator: Loaded side options component (with defaultComponents):', componentKey);\n            } else {\n              // MODEL WITHOUT defaultComponents: This is the MAIN component (legacy behavior)\n              this.modelLoader.loadedComponents['main'] = component;\n              this.loadedComponent = component;\n              this.currentComponentKey = componentKey;\n              console.log('Summit-608 Configurator: Loaded main component (legacy mode):', componentKey);\n            }\n          }\n        } catch (e) {\n          console.warn(`Summit-608 Configurator: Could not load component ${componentKey}:`, e.message);\n        }\n      }\n      \n      if (!defaultComponentLoaded && !sideComponentLoaded && !this.loadedComponent) {\n        log('Summit-608 Configurator: No components found to load');\n      }\n      \n      // Log total meshes after loading\n      const allMeshesAfterLoad = this.modelLoader?.getAllMeshes?.() || [];\n      console.log(`Summit-608 Configurator: Total meshes after loading all components: ${allMeshesAfterLoad.length}`);\n\n      // Load furniture model if available\n      const furnitureFiles = modelConfig.modelFiles?.furniture;\n      if (furnitureFiles) {\n        let furnitureUrl = null;\n        \n        if (furnitureFiles.obj) {\n          furnitureUrl = furnitureFiles.obj;\n        } else {\n          const bathOption = this.componentOptionValues.bathOptions || \n                            this.configData.defaultConfiguration?.bathOptions || 'single-bathroom';\n          const furnitureEntry = furnitureFiles[bathOption];\n          if (furnitureEntry) {\n            furnitureUrl = furnitureEntry.obj || furnitureEntry;\n          }\n        }\n        \n        if (furnitureUrl) {\n          try {\n            const furniture = await this.modelLoader.loadObjWithMtl(furnitureUrl, null);\n            if (furniture) {\n              if (typeof this.modelLoader.registerMeshes === 'function') {\n                this.modelLoader.registerMeshes(furniture, `furniture_`);\n              }\n              this.sceneManager?.scene?.add(furniture);\n              this.loadedFurniture = furniture;\n            }\n          } catch (e) {\n            log('Could not load furniture:', e);\n          }\n        }\n      }\n\n      // Create programmatic floor plane\n      this.createProgrammaticFloor();\n\n      // Debug logging - only when DEBUG is enabled\n      if (DEBUG) {\n        try { this.debugLogLoadedMeshes(); } catch (e) {}\n      }\n\n      // Initialize materials\n      try {\n        await this.materialManager.initializeDefaultMaterials();\n      } catch (e) { log('Could not initialize materials:', e); }\n\n      // Apply default finishes\n      await this.applyDefaultFloorFinish();\n      await this.applyDefaultExteriorFinishes();\n\n      // Set view for step first (handles roof visibility)\n      this.setViewForStep(this.currentStep);\n      \n      // Setup optimal camera for Summit model (3/4 exterior view)\n      if (this.currentStep >= 2) {\n        this.setupSummitCamera(modelKey);\n      }\n      \n      this.onModelLoaded(orientation);\n      \n      // Run diagnostic only when DEBUG is enabled\n      if (DEBUG) this.runLoadingDiagnostic();\n    } catch (error) {\n      console.error('Error loading model:', error);\n    } finally {\n      this.isLoading = false;\n      this.hideLoader();\n    }\n  }\n\n  /**\n   * Comprehensive diagnostic - disabled in production\n   */\n  runLoadingDiagnostic() {\n    // Disabled to reduce console noise - enable DEBUG flag for diagnostics\n    if (!DEBUG) return;\n    \n    const issues = [];\n    \n    // 1. Check base model\n    const baseModel = this.modelLoader?.loadedModel;\n    if (baseModel) {\n      let baseMeshCount = 0;\n      baseModel.traverse(c => { if (c.isMesh) baseMeshCount++; });\n      console.log(`\u2705 Base Model: Loaded (${baseMeshCount} meshes)`);\n    } else {\n      console.log('\u274C Base Model: NOT LOADED');\n      issues.push('Base model failed to load');\n    }\n    \n    // 2. Check roof\n    const roof = this.modelLoader?.loadedRoof;\n    if (roof) {\n      let roofMeshCount = 0;\n      roof.traverse(c => { if (c.isMesh) roofMeshCount++; });\n      console.log(`\u2705 Roof: Loaded (${roofMeshCount} meshes)`);\n    } else {\n      console.log('\u26A0\uFE0F Roof: NOT LOADED (may be optional)');\n    }\n    \n    // 3. Check component\n    if (this.loadedComponent) {\n      let compMeshCount = 0;\n      this.loadedComponent.traverse(c => { if (c.isMesh) compMeshCount++; });\n      console.log(`\u2705 Component (${this.currentComponentKey}): Loaded (${compMeshCount} meshes)`);\n    } else {\n      console.log(`\u274C Component (${this.currentComponentKey}): NOT LOADED`);\n      issues.push(`Component ${this.currentComponentKey} failed to load`);\n    }\n    \n    // 4. Check furniture\n    if (this.loadedFurniture) {\n      let furnMeshCount = 0;\n      this.loadedFurniture.traverse(c => { if (c.isMesh) furnMeshCount++; });\n      console.log(`\u2705 Furniture: Loaded (${furnMeshCount} meshes)`);\n    } else {\n      console.log('\u26A0\uFE0F Furniture: NOT LOADED');\n      issues.push('Furniture failed to load');\n    }\n    \n    // 5. Check component key generation\n    const expectedKey = this.getComponentKey();\n    console.log(`\\n\uD83D\uDCCB Component Key: \"${expectedKey}\"`);\n    console.log(`   Current stored key: \"${this.currentComponentKey}\"`);\n    if (expectedKey !== this.currentComponentKey) {\n      console.log('\u26A0\uFE0F Component key mismatch!');\n      issues.push('Component key mismatch');\n    }\n    \n    // 6. Check available components\n    const modelKey = this.currentModelKey;\n    const modelConfig = this.configData.models?.[modelKey];\n    const availableComponents = Object.keys(modelConfig?.modelFiles?.components || {});\n    console.log(`\\n\uD83D\uDCE6 Available Components: ${availableComponents.join(', ') || 'NONE'}`);\n    \n    if (!availableComponents.includes(expectedKey)) {\n      console.log(`\u274C Expected component \"${expectedKey}\" NOT in available components!`);\n      issues.push(`Component \"${expectedKey}\" not found in config`);\n    }\n    \n    // 7. Log all mesh names for debugging\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    const meshNames = allMeshes.map(m => m.name).filter(Boolean);\n    console.log(`\\n\uD83D\uDCCA Total Meshes in Scene: ${allMeshes.length}`);\n    \n    // Check for front-related meshes\n    const frontMeshes = meshNames.filter(n => /front/i.test(n));\n    const wallMeshes = meshNames.filter(n => /wall|siding|plank|wood_texture/i.test(n));\n    const doorMeshes = meshNames.filter(n => /door/i.test(n));\n    \n    console.log(`\\n\uD83E\uDDF1 Wall/Siding Meshes (${wallMeshes.length}): ${wallMeshes.slice(0, 10).join(', ')}${wallMeshes.length > 10 ? '...' : ''}`);\n    console.log(`\uD83D\uDEAA Door Meshes (${doorMeshes.length}): ${doorMeshes.join(', ') || 'NONE'}`);\n    console.log(`\uD83C\uDFE0 Front-related Meshes (${frontMeshes.length}): ${frontMeshes.join(', ') || 'NONE'}`);\n    \n    // Summary\n    console.log('\\n========================================');\n    if (issues.length === 0) {\n      console.log('\u2705 ALL MODEL PARTS LOADED SUCCESSFULLY');\n    } else {\n      console.log(`\u274C ISSUES FOUND (${issues.length}):`);\n      issues.forEach((issue, i) => console.log(`   ${i + 1}. ${issue}`));\n    }\n    console.log('========================================\\n');\n    \n    return issues;\n  }\n\n  /**\n   * Handle component change (any option that affects component selection)\n   * Gets all component option values from stored state to ensure component is correct\n   */\n  async handleComponentChange(config) {\n    // Update the stored value for the section that changed\n    this.componentOptionValues[config.section] = config.value;\n    // Update the component with current values\n    await this.updateComponent();\n  }\n\n  /**\n   * Update component based on current component option values\n   * For models with defaultComponents + components mapping:\n   *   - defaultComponents stays (never removed)\n   *   - Only the side options component is swapped\n   * For models with only components mapping:\n   *   - The entire component is swapped (legacy behavior)\n   */\n  async updateComponent() {\n    if (!this.isInitialized || this.isLoading) return;\n\n    const modelKey = this.currentModelKey || (this.configData.models ? Object.keys(this.configData.models)[0] : 'summit-1');\n    const modelConfig = this.configData.models?.[modelKey];\n    \n    // Check if this model has component mapping - required for dynamic updates\n    const hasComponentMapping = modelConfig?.modelFiles?.components && Object.keys(modelConfig.modelFiles.components).length > 0;\n    if (!hasComponentMapping) {\n      log('Summit-608 Configurator: No component mapping found, skipping component update');\n      return;\n    }\n    \n    const componentKey = this.getComponentKey();\n\n    // Check if this is a model with defaultComponents (side options mode)\n    const hasDefaultComponent = this.loadedDefaultComponent !== null;\n    \n    if (hasDefaultComponent) {\n      // SIDE OPTIONS MODE: Only swap the side component, keep defaultComponents\n      \n      // If side component hasn't changed, skip\n      if (this.currentSideComponentKey === componentKey) {\n        console.log('Summit-608 Configurator: Side component unchanged, skipping');\n        return;\n      }\n\n      console.log(`Summit-608 Configurator: Swapping side options component from \"${this.currentSideComponentKey}\" to \"${componentKey}\"`);\n      this.showLoader();\n\n      // Remove old side component only (keep defaultComponents)\n      if (this.loadedSideComponent) {\n        try {\n          this.sceneManager?.scene?.remove(this.loadedSideComponent);\n          if (this.modelLoader.loadedComponents?.['sideOptions']) {\n            delete this.modelLoader.loadedComponents['sideOptions'];\n          }\n          this.loadedSideComponent = null;\n          console.log('Summit-608 Configurator: Removed old side options component');\n        } catch (e) {\n          log('Could not remove old side component:', e);\n        }\n      }\n\n      // Load new side component\n      try {\n        const sideComponent = await this.loadSummitComponent(modelKey, componentKey);\n        if (sideComponent) {\n          if (!this.modelLoader.loadedComponents) {\n            this.modelLoader.loadedComponents = {};\n          }\n          this.modelLoader.loadedComponents['sideOptions'] = sideComponent;\n          \n          this.loadedSideComponent = sideComponent;\n          this.currentSideComponentKey = componentKey;\n          \n          console.log('Summit-608 Configurator: Loaded new side options component:', componentKey);\n        }\n      } catch (e) {\n        console.warn(`Summit-608 Configurator: Could not load side options component ${componentKey}:`, e.message);\n      }\n    } else {\n      // LEGACY MODE: Swap entire component (no defaultComponents)\n      \n      // If component hasn't changed, skip\n      if (this.currentComponentKey === componentKey) return;\n\n      this.showLoader();\n\n      // Remove old component\n      if (this.loadedComponent && this.currentComponentKey) {\n        try {\n          this.removeSummitComponent(this.currentComponentKey);\n        } catch (e) {\n          log('Could not remove old component:', e);\n        }\n      }\n\n      // Load new component\n      try {\n        this.loadedComponent = await this.loadSummitComponent(modelKey, componentKey);\n        this.currentComponentKey = componentKey;\n      \n        // Clear floor mesh cache so floor detection re-scans the new component\n        this.floorMeshCache = {};\n        \n        log(`Summit-608 Configurator: Updated component to ${componentKey}`);\n        \n        // Re-initialize default materials for the new component (glass, metal, etc.)\n        try {\n          await this.materialManager.initializeDefaultMaterials();\n        } catch (e) {\n          log('Could not initialize materials for new component:', e);\n        }\n        \n        // Reapply cached configurations (including siding and floor) to the new component\n        this.reapplyCachedConfigurations();\n        \n        // Reload furniture if bath options changed (Summit 800 models)\n        const legacyModelConfig = this.configData.models?.[modelKey];\n        const furnitureFiles = legacyModelConfig?.modelFiles?.furniture;\n        if (furnitureFiles && !furnitureFiles.obj) {\n          // Remove old furniture\n          if (this.loadedFurniture) {\n            this.sceneManager?.scene?.remove(this.loadedFurniture);\n            this.loadedFurniture.traverse?.((child) => {\n              child.geometry?.dispose?.();\n              if (Array.isArray(child.material)) {\n                child.material.forEach(mat => mat?.dispose?.());\n              } else {\n                child.material?.dispose?.();\n              }\n            });\n            this.loadedFurniture = null;\n          }\n          \n          // Load new furniture based on current bath option\n          const bathOption = this.componentOptionValues.bathOptions || \n                            this.configData.defaultConfiguration?.bathOptions || 'single-bathroom';\n          const furnitureEntry = furnitureFiles[bathOption];\n          if (furnitureEntry) {\n            try {\n              const furnitureUrl = furnitureEntry.obj || furnitureEntry;\n              if (furnitureUrl) {\n                const furniture = await this.modelLoader.loadObjWithMtl(furnitureUrl, null);\n                if (furniture) {\n                  if (typeof this.modelLoader.registerMeshes === 'function') {\n                    this.modelLoader.registerMeshes(furniture, `furniture_`);\n                  }\n                  this.sceneManager?.scene?.add(furniture);\n                  this.loadedFurniture = furniture;\n                  log(`Summit-608 Configurator: Furniture reloaded for ${bathOption}`);\n                }\n              }\n            } catch (e) {\n              log(`Could not reload furniture for ${bathOption}:`, e);\n            }\n          }\n        }\n      } catch (e) {\n        log(`Summit-608 Configurator: Could not load component ${componentKey}:`, e);\n        this.loadedComponent = null;\n      } finally {\n        this.hideLoader();\n      }\n    }\n    \n    // Common post-update for both modes: reapply materials and cached configs\n    if (hasDefaultComponent) {\n      // Clear floor mesh cache\n      this.floorMeshCache = {};\n      \n      // Re-initialize default materials\n      try {\n        await this.materialManager.initializeDefaultMaterials();\n      } catch (e) {\n        log('Could not initialize materials for new side component:', e);\n      }\n      \n      // Reapply cached configurations\n      this.reapplyCachedConfigurations();\n      \n      this.hideLoader();\n    }\n  }\n\n  /**\n   * Handle interiorOptions change (shell-only vs lifestyle).\n   * Mirrors Bliss/Harp behavior: toggle the lifestyle mesh group and floor.\n   */\n  handleInteriorOptionsChange(config) {\n    const value = config.value || 'lifestyle-adu';\n    const isShellOnly = /shell[-_]?only/i.test(value);\n\n    // Toggle interior kit mesh groups (mirrors Bliss setSummitNxInteriorKit)\n    const interiorKitGroups = [\n      'fixture', 'sheathing', 'counter', 'countertop', 'cabinet',\n      'white', 'black', 'appliance', 'shower_door_glass',\n      'shower_door_trim', 'mirror', 'bathroom_floor', 'drywall', 'lifestyle',\n      'furniture', 'G_1_furniture', 'G_2_furniture', 'couch'\n    ];\n    interiorKitGroups.forEach(group => {\n      this.modelLoader.setGroupVisibility(group, !isShellOnly);\n    });\n\n    // Also toggle in separately-stored components that ModelLoader doesn't track\n    const separateComponents = [\n      this.loadedComponent, this.loadedDefaultComponent, this.loadedSideComponent, this.loadedFurniture\n    ].filter(Boolean);\n    separateComponents.forEach(component => {\n      component.traverse(child => {\n        if (child.isMesh && child.name) {\n          const matches = interiorKitGroups.some(group => {\n            return child.name.includes(group) || new RegExp(group.replace(/[-_]/g, '[-_]?'), 'i').test(child.name);\n          });\n          if (matches) {\n            child.visible = !isShellOnly;\n          }\n        }\n      });\n    });\n\n    // Hide/show furniture object directly\n    if (this.loadedFurniture) {\n      this.loadedFurniture.visible = !isShellOnly;\n    }\n\n    // Sheathing stays visible in shell-only (plywood between studs and siding)\n    if (isShellOnly) {\n      this.modelLoader.setGroupVisibility('sheathing', true);\n    }\n\n    const concreteUrl = this.configData?.textures?.concrete ||\n                       'https://cdn.shopify.com/s/files/1/0969/5304/1190/files/concrete.jpg?v=1764337343';\n    if (isShellOnly) {\n      this.materialManager.applyTextureToGroups(\n        ['main_floor', 'flooring', 'floor'], concreteUrl,\n        { textureScale: { uScale: 1, vScale: 1 } }\n      );\n      if (this.sceneManager?.setGroundMaterial) {\n        this.materialManager.createTexturedMaterial(concreteUrl, {\n          roughness: 0.9, metalness: 0.0, textureScale: { uScale: 1, vScale: 1 }\n        }).then(mat => this.sceneManager.setGroundMaterial(mat));\n      }\n      if (this.floorPlane) {\n        this.materialManager.createTexturedMaterial(concreteUrl, {\n          roughness: 0.9, metalness: 0.0, textureScale: { uScale: 4, vScale: 4 }\n        }).then(mat => { this.floorPlane.material = mat; });\n      }\n    } else {\n      const mainFloor = this.configData?.defaultConfiguration?.mainFloorFinish || 'ashlar-oak';\n      const bathFloor = this.configData?.defaultConfiguration?.bathFloorFinish || 'ice-fog';\n      if (this.materialManager?.applyMainFloorFinish) this.materialManager.applyMainFloorFinish(mainFloor);\n      if (this.materialManager?.applyBathFloorFinish) this.materialManager.applyBathFloorFinish(bathFloor);\n    }\n  }\n\n  setViewForStep(step) {\n    this.currentStep = step;\n    const isTopDown = step === 1;\n\n    this.modelLoader.setRoofVisible(!isTopDown);\n    if (isTopDown) {\n      this.cameraControls.setTopDownView();\n    } else {\n      this.cameraControls.setFrontView();\n    }\n  }\n\n  focusOnMeshGroups(meshGroups, animate = true) {\n    if (!meshGroups?.length) return;\n\n    const meshes = meshGroups.flatMap(group => this.modelLoader?.getMeshesByGroup(group) || []);\n    if (meshes.length && this.sceneManager?.focusOnMeshes) {\n      this.sceneManager.focusOnMeshes(meshes, animate);\n    }\n  }\n\n  updateConfiguration(config) {\n    console.log('updateConfiguration received:', config);\n    if (!this.isInitialized) {\n      console.log('updateConfiguration - not initialized, returning');\n      return;\n    }\n\n    log('updateConfiguration:', config.section, config.value);\n\n    const sectionBase = config.section?.includes('.') ? config.section.split('.')[0] : config.section;\n    console.log('updateConfiguration - sectionBase:', sectionBase);\n\n    // Handle orientation change\n    if (sectionBase === 'orientation') {\n      if (config.value && config.value !== this.currentOrientation && !this.isLoading) {\n        this.container.dispatchEvent(new CustomEvent('configurator:modelLoading', { detail: { orientation: config.value } }));\n        this.loadModel(config.value);\n      }\n      return;\n    }\n\n    // Handle interiorOptions (shell-only vs lifestyle) \u2014 toggle lifestyle meshes + floor.\n    if (sectionBase === 'interiorOptions') {\n      this.handleInteriorOptionsChange(config);\n      if (this.isComponentOption(sectionBase)) {\n        this.handleComponentChange(config);\n      }\n      return;\n    }\n\n    // Handle component option changes (entryLocation, windowOptions, sideOptions, etc.)\n    console.log(`updateConfiguration - checking if \"${sectionBase}\" is a component option...`);\n    if (this.isComponentOption(sectionBase)) {\n      console.log(`updateConfiguration - \"${sectionBase}\" IS a component option, calling handleComponentChange`);\n      this.handleComponentChange(config);\n      return;\n    }\n    console.log(`updateConfiguration - \"${sectionBase}\" is NOT a component option, continuing to other handlers`);\n\n    this.cachedConfigurations[config.section] = { ...config };\n    this.executeConfiguration(config);\n  }\n\n  // ============================================================================\n  // CONSOLIDATED HANDLERS\n  // ============================================================================\n\n  /**\n   * Handle visibility changes (layout, kitchen, exterior, elevations, sideOptions, etc.)\n   * Pattern: Hide all other options, show selected option\n   */\n  handleVisibilityChange(config) {\n    console.log(`[Visibility Change] Section: ${config.section}, Value: ${config.value}`);\n    \n    const sectionBase = config.section?.includes('.') ? config.section.split('.')[0] : config.section;\n    const selectedOption = config.allOptions?.find(opt => opt.value === config.value);\n    console.log(`[Visibility Change] Selected option:`, selectedOption);\n    console.log(`[Visibility Change] All options count:`, config.allOptions?.length || 0);\n\n    // For entry/door options, use special handling for models with defaultComponents\n    const isDoorOption = ['sideOptions', 'frontOptions', 'entryOptions', 'entryLocation', 'windowOptions', 'bathOptions'].includes(sectionBase);\n    const usesDefaultComponents = this.hasDefaultComponents();\n    \n    if (isDoorOption && usesDefaultComponents) {\n      console.log(`[Visibility Change] Using door option handler for defaultComponents model`);\n      this.handleDoorOptionChange(config);\n      return;\n    }\n\n    // Hide disabled groups or all other options' groups\n    if (selectedOption?.meshGroups?.disabled) {\n      console.log(`[Visibility Change] Hiding disabled groups:`, selectedOption.meshGroups.disabled);\n      selectedOption.meshGroups.disabled.forEach(group => {\n        this.modelLoader.setGroupVisibility(group, false);\n      });\n    } else if (config.allOptions) {\n      config.allOptions.forEach(option => {\n        if (option.value !== config.value) {\n          const groupsToHide = getMeshGroups(option.meshGroups);\n          if (groupsToHide.length > 0) {\n            console.log(`[Visibility Change] Hiding groups for \"${option.value}\":`, groupsToHide);\n          }\n          groupsToHide.forEach(group => {\n            this.modelLoader.setGroupVisibility(group, false);\n          });\n        }\n      });\n    }\n\n    // Show selected option\n    const groupsToShow = selectedOption?.meshGroups?.enabled || getMeshGroups(config.meshGroups);\n    console.log(`[Visibility Change] Groups to show:`, groupsToShow);\n    groupsToShow.forEach(group => {\n      const count = this.modelLoader.setGroupVisibility(group, true);\n      console.log(`[Visibility Change] Showed group \"${group}\": ${count} meshes`);\n    });\n\n    // Track layout for floor textures\n    if (config.section === 'layout') {\n      this.currentLayout = config.value || this.currentLayout;\n      this.floorMeshCache = {};\n\n      if (this.currentFloorConfig) {\n        this.applyFloorTexture(this.currentFloorConfig);\n      }\n    }\n  }\n\n  /**\n   * Check if current model uses ONLY defaultComponents (fixed component, no component swapping)\n   * Returns false if model has a components mapping (meaning component swapping is supported)\n   */\n  hasDefaultComponents() {\n    const modelKey = this.currentModelKey || this.configData.defaultConfiguration?.model;\n    const modelConfig = this.configData.models?.[modelKey];\n    const defaultComponents = modelConfig?.modelFiles?.defaultComponents || this.configData.defaultComponents;\n    const hasComponentMapping = modelConfig?.modelFiles?.components && Object.keys(modelConfig.modelFiles.components).length > 0;\n    \n    // Only return true if model has defaultComponents AND no components mapping\n    // If both exist, component swapping is possible\n    return !!(defaultComponents?.obj) && !hasComponentMapping;\n  }\n\n  /**\n   * Handle door/entry option changes for models with defaultComponents\n   * These models have fixed components, so we toggle mesh visibility instead of loading different components\n   * All meshGroups must be defined in the JSON configuration\n   */\n  handleDoorOptionChange(config) {\n    const value = config.value;\n    const selectedOption = config.allOptions?.find(opt => opt.value === value);\n    \n    console.log(`[Door Option] Section: ${config.section}, Value: ${value}`);\n    console.log(`[Door Option] Selected option:`, selectedOption);\n    \n    // Debug: Log all meshes in the model for troubleshooting\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    const meshNames = allMeshes.map(m => m.name).filter(Boolean);\n    console.log(`[Door Option] Total meshes in model: ${allMeshes.length}`);\n    console.log(`[Door Option] All mesh names:`, meshNames.slice(0, 50));\n    \n    // Use meshGroups from the selected option (must be defined in JSON)\n    if (selectedOption?.meshGroups?.enabled || selectedOption?.meshGroups?.disabled) {\n      console.log(`[Door Option] Using meshGroups from config`);\n      \n      // Hide disabled groups\n      if (selectedOption.meshGroups.disabled) {\n        selectedOption.meshGroups.disabled.forEach(group => {\n          const count = this.modelLoader.setGroupVisibility(group, false);\n          console.log(`[Door Option] Hid group \"${group}\": ${count} meshes`);\n        });\n      }\n      \n      // Show enabled groups\n      if (selectedOption.meshGroups.enabled) {\n        selectedOption.meshGroups.enabled.forEach(group => {\n          const count = this.modelLoader.setGroupVisibility(group, true);\n          console.log(`[Door Option] Showed group \"${group}\": ${count} meshes`);\n        });\n      }\n      return;\n    }\n    \n    // Alternative: Hide all other options' meshGroups, show selected option's meshGroups\n    if (config.allOptions) {\n      config.allOptions.forEach(option => {\n        const groups = getMeshGroups(option.meshGroups);\n        const shouldShow = option.value === value;\n        groups.forEach(group => {\n          const count = this.modelLoader.setGroupVisibility(group, shouldShow);\n          if (count > 0) {\n            console.log(`[Door Option] ${shouldShow ? 'Showed' : 'Hid'} group \"${group}\": ${count} meshes`);\n          }\n        });\n      });\n      return;\n    }\n    \n    // No meshGroups defined - log warning\n    console.warn(`[Door Option] No meshGroups defined in JSON for section \"${config.section}\". Please add meshGroups to the option configuration.`);\n  }\n\n  /**\n   * Handle color changes (siding, trim, door, soffit, fascia, eaves)\n   */\n  handleColorChange(config) {\n    const meshGroups = getMeshGroups(config.meshGroups);\n    if (meshGroups.length && config.hex) {\n      this.materialManager.applyColorToGroups(meshGroups, config.hex);\n    }\n\n    // Window casement color \u2014 derived from trim color selection.\n    const sectionBase = config.section?.includes('.') ? config.section.split('.')[0] : config.section;\n    if (sectionBase === 'trimColor') {\n      const WINDOW_CASEMENT_MAP = {\n        'aluminum':           '#8C826E',  // Pebble Gray \u2014 warm gray for CA trim\n        'studio-shed-bronze': '#202021',  // Ebony \u2014 near-black for bronze trim\n      };\n      const casementColor = WINDOW_CASEMENT_MAP[config.value];\n      if (casementColor && this.materialManager) {\n        this.materialManager.applyColorToGroups(['window_exterior'], casementColor, { roughness: 0.45, metalness: 0.35 });\n      }\n    }\n  }\n\n  /**\n   * Handle texture changes (bath floor, counter)\n   */\n  handleTextureChange(config) {\n    if (config.texture && config.meshGroups?.length) {\n      this.materialManager.applyTextureToGroups(config.meshGroups, config.texture, {\n        textureScale: config.textureScale\n      });\n    }\n  }\n\n  /**\n   * Handle metal finish changes (fixtures)\n   */\n  handleMetalFinishChange(config) {\n    if (config.hex && config.meshGroups?.length) {\n      this.materialManager.applyColorToGroups(config.meshGroups, config.hex, {\n        metalness: config.metalness ?? 0.8,\n        roughness: config.roughness ?? 0.2\n      });\n    } else if (this.materialManager.applyFixtureFinish) {\n      this.materialManager.applyFixtureFinish(config.value);\n    }\n  }\n\n  /**\n   * Handle cabinet finish changes (hex color or texture)\n   */\n  handleCabinetChange(config) {\n    if (config.hex && config.meshGroups?.length) {\n      this.materialManager.applyColorToGroups(config.meshGroups, config.hex);\n    } else if (config.texture && config.meshGroups?.length) {\n      this.materialManager.applyTextureToGroups(config.meshGroups, config.texture, {\n        textureScale: config.textureScale\n      });\n    } else if (this.materialManager.applyCabinetFinish) {\n      this.materialManager.applyCabinetFinish(config.value);\n    }\n  }\n\n  /**\n   * Siding mesh configurations - defines which meshes to show/hide and how to style them\n   * Based on reference implementation from other models (Signature, Aspect)\n   */\n  static SIDING_CONFIG = {\n    'lap': {\n      meshGroups: ['wood_texture', 'wood_texture_trims', 'accent_color'],\n      metalMeshGroups: ['wood_texture_metal', 'wood_texture_metal_trims'],\n      colorMeshes: ['wood_texture', 'wood_texture_metal'],\n      trimMeshes: ['wood_texture_trims', 'wood_texture_metal_trims'],\n      hasTexture: true,\n      textureKey: 'base-lap',\n      textureUrl: 'https://cdn.shopify.com/s/files/1/0969/5304/1190/files/base_lap.png',\n      textureScale: { u: 1, v: 0.142 },  // Horizontal boards - like Signature\n      usesSidingColor: true\n    },\n    'plank': {\n      meshGroups: ['plank_siding', 'plank_siding_color', 'plank_trims', 'plank_trim', 'plank_siding_trims'],\n      metalMeshGroups: ['plank_siding_metal', 'plank_siding_metal_color', 'plank_siding_metal_trims'],\n      colorMeshes: ['plank_siding_color', 'plank_siding', 'plank_siding_metal', 'plank_siding_metal_color'],\n      trimMeshes: ['plank_siding_trims', 'plank_siding_metal_trims', 'plank_trims', 'plank_trim'],\n      hasTexture: false,  // Plank uses solid color like Signature (no texture)\n      usesSidingColor: true\n    },\n    'block': {\n      meshGroups: ['block_siding', 'block_siding_color', 'block_siding_fastener', 'block_siding_trims'],\n      metalMeshGroups: ['block_siding_metal', 'block_siding_metal_color', 'block_siding_metal_fastener', 'block_siding_metal_trims'],\n      colorMeshes: ['block_siding_color', 'block_siding_metal_color'],\n      trimMeshes: ['block_siding_trims', 'block_siding_metal_trims'],\n      fastenerMeshes: ['block_siding_fastener', 'block_siding_metal_fastener'],\n      hasTexture: false,\n      usesSidingColor: true,\n      applianceColor: '#C0C0C0' // For fasteners\n    },\n    'cedar-plank': {\n      meshGroups: ['wood_texture', 'wood_texture_trims'],\n      metalMeshGroups: ['wood_texture_metal', 'wood_texture_metal_trims'],\n      colorMeshes: ['wood_texture', 'wood_texture_metal'],\n      trimMeshes: ['wood_texture_trims', 'wood_texture_metal_trims'],\n      hasTexture: true,\n      textureKey: 'cedar-plank',\n      textureUrl: 'https://cdn.shopify.com/s/files/1/0969/5304/1190/files/cedar-plank.jpg',\n      textureScale: { u: 0.0075, v: 0.05 },\n      usesSidingColor: false,\n      baseColor: '#FFFFFF'\n    },\n    'cedar-shake': {\n      meshGroups: ['wood_texture', 'wood_texture_trims'],\n      metalMeshGroups: ['wood_texture_metal', 'wood_texture_metal_trims'],\n      colorMeshes: ['wood_texture', 'wood_texture_metal'],\n      trimMeshes: ['wood_texture_trims', 'wood_texture_metal_trims'],\n      hasTexture: true,\n      textureKey: 'cedar-shake',\n      textureUrl: 'https://cdn.shopify.com/s/files/1/0969/5304/1190/files/cedar-shake.jpg?v=1764337343',\n      textureScale: { u: 0.05, v: 0.035 },\n      usesSidingColor: false,\n      baseColor: '#FFFFFF'\n    }\n  };\n\n  // All possible siding mesh groups (for hiding when switching types)\n  static ALL_SIDING_MESHES = [\n    'plank_siding', 'plank_siding_color', 'plank_trims', 'plank_trim', 'plank_siding_trims',\n    'plank_siding_metal', 'plank_siding_metal_color', 'plank_siding_metal_trims',\n    'wood_texture', 'wood_texture_trims', 'wood_texture_metal', 'wood_texture_metal_trims',\n    'block_siding', 'block_siding_color', 'block_siding_fastener', 'block_siding_trims',\n    'block_siding_metal', 'block_siding_metal_color', 'block_siding_metal_fastener', 'block_siding_metal_trims',\n    'accent_color'\n  ];\n\n  /**\n   * Handle siding type change - manages mesh visibility and applies textures/colors\n   * Following the reference implementation pattern\n   */\n  async handleSidingTypeChange(config) {\n    const defaults = this.configData?.defaultConfiguration || {};\n    const sidingType = config.value || defaults.siding || 'lap';\n    const sidingColor = this.cachedConfigurations?.sidingColor?.value || defaults.sidingColor || 'iron-gray';\n    const hasMetalWainscot = this.cachedConfigurations?.exteriorAddon?.value === 'metal-wainscot' ||\n                            this.currentConfig?.exteriorAddon === 'metal-wainscot';\n    \n    console.log(`[Summit Siding] ===== handleSidingTypeChange =====`);\n    console.log(`[Summit Siding] Type: ${sidingType}, Color: ${sidingColor}, Metal Wainscot: ${hasMetalWainscot}`);\n    \n    // Debug: Log all available meshes\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    console.log(`[Summit Siding] Total meshes available: ${allMeshes.length}`);\n    \n    if (allMeshes.length === 0) {\n      console.warn(`[Summit Siding] WARNING: No meshes found! Check if model is loaded.`);\n      return;\n    }\n    \n    // Get siding configuration\n    const sidingConfig = Summit608Configurator3D.SIDING_CONFIG[sidingType] || Summit608Configurator3D.SIDING_CONFIG['lap'];\n    console.log(`[Summit Siding] Config for \"${sidingType}\":`, {\n      meshGroups: sidingConfig.meshGroups,\n      metalMeshGroups: sidingConfig.metalMeshGroups,\n      hasTexture: sidingConfig.hasTexture,\n      usesSidingColor: sidingConfig.usesSidingColor\n    });\n    \n    // Determine which mesh patterns to enable\n    const meshesToEnable = hasMetalWainscot \n      ? (sidingConfig.metalMeshGroups || [])\n      : (sidingConfig.meshGroups || []);\n    \n    // STEP 1: Disable ALL siding meshes first\n    let disabledCount = 0;\n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      const isSidingMesh = Summit608Configurator3D.ALL_SIDING_MESHES.some(pattern => \n        nameLower.includes(pattern.toLowerCase())\n      );\n      if (isSidingMesh) {\n        mesh.visible = false;\n        disabledCount++;\n      }\n    });\n    console.log(`[Summit Siding] Step 1: Disabled ${disabledCount} siding meshes`);\n    \n    // STEP 2: Enable appropriate meshes using EXCLUSIVE matching (like Signature)\n    // This prevents z-fighting between standard and metal meshes\n    let enabledCount = 0;\n    const colorMeshes = [];\n    const trimMeshes = [];\n    const fastenerMeshes = [];\n    const enabledMeshNames = [];\n    \n    const colorMeshPatterns = sidingConfig.colorMeshes || meshesToEnable;\n    const trimMeshPatterns = sidingConfig.trimMeshes || ['_trims', '_trim'];\n    const fastenerMeshPatterns = sidingConfig.fastenerMeshes || [];\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      // EXCLUSIVE MESH MATCHING (from Signature):\n      // Problem: 'wood_texture_metal'.includes('wood_texture') = true, causing both to be enabled\n      // Solution: In standard mode, exclude meshes with '_metal'; in metal mode, require '_metal'\n      const isMetalMesh = nameLower.includes('_metal');\n      let shouldEnable = false;\n      \n      if (hasMetalWainscot) {\n        // Metal mode: only enable meshes that contain '_metal' AND match the pattern\n        shouldEnable = isMetalMesh && meshesToEnable.some(pattern => \n          nameLower.includes(pattern.toLowerCase())\n        );\n      } else {\n        // Standard mode: only enable meshes that do NOT contain '_metal' AND match the pattern\n        shouldEnable = !isMetalMesh && meshesToEnable.some(pattern => \n          nameLower.includes(pattern.toLowerCase())\n        );\n      }\n      \n      if (shouldEnable) {\n        mesh.visible = true;\n        enabledCount++;\n        enabledMeshNames.push(mesh.name);\n        \n        // Categorize mesh for material application\n        const isTrimMesh = trimMeshPatterns.some(p => nameLower.includes(p.toLowerCase()));\n        const isFastenerMesh = fastenerMeshPatterns.some(p => nameLower.includes(p.toLowerCase()));\n        \n        if (isTrimMesh) {\n          trimMeshes.push(mesh);\n        } else if (isFastenerMesh) {\n          fastenerMeshes.push(mesh);\n        } else {\n          colorMeshes.push(mesh);\n        }\n      }\n    });\n    \n    console.log(`[Summit Siding] Step 2: Enabled ${enabledCount} meshes (color: ${colorMeshes.length}, trim: ${trimMeshes.length}, fastener: ${fastenerMeshes.length})`);\n    console.log(`[Summit Siding] Enabled mesh names:`, enabledMeshNames.slice(0, 10));\n    \n    // STEP 3: Get color to apply - prefer cached hex value (preserves user's selection)\n    const cachedSidingColor = this.cachedConfigurations?.sidingColor;\n    const hexColor = cachedSidingColor?.hex || this.getSidingColorHex(sidingColor);\n    const colorToUse = sidingConfig.usesSidingColor ? hexColor : (sidingConfig.baseColor || '#FFFFFF');\n    console.log(`[Summit Siding] Step 3: Color to apply: ${colorToUse} (cached hex: ${!!cachedSidingColor?.hex})`);\n    \n    // STEP 4: Apply texture or color to collected meshes\n    if (sidingConfig.hasTexture && sidingConfig.textureUrl) {\n      console.log(`[Summit Siding] Step 4: Applying texture with color tint`);\n      await this.applySidingTextureToMeshes(colorMeshes, sidingConfig, colorToUse);\n    } else {\n      console.log(`[Summit Siding] Step 4: Applying solid color`);\n      this.applySidingColorToMeshes(colorMeshes, colorToUse);\n    }\n    \n    // STEP 5: Apply trim color - use cached hex value if available (preserves user's selection)\n    if (trimMeshes.length > 0) {\n      const cachedTrim = this.cachedConfigurations?.trimColor;\n      // Prefer cached hex value (from user's selection), then lookup by value, then default\n      const trimHex = cachedTrim?.hex || \n                      this.getColorHex('trimColor', cachedTrim?.value || defaults.trimColor || 'white');\n      this.applySidingColorToMeshes(trimMeshes, trimHex);\n      console.log(`[Summit Siding] Step 5: Applied trim color ${trimHex} (cached: ${!!cachedTrim?.hex}) to ${trimMeshes.length} meshes`);\n    }\n    \n    // STEP 6: Handle fasteners (block siding)\n    if (fastenerMeshes.length > 0 && sidingConfig.applianceColor) {\n      this.applySidingColorToMeshes(fastenerMeshes, sidingConfig.applianceColor);\n      console.log(`[Summit Siding] Step 6: Applied fastener color to ${fastenerMeshes.length} meshes`);\n    }\n    \n    // Store current siding type for color change handling\n    this.currentSidingType = sidingType;\n    \n    // Force render update\n    if (this.sceneManager?.renderer) {\n      this.sceneManager.renderer.render(this.sceneManager.scene, this.sceneManager.camera);\n    }\n    \n    console.log(`[Summit Siding] \u2705 Completed ${sidingType} siding with color ${colorToUse}`);\n    console.log(`[Summit Siding] =====================================`);\n  }\n  \n  /**\n   * Apply siding texture directly to mesh objects (like Signature)\n   */\n  async applySidingTextureToMeshes(meshes, sidingConfig, tintColor) {\n    if (!meshes || meshes.length === 0) {\n      console.warn('[Summit Siding] No meshes to apply texture to');\n      return;\n    }\n    \n    const textureUrl = this.configData?.textures?.[sidingConfig.textureKey] || sidingConfig.textureUrl;\n    \n    if (!textureUrl) {\n      console.warn(`[Summit Siding] No texture URL for ${sidingConfig.textureKey}, using color only`);\n      this.applySidingColorToMeshes(meshes, tintColor);\n      return;\n    }\n    \n    console.log(`[Summit Siding] Loading texture: ${textureUrl}`);\n    \n    try {\n      const textureLoader = new THREE.TextureLoader();\n      const texture = await new Promise((resolve, reject) => {\n        textureLoader.load(textureUrl, resolve, undefined, reject);\n      });\n      \n      // Configure texture (matching Signature's approach)\n      texture.colorSpace = THREE.SRGBColorSpace;\n      texture.wrapS = THREE.RepeatWrapping;\n      texture.wrapT = THREE.RepeatWrapping;\n      \n      if (sidingConfig.textureScale) {\n        const uScale = sidingConfig.textureScale.u ?? sidingConfig.textureScale.uScale ?? 1;\n        const vScale = sidingConfig.textureScale.v ?? sidingConfig.textureScale.vScale ?? 1;\n        texture.repeat.set(uScale, vScale);\n      }\n      texture.needsUpdate = true;\n      \n      console.log(`[Summit Siding] Texture loaded, applying to ${meshes.length} meshes with tint ${tintColor}`);\n      \n      // Apply to each mesh\n      meshes.forEach(mesh => {\n        const newMaterial = new THREE.MeshStandardMaterial({\n          map: texture,\n          color: new THREE.Color(tintColor),\n          roughness: 0.8,\n          metalness: 0.0,\n          side: THREE.DoubleSide,\n          transparent: false,\n          opacity: 1.0\n        });\n        \n        mesh.material = newMaterial;\n        mesh.material.needsUpdate = true;\n        mesh.visible = true;\n      });\n      \n      console.log(`[Summit Siding] \u2713 Texture applied to ${meshes.length} meshes`);\n    } catch (err) {\n      console.warn(`[Summit Siding] Failed to load texture: ${textureUrl}`, err);\n      this.applySidingColorToMeshes(meshes, tintColor);\n    }\n  }\n  \n  /**\n   * Apply solid color directly to mesh objects\n   */\n  applySidingColorToMeshes(meshes, hexColor) {\n    if (!meshes || meshes.length === 0) return;\n    \n    const colorObj = new THREE.Color(hexColor);\n    const material = new THREE.MeshStandardMaterial({\n      color: colorObj,\n      roughness: 0.8,\n      metalness: 0.1,\n      side: THREE.DoubleSide,\n      visible: true\n    });\n    \n    meshes.forEach(mesh => {\n      mesh.material = material.clone();\n      mesh.material.needsUpdate = true;\n      mesh.visible = true;\n    });\n  }\n\n  /**\n   * Handle siding color change - applies color to visible siding meshes\n   * Uses exclusive mesh matching like Signature\n   */\n  async handleSidingColorChange(config) {\n    const defaults = this.configData?.defaultConfiguration || {};\n    const sidingType = this.currentSidingType || this.cachedConfigurations?.siding?.value || defaults.siding || 'lap';\n    \n    // CRITICAL: Check if metal wainscot is enabled\n    const hasMetalWainscot = this.cachedConfigurations?.exteriorAddon?.value === 'metal-wainscot' ||\n                            this.currentConfig?.exteriorAddon === 'metal-wainscot';\n    \n    // Get hex color - try config.hex first, then look up by value\n    let hexColor = config.hex;\n    if (!hexColor && config.value) {\n      hexColor = this.getSidingColorHex(config.value);\n    }\n    if (!hexColor) {\n      hexColor = '#525654'; // Default iron-gray\n    }\n    \n    console.log(`[Summit Siding] ===== handleSidingColorChange =====`);\n    console.log(`[Summit Siding] Type: ${sidingType}, Color: ${config.value}, Hex: ${hexColor}, Metal Wainscot: ${hasMetalWainscot}`);\n    \n    // Get siding config\n    const sidingConfig = Summit608Configurator3D.SIDING_CONFIG[sidingType] || Summit608Configurator3D.SIDING_CONFIG['lap'];\n    \n    // Cedar types don't use siding color - they have a fixed base color\n    if (!sidingConfig.usesSidingColor) {\n      console.log(`[Summit Siding] Type \"${sidingType}\" uses fixed base color, ignoring color change`);\n      return;\n    }\n    \n    // Get meshes to apply color to using exclusive matching\n    const meshesToEnable = hasMetalWainscot \n      ? (sidingConfig.metalMeshGroups || [])\n      : (sidingConfig.meshGroups || []);\n    \n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    const colorMeshes = [];\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      // Skip trim and fastener meshes - only apply to color meshes\n      if (nameLower.includes('_trim') || nameLower.includes('fastener')) return;\n      \n      // Use exclusive matching\n      const isMetalMesh = nameLower.includes('_metal');\n      let shouldApply = false;\n      \n      if (hasMetalWainscot) {\n        shouldApply = isMetalMesh && meshesToEnable.some(pattern => \n          nameLower.includes(pattern.toLowerCase())\n        );\n      } else {\n        shouldApply = !isMetalMesh && meshesToEnable.some(pattern => \n          nameLower.includes(pattern.toLowerCase())\n        );\n      }\n      \n      if (shouldApply && mesh.visible) {\n        colorMeshes.push(mesh);\n      }\n    });\n    \n    console.log(`[Summit Siding] Found ${colorMeshes.length} visible color meshes to update`);\n    \n    // Apply color based on siding type\n    if (sidingConfig.hasTexture && sidingConfig.textureUrl) {\n      console.log(`[Summit Siding] Applying texture with new color tint`);\n      await this.applySidingTextureToMeshes(colorMeshes, sidingConfig, hexColor);\n    } else {\n      console.log(`[Summit Siding] Applying solid color`);\n      this.applySidingColorToMeshes(colorMeshes, hexColor);\n    }\n    \n    // CRITICAL: Re-apply wainscot visibility after color change\n    if (hasMetalWainscot) {\n      await this.reapplyWainscotVisibility();\n    }\n    \n    // Force render update\n    if (this.sceneManager?.renderer) {\n      this.sceneManager.renderer.render(this.sceneManager.scene, this.sceneManager.camera);\n    }\n    \n    console.log(`[Summit Siding] \u2705 Applied color ${hexColor} to ${sidingType} siding`);\n    console.log(`[Summit Siding] =====================================`);\n  }\n\n  /**\n   * Get siding color hex value from color name\n   */\n  getSidingColorHex(colorName) {\n    if (!colorName) return '#525654';\n    \n    // Try to find color in sidingColor section\n    for (const step of (this.configData?.steps || [])) {\n      const options = step.options || {};\n      \n      // Check sidingColor section\n      const sidingColorSection = options.sidingColor || options['sidingColor.main'];\n      if (sidingColorSection) {\n        const colorOptions = sidingColorSection.options || sidingColorSection.choices || [];\n        const colorOption = colorOptions.find(c => c.value === colorName);\n        if (colorOption?.hex) {\n          return colorOption.hex;\n        }\n      }\n      \n      // Check all sections for color options\n      for (const sectionData of Object.values(options)) {\n        if (sectionData?.options || sectionData?.choices) {\n          const colorOptions = sectionData.options || sectionData.choices || [];\n          const colorOption = colorOptions.find(c => c.value === colorName);\n          if (colorOption?.hex) {\n            return colorOption.hex;\n          }\n        }\n      }\n    }\n    \n    // Check colorsData\n    if (this.configData?.colors?.[colorName]) {\n      return this.configData.colors[colorName];\n    }\n    \n    // Fallback color map for common siding colors\n    const colorMap = {\n      'iron-gray': '#525654',\n      'iron-grey': '#525654',\n      'mountain-blue': '#4A5568',\n      'forest-green': '#2D5A27',\n      'desert-tan': '#C9B896',\n      'charcoal': '#36454F',\n      'slate-gray': '#708090',\n      'slate-grey': '#708090',\n      'white': '#FFFFFF',\n      'aluminum': '#D3D3D3',\n      'black': '#000000',\n      'bronze': '#8B4513',\n      'clay': '#B66A50',\n      'sandstone': '#786D5F'\n    };\n    \n    return colorMap[colorName.toLowerCase()] || '#525654';\n  }\n\n  /**\n   * Get color hex value from color name for a specific color type\n   * Used for trim color, door color, etc.\n   */\n  getColorHex(colorType, colorName) {\n    if (!colorName) return '#FFFFFF';\n    \n    // Try to find color in config steps\n    for (const step of (this.configData?.steps || [])) {\n      const options = step.options || {};\n      \n      // Check the specific color type section\n      const colorSection = options[colorType];\n      if (colorSection) {\n        const colorOptions = colorSection.options || colorSection.choices || [];\n        const colorOption = colorOptions.find(c => c.value === colorName);\n        if (colorOption?.hex) {\n          return colorOption.hex;\n        }\n      }\n    }\n    \n    // Check colorsData\n    if (this.configData?.colors?.[colorName]) {\n      return this.configData.colors[colorName];\n    }\n    \n    // Fallback color map for common colors\n    const colorMap = {\n      'white': '#FFFFFF',\n      'aluminum': '#D3D3D3',\n      'black': '#000000',\n      'bronze': '#8B4513',\n      'clay': '#B66A50',\n      'iron-gray': '#525654',\n      'iron-grey': '#525654',\n      'charcoal': '#36454F',\n      'slate-gray': '#708090',\n      'slate-grey': '#708090',\n      'studio-shed-bronze': '#201A18'\n    };\n    \n    return colorMap[colorName.toLowerCase()] || '#FFFFFF';\n  }\n\n  /**\n   * Set visibility for siding mesh groups\n   */\n  setSidingMeshesVisibility(meshPatterns, visible) {\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    let count = 0;\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      const matches = meshPatterns.some(pattern => nameLower.includes(pattern.toLowerCase()));\n      if (matches) {\n        mesh.visible = visible;\n        count++;\n      }\n    });\n    \n    console.log(`[Summit Siding] Set ${count} meshes to visible=${visible} for patterns: ${meshPatterns.slice(0, 3).join(', ')}...`);\n  }\n\n  /**\n   * Apply texture to siding meshes\n   */\n  async applySidingTexture(sidingConfig, tintColor, hasMetalWainscot = false) {\n    const textureUrl = this.configData?.textures?.[sidingConfig.textureKey] || sidingConfig.textureUrl;\n    \n    // Determine which meshes to apply texture to\n    // CRITICAL: When metal wainscot is enabled, use metalMeshGroups instead of meshGroups\n    // This ensures textures are applied to the correct (upper-only) siding meshes\n    let targetMeshes;\n    if (hasMetalWainscot) {\n      // When wainscot is enabled, use metalMeshGroups (upper siding only)\n      targetMeshes = sidingConfig.metalMeshGroups || [];\n    } else {\n      // When wainscot is disabled, use regular meshGroups (full-height siding)\n      // For plank siding, use colorMeshes; otherwise use meshGroups\n      targetMeshes = sidingConfig.colorMeshes || sidingConfig.meshGroups || [];\n    }\n    \n    console.log(`[Summit Siding] Applying texture to meshes (metal wainscot: ${hasMetalWainscot}):`, targetMeshes);\n    \n    if (!textureUrl) {\n      console.warn(`[Summit Siding] No texture URL for ${sidingConfig.textureKey}`);\n      // Fall back to color only\n      this.applySidingColor(targetMeshes, tintColor);\n      return;\n    }\n    \n    try {\n      const textureLoader = new THREE.TextureLoader();\n      const texture = await new Promise((resolve, reject) => {\n        textureLoader.load(textureUrl, resolve, undefined, reject);\n      });\n      \n      // Configure texture\n      texture.wrapS = THREE.RepeatWrapping;\n      texture.wrapT = THREE.RepeatWrapping;\n      if (sidingConfig.textureScale) {\n        // Handle both {u, v} and {uScale, vScale} formats\n        const uScale = sidingConfig.textureScale.u ?? sidingConfig.textureScale.uScale ?? 1;\n        const vScale = sidingConfig.textureScale.v ?? sidingConfig.textureScale.vScale ?? 1;\n        texture.repeat.set(uScale, vScale);\n      }\n      texture.colorSpace = THREE.SRGBColorSpace;\n      texture.needsUpdate = true;\n      \n      // Create material with texture and tint color\n      const sidingMaterial = new THREE.MeshStandardMaterial({\n        map: texture,\n        color: new THREE.Color(tintColor),\n        roughness: 0.8,\n        metalness: 0.0,\n        side: THREE.DoubleSide\n      });\n      \n      // Apply to target meshes\n      this.applyMaterialToMeshGroups(targetMeshes, sidingMaterial);\n      \n      console.log(`[Summit Siding] Applied texture ${sidingConfig.textureKey} with tint ${tintColor}`);\n    } catch (err) {\n      console.warn(`[Summit Siding] Failed to load texture: ${textureUrl}`, err);\n      // Fall back to color only\n      this.applySidingColor(targetMeshes, tintColor);\n    }\n  }\n\n  /**\n   * Apply texture with color tint (for lap siding color changes)\n   */\n  async applySidingTextureWithColor(sidingConfig, hexColor, hasMetalWainscot = false) {\n    // Re-apply texture with new color tint\n    // CRITICAL: Pass hasMetalWainscot to ensure correct meshes are used\n    await this.applySidingTexture(sidingConfig, hexColor, hasMetalWainscot);\n  }\n\n  /**\n   * Re-apply wainscot visibility and properties\n   * Called after siding operations to ensure wainscot remains visible\n   */\n  async reapplyWainscotVisibility() {\n    const hasMetalWainscot = this.cachedConfigurations?.exteriorAddon?.value === 'metal-wainscot' ||\n                            this.currentConfig?.exteriorAddon === 'metal-wainscot';\n    \n    if (!hasMetalWainscot) {\n      return; // Wainscot not enabled, nothing to do\n    }\n    \n    // Get wainscot mesh patterns from config\n    let wainscotMeshPatterns = [];\n    for (const step of (this.configData?.steps || [])) {\n      const exteriorAddonConfig = step.options?.exteriorAddon;\n      if (exteriorAddonConfig) {\n        if (exteriorAddonConfig.meshGroups && Array.isArray(exteriorAddonConfig.meshGroups)) {\n          wainscotMeshPatterns = [...exteriorAddonConfig.meshGroups];\n        }\n        const selectedChoice = (exteriorAddonConfig.choices || []).find(c => c.value === 'metal-wainscot');\n        if (selectedChoice?.meshGroups) {\n          const choiceMeshGroups = selectedChoice.meshGroups.enabled || selectedChoice.meshGroups.disabled || [];\n          if (choiceMeshGroups.length > 0) {\n            wainscotMeshPatterns = [...new Set([...wainscotMeshPatterns, ...choiceMeshGroups])];\n          }\n        }\n        break;\n      }\n    }\n    \n    if (wainscotMeshPatterns.length === 0) {\n      console.warn('[Summit608] No meshGroups found in config for exteriorAddon, using fallback patterns');\n      wainscotMeshPatterns = [\n        'metal_wainscot', 'metal_wainscot1', 'metal_wainscot2', 'metal_wainscot3', 'metal_wainscot4',\n        'wainscot', 'wainscot1', 'wainscot2', 'wainscot3', 'wainscot4',\n        'wainscot_front', 'wainscot_back', 'wainscot_left', 'wainscot_right',\n        'metal_wainscot_front', 'metal_wainscot_back', 'metal_wainscot_left', 'metal_wainscot_right'\n      ];\n    }\n    \n    // Use cached hex value if available (preserves user's selection)\n    const cachedTrim = this.cachedConfigurations?.trimColor;\n    const trimHex = cachedTrim?.hex || \n                    this.getColorHex('trimColor', cachedTrim?.value || this.configData?.defaultConfiguration?.trimColor || 'white');\n    \n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    let reAppliedCount = 0;\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      const isWainscot = wainscotMeshPatterns.some(pattern => nameLower.includes(pattern.toLowerCase()));\n      \n      if (isWainscot) {\n        // Ensure visibility is set\n        if (!mesh.visible) {\n          mesh.visible = true;\n          reAppliedCount++;\n        }\n        \n        // Ensure render order is maintained (render on top of siding)\n        mesh.renderOrder = 1;\n        \n        // Re-apply trim color and material properties\n        if (mesh.material && trimHex) {\n          const color = new THREE.Color(trimHex);\n          if (Array.isArray(mesh.material)) {\n            mesh.material.forEach(m => {\n              if (m.color) m.color = color;\n              if (m.roughness !== undefined) m.roughness = 0.3;\n              if (m.metalness !== undefined) m.metalness = 0.6;\n              if (m.depthTest !== undefined) m.depthTest = true;\n              if (m.depthWrite !== undefined) m.depthWrite = true;\n            });\n          } else {\n            if (mesh.material.color) mesh.material.color = color;\n            if (mesh.material.roughness !== undefined) mesh.material.roughness = 0.3;\n            if (mesh.material.metalness !== undefined) mesh.material.metalness = 0.6;\n            if (mesh.material.depthTest !== undefined) mesh.material.depthTest = true;\n            if (mesh.material.depthWrite !== undefined) mesh.material.depthWrite = true;\n          }\n          mesh.material.needsUpdate = true;\n        }\n        \n        // Ensure parent is visible\n        let parent = mesh.parent;\n        while (parent && parent !== this.sceneManager?.scene) {\n          if (parent.visible === false) {\n            parent.visible = true;\n          }\n          parent = parent.parent;\n        }\n      }\n    });\n    \n    if (reAppliedCount > 0) {\n      console.log(`[Summit608] Re-applied visibility to ${reAppliedCount} wainscot meshes`);\n    }\n    console.log(`[Summit608] Verified all wainscot meshes are visible and properly styled`);\n  }\n\n  /**\n   * Handle addon changes (exteriorAddon, roofAddon)\n   * Dispatches to specific handlers based on addon type\n   */\n  async handleAddonChange(addonType, value) {\n    console.log(`Addon change: ${addonType} -> ${value}`);\n    \n    // Store in cachedConfigurations for persistence\n    this.cachedConfigurations[`${addonType}Addon`] = { \n      section: `${addonType}Addon`, \n      value \n    };\n\n    if (addonType === 'exterior') {\n      await this.handleExteriorAddon(value);\n    } else if (addonType === 'roof') {\n      this.handleRoofAddon(value);\n    }\n  }\n\n  /**\n   * Handle exterior addon (metal wainscot)\n   * Shows/hides wainscot meshes and refreshes siding for standard/metal mesh sets\n   * Now reads meshGroups from JSON config instead of using hardcoded patterns\n   */\n  async handleExteriorAddon(value) {\n    const isMetalWainscot = value === 'metal-wainscot';\n    \n    // Get mesh patterns from config instead of hardcoding\n    let wainscotMeshPatterns = [];\n    \n    // Search through steps to find exteriorAddon config\n    for (const step of (this.configData?.steps || [])) {\n      const exteriorAddonConfig = step.options?.exteriorAddon;\n      if (exteriorAddonConfig) {\n        // Get section-level meshGroups as fallback\n        if (exteriorAddonConfig.meshGroups && Array.isArray(exteriorAddonConfig.meshGroups)) {\n          wainscotMeshPatterns = [...exteriorAddonConfig.meshGroups];\n        }\n        \n        // Find the selected choice and get its meshGroups\n        const selectedChoice = (exteriorAddonConfig.choices || []).find(c => c.value === value);\n        if (selectedChoice?.meshGroups) {\n          const choiceMeshGroups = selectedChoice.meshGroups.enabled || selectedChoice.meshGroups.disabled || [];\n          if (choiceMeshGroups.length > 0) {\n            wainscotMeshPatterns = [...new Set([...wainscotMeshPatterns, ...choiceMeshGroups])];\n          }\n        }\n        break;\n      }\n    }\n    \n    // Fallback to hardcoded patterns if nothing found in config\n    if (wainscotMeshPatterns.length === 0) {\n      console.warn('[Summit608] No meshGroups found in config for exteriorAddon, using fallback patterns');\n      wainscotMeshPatterns = [\n        'metal_wainscot', 'metal_wainscot1', 'metal_wainscot2', 'metal_wainscot3', 'metal_wainscot4',\n        'wainscot', 'wainscot1', 'wainscot2', 'wainscot3', 'wainscot4',\n        'wainscot_front', 'wainscot_back', 'wainscot_left', 'wainscot_right',\n        'metal_wainscot_front', 'metal_wainscot_back', 'metal_wainscot_left', 'metal_wainscot_right'\n      ];\n    }\n    \n    // Get trim color for wainscot (wainscot uses trim color) - use cached hex if available\n    const cachedTrim = this.cachedConfigurations?.trimColor;\n    const trimHex = cachedTrim?.hex || \n                    this.getColorHex('trimColor', cachedTrim?.value || this.configData?.defaultConfiguration?.trimColor || 'white');\n\n    console.log(`[Summit608] Exterior addon: ${value}, wainscot: ${isMetalWainscot}, trimHex: ${trimHex} (cached: ${!!cachedTrim?.hex})`);\n    console.log(`[Summit608] Using meshGroups from config:`, wainscotMeshPatterns);\n\n    // Get all meshes from model loader\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    \n    console.log(`[Summit608] DEBUG - Total meshes in scene: ${allMeshes.length}`);\n    \n    // Look for potential wainscot meshes\n    const wainscotRelatedMeshes = allMeshes.filter(m => {\n      const name = (m.name || '').toLowerCase();\n      return name.includes('wainscot') || name.includes('metal_w');\n    });\n    console.log(`[Summit608] DEBUG - Found ${wainscotRelatedMeshes.length} potential wainscot meshes:`, \n      wainscotRelatedMeshes.map(m => m.name));\n    \n    let toggledCount = 0;\n    const toggledMeshNames = [];\n\n    // Toggle wainscot meshes and apply trim color\n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      // Check if mesh name contains any wainscot pattern from config\n      const isWainscot = wainscotMeshPatterns.some(pattern => nameLower.includes(pattern.toLowerCase()));\n      \n      if (isWainscot) {\n        mesh.visible = isMetalWainscot;\n        \n        // CRITICAL: Set renderOrder so wainscot renders ON TOP of siding meshes\n        if (isMetalWainscot) {\n          mesh.renderOrder = 1; // Render after siding (which defaults to 0)\n          \n          // Ensure proper depth testing for correct rendering\n          if (mesh.material) {\n            if (Array.isArray(mesh.material)) {\n              mesh.material.forEach(m => {\n                if (m.depthTest !== undefined) m.depthTest = true;\n                if (m.depthWrite !== undefined) m.depthWrite = true;\n              });\n            } else {\n              if (mesh.material.depthTest !== undefined) mesh.material.depthTest = true;\n              if (mesh.material.depthWrite !== undefined) mesh.material.depthWrite = true;\n            }\n          }\n        } else {\n          // Reset renderOrder when hiding wainscot\n          mesh.renderOrder = 0;\n        }\n        \n        // CRITICAL: Ensure parent objects are also visible\n        if (isMetalWainscot) {\n          let parent = mesh.parent;\n          while (parent && parent !== this.sceneManager?.scene) {\n            if (parent.visible === false) {\n              console.log(`[Summit608] Making parent visible for ${mesh.name}:`, parent.name || parent.type || 'unnamed');\n              parent.visible = true;\n            }\n            parent = parent.parent;\n          }\n        }\n        \n        toggledCount++;\n        toggledMeshNames.push(mesh.name);\n        \n        // Apply trim color to visible wainscot meshes\n        if (isMetalWainscot && mesh.material && trimHex) {\n          const color = new THREE.Color(trimHex);\n          if (Array.isArray(mesh.material)) {\n            mesh.material.forEach(m => { \n              if (m.color) m.color = color;\n              if (m.roughness !== undefined) m.roughness = 0.3;\n              if (m.metalness !== undefined) m.metalness = 0.6;\n            });\n          } else {\n            if (mesh.material.color) mesh.material.color = color;\n            if (mesh.material.roughness !== undefined) mesh.material.roughness = 0.3;\n            if (mesh.material.metalness !== undefined) mesh.material.metalness = 0.6;\n          }\n          mesh.material.needsUpdate = true;\n        }\n      }\n    });\n\n    console.log(`[Summit608] Toggled ${toggledCount} wainscot meshes to visible=${isMetalWainscot}:`, toggledMeshNames);\n\n    // Refresh siding to use correct mesh set (standard vs metal)\n    const currentSiding = this.cachedConfigurations?.siding?.value || \n                          this.configData?.defaultConfiguration?.siding || 'lap';\n    const currentColor = this.cachedConfigurations?.sidingColor?.value || \n                         this.configData?.defaultConfiguration?.sidingColor || 'iron-gray';\n    \n    // Re-apply siding with updated metal wainscot state\n    await this.handleSidingTypeChange({ \n      section: 'siding', \n      value: currentSiding,\n      sidingColor: currentColor\n    });\n    \n    // CRITICAL: Re-apply wainscot visibility and properties AFTER siding refresh completes\n    if (isMetalWainscot) {\n      await this.reapplyWainscotVisibility();\n    }\n  }\n\n  /**\n   * Handle roof addon (e.g., shortened back eaves)\n   */\n  handleRoofAddon(value) {\n    console.log(`[Summit608] Roof addon: ${value}`);\n    \n    // Get mesh patterns from config instead of hardcoding\n    let roofAddonMeshPatterns = {\n      standard: [],\n      b6: []\n    };\n    \n    // Search through steps to find roofAddon config\n    for (const step of (this.configData?.steps || [])) {\n      const roofAddonConfig = step.options?.roofAddon;\n      if (roofAddonConfig) {\n        // Find the selected choice and get its meshGroups\n        const selectedChoice = (roofAddonConfig.choices || []).find(c => c.value === value);\n        if (selectedChoice?.meshGroups) {\n          // If choice has meshGroups, use them\n          if (value === 'b6') {\n            roofAddonMeshPatterns.b6 = selectedChoice.meshGroups.enabled || selectedChoice.meshGroups || [];\n          } else {\n            roofAddonMeshPatterns.standard = selectedChoice.meshGroups.enabled || selectedChoice.meshGroups || [];\n          }\n        }\n        \n        // Also check the 'none' choice for standard meshes\n        const noneChoice = (roofAddonConfig.choices || []).find(c => c.value === 'none');\n        if (noneChoice?.meshGroups) {\n          roofAddonMeshPatterns.standard = noneChoice.meshGroups.enabled || noneChoice.meshGroups || [];\n        }\n        \n        break;\n      }\n    }\n    \n    // Fallback to hardcoded patterns if nothing found in config\n    if (roofAddonMeshPatterns.standard.length === 0 && roofAddonMeshPatterns.b6.length === 0) {\n      console.warn('[Summit608] No meshGroups found in config for roofAddon, using fallback patterns');\n      roofAddonMeshPatterns.standard = ['eave_standard', 'back_eave_standard', 'eave_full', 'roof_eave_back', 'back_eave'];\n      roofAddonMeshPatterns.b6 = ['eave_back_6', 'back_eave_6', 'shortened_eave', 'b6_eave', 'eave_6', 'back_6', 'b6'];\n    }\n    \n    // Get all meshes from model loader\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    \n    console.log(`[Summit608] DEBUG - Total meshes in scene: ${allMeshes.length}`);\n    \n    // DEBUG: Log all eave/back-related mesh names to identify correct patterns\n    const roofRelatedMeshes = allMeshes.filter(m => {\n      const name = (m.name || '').toLowerCase();\n      return name.includes('eave') || name.includes('back') || \n             name.includes('b6') || name.includes('shorten') ||\n             name.includes('roof') || name.includes('soffit');\n    });\n    console.log(`[Summit608] DEBUG - Found ${roofRelatedMeshes.length} roof-related meshes:`, \n      roofRelatedMeshes.map(m => m.name).slice(0, 30));\n    \n    let shownCount = 0;\n    let hiddenCount = 0;\n    const shownMeshes = [];\n    const hiddenMeshes = [];\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      // Check if this is a standard eave mesh\n      const isStandardEave = roofAddonMeshPatterns.standard.some(p => nameLower.includes(p.toLowerCase()));\n      // Check if this is a b6 (shortened) eave mesh\n      const isB6Eave = roofAddonMeshPatterns.b6.some(p => nameLower.includes(p.toLowerCase()));\n      \n      if (isStandardEave) {\n        // Standard eaves: show when 'none', hide when 'b6'\n        mesh.visible = (value === 'none');\n        if (mesh.visible) {\n          shownCount++;\n          shownMeshes.push(mesh.name);\n        } else {\n          hiddenCount++;\n          hiddenMeshes.push(mesh.name);\n        }\n      } else if (isB6Eave) {\n        // B6 eaves: hide when 'none', show when 'b6'\n        mesh.visible = (value === 'b6');\n        if (mesh.visible) {\n          shownCount++;\n          shownMeshes.push(mesh.name);\n        } else {\n          hiddenCount++;\n          hiddenMeshes.push(mesh.name);\n        }\n      }\n    });\n    \n    console.log(`[Summit608] Roof addon: showed ${shownCount}, hid ${hiddenCount} meshes for value=\"${value}\"`);\n    if (shownMeshes.length > 0) {\n      console.log(`[Summit608] Shown meshes:`, shownMeshes.slice(0, 10));\n    }\n    if (hiddenMeshes.length > 0) {\n      console.log(`[Summit608] Hidden meshes:`, hiddenMeshes.slice(0, 10));\n    }\n    \n    // If no meshes were found, log a warning with guidance\n    if (shownCount === 0 && hiddenCount === 0) {\n      console.warn(`[Summit608] No roof addon meshes found. Check the DEBUG log above for available mesh names.`);\n      console.warn(`[Summit608] Expected mesh patterns - Standard: ${roofAddonMeshPatterns.standard.join(', ')}`);\n      console.warn(`[Summit608] Expected mesh patterns - B6: ${roofAddonMeshPatterns.b6.join(', ')}`);\n    }\n  }\n\n  /**\n   * Apply material to mesh groups\n   * @param {string[]} meshPatterns - Patterns to match mesh names\n   * @param {THREE.Material} material - Material to apply\n   * @param {boolean} onlyVisible - Only apply to visible meshes (default: false for siding)\n   */\n  applyMaterialToMeshGroups(meshPatterns, material, onlyVisible = false) {\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    let count = 0;\n    const matchedNames = [];\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      const matches = meshPatterns.some(pattern => nameLower.includes(pattern.toLowerCase()));\n      if (matches) {\n        // Apply to mesh if not checking visibility, or if mesh is visible\n        if (!onlyVisible || mesh.visible) {\n          mesh.material = material.clone();\n          mesh.material.needsUpdate = true;\n          mesh.visible = true; // Ensure mesh is visible\n          count++;\n          matchedNames.push(mesh.name);\n        }\n      }\n    });\n    \n    console.log(`[Summit Siding] Applied material to ${count} meshes:`, matchedNames.slice(0, 5).join(', '), count > 5 ? '...' : '');\n    \n    // Force render update\n    if (this.sceneManager?.renderer && count > 0) {\n      this.sceneManager.renderer.render(this.sceneManager.scene, this.sceneManager.camera);\n    }\n  }\n\n  /**\n   * Apply siding color to meshes - creates new materials for proper color application\n   */\n  applySidingColor(meshPatterns, hexColor) {\n    if (!meshPatterns || !meshPatterns.length) {\n      console.warn('[Summit Siding] No mesh patterns provided');\n      return;\n    }\n    \n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    console.log(`[Summit Siding] Applying color ${hexColor} to ${meshPatterns.length} patterns`);\n    \n    const sidingColorObj = new THREE.Color(hexColor);\n    let appliedCount = 0;\n    const matchedMeshNames = [];\n    \n    // Create a new material with the siding color\n    const sidingMaterial = new THREE.MeshStandardMaterial({\n      color: sidingColorObj,\n      roughness: 0.8,\n      metalness: 0.1,\n      side: THREE.DoubleSide,\n      visible: true\n    });\n    \n    // Elements to exclude from siding\n    const excludePattern = /roof|fascia|eave|soffit|trim_color|door_slab|door_color|window|frame|glass|floor|cabinet|counter|fixture|furniture|programmatic|lumber|drywall|lifestyle/i;\n    \n    allMeshes.forEach(mesh => {\n      if (!mesh.name) return;\n      const nameLower = mesh.name.toLowerCase();\n      \n      // Skip excluded elements\n      if (excludePattern.test(nameLower)) return;\n      \n      // Check if mesh name matches any pattern\n      const isSidingMesh = meshPatterns.some(pattern => nameLower.includes(pattern.toLowerCase()));\n      \n      if (isSidingMesh) {\n        mesh.material = sidingMaterial.clone();\n        mesh.material.needsUpdate = true;\n        mesh.visible = true;\n        appliedCount++;\n        matchedMeshNames.push(mesh.name);\n      }\n    });\n    \n    // Force render update\n    if (this.sceneManager?.renderer) {\n      this.sceneManager.renderer.render(this.sceneManager.scene, this.sceneManager.camera);\n    }\n    \n    console.log(`[Summit Siding] Applied color ${hexColor} to ${appliedCount} meshes`);\n    if (appliedCount > 0) {\n      console.log(`[Summit Siding] Matched:`, matchedMeshNames.slice(0, 10).join(', '), appliedCount > 10 ? `... and ${appliedCount - 10} more` : '');\n    } else {\n      console.warn(`[Summit Siding] WARNING: No meshes matched siding patterns!`);\n    }\n  }\n\n  /**\n   * Handle roof type change\n   */\n  handleRoofChange(config) {\n    if (config.value === '4-front-eaves' || config.value === 'extended') {\n      this.loadModel(this.currentOrientation);\n    }\n  }\n\n  /**\n   * Handle main floor finish change\n   * Follows same pattern as Aspect: uses meshGroups from config first\n   */\n  async handleFloorFinishChange(config) {\n    const textureUrl = this.getFloorTextureUrl(config.value, config.texture);\n    \n    // Get meshGroups from config - these should match actual mesh names in the OBJ file\n    let meshGroups = getMeshGroups(config.meshGroups);\n    \n    // If not in config, try to get from step options (like Aspect does)\n    if (!meshGroups.length) {\n      const finishesStep = this.configData.steps?.find(s => s.id === 'finishes');\n      const mainFloorOption = finishesStep?.options?.mainFloorFinish;\n      meshGroups = getMeshGroups(mainFloorOption?.meshGroups);\n    }\n    \n    console.log('Summit-608 Floor \u25BA selection', {\n      section: config.section,\n      value: config.value,\n      texture: textureUrl || config.texture || 'auto',\n      meshGroups: meshGroups\n    });\n\n    if (!textureUrl) {\n      if (this.materialManager.applyMainFloorFinish) {\n        this.materialManager.applyMainFloorFinish(config.value);\n      }\n      return;\n    }\n\n    // Apply to ground plane\n    this.applyFloorTextureToGroundPlane(textureUrl, config.textureScale);\n\n    // Store config with meshGroups and apply to model meshes\n    this.currentFloorConfig = { \n      ...config, \n      texture: textureUrl,\n      meshGroups: meshGroups \n    };\n\n    const success = await this.applyFloorTexture(this.currentFloorConfig);\n    console.log(`Summit-608 Floor \u25BA model meshes ${success ? 'updated' : 'not found'}`);\n\n    if (!success) {\n      if (this.materialManager.applyMainFloorFinish) {\n        this.materialManager.applyMainFloorFinish(config.value);\n      }\n    }\n  }\n\n  /**\n   * Handle generic changes (visibility or material based on config)\n   */\n  handleGenericChange(config) {\n    const meshGroups = getMeshGroups(config.meshGroups);\n    const hasColor = config.hex || config.rgb;\n    const hasTexture = config.texture;\n\n    if (hasColor && meshGroups.length) {\n      this.materialManager.applyColorToGroups(meshGroups, config.hex || config.rgb);\n    } else if (hasTexture && meshGroups.length) {\n      this.materialManager.applyTextureToGroups(meshGroups, config.texture, { textureScale: config.textureScale });\n    } else if (meshGroups.length) {\n      // Toggle visibility\n      meshGroups.forEach(group => this.modelLoader.setGroupVisibility(group, true));\n\n      if (config.allOptions) {\n        config.allOptions.forEach(option => {\n          if (option.value !== config.value) {\n            [...getMeshGroups(option.meshGroups), ...getDisabledMeshGroups(option.meshGroups)]\n              .forEach(group => this.modelLoader.setGroupVisibility(group, false));\n          }\n        });\n      }\n    }\n  }\n\n  // ============================================================================\n  // FLOOR TEXTURE HELPERS\n  // ============================================================================\n\n  getFloorTextureUrl(finishValue, providedTexture) {\n    if (providedTexture) return providedTexture;\n    if (this.configData?.textures?.[finishValue]) return this.configData.textures[finishValue];\n    return this.textureFallbacks[finishValue] || null;\n  }\n\n  async applyFloorTextureToGroundPlane(textureUrl, textureScale) {\n    const ground = this.sceneManager?.getGround?.();\n    if (!ground) return;\n\n    try {\n      const material = await this.materialManager.createTexturedMaterial(textureUrl, {\n        roughness: 0.7,\n        metalness: 0.0,\n        textureScale: textureScale || { uScale: 10, vScale: 10 }\n      });\n      this.sceneManager.setGroundMaterial(material);\n    } catch (error) {\n      console.error('Failed to apply floor texture to ground:', error);\n    }\n  }\n\n  async applyFloorTexture(config) {\n    if (!config?.texture) return false;\n\n    let floorMeshes = [];\n    \n    // STEP 1: Try to find meshes using meshGroups from config (like Aspect does)\n    // This is the primary method - meshGroups should contain the exact mesh names\n    const meshGroupsFromConfig = getMeshGroups(config.meshGroups);\n    \n    if (meshGroupsFromConfig.length > 0) {\n      console.log('Summit-608 Floor \u25BA trying meshGroups from config:', meshGroupsFromConfig);\n      \n      meshGroupsFromConfig.forEach(groupName => {\n        const meshesForGroup = this.modelLoader?.getMeshesByGroup(groupName) || [];\n        if (meshesForGroup.length > 0) {\n          console.log(`Summit-608 Floor \u25BA found ${meshesForGroup.length} meshes for group \"${groupName}\"`);\n          floorMeshes.push(...meshesForGroup);\n        }\n      });\n    }\n\n    // STEP 2: If meshGroups didn't find anything, try layout-based lookup\n    if (!floorMeshes.length) {\n      const layout = this.currentLayout || this.configData.defaultConfiguration?.layout || 'more-living';\n      floorMeshes = this.getFloorMeshesForLayout(layout);\n      \n      if (floorMeshes?.length) {\n        console.log(`Summit-608 Floor \u25BA found ${floorMeshes.length} meshes via layout \"${layout}\"`);\n      }\n    }\n\n    // STEP 3: Fall back to geometry-based detection\n    if (!floorMeshes?.length) {\n      const layout = this.currentLayout || this.configData.defaultConfiguration?.layout || 'more-living';\n      floorMeshes = this.findFloorMeshesByGeometry(layout);\n      if (floorMeshes?.length) {\n        this.floorMeshCache[layout] = floorMeshes;\n        console.log(`Summit-608 Floor \u25BA found ${floorMeshes.length} meshes via geometry detection`);\n      }\n    }\n\n    console.log(`Summit-608 Floor \u25BA mesh candidates (raw): ${floorMeshes?.length || 0}`);\n\n    // Filter out bathroom meshes (those should use bathFloorFinish)\n    const filtered = floorMeshes.filter(m => !/bathroom/i.test(m.name || ''));\n    console.log(`Summit-608 Floor \u25BA mesh candidates (filtered): ${filtered.length}`);\n\n    // STEP 4: If no mesh-based floors found, use the programmatic floor plane\n    if (!filtered.length) {\n      console.log('Summit-608 Floor \u25BA No mesh-based floors found, using programmatic floor plane');\n      \n      if (this.floorPlane) {\n        const result = await this.applyTextureToFloorPlane(config.texture, config.textureScale);\n        if (result) {\n          console.log('Summit-608 Floor \u25BA \u2705 Applied texture to programmatic floor');\n          return true;\n        }\n      } else {\n        // Create floor plane if it doesn't exist\n        this.createProgrammaticFloor();\n        if (this.floorPlane) {\n          const result = await this.applyTextureToFloorPlane(config.texture, config.textureScale);\n          if (result) {\n            console.log('Summit-608 Floor \u25BA \u2705 Created and applied texture to programmatic floor');\n            return true;\n          }\n        }\n      }\n      \n      console.warn('Summit-608 Floor \u25BA Could not create or apply texture to programmatic floor');\n      return false;\n    }\n    \n    // Calculate dynamic texture scale based on model dimensions\n    const textureScale = this.calculateFloorTextureScale(filtered, config.textureScale);\n    const textureOptions = { textureScale };\n\n    console.log('\uD83C\uDFA8 Applying floor texture with scale:', textureScale);\n\n    try {\n      if (typeof this.materialManager.applyTextureToMeshes === 'function') {\n        console.log('  - using materialManager.applyTextureToMeshes...');\n        const result = await this.materialManager.applyTextureToMeshes(filtered, config.texture, textureOptions);\n        console.log('  - applyTextureToMeshes result:', result);\n        return result > 0;\n      }\n\n      console.log('  - using createTexturedMaterial fallback...');\n      const material = await this.materialManager.createTexturedMaterial(config.texture, textureOptions);\n      filtered.forEach(mesh => { mesh.material = material.clone(); });\n      console.log('  \u2705 Applied texture via fallback');\n      return true;\n    } catch (error) {\n      console.error('Failed to apply floor texture:', error);\n      return false;\n    }\n  }\n\n  /**\n   * Calculate dynamic texture scale based on floor mesh dimensions\n   * This ensures the floor texture looks correct regardless of model size\n   */\n  calculateFloorTextureScale(floorMeshes, configScale) {\n    // If config provides a scale, use it as base\n    if (configScale && (configScale.uScale || configScale.vScale)) {\n      return configScale;\n    }\n\n    // Standard texture coverage - each texture tile represents approximately 4 feet\n    // This creates a realistic wood plank appearance\n    const TEXTURE_COVERAGE_FEET = 4;\n\n    // First, try to use dimensions from configData if available\n    const configWidth = this.configData?.width || this.configData?.length;\n    const configDepth = this.configData?.depth;\n\n    if (configWidth && configDepth) {\n      // Config dimensions are in feet - convert to texture repeat count\n      const uScale = parseFloat(configWidth) / TEXTURE_COVERAGE_FEET;\n      const vScale = parseFloat(configDepth) / TEXTURE_COVERAGE_FEET;\n      console.log(`Floor texture scale from config: ${uScale.toFixed(2)} x ${vScale.toFixed(2)}`);\n      return { uScale, vScale };\n    }\n\n    // Fall back to calculating from mesh bounding box\n    // Get the largest floor mesh to determine model size\n    let maxArea = 0;\n    let largestMesh = null;\n\n    floorMeshes.forEach(mesh => {\n      if (!mesh.geometry) return;\n      if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();\n      const bbox = mesh.geometry.boundingBox;\n      const width = Math.abs(bbox.max.x - bbox.min.x);\n      const depth = Math.abs(bbox.max.z - bbox.min.z);\n      const area = width * depth;\n      if (area > maxArea) {\n        maxArea = area;\n        largestMesh = mesh;\n      }\n    });\n\n    if (!largestMesh || !largestMesh.geometry.boundingBox) {\n      // Fallback to reasonable defaults for large models\n      return { uScale: 8, vScale: 8 };\n    }\n\n    const bbox = largestMesh.geometry.boundingBox;\n    const modelWidth = Math.abs(bbox.max.x - bbox.min.x);\n    const modelDepth = Math.abs(bbox.max.z - bbox.min.z);\n\n    // Calculate texture scale assuming model units are in inches\n    // Convert to feet and then to texture repeat count\n    const TEXTURE_COVERAGE_INCHES = TEXTURE_COVERAGE_FEET * 12; // 48 inches\n    const uScale = modelWidth / TEXTURE_COVERAGE_INCHES;\n    const vScale = modelDepth / TEXTURE_COVERAGE_INCHES;\n\n    // Clamp to reasonable range\n    const finalUScale = Math.max(1, Math.min(20, uScale));\n    const finalVScale = Math.max(1, Math.min(20, vScale));\n\n    console.log(`Floor texture scale from mesh: ${finalUScale.toFixed(2)} x ${finalVScale.toFixed(2)}`);\n\n    return { uScale: finalUScale, vScale: finalVScale };\n  }\n\n  getFloorMeshesForLayout(layout) {\n    const normalized = layout || 'more-living';\n\n    if (this.floorMeshCache[normalized]) {\n      return this.floorMeshCache[normalized];\n    }\n\n    if (this.modelLoader?.getFloorMeshesForLayout) {\n      const meshes = this.modelLoader.getFloorMeshesForLayout(normalized) || [];\n      if (meshes.length) {\n        this.floorMeshCache[normalized] = meshes;\n        return meshes;\n      }\n      console.log(`Summit-608 Floor \u25BA group meshes missing for layout \"${normalized}\", using geometry fallback`);\n    }\n\n    return this.findFloorMeshesByGeometry(normalized);\n  }\n\n  findFloorMeshesByGeometry(layout) {\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    console.log(`Summit-608 Floor \u25BA scanning ${allMeshes.length} meshes for layout \"${layout}\"`);\n\n    // First log ALL mesh names for debugging\n    const allMeshInfo = [];\n    allMeshes.forEach(mesh => {\n      if (!mesh.geometry) return;\n      if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();\n      const bbox = mesh.geometry.boundingBox;\n      const height = bbox.max.y - bbox.min.y;\n      const minY = bbox.min.y;\n      const maxY = bbox.max.y;\n      const length = bbox.max.x - bbox.min.x;\n      const width = bbox.max.z - bbox.min.z;\n      const area = Math.abs(length * width);\n      allMeshInfo.push({\n        name: mesh.name || 'unnamed',\n        material: mesh.material?.name || 'no-mat',\n        area,\n        height,\n        minY,\n        maxY,\n        length,\n        width,\n        mesh\n      });\n    });\n    \n    // Sort by area and log top meshes for debugging\n    allMeshInfo.sort((a, b) => b.area - a.area);\n    console.log('Summit-608 Floor \u25BA ALL meshes by area (top 20):', allMeshInfo.slice(0, 20).map(m => \n      `${m.name} [${m.material}] area:${m.area.toFixed(0)} h:${m.height.toFixed(1)} minY:${m.minY.toFixed(1)}`\n    ));\n\n    // Strategy: Find the INTERIOR floor - large horizontal surface at walking level\n    // Interior floor should be above 0 (ground is at 0), typically 1-20 units up\n    \n    const potentialFloors = [];\n    // Match floor meshes - \"interior\" is the main floor mesh name in Summit models\n    // Use word boundary \\b to avoid matching \"interior_door\" when looking for \"interior\"\n    const floorKeywords = /\\bfloor\\b|\\bflooring\\b|\\blvp\\b|\\bvinyl\\b|\\bhardwood\\b|\\binterior\\s+white\\b|\\bdeck\\b/i;\n    \n    // These are DEFINITELY not interior floors\n    const strictExclude = /roof|fascia|eave|soffit|exterior|outside|ceiling|door|frame|slab|window|glass|cabinet|counter|appliance|fixture|shower|sink|toilet|furniture|chair|sofa|bed|stair|railing|baseboard|wainscot|closet/i;\n    \n    // Siding-related - these are walls, not floors\n    // IMPORTANT: Don't exclude plain \"wood_texture\" meshes as they might be floors\n    // Only exclude when combined with siding indicators like \"plank_siding\" or \"wood_texture_metal\"\n    const sidingPattern = /plank.*siding|wood_texture_metal|block.*siding|cedar.*siding|lap.*siding|trim(?!_color)/i;\n\n    allMeshInfo.forEach(info => {\n      const name = info.name.toLowerCase();\n      const matName = info.material.toLowerCase();\n      \n      // Check if this is a wood_texture mesh for detailed logging\n      const isWoodTexture = /wood_texture/i.test(info.name);\n      \n      // Strict exclusions - these can NEVER be floors\n      if (strictExclude.test(name) || strictExclude.test(matName)) {\n        if (isWoodTexture) console.log(`[Floor Debug] Excluded ${info.name}: strictExclude pattern matched`);\n        return;\n      }\n      \n      // Siding is never a floor\n      if (sidingPattern.test(name) || sidingPattern.test(matName)) {\n        if (isWoodTexture) console.log(`[Floor Debug] Excluded ${info.name}: sidingPattern matched`);\n        return;\n      }\n      \n      // Must have floor keywords OR meet strict geometry criteria\n      const hasFloorKeyword = floorKeywords.test(name) || floorKeywords.test(matName);\n      \n      // Geometric criteria for interior floors:\n      // - Horizontal (thin in Y direction) - CRITICAL: floor must be thin\n      // - At floor level (minY near 0, typically -5 to 15)\n      // - Large surface area (at least 500 sq units for a room)\n      // - Wider than tall\n      \n      const isThin = info.height < 5; // Floor surfaces should be thin\n      const isAtFloorLevel = info.minY >= -5 && info.minY <= 15; // Near ground level\n      const isLarge = info.area >= 500; // Significant floor area\n      const isHorizontal = info.height < Math.min(info.length, info.width) / 3;\n      \n      // IMPORTANT: Even keyword matches must be geometrically thin to be a floor!\n      // If height > 10, it's a volume (like \"interior\" box), not a floor surface\n      const isNotAVolume = info.height < 10;\n      \n      // Log wood_texture mesh evaluation for debugging\n      if (isWoodTexture) {\n        console.log(`[Floor Debug] ${info.name}: hasKeyword=${hasFloorKeyword}, isThin=${isThin}, isAtFloorLevel=${isAtFloorLevel}, isLarge=${isLarge}, isHorizontal=${isHorizontal}, isNotAVolume=${isNotAVolume}, area=${info.area.toFixed(0)}, height=${info.height.toFixed(1)}, minY=${info.minY.toFixed(1)}`);\n      }\n      \n      if (hasFloorKeyword && isNotAVolume && isAtFloorLevel) {\n        // Floor keyword match AND geometrically valid - high priority\n        potentialFloors.push({ ...info, priority: 1, reason: 'keyword' });\n        if (isWoodTexture) console.log(`[Floor Debug] \u2705 Added ${info.name} as floor (keyword match)`);\n      } else if (isThin && isAtFloorLevel && isLarge && isHorizontal) {\n        // Pure geometry match for large horizontal surfaces at floor level\n        potentialFloors.push({ ...info, priority: 2, reason: 'geometry' });\n        if (isWoodTexture) console.log(`[Floor Debug] \u2705 Added ${info.name} as floor (geometry match)`);\n      } else if (isWoodTexture) {\n        console.log(`[Floor Debug] \u274C Rejected ${info.name}: Failed criteria`);\n      }\n    });\n\n    // Sort by priority then area\n    potentialFloors.sort((a, b) => {\n      if (a.priority !== b.priority) return a.priority - b.priority;\n      return b.area - a.area;\n    });\n\n    console.log(`Summit-608 Floor \u25BA detected ${potentialFloors.length} floor meshes:`, \n      potentialFloors.slice(0, 10).map(f => `${f.name} (${f.reason}, area:${f.area.toFixed(0)}, minY:${f.minY.toFixed(1)})`));\n\n    if (potentialFloors.length === 0) {\n      console.warn('Summit-608 Floor \u25BA No floors found! Falling back to largest horizontal mesh near ground...');\n      \n      // Ultimate fallback - just find the LARGEST horizontal mesh not on the roof\n      const fallback = allMeshInfo.filter(m => {\n        const name = m.name.toLowerCase();\n        // Exclude obvious non-floors (including trim which is often mistaken for floor)\n        if (/roof|fascia|eave|soffit|ceiling|trim_color|trim[^a-z]|door|window/i.test(name)) return false;\n        // Must be relatively thin and horizontal\n        return m.height < 5 && m.minY < 30 && m.area > 200;\n      });\n      \n      console.log(`Summit-608 Floor \u25BA Fallback candidates:`, fallback.slice(0, 5).map(f => \n        `${f.name} (area:${f.area.toFixed(0)}, minY:${f.minY.toFixed(1)})`));\n      \n      if (fallback.length > 0) {\n        const result = fallback.slice(0, 3).map(f => f.mesh);\n        this.floorMeshCache[layout] = result;\n        return result;\n      }\n    }\n\n    const result = potentialFloors.map(f => f.mesh);\n    this.floorMeshCache[layout] = result;\n    return result;\n  }\n\n  /**\n   * Apply default floor finish immediately after model loads\n   * This ensures floor is visible on initial load before applyConfigTo3D runs\n   */\n  async applyDefaultFloorFinish() {\n    // Get default floor value from config\n    const defaultFloor = this.configData.defaultConfiguration?.mainFloorFinish || 'ashlar-oak';\n    \n    // Find the floor option to get texture URL\n    let textureUrl = null;\n    let optionData = null;\n    \n    // Search through steps for mainFloorFinish option\n    this.configData.steps?.forEach(step => {\n      if (step.options?.mainFloorFinish) {\n        optionData = step.options.mainFloorFinish;\n        const selectedOption = optionData.choices?.find(c => c.value === defaultFloor) || \n                               optionData.options?.find(o => o.value === defaultFloor);\n        if (selectedOption?.texture) {\n          textureUrl = selectedOption.texture;\n        }\n      }\n    });\n\n    // Fallback to texture lookup\n    if (!textureUrl) {\n      textureUrl = this.getFloorTextureUrl(defaultFloor, null);\n    }\n\n    console.log('Summit-608 Floor \u25BA applying default floor finish:', { defaultFloor, textureUrl });\n\n    // Debug: Log all unique mesh names to help identify floor meshes\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    const uniqueNames = [...new Set(allMeshes.map(m => m.name).filter(Boolean))];\n    console.log('Summit-608 Floor \u25BA All mesh names in model:', uniqueNames.slice(0, 50).join(', '));\n    \n    // Also log mesh names that might be floor-related\n    const floorRelated = uniqueNames.filter(n => /floor|cube|plane|ground|slab|wood|deck/i.test(n));\n    console.log('Summit-608 Floor \u25BA Floor-related mesh names:', floorRelated.join(', ') || 'NONE FOUND');\n\n    if (!textureUrl) {\n      console.warn('Summit-608 Floor \u25BA no texture URL found for default floor');\n      return;\n    }\n\n    // Clear floor mesh cache to force re-detection\n    this.floorMeshCache = {};\n\n    // Apply floor texture using the existing method\n    const config = {\n      section: 'mainFloorFinish',\n      value: defaultFloor,\n      texture: textureUrl,\n      meshGroups: optionData?.meshGroups || ['main_floor', 'flooring', 'cube']\n    };\n\n    await this.handleFloorFinishChange(config);\n    \n    // Cache this config for reapplication\n    this.cachedConfigurations['mainFloorFinish'] = config;\n  }\n\n  /**\n   * Apply default siding and exterior colors immediately after model loads\n   * This ensures siding, trim, door, fascia, and soffit have correct colors on initial load\n   */\n  async applyDefaultExteriorFinishes() {\n    const defaults = this.configData.defaultConfiguration || {};\n    \n    console.log('Summit-608 Exterior \u25BA applying default exterior finishes');\n    console.log('Summit-608 Exterior \u25BA defaultConfiguration:', defaults);\n    \n    // Debug: Log all available meshes to see what we're working with\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    console.log(`Summit-608 Exterior \u25BA Total meshes available: ${allMeshes.length}`);\n    if (allMeshes.length > 0) {\n      const meshNames = allMeshes.map(m => m.name).filter(Boolean);\n      const sidingMeshes = meshNames.filter(n => /siding|plank|wood_texture|block/i.test(n));\n      console.log(`Summit-608 Exterior \u25BA Siding-related meshes found: ${sidingMeshes.length}`, sidingMeshes.slice(0, 10));\n    }\n\n    // Find the siding step - try multiple possible IDs\n    let sidingStep = this.configData.steps?.find(s => \n      s.id === 'sidingAndColor' || \n      s.id === 'siding' || \n      s.id === 'exterior' ||\n      s.name?.toLowerCase().includes('siding')\n    );\n    \n    // If no step found, try to find options directly from any step\n    let sidingOptions = sidingStep?.options || {};\n    if (!sidingStep) {\n      // Try to find siding options in any step\n      for (const step of (this.configData.steps || [])) {\n        if (step.options?.siding || step.options?.sidingColor || step.options?.sidingType) {\n          sidingOptions = step.options;\n          sidingStep = step;\n          break;\n        }\n      }\n    }\n    \n    console.log('Summit-608 Exterior \u25BA Found siding step:', sidingStep?.id || sidingStep?.name || 'none');\n    console.log('Summit-608 Exterior \u25BA Siding options keys:', Object.keys(sidingOptions));\n    \n    if (!sidingStep && Object.keys(sidingOptions).length === 0) {\n      console.warn('Summit-608 Exterior \u25BA No siding step or options found in config');\n      // Still try to apply siding with defaults even without step config\n    }\n\n    // Apply siding TYPE first (lap, plank, block, cedar-plank, cedar-shake)\n    const sidingTypeValue = defaults.siding || defaults.sidingType || 'lap';\n    const sidingTypeOption = sidingOptions.siding || sidingOptions.sidingType || sidingOptions.sidingOptions;\n    \n    if (sidingTypeOption) {\n      const selectedType = sidingTypeOption.choices?.find(c => c.value === sidingTypeValue) ||\n                          sidingTypeOption.options?.find(o => o.value === sidingTypeValue);\n      \n      const sidingTypeConfig = {\n        section: 'siding',\n        value: sidingTypeValue,\n        meshGroups: selectedType?.meshGroups || sidingTypeOption.meshGroups || []\n      };\n      \n      console.log('Summit-608 Exterior \u25BA applying default siding type:', sidingTypeValue);\n      await this.handleSidingTypeChange(sidingTypeConfig);\n      this.cachedConfigurations['siding'] = sidingTypeConfig;\n      this.currentSidingType = sidingTypeValue;\n    } else {\n      // No siding type config found - apply default siding type anyway\n      console.log('Summit-608 Exterior \u25BA no siding type config, applying default:', sidingTypeValue);\n      const sidingTypeConfig = {\n        section: 'siding',\n        value: sidingTypeValue,\n        meshGroups: []\n      };\n      await this.handleSidingTypeChange(sidingTypeConfig);\n      this.cachedConfigurations['siding'] = sidingTypeConfig;\n      this.currentSidingType = sidingTypeValue;\n    }\n\n    // Apply siding color\n    const sidingColorValue = defaults.sidingColor || 'iron-gray';\n    const sidingColorOption = sidingOptions.sidingColor;\n    if (sidingColorOption) {\n      const selectedColor = sidingColorOption.choices?.find(c => c.value === sidingColorValue) ||\n                           sidingColorOption.options?.find(o => o.value === sidingColorValue);\n      if (selectedColor?.hex) {\n        const sidingConfig = {\n          section: 'sidingColor',\n          value: sidingColorValue,\n          hex: selectedColor.hex,\n          meshGroups: sidingColorOption.meshGroups || []\n        };\n        \n        console.log('Summit-608 Exterior \u25BA applying default siding color:', sidingColorValue, selectedColor.hex);\n        await this.handleSidingColorChange(sidingConfig);\n        this.cachedConfigurations['sidingColor'] = sidingConfig;\n      }\n    } else {\n      // No siding color config - apply with default hex lookup\n      const hexColor = this.getSidingColorHex(sidingColorValue);\n      const sidingConfig = {\n        section: 'sidingColor',\n        value: sidingColorValue,\n        hex: hexColor,\n        meshGroups: []\n      };\n      console.log('Summit-608 Exterior \u25BA applying default siding color (no config):', sidingColorValue, hexColor);\n      await this.handleSidingColorChange(sidingConfig);\n      this.cachedConfigurations['sidingColor'] = sidingConfig;\n    }\n\n    // Apply trim color\n    const trimColorValue = defaults.trimColor || 'aluminum';\n    const trimColorOption = sidingOptions.trimColor;\n    if (trimColorOption) {\n      const selectedTrim = trimColorOption.choices?.find(c => c.value === trimColorValue) ||\n                          trimColorOption.options?.find(o => o.value === trimColorValue);\n      if (selectedTrim?.hex) {\n        const trimConfig = {\n          section: 'trimColor',\n          value: trimColorValue,\n          hex: selectedTrim.hex,\n          meshGroups: trimColorOption.meshGroups || ['trim_color']\n        };\n        \n        console.log('Summit-608 Exterior \u25BA applying default trim color:', trimColorValue, selectedTrim.hex);\n        this.handleColorChange(trimConfig);\n        this.cachedConfigurations['trimColor'] = trimConfig;\n      }\n    }\n\n    // Apply door color\n    const doorColorValue = defaults.doorColor || 'factory-primed-white';\n    const doorColorOption = sidingOptions.doorColor;\n    if (doorColorOption) {\n      const selectedDoor = doorColorOption.choices?.find(c => c.value === doorColorValue) ||\n                          doorColorOption.options?.find(o => o.value === doorColorValue);\n      if (selectedDoor?.hex) {\n        const doorConfig = {\n          section: 'doorColor',\n          value: doorColorValue,\n          hex: selectedDoor.hex,\n          meshGroups: doorColorOption.meshGroups || ['door_color', 'door_slab']\n        };\n        \n        console.log('Summit-608 Exterior \u25BA applying default door color:', doorColorValue, selectedDoor.hex);\n        this.handleColorChange(doorConfig);\n        this.cachedConfigurations['doorColor'] = doorConfig;\n      }\n    }\n\n    // Apply fascia color\n    const fasciaColorValue = defaults.fasciaColor || 'iron-gray';\n    const fasciaColorOption = sidingOptions.fasciaColor;\n    if (fasciaColorOption) {\n      const selectedFascia = fasciaColorOption.choices?.find(c => c.value === fasciaColorValue) ||\n                            fasciaColorOption.options?.find(o => o.value === fasciaColorValue);\n      if (selectedFascia?.hex) {\n        const fasciaConfig = {\n          section: 'fasciaColor',\n          value: fasciaColorValue,\n          hex: selectedFascia.hex,\n          meshGroups: fasciaColorOption.meshGroups || ['fascia_color']\n        };\n        \n        console.log('Summit-608 Exterior \u25BA applying default fascia color:', fasciaColorValue, selectedFascia.hex);\n        this.handleColorChange(fasciaConfig);\n        this.cachedConfigurations['fasciaColor'] = fasciaConfig;\n      }\n    }\n\n    // Apply soffit color\n    const soffitColorValue = defaults.soffitColor || 'unfinished-eaves';\n    const soffitColorOption = sidingOptions.soffitColor;\n    if (soffitColorOption) {\n      const selectedSoffit = soffitColorOption.choices?.find(c => c.value === soffitColorValue) ||\n                            soffitColorOption.options?.find(o => o.value === soffitColorValue);\n      if (selectedSoffit?.hex) {\n        const soffitConfig = {\n          section: 'soffitColor',\n          value: soffitColorValue,\n          hex: selectedSoffit.hex,\n          meshGroups: soffitColorOption.meshGroups || ['soffit_color', 'eaves_color']\n        };\n        \n        console.log('Summit-608 Exterior \u25BA applying default soffit color:', soffitColorValue, selectedSoffit.hex);\n        this.handleColorChange(soffitConfig);\n        this.cachedConfigurations['soffitColor'] = soffitConfig;\n      }\n    }\n\n    // Apply exterior addon (metal wainscot) - IMPORTANT: Must hide wainscot if default is \"none\"\n    const exteriorAddonValue = defaults.exteriorAddon || 'none';\n    console.log('Summit-608 Exterior \u25BA applying default exterior addon:', exteriorAddonValue);\n    await this.handleExteriorAddon(exteriorAddonValue);\n    this.cachedConfigurations['exteriorAddon'] = { \n      section: 'exteriorAddon', \n      value: exteriorAddonValue \n    };\n\n    // Apply roof addon\n    const roofAddonValue = defaults.roofAddon || 'none';\n    console.log('Summit-608 Exterior \u25BA applying default roof addon:', roofAddonValue);\n    this.handleRoofAddon(roofAddonValue);\n    this.cachedConfigurations['roofAddon'] = { \n      section: 'roofAddon', \n      value: roofAddonValue \n    };\n\n    console.log('Summit-608 Exterior \u25BA finished applying default exterior finishes');\n    console.log('Summit-608 Exterior \u25BA cached configurations:', Object.keys(this.cachedConfigurations));\n  }\n\n  // ============================================================================\n  // EVENT DISPATCHING\n  // ============================================================================\n\n  onConfigChange(data) {\n    this.container.dispatchEvent(new CustomEvent('configurator:change', { detail: data }));\n  }\n\n  onModelLoaded(orientation) {\n    this.container.dispatchEvent(new CustomEvent('configurator:modelLoaded', { detail: { orientation } }));\n  }\n\n  // ============================================================================\n  // PUBLIC API\n  // ============================================================================\n\n  setMeshGroupsVisibility(meshGroups, visible) {\n    meshGroups?.forEach(group => this.modelLoader?.setGroupVisibility(group, visible));\n  }\n\n  applyColorToMeshGroups(meshGroups, color) {\n    this.materialManager?.applyColorToGroups(meshGroups, color);\n  }\n\n  applyTextureToMeshGroups(meshGroups, textureUrl, textureScale) {\n    this.materialManager?.applyTextureToGroups(meshGroups, textureUrl, { textureScale });\n  }\n\n  resetCamera() {\n    this.cameraControls?.reset();\n  }\n\n  rotateCamera(degrees) {\n    this.cameraControls?.rotateBy(degrees);\n  }\n\n  setInteriorView(enabled) {\n    if (enabled) {\n      this.modelLoader?.setRoofVisible(false);\n      this.cameraControls?.setTopDownView();\n    } else {\n      this.modelLoader?.setRoofVisible(true);\n      this.cameraControls?.restoreExteriorView();\n    }\n  }\n\n  getState() {\n    return { orientation: this.currentOrientation, step: this.currentStep };\n  }\n\n  getAllMeshNames() {\n    return this.modelLoader?.getAllMeshNames() || [];\n  }\n\n  /**\n   * Debug method: Log all loaded meshes organized by source (base, roof, component, furniture)\n   */\n  debugLogLoadedMeshes() {\n    console.log('=== Summit-608 Configurator: Loaded Meshes Debug ===');\n    console.log(`Model: ${this.currentModelKey}, Component: ${this.currentComponentKey}`);\n    \n    const logMeshesFromObject = (obj, label) => {\n      if (!obj) {\n        console.log(`  ${label}: \u274C NOT LOADED`);\n        return { total: 0, visible: 0, hidden: 0 };\n      }\n      const meshes = [];\n      let visibleCount = 0;\n      let hiddenCount = 0;\n      \n      obj.traverse((child) => {\n        if (child.isMesh) {\n          const name = child.name || 'unnamed';\n          meshes.push({ name, visible: child.visible });\n          if (child.visible) visibleCount++;\n          else hiddenCount++;\n        }\n      });\n      \n      console.log(`  ${label}: ${meshes.length} meshes (${visibleCount} visible, ${hiddenCount} hidden)`);\n      \n      // Show all mesh names with visibility status\n      if (meshes.length > 0 && meshes.length <= 60) {\n        const meshInfo = meshes.map(m => m.visible ? m.name : `[HIDDEN]${m.name}`);\n        console.log(`    All meshes: ${meshInfo.join(', ')}`);\n      } else if (meshes.length > 60) {\n        const meshInfo = meshes.slice(0, 60).map(m => m.visible ? m.name : `[HIDDEN]${m.name}`);\n        console.log(`    First 60: ${meshInfo.join(', ')}...`);\n      }\n      \n      // Check for wall-related meshes\n      const wallMeshes = meshes.filter(m => /wall|front|back|side|panel|exterior|siding|plank|wood_texture/i.test(m.name));\n      if (wallMeshes.length > 0) {\n        console.log(`    \uD83E\uDDF1 Wall-related (${wallMeshes.length}): ${wallMeshes.map(m => m.visible ? m.name : `[H]${m.name}`).join(', ')}`);\n      } else {\n        console.log(`    \uD83E\uDDF1 Wall-related: NONE FOUND`);\n      }\n      \n      // Check for interior-related meshes\n      const interiorMeshes = meshes.filter(m => /interior|floor|cabinet|counter|fixture|furniture|bathroom|kitchen|toilet|sink|shower|tub/i.test(m.name));\n      if (interiorMeshes.length > 0) {\n        console.log(`    \uD83C\uDFE0 Interior-related (${interiorMeshes.length}): ${interiorMeshes.map(m => m.visible ? m.name : `[H]${m.name}`).join(', ')}`);\n      } else {\n        console.log(`    \uD83C\uDFE0 Interior-related: NONE FOUND`);\n      }\n      \n      return { total: meshes.length, visible: visibleCount, hidden: hiddenCount };\n    };\n    \n    // Log base model\n    const baseStats = logMeshesFromObject(this.modelLoader?.loadedModel, '\uD83D\uDCE6 Base Model');\n    \n    // Log roof\n    const roofStats = logMeshesFromObject(this.modelLoader?.loadedRoof, '\uD83C\uDFE0 Roof');\n    \n    // Log component\n    let componentStats = { total: 0, visible: 0, hidden: 0 };\n    if (this.loadedComponent) {\n      componentStats = logMeshesFromObject(this.loadedComponent, `\uD83D\uDD27 Component (${this.currentComponentKey})`);\n    } else {\n      console.log(`  \uD83D\uDD27 Component: \u274C NOT LOADED (key: ${this.currentComponentKey})`);\n    }\n    \n    // Log furniture\n    let furnitureStats = { total: 0, visible: 0, hidden: 0 };\n    if (this.loadedFurniture) {\n      furnitureStats = logMeshesFromObject(this.loadedFurniture, '\uD83E\uDE91 Furniture');\n    } else {\n      console.log(`  \uD83E\uDE91 Furniture: \u274C NOT LOADED`);\n    }\n    \n    // Summary\n    const total = baseStats.total + roofStats.total + componentStats.total + furnitureStats.total;\n    const visible = baseStats.visible + roofStats.visible + componentStats.visible + furnitureStats.visible;\n    console.log(`\\n\uD83D\uDCCA TOTAL: ${total} meshes (${visible} visible, ${total - visible} hidden)`);\n    \n    // Check specifically for bathroom and front wall\n    console.log('\\n\uD83D\uDD0D Searching for specific elements...');\n    const allMeshes = this.modelLoader?.getAllMeshes?.() || [];\n    \n    const bathroomMeshes = allMeshes.filter(m => /bathroom|bath|toilet|shower|sink|tub/i.test(m.name || ''));\n    console.log(`  Bathroom meshes: ${bathroomMeshes.length > 0 ? bathroomMeshes.map(m => `${m.name}(${m.visible ? 'V' : 'H'})`).join(', ') : 'NONE FOUND'}`);\n    \n    const frontMeshes = allMeshes.filter(m => /front/i.test(m.name || ''));\n    console.log(`  Front meshes: ${frontMeshes.length > 0 ? frontMeshes.map(m => `${m.name}(${m.visible ? 'V' : 'H'})`).join(', ') : 'NONE FOUND'}`);\n    \n    console.log('=== End Mesh Debug ===');\n  }\n\n  dispose() {\n    try {\n      // Clear caches\n      this.materialManager?.clearCache?.();\n      this.floorMeshCache = {};\n      this.currentFloorConfig = null;\n      this.cachedConfigurations = {};\n\n      // Dispose managers\n      this.cameraControls?.dispose?.();\n      this.modelLoader?.dispose?.();\n      this.sceneManager?.dispose?.();\n\n      // Clear references\n      this.sceneManager = null;\n      this.modelLoader = null;\n      this.materialManager = null;\n      this.cameraControls = null;\n      this.configData = null;\n      this.textureFallbacks = null;\n\n      this.isInitialized = false;\n      this.isLoading = false;\n\n      log('Summit608Configurator3D disposed');\n    } catch (error) {\n      console.error('Error disposing Summit608Configurator3D:', error);\n    }\n  }\n\n  executeConfiguration(config, { emitEvent = true } = {}) {\n    const sectionBase = config.section?.includes('.') ? config.section.split('.')[0] : config.section;\n    const handlers = {\n      layout: () => this.handleVisibilityChange(config),\n      kitchen: () => this.handleVisibilityChange(config),\n      exterior: () => this.handleVisibilityChange(config),\n      elevations: () => this.handleVisibilityChange(config),\n      // Entry/Door options - these toggle visibility of door-related meshes\n      sideOptions: () => this.handleVisibilityChange(config),\n      frontOptions: () => this.handleVisibilityChange(config),\n      entryOptions: () => this.handleVisibilityChange(config),\n      entryLocation: () => this.handleVisibilityChange(config),\n      windowOptions: () => this.handleVisibilityChange(config),\n      bathOptions: () => this.handleVisibilityChange(config),\n      interiorOptions: () => this.handleInteriorOptionsChange(config),\n      // Siding handlers\n      siding: () => this.handleSidingTypeChange(config),\n      sidingOptions: () => this.handleSidingTypeChange(config),\n      sidingType: () => this.handleSidingTypeChange(config),\n      sidingColor: () => this.handleSidingColorChange(config),\n      trimColor: () => this.handleColorChange(config),\n      doorColor: () => this.handleColorChange(config),\n      soffitColor: () => this.handleColorChange(config),\n      fasciaColor: () => this.handleColorChange(config),\n      eavesColor: () => this.handleColorChange(config),\n      mainFloorFinish: () => this.handleFloorFinishChange(config),\n      flooring: () => this.handleFloorFinishChange(config),\n      'flooring.main': () => this.handleFloorFinishChange(config),\n      bathFloorFinish: () => this.handleTextureChange(config),\n      'flooring.bath': () => this.handleTextureChange(config),\n      fixtureFinish: () => this.handleMetalFinishChange(config),\n      'finishes.fixture': () => this.handleMetalFinishChange(config),\n      counterFinish: () => this.handleTextureChange(config),\n      countertop: () => this.handleTextureChange(config),\n      'finishes.countertop': () => this.handleTextureChange(config),\n      cabinetFinish: () => this.handleCabinetChange(config),\n      cabinets: () => this.handleCabinetChange(config),\n      'finishes.cabinets': () => this.handleCabinetChange(config),\n      roof: () => this.handleRoofChange(config),\n      roofEaves: () => this.handleRoofChange(config),\n      // Addon handlers - show/hide meshes based on selection\n      exteriorAddon: () => this.handleAddonChange('exterior', config.value),\n      roofAddon: () => this.handleAddonChange('roof', config.value)\n    };\n\n    const handler = handlers[sectionBase] || handlers[config.section];\n    if (handler) {\n      handler();\n    } else {\n      this.handleGenericChange(config);\n    }\n\n    if (emitEvent) {\n      this.onConfigChange({ key: config.section, value: config.value });\n    }\n  }\n\n  reapplyCachedConfigurations() {\n    Object.values(this.cachedConfigurations).forEach((config) => {\n      this.executeConfiguration(config, { emitEvent: false });\n    });\n  }\n\n  /**\n   * Check if the viewer is ready for operations\n   */\n  isReady() {\n    return this.isInitialized && !this.isLoading;\n  }\n}\n\n// Export for both module and non-module usage\nwindow.Summit608Configurator3D = Summit608Configurator3D;\n\nexport { Summit608Configurator3D };\n"],
  "mappings": "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",
  "names": ["entryValue", "uScale", "vScale", "bbox", "result"]
}
