{"version":3,"mappings":"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","names":["DEFAULT_NKN_RPC_ENDPOINTS","UIController","options","_a","_b","handler","mode","path","fallback","value","patch","el","rangeEl","numberEl","text","settings","nknSettings","configured","addr","normalized","rawRpcServerAddr","token","nextPool","idx","allowed","key","pool","now","i","endpoint","state","bestIdx","bestCooldown","cooldownUntilMs","err","msg","code","prev","failures","cooldown","ok","cutoff","ts","reason","cooldownMs","context","attempts","fatal","endpointFailed","sidebar","sidebarToggle","sidebarClose","overlaySidebar","overlayToggle","overlaySidebarClose","bindPanel","panel","toggle","close","setOpen","open","groups","setGroupState","group","header","isCollapsed","willOpen","other","section","title","e","settingsFile","settingsDownload","settingsReset","settingsStatus","setStatus","message","event","file","error","data","blob","url","link","sdkStatusEl","connStatusEl","enabled","next","relayEl","datasetEl","syncFromSettings","relayValue","DEFAULT_FORWARDER","datasetValue","relay","dataset","updateRelayDataset","raw","cleaned","src","id","selector","existing","resolve","reject","script","Buffer","__vitePreload","n","nknSdkUrls","lastError","loadErr","sdk","nknPattern","nknTextPattern","lastByMethod","method","orig","args","stack","arg","last","settingsSeed","storedSeed","arr","hex","b","gate","delay","label","baseDelay","jitter","skipReconnect","handleIncoming","nknEnabled","seed","rpcServerAddr","configuredWebrtc","webrtc","tls","minReconnectMs","maxReconnectMs","numSubClients","generation","client","cachedAddr","connectFailed","addrInput","_d","_c","payload","cfgBatchSize","cfgBatchSizeRange","cfgMaxConcurrent","cfgMaxConcurrentRange","cfgMinInterval","cfgMinIntervalRange","cfgMaxKBPerMin","cfgMaxKBPerMinRange","cfgMaxVertexRecords","cfgMaxVertexRecordsRange","cfgElevSurfaceMaxLod","cfgElevSurfaceMaxLodRange","cfgElevSurfaceFalloff","cfgElevSurfaceFalloffRange","cfgSurfaceStageMinLOD","cfgSurfaceStageMinLODRange","cfgSurfaceStageMaxLOD","cfgSurfaceStageMaxLODRange","cfgSurfaceLodNear","cfgSurfaceLodNearRange","cfgSurfaceLodFar","cfgSurfaceLodFarRange","cfgSurfaceLodFalloff","cfgSurfaceLodFalloffRange","cfgSurfaceLodStart","cfgSurfaceLodStartRange","cfgSurfaceStageCooldown","cfgSurfaceStageCooldownRange","cfgSurfaceCullAngle","cfgSurfaceCullAngleRange","cfgOrbitFalloffMargin","cfgOrbitFalloffMarginRange","cfgOrbitFalloffAnchor","cfgOrbitFalloffAnchorRange","cfgOrbitLodFalloff","cfgOrbitLodFalloffRange","cfgElevAngleLimit","cfgElevAngleLimitRange","cfgElevSurfaceMinLevel","cfgElevSurfaceMinLevelRange","cfgElevRingNearKm","cfgElevRingNearKmRange","cfgElevRingMidKm","cfgElevRingMidKmRange","cfgElevRingBudgetNear","cfgElevRingBudgetNearRange","cfgElevRingBudgetMid","cfgElevRingBudgetMidRange","cfgElevQueueResetKm","cfgElevQueueResetKmRange","cfgElevQueueResetAngle","cfgElevQueueResetAngleRange","readNumber","num","elevation","staging","falloff","orbitFalloff","batchSize","maxConcurrent","minInterval","maxKB","maxVertexRecords","_e","elevAngleLimit","_f","elevSurfaceMinLevel","_g","ringNearMeters","_h","ringMidMeters","_i","ringNearKm","ringMidKm","ringBudgetNear","_k","_j","ringBudgetMid","_m","_l","queueResetMeters","_n","queueResetAngle","_o","queueResetKm","surfaceStageMinLOD","surfaceStageMaxLOD","surfaceStageCooldown","surfaceCullAngle","surfaceLodNear","surfaceLodFar","surfaceLodFalloff","surfaceLodStart","orbitFalloffMargin","_p","orbitFalloffAnchor","_q","orbitLodFalloff","_r","applyElevConfig","elevSurfaceMaxLod","elevSurfaceFalloff","elevRingNearKm","elevRingMidKm","clampPercent","elevRingBudgetNear","elevRingBudgetMid","elevQueueResetKm","elevQueueResetAngle","surfaceLodNearFinal","surfaceLodFalloffFinal","ringBaseLod","ringFalloffPower","ringMidDrop","ringFarDrop","ringLodCaps","queueResetDistanceM","bindRangeNumberPair","syncFromRange","syncFromNumber","ev","btnLodOrbit","btnLodZoom","cfgTileBudget","cfgSplitBudget","cfgMergeBudget","lblTileBudget","lblSplitBudget","lblMergeBudget","updateLodButtons","lodMode","lod","tileBudget","splitBudget","mergeBudget","applyLodBudgets","btnEnterSurface","btnExitSurface","surfaceModeHint","viewDir","THREE.Vector3","cameraPos","planetGroup","hit","rayEllipsoidIntersection","raySphereIntersection","updateCameraModeUI","isOnSurface","newMode","cfgImageryEnabled","cfgImageryDataset","cfgImageryVersion","cfgImageryZoom","btnImageryPreview","imageryPreviewImg","imageryUrlEl","cfgImageryMinZoom","cfgImageryMaxZoom","lblImageryMinZoom","lblImageryMaxZoom","waybackVersions","waybackFetchPromise","lastVersionId","normalizeVersionId","isLatestVersion","buildWaybackCapabilitiesUrl","marker","WMTS_ROOT","WAYBACK_WMTS_CAPABILITIES","setDatasetStatus","opt","syncDatasetSelection","versionId","resolved","targetId","match","v","existingCustom","customOpt","populateDatasetOptions","versions","loadWaybackVersions","resp","xml","layers","layer","version","sortKey","dateMatch","a","imagery","managerCfg","rawVersion","preferLatest","fallbackVersion","DEFAULT_WAYBACK_VERSION","zoom","minZoom","maxZoom","applyImageryConfig","versionInput","latestMode","nextMin","nextMax","latestResolved","current","cfg","z","ll","worldPosToLatLonLocal","coords","lonLatToTileCoords","cfgPhotogramEnabled","cfgPhotogramRing0Only","cfgPhotogramInvert","cfgPhotogramAutoSun","cfgPhotogramMinZoom","lblPhotogramMinZoom","cfgPhotogramMapResolution","lblPhotogramMapResolution","cfgPhotogramPyramidLevels","lblPhotogramPyramidLevels","cfgPhotogramIllumBlur","lblPhotogramIllumBlur","cfgPhotogramDisplacement","lblPhotogramDisplacement","cfgPhotogramDetailGain","lblPhotogramDetailGain","cfgPhotogramShadowMicro","lblPhotogramShadowMicro","cfgPhotogramDirMicro","lblPhotogramDirMicro","cfgPhotogramCanopyScale","lblPhotogramCanopyScale","cfgPhotogramVegThreshold","lblPhotogramVegThreshold","cfgPhotogramShadowThreshold","lblPhotogramShadowThreshold","cfgPhotogramMaxShadow","lblPhotogramMaxShadow","cfgPhotogramCanopyBlur","lblPhotogramCanopyBlur","cfgPhotogramDome","lblPhotogramDome","cfgPhotogramSmoothPasses","lblPhotogramSmoothPasses","cfgPhotogramSunAzimuth","lblPhotogramSunAzimuth","cfgPhotogramSunElevation","lblPhotogramSunElevation","cfgPhotogramTiles","lblPhotogramTiles","cfgPhotogramSubdiv","lblPhotogramSubdiv","cfgPhotogramMaxSubdiv","lblPhotogramMaxSubdiv","cfgPhotogramJobsPerFrame","lblPhotogramJobsPerFrame","cfgPhotogramConcurrentJobs","lblPhotogramConcurrentJobs","cfgPhotogramProcessingMs","lblPhotogramProcessingMs","cfgPhotogramCacheMaxTiles","lblPhotogramCacheMaxTiles","readFloat","readInt","formatInt","formatFloat2","syncLabels","buildConfigFromInputs","config","applyPhotogramConfig","settingsCfg","resolveBool","resolveNum","cfgWireframe","cfgStatePersist","cfgAtmosphereEnabled","cfgGeoJson","cfgGeoJsonAutoDepth","cfgGeoJsonMaxDepth","cfgGeoJsonAdminLevel","cfgGeoJsonCountry","geoJsonBasePath","adminLevels","maxDepthLevels","admIndexes","worldCountries","geoJsonOptionsReady","geoJsonOptionsPromise","pendingGeoJsonSelection","normalizeIso3","trimmed","getFeatureName","props","getFeatureIso3","candidates","iso3","parseWorldCountries","geojson","map","feature","name","fetchWorldCountries","fetchJsonResource","fetchAdminIndex","level","list","filesByIso","countries","entry","loadGeoJsonIndexes","world","adm1","adm2","adm3","ensureGeoJsonOptions","option","setAdminLevelValue","nextIso3","populateCountryOptions","applyGeoJsonSelection","syncGeoJsonControlState","numeric","setMaxDepthValue","autoDepthEnabled","baseDisabled","selectedIso3","adminLevel","allowAll","available","resolveSelectionFromSettings","debug","country","source","atmosphere","selection","applyGeoJson","visible","applyGeoJsonAutoDepth","applyGeoJsonMaxDepth","resolveGeoJsonSelection","index","applyWireframe","wireframeEnabled","LS_STATE","saveState","togglePersistInterval","throttledSave","fn","timeout","remaining","params","body","latParam","lonParam","latRaw","lonRaw","lat","lon","hasLatLon","altitudeRaw","altitude","heading","pitch","hasHeading","hasPitch","angle","stateOverride","store","hasOrientation","surfaceThreshold","hasAltitude","useSurface","yaw","THREE.MathUtils","upDir","latLonToLocalDir","planetQuat","THREE.Quaternion","terrainR","PLANET_RADIUS","surfaceAlt","minSurfaceAlt","dir","ellipsoidR","ellipsoidRadiusForWorldDir","baseRadius","pos","force","wantsSurface","inSurface","includeElevationCache","rawMode","camera","controls","target","worldPos","camPos","camQuat","surfacePos","surfaceAltitude","surfaceTerrainRadius","surfaceLatLon","orbitLatLon","orbitRadius","targetPos","surfaceOrientation","vrState","dolly","updateUrl","applyElevationCache","allowPersistToggle","savedCamera","surface","isSurfaceMode","resolveWorldDirFromLatLon","localDir","worldQuat","surfaceDir","surfaceVec","cameraVec","terrainRadius","orbitDir","dollyPos","cfgDate","cfgTime","cfgTimeSpeed","cfgTimeSpeedLabel","cfgUseSimplified","btnTimeNow","btnTimeSunrise","btnTimeNoon","btnTimeSunset","btnTimeMidnight","pad2","formatUtcDateInput","date","year","month","day","updateTimeInputs","activeEl","persistLighting","hours","minutes","speed","cfgAtmBaseOffset","cfgAtmBaseOffsetRange","cfgAtmIrradianceScale","cfgAtmIrradianceScaleRange","cfgAtmShadowRadius","cfgAtmShadowRadiusRange","cfgAtmSkyAlphaScale","cfgAtmSkyAlphaScaleRange","cfgAtmSkyAlphaClamp","cfgAtmSkyAlphaClampRange","cfgAtmSkyLimbBoost","cfgAtmSkyLimbBoostRange","cfgAtmSkyPathShort","cfgAtmSkyPathShortRange","cfgAtmSkyLimbMax","cfgAtmSkyLimbMaxRange","cfgAtmSkyDensityScale","cfgAtmSkyDensityScaleRange","cfgAtmSkyScaleHeight","cfgAtmSkyScaleHeightRange","cfgAtmSkyVerticalFadeStart","cfgAtmSkyVerticalFadeStartRange","cfgAtmSkyVerticalFadeEnd","cfgAtmSkyVerticalFadeEndRange","cfgAtmSkyAltitudeFadeStart","cfgAtmSkyAltitudeFadeStartRange","cfgAtmSkyAltitudeFadeEnd","cfgAtmSkyAltitudeFadeEndRange","cfgAtmSkyOutsideFadeStart","cfgAtmSkyOutsideFadeStartRange","cfgAtmSkyOutsideFadeEnd","cfgAtmSkyOutsideFadeEndRange","cfgAtmSkyDepthThreshold","cfgAtmSkyDepthThresholdRange","cfgAtmPhotometric","cfgAtmSunIrradiance","cfgAtmSkyIrradiance","cfgAtmTransmittance","cfgAtmInscatter","cfgAtmSky","cfgAtmSun","cfgAtmMoon","cfgCloudsEnabled","cfgCloudCoverage","cfgCloudCoverageRange","cfgCloudScattering","cfgCloudScatteringRange","cfgCloudAbsorption","cfgCloudAbsorptionRange","cfgCloudTurbulenceDisp","cfgCloudTurbulenceDispRange","cfgCloudLightShafts","cfgCloudShapeDetail","cfgCloudTurbulence","cfgCloudHaze","cfgCloudLowAltitude","cfgCloudLowAltitudeRange","cfgCloudLowHeight","cfgCloudLowHeightRange","cfgCloudMidAltitude","cfgCloudMidAltitudeRange","cfgCloudMidHeight","cfgCloudMidHeightRange","cfgCloudHighAltitude","cfgCloudHighAltitudeRange","cfgCloudHighHeight","cfgCloudHighHeightRange","toNumber","applyAtmospherePatch","baseOffset","irradianceScale","PHOTOREAL_ALBEDO_SCALE_DEFAULT","shadowRadius","skyTuning","skyAlphaScale","skyAlphaClamp","skyLimbBoost","skyPathShort","skyLimbMax","skyDensityScale","skyScaleHeight","skyVerticalFadeStart","skyVerticalFadeEnd","skyAltitudeFadeStart","skyAltitudeFadeEnd","skyOutsideFadeStart","skyOutsideFadeEnd","skyDepthThreshold","cloudSettings","cloudCoverage","scattering","absorption","turbulenceDisp","layerSettings","low","mid","high","setAtmosphereEnabled","setCloudsEnabled","applyAtmosphere","updates","applyClouds","coverage","applyCloudLayers","lowAlt","lowHeight","midAlt","midHeight","highAlt","highHeight","onChange","cfgWeatherEnabled","cfgWeatherAuto","cfgWeatherRadius","cfgWeatherRadiusRange","cfgWeatherInfluence","cfgWeatherInfluenceRange","cfgWeatherInterval","cfgWeatherIntervalRange","cfgWeatherMinDelta","cfgWeatherMinDeltaRange","applyWeatherPatch","weather","radiusKm","influence","intervalMin","minDelta","applyWeather","detail","weatherLocation","weatherCondition","weatherTemp","weatherClouds","weatherHumidity","weatherWind","weatherPrecip","weatherUpdated","system","lastUpdate","setText","desc","temp","clouds","humidity","wind","precipValue","precip","ageMs","cloudTuneables","tuneables","cfgRenderScale","cfgRenderScaleRange","cfgAutoRenderScale","clampScale","applyScale","rendererSettings","initial","debugToggle","debugPanel","cfgFlipRotation180","cfgNegateSunX","cfgNegateSunZ","cfgInvertFocusDir","cfgNegateFocusX","cfgNegateFocusZ","cfgInvertCameraDir","cfgInvertCameraPos","cfgNegateCamPosX","cfgNegateCamPosZ","cfgInvertQuaternion","cfgDisableViewportCulling","cfgNeighborDetection","bindDebugToggle","defaults","loadProfile","stored","parsed","profile","applyProfileToUI","setVal","syncToScene","saveProfile","fields","maybeRedraw","rangeBindings","rangeKey","numKey","numEl","syncRangeToNum","syncNumToRange"],"ignoreList":[],"sources":["../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/ui-controller.js"],"sourcesContent":["/**\n * UI Controller Module\n *\n * Manages all UI interactions, sidebar behavior, and configuration controls.\n * Coordinates between UI elements and the various system components.\n */\n\nimport * as THREE from 'three';\nimport { DEFAULT_FORWARDER, PLANET_RADIUS, WMTS_ROOT, DEFAULT_WAYBACK_VERSION, WAYBACK_WMTS_CAPABILITIES } from './constants.js';\nimport {\n    raySphereIntersection,\n    rayEllipsoidIntersection,\n    lonLatToTileCoords,\n    worldPosToLatLonLocal,\n    latLonToLocalDir,\n    ellipsoidRadiusForWorldDir\n} from './geometry-utils.js';\nimport { fetchJsonResource } from '../refactor/shared/JsonResourceCache.js';\nimport {\n    PHOTOREAL_ALBEDO_SCALE_DEFAULT,\n} from '../refactor/tiles/PhotorealAppearanceContract.js';\n\nconst DEFAULT_NKN_RPC_ENDPOINTS = Object.freeze([\n    'https://mainnet-rpc-node-0001.nkn.org/mainnet/api/wallet',\n    'https://mainnet-rpc-node-0002.nkn.org/mainnet/api/wallet',\n    'https://mainnet-rpc-node-0003.nkn.org/mainnet/api/wallet',\n    'https://mainnet-rpc-node-0004.nkn.org/mainnet/api/wallet'\n]);\n\nexport class UIController {\n    constructor(options) {\n        // System components\n        this.elevationClient = options.elevationClient;\n        this.triTree = options.triTree;\n        this.imageryManager = options.imageryManager;\n        this.lightingSystem = options.lightingSystem;\n        this.surfaceController = options.surfaceController;\n        this.camera = options.camera;\n        this.renderer = options.renderer;\n        this.sceneInitializer = options.sceneInitializer;\n        this.weatherSystem = options.weatherSystem || null;\n        this.eventBus = options.eventBus || null;\n        this.onGeoJsonToggle = options.onGeoJsonToggle || null;\n        this.onGeoJsonSourceChange = options.onGeoJsonSourceChange || null;\n        this.settings = options.settings || null;\n        this._settingsSyncHandlers = [];\n        this._settingsUnsub = null;\n\n        // Callback for when atmosphere materials are ready\n        this.onAtmosphereMaterialsReady = null;\n\n        // DOM elements\n        this.elements = this.collectDOMElements();\n\n        // NKN client\n        this.multiClient = null;\n        this._nknInitAttempts = 0;\n        this._nknInitMaxAttempts = 15;\n        this._nknInitRetryMs = 1000;\n        this._nknInitTimer = null;\n        this._nknHandleIncoming = null;\n        this._nknReconnectTimer = null;\n        this._nknBackoffMs = 1000;\n        this._nknMaxBackoffMs = 15000;\n        this._nknBackoffBaseMs = 15000;\n        this._nknConnectPromise = null;\n        this._nknConnectInFlight = false;\n        this._nknConnectResolve = null;\n        this._nknConnectReject = null;\n        this._nknConnectGeneration = 0;\n        this._nknFailureCount = 0;\n        this._nknCooldownUntilMs = 0;\n        this._nknAttemptWindow = [];\n        this._nknAttemptWindowMs = 60 * 60 * 1000;\n        this._nknMaxAttemptsPerWindow = 60;\n        this._nknCircuitThreshold = 6;\n        this._nknCooldownMs = 10 * 60 * 1000;\n        this._nknStateKey = '';\n        this._nknOnlineListener = null;\n        this._nknVisibilityListener = null;\n        this._nknRpcPool = [];\n        this._nknRpcCursor = 0;\n        this._nknRpcFailures = new Map();\n        this._nknActiveRpcServerAddr = '';\n        this._nknForceNoWebrtc = false;\n        this._nknWebrtcFailureCount = 0;\n        this._nknWebrtcFailureThreshold = 2;\n        this._nknRpcCooldownBaseMs = 30000;\n        this._nknRpcCooldownMaxMs = 30 * 60 * 1000;\n        this._updateLodButtons = null;\n        this._nknSdk = null;\n        this._nknSdkPromise = null;\n        this._nknEnabled = this._resolveNknEnabled();\n        this._lightingLiveInterval = null;\n        this._urlStateLast = '';\n        this._urlSyncEnabled = true;\n        this._urlViewState = null;\n        this._urlViewStateMode = null;\n        this._urlViewStateEnforceUntilMs = 0;\n        this._urlViewStateAttempts = 0;\n        this._urlViewStateMaxAttempts = 6;\n        this._urlViewStateApplying = false;\n        this._initializingViewState = false;\n        const initialUrlState = this._readUrlViewState?.();\n        if (initialUrlState) {\n            this._initializingViewState = true;\n        }\n        this._statePersistInterval = null;\n\n        // Local storage keys\n        this.LS_RELAY = 'nkn.globe.relay';\n        this.LS_DATASET = 'nkn.globe.dataset';\n        this.LS_NKN_SEED = 'nkn.globe.seed';\n        this.LS_NKN_ADDR = 'nkn.globe.addr';\n        this.LS_PATH = 'nkn.globe.pathWeights';\n        // Elevation localStorage removed — unified in SceneStateStore\n        this._debugViewStateLogging = false;\n        this.onAutoRenderScaleToggle = null;\n        this.applyRenderScale = null;\n        this.onPathWeightsChange = null;\n\n        // Initialize\n        // These legacy controls mirror already-loaded canonical settings.\n        // Binding/syncing their initial DOM values is not a settings mutation.\n        this._bindingSettingsControls = true;\n        this.setupSidebar();\n        this.setupSettingsControls();\n        this.setupNKNControls();\n        this.setupElevationControls();\n        this.setupLODControls();\n        this.setupSurfaceModeControls();\n        this.setupImageryControls();\n        this.setupPhotogrammetryControls();\n        this.setupLightingControls();\n        this.setupAtmosphereControls();\n        this.setupWeatherControls();\n        this.setupRenderControls();\n        this.setupDebugControls();\n        this.setupWireframeControls();\n        this.setupSignFlipDebugControls();\n        this.setupPathfindingControls();\n        this._bindingSettingsControls = false;\n        this.setupUrlStateSync();\n        const appliedUrlState = this._applyUrlViewState();\n        if (!appliedUrlState) {\n            this._initializingViewState = false;\n            this.restoreViewState();\n        }\n\n        if (this.settings?.subscribe) {\n            this._settingsUnsub = this.settings.subscribe(() => {\n                this.syncUIFromSettings();\n            });\n        }\n    }\n\n    collectDOMElements() {\n        return {\n            // Sidebar\n            sidebar: document.getElementById('sidebar'),\n            sidebarToggle: document.getElementById('sidebar-toggle'),\n            sidebarClose: document.getElementById('sidebar-close'),\n            sidebarTabs: document.querySelectorAll('.sidebar-tab'),\n            sidebarPages: document.querySelectorAll('.sidebar-page'),\n            overlaySidebar: document.getElementById('overlay-sidebar'),\n            overlayToggle: document.getElementById('overlay-toggle'),\n            overlaySidebarClose: document.getElementById('overlay-sidebar-close'),\n\n            // Settings JSON controls\n            settingsFile: document.getElementById('settings-file'),\n            settingsDownload: document.getElementById('settings-download'),\n            settingsReset: document.getElementById('settings-reset'),\n            settingsStatus: document.getElementById('settings-status'),\n\n            // NKN status\n            sdkStatusEl: document.getElementById('sdkStatus'),\n            connStatusEl: document.getElementById('connStatus'),\n            myAddrEl: document.getElementById('myAddr'),\n\n            // NKN config\n            relayEl: document.getElementById('relay'),\n            datasetEl: document.getElementById('dataset'),\n\n            // Elevation config\n            cfgBatchSize: document.getElementById('cfg-batchSize'),\n            cfgBatchSizeRange: document.getElementById('cfg-batchSizeRange'),\n            cfgMaxConcurrent: document.getElementById('cfg-maxConcurrent'),\n            cfgMaxConcurrentRange: document.getElementById('cfg-maxConcurrentRange'),\n            cfgMinInterval: document.getElementById('cfg-minInterval'),\n            cfgMinIntervalRange: document.getElementById('cfg-minIntervalRange'),\n            cfgMaxKBPerMin: document.getElementById('cfg-maxKBPerMin'),\n            cfgMaxKBPerMinRange: document.getElementById('cfg-maxKBPerMinRange'),\n            cfgMaxVertexRecords: document.getElementById('cfg-maxVertexRecords'),\n            cfgMaxVertexRecordsRange: document.getElementById('cfg-maxVertexRecordsRange'),\n            cfgElevSurfaceMaxLod: document.getElementById('cfg-elevSurfaceMaxLod'),\n            cfgElevSurfaceMaxLodRange: document.getElementById('cfg-elevSurfaceMaxLodRange'),\n            cfgElevSurfaceFalloff: document.getElementById('cfg-elevSurfaceFalloff'),\n            cfgElevSurfaceFalloffRange: document.getElementById('cfg-elevSurfaceFalloffRange'),\n            cfgElevRingNearKm: document.getElementById('cfg-elevRingNearKm'),\n            cfgElevRingNearKmRange: document.getElementById('cfg-elevRingNearKmRange'),\n            cfgElevRingMidKm: document.getElementById('cfg-elevRingMidKm'),\n            cfgElevRingMidKmRange: document.getElementById('cfg-elevRingMidKmRange'),\n            cfgElevRingBudgetNear: document.getElementById('cfg-elevRingBudgetNear'),\n            cfgElevRingBudgetNearRange: document.getElementById('cfg-elevRingBudgetNearRange'),\n            cfgElevRingBudgetMid: document.getElementById('cfg-elevRingBudgetMid'),\n            cfgElevRingBudgetMidRange: document.getElementById('cfg-elevRingBudgetMidRange'),\n            cfgElevQueueResetKm: document.getElementById('cfg-elevQueueResetKm'),\n            cfgElevQueueResetKmRange: document.getElementById('cfg-elevQueueResetKmRange'),\n            cfgElevQueueResetAngle: document.getElementById('cfg-elevQueueResetAngle'),\n            cfgElevQueueResetAngleRange: document.getElementById('cfg-elevQueueResetAngleRange'),\n            cfgSurfaceStageMinLOD: document.getElementById('cfg-surfaceStageMinLOD'),\n            cfgSurfaceStageMinLODRange: document.getElementById('cfg-surfaceStageMinLODRange'),\n            cfgSurfaceStageMaxLOD: document.getElementById('cfg-surfaceStageMaxLOD'),\n            cfgSurfaceStageMaxLODRange: document.getElementById('cfg-surfaceStageMaxLODRange'),\n            cfgSurfaceLodNear: document.getElementById('cfg-surfaceLodNear'),\n            cfgSurfaceLodNearRange: document.getElementById('cfg-surfaceLodNearRange'),\n            cfgSurfaceLodFar: document.getElementById('cfg-surfaceLodFar'),\n            cfgSurfaceLodFarRange: document.getElementById('cfg-surfaceLodFarRange'),\n            cfgSurfaceLodFalloff: document.getElementById('cfg-surfaceLodFalloff'),\n            cfgSurfaceLodFalloffRange: document.getElementById('cfg-surfaceLodFalloffRange'),\n            cfgSurfaceLodStart: document.getElementById('cfg-surfaceLodStart'),\n            cfgSurfaceLodStartRange: document.getElementById('cfg-surfaceLodStartRange'),\n            cfgSurfaceStageCooldown: document.getElementById('cfg-surfaceStageCooldown'),\n            cfgSurfaceStageCooldownRange: document.getElementById('cfg-surfaceStageCooldownRange'),\n            cfgSurfaceCullAngle: document.getElementById('cfg-surfaceCullAngle'),\n            cfgSurfaceCullAngleRange: document.getElementById('cfg-surfaceCullAngleRange'),\n            cfgOrbitFalloffMargin: document.getElementById('cfg-orbitFalloffMargin'),\n            cfgOrbitFalloffMarginRange: document.getElementById('cfg-orbitFalloffMarginRange'),\n            cfgOrbitFalloffAnchor: document.getElementById('cfg-orbitFalloffAnchor'),\n            cfgOrbitFalloffAnchorRange: document.getElementById('cfg-orbitFalloffAnchorRange'),\n            cfgOrbitLodFalloff: document.getElementById('cfg-orbitLodFalloff'),\n            cfgOrbitLodFalloffRange: document.getElementById('cfg-orbitLodFalloffRange'),\n            cfgElevAngleLimit: document.getElementById('cfg-elevAngleLimit'),\n            cfgElevAngleLimitRange: document.getElementById('cfg-elevAngleLimitRange'),\n            cfgElevSurfaceMinLevel: document.getElementById('cfg-elevSurfaceMinLevel'),\n            cfgElevSurfaceMinLevelRange: document.getElementById('cfg-elevSurfaceMinLevelRange'),\n            // Pathfinding\n            cfgPathLateralMaxDeg: document.getElementById('cfg-path-lateralMaxDeg'),\n            cfgPathStepsS: document.getElementById('cfg-path-stepsS'),\n            cfgPathStepsT: document.getElementById('cfg-path-stepsT'),\n            cfgPathUphill: document.getElementById('cfg-path-uphill'),\n            cfgPathDownhill: document.getElementById('cfg-path-downhill'),\n            cfgPathElevDelta: document.getElementById('cfg-path-elevDelta'),\n            cfgPathSlopeSq: document.getElementById('cfg-path-slopeSq'),\n            cfgPathLateral: document.getElementById('cfg-path-lateral'),\n            cfgPathDistance: document.getElementById('cfg-path-distance'),\n            cfgPathHigh: document.getElementById('cfg-path-high'),\n            cfgPathRough: document.getElementById('cfg-path-rough'),\n            cfgPathSmooth: document.getElementById('cfg-path-smooth'),\n            // Pathfinding ranges\n            cfgPathLateralMaxDegRange: document.getElementById('cfg-path-lateralMaxDegRange'),\n            cfgPathStepsSRange: document.getElementById('cfg-path-stepsSRange'),\n            cfgPathStepsTRange: document.getElementById('cfg-path-stepsTRange'),\n            cfgPathUphillRange: document.getElementById('cfg-path-uphillRange'),\n            cfgPathDownhillRange: document.getElementById('cfg-path-downhillRange'),\n            cfgPathElevDeltaRange: document.getElementById('cfg-path-elevDeltaRange'),\n            cfgPathSlopeSqRange: document.getElementById('cfg-path-slopeSqRange'),\n            cfgPathLateralRange: document.getElementById('cfg-path-lateralRange'),\n            cfgPathDistanceRange: document.getElementById('cfg-path-distanceRange'),\n            cfgPathHighRange: document.getElementById('cfg-path-highRange'),\n            cfgPathRoughRange: document.getElementById('cfg-path-roughRange'),\n            cfgPathSmoothRange: document.getElementById('cfg-path-smoothRange'),\n\n            // LOD mode\n            btnLodOrbit: document.getElementById('btnLodOrbit'),\n            btnLodZoom: document.getElementById('btnLodZoom'),\n\n            // Surface mode\n            btnEnterSurface: document.getElementById('btnEnterSurface'),\n            btnExitSurface: document.getElementById('btnExitSurface'),\n            surfaceModeHint: document.getElementById('surfaceModeHint'),\n\n            // LOD budgets\n            cfgTileBudget: document.getElementById('cfg-tileBudget'),\n            cfgSplitBudget: document.getElementById('cfg-splitBudget'),\n            cfgMergeBudget: document.getElementById('cfg-mergeBudget'),\n            lblTileBudget: document.getElementById('lbl-tileBudget'),\n            lblSplitBudget: document.getElementById('lbl-splitBudget'),\n            lblMergeBudget: document.getElementById('lbl-mergeBudget'),\n            cfgWireframe: document.getElementById('cfg-wireframe'),\n            cfgGeoJson: document.getElementById('cfg-geojson'),\n            cfgGeoJsonAutoDepth: document.getElementById('cfg-geojson-auto-depth'),\n            cfgGeoJsonMaxDepth: document.getElementById('cfg-geojson-max-depth'),\n            cfgGeoJsonAdminLevel: document.getElementById('cfg-geojson-admin-level'),\n            cfgGeoJsonCountry: document.getElementById('cfg-geojson-country'),\n            cfgStatePersist: document.getElementById('cfg-statePersist'),\n            cfgRenderScale: document.getElementById('cfg-renderScale'),\n            cfgRenderScaleRange: document.getElementById('cfg-renderScaleRange'),\n            cfgAutoRenderScale: document.getElementById('cfg-autoRenderScale'),\n\n            // Imagery\n            cfgImageryEnabled: document.getElementById('cfg-imageryEnabled'),\n            cfgImageryDataset: document.getElementById('cfg-imageryDataset'),\n            cfgImageryVersion: document.getElementById('cfg-imageryVersion'),\n            cfgImageryZoom: document.getElementById('cfg-imageryZoom'),\n            cfgImageryMinZoom: document.getElementById('cfg-imageryMinZoom'),\n            cfgImageryMaxZoom: document.getElementById('cfg-imageryMaxZoom'),\n            lblImageryMinZoom: document.getElementById('lbl-imageryMinZoom'),\n            lblImageryMaxZoom: document.getElementById('lbl-imageryMaxZoom'),\n            btnImageryPreview: document.getElementById('btnImageryPreview'),\n            imageryPreviewImg: document.getElementById('imageryPreview'),\n            imageryUrlEl: document.getElementById('imageryUrl'),\n\n            // Photogrammetry\n            cfgPhotogramEnabled: document.getElementById('cfg-photogramEnabled'),\n            cfgPhotogramRing0Only: document.getElementById('cfg-photogramRing0Only'),\n            cfgPhotogramInvert: document.getElementById('cfg-photogramInvert'),\n            cfgPhotogramAutoSun: document.getElementById('cfg-photogramAutoSun'),\n            cfgPhotogramMinZoom: document.getElementById('cfg-photogramMinZoom'),\n            lblPhotogramMinZoom: document.getElementById('lbl-photogramMinZoom'),\n            cfgPhotogramMapResolution: document.getElementById('cfg-photogramMapResolution'),\n            lblPhotogramMapResolution: document.getElementById('lbl-photogramMapResolution'),\n            cfgPhotogramPyramidLevels: document.getElementById('cfg-photogramPyramidLevels'),\n            lblPhotogramPyramidLevels: document.getElementById('lbl-photogramPyramidLevels'),\n            cfgPhotogramIllumBlur: document.getElementById('cfg-photogramIllumBlur'),\n            lblPhotogramIllumBlur: document.getElementById('lbl-photogramIllumBlur'),\n            cfgPhotogramDisplacement: document.getElementById('cfg-photogramDisplacement'),\n            lblPhotogramDisplacement: document.getElementById('lbl-photogramDisplacement'),\n            cfgPhotogramDetailGain: document.getElementById('cfg-photogramDetailGain'),\n            lblPhotogramDetailGain: document.getElementById('lbl-photogramDetailGain'),\n            cfgPhotogramShadowMicro: document.getElementById('cfg-photogramShadowMicro'),\n            lblPhotogramShadowMicro: document.getElementById('lbl-photogramShadowMicro'),\n            cfgPhotogramDirMicro: document.getElementById('cfg-photogramDirMicro'),\n            lblPhotogramDirMicro: document.getElementById('lbl-photogramDirMicro'),\n            cfgPhotogramCanopyScale: document.getElementById('cfg-photogramCanopyScale'),\n            lblPhotogramCanopyScale: document.getElementById('lbl-photogramCanopyScale'),\n            cfgPhotogramVegThreshold: document.getElementById('cfg-photogramVegThreshold'),\n            lblPhotogramVegThreshold: document.getElementById('lbl-photogramVegThreshold'),\n            cfgPhotogramShadowThreshold: document.getElementById('cfg-photogramShadowThreshold'),\n            lblPhotogramShadowThreshold: document.getElementById('lbl-photogramShadowThreshold'),\n            cfgPhotogramMaxShadow: document.getElementById('cfg-photogramMaxShadow'),\n            lblPhotogramMaxShadow: document.getElementById('lbl-photogramMaxShadow'),\n            cfgPhotogramCanopyBlur: document.getElementById('cfg-photogramCanopyBlur'),\n            lblPhotogramCanopyBlur: document.getElementById('lbl-photogramCanopyBlur'),\n            cfgPhotogramDome: document.getElementById('cfg-photogramDome'),\n            lblPhotogramDome: document.getElementById('lbl-photogramDome'),\n            cfgPhotogramSmoothPasses: document.getElementById('cfg-photogramSmoothPasses'),\n            lblPhotogramSmoothPasses: document.getElementById('lbl-photogramSmoothPasses'),\n            cfgPhotogramSunAzimuth: document.getElementById('cfg-photogramSunAzimuth'),\n            lblPhotogramSunAzimuth: document.getElementById('lbl-photogramSunAzimuth'),\n            cfgPhotogramSunElevation: document.getElementById('cfg-photogramSunElevation'),\n            lblPhotogramSunElevation: document.getElementById('lbl-photogramSunElevation'),\n            cfgPhotogramTiles: document.getElementById('cfg-photogramTiles'),\n            lblPhotogramTiles: document.getElementById('lbl-photogramTiles'),\n            cfgPhotogramSubdiv: document.getElementById('cfg-photogramSubdiv'),\n            lblPhotogramSubdiv: document.getElementById('lbl-photogramSubdiv'),\n            cfgPhotogramMaxSubdiv: document.getElementById('cfg-photogramMaxSubdiv'),\n            lblPhotogramMaxSubdiv: document.getElementById('lbl-photogramMaxSubdiv'),\n            cfgPhotogramJobsPerFrame: document.getElementById('cfg-photogramJobsPerFrame'),\n            lblPhotogramJobsPerFrame: document.getElementById('lbl-photogramJobsPerFrame'),\n            cfgPhotogramConcurrentJobs: document.getElementById('cfg-photogramConcurrentJobs'),\n            lblPhotogramConcurrentJobs: document.getElementById('lbl-photogramConcurrentJobs'),\n            cfgPhotogramProcessingMs: document.getElementById('cfg-photogramProcessingMs'),\n            lblPhotogramProcessingMs: document.getElementById('lbl-photogramProcessingMs'),\n            cfgPhotogramCacheMaxTiles: document.getElementById('cfg-photogramCacheMaxTiles'),\n            lblPhotogramCacheMaxTiles: document.getElementById('lbl-photogramCacheMaxTiles'),\n\n            // Lighting / Time\n            cfgDate: document.getElementById('cfg-date'),\n            cfgTime: document.getElementById('cfg-time'),\n            cfgTimeSpeed: document.getElementById('cfg-timeSpeed'),\n            cfgTimeSpeedLabel: document.getElementById('cfg-timeSpeedLabel'),\n            cfgUseSimplified: document.getElementById('cfg-useSimplified'),\n            btnTimeNow: document.getElementById('btn-timeNow'),\n            btnTimeSunrise: document.getElementById('btn-timeSunrise'),\n            btnTimeNoon: document.getElementById('btn-timeNoon'),\n            btnTimeSunset: document.getElementById('btn-timeSunset'),\n            btnTimeMidnight: document.getElementById('btn-timeMidnight'),\n\n            // Atmosphere + Clouds (Takram system)\n            cfgAtmBaseOffset: document.getElementById('cfg-atmBaseOffset'),\n            cfgAtmBaseOffsetRange: document.getElementById('cfg-atmBaseOffsetRange'),\n            cfgAtmIrradianceScale: document.getElementById('cfg-atmIrradianceScale'),\n            cfgAtmIrradianceScaleRange: document.getElementById('cfg-atmIrradianceScaleRange'),\n            cfgAtmShadowRadius: document.getElementById('cfg-atmShadowRadius'),\n            cfgAtmShadowRadiusRange: document.getElementById('cfg-atmShadowRadiusRange'),\n            cfgAtmSkyAlphaScale: document.getElementById('cfg-atmSkyAlphaScale'),\n            cfgAtmSkyAlphaScaleRange: document.getElementById('cfg-atmSkyAlphaScaleRange'),\n            cfgAtmSkyAlphaClamp: document.getElementById('cfg-atmSkyAlphaClamp'),\n            cfgAtmSkyAlphaClampRange: document.getElementById('cfg-atmSkyAlphaClampRange'),\n            cfgAtmSkyLimbBoost: document.getElementById('cfg-atmSkyLimbBoost'),\n            cfgAtmSkyLimbBoostRange: document.getElementById('cfg-atmSkyLimbBoostRange'),\n            cfgAtmSkyPathShort: document.getElementById('cfg-atmSkyPathShort'),\n            cfgAtmSkyPathShortRange: document.getElementById('cfg-atmSkyPathShortRange'),\n            cfgAtmSkyLimbMax: document.getElementById('cfg-atmSkyLimbMax'),\n            cfgAtmSkyLimbMaxRange: document.getElementById('cfg-atmSkyLimbMaxRange'),\n            cfgAtmSkyDensityScale: document.getElementById('cfg-atmSkyDensityScale'),\n            cfgAtmSkyDensityScaleRange: document.getElementById('cfg-atmSkyDensityScaleRange'),\n            cfgAtmSkyScaleHeight: document.getElementById('cfg-atmSkyScaleHeight'),\n            cfgAtmSkyScaleHeightRange: document.getElementById('cfg-atmSkyScaleHeightRange'),\n            cfgAtmSkyVerticalFadeStart: document.getElementById('cfg-atmSkyVerticalFadeStart'),\n            cfgAtmSkyVerticalFadeStartRange: document.getElementById('cfg-atmSkyVerticalFadeStartRange'),\n            cfgAtmSkyVerticalFadeEnd: document.getElementById('cfg-atmSkyVerticalFadeEnd'),\n            cfgAtmSkyVerticalFadeEndRange: document.getElementById('cfg-atmSkyVerticalFadeEndRange'),\n            cfgAtmSkyAltitudeFadeStart: document.getElementById('cfg-atmSkyAltitudeFadeStart'),\n            cfgAtmSkyAltitudeFadeStartRange: document.getElementById('cfg-atmSkyAltitudeFadeStartRange'),\n            cfgAtmSkyAltitudeFadeEnd: document.getElementById('cfg-atmSkyAltitudeFadeEnd'),\n            cfgAtmSkyAltitudeFadeEndRange: document.getElementById('cfg-atmSkyAltitudeFadeEndRange'),\n            cfgAtmSkyOutsideFadeStart: document.getElementById('cfg-atmSkyOutsideFadeStart'),\n            cfgAtmSkyOutsideFadeStartRange: document.getElementById('cfg-atmSkyOutsideFadeStartRange'),\n            cfgAtmSkyOutsideFadeEnd: document.getElementById('cfg-atmSkyOutsideFadeEnd'),\n            cfgAtmSkyOutsideFadeEndRange: document.getElementById('cfg-atmSkyOutsideFadeEndRange'),\n            cfgAtmSkyDepthThreshold: document.getElementById('cfg-atmSkyDepthThreshold'),\n            cfgAtmSkyDepthThresholdRange: document.getElementById('cfg-atmSkyDepthThresholdRange'),\n            cfgAtmPhotometric: document.getElementById('cfg-atmPhotometric'),\n            cfgAtmSunIrradiance: document.getElementById('cfg-atmSunIrradiance'),\n            cfgAtmSkyIrradiance: document.getElementById('cfg-atmSkyIrradiance'),\n            cfgAtmTransmittance: document.getElementById('cfg-atmTransmittance'),\n            cfgAtmInscatter: document.getElementById('cfg-atmInscatter'),\n            cfgAtmSky: document.getElementById('cfg-atmSky'),\n            cfgAtmSun: document.getElementById('cfg-atmSun'),\n            cfgAtmMoon: document.getElementById('cfg-atmMoon'),\n            cfgCloudsEnabled: document.getElementById('cfg-cloudsEnabled'),\n            cfgCloudCoverage: document.getElementById('cfg-cloudCoverage'),\n            cfgCloudCoverageRange: document.getElementById('cfg-cloudCoverageRange'),\n            cfgCloudScattering: document.getElementById('cfg-cloudScattering'),\n            cfgCloudScatteringRange: document.getElementById('cfg-cloudScatteringRange'),\n            cfgCloudAbsorption: document.getElementById('cfg-cloudAbsorption'),\n            cfgCloudAbsorptionRange: document.getElementById('cfg-cloudAbsorptionRange'),\n            cfgCloudTurbulenceDisp: document.getElementById('cfg-cloudTurbulenceDisp'),\n            cfgCloudTurbulenceDispRange: document.getElementById('cfg-cloudTurbulenceDispRange'),\n            cfgCloudLightShafts: document.getElementById('cfg-cloudLightShafts'),\n            cfgCloudShapeDetail: document.getElementById('cfg-cloudShapeDetail'),\n            cfgCloudTurbulence: document.getElementById('cfg-cloudTurbulence'),\n            cfgCloudHaze: document.getElementById('cfg-cloudHaze'),\n            cfgCloudLowAltitude: document.getElementById('cfg-cloudLowAltitude'),\n            cfgCloudLowAltitudeRange: document.getElementById('cfg-cloudLowAltitudeRange'),\n            cfgCloudLowHeight: document.getElementById('cfg-cloudLowHeight'),\n            cfgCloudLowHeightRange: document.getElementById('cfg-cloudLowHeightRange'),\n            cfgCloudMidAltitude: document.getElementById('cfg-cloudMidAltitude'),\n            cfgCloudMidAltitudeRange: document.getElementById('cfg-cloudMidAltitudeRange'),\n            cfgCloudMidHeight: document.getElementById('cfg-cloudMidHeight'),\n            cfgCloudMidHeightRange: document.getElementById('cfg-cloudMidHeightRange'),\n            cfgCloudHighAltitude: document.getElementById('cfg-cloudHighAltitude'),\n            cfgCloudHighAltitudeRange: document.getElementById('cfg-cloudHighAltitudeRange'),\n            cfgCloudHighHeight: document.getElementById('cfg-cloudHighHeight'),\n            cfgCloudHighHeightRange: document.getElementById('cfg-cloudHighHeightRange'),\n            cfgAtmosphereEnabled: document.getElementById('cfg-atmosphereEnabled'),\n            cfgWeatherEnabled: document.getElementById('cfg-weatherEnabled'),\n            cfgWeatherAuto: document.getElementById('cfg-weatherAuto'),\n            cfgWeatherRadius: document.getElementById('cfg-weatherRadius'),\n            cfgWeatherRadiusRange: document.getElementById('cfg-weatherRadiusRange'),\n            cfgWeatherInfluence: document.getElementById('cfg-weatherInfluence'),\n            cfgWeatherInfluenceRange: document.getElementById('cfg-weatherInfluenceRange'),\n            cfgWeatherInterval: document.getElementById('cfg-weatherInterval'),\n            cfgWeatherIntervalRange: document.getElementById('cfg-weatherIntervalRange'),\n            cfgWeatherMinDelta: document.getElementById('cfg-weatherMinDelta'),\n            cfgWeatherMinDeltaRange: document.getElementById('cfg-weatherMinDeltaRange'),\n            weatherLocation: document.getElementById('weather-location'),\n            weatherCondition: document.getElementById('weather-condition'),\n            weatherTemp: document.getElementById('weather-temp'),\n            weatherClouds: document.getElementById('weather-clouds'),\n            weatherHumidity: document.getElementById('weather-humidity'),\n            weatherWind: document.getElementById('weather-wind'),\n            weatherPrecip: document.getElementById('weather-precip'),\n            weatherUpdated: document.getElementById('weather-updated'),\n\n            // Debug sign flip testing\n            cfgFlipRotation180: document.getElementById('cfg-flipRotation180'),\n            cfgNegateSunX: document.getElementById('cfg-negateSunX'),\n            cfgNegateSunZ: document.getElementById('cfg-negateSunZ'),\n            cfgInvertFocusDir: document.getElementById('cfg-invertFocusDir'),\n            cfgNegateFocusX: document.getElementById('cfg-negateFocusX'),\n            cfgNegateFocusZ: document.getElementById('cfg-negateFocusZ'),\n            cfgInvertCameraDir: document.getElementById('cfg-invertCameraDir'),\n            cfgInvertCameraPos: document.getElementById('cfg-invertCameraPos'),\n            cfgNegateCamPosX: document.getElementById('cfg-negateCamPosX'),\n            cfgNegateCamPosZ: document.getElementById('cfg-negateCamPosZ'),\n            cfgInvertQuaternion: document.getElementById('cfg-invertQuaternion'),\n            cfgDisableViewportCulling: document.getElementById('cfg-disableViewportCulling'),\n            cfgNeighborDetection: document.getElementById('cfg-neighbor-detection'),\n\n            // Debug\n            debugToggle: document.getElementById('debug-toggle'),\n            debugPanel: document.getElementById('debug-panel')\n        };\n    }\n\n    _registerSettingsSync(handler) {\n        if (typeof handler === 'function') {\n            this._settingsSyncHandlers.push(handler);\n        }\n    }\n\n    syncUIFromSettings() {\n        this._settingsSyncHandlers.forEach(handler => handler());\n    }\n\n    syncLodButtons() {\n        if (typeof this._updateLodButtons === 'function') {\n            this._updateLodButtons();\n        }\n    }\n\n    setLodMode(mode) {\n        if (!this.surfaceController) return;\n        this.surfaceController.setLODMode(mode);\n        this.syncLodButtons();\n    }\n\n    _getSettingValue(path, fallback) {\n        if (!this.settings || !path) return fallback;\n        const value = this.settings.getSection(path);\n        return value === null || value === undefined ? fallback : value;\n    }\n\n    _updateSceneSettings(patch, options) {\n        if (!this.settings || !patch) return false;\n        if (this._bindingSettingsControls) return true;\n        this.settings.updateScene(patch, options);\n        return true;\n    }\n\n    _updateSettings(patch, options) {\n        if (!this.settings || !patch) return false;\n        if (this._bindingSettingsControls) return true;\n        this.settings.update(patch, options);\n        return true;\n    }\n\n    _setInputValue(el, value) {\n        if (!el || value === null || value === undefined) return;\n        el.value = value;\n    }\n\n    _setRangeNumber(rangeEl, numberEl, value) {\n        if (!Number.isFinite(value)) return;\n        if (rangeEl) rangeEl.value = value;\n        if (numberEl) numberEl.value = value;\n    }\n\n    _setChecked(el, value) {\n        if (!el || typeof value !== 'boolean') return;\n        el.checked = value;\n    }\n\n    _resolveNknEnabled() {\n        if (!this.settings) return false;\n        const enabled = this._getSettingValue('nkn.enabled', false);\n        return enabled === true;\n    }\n\n    _getNknSettings() {\n        return this._getSettingValue('nkn', {}) || {};\n    }\n\n    _normalizeNknRpcServerAddr(value) {\n        if (typeof value !== 'string') return '';\n        const text = value.trim();\n        if (!text || !/^https?:\\/\\//i.test(text)) return '';\n        return text.replace(/\\/+$/, '');\n    }\n\n    _buildNknRpcPool(settings = null) {\n        const nknSettings = settings || this._getNknSettings();\n        const configured = [];\n\n        if (Array.isArray(nknSettings.rpcServerAddrs)) {\n            nknSettings.rpcServerAddrs.forEach((addr) => {\n                const normalized = this._normalizeNknRpcServerAddr(addr);\n                if (normalized) configured.push(normalized);\n            });\n        }\n\n        const rawRpcServerAddr = String(nknSettings.rpcServerAddr || '').trim();\n        if (rawRpcServerAddr) {\n            rawRpcServerAddr\n                .split(/[,\\n;]+/)\n                .map((token) => this._normalizeNknRpcServerAddr(token))\n                .filter(Boolean)\n                .forEach((addr) => configured.push(addr));\n        }\n\n        const nextPool = Array.from(new Set(configured.length ? configured : DEFAULT_NKN_RPC_ENDPOINTS));\n        const changed = nextPool.length !== this._nknRpcPool.length\n            || nextPool.some((addr, idx) => addr !== this._nknRpcPool[idx]);\n        if (changed) {\n            this._nknRpcPool = nextPool;\n            this._nknRpcCursor = 0;\n            const allowed = new Set(nextPool);\n            for (const key of this._nknRpcFailures.keys()) {\n                if (!allowed.has(key)) this._nknRpcFailures.delete(key);\n            }\n        }\n        return this._nknRpcPool;\n    }\n\n    _selectNknRpcServer(settings = null) {\n        const pool = this._buildNknRpcPool(settings);\n        if (!pool.length) return '';\n        const now = Date.now();\n\n        for (let i = 0; i < pool.length; i += 1) {\n            const idx = (this._nknRpcCursor + i) % pool.length;\n            const endpoint = pool[idx];\n            const state = this._nknRpcFailures.get(endpoint);\n            if (!state || !Number.isFinite(state.cooldownUntilMs) || state.cooldownUntilMs <= now) {\n                this._nknRpcCursor = (idx + 1) % pool.length;\n                return endpoint;\n            }\n        }\n\n        let bestIdx = this._nknRpcCursor % pool.length;\n        let bestCooldown = Number.POSITIVE_INFINITY;\n        for (let i = 0; i < pool.length; i += 1) {\n            const idx = (this._nknRpcCursor + i) % pool.length;\n            const endpoint = pool[idx];\n            const cooldownUntilMs = this._nknRpcFailures.get(endpoint)?.cooldownUntilMs ?? 0;\n            if (cooldownUntilMs < bestCooldown) {\n                bestCooldown = cooldownUntilMs;\n                bestIdx = idx;\n            }\n        }\n        this._nknRpcCursor = (bestIdx + 1) % pool.length;\n        return pool[bestIdx];\n    }\n\n    _hasHealthyNknRpc(now = Date.now()) {\n        const pool = this._nknRpcPool.length ? this._nknRpcPool : this._buildNknRpcPool();\n        if (!pool.length) return false;\n        return pool.some((endpoint) => {\n            const state = this._nknRpcFailures.get(endpoint);\n            return !state || !Number.isFinite(state.cooldownUntilMs) || state.cooldownUntilMs <= now;\n        });\n    }\n\n    _isNknRpcBootstrapError(err) {\n        const msg = String((err && err.message) || err || '').toLowerCase();\n        const code = String((err && err.code) || '').toLowerCase();\n        return (\n            msg.includes('access-control-allow-origin') ||\n            msg.includes('cors') ||\n            msg.includes('preflight') ||\n            msg.includes('failed to fetch') ||\n            msg.includes('err_failed') ||\n            msg.includes('xmlhttprequest') ||\n            msg.includes('429') ||\n            msg.includes('rate limit') ||\n            msg.includes('403') ||\n            code === '429' ||\n            code === '403'\n        );\n    }\n\n    _markNknRpcFailure(endpoint, err) {\n        if (!endpoint || !this._isNknRpcBootstrapError(err)) return false;\n        const prev = this._nknRpcFailures.get(endpoint) || { failures: 0, cooldownUntilMs: 0 };\n        const failures = Math.min(12, prev.failures + 1);\n        const cooldown = Math.min(\n            this._nknRpcCooldownMaxMs,\n            Math.floor(this._nknRpcCooldownBaseMs * Math.pow(2, failures - 1))\n        );\n        this._nknRpcFailures.set(endpoint, {\n            failures,\n            cooldownUntilMs: Date.now() + cooldown,\n            lastError: String((err && err.message) || err || '')\n        });\n        return true;\n    }\n\n    _markNknRpcSuccess(endpoint) {\n        if (!endpoint) return;\n        this._nknRpcFailures.delete(endpoint);\n    }\n\n    _isNknWebrtcError(err) {\n        const msg = String((err && err.message) || err || '').toLowerCase();\n        return (\n            msg.includes('rtcdatachannel') ||\n            msg.includes('createdatachannel') ||\n            msg.includes('rtcpeerconnection') ||\n            msg.includes('setremotedescription') ||\n            msg.includes('setlocaldescription')\n        );\n    }\n\n    _refreshNknLimits(settings = null) {\n        const nknSettings = settings || this._getNknSettings();\n        if (Number.isFinite(nknSettings.circuitBreakFailures)) {\n            this._nknCircuitThreshold = Math.max(1, Math.floor(nknSettings.circuitBreakFailures));\n        }\n        if (Number.isFinite(nknSettings.cooldownMs)) {\n            this._nknCooldownMs = Math.max(10_000, Math.floor(nknSettings.cooldownMs));\n        }\n        if (Number.isFinite(nknSettings.maxAttemptsPerHour)) {\n            this._nknMaxAttemptsPerWindow = Math.max(1, Math.floor(nknSettings.maxAttemptsPerHour));\n            this._nknAttemptWindowMs = 60 * 60 * 1000;\n        }\n        if (Number.isFinite(nknSettings.webrtcFailureThreshold)) {\n            this._nknWebrtcFailureThreshold = Math.max(1, Math.floor(nknSettings.webrtcFailureThreshold));\n        }\n        if (Number.isFinite(nknSettings.rpcEndpointCooldownBaseMs)) {\n            this._nknRpcCooldownBaseMs = Math.max(5000, Math.floor(nknSettings.rpcEndpointCooldownBaseMs));\n        }\n        if (Number.isFinite(nknSettings.rpcEndpointCooldownMaxMs)) {\n            this._nknRpcCooldownMaxMs = Math.max(this._nknRpcCooldownBaseMs, Math.floor(nknSettings.rpcEndpointCooldownMaxMs));\n        }\n        if (nknSettings.webrtc === false) {\n            this._nknForceNoWebrtc = true;\n        }\n        this._buildNknRpcPool(nknSettings);\n    }\n\n    _setNknState(ok, text) {\n        const key = `${ok ? '1' : '0'}:${text || ''}`;\n        if (key !== this._nknStateKey) {\n            this._nknStateKey = key;\n            this.setConnStatus(ok, text);\n        } else {\n            this.setConnStatus(ok, text);\n        }\n    }\n\n    _clearOldNknAttempts(now = Date.now()) {\n        const cutoff = now - this._nknAttemptWindowMs;\n        this._nknAttemptWindow = this._nknAttemptWindow.filter((ts) => ts >= cutoff);\n    }\n\n    _recordNknAttempt(now = Date.now()) {\n        this._clearOldNknAttempts(now);\n        this._nknAttemptWindow.push(now);\n        return this._nknAttemptWindow.length;\n    }\n\n    _isAttemptLimitReached(now = Date.now()) {\n        this._clearOldNknAttempts(now);\n        return this._nknAttemptWindow.length >= this._nknMaxAttemptsPerWindow;\n    }\n\n    _bindNknGateListeners() {\n        if (!this._nknOnlineListener) {\n            this._nknOnlineListener = () => {\n                if (this._resolveNknEnabled()) {\n                    this.initNKN(this._nknHandleIncoming);\n                }\n            };\n            window.addEventListener('online', this._nknOnlineListener);\n        }\n        if (!this._nknVisibilityListener) {\n            this._nknVisibilityListener = () => {\n                if (document.visibilityState === 'visible' && this._resolveNknEnabled()) {\n                    this.initNKN(this._nknHandleIncoming);\n                }\n            };\n            document.addEventListener('visibilitychange', this._nknVisibilityListener);\n        }\n    }\n\n    _getNknGateState() {\n        const now = Date.now();\n        if (!this._resolveNknEnabled()) {\n            return { blocked: true, reason: 'disabled' };\n        }\n        if (typeof navigator !== 'undefined' && navigator.onLine === false) {\n            return { blocked: true, reason: 'offline' };\n        }\n        if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {\n            return { blocked: true, reason: 'background' };\n        }\n        if (this._nknCooldownUntilMs && now < this._nknCooldownUntilMs) {\n            return { blocked: true, reason: 'cooldown', retryAt: this._nknCooldownUntilMs };\n        }\n        if (this._isAttemptLimitReached(now)) {\n            return { blocked: true, reason: 'attempt-limit' };\n        }\n        return { blocked: false };\n    }\n\n    _isNknFatalError(err) {\n        const msg = String((err && err.message) || err || '').toLowerCase();\n        if (this._isNknRpcBootstrapError(err)) {\n            return true;\n        }\n        if (msg.includes('err_insufficient_resources')) {\n            return true;\n        }\n        if (msg.includes('failed to fetch') && (typeof navigator === 'undefined' || navigator.onLine !== false)) {\n            return true;\n        }\n        return false;\n    }\n\n    _openNknCircuit(reason, cooldownMs = null) {\n        const now = Date.now();\n        const cooldown = Number.isFinite(cooldownMs) ? cooldownMs : this._nknCooldownMs;\n        this._nknCooldownUntilMs = now + cooldown;\n        this._nknFailureCount = 0;\n        this._nknActiveRpcServerAddr = '';\n        if (this._nknReconnectTimer) {\n            clearTimeout(this._nknReconnectTimer);\n            this._nknReconnectTimer = null;\n        }\n        this._setNknState(false, `cooldown (${reason || 'blocked'})`);\n        this._resetNknClient(`cooldown: ${reason || 'blocked'}`, { skipReconnect: true });\n        this._scheduleNknReconnect('cooldown');\n    }\n\n    _handleNknFailure(err, context = '') {\n        const now = Date.now();\n        const attempts = this._recordNknAttempt(now);\n        const fatal = this._isNknFatalError(err);\n        const endpointFailed = this._markNknRpcFailure(this._nknActiveRpcServerAddr, err);\n        this._nknFailureCount += 1;\n        if (this._isNknWebrtcError(err)) {\n            this._nknWebrtcFailureCount += 1;\n            if (this._nknWebrtcFailureCount >= this._nknWebrtcFailureThreshold) {\n                this._nknForceNoWebrtc = true;\n            }\n        }\n\n        if (attempts >= this._nknMaxAttemptsPerWindow) {\n            this._openNknCircuit('attempt limit', this._nknAttemptWindowMs);\n            return;\n        }\n\n        if (endpointFailed && this._hasHealthyNknRpc(now)) {\n            this._scheduleNknReconnect('rpc failover');\n            return;\n        }\n\n        if (fatal || this._nknFailureCount >= this._nknCircuitThreshold) {\n            const reason = fatal\n                ? (endpointFailed ? 'rpc unavailable' : 'bootstrap blocked')\n                : 'failures';\n            this._openNknCircuit(reason);\n            return;\n        }\n\n        this._scheduleNknReconnect(context || 'retry');\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Sidebar\n    // ─────────────────────────────────────────────────────────────\n\n    setupSidebar() {\n        const {\n            sidebar,\n            sidebarToggle,\n            sidebarClose,\n            overlaySidebar,\n            overlayToggle,\n            overlaySidebarClose\n        } = this.elements;\n\n        const bindPanel = (panel, toggle, close) => {\n            if (!panel || !toggle || !close) return () => {};\n            const setOpen = (open) => {\n                panel.classList.toggle('open', open);\n                toggle.classList.toggle('open', open);\n            };\n            toggle.addEventListener('click', () => {\n                setOpen(!panel.classList.contains('open'));\n            });\n            close.addEventListener('click', () => setOpen(false));\n            setOpen(panel.classList.contains('open'));\n            return setOpen;\n        };\n\n        this._setSidebarOpen = bindPanel(sidebar, sidebarToggle, sidebarClose);\n        this._setOverlaySidebarOpen = bindPanel(overlaySidebar, overlayToggle, overlaySidebarClose);\n\n        if (!sidebar) return;\n\n        const groups = Array.from(sidebar.querySelectorAll('.sidebar-group'));\n        const setGroupState = (group, open) => {\n            group.classList.toggle('collapsed', !open);\n            const header = group.querySelector('.sidebar-group-header');\n            if (header) {\n                header.setAttribute('aria-expanded', open ? 'true' : 'false');\n            }\n        };\n\n        groups.forEach(group => {\n            const header = group.querySelector('.sidebar-group-header');\n            if (!header) return;\n            const isCollapsed = group.classList.contains('collapsed');\n            header.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');\n            header.addEventListener('click', () => {\n                const willOpen = group.classList.contains('collapsed');\n                groups.forEach(other => {\n                    if (other !== group) setGroupState(other, false);\n                });\n                setGroupState(group, willOpen ? true : false);\n            });\n        });\n\n        const sections = Array.from(sidebar.querySelectorAll('.sidebar-section'));\n        sections.forEach(section => {\n            const title = section.querySelector('.sidebar-section-title');\n            if (!title) return;\n            const isCollapsed = section.classList.contains('collapsed');\n            title.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');\n            title.addEventListener('click', (e) => {\n                e.stopPropagation();\n                const willOpen = section.classList.contains('collapsed');\n                section.classList.toggle('collapsed', !willOpen);\n                title.setAttribute('aria-expanded', willOpen ? 'true' : 'false');\n            });\n        });\n    }\n\n    setupSettingsControls() {\n        const { settingsFile, settingsDownload, settingsReset, settingsStatus } = this.elements;\n        if (!this.settings) return;\n\n        const setStatus = (message) => {\n            if (settingsStatus) settingsStatus.textContent = message;\n        };\n\n        if (settingsFile) {\n            settingsFile.addEventListener('change', async (event) => {\n                const file = event.target?.files?.[0];\n                if (!file) return;\n                try {\n                    const text = await file.text();\n                    this.settings.import(text);\n                    this.syncUIFromSettings();\n                    setStatus(`Imported ${file.name}`);\n                } catch (error) {\n                    console.warn('[Settings] Import failed', error);\n                    setStatus('Import failed');\n                } finally {\n                    settingsFile.value = '';\n                }\n            });\n        }\n\n        if (settingsDownload) {\n            settingsDownload.addEventListener('click', () => {\n                const data = this.settings.export();\n                const blob = new Blob([data], { type: 'application/json' });\n                const url = URL.createObjectURL(blob);\n                const link = document.createElement('a');\n                link.href = url;\n                link.download = 'scene-settings.json';\n                document.body.appendChild(link);\n                link.click();\n                link.remove();\n                URL.revokeObjectURL(url);\n                setStatus('Downloaded settings JSON');\n            });\n        }\n\n        if (settingsReset) {\n            settingsReset.addEventListener('click', () => {\n                this.settings.reset();\n                this.syncUIFromSettings();\n                setStatus('Reset to defaults');\n            });\n        }\n    }\n\n    setupUrlStateSync() {\n        // ── DISABLED: superseded by PlanetScene._setupUrlStateSync ─────\n        //\n        // This method historically wired its own `_updateUrlFromView`\n        // to `controls.change`. PlanetScene now does the same wiring\n        // (see refactor/scene/PlanetScene.js#_setupUrlStateSync) — both\n        // listeners firing on the same event was the \"two systems\n        // fighting\" the user observed: each ran its own altitude\n        // formula and wrote conflicting `altitude=` values to the URL,\n        // and the legacy ui-controller writer had no bounds check so it\n        // could serialize meaningless negatives like `altitude=-6266732`\n        // when the camera's parent (vrDolly) drifted off origin.\n        //\n        // Kept as a no-op so external callers don't crash. The\n        // `_throttledUpdateUrlState` reference is left undefined; any\n        // code that invokes it should fall through to PlanetScene's\n        // canonical writer instead.\n        return;\n    }\n\n    openSidebar() {\n        if (this._setSidebarOpen) {\n            this._setSidebarOpen(true);\n            return;\n        }\n        this.elements.sidebar?.classList.add('open');\n        this.elements.sidebarToggle?.classList.add('open');\n    }\n\n    closeSidebar() {\n        if (this._setSidebarOpen) {\n            this._setSidebarOpen(false);\n            return;\n        }\n        this.elements.sidebar?.classList.remove('open');\n        this.elements.sidebarToggle?.classList.remove('open');\n    }\n\n    openOverlaySidebar() {\n        if (this._setOverlaySidebarOpen) {\n            this._setOverlaySidebarOpen(true);\n            return;\n        }\n        this.elements.overlaySidebar?.classList.add('open');\n        this.elements.overlayToggle?.classList.add('open');\n    }\n\n    closeOverlaySidebar() {\n        if (this._setOverlaySidebarOpen) {\n            this._setOverlaySidebarOpen(false);\n            return;\n        }\n        this.elements.overlaySidebar?.classList.remove('open');\n        this.elements.overlayToggle?.classList.remove('open');\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // NKN Status & Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setSDKStatus(ok, text) {\n        const { sdkStatusEl } = this.elements;\n        if (ok) {\n            sdkStatusEl.innerHTML = '<span class=\"ok\">' + (text || 'nkn-sdk loaded') + '</span>';\n        } else {\n            sdkStatusEl.innerHTML = '<span class=\"bad\">' + (text || 'nkn-sdk not loaded') + '</span>';\n        }\n    }\n\n    setConnStatus(ok, text) {\n        const { connStatusEl } = this.elements;\n        if (ok) {\n            connStatusEl.innerHTML = '<span class=\"ok\">' + (text || 'connected') + '</span>';\n        } else {\n            connStatusEl.innerHTML = '<span class=\"bad\">' + (text || 'not connected') + '</span>';\n        }\n    }\n\n    setNknEnabled(enabled) {\n        const next = !!enabled;\n        if (this._nknEnabled === next) return;\n        this._nknEnabled = next;\n        if (!next) {\n            this._disableNkn();\n            return;\n        }\n        if (this._nknHandleIncoming) {\n            this.initNKN(this._nknHandleIncoming);\n        }\n    }\n\n    _disableNkn() {\n        if (this._nknInitTimer) {\n            clearTimeout(this._nknInitTimer);\n            this._nknInitTimer = null;\n        }\n        if (this._nknReconnectTimer) {\n            clearTimeout(this._nknReconnectTimer);\n            this._nknReconnectTimer = null;\n        }\n        this._nknInitAttempts = 0;\n        this._nknConnectGeneration += 1;\n        this._nknBackoffMs = 1000;\n        this._nknBackoffBaseMs = 15000;\n        this._nknFailureCount = 0;\n        this._nknCooldownUntilMs = 0;\n        this._nknAttemptWindow = [];\n        this._nknRpcPool = [];\n        this._nknRpcFailures.clear();\n        this._nknRpcCursor = 0;\n        this._nknActiveRpcServerAddr = '';\n        this._nknWebrtcFailureCount = 0;\n        this._nknForceNoWebrtc = false;\n        this._nknConnectInFlight = false;\n        this._nknConnectPromise = null;\n        this._nknConnectResolve = null;\n        this._nknConnectReject = null;\n        try {\n            if (this.multiClient && typeof this.multiClient.close === 'function') {\n                this.multiClient.close();\n            }\n        } catch {\n            // ignore\n        }\n        this.multiClient = null;\n        if (this.elevationClient?.setMultiClient) {\n            this.elevationClient.setMultiClient(null);\n        }\n        if (this.elevationClient?.setNknErrorHandler) {\n            this.elevationClient.setNknErrorHandler(null);\n        }\n        if (this.elements.myAddrEl) {\n            this.elements.myAddrEl.textContent = 'disabled';\n        }\n        this.setSDKStatus(false, 'nkn disabled');\n        this.setConnStatus(false, 'disabled');\n    }\n\n    setupNKNControls() {\n        const { relayEl, datasetEl } = this.elements;\n        if (!relayEl || !datasetEl) return;\n\n        const syncFromSettings = () => {\n            this.setNknEnabled(this._resolveNknEnabled());\n            const nknSettings = this._getSettingValue('nkn', {}) || {};\n            const relayValue = (nknSettings.relay ?? localStorage.getItem(this.LS_RELAY) ?? DEFAULT_FORWARDER);\n            const datasetValue = (nknSettings.dataset ?? localStorage.getItem(this.LS_DATASET) ?? 'mapzen');\n            const relay = String(relayValue).trim() || DEFAULT_FORWARDER;\n            const dataset = String(datasetValue).trim() || 'mapzen';\n            relayEl.value = relay;\n            datasetEl.value = dataset;\n            this.elevationClient.setRelayAndDataset(relay, dataset);\n        };\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n\n        const updateRelayDataset = () => {\n            const relay = relayEl.value.trim() || DEFAULT_FORWARDER;\n            const dataset = datasetEl.value.trim() || 'mapzen';\n            relayEl.value = relay;\n            this._updateSettings({ nkn: { relay, dataset } }, { apply: false });\n            localStorage.setItem(this.LS_RELAY, relay);\n            localStorage.setItem(this.LS_DATASET, dataset);\n            this.elevationClient.setRelayAndDataset(relay, dataset);\n        };\n\n        relayEl.addEventListener('input', updateRelayDataset);\n        relayEl.addEventListener('change', updateRelayDataset);\n        datasetEl.addEventListener('input', updateRelayDataset);\n        datasetEl.addEventListener('change', updateRelayDataset);\n        updateRelayDataset();\n    }\n\n    _normalizeNknSeed(raw) {\n        if (raw === null || raw === undefined) return null;\n        const text = String(raw).trim().toLowerCase();\n        if (!text) return null;\n        const cleaned = text.startsWith('0x') ? text.slice(2) : text;\n        if (/^[0-9a-f]{64}$/.test(cleaned)) return cleaned;\n        return null;\n    }\n\n    _loadScriptOnce(src, id) {\n        if (typeof document === 'undefined') {\n            return Promise.reject(new Error('document not available'));\n        }\n        const selector = id ? `script[data-sdk=\"${id}\"]` : `script[src=\"${src}\"]`;\n        const existing = document.querySelector(selector);\n        if (existing) {\n            if (existing.dataset.loaded === 'true') return Promise.resolve();\n            if (existing.dataset.failed === 'true') {\n                existing.remove();\n            } else {\n            return new Promise((resolve, reject) => {\n                existing.addEventListener('load', () => resolve(), { once: true });\n                existing.addEventListener('error', () => reject(new Error(`Failed to load ${src}`)), { once: true });\n            });\n            }\n        }\n        return new Promise((resolve, reject) => {\n            const script = document.createElement('script');\n            script.src = src;\n            script.async = true;\n            if (id) script.dataset.sdk = id;\n            script.addEventListener('load', () => {\n                script.dataset.loaded = 'true';\n                resolve();\n            }, { once: true });\n            script.addEventListener('error', () => {\n                script.dataset.failed = 'true';\n                reject(new Error(`Failed to load ${src}`));\n            }, { once: true });\n            document.head.appendChild(script);\n        });\n    }\n\n    _loadNknSdk() {\n        if (this._nknSdk) return Promise.resolve(this._nknSdk);\n        if (this._nknSdkPromise) return this._nknSdkPromise;\n        this._nknSdkPromise = (async () => {\n            if (window.nkn && window.nkn.MultiClient) {\n                return window.nkn;\n            }\n            if (typeof globalThis.Buffer === 'undefined') {\n                const { Buffer } = await import('buffer');\n                globalThis.Buffer = Buffer;\n            }\n            const nknSdkUrls = [\n                'https://cdn.jsdelivr.net/npm/nkn-sdk@1.3.6/dist/nkn.min.js',\n                '/refactor/vendor/nkn-sdk/nkn.min.js',\n                '/vendor/nkn-sdk/nkn.min.js'\n            ];\n            let lastError = null;\n            for (const url of nknSdkUrls) {\n                try {\n                    await this._loadScriptOnce(url, 'nkn-sdk');\n                    lastError = null;\n                    break;\n                } catch (loadErr) {\n                    lastError = loadErr;\n                }\n            }\n            if (lastError) throw lastError;\n            const sdk = window.nkn;\n            if (!sdk || !sdk.MultiClient) {\n                throw new Error('nkn-sdk missing MultiClient');\n            }\n            if (typeof sdk.setDisableWASM === 'function') {\n                sdk.setDisableWASM(true);\n            }\n            // Silence all console output originating from nkn.min.js —\n            // the SDK spams reconnect/timeout/RPC errors every few seconds\n            // which hammers the console and degrades page performance.\n            if (!window.__nknConsoleMuted) {\n                window.__nknConsoleMuted = true;\n                const nknPattern = /nkn\\.min\\.js|nkn-sdk/;\n                const nknTextPattern = /(nkn|rpc call failed|client connect failed|reconnecting in|rtcpeerconnection|rtcdatachannel|signalingstate|createdatachannel|getwsaddr|getwssaddr)/i;\n                const lastByMethod = new Map();\n                for (const method of ['log', 'warn', 'error', 'info', 'debug']) {\n                    const orig = console[method];\n                    console[method] = function (...args) {\n                        try {\n                            const stack = new Error().stack || '';\n                            if (nknPattern.test(stack)) return;\n                            const text = args.map((arg) => String(arg?.message || arg || '')).join(' ');\n                            if (nknTextPattern.test(text)) {\n                                const now = Date.now();\n                                const key = `${method}:${text.slice(0, 120)}`;\n                                const last = lastByMethod.get(key) || 0;\n                                if (now - last < 60_000) return;\n                                lastByMethod.set(key, now);\n                            }\n                        } catch {}\n                        return orig.apply(console, args);\n                    };\n                }\n            }\n            return sdk;\n        })()\n            .then((sdk) => {\n                this._nknSdk = sdk;\n                this._nknSdkPromise = null;\n                return sdk;\n            })\n            .catch((err) => {\n                this._nknSdkPromise = null;\n                throw err;\n            });\n        return this._nknSdkPromise;\n    }\n\n    _getOrCreateNknSeed() {\n        const key = this.LS_NKN_SEED;\n        const settingsSeed = this._getSettingValue('nkn.seed', null);\n        let storedSeed = null;\n        try {\n            storedSeed = localStorage.getItem(key);\n        } catch {\n            storedSeed = null;\n        }\n        const normalized = this._normalizeNknSeed(settingsSeed)\n            || this._normalizeNknSeed(storedSeed);\n        if (normalized) {\n            if (normalized !== storedSeed) {\n                try { localStorage.setItem(key, normalized); } catch { /* ignore */ }\n            }\n            if (normalized !== settingsSeed) {\n                this._updateSettings({ nkn: { seed: normalized } }, { apply: false });\n            }\n            return normalized;\n        }\n        try {\n            const arr = new Uint8Array(32);\n            if (window.crypto && window.crypto.getRandomValues) {\n                window.crypto.getRandomValues(arr);\n            } else {\n                for (let i = 0; i < arr.length; i++) {\n                    arr[i] = Math.floor(Math.random() * 256);\n                }\n            }\n            const hex = Array.from(arr, b => b.toString(16).padStart(2, '0')).join('');\n            try { localStorage.setItem(key, hex); } catch { /* ignore */ }\n            this._updateSettings({ nkn: { seed: hex } }, { apply: false });\n            return hex;\n        } catch (error) {\n            const arr = new Uint8Array(32);\n            if (window.crypto && window.crypto.getRandomValues) {\n                window.crypto.getRandomValues(arr);\n            } else {\n                for (let i = 0; i < arr.length; i++) {\n                    arr[i] = Math.floor(Math.random() * 256);\n                }\n            }\n            const hex = Array.from(arr, b => b.toString(16).padStart(2, '0')).join('');\n            try { localStorage.setItem(key, hex); } catch { /* ignore */ }\n            this._updateSettings({ nkn: { seed: hex } }, { apply: false });\n            return hex;\n        }\n    }\n\n    _isRetryableNknError(err) {\n        const msg = String((err && err.message) || err || '').toLowerCase();\n        return (\n            msg.includes('message timeout') ||\n            msg.includes('failed to send') ||\n            msg.includes('timeout') ||\n            msg.includes('readystate is not') ||\n            msg.includes('rtcdatachannel')\n        );\n    }\n\n    _scheduleNknReconnect(reason = '') {\n        if (!this._resolveNknEnabled()) {\n            this._disableNkn();\n            return;\n        }\n        if (this._nknReconnectTimer) return;\n\n        const gate = this._getNknGateState();\n        if (gate.blocked) {\n            if (gate.reason === 'attempt-limit') {\n                this._openNknCircuit('attempt limit', this._nknAttemptWindowMs);\n                return;\n            }\n            this._bindNknGateListeners();\n            if (gate.reason === 'cooldown' && gate.retryAt) {\n                const delay = Math.max(0, gate.retryAt - Date.now());\n                this._setNknState(false, 'cooldown');\n                this._nknReconnectTimer = setTimeout(() => {\n                    this._nknReconnectTimer = null;\n                    if (this._nknHandleIncoming) {\n                        this.initNKN(this._nknHandleIncoming);\n                    }\n                }, delay);\n                return;\n            }\n            const label = gate.reason === 'offline'\n                ? 'offline'\n                : (gate.reason === 'background' ? 'background' : 'cooldown');\n            this._setNknState(false, label);\n            return;\n        }\n\n        const baseDelay = this._nknBackoffMs;\n        const jitter = baseDelay * 0.25 * (Math.random() * 2 - 1);\n        const delay = Math.max(0, Math.floor(baseDelay + jitter));\n        this._nknBackoffMs = Math.min(this._nknBackoffMs * 1.5, this._nknMaxBackoffMs);\n        const label = reason ? `reconnecting… ${reason}` : 'reconnecting…';\n        this._setNknState(false, label);\n        this._nknReconnectTimer = setTimeout(() => {\n            this._nknReconnectTimer = null;\n            if (this._nknHandleIncoming) {\n                this.initNKN(this._nknHandleIncoming);\n            }\n        }, delay);\n    }\n\n    _resetNknClient(reason = '', { skipReconnect = false } = {}) {\n        this._nknConnectGeneration += 1;\n        try {\n            if (this.multiClient && typeof this.multiClient.close === 'function') {\n                this.multiClient.close();\n            }\n        } catch (_) {\n            // ignore\n        }\n        this.multiClient = null;\n        this._nknConnectInFlight = false;\n        this._nknConnectPromise = null;\n        this._nknConnectResolve = null;\n        this._nknConnectReject = null;\n        if (this.elements.myAddrEl) {\n            this.elements.myAddrEl.textContent = '...';\n        }\n        if (this.elevationClient) {\n            this.elevationClient.setMultiClient(null);\n        }\n        if (!this._resolveNknEnabled()) {\n            this._disableNkn();\n            return;\n        }\n        if (!skipReconnect) {\n            this._scheduleNknReconnect(reason);\n        }\n    }\n\n    _handleNknSendError(err) {\n        if (!this._isRetryableNknError(err)) return;\n        const msg = err && err.message ? err.message : String(err || 'send failed');\n        this._resetNknClient(`send failed: ${msg}`, { skipReconnect: true });\n        this._handleNknFailure(err, 'send failed');\n    }\n\n    initNKN(handleIncoming) {\n        if (handleIncoming) {\n            this._nknHandleIncoming = handleIncoming;\n        }\n        const nknEnabled = this._resolveNknEnabled();\n        this._nknEnabled = nknEnabled;\n        if (!nknEnabled) {\n            this._disableNkn();\n            return;\n        }\n        this._bindNknGateListeners();\n\n        const nknSettings = this._getNknSettings();\n        this._refreshNknLimits(nknSettings);\n\n        const gate = this._getNknGateState();\n        if (gate.blocked) {\n            if (gate.reason === 'attempt-limit') {\n                this._openNknCircuit('attempt limit', this._nknAttemptWindowMs);\n                return;\n            }\n            this._scheduleNknReconnect(gate.reason);\n            return;\n        }\n        if (this._nknConnectInFlight || this._nknConnectPromise) {\n            return this._nknConnectPromise;\n        }\n        if (this.multiClient) return;\n\n        if (this.elevationClient?.setNknErrorHandler) {\n            this.elevationClient.setNknErrorHandler((err) => this._handleNknSendError(err));\n        }\n        let sdk = this._nknSdk;\n        if (!sdk && window.nkn && window.nkn.MultiClient) {\n            sdk = window.nkn;\n        }\n        if (!sdk) {\n            this.setSDKStatus(false, 'loading nkn-sdk…');\n            if (!this._nknSdkPromise) {\n                this._loadNknSdk()\n                    .then(() => this.initNKN(handleIncoming))\n                    .catch((err) => {\n                        console.error('NKN SDK load error', err);\n                        this.setSDKStatus(false, 'nkn-sdk load failed');\n                    });\n            }\n            if (!this._nknInitTimer && this._nknInitAttempts < this._nknInitMaxAttempts) {\n                this._nknInitAttempts += 1;\n                this._nknInitTimer = setTimeout(() => {\n                    this._nknInitTimer = null;\n                    this.initNKN(handleIncoming);\n                }, this._nknInitRetryMs);\n            }\n            return;\n        }\n        this.setSDKStatus(true, 'nkn-sdk loaded');\n        this._nknInitAttempts = 0;\n        if (!this._nknSdk && sdk) {\n            this._nknSdk = sdk;\n        }\n\n        const seed = this._getOrCreateNknSeed();\n        const rpcServerAddr = this._selectNknRpcServer(nknSettings);\n        const configuredWebrtc = (typeof nknSettings.webrtc === 'boolean') ? nknSettings.webrtc : undefined;\n        const webrtc = (configuredWebrtc === false || this._nknForceNoWebrtc) ? false : configuredWebrtc;\n        const tls = (typeof nknSettings.tls === 'boolean') ? nknSettings.tls : undefined;\n        const minReconnectMs = Number.isFinite(nknSettings.reconnectIntervalMinMs)\n            ? Math.max(5000, Math.floor(nknSettings.reconnectIntervalMinMs))\n            : 15000;\n        const maxReconnectMs = Number.isFinite(nknSettings.reconnectIntervalMaxMs)\n            ? Math.max(minReconnectMs, Math.floor(nknSettings.reconnectIntervalMaxMs))\n            : 600000;\n        const numSubClients = Number.isFinite(nknSettings.numSubClients)\n            ? Math.max(1, Math.floor(nknSettings.numSubClients))\n            : 1;\n\n        this._nknBackoffMs = Math.max(this._nknBackoffMs, minReconnectMs);\n        this._nknMaxBackoffMs = Math.max(maxReconnectMs, this._nknBackoffMs);\n        this._nknBackoffBaseMs = minReconnectMs;\n\n        const generation = ++this._nknConnectGeneration;\n        this._nknConnectInFlight = true;\n        this._nknActiveRpcServerAddr = rpcServerAddr || '';\n        this._recordNknAttempt();\n        if (!this._nknConnectPromise) {\n            this._nknConnectPromise = new Promise((resolve, reject) => {\n                this._nknConnectResolve = resolve;\n                this._nknConnectReject = reject;\n            });\n        }\n\n        let client = null;\n        try {\n            client = new sdk.MultiClient({\n                identifier: 'earth',\n                numSubClients,\n                originalClient: false,\n                seed,\n                rpcServerAddr,\n                webrtc,\n                tls,\n                msgCacheSize: 2048,\n                msgCacheExpiration: 300000,\n                msgHoldingSeconds: 60,\n                reconnectIntervalMin: minReconnectMs,\n                reconnectIntervalMax: maxReconnectMs,\n                responseTimeout: 15000\n            });\n            if (generation !== this._nknConnectGeneration) {\n                try { client.close?.(); } catch { /* ignore */ }\n                return;\n            }\n            this.multiClient = client;\n        } catch (e) {\n            this.setConnStatus(false, 'failed to create MultiClient');\n            console.error('NKN init error', e);\n            this._nknConnectInFlight = false;\n            if (this._nknConnectReject) {\n                this._nknConnectReject(e);\n            }\n            this._nknConnectPromise = null;\n            this._nknConnectResolve = null;\n            this._nknConnectReject = null;\n            this._handleNknFailure(e, 'create client');\n            return;\n        }\n\n        this.elements.myAddrEl.textContent = '…';\n        this._setNknState(false, 'connecting…');\n        try {\n            const cachedAddr = localStorage.getItem(this.LS_NKN_ADDR);\n            if (cachedAddr) this.elements.myAddrEl.textContent = cachedAddr;\n        } catch {\n            // ignore\n        }\n\n        const connectFailed = (err) => {\n            if (generation !== this._nknConnectGeneration || this.multiClient !== client) {\n                try { client?.close?.(); } catch { /* ignore */ }\n                return;\n            }\n            const msg = err && err.message ? err.message : String(err || 'connect failed');\n            if (this._nknConnectReject) {\n                this._nknConnectReject(err);\n            }\n            this._nknConnectPromise = null;\n            this._nknConnectResolve = null;\n            this._nknConnectReject = null;\n            this._resetNknClient(`connect failed: ${msg}`, { skipReconnect: true });\n            this._handleNknFailure(err, 'connect failed');\n        };\n        if (typeof client.onConnectFailed === 'function') {\n            client.onConnectFailed(connectFailed);\n        } else if (typeof client.on === 'function') {\n            client.on('connectFailed', connectFailed);\n            client.on('error', connectFailed);\n        }\n\n        client.onConnect(() => {\n            if (generation !== this._nknConnectGeneration || this.multiClient !== client) {\n                try { client.close?.(); } catch { /* ignore */ }\n                return;\n            }\n            this.elements.myAddrEl.textContent = client.addr;\n            this._setNknState(true, 'connected');\n            this.elevationClient.setMultiClient(client);\n            this._nknBackoffMs = this._nknBackoffBaseMs;\n            this._markNknRpcSuccess(this._nknActiveRpcServerAddr);\n            this._nknWebrtcFailureCount = 0;\n            if (this._nknReconnectTimer) {\n                clearTimeout(this._nknReconnectTimer);\n                this._nknReconnectTimer = null;\n            }\n            this._nknFailureCount = 0;\n            this._nknAttemptWindow = [];\n            this._nknConnectInFlight = false;\n            if (this._nknConnectResolve) {\n                this._nknConnectResolve(client);\n            }\n            this._nknConnectPromise = null;\n            this._nknConnectResolve = null;\n            this._nknConnectReject = null;\n            try { localStorage.setItem(this.LS_NKN_ADDR, client.addr); } catch { /* ignore */ }\n            try {\n                const addrInput = document.querySelector('input[data-setting=\"nknAddress\"]');\n                if (addrInput) addrInput.value = client.addr;\n            } catch {\n                // ignore\n            }\n            if (this.eventBus?.emit) {\n                this.eventBus.emit('nkn:connected', { address: client.addr });\n            }\n            console.log('✅ NKN connected as', client.addr);\n            if (this.surfaceController?.isInSurfaceMode?.()) {\n                this.handleSurfaceEnter({ reason: 'nkn-connect' });\n            }\n        });\n\n        client.onMessage(({ src, payload }) => {\n            if (generation !== this._nknConnectGeneration || this.multiClient !== client) return;\n            handleIncoming(src, payload);\n        });\n        return this._nknConnectPromise;\n    }\n\n    handleSurfaceEnter({ reason = '' } = {}) {\n        if (!this.elevationClient) return;\n        const relay = this.elements.relayEl?.value?.trim()\n            || localStorage.getItem(this.LS_RELAY)\n            || DEFAULT_FORWARDER;\n        const dataset = this.elements.datasetEl?.value?.trim()\n            || localStorage.getItem(this.LS_DATASET)\n            || 'mapzen';\n        this.elevationClient.setRelayAndDataset(relay, dataset);\n        if (this.multiClient) {\n            this.elevationClient.setMultiClient(this.multiClient);\n        }\n        if (typeof this.elevationClient.kickSurfaceMode === 'function') {\n            this.elevationClient.kickSurfaceMode();\n        } else if (typeof this.elevationClient.clearPendingRequests === 'function') {\n            this.elevationClient.clearPendingRequests();\n        }\n        if (typeof this.elevationClient.tick === 'function') {\n            this.elevationClient.tick();\n        }\n        if (reason) {\n            console.log(`[elev] surface fetch kick (${reason})`);\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Elevation Config\n    // ─────────────────────────────────────────────────────────────\n\n    setupElevationControls() {\n        const {\n            cfgBatchSize,\n            cfgBatchSizeRange,\n            cfgMaxConcurrent,\n            cfgMaxConcurrentRange,\n            cfgMinInterval,\n            cfgMinIntervalRange,\n            cfgMaxKBPerMin,\n            cfgMaxKBPerMinRange,\n            cfgMaxVertexRecords,\n            cfgMaxVertexRecordsRange,\n            cfgElevSurfaceMaxLod,\n            cfgElevSurfaceMaxLodRange,\n            cfgElevSurfaceFalloff,\n            cfgElevSurfaceFalloffRange,\n            cfgSurfaceStageMinLOD,\n            cfgSurfaceStageMinLODRange,\n            cfgSurfaceStageMaxLOD,\n            cfgSurfaceStageMaxLODRange,\n            cfgSurfaceLodNear,\n            cfgSurfaceLodNearRange,\n            cfgSurfaceLodFar,\n            cfgSurfaceLodFarRange,\n            cfgSurfaceLodFalloff,\n            cfgSurfaceLodFalloffRange,\n            cfgSurfaceLodStart,\n            cfgSurfaceLodStartRange,\n            cfgSurfaceStageCooldown,\n            cfgSurfaceStageCooldownRange,\n            cfgSurfaceCullAngle,\n            cfgSurfaceCullAngleRange,\n            cfgOrbitFalloffMargin,\n            cfgOrbitFalloffMarginRange,\n            cfgOrbitFalloffAnchor,\n            cfgOrbitFalloffAnchorRange,\n            cfgOrbitLodFalloff,\n            cfgOrbitLodFalloffRange,\n            cfgElevAngleLimit,\n            cfgElevAngleLimitRange,\n            cfgElevSurfaceMinLevel,\n            cfgElevSurfaceMinLevelRange,\n            cfgElevRingNearKm,\n            cfgElevRingNearKmRange,\n            cfgElevRingMidKm,\n            cfgElevRingMidKmRange,\n            cfgElevRingBudgetNear,\n            cfgElevRingBudgetNearRange,\n            cfgElevRingBudgetMid,\n            cfgElevRingBudgetMidRange,\n            cfgElevQueueResetKm,\n            cfgElevQueueResetKmRange,\n            cfgElevQueueResetAngle,\n            cfgElevQueueResetAngleRange\n        } = this.elements;\n\n        const readNumber = (el, fallback) => {\n            if (!el) return fallback;\n            const num = parseFloat(el.value);\n            return Number.isFinite(num) ? num : fallback;\n        };\n\n        const syncFromSettings = () => {\n            const elevation = this._getSettingValue('scene.terrain.elevation', {}) || {};\n            const staging = this._getSettingValue('scene.terrain.surface.staging', {}) || {};\n            const falloff = this._getSettingValue('scene.terrain.surface.falloff', {}) || {};\n            const orbitFalloff = this._getSettingValue('scene.terrain.orbit.falloff', {}) || {};\n\n            const batchSize = Number.isFinite(elevation.batchSize)\n                ? elevation.batchSize\n                : (this.elevationClient?.batchSize ?? readNumber(cfgBatchSize, 256));\n            const maxConcurrent = Number.isFinite(elevation.maxConcurrent)\n                ? elevation.maxConcurrent\n                : (this.elevationClient?.maxConcurrentBatches ?? readNumber(cfgMaxConcurrent, 8));\n            const minInterval = Number.isFinite(elevation.minIntervalMs)\n                ? elevation.minIntervalMs\n                : (this.elevationClient?.minIntervalMs ?? readNumber(cfgMinInterval, 50));\n            const maxKB = Number.isFinite(elevation.maxKBPerMinute)\n                ? elevation.maxKBPerMinute\n                : (this.elevationClient?.maxKBPerMinute ?? readNumber(cfgMaxKBPerMin, 0));\n            const maxVertexRecords = Number.isFinite(elevation.maxVertexRecords)\n                ? elevation.maxVertexRecords\n                : (this.elevationClient?.maxVertexRecords ?? readNumber(cfgMaxVertexRecords, 400000));\n            const elevAngleLimit = Number.isFinite(elevation.angleLimitDeg)\n                ? elevation.angleLimitDeg\n                : (this.elevationClient?.angleLimitDeg ?? readNumber(cfgElevAngleLimit, 80));\n            const elevSurfaceMinLevel = Number.isFinite(elevation.surfaceMinLevel)\n                ? elevation.surfaceMinLevel\n                : (this.elevationClient?.surfaceMinLevel ?? readNumber(cfgElevSurfaceMinLevel, 1));\n            const ringNearMeters = Number.isFinite(elevation.ringNearMeters)\n                ? elevation.ringNearMeters\n                : (this.elevationClient?.ringNearMeters ?? 10000);\n            const ringMidMeters = Number.isFinite(elevation.ringMidMeters)\n                ? elevation.ringMidMeters\n                : (this.elevationClient?.ringMidMeters ?? 40000);\n            const ringNearKm = ringNearMeters / 1000;\n            const ringMidKm = ringMidMeters / 1000;\n            const ringBudgetNear = Number.isFinite(elevation.ringBudgetNear)\n                ? elevation.ringBudgetNear\n                : ((this.elevationClient?.ringBudgetWeights?.near ?? 0.6) * 100);\n            const ringBudgetMid = Number.isFinite(elevation.ringBudgetMid)\n                ? elevation.ringBudgetMid\n                : ((this.elevationClient?.ringBudgetWeights?.mid ?? 0.25) * 100);\n            const queueResetMeters = Number.isFinite(elevation.queueResetDistanceM)\n                ? elevation.queueResetDistanceM\n                : (this.triTree?.elevationQueueResetDistance ?? 200000);\n            const queueResetAngle = Number.isFinite(elevation.queueResetAngleDeg)\n                ? elevation.queueResetAngleDeg\n                : (this.triTree?.elevationQueueResetAngleDeg ?? 8);\n            const queueResetKm = queueResetMeters / 1000;\n\n            const surfaceStageMinLOD = Number.isFinite(staging.minLOD)\n                ? staging.minLOD\n                : readNumber(cfgSurfaceStageMinLOD, 6);\n            const surfaceStageMaxLOD = Number.isFinite(staging.maxLOD)\n                ? staging.maxLOD\n                : readNumber(cfgSurfaceStageMaxLOD, 15);\n            const surfaceStageCooldown = Number.isFinite(staging.cooldownMs)\n                ? staging.cooldownMs\n                : readNumber(cfgSurfaceStageCooldown, 750);\n            const surfaceCullAngle = Number.isFinite(staging.cullAngleDeg)\n                ? staging.cullAngleDeg\n                : readNumber(cfgSurfaceCullAngle, 50);\n\n            const surfaceLodNear = Number.isFinite(falloff.nearLOD)\n                ? falloff.nearLOD\n                : readNumber(cfgSurfaceLodNear, 15);\n            const surfaceLodFar = Number.isFinite(falloff.farLOD)\n                ? falloff.farLOD\n                : readNumber(cfgSurfaceLodFar, 6);\n            const surfaceLodFalloff = Number.isFinite(falloff.power)\n                ? falloff.power\n                : readNumber(cfgSurfaceLodFalloff, 0.8);\n            const surfaceLodStart = Number.isFinite(falloff.startDeg)\n                ? falloff.startDeg\n                : readNumber(cfgSurfaceLodStart, 0.5);\n\n            const orbitFalloffMargin = Number.isFinite(orbitFalloff.marginDeg)\n                ? orbitFalloff.marginDeg\n                : (this.triTree?.orbitFalloffMarginDeg ?? readNumber(cfgOrbitFalloffMargin, 6));\n            const orbitFalloffAnchor = Number.isFinite(orbitFalloff.anchorDeg)\n                ? orbitFalloff.anchorDeg\n                : (this.triTree?.orbitFalloffAnchorDeg ?? readNumber(cfgOrbitFalloffAnchor, 65));\n            const orbitLodFalloff = Number.isFinite(orbitFalloff.power)\n                ? orbitFalloff.power\n                : (this.triTree?.orbitLodFalloffPower ?? readNumber(cfgOrbitLodFalloff, 1));\n\n            this._setRangeNumber(cfgBatchSizeRange, cfgBatchSize, batchSize);\n            this._setRangeNumber(cfgMaxConcurrentRange, cfgMaxConcurrent, maxConcurrent);\n            this._setRangeNumber(cfgMinIntervalRange, cfgMinInterval, minInterval);\n            this._setRangeNumber(cfgMaxKBPerMinRange, cfgMaxKBPerMin, maxKB);\n            this._setRangeNumber(cfgMaxVertexRecordsRange, cfgMaxVertexRecords, maxVertexRecords);\n            this._setRangeNumber(cfgElevAngleLimitRange, cfgElevAngleLimit, elevAngleLimit);\n            this._setRangeNumber(cfgElevSurfaceMinLevelRange, cfgElevSurfaceMinLevel, elevSurfaceMinLevel);\n            this._setRangeNumber(cfgElevSurfaceMaxLodRange, cfgElevSurfaceMaxLod, surfaceStageMaxLOD);\n            this._setRangeNumber(cfgElevSurfaceFalloffRange, cfgElevSurfaceFalloff, surfaceLodFalloff);\n            this._setRangeNumber(cfgElevRingNearKmRange, cfgElevRingNearKm, ringNearKm);\n            this._setRangeNumber(cfgElevRingMidKmRange, cfgElevRingMidKm, ringMidKm);\n            this._setRangeNumber(cfgElevRingBudgetNearRange, cfgElevRingBudgetNear, ringBudgetNear);\n            this._setRangeNumber(cfgElevRingBudgetMidRange, cfgElevRingBudgetMid, ringBudgetMid);\n            this._setRangeNumber(cfgElevQueueResetKmRange, cfgElevQueueResetKm, queueResetKm);\n            this._setRangeNumber(cfgElevQueueResetAngleRange, cfgElevQueueResetAngle, queueResetAngle);\n\n            this._setRangeNumber(cfgSurfaceStageMinLODRange, cfgSurfaceStageMinLOD, surfaceStageMinLOD);\n            this._setRangeNumber(cfgSurfaceStageMaxLODRange, cfgSurfaceStageMaxLOD, surfaceStageMaxLOD);\n            this._setRangeNumber(cfgSurfaceStageCooldownRange, cfgSurfaceStageCooldown, surfaceStageCooldown);\n            this._setRangeNumber(cfgSurfaceCullAngleRange, cfgSurfaceCullAngle, surfaceCullAngle);\n\n            this._setRangeNumber(cfgSurfaceLodNearRange, cfgSurfaceLodNear, surfaceLodNear);\n            this._setRangeNumber(cfgSurfaceLodFarRange, cfgSurfaceLodFar, surfaceLodFar);\n            this._setRangeNumber(cfgSurfaceLodFalloffRange, cfgSurfaceLodFalloff, surfaceLodFalloff);\n            this._setRangeNumber(cfgSurfaceLodStartRange, cfgSurfaceLodStart, surfaceLodStart);\n            this._setRangeNumber(cfgOrbitFalloffMarginRange, cfgOrbitFalloffMargin, orbitFalloffMargin);\n            this._setRangeNumber(cfgOrbitFalloffAnchorRange, cfgOrbitFalloffAnchor, orbitFalloffAnchor);\n            this._setRangeNumber(cfgOrbitLodFalloffRange, cfgOrbitLodFalloff, orbitLodFalloff);\n        };\n\n        const applyElevConfig = () => {\n            const batchSize = parseInt(cfgBatchSize.value, 10);\n            const maxConcurrent = parseInt(cfgMaxConcurrent.value, 10);\n            const minInterval = parseInt(cfgMinInterval.value, 10);\n            const maxKB = parseInt(cfgMaxKBPerMin.value, 10);\n            const maxVertexRecords = parseInt(cfgMaxVertexRecords.value, 10);\n            const surfaceStageMinLOD = parseInt(cfgSurfaceStageMinLOD.value, 10);\n            let surfaceStageMaxLOD = parseInt(cfgSurfaceStageMaxLOD.value, 10);\n            const surfaceLodNear = parseFloat(cfgSurfaceLodNear.value);\n            const surfaceLodFar = parseFloat(cfgSurfaceLodFar.value);\n            const surfaceLodFalloff = parseFloat(cfgSurfaceLodFalloff.value);\n            const surfaceLodStart = parseFloat(cfgSurfaceLodStart.value);\n            const surfaceStageCooldown = parseInt(cfgSurfaceStageCooldown.value, 10);\n            const surfaceCullAngle = parseInt(cfgSurfaceCullAngle.value, 10);\n            const orbitFalloffMargin = parseFloat(cfgOrbitFalloffMargin.value);\n            const orbitFalloffAnchor = parseFloat(cfgOrbitFalloffAnchor.value);\n            const orbitLodFalloff = parseFloat(cfgOrbitLodFalloff.value);\n            const elevAngleLimit = parseInt(cfgElevAngleLimit.value, 10);\n            const elevSurfaceMinLevel = parseInt(cfgElevSurfaceMinLevel.value, 10);\n            const elevSurfaceMaxLod = cfgElevSurfaceMaxLod ? parseInt(cfgElevSurfaceMaxLod.value, 10) : NaN;\n            const elevSurfaceFalloff = cfgElevSurfaceFalloff ? parseFloat(cfgElevSurfaceFalloff.value) : NaN;\n            const elevRingNearKm = cfgElevRingNearKm ? parseFloat(cfgElevRingNearKm.value) : NaN;\n            const elevRingMidKm = cfgElevRingMidKm ? parseFloat(cfgElevRingMidKm.value) : NaN;\n            const clampPercent = (value) => (Number.isFinite(value) ? Math.max(0, Math.min(100, value)) : value);\n            const elevRingBudgetNear = cfgElevRingBudgetNear\n                ? clampPercent(parseFloat(cfgElevRingBudgetNear.value))\n                : NaN;\n            const elevRingBudgetMid = cfgElevRingBudgetMid\n                ? clampPercent(parseFloat(cfgElevRingBudgetMid.value))\n                : NaN;\n            const elevQueueResetKm = cfgElevQueueResetKm ? parseFloat(cfgElevQueueResetKm.value) : NaN;\n            const elevQueueResetAngle = cfgElevQueueResetAngle ? parseFloat(cfgElevQueueResetAngle.value) : NaN;\n\n            if (Number.isFinite(elevSurfaceMaxLod)) {\n                surfaceStageMaxLOD = elevSurfaceMaxLod;\n                if (cfgSurfaceStageMaxLOD) {\n                    this._setRangeNumber(cfgSurfaceStageMaxLODRange, cfgSurfaceStageMaxLOD, elevSurfaceMaxLod);\n                }\n                if (cfgSurfaceLodNear) {\n                    this._setRangeNumber(cfgSurfaceLodNearRange, cfgSurfaceLodNear, elevSurfaceMaxLod);\n                }\n            }\n\n            let surfaceLodNearFinal = surfaceLodNear;\n            let surfaceLodFalloffFinal = surfaceLodFalloff;\n\n            if (Number.isFinite(elevSurfaceMaxLod)) {\n                surfaceLodNearFinal = elevSurfaceMaxLod;\n            }\n            if (Number.isFinite(elevSurfaceFalloff)) {\n                surfaceLodFalloffFinal = elevSurfaceFalloff;\n                this._setRangeNumber(cfgSurfaceLodFalloffRange, cfgSurfaceLodFalloff, elevSurfaceFalloff);\n            }\n\n            if (Number.isFinite(surfaceStageMinLOD) && Number.isFinite(surfaceStageMaxLOD) &&\n                surfaceStageMaxLOD < surfaceStageMinLOD) {\n                surfaceStageMaxLOD = surfaceStageMinLOD;\n                cfgSurfaceStageMaxLOD.value = surfaceStageMaxLOD;\n                if (cfgSurfaceStageMaxLODRange) cfgSurfaceStageMaxLODRange.value = surfaceStageMaxLOD;\n            }\n\n            this._setRangeNumber(cfgElevSurfaceMaxLodRange, cfgElevSurfaceMaxLod, surfaceStageMaxLOD);\n            this._setRangeNumber(cfgElevSurfaceFalloffRange, cfgElevSurfaceFalloff, surfaceLodFalloffFinal);\n\n            const ringBaseLod = Number.isFinite(elevSurfaceMaxLod) ? elevSurfaceMaxLod : surfaceStageMaxLOD;\n            const ringFalloffPower = Number.isFinite(elevSurfaceFalloff) ? elevSurfaceFalloff : surfaceLodFalloffFinal;\n            const ringMidDrop = Math.max(1, Math.round(2 * ringFalloffPower));\n            const ringFarDrop = Math.max(ringMidDrop + 1, Math.round(4 * ringFalloffPower));\n            const ringLodCaps = {\n                near: ringBaseLod,\n                mid: Math.max(0, ringBaseLod - ringMidDrop),\n                far: Math.max(0, ringBaseLod - ringFarDrop)\n            };\n\n            const ringNearMeters = Number.isFinite(elevRingNearKm) ? elevRingNearKm * 1000 : NaN;\n            let ringMidMeters = Number.isFinite(elevRingMidKm) ? elevRingMidKm * 1000 : NaN;\n            if (Number.isFinite(ringNearMeters) && Number.isFinite(ringMidMeters) && ringMidMeters < ringNearMeters) {\n                ringMidMeters = ringNearMeters;\n                if (cfgElevRingMidKm) {\n                    cfgElevRingMidKm.value = (ringMidMeters / 1000).toFixed(1);\n                }\n                if (cfgElevRingMidKmRange) cfgElevRingMidKmRange.value = (ringMidMeters / 1000).toFixed(1);\n            }\n            const queueResetDistanceM = Number.isFinite(elevQueueResetKm) ? elevQueueResetKm * 1000 : NaN;\n\n            const patch = {\n                terrain: {\n                    elevation: {\n                        batchSize,\n                        maxConcurrent,\n                        minIntervalMs: minInterval,\n                        maxKBPerMinute: maxKB,\n                        angleLimitDeg: elevAngleLimit,\n                        surfaceMinLevel: elevSurfaceMinLevel,\n                        maxVertexRecords,\n                        ringNearMeters,\n                        ringMidMeters,\n                        ringBudgetNear: elevRingBudgetNear,\n                        ringBudgetMid: elevRingBudgetMid,\n                        ringLodCaps,\n                        queueResetDistanceM,\n                        queueResetAngleDeg: elevQueueResetAngle\n                    },\n                    surface: {\n                        staging: {\n                            minLOD: surfaceStageMinLOD,\n                            maxLOD: surfaceStageMaxLOD,\n                            cooldownMs: surfaceStageCooldown,\n                            cullAngleDeg: surfaceCullAngle\n                        },\n                        falloff: {\n                            nearLOD: surfaceLodNearFinal,\n                            farLOD: surfaceLodFar,\n                            power: surfaceLodFalloffFinal,\n                            startDeg: surfaceLodStart\n                        }\n                    },\n                    orbit: {\n                        falloff: {\n                            marginDeg: orbitFalloffMargin,\n                            anchorDeg: orbitFalloffAnchor,\n                            power: orbitLodFalloff\n                        }\n                    }\n                }\n            };\n\n            if (this._updateSceneSettings(patch)) return;\n\n            this.elevationClient.setConfig({\n                batchSize,\n                maxConcurrent,\n                minIntervalMs: minInterval,\n                maxKBPerMinute: maxKB,\n                angleLimitDeg: elevAngleLimit,\n                surfaceMinLevel: elevSurfaceMinLevel,\n                maxVertexRecords,\n                ringNearMeters,\n                ringMidMeters,\n                ringBudgetNear: elevRingBudgetNear,\n                ringBudgetMid: elevRingBudgetMid,\n                ringLodCaps\n            });\n            if (this.triTree) {\n                if (Number.isFinite(queueResetDistanceM)) {\n                    this.triTree.elevationQueueResetDistance = Math.max(10000, queueResetDistanceM);\n                }\n                if (Number.isFinite(elevQueueResetAngle)) {\n                    this.triTree.elevationQueueResetAngleDeg = Math.max(1, elevQueueResetAngle);\n                }\n            }\n            if (this.triTree && typeof this.triTree.setSurfaceStagingConfig === 'function') {\n                this.triTree.setSurfaceStagingConfig({\n                    minLOD: surfaceStageMinLOD,\n                    maxLOD: surfaceStageMaxLOD,\n                    cooldownMs: surfaceStageCooldown,\n                    cullAngleDeg: surfaceCullAngle\n                });\n            }\n            if (this.triTree && typeof this.triTree.setSurfaceFalloffConfig === 'function') {\n                this.triTree.setSurfaceFalloffConfig({\n                    nearLOD: surfaceLodNearFinal,\n                    farLOD: surfaceLodFar,\n                    falloffPower: surfaceLodFalloffFinal,\n                    startDeg: surfaceLodStart\n                });\n            }\n            if (this.triTree && typeof this.triTree.setOrbitFalloffConfig === 'function') {\n                this.triTree.setOrbitFalloffConfig({\n                    marginDeg: orbitFalloffMargin,\n                    anchorDeg: orbitFalloffAnchor,\n                    power: orbitLodFalloff\n                });\n            }\n        };\n\n        const bindRangeNumberPair = (rangeEl, numberEl) => {\n            if (!numberEl) return;\n            if (rangeEl) {\n                rangeEl.value = numberEl.value;\n                const syncFromRange = () => {\n                    numberEl.value = rangeEl.value;\n                    applyElevConfig();\n                };\n                const syncFromNumber = () => {\n                    rangeEl.value = numberEl.value;\n                    applyElevConfig();\n                };\n                ['input', 'change'].forEach(ev => rangeEl.addEventListener(ev, syncFromRange));\n                ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, syncFromNumber));\n            } else {\n                ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, applyElevConfig));\n            }\n        };\n\n        bindRangeNumberPair(cfgBatchSizeRange, cfgBatchSize);\n        bindRangeNumberPair(cfgMaxConcurrentRange, cfgMaxConcurrent);\n        bindRangeNumberPair(cfgMinIntervalRange, cfgMinInterval);\n        bindRangeNumberPair(cfgMaxKBPerMinRange, cfgMaxKBPerMin);\n        bindRangeNumberPair(cfgMaxVertexRecordsRange, cfgMaxVertexRecords);\n        bindRangeNumberPair(cfgElevSurfaceMaxLodRange, cfgElevSurfaceMaxLod);\n        bindRangeNumberPair(cfgElevSurfaceFalloffRange, cfgElevSurfaceFalloff);\n        bindRangeNumberPair(cfgElevRingNearKmRange, cfgElevRingNearKm);\n        bindRangeNumberPair(cfgElevRingMidKmRange, cfgElevRingMidKm);\n        bindRangeNumberPair(cfgElevRingBudgetNearRange, cfgElevRingBudgetNear);\n        bindRangeNumberPair(cfgElevRingBudgetMidRange, cfgElevRingBudgetMid);\n        bindRangeNumberPair(cfgElevQueueResetKmRange, cfgElevQueueResetKm);\n        bindRangeNumberPair(cfgElevQueueResetAngleRange, cfgElevQueueResetAngle);\n        bindRangeNumberPair(cfgSurfaceStageMinLODRange, cfgSurfaceStageMinLOD);\n        bindRangeNumberPair(cfgSurfaceStageMaxLODRange, cfgSurfaceStageMaxLOD);\n        bindRangeNumberPair(cfgSurfaceLodNearRange, cfgSurfaceLodNear);\n        bindRangeNumberPair(cfgSurfaceLodFarRange, cfgSurfaceLodFar);\n        bindRangeNumberPair(cfgSurfaceLodFalloffRange, cfgSurfaceLodFalloff);\n        bindRangeNumberPair(cfgSurfaceLodStartRange, cfgSurfaceLodStart);\n        bindRangeNumberPair(cfgSurfaceStageCooldownRange, cfgSurfaceStageCooldown);\n        bindRangeNumberPair(cfgSurfaceCullAngleRange, cfgSurfaceCullAngle);\n        bindRangeNumberPair(cfgOrbitFalloffMarginRange, cfgOrbitFalloffMargin);\n        bindRangeNumberPair(cfgOrbitFalloffAnchorRange, cfgOrbitFalloffAnchor);\n        bindRangeNumberPair(cfgOrbitLodFalloffRange, cfgOrbitLodFalloff);\n        bindRangeNumberPair(cfgElevAngleLimitRange, cfgElevAngleLimit);\n        bindRangeNumberPair(cfgElevSurfaceMinLevelRange, cfgElevSurfaceMinLevel);\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyElevConfig();\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // LOD Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupLODControls() {\n        const { btnLodOrbit, btnLodZoom } = this.elements;\n        const {\n            cfgTileBudget,\n            cfgSplitBudget,\n            cfgMergeBudget,\n            lblTileBudget,\n            lblSplitBudget,\n            lblMergeBudget\n        } = this.elements;\n\n        // LOD mode buttons\n        const updateLodButtons = () => {\n            const lodMode = this.surfaceController.getLODMode();\n            btnLodOrbit.classList.toggle('active', lodMode === 'orbit');\n            btnLodZoom.classList.toggle('active', lodMode === 'zoom');\n        };\n        this._updateLodButtons = updateLodButtons;\n\n        btnLodOrbit.addEventListener('click', () => {\n            this.setLodMode('orbit');\n        });\n\n        btnLodZoom.addEventListener('click', () => {\n            this.setLodMode('zoom');\n        });\n\n        updateLodButtons();\n\n        const syncFromSettings = () => {\n            const lod = this._getSettingValue('scene.terrain.lod', {}) || {};\n            const tileBudget = Number.isFinite(lod.tileBudget) ? lod.tileBudget : this.triTree.tileBudget;\n            const splitBudget = Number.isFinite(lod.splitBudget) ? lod.splitBudget : this.triTree.splitBudget;\n            const mergeBudget = Number.isFinite(lod.mergeBudget) ? lod.mergeBudget : this.triTree.mergeBudget;\n            this._setInputValue(cfgTileBudget, tileBudget);\n            this._setInputValue(cfgSplitBudget, splitBudget);\n            this._setInputValue(cfgMergeBudget, mergeBudget);\n            lblTileBudget.textContent = tileBudget;\n            lblSplitBudget.textContent = splitBudget;\n            lblMergeBudget.textContent = mergeBudget;\n        };\n\n        const applyLodBudgets = () => {\n            const tileBudget = parseInt(cfgTileBudget.value, 10);\n            const splitBudget = parseInt(cfgSplitBudget.value, 10);\n            const mergeBudget = parseInt(cfgMergeBudget.value, 10);\n            if (!this._updateSceneSettings({\n                terrain: {\n                    lod: { tileBudget, splitBudget, mergeBudget }\n                }\n            })) {\n                this.triTree.setBudgets({ tileBudget, splitBudget, mergeBudget });\n            }\n            lblTileBudget.textContent = tileBudget;\n            lblSplitBudget.textContent = splitBudget;\n            lblMergeBudget.textContent = mergeBudget;\n        };\n\n        ['input', 'change'].forEach(ev => {\n            cfgTileBudget.addEventListener(ev, applyLodBudgets);\n            cfgSplitBudget.addEventListener(ev, applyLodBudgets);\n            cfgMergeBudget.addEventListener(ev, applyLodBudgets);\n        });\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyLodBudgets();\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Surface Mode Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupSurfaceModeControls() {\n        const { btnEnterSurface, btnExitSurface, surfaceModeHint } = this.elements;\n\n        btnEnterSurface.addEventListener('click', () => {\n            const viewDir = new THREE.Vector3();\n            this.camera.getWorldDirection(viewDir);\n            const cameraPos = this.camera?.userData?.worldPosition || this.camera.position;\n            const planetGroup = this.triTree?.group || null;\n            const hit = rayEllipsoidIntersection(cameraPos, viewDir, planetGroup) ||\n                raySphereIntersection(cameraPos, viewDir);\n            if (hit) {\n                this.surfaceController.enterSurfaceAt(hit.clone().normalize());\n            } else {\n                this.surfaceController.enterSurfaceAt(cameraPos.clone().normalize());\n            }\n            this.handleSurfaceEnter({ reason: 'button' });\n        });\n\n        btnExitSurface.addEventListener('click', () => {\n            this.surfaceController.exitSurfaceMode();\n        });\n\n        // Update UI based on camera mode\n        const updateCameraModeUI = () => {\n            const isOnSurface = this.surfaceController.isInSurfaceMode();\n            btnEnterSurface.style.display = isOnSurface ? 'none' : 'block';\n            btnExitSurface.style.display = isOnSurface ? 'block' : 'none';\n            surfaceModeHint.style.display = isOnSurface ? 'block' : 'none';\n            this.syncLodButtons();\n        };\n\n        this.surfaceController.onCameraModeChange = updateCameraModeUI;\n        updateCameraModeUI();\n\n        // Save state immediately when mode transitions complete\n        this.surfaceController.onModeTransitionComplete = (newMode) => {\n            console.log('[VIEW STATE] Mode transition complete to:', newMode, '- triggering immediate save');\n            if (this.elements.cfgStatePersist && this.elements.cfgStatePersist.checked && this._saveViewState) {\n                this._saveViewState();\n            }\n            if (newMode === 'surface') {\n                this.handleSurfaceEnter({ reason: 'transition' });\n            }\n        };\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Imagery Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupImageryControls() {\n        const { cfgImageryEnabled, cfgImageryDataset, cfgImageryVersion, cfgImageryZoom } = this.elements;\n        const { btnImageryPreview, imageryPreviewImg, imageryUrlEl } = this.elements;\n        const { cfgImageryMinZoom, cfgImageryMaxZoom, lblImageryMinZoom, lblImageryMaxZoom } = this.elements;\n        let waybackVersions = null;\n        let waybackFetchPromise = null;\n        let lastVersionId = null;\n        const normalizeVersionId = (value) => (value ? String(value).trim() : '');\n        const isLatestVersion = (value) => {\n            const normalized = normalizeVersionId(value).toLowerCase();\n            return normalized === '' || normalized === 'latest';\n        };\n\n        const buildWaybackCapabilitiesUrl = () => {\n            const marker = '/WMTS/1.0.0/default028mm/MapServer';\n            if (WMTS_ROOT && WMTS_ROOT.includes(marker)) {\n                return WMTS_ROOT.replace(marker, '/MapServer/WMTS/1.0.0/WMTSCapabilities.xml');\n            }\n            return WAYBACK_WMTS_CAPABILITIES;\n        };\n\n        const setDatasetStatus = (label) => {\n            if (!cfgImageryDataset) return;\n            cfgImageryDataset.innerHTML = '';\n            const opt = document.createElement('option');\n            opt.value = '';\n            opt.textContent = label;\n            opt.disabled = true;\n            opt.selected = true;\n            cfgImageryDataset.appendChild(opt);\n        };\n\n        const syncDatasetSelection = (versionId) => {\n            if (!cfgImageryDataset) return;\n            const raw = normalizeVersionId(versionId);\n            const resolved = isLatestVersion(raw) && waybackVersions?.length\n                ? waybackVersions[0].id\n                : raw;\n            if (resolved) lastVersionId = resolved;\n            if (!waybackVersions || !waybackVersions.length) return;\n            const targetId = lastVersionId;\n            const match = targetId\n                ? waybackVersions.find(v => v.id === targetId)\n                : null;\n            const existingCustom = cfgImageryDataset.querySelector('option[data-custom=\"true\"]');\n            if (existingCustom) existingCustom.remove();\n            if (match) {\n                cfgImageryDataset.value = match.id;\n                return;\n            }\n            if (targetId) {\n                const customOpt = document.createElement('option');\n                customOpt.value = targetId;\n                customOpt.textContent = `Custom - ${targetId}`;\n                customOpt.dataset.custom = 'true';\n                cfgImageryDataset.insertBefore(customOpt, cfgImageryDataset.firstChild);\n                cfgImageryDataset.value = targetId;\n            }\n        };\n\n        const populateDatasetOptions = (versions) => {\n            if (!cfgImageryDataset) return;\n            cfgImageryDataset.innerHTML = '';\n            if (!versions || !versions.length) {\n                setDatasetStatus('No Wayback versions found');\n                return;\n            }\n            versions.forEach((v) => {\n                const opt = document.createElement('option');\n                opt.value = v.id;\n                opt.textContent = `${v.label} - ${v.id}`;\n                cfgImageryDataset.appendChild(opt);\n            });\n            syncDatasetSelection(lastVersionId);\n        };\n\n        const loadWaybackVersions = async () => {\n            if (!cfgImageryDataset) return null;\n            if (typeof fetch !== 'function' || typeof DOMParser === 'undefined') {\n                setDatasetStatus('Wayback versions unavailable');\n                return null;\n            }\n            if (waybackVersions) return waybackVersions;\n            if (waybackFetchPromise) return waybackFetchPromise;\n            setDatasetStatus('Loading Wayback versions...');\n            const url = buildWaybackCapabilitiesUrl();\n            waybackFetchPromise = fetch(url, { mode: 'cors' })\n                .then((resp) => {\n                    if (!resp.ok) {\n                        throw new Error(`Wayback capabilities request failed (${resp.status})`);\n                    }\n                    return resp.text();\n                })\n                .then((text) => {\n                    const parser = new DOMParser();\n                    const xml = parser.parseFromString(text, 'application/xml');\n                    const layers = Array.from(xml.querySelectorAll('Contents > Layer'));\n                    const versions = [];\n                    for (const layer of layers) {\n                        const title = (layer.querySelector('ows\\\\:Title') || layer.querySelector('Title'))?.textContent?.trim() || '';\n                        const resUrl = layer.querySelector('ResourceURL[resourceType=\"tile\"]')?.getAttribute('template') || '';\n                        const match = resUrl.match(/\\/tile\\/(\\d+)\\/\\{?TileMatrix/i);\n                        const version = match ? match[1] : '';\n                        if (!version) continue;\n                        let sortKey = version;\n                        let label = title || version;\n                        const dateMatch = title.match(/(\\d{4}-\\d{2}-\\d{2})/);\n                        if (dateMatch) {\n                            sortKey = dateMatch[1];\n                            label = `${dateMatch[1]}  (v${version})`;\n                        } else {\n                            label = `${label}  (v${version})`;\n                        }\n                        versions.push({ id: version, label, sortKey });\n                    }\n                    versions.sort((a, b) => (a.sortKey < b.sortKey ? 1 : (a.sortKey > b.sortKey ? -1 : 0)));\n                    waybackVersions = versions;\n                    populateDatasetOptions(versions);\n                    return versions;\n                })\n                .catch((err) => {\n                    console.warn('[Imagery] Failed to load Wayback versions:', err);\n                    setDatasetStatus('Unable to load Wayback versions');\n                    return null;\n                })\n                .finally(() => {\n                    waybackFetchPromise = null;\n                });\n            return waybackFetchPromise;\n        };\n\n        const syncFromSettings = () => {\n            const imagery = this._getSettingValue('scene.terrain.imagery', {}) || {};\n            const managerCfg = this.imageryManager?.getConfig?.() || {};\n            const enabled = typeof imagery.enabled === 'boolean' ? imagery.enabled : managerCfg.enabled;\n            const rawVersion = normalizeVersionId(imagery.versionId);\n            const preferLatest = isLatestVersion(rawVersion);\n            const managerVersion = normalizeVersionId(managerCfg.versionId);\n            const fallbackVersion = managerVersion || DEFAULT_WAYBACK_VERSION;\n            const versionId = preferLatest ? fallbackVersion : (rawVersion || fallbackVersion);\n            const zoom = Number.isFinite(imagery.zoom) ? imagery.zoom : (managerCfg.zoom ?? 8);\n            const minZoom = Number.isFinite(imagery.minZoom)\n                ? imagery.minZoom\n                : (this.triTree?.imageryMinZoom ?? 0);\n            const maxZoom = Number.isFinite(imagery.maxZoom)\n                ? imagery.maxZoom\n                : (this.triTree?.imageryMaxZoom ?? 22);\n\n            if (cfgImageryEnabled) cfgImageryEnabled.checked = !!enabled;\n            if (cfgImageryVersion) {\n                cfgImageryVersion.dataset.latestMode = preferLatest ? 'true' : 'false';\n                cfgImageryVersion.dataset.latestResolved = preferLatest ? versionId : '';\n                this._setInputValue(cfgImageryVersion, versionId);\n            }\n            this._setInputValue(cfgImageryZoom, zoom);\n            this._setInputValue(cfgImageryMinZoom, minZoom);\n            this._setInputValue(cfgImageryMaxZoom, maxZoom);\n            if (lblImageryMinZoom) lblImageryMinZoom.textContent = minZoom;\n            if (lblImageryMaxZoom) lblImageryMaxZoom.textContent = maxZoom;\n            syncDatasetSelection(versionId);\n        };\n\n        const applyImageryConfig = () => {\n            const enabled = cfgImageryEnabled.checked;\n            const versionInput = normalizeVersionId(cfgImageryVersion.value);\n            const latestMode = cfgImageryVersion?.dataset?.latestMode === 'true';\n            const versionId = latestMode\n                ? 'latest'\n                : (versionInput || DEFAULT_WAYBACK_VERSION);\n            const zoom = parseInt(cfgImageryZoom.value, 10);\n            const minZoom = parseInt(cfgImageryMinZoom.value, 10);\n            const maxZoom = parseInt(cfgImageryMaxZoom.value, 10);\n            if (!latestMode) cfgImageryVersion.value = versionId;\n\n            let nextMin = minZoom;\n            let nextMax = maxZoom;\n            if (Number.isFinite(nextMin) && Number.isFinite(nextMax) && nextMin > nextMax) {\n                nextMax = nextMin;\n                if (cfgImageryMaxZoom) cfgImageryMaxZoom.value = nextMax;\n            }\n\n            if (lblImageryMinZoom) lblImageryMinZoom.textContent = nextMin;\n            if (lblImageryMaxZoom) lblImageryMaxZoom.textContent = nextMax;\n\n            const patch = {\n                terrain: {\n                    imagery: {\n                        enabled,\n                        versionId,\n                        zoom,\n                        minZoom: nextMin,\n                        maxZoom: nextMax\n                    }\n                }\n            };\n\n            syncDatasetSelection(versionId);\n            if (this._updateSceneSettings(patch)) return;\n\n            this.triTree.setImageryConfig({ enabled, versionId, zoom });\n            if (Number.isFinite(nextMin) || Number.isFinite(nextMax)) {\n                this.triTree.setImageryZoomRange(nextMin, nextMax);\n            }\n            this.sceneInitializer?.moonSystem?.setImageryEnabled?.(enabled);\n        };\n\n        if (cfgImageryDataset) {\n            cfgImageryDataset.addEventListener('change', () => {\n                const versionId = cfgImageryDataset.value;\n                if (!versionId) return;\n                if (cfgImageryVersion) {\n                    cfgImageryVersion.value = versionId;\n                    cfgImageryVersion.dataset.latestMode = 'false';\n                    cfgImageryVersion.dataset.latestResolved = '';\n                }\n                applyImageryConfig();\n            });\n        }\n\n        cfgImageryEnabled.addEventListener('change', applyImageryConfig);\n        cfgImageryVersion.addEventListener('change', () => {\n            const latestMode = cfgImageryVersion?.dataset?.latestMode === 'true';\n            const latestResolved = normalizeVersionId(cfgImageryVersion?.dataset?.latestResolved);\n            const current = normalizeVersionId(cfgImageryVersion.value);\n            if (latestMode && latestResolved && current !== latestResolved) {\n                cfgImageryVersion.dataset.latestMode = 'false';\n                cfgImageryVersion.dataset.latestResolved = '';\n            }\n            applyImageryConfig();\n        });\n        cfgImageryZoom.addEventListener('change', applyImageryConfig);\n        cfgImageryMinZoom.addEventListener('input', applyImageryConfig);\n        cfgImageryMinZoom.addEventListener('change', applyImageryConfig);\n        cfgImageryMaxZoom.addEventListener('input', applyImageryConfig);\n        cfgImageryMaxZoom.addEventListener('change', applyImageryConfig);\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyImageryConfig();\n        loadWaybackVersions();\n\n        btnImageryPreview.addEventListener('click', () => {\n            const cfg = this.imageryManager.getConfig();\n            const enabled = cfg.enabled;\n            const z = cfg.zoom;\n\n            if (!enabled) {\n                imageryPreviewImg.removeAttribute('src');\n                imageryUrlEl.textContent = 'Imagery disabled.';\n                return;\n            }\n\n            const viewDir = new THREE.Vector3();\n            this.camera.getWorldDirection(viewDir);\n            const cameraPos = this.camera?.userData?.worldPosition || this.camera.position;\n            const planetGroup = this.triTree?.group || null;\n            const hit = rayEllipsoidIntersection(cameraPos, viewDir, planetGroup) ||\n                raySphereIntersection(cameraPos, viewDir);\n\n            if (!hit) {\n                imageryPreviewImg.removeAttribute('src');\n                imageryUrlEl.textContent = 'Camera not intersecting globe.';\n                return;\n            }\n\n            const ll = worldPosToLatLonLocal(hit, this.triTree?.group);\n            if (!ll) {\n                imageryPreviewImg.removeAttribute('src');\n                imageryUrlEl.textContent = 'Lat/lon unavailable.';\n                return;\n            }\n\n            const coords = lonLatToTileCoords(ll.lonDeg, ll.latDeg, z);\n            const url = this.imageryManager.buildUrl(cfg.versionId, z, coords.x, coords.y);\n            imageryPreviewImg.src = url + (url.includes('?') ? '&' : '?') + 'ts=' + Date.now();\n            imageryUrlEl.textContent =\n                `z/x/y: ${z}/${coords.x}/${coords.y} · center: ${ll.latDeg.toFixed(6)}, ${ll.lonDeg.toFixed(6)}\\n` +\n                url;\n        });\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Photogrammetry Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupPhotogrammetryControls() {\n        const {\n            cfgPhotogramEnabled,\n            cfgPhotogramRing0Only,\n            cfgPhotogramInvert,\n            cfgPhotogramAutoSun,\n            cfgPhotogramMinZoom,\n            lblPhotogramMinZoom,\n            cfgPhotogramMapResolution,\n            lblPhotogramMapResolution,\n            cfgPhotogramPyramidLevels,\n            lblPhotogramPyramidLevels,\n            cfgPhotogramIllumBlur,\n            lblPhotogramIllumBlur,\n            cfgPhotogramDisplacement,\n            lblPhotogramDisplacement,\n            cfgPhotogramDetailGain,\n            lblPhotogramDetailGain,\n            cfgPhotogramShadowMicro,\n            lblPhotogramShadowMicro,\n            cfgPhotogramDirMicro,\n            lblPhotogramDirMicro,\n            cfgPhotogramCanopyScale,\n            lblPhotogramCanopyScale,\n            cfgPhotogramVegThreshold,\n            lblPhotogramVegThreshold,\n            cfgPhotogramShadowThreshold,\n            lblPhotogramShadowThreshold,\n            cfgPhotogramMaxShadow,\n            lblPhotogramMaxShadow,\n            cfgPhotogramCanopyBlur,\n            lblPhotogramCanopyBlur,\n            cfgPhotogramDome,\n            lblPhotogramDome,\n            cfgPhotogramSmoothPasses,\n            lblPhotogramSmoothPasses,\n            cfgPhotogramSunAzimuth,\n            lblPhotogramSunAzimuth,\n            cfgPhotogramSunElevation,\n            lblPhotogramSunElevation,\n            cfgPhotogramTiles,\n            lblPhotogramTiles,\n            cfgPhotogramSubdiv,\n            lblPhotogramSubdiv,\n            cfgPhotogramMaxSubdiv,\n            lblPhotogramMaxSubdiv,\n            cfgPhotogramJobsPerFrame,\n            lblPhotogramJobsPerFrame,\n            cfgPhotogramConcurrentJobs,\n            lblPhotogramConcurrentJobs,\n            cfgPhotogramProcessingMs,\n            lblPhotogramProcessingMs,\n            cfgPhotogramCacheMaxTiles,\n            lblPhotogramCacheMaxTiles\n        } = this.elements;\n\n        if (!cfgPhotogramEnabled) return;\n\n        const readFloat = (el, fallback) => {\n            if (!el) return fallback;\n            const num = parseFloat(el.value);\n            return Number.isFinite(num) ? num : fallback;\n        };\n        const readInt = (el, fallback) => {\n            if (!el) return fallback;\n            const num = parseInt(el.value, 10);\n            return Number.isFinite(num) ? num : fallback;\n        };\n        const formatInt = (value) => (Number.isFinite(value) ? String(Math.round(value)) : '');\n        const formatFloat2 = (value) => (Number.isFinite(value) ? value.toFixed(2) : '');\n\n        const syncLabels = (cfg) => {\n            if (lblPhotogramMinZoom) lblPhotogramMinZoom.textContent = formatInt(cfg.minImageryZoom);\n            if (lblPhotogramMapResolution) lblPhotogramMapResolution.textContent = formatInt(cfg.mapResolution);\n            if (lblPhotogramPyramidLevels) lblPhotogramPyramidLevels.textContent = formatInt(cfg.pyramidLevels);\n            if (lblPhotogramIllumBlur) lblPhotogramIllumBlur.textContent = formatInt(cfg.illumBlurRadius);\n            if (lblPhotogramDisplacement) lblPhotogramDisplacement.textContent = formatFloat2(cfg.displacementScale);\n            if (lblPhotogramDetailGain) lblPhotogramDetailGain.textContent = formatFloat2(cfg.detailGain);\n            if (lblPhotogramShadowMicro) lblPhotogramShadowMicro.textContent = formatFloat2(cfg.shadowMicro);\n            if (lblPhotogramDirMicro) lblPhotogramDirMicro.textContent = formatFloat2(cfg.dirMicro);\n            if (lblPhotogramCanopyScale) lblPhotogramCanopyScale.textContent = formatFloat2(cfg.canopyScale);\n            if (lblPhotogramVegThreshold) lblPhotogramVegThreshold.textContent = formatFloat2(cfg.vegThreshold);\n            if (lblPhotogramShadowThreshold) lblPhotogramShadowThreshold.textContent = formatFloat2(cfg.shadowThreshold);\n            if (lblPhotogramMaxShadow) lblPhotogramMaxShadow.textContent = formatInt(cfg.maxShadowLenPx);\n            if (lblPhotogramCanopyBlur) lblPhotogramCanopyBlur.textContent = formatInt(cfg.canopyBlurPx);\n            if (lblPhotogramDome) lblPhotogramDome.textContent = formatFloat2(cfg.domeStrength);\n            if (lblPhotogramSmoothPasses) lblPhotogramSmoothPasses.textContent = formatInt(cfg.smoothPasses);\n            if (lblPhotogramSunAzimuth) lblPhotogramSunAzimuth.textContent = formatInt(cfg.sunAzimuthDeg);\n            if (lblPhotogramSunElevation) lblPhotogramSunElevation.textContent = formatInt(cfg.sunElevationDeg);\n            if (lblPhotogramTiles) lblPhotogramTiles.textContent = formatInt(cfg.tilesPerAxis);\n            if (lblPhotogramSubdiv) lblPhotogramSubdiv.textContent = formatInt(cfg.subdivPerTile);\n            if (lblPhotogramMaxSubdiv) lblPhotogramMaxSubdiv.textContent = formatInt(cfg.maxSubdiv);\n            if (lblPhotogramJobsPerFrame) lblPhotogramJobsPerFrame.textContent = formatInt(cfg.maxJobsPerFrame);\n            if (lblPhotogramConcurrentJobs) lblPhotogramConcurrentJobs.textContent = formatInt(cfg.maxConcurrentJobs);\n            if (lblPhotogramProcessingMs) lblPhotogramProcessingMs.textContent = formatInt(cfg.maxProcessingMs);\n            if (lblPhotogramCacheMaxTiles) lblPhotogramCacheMaxTiles.textContent = formatInt(cfg.cacheMaxTiles);\n        };\n\n        const buildConfigFromInputs = () => {\n            const config = {\n                enabled: !!cfgPhotogramEnabled.checked,\n                ring0Only: !!cfgPhotogramRing0Only?.checked,\n                invertHeight: !!cfgPhotogramInvert?.checked,\n                autoSun: !!cfgPhotogramAutoSun?.checked,\n                minImageryZoom: readInt(cfgPhotogramMinZoom, 18),\n                mapResolution: readInt(cfgPhotogramMapResolution, 512),\n                pyramidLevels: readInt(cfgPhotogramPyramidLevels, 3),\n                illumBlurRadius: readInt(cfgPhotogramIllumBlur, 34),\n                displacementScale: readFloat(cfgPhotogramDisplacement, 1.35),\n                detailGain: readFloat(cfgPhotogramDetailGain, 1.1),\n                shadowMicro: readFloat(cfgPhotogramShadowMicro, 0.35),\n                dirMicro: readFloat(cfgPhotogramDirMicro, 0.85),\n                canopyScale: readFloat(cfgPhotogramCanopyScale, 2.6),\n                vegThreshold: readFloat(cfgPhotogramVegThreshold, 0.35),\n                shadowThreshold: readFloat(cfgPhotogramShadowThreshold, 0.22),\n                maxShadowLenPx: readInt(cfgPhotogramMaxShadow, 72),\n                canopyBlurPx: readInt(cfgPhotogramCanopyBlur, 18),\n                domeStrength: readFloat(cfgPhotogramDome, 0.55),\n                smoothPasses: readInt(cfgPhotogramSmoothPasses, 2),\n                sunAzimuthDeg: readFloat(cfgPhotogramSunAzimuth, 50),\n                sunElevationDeg: readFloat(cfgPhotogramSunElevation, 35),\n                tilesPerAxis: readInt(cfgPhotogramTiles, 4),\n                subdivPerTile: readInt(cfgPhotogramSubdiv, 160),\n                maxSubdiv: readInt(cfgPhotogramMaxSubdiv, 256),\n                maxJobsPerFrame: readInt(cfgPhotogramJobsPerFrame, 1),\n                maxConcurrentJobs: readInt(cfgPhotogramConcurrentJobs, 1),\n                maxProcessingMs: readInt(cfgPhotogramProcessingMs, 12),\n                cacheMaxTiles: readInt(cfgPhotogramCacheMaxTiles, 48)\n            };\n            syncLabels(config);\n            return config;\n        };\n\n        const applyPhotogramConfig = () => {\n            const config = buildConfigFromInputs();\n            const patch = { terrain: { photogrammetry: config } };\n            if (this._updateSceneSettings(patch)) return;\n            if (this.triTree && typeof this.triTree.setPhotogramConfig === 'function') {\n                this.triTree.setPhotogramConfig(config);\n            }\n        };\n\n        const syncFromSettings = () => {\n            const settingsCfg = this._getSettingValue('scene.terrain.photogrammetry', {}) || {};\n            const managerCfg = this.triTree?.photogramManager?.config || {};\n            const resolveBool = (value, fallback) => (typeof value === 'boolean' ? value : fallback);\n            const resolveNum = (value, fallback) => (Number.isFinite(value) ? value : fallback);\n\n            const config = {\n                enabled: resolveBool(settingsCfg.enabled, managerCfg.enabled ?? cfgPhotogramEnabled.checked),\n                ring0Only: resolveBool(settingsCfg.ring0Only, managerCfg.ring0Only ?? true),\n                invertHeight: resolveBool(settingsCfg.invertHeight, managerCfg.invertHeight ?? false),\n                autoSun: resolveBool(settingsCfg.autoSun, managerCfg.autoSun ?? true),\n                minImageryZoom: resolveNum(settingsCfg.minImageryZoom, managerCfg.minImageryZoom ?? readInt(cfgPhotogramMinZoom, 18)),\n                mapResolution: resolveNum(settingsCfg.mapResolution, managerCfg.mapResolution ?? readInt(cfgPhotogramMapResolution, 512)),\n                pyramidLevels: resolveNum(settingsCfg.pyramidLevels, managerCfg.pyramidLevels ?? readInt(cfgPhotogramPyramidLevels, 3)),\n                illumBlurRadius: resolveNum(settingsCfg.illumBlurRadius, managerCfg.illumBlurRadius ?? readInt(cfgPhotogramIllumBlur, 34)),\n                displacementScale: resolveNum(settingsCfg.displacementScale, managerCfg.displacementScale ?? readFloat(cfgPhotogramDisplacement, 1.35)),\n                detailGain: resolveNum(settingsCfg.detailGain, managerCfg.detailGain ?? readFloat(cfgPhotogramDetailGain, 1.1)),\n                shadowMicro: resolveNum(settingsCfg.shadowMicro, managerCfg.shadowMicro ?? readFloat(cfgPhotogramShadowMicro, 0.35)),\n                dirMicro: resolveNum(settingsCfg.dirMicro, managerCfg.dirMicro ?? readFloat(cfgPhotogramDirMicro, 0.85)),\n                canopyScale: resolveNum(settingsCfg.canopyScale, managerCfg.canopyScale ?? readFloat(cfgPhotogramCanopyScale, 2.6)),\n                vegThreshold: resolveNum(settingsCfg.vegThreshold, managerCfg.vegThreshold ?? readFloat(cfgPhotogramVegThreshold, 0.35)),\n                shadowThreshold: resolveNum(settingsCfg.shadowThreshold, managerCfg.shadowThreshold ?? readFloat(cfgPhotogramShadowThreshold, 0.22)),\n                maxShadowLenPx: resolveNum(settingsCfg.maxShadowLenPx, managerCfg.maxShadowLenPx ?? readInt(cfgPhotogramMaxShadow, 72)),\n                canopyBlurPx: resolveNum(settingsCfg.canopyBlurPx, managerCfg.canopyBlurPx ?? readInt(cfgPhotogramCanopyBlur, 18)),\n                domeStrength: resolveNum(settingsCfg.domeStrength, managerCfg.domeStrength ?? readFloat(cfgPhotogramDome, 0.55)),\n                smoothPasses: resolveNum(settingsCfg.smoothPasses, managerCfg.smoothPasses ?? readInt(cfgPhotogramSmoothPasses, 2)),\n                sunAzimuthDeg: resolveNum(settingsCfg.sunAzimuthDeg, managerCfg.sunAzimuthDeg ?? readFloat(cfgPhotogramSunAzimuth, 50)),\n                sunElevationDeg: resolveNum(settingsCfg.sunElevationDeg, managerCfg.sunElevationDeg ?? readFloat(cfgPhotogramSunElevation, 35)),\n                tilesPerAxis: resolveNum(settingsCfg.tilesPerAxis, managerCfg.tilesPerAxis ?? readInt(cfgPhotogramTiles, 4)),\n                subdivPerTile: resolveNum(settingsCfg.subdivPerTile, managerCfg.subdivPerTile ?? readInt(cfgPhotogramSubdiv, 160)),\n                maxSubdiv: resolveNum(settingsCfg.maxSubdiv, managerCfg.maxSubdiv ?? readInt(cfgPhotogramMaxSubdiv, 256)),\n                maxJobsPerFrame: resolveNum(settingsCfg.maxJobsPerFrame, managerCfg.maxJobsPerFrame ?? readInt(cfgPhotogramJobsPerFrame, 1)),\n                maxConcurrentJobs: resolveNum(settingsCfg.maxConcurrentJobs, managerCfg.maxConcurrentJobs ?? readInt(cfgPhotogramConcurrentJobs, 1)),\n                maxProcessingMs: resolveNum(settingsCfg.maxProcessingMs, managerCfg.maxProcessingMs ?? readInt(cfgPhotogramProcessingMs, 12)),\n                cacheMaxTiles: resolveNum(settingsCfg.cacheMaxTiles, managerCfg.cacheMaxTiles ?? readInt(cfgPhotogramCacheMaxTiles, 48))\n            };\n\n            this._setChecked(cfgPhotogramEnabled, config.enabled);\n            if (cfgPhotogramRing0Only) cfgPhotogramRing0Only.checked = !!config.ring0Only;\n            if (cfgPhotogramInvert) cfgPhotogramInvert.checked = !!config.invertHeight;\n            if (cfgPhotogramAutoSun) cfgPhotogramAutoSun.checked = !!config.autoSun;\n\n            this._setInputValue(cfgPhotogramMinZoom, config.minImageryZoom);\n            this._setInputValue(cfgPhotogramMapResolution, config.mapResolution);\n            this._setInputValue(cfgPhotogramPyramidLevels, config.pyramidLevels);\n            this._setInputValue(cfgPhotogramIllumBlur, config.illumBlurRadius);\n            this._setInputValue(cfgPhotogramDisplacement, config.displacementScale);\n            this._setInputValue(cfgPhotogramDetailGain, config.detailGain);\n            this._setInputValue(cfgPhotogramShadowMicro, config.shadowMicro);\n            this._setInputValue(cfgPhotogramDirMicro, config.dirMicro);\n            this._setInputValue(cfgPhotogramCanopyScale, config.canopyScale);\n            this._setInputValue(cfgPhotogramVegThreshold, config.vegThreshold);\n            this._setInputValue(cfgPhotogramShadowThreshold, config.shadowThreshold);\n            this._setInputValue(cfgPhotogramMaxShadow, config.maxShadowLenPx);\n            this._setInputValue(cfgPhotogramCanopyBlur, config.canopyBlurPx);\n            this._setInputValue(cfgPhotogramDome, config.domeStrength);\n            this._setInputValue(cfgPhotogramSmoothPasses, config.smoothPasses);\n            this._setInputValue(cfgPhotogramSunAzimuth, config.sunAzimuthDeg);\n            this._setInputValue(cfgPhotogramSunElevation, config.sunElevationDeg);\n            this._setInputValue(cfgPhotogramTiles, config.tilesPerAxis);\n            this._setInputValue(cfgPhotogramSubdiv, config.subdivPerTile);\n            this._setInputValue(cfgPhotogramMaxSubdiv, config.maxSubdiv);\n            this._setInputValue(cfgPhotogramJobsPerFrame, config.maxJobsPerFrame);\n            this._setInputValue(cfgPhotogramConcurrentJobs, config.maxConcurrentJobs);\n            this._setInputValue(cfgPhotogramProcessingMs, config.maxProcessingMs);\n            this._setInputValue(cfgPhotogramCacheMaxTiles, config.cacheMaxTiles);\n\n            syncLabels(config);\n        };\n\n        const rangeInputs = [\n            cfgPhotogramMinZoom,\n            cfgPhotogramMapResolution,\n            cfgPhotogramPyramidLevels,\n            cfgPhotogramIllumBlur,\n            cfgPhotogramDisplacement,\n            cfgPhotogramDetailGain,\n            cfgPhotogramShadowMicro,\n            cfgPhotogramDirMicro,\n            cfgPhotogramCanopyScale,\n            cfgPhotogramVegThreshold,\n            cfgPhotogramShadowThreshold,\n            cfgPhotogramMaxShadow,\n            cfgPhotogramCanopyBlur,\n            cfgPhotogramDome,\n            cfgPhotogramSmoothPasses,\n            cfgPhotogramSunAzimuth,\n            cfgPhotogramSunElevation,\n            cfgPhotogramTiles,\n            cfgPhotogramSubdiv,\n            cfgPhotogramMaxSubdiv,\n            cfgPhotogramJobsPerFrame,\n            cfgPhotogramConcurrentJobs,\n            cfgPhotogramProcessingMs,\n            cfgPhotogramCacheMaxTiles\n        ];\n        rangeInputs.forEach((el) => {\n            if (!el) return;\n            el.addEventListener('input', applyPhotogramConfig);\n            el.addEventListener('change', applyPhotogramConfig);\n        });\n\n        const toggleInputs = [\n            cfgPhotogramEnabled,\n            cfgPhotogramRing0Only,\n            cfgPhotogramInvert,\n            cfgPhotogramAutoSun\n        ];\n        toggleInputs.forEach((el) => {\n            if (!el) return;\n            el.addEventListener('change', applyPhotogramConfig);\n        });\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyPhotogramConfig();\n    }\n\n    setupWireframeControls() {\n        const {\n            cfgWireframe,\n            cfgStatePersist,\n            cfgAtmosphereEnabled,\n            cfgGeoJson,\n            cfgGeoJsonAutoDepth,\n            cfgGeoJsonMaxDepth,\n            cfgGeoJsonAdminLevel,\n            cfgGeoJsonCountry\n        } = this.elements;\n        const geoJsonBasePath = '/refactor/data/geojson/';\n        const adminLevels = [0, 1, 2, 3];\n        const maxDepthLevels = [0, 1, 2, 3];\n        const admIndexes = new Map();\n        let worldCountries = [];\n        let geoJsonOptionsReady = false;\n        let geoJsonOptionsPromise = null;\n        let pendingGeoJsonSelection = { level: 0, country: null };\n\n        const normalizeIso3 = (value) => {\n            if (typeof value !== 'string') return null;\n            const trimmed = value.trim().toUpperCase();\n            if (!/^[A-Z]{3}$/.test(trimmed)) return null;\n            return trimmed;\n        };\n\n        const getFeatureName = (props) => {\n            if (!props) return null;\n            return props.name || props.admin || props.name_long || props.name_en || props.sovereignt || props.brk_name || null;\n        };\n\n        const getFeatureIso3 = (props) => {\n            if (!props) return null;\n            const candidates = [\n                props.iso3,\n                props.iso_a3,\n                props.adm0_a3,\n                props.sov_a3,\n                props.iso_a3_eh,\n                props.adm0_a3_us,\n                props.adm0_a3_un,\n                props.adm0_a3_wb,\n                props.brk_a3,\n                props.gu_a3,\n                props.su_a3\n            ];\n            for (const value of candidates) {\n                const iso3 = normalizeIso3(value);\n                if (iso3) return iso3;\n            }\n            return null;\n        };\n\n        const parseWorldCountries = (geojson) => {\n            if (!geojson || !Array.isArray(geojson.features)) return [];\n            const map = new Map();\n            for (const feature of geojson.features) {\n                const props = feature?.properties || {};\n                const iso3 = getFeatureIso3(props);\n                if (!iso3) continue;\n                const name = getFeatureName(props) || iso3;\n                if (!map.has(iso3)) {\n                    map.set(iso3, name);\n                }\n            }\n            return Array.from(map.entries())\n                .map(([iso3, name]) => ({ iso3, name }))\n                .sort((a, b) => a.name.localeCompare(b.name));\n        };\n\n        const fetchWorldCountries = async () => {\n            try {\n                const data = await fetchJsonResource(`${geoJsonBasePath}world.geojson`, {\n                    errorMessage: 'GeoJSON world load failed'\n                });\n                return parseWorldCountries(data);\n            } catch (error) {\n                return [];\n            }\n        };\n\n        const fetchAdminIndex = async (level) => {\n            try {\n                const data = await fetchJsonResource(`${geoJsonBasePath}ADM${level}/index.json`, {\n                    errorMessage: `ADM${level} index load failed`\n                });\n                const list = Array.isArray(data?.countries) ? data.countries : [];\n                const filesByIso = new Map();\n                const countries = [];\n                for (const entry of list) {\n                    const iso3 = normalizeIso3(entry?.iso3);\n                    if (!iso3) continue;\n                    const name = entry?.name || iso3;\n                    if (!filesByIso.has(iso3)) {\n                        const file = entry?.file || `ADM${level}/${iso3}.geojson`;\n                        filesByIso.set(iso3, file);\n                        countries.push({ iso3, name });\n                    }\n                }\n                countries.sort((a, b) => a.name.localeCompare(b.name));\n                return { countries, filesByIso };\n            } catch (error) {\n                return { countries: [], filesByIso: new Map() };\n            }\n        };\n\n        const loadGeoJsonIndexes = async () => {\n            const [world, adm1, adm2, adm3] = await Promise.all([\n                fetchWorldCountries(),\n                fetchAdminIndex(1),\n                fetchAdminIndex(2),\n                fetchAdminIndex(3)\n            ]);\n            worldCountries = world.length ? world : adm1.countries;\n            admIndexes.set(1, adm1);\n            admIndexes.set(2, adm2);\n            admIndexes.set(3, adm3);\n        };\n\n        const ensureGeoJsonOptions = async () => {\n            if (geoJsonOptionsReady) return true;\n            if (!cfgGeoJsonAdminLevel || !cfgGeoJsonCountry) return false;\n            if (!geoJsonOptionsPromise) {\n                cfgGeoJsonCountry.disabled = true;\n                cfgGeoJsonCountry.dataset.baseDisabled = 'true';\n                if (!cfgGeoJsonCountry.options.length) {\n                    const option = document.createElement('option');\n                    option.value = '';\n                    option.textContent = 'Loading countries...';\n                    cfgGeoJsonCountry.appendChild(option);\n                }\n                geoJsonOptionsPromise = loadGeoJsonIndexes().then(() => {\n                    geoJsonOptionsReady = true;\n                    setAdminLevelValue(pendingGeoJsonSelection.level);\n                    const nextIso3 = populateCountryOptions(\n                        pendingGeoJsonSelection.level,\n                        pendingGeoJsonSelection.country\n                    );\n                    pendingGeoJsonSelection.country = nextIso3;\n                    applyGeoJsonSelection();\n                    syncGeoJsonControlState();\n                    return true;\n                }).finally(() => {\n                    geoJsonOptionsPromise = null;\n                });\n            }\n            return geoJsonOptionsPromise;\n        };\n\n        const setAdminLevelValue = (value) => {\n            if (!cfgGeoJsonAdminLevel) return;\n            const numeric = Number.parseInt(value, 10);\n            const next = Number.isFinite(numeric) && adminLevels.includes(numeric) ? numeric : 0;\n            cfgGeoJsonAdminLevel.value = String(next);\n        };\n\n        const setMaxDepthValue = (value) => {\n            if (!cfgGeoJsonMaxDepth) return;\n            const numeric = Number.parseInt(value, 10);\n            const next = Number.isFinite(numeric) && maxDepthLevels.includes(numeric) ? numeric : 3;\n            cfgGeoJsonMaxDepth.value = String(next);\n        };\n\n        const syncGeoJsonControlState = () => {\n            const autoDepthEnabled = !!cfgGeoJsonAutoDepth?.checked;\n            if (cfgGeoJsonAdminLevel) cfgGeoJsonAdminLevel.disabled = autoDepthEnabled;\n            if (cfgGeoJsonCountry) {\n                const baseDisabled = cfgGeoJsonCountry.dataset?.baseDisabled === 'true';\n                cfgGeoJsonCountry.disabled = autoDepthEnabled || baseDisabled;\n            }\n            if (cfgGeoJsonMaxDepth) cfgGeoJsonMaxDepth.disabled = !autoDepthEnabled;\n        };\n\n        const populateCountryOptions = (level, selectedIso3) => {\n            if (!cfgGeoJsonCountry) return null;\n            const adminLevel = Number.isFinite(level) ? level : 0;\n            const allowAll = adminLevel === 0;\n            const index = adminLevel === 0\n                ? { countries: worldCountries, filesByIso: new Map() }\n                : (admIndexes.get(adminLevel) || { countries: [], filesByIso: new Map() });\n            const list = index.countries || [];\n            const available = new Set(list.map((entry) => entry.iso3));\n\n            cfgGeoJsonCountry.innerHTML = '';\n            cfgGeoJsonCountry.disabled = false;\n\n            if (allowAll) {\n                const option = document.createElement('option');\n                option.value = '';\n                option.textContent = 'All countries (ADM0)';\n                cfgGeoJsonCountry.appendChild(option);\n            } else {\n                const option = document.createElement('option');\n                option.value = '';\n                option.textContent = list.length ? 'Select a country' : `No ADM${adminLevel} data`;\n                option.disabled = true;\n                option.hidden = !!list.length;\n                cfgGeoJsonCountry.appendChild(option);\n            }\n\n            for (const entry of list) {\n                const option = document.createElement('option');\n                option.value = entry.iso3;\n                option.textContent = `${entry.name} (${entry.iso3})`;\n                cfgGeoJsonCountry.appendChild(option);\n            }\n\n            let nextIso3 = normalizeIso3(selectedIso3);\n            if (!nextIso3 || !available.has(nextIso3)) {\n                nextIso3 = allowAll ? null : (list[0]?.iso3 || null);\n            }\n            cfgGeoJsonCountry.value = nextIso3 || '';\n            if (!allowAll && !list.length) {\n                cfgGeoJsonCountry.disabled = true;\n            }\n            cfgGeoJsonCountry.dataset.baseDisabled = cfgGeoJsonCountry.disabled ? 'true' : 'false';\n            return nextIso3;\n        };\n\n        const resolveSelectionFromSettings = (debug) => {\n            let level = Number.isFinite(debug.geoJsonAdminLevel)\n                ? debug.geoJsonAdminLevel\n                : Number.parseInt(debug.geoJsonAdminLevel, 10);\n            let country = normalizeIso3(debug.geoJsonCountry);\n\n            const source = typeof debug.geoJsonSource === 'string' ? debug.geoJsonSource : '';\n            if ((!Number.isFinite(level) || !country) && source) {\n                const match = source.match(/ADM([1-3])[\\\\/]([A-Za-z]{3})\\.geojson/i);\n                if (match) {\n                    if (!Number.isFinite(level)) {\n                        level = Number.parseInt(match[1], 10);\n                    }\n                    if (!country) {\n                        country = normalizeIso3(match[2]);\n                    }\n                }\n            }\n\n            if (!Number.isFinite(level) || !adminLevels.includes(level)) {\n                level = 0;\n            }\n            return { level, country };\n        };\n\n        const syncFromSettings = () => {\n            const debug = this._getSettingValue('scene.debug', {}) || {};\n            const atmosphere = this._getSettingValue('scene.atmosphere', {}) || {};\n            if (cfgWireframe && typeof debug.wireframe === 'boolean') cfgWireframe.checked = debug.wireframe;\n            if (cfgGeoJson && typeof debug.geoJson === 'boolean') cfgGeoJson.checked = debug.geoJson;\n            if (cfgGeoJsonAutoDepth && typeof debug.geoJsonAutoDepth === 'boolean') {\n                cfgGeoJsonAutoDepth.checked = debug.geoJsonAutoDepth;\n            }\n            if (cfgStatePersist && typeof debug.statePersist === 'boolean') {\n                cfgStatePersist.checked = debug.statePersist;\n            }\n            if (cfgGeoJsonMaxDepth && debug.geoJsonMaxAdminLevel !== undefined) {\n                setMaxDepthValue(debug.geoJsonMaxAdminLevel);\n            }\n            if (cfgAtmosphereEnabled && typeof atmosphere.enabled === 'boolean') {\n                cfgAtmosphereEnabled.checked = atmosphere.enabled;\n            }\n            const selection = resolveSelectionFromSettings(debug);\n            pendingGeoJsonSelection = { ...selection };\n            if (geoJsonOptionsReady && cfgGeoJsonAdminLevel && cfgGeoJsonCountry) {\n                setAdminLevelValue(selection.level);\n                const nextIso3 = populateCountryOptions(selection.level, selection.country);\n                pendingGeoJsonSelection.country = nextIso3;\n            }\n            syncGeoJsonControlState();\n        };\n\n        const setAtmosphereEnabled = (visible) => {\n            if (this._updateSceneSettings({ atmosphere: { enabled: visible } })) return;\n            if (this.onAtmosphereToggle) {\n                this.onAtmosphereToggle(visible);\n            }\n        };\n\n        const applyGeoJson = () => {\n            if (!cfgGeoJson) return;\n            const visible = !!cfgGeoJson.checked;\n            if (this._updateSceneSettings({ debug: { geoJson: visible } })) return;\n            if (typeof this.onGeoJsonToggle === 'function') {\n                this.onGeoJsonToggle(visible);\n            }\n        };\n\n        const applyGeoJsonAutoDepth = () => {\n            if (!cfgGeoJsonAutoDepth) return;\n            const enabled = !!cfgGeoJsonAutoDepth.checked;\n            syncGeoJsonControlState();\n            if (this._updateSceneSettings({ debug: { geoJsonAutoDepth: enabled } })) return;\n        };\n\n        const applyGeoJsonMaxDepth = () => {\n            if (!cfgGeoJsonMaxDepth) return;\n            const numeric = Number.parseInt(cfgGeoJsonMaxDepth.value, 10);\n            const next = Number.isFinite(numeric) && maxDepthLevels.includes(numeric) ? numeric : 3;\n            cfgGeoJsonMaxDepth.value = String(next);\n            if (this._updateSceneSettings({ debug: { geoJsonMaxAdminLevel: next } })) return;\n        };\n\n        const resolveGeoJsonSelection = () => {\n            if (!cfgGeoJsonAdminLevel || !cfgGeoJsonCountry) return null;\n            const adminLevel = Number.parseInt(cfgGeoJsonAdminLevel.value, 10);\n            const level = Number.isFinite(adminLevel) && adminLevels.includes(adminLevel) ? adminLevel : 0;\n            const iso3 = normalizeIso3(cfgGeoJsonCountry.value);\n            if (level === 0) {\n                const source = 'world.geojson';\n                return {\n                    adminLevel: level,\n                    country: iso3 || null,\n                    source,\n                    url: `${geoJsonBasePath}${source}`\n                };\n            }\n            if (!iso3) {\n                return { adminLevel: level, country: null, source: null, url: null };\n            }\n            const index = admIndexes.get(level);\n            const file = index?.filesByIso?.get(iso3) || `ADM${level}/${iso3}.geojson`;\n            return {\n                adminLevel: level,\n                country: iso3,\n                source: file,\n                url: `${geoJsonBasePath}${file}`\n            };\n        };\n\n        const applyGeoJsonSelection = () => {\n            if (cfgGeoJsonAutoDepth?.checked) return;\n            const selection = resolveGeoJsonSelection();\n            if (!selection) return;\n            const patch = {\n                geoJsonAdminLevel: selection.adminLevel,\n                geoJsonCountry: selection.country || null\n            };\n            if (selection.source) {\n                patch.geoJsonSource = selection.source;\n            }\n            if (this._updateSceneSettings({ debug: patch })) return;\n            if (typeof this.onGeoJsonSelectionChange === 'function') {\n                this.onGeoJsonSelectionChange(selection);\n                return;\n            }\n            if (typeof this.onGeoJsonSourceChange === 'function' && selection.url) {\n                this.onGeoJsonSourceChange(selection.url, selection.source, {\n                    adminLevel: selection.adminLevel,\n                    country: selection.country\n                });\n            }\n        };\n\n        const applyWireframe = () => {\n            const wireframeEnabled = !!cfgWireframe.checked;\n            if (!this._updateSceneSettings({ debug: { wireframe: wireframeEnabled } })) {\n                this.triTree.setRenderRules({ wireframe: wireframeEnabled });\n            }\n        };\n\n        cfgWireframe.addEventListener('change', applyWireframe);\n\n        if (cfgGeoJson) cfgGeoJson.addEventListener('change', applyGeoJson);\n        if (cfgGeoJsonAutoDepth) cfgGeoJsonAutoDepth.addEventListener('change', applyGeoJsonAutoDepth);\n        if (cfgGeoJsonMaxDepth) cfgGeoJsonMaxDepth.addEventListener('change', applyGeoJsonMaxDepth);\n        if (cfgGeoJsonAdminLevel) {\n            cfgGeoJsonAdminLevel.addEventListener('pointerdown', () => { void ensureGeoJsonOptions(); }, { passive: true });\n            cfgGeoJsonAdminLevel.addEventListener('focus', () => { void ensureGeoJsonOptions(); });\n            cfgGeoJsonAdminLevel.addEventListener('change', async () => {\n                if (!geoJsonOptionsReady) {\n                    await ensureGeoJsonOptions();\n                }\n                if (!geoJsonOptionsReady) return;\n                const level = Number.parseInt(cfgGeoJsonAdminLevel.value, 10);\n                populateCountryOptions(level, cfgGeoJsonCountry?.value);\n                syncGeoJsonControlState();\n                applyGeoJsonSelection();\n            });\n        }\n        if (cfgGeoJsonCountry) {\n            cfgGeoJsonCountry.addEventListener('pointerdown', () => { void ensureGeoJsonOptions(); }, { passive: true });\n            cfgGeoJsonCountry.addEventListener('focus', () => { void ensureGeoJsonOptions(); });\n            cfgGeoJsonCountry.addEventListener('change', async () => {\n                if (!geoJsonOptionsReady) {\n                    await ensureGeoJsonOptions();\n                }\n                if (!geoJsonOptionsReady) return;\n                applyGeoJsonSelection();\n            });\n        }\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyWireframe();\n        applyGeoJson();\n        applyGeoJsonAutoDepth();\n        applyGeoJsonMaxDepth();\n        if (cfgGeoJsonAdminLevel && cfgGeoJsonCountry) {\n            cfgGeoJsonCountry.disabled = true;\n            cfgGeoJsonCountry.dataset.baseDisabled = 'true';\n            if (!cfgGeoJsonCountry.options.length) {\n                const option = document.createElement('option');\n                option.value = '';\n                option.textContent = 'Choose admin level first';\n                cfgGeoJsonCountry.appendChild(option);\n            }\n        }\n\n        // State persistence toggle\n        const LS_STATE = 'nkn.globe.state';\n        const saveState = () => {\n            const state = this.captureViewState({ includeElevationCache: false });\n            localStorage.setItem(LS_STATE, JSON.stringify(state));\n            if (this._debugViewStateLogging) {\n                console.log('[VIEW STATE] State saved -', state.mode, 'mode');\n            }\n        };\n\n        const togglePersistInterval = () => {\n            if (!cfgStatePersist.checked) {\n                if (this._statePersistInterval) {\n                    clearInterval(this._statePersistInterval);\n                    this._statePersistInterval = null;\n                }\n                return;\n            }\n            if (this._statePersistInterval) return;\n            this._statePersistInterval = setInterval(() => {\n                if (cfgStatePersist.checked) {\n                    saveState();\n                }\n            }, 15000);\n        };\n\n        cfgStatePersist.addEventListener('change', () => {\n            if (!cfgStatePersist.checked) {\n                localStorage.removeItem(LS_STATE);\n            } else {\n                saveState();\n            }\n            this._updateSceneSettings({ debug: { statePersist: cfgStatePersist.checked } }, { apply: false });\n            togglePersistInterval();\n        });\n\n        // Save on camera changes if enabled\n        const throttledSave = this.throttle(() => {\n            // Don't save during view state initialization/restoration\n            if (this._initializingViewState) return;\n            if (cfgStatePersist.checked) saveState();\n        }, 1000);\n\n        if (this.surfaceController && this.surfaceController.controls) {\n            this.surfaceController.controls.addEventListener('change', throttledSave);\n        }\n\n        // Public method for external triggers (e.g., from animation loop)\n        this._saveViewState = saveState;\n        this._throttledSaveViewState = throttledSave;\n\n        if (cfgStatePersist.checked) {\n            saveState();\n        }\n        togglePersistInterval();\n    }\n\n    throttle(fn, delay) {\n        let last = 0;\n        let timeout = null;\n        return (...args) => {\n            const now = Date.now();\n            const remaining = delay - (now - last);\n            if (remaining <= 0) {\n                last = now;\n                fn(...args);\n            } else if (!timeout) {\n                timeout = setTimeout(() => {\n                    last = Date.now();\n                    timeout = null;\n                    fn(...args);\n                }, remaining);\n            }\n        };\n    }\n\n    _readUrlViewState() {\n        if (typeof window === 'undefined') return null;\n        const params = new URLSearchParams(window.location.search);\n        const body = params.get('body');\n        const latParam = String(params.get('latitude') ?? '').trim();\n        const lonParam = String(params.get('longitude') ?? '').trim();\n        const latRaw = latParam ? Number(latParam) : null;\n        const lonRaw = lonParam ? Number(lonParam) : null;\n        const lat = Number.isFinite(latRaw) && latRaw >= -90 && latRaw <= 90 ? latRaw : null;\n        const lon = Number.isFinite(lonRaw)\n            ? ((((lonRaw + 180) % 360) + 360) % 360) - 180\n            : null;\n        // Allow body-only URLs (e.g. ?body=luna without lat/lon)\n        const hasLatLon = Number.isFinite(lat) && Number.isFinite(lon);\n        if (!hasLatLon && !body) return null;\n        const altitudeRaw = Number.parseFloat(params.get('altitude'));\n        const altitude = Number.isFinite(altitudeRaw)\n            && altitudeRaw >= -500\n            && altitudeRaw <= 40_000_000\n                ? altitudeRaw\n                : null;\n        const heading = Number.parseFloat(params.get('heading'));\n        const pitch = Number.parseFloat(params.get('pitch'));\n        const hasHeading = Number.isFinite(heading);\n        const hasPitch = Number.isFinite(pitch);\n        const validBodies = ['terra', 'luna', 'sol'];\n        return {\n            lat: hasLatLon ? lat : null,\n            lon: hasLatLon ? lon : null,\n            altitude,\n            headingDeg: hasHeading ? heading : null,\n            pitchDeg: hasPitch ? pitch : null,\n            hasOrientation: hasHeading || hasPitch,\n            body: (body && validBodies.includes(body.toLowerCase())) ? body.toLowerCase() : null\n        };\n    }\n\n    getUrlViewState() {\n        return this._readUrlViewState() || this._urlViewState || null;\n    }\n\n    _syncEarthRotationForUrl() {\n        if (!this.triTree || !this.triTree.group) return;\n        if (!this.lightingSystem || typeof this.lightingSystem.getEarthRotationAngle !== 'function') return;\n        const angle = this.lightingSystem.getEarthRotationAngle();\n        if (!Number.isFinite(angle)) return;\n        if (typeof this.triTree.setEarthRotation === 'function') {\n            this.triTree.setEarthRotation(angle);\n        } else {\n            this.triTree.group.rotation.y = angle;\n        }\n        this.triTree.group.updateMatrixWorld?.(true);\n    }\n\n    _applyUrlViewState(stateOverride = null, { store = true } = {}) {\n        if (!this.surfaceController || typeof this.surfaceController.initializeSurfaceModeFromLatLon !== 'function') {\n            return false;\n        }\n        const state = stateOverride || this._readUrlViewState();\n        if (!state) return false;\n\n        // Apply celestial body anchor from URL\n        if (state.body && state.body !== 'terra' && typeof this.surfaceController.setBodyAnchorImmediate === 'function') {\n            this.surfaceController.setBodyAnchorImmediate(state.body);\n        }\n\n        // Non-terra body or body-only URL: don't apply Earth lat/lon\n        if ((state.body && state.body !== 'terra') || state.lat === null || state.lon === null) {\n            this._initializingViewState = false;\n            this._urlViewStateApplying = false;\n            return true;\n        }\n\n        this._syncEarthRotationForUrl();\n\n        const altitude = Number.isFinite(state.altitude) ? state.altitude : null;\n        const hasHeading = Number.isFinite(state.headingDeg);\n        const hasPitch = Number.isFinite(state.pitchDeg);\n        const hasOrientation = state.hasOrientation || hasHeading || hasPitch;\n        const surfaceThreshold = Number.isFinite(this.surfaceController?.SURFACE_ALTITUDE_MAX)\n            ? this.surfaceController.SURFACE_ALTITUDE_MAX\n            : 100000;\n        const hasAltitude = Number.isFinite(altitude);\n        const useSurface = (hasAltitude && altitude <= surfaceThreshold)\n            || (!hasAltitude && hasOrientation);\n\n        if (store) {\n            this._urlViewState = state;\n            this._urlViewStateMode = useSurface ? 'surface' : 'orbit';\n            this._urlViewStateEnforceUntilMs = Date.now() + 5000;\n            this._urlViewStateAttempts = 0;\n        }\n\n        if (this._urlViewStateApplying) return true;\n        this._urlViewStateApplying = true;\n        this._initializingViewState = true;\n\n        if (useSurface) {\n            const yaw = hasHeading ? THREE.MathUtils.degToRad(state.headingDeg) : 0;\n            const pitch = hasPitch ? THREE.MathUtils.degToRad(state.pitchDeg) : 0;\n\n            const upDir = latLonToLocalDir(state.lat, state.lon);\n            if (this.triTree?.group?.getWorldQuaternion) {\n                const planetQuat = new THREE.Quaternion();\n                this.triTree.group.getWorldQuaternion(planetQuat);\n                upDir.applyQuaternion(planetQuat);\n            }\n            const terrainR = this.surfaceController?.sampleTerrainRadiusForDir\n                ? this.surfaceController.sampleTerrainRadiusForDir(upDir)\n                : PLANET_RADIUS;\n            // PlanetScene is the sole URL writer and stores surface altitude above\n            // the active terrain floor (AGL). Keep the canonical latitude/longitude\n            // reader on that same contract. Subtracting terrain elevation here\n            // interpreted the value as MSL, then setSurfaceAltitudeMSL applied it\n            // a second time. The first terrain drag subsequently resynchronised the\n            // camera and appeared as a large altitude snap.\n            let surfaceAlt = Number.isFinite(altitude) ? altitude : null;\n            const minSurfaceAlt = Number.isFinite(this.surfaceController?.SURFACE_ALTITUDE_MIN)\n                ? this.surfaceController.SURFACE_ALTITUDE_MIN\n                : 1.6;\n            if (Number.isFinite(surfaceAlt)) {\n                surfaceAlt = Math.max(minSurfaceAlt, surfaceAlt);\n            }\n            this.surfaceController.initializeSurfaceModeFromLatLon(\n                state.lat,\n                state.lon,\n                terrainR,\n                yaw,\n                pitch,\n                surfaceAlt\n            );\n            if (this.triTree && typeof this.triTree.initializeSurfaceLODCascade === 'function') {\n                this.triTree.initializeSurfaceLODCascade();\n            }\n            this.handleSurfaceEnter({ reason: 'url' });\n            setTimeout(() => {\n                this._initializingViewState = false;\n                this._urlViewStateApplying = false;\n                if (!this._urlViewState || Date.now() > this._urlViewStateEnforceUntilMs) {\n                    this._updateUrlFromView({ force: true });\n                }\n            }, 500);\n            return true;\n        }\n\n        const dir = latLonToLocalDir(state.lat, state.lon);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            const planetQuat = new THREE.Quaternion();\n            this.triTree.group.getWorldQuaternion(planetQuat);\n            dir.applyQuaternion(planetQuat);\n        }\n        const ellipsoidR = ellipsoidRadiusForWorldDir(dir, this.triTree?.group);\n        const baseRadius = Number.isFinite(altitude)\n            ? ellipsoidR + altitude\n            : (this.camera?.position?.length?.() || PLANET_RADIUS + surfaceThreshold);\n        const pos = dir.multiplyScalar(baseRadius);\n        this.camera.position.copy(pos);\n        this.camera.lookAt(0, 0, 0);\n        if (this.surfaceController?.setLODMode) {\n            this.surfaceController.setLODMode('orbit');\n        }\n        if (this.surfaceController?.controls) {\n            this.surfaceController.controls.target.set(0, 0, 0);\n            this.surfaceController.controls.update();\n        }\n\n        this._initializingViewState = false;\n        this._urlViewStateApplying = false;\n        if (!this._urlViewState || Date.now() > this._urlViewStateEnforceUntilMs) {\n            this._updateUrlFromView({ force: true });\n        }\n        return true;\n    }\n\n    _updateUrlFromView({ force = false } = {}) {\n        // ── DISABLED: superseded by PlanetScene._updateUrlFromView ─────\n        //\n        // The legacy implementation (preserved below in version control\n        // history) wrote `altitude=` to the URL with no bounds check on\n        // the value, no awareness of the camera's parent hierarchy, and\n        // a different MSL/AGL formula than PlanetScene's writer. Two\n        // writers racing to the URL produced inconsistent values and,\n        // when the camera read its position locally inside a non-zero\n        // vrDolly, even bogus `altitude=-6266732`.\n        //\n        // PlanetScene._updateUrlFromView is now the only URL writer.\n        // This method remains as a no-op shell for any internal call\n        // site that hasn't been refactored yet.\n        return;\n    }\n\n    _enforceUrlViewState() {\n        if (!this._urlViewState || this._urlViewStateApplying || this._initializingViewState) return;\n        if (Date.now() > this._urlViewStateEnforceUntilMs) {\n            this._urlViewState = null;\n            this._urlViewStateMode = null;\n            return;\n        }\n        const wantsSurface = this._urlViewStateMode === 'surface';\n        const inSurface = !!this.surfaceController?.isInSurfaceMode?.();\n        if (wantsSurface && !inSurface) {\n            if (this._urlViewStateAttempts >= this._urlViewStateMaxAttempts) {\n                this._urlViewState = null;\n                this._urlViewStateMode = null;\n                return;\n            }\n            this._urlViewStateAttempts += 1;\n            this._applyUrlViewState(this._urlViewState, { store: false });\n        }\n    }\n\n    captureViewState({ includeElevationCache = false } = {}) {\n        // Get the actual camera mode from the controller (orbit, surface, toSurface, toOrbit)\n        const rawMode = this.surfaceController?.getCameraMode?.() || 'orbit';\n\n        // For saving state, normalize transition modes to their target state\n        // 'toSurface' -> 'surface', 'toOrbit' -> 'orbit'\n        const mode = (rawMode === 'surface' || rawMode === 'toSurface') ? 'surface' : 'orbit';\n\n        const camera = this.camera;\n        const controls = this.surfaceController ? this.surfaceController.controls : null;\n        const target = controls ? controls.target.clone() : new THREE.Vector3();\n        const worldPos = camera?.userData?.worldPosition;\n        const camPos = worldPos ? worldPos.clone() : camera.position.clone();\n        const camQuat = new THREE.Quaternion();\n        camera.getWorldQuaternion(camQuat);\n        const surfacePos = this.surfaceController ? this.surfaceController.getSurfacePosition() : null;\n        const planetGroup = this.triTree?.group || null;\n        const lodMode = this.surfaceController?.getLODMode?.() || 'orbit';\n        const surfaceAltitude = this.surfaceController?.getSurfaceAltitudeMeters?.() ?? null;\n        const surfaceTerrainRadius = surfacePos ? surfacePos.length() : null;\n        const surfaceLatLon = surfacePos ? worldPosToLatLonLocal(surfacePos, planetGroup) : null;\n\n        let orbitLatLon = null;\n        let orbitRadius = null;\n        if (mode === 'orbit') {\n            orbitRadius = camPos.length();\n            const viewDir = new THREE.Vector3();\n            camera.getWorldDirection(viewDir);\n            const hit = rayEllipsoidIntersection(camPos, viewDir, planetGroup) ||\n                raySphereIntersection(camPos, viewDir);\n            const baseRadius = ellipsoidRadiusForWorldDir(camPos, planetGroup);\n            const targetPos = hit || camPos.clone().normalize().multiplyScalar(baseRadius);\n            orbitLatLon = worldPosToLatLonLocal(targetPos, planetGroup);\n        }\n\n        // Capture surface camera orientation (yaw/pitch) when in surface mode\n        // No need for lat/lon conversion - we save camera.position directly just like orbit mode\n        let surfaceOrientation = null;\n        if (mode === 'surface' && this.surfaceController && this.surfaceController.surfaceState) {\n            surfaceOrientation = {\n                yaw: this.surfaceController.surfaceState.yaw,\n                pitch: this.surfaceController.surfaceState.pitch\n            };\n            if (this._debugViewStateLogging) {\n                console.log('[VIEW STATE] Saved surface orientation - yaw:', surfaceOrientation.yaw, 'pitch:', surfaceOrientation.pitch);\n            }\n        }\n\n        // Capture VR state if in VR mode\n        // Note: We save the dolly position as the VR \"feet position\" for restoration\n        let vrState = null;\n        const isVRMode = this.surfaceController?.isVRMode?.() ?? false;\n        if (isVRMode || this.sceneInitializer?.isXRPresenting?.()) {\n            const dolly = this.sceneInitializer?.vrDolly;\n            if (dolly) {\n                vrState = {\n                    wasInVR: true,\n                    dollyPosition: { x: dolly.position.x, y: dolly.position.y, z: dolly.position.z },\n                    dollyRotationY: dolly.rotation.y\n                };\n            }\n        }\n\n        const state = {\n            mode,\n            lodMode,\n            camera: { x: camPos.x, y: camPos.y, z: camPos.z },\n            quaternion: { x: camQuat.x, y: camQuat.y, z: camQuat.z, w: camQuat.w },\n            target: { x: target.x, y: target.y, z: target.z },\n            surface: surfacePos ? { x: surfacePos.x, y: surfacePos.y, z: surfacePos.z } : null,\n            surfaceLatLon: surfaceLatLon ? { lat: surfaceLatLon.latDeg, lon: surfaceLatLon.lonDeg } : null,\n            surfaceOrientation: surfaceOrientation,\n            surfaceAltitude: surfaceAltitude,\n            surfaceTerrainRadius: surfaceTerrainRadius,\n            orbitLatLon: orbitLatLon ? { lat: orbitLatLon.latDeg, lon: orbitLatLon.lonDeg } : null,\n            orbitRadius: orbitRadius,\n            vrState: vrState\n        };\n\n        if (this._debugViewStateLogging) {\n            console.log(\n                '[VIEW STATE] Capturing state - mode:',\n                mode,\n                'camPos:',\n                camPos,\n                'orientation:',\n                surfaceOrientation || 'orbit mode'\n            );\n        }\n        return state;\n    }\n\n    restoreViewState() {\n        const LS_STATE = 'nkn.globe.state';\n        const raw = localStorage.getItem(LS_STATE);\n        if (!raw) {\n            console.log('[VIEW STATE] No saved state found');\n            return;\n        }\n        let state = null;\n        try {\n            state = JSON.parse(raw);\n        } catch (e) {\n            console.warn('[VIEW STATE] Failed to parse saved view state', e);\n            return;\n        }\n        this._applyViewStateSnapshot(state, { updateUrl: true, applyElevationCache: true, allowPersistToggle: true });\n    }\n\n    applyViewStateSnapshot(state, { updateUrl = false, applyElevationCache = false } = {}) {\n        this._applyViewStateSnapshot(state, { updateUrl, applyElevationCache, allowPersistToggle: false });\n    }\n\n    _applyViewStateSnapshot(state, { updateUrl = true, applyElevationCache = true, allowPersistToggle = true } = {}) {\n        if (!state || !state.camera) {\n            console.warn('[VIEW STATE] Invalid state - missing camera data');\n            return;\n        }\n\n        if (this.triTree && this.lightingSystem\n            && typeof this.triTree.setEarthRotation === 'function'\n            && typeof this.lightingSystem.getEarthRotationAngle === 'function') {\n            const angle = this.lightingSystem.getEarthRotationAngle();\n            this.triTree.setEarthRotation(angle);\n            this.triTree.group?.updateMatrixWorld?.(true);\n        }\n\n        // Elevation cache restore now handled by unified SceneStateStore\n        const { camera: savedCamera, target, surface, mode } = state;\n        if (this._debugViewStateLogging) {\n            console.log('[VIEW STATE] Restoring state:', {\n                mode,\n                hasCamera: !!savedCamera,\n                hasSurface: !!surface,\n                hasOrientation: !!state.surfaceOrientation\n            });\n        }\n\n        const isSurfaceMode = mode === 'surface' && this.surfaceController;\n        const lodMode = isSurfaceMode ? 'zoom' : (state.lodMode || 'orbit');\n        if (this.surfaceController && typeof this.surfaceController.setLODMode === 'function') {\n            this.surfaceController.setLODMode(lodMode);\n        }\n\n        const { btnLodOrbit, btnLodZoom, cfgStatePersist } = this.elements;\n        if (btnLodOrbit && btnLodZoom) {\n            btnLodOrbit.classList.toggle('active', lodMode === 'orbit');\n            btnLodZoom.classList.toggle('active', lodMode === 'zoom');\n        }\n        this.syncLodButtons();\n\n        const resolveWorldDirFromLatLon = (lat, lon) => {\n            if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;\n            const localDir = latLonToLocalDir(lat, lon);\n            if (this.triTree?.group && typeof this.triTree.group.getWorldQuaternion === 'function') {\n                const worldQuat = this.triTree.group.getWorldQuaternion(new THREE.Quaternion());\n                return localDir.applyQuaternion(worldQuat);\n            }\n            return localDir;\n        };\n\n        if (isSurfaceMode && typeof this.surfaceController.initializeSurfaceMode === 'function') {\n            console.log('[VIEW STATE] Saved state indicates surface mode, activating surface controls...');\n\n            const yaw = state.surfaceOrientation ? state.surfaceOrientation.yaw : 0;\n            const pitch = state.surfaceOrientation ? state.surfaceOrientation.pitch : 0;\n\n            const surfaceLatLon = state.surfaceLatLon;\n            let surfaceDir = null;\n            if (surfaceLatLon && Number.isFinite(surfaceLatLon.lat) && Number.isFinite(surfaceLatLon.lon)) {\n                surfaceDir = resolveWorldDirFromLatLon(surfaceLatLon.lat, surfaceLatLon.lon);\n            }\n\n            const surfaceVec = (surface && Number.isFinite(surface.x) && Number.isFinite(surface.y) && Number.isFinite(surface.z))\n                ? new THREE.Vector3(surface.x, surface.y, surface.z)\n                : null;\n            const cameraVec = new THREE.Vector3(savedCamera.x, savedCamera.y, savedCamera.z);\n            if (!surfaceDir) {\n                surfaceDir = surfaceVec && surfaceVec.lengthSq() > 0\n                    ? surfaceVec.clone().normalize()\n                    : cameraVec;\n                if (surfaceDir.lengthSq() > 0) {\n                    surfaceDir.normalize();\n                } else {\n                    surfaceDir = new THREE.Vector3(0, 1, 0);\n                }\n            }\n\n            const terrainRadius = Number.isFinite(state.surfaceTerrainRadius)\n                ? state.surfaceTerrainRadius\n                : (surfaceVec ? surfaceVec.length() : null);\n            const altitude = Number.isFinite(state.surfaceAltitude)\n                ? state.surfaceAltitude\n                : null;\n\n            this._initializingViewState = true;\n\n            this.surfaceController.initializeSurfaceMode(surfaceDir, yaw, pitch, altitude, terrainRadius);\n\n            if (this.triTree && typeof this.triTree.initializeSurfaceLODCascade === 'function') {\n                this.triTree.initializeSurfaceLODCascade();\n            }\n\n            this.handleSurfaceEnter({ reason: 'restore' });\n\n            setTimeout(() => {\n                this._initializingViewState = false;\n                console.log('[VIEW STATE] Initialization complete, state saves now enabled');\n                if (updateUrl) {\n                    this._updateUrlFromView({ force: true });\n                }\n            }, 500);\n        } else {\n            const orbitLatLon = state.orbitLatLon;\n            const orbitRadius = Number.isFinite(state.orbitRadius) ? state.orbitRadius : null;\n            const orbitDir = (orbitLatLon && Number.isFinite(orbitLatLon.lat) && Number.isFinite(orbitLatLon.lon))\n                ? resolveWorldDirFromLatLon(orbitLatLon.lat, orbitLatLon.lon)\n                : null;\n\n            if (orbitDir && orbitRadius) {\n                const pos = orbitDir.multiplyScalar(orbitRadius);\n                this.camera.position.copy(pos);\n                this.camera.lookAt(0, 0, 0);\n                if (this.surfaceController && this.surfaceController.controls) {\n                    this.surfaceController.controls.target.set(0, 0, 0);\n                    this.surfaceController.controls.update();\n                }\n                console.log('[VIEW STATE] ✓ Orbit restored from lat/lon');\n            } else {\n                // Restore camera position immediately\n                this.camera.position.set(savedCamera.x, savedCamera.y, savedCamera.z);\n\n                // Restore camera quaternion for exact orientation\n                if (state.quaternion) {\n                    this.camera.quaternion.set(\n                        state.quaternion.x,\n                        state.quaternion.y,\n                        state.quaternion.z,\n                        state.quaternion.w\n                    );\n                    console.log('[VIEW STATE] ✓ Camera quaternion restored');\n                }\n\n                // Restore orbit controls target if available\n                if (this.surfaceController && this.surfaceController.controls && target) {\n                    this.surfaceController.controls.target.set(target.x, target.y, target.z);\n                    this.surfaceController.controls.update();\n                }\n            }\n        }\n\n        // Restore VR dolly position if user was in VR when they left\n        // This positions the dolly so when they enter VR again, they'll be at the same spot\n        if (state.vrState && state.vrState.wasInVR && this.sceneInitializer?.vrDolly) {\n            const dolly = this.sceneInitializer.vrDolly;\n            const dollyPos = state.vrState.dollyPosition;\n            if (dollyPos && Number.isFinite(dollyPos.x) && Number.isFinite(dollyPos.y) && Number.isFinite(dollyPos.z)) {\n                dolly.position.set(dollyPos.x, dollyPos.y, dollyPos.z);\n            }\n            if (Number.isFinite(state.vrState.dollyRotationY)) {\n                dolly.rotation.set(0, state.vrState.dollyRotationY, 0);\n            }\n            dolly.updateMatrixWorld(true);\n            console.log('[VIEW STATE] ✓ VR dolly position restored:', dollyPos);\n        }\n\n        if (allowPersistToggle && cfgStatePersist) cfgStatePersist.checked = true;\n        if (updateUrl) {\n            this._updateUrlFromView({ force: true });\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Lighting / Time Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupLightingControls() {\n        const { cfgDate, cfgTime, cfgTimeSpeed, cfgTimeSpeedLabel, cfgUseSimplified } = this.elements;\n        const { btnTimeNow, btnTimeSunrise, btnTimeNoon, btnTimeSunset, btnTimeMidnight } = this.elements;\n\n        const pad2 = (value) => String(value).padStart(2, '0');\n        const formatUtcDateInput = (date) => {\n            const year = date.getUTCFullYear();\n            const month = pad2(date.getUTCMonth() + 1);\n            const day = pad2(date.getUTCDate());\n            return `${year}-${month}-${day}`;\n        };\n\n        const updateTimeInputs = () => {\n            if (!this.lightingSystem) return;\n            const timeInfo = this.lightingSystem.getTimeInfo();\n            const date = timeInfo.date;\n\n            const activeEl = document.activeElement;\n            if (cfgDate && activeEl !== cfgDate) {\n                cfgDate.value = formatUtcDateInput(date);\n            }\n            if (cfgTime && activeEl !== cfgTime) {\n                cfgTime.value = `${pad2(date.getUTCHours())}:${pad2(date.getUTCMinutes())}`;\n            }\n            if (cfgTimeSpeed) {\n                cfgTimeSpeed.value = this.lightingSystem.timeSpeed;\n            }\n\n            if (this.lightingSystem.timeSpeed === 0) {\n                cfgTimeSpeedLabel.textContent = 'Paused';\n            } else if (this.lightingSystem.followSystemTime) {\n                cfgTimeSpeedLabel.textContent = 'Live';\n            } else if (this.lightingSystem.timeSpeed === 1) {\n                cfgTimeSpeedLabel.textContent = 'Real-time';\n            } else {\n                cfgTimeSpeedLabel.textContent = `${this.lightingSystem.timeSpeed}×`;\n            }\n        };\n\n        const syncFromSettings = () => {\n            updateTimeInputs();\n            if (cfgUseSimplified) {\n                cfgUseSimplified.checked = !!this.lightingSystem.useSimplified;\n            }\n        };\n\n        const persistLighting = (patch) => {\n            this._updateSceneSettings({ lighting: patch }, { apply: false });\n        };\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n\n        if (!this._lightingLiveInterval) {\n            this._lightingLiveInterval = setInterval(() => {\n                updateTimeInputs();\n            }, 1000);\n        }\n\n        cfgDate.addEventListener('change', () => {\n            if (!cfgDate.value) return;\n            const [year, month, day] = cfgDate.value.split('-').map(Number);\n            if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return;\n            const current = this.lightingSystem.currentDate;\n            const next = new Date(Date.UTC(\n                year,\n                month - 1,\n                day,\n                current.getUTCHours(),\n                current.getUTCMinutes(),\n                0,\n                0\n            ));\n            this.lightingSystem.setDate(next);\n            this.lightingSystem.setTimeSpeed(0);\n            persistLighting({\n                date: this.lightingSystem.currentDate.toISOString(),\n                timeSpeed: 0\n            });\n            updateTimeInputs();\n        });\n\n        cfgTime.addEventListener('change', () => {\n            if (cfgTime.value) {\n                const [hours, minutes] = cfgTime.value.split(':').map(Number);\n                this.lightingSystem.setTimeOfDay(hours, minutes || 0);\n                this.lightingSystem.setTimeSpeed(0);\n                persistLighting({\n                    date: this.lightingSystem.currentDate.toISOString(),\n                    timeSpeed: 0\n                });\n                updateTimeInputs();\n            }\n        });\n\n        cfgTimeSpeed.addEventListener('input', () => {\n            const speed = parseFloat(cfgTimeSpeed.value) || 0;\n            this.lightingSystem.setFollowSystemTime(false);\n            this.lightingSystem.setTimeSpeed(speed);\n            persistLighting({ timeSpeed: speed });\n            updateTimeInputs();\n        });\n\n        cfgUseSimplified.addEventListener('change', () => {\n            this.lightingSystem.setSimplifiedMode(cfgUseSimplified.checked);\n            persistLighting({ simplified: cfgUseSimplified.checked });\n        });\n\n        btnTimeNow.addEventListener('click', () => {\n            this.lightingSystem.setFollowSystemTime(true);\n            this.lightingSystem.setTimeSpeed(1);\n            persistLighting({ date: null, timeSpeed: 1 });\n            updateTimeInputs();\n        });\n\n        btnTimeSunrise.addEventListener('click', () => {\n            this.lightingSystem.setTimeOfDay(6, 0);\n            this.lightingSystem.setTimeSpeed(0);\n            persistLighting({\n                date: this.lightingSystem.currentDate.toISOString(),\n                timeSpeed: 0\n            });\n            updateTimeInputs();\n        });\n\n        btnTimeNoon.addEventListener('click', () => {\n            this.lightingSystem.setTimeOfDay(12, 0);\n            this.lightingSystem.setTimeSpeed(0);\n            persistLighting({\n                date: this.lightingSystem.currentDate.toISOString(),\n                timeSpeed: 0\n            });\n            updateTimeInputs();\n        });\n\n        btnTimeSunset.addEventListener('click', () => {\n            this.lightingSystem.setTimeOfDay(18, 0);\n            this.lightingSystem.setTimeSpeed(0);\n            persistLighting({\n                date: this.lightingSystem.currentDate.toISOString(),\n                timeSpeed: 0\n            });\n            updateTimeInputs();\n        });\n\n        btnTimeMidnight.addEventListener('click', () => {\n            this.lightingSystem.setTimeOfDay(0, 0);\n            this.lightingSystem.setTimeSpeed(0);\n            persistLighting({\n                date: this.lightingSystem.currentDate.toISOString(),\n                timeSpeed: 0\n            });\n            updateTimeInputs();\n        });\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Atmosphere Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupAtmosphereControls() {\n        const {\n            cfgAtmosphereEnabled,\n            cfgAtmBaseOffset,\n            cfgAtmBaseOffsetRange,\n            cfgAtmIrradianceScale,\n            cfgAtmIrradianceScaleRange,\n            cfgAtmShadowRadius,\n            cfgAtmShadowRadiusRange,\n            cfgAtmSkyAlphaScale,\n            cfgAtmSkyAlphaScaleRange,\n            cfgAtmSkyAlphaClamp,\n            cfgAtmSkyAlphaClampRange,\n            cfgAtmSkyLimbBoost,\n            cfgAtmSkyLimbBoostRange,\n            cfgAtmSkyPathShort,\n            cfgAtmSkyPathShortRange,\n            cfgAtmSkyLimbMax,\n            cfgAtmSkyLimbMaxRange,\n            cfgAtmSkyDensityScale,\n            cfgAtmSkyDensityScaleRange,\n            cfgAtmSkyScaleHeight,\n            cfgAtmSkyScaleHeightRange,\n            cfgAtmSkyVerticalFadeStart,\n            cfgAtmSkyVerticalFadeStartRange,\n            cfgAtmSkyVerticalFadeEnd,\n            cfgAtmSkyVerticalFadeEndRange,\n            cfgAtmSkyAltitudeFadeStart,\n            cfgAtmSkyAltitudeFadeStartRange,\n            cfgAtmSkyAltitudeFadeEnd,\n            cfgAtmSkyAltitudeFadeEndRange,\n            cfgAtmSkyOutsideFadeStart,\n            cfgAtmSkyOutsideFadeStartRange,\n            cfgAtmSkyOutsideFadeEnd,\n            cfgAtmSkyOutsideFadeEndRange,\n            cfgAtmSkyDepthThreshold,\n            cfgAtmSkyDepthThresholdRange,\n            cfgAtmPhotometric,\n            cfgAtmSunIrradiance,\n            cfgAtmSkyIrradiance,\n            cfgAtmTransmittance,\n            cfgAtmInscatter,\n            cfgAtmSky,\n            cfgAtmSun,\n            cfgAtmMoon,\n            cfgCloudsEnabled,\n            cfgCloudCoverage,\n            cfgCloudCoverageRange,\n            cfgCloudScattering,\n            cfgCloudScatteringRange,\n            cfgCloudAbsorption,\n            cfgCloudAbsorptionRange,\n            cfgCloudTurbulenceDisp,\n            cfgCloudTurbulenceDispRange,\n            cfgCloudLightShafts,\n            cfgCloudShapeDetail,\n            cfgCloudTurbulence,\n            cfgCloudHaze,\n            cfgCloudLowAltitude,\n            cfgCloudLowAltitudeRange,\n            cfgCloudLowHeight,\n            cfgCloudLowHeightRange,\n            cfgCloudMidAltitude,\n            cfgCloudMidAltitudeRange,\n            cfgCloudMidHeight,\n            cfgCloudMidHeightRange,\n            cfgCloudHighAltitude,\n            cfgCloudHighAltitudeRange,\n            cfgCloudHighHeight,\n            cfgCloudHighHeightRange\n        } = this.elements;\n\n        this.onAtmosphereToggle = null;\n\n        const toNumber = (value, fallback) => {\n            const num = Number(value);\n            return Number.isFinite(num) ? num : fallback;\n        };\n\n        const applyAtmospherePatch = (patch) => {\n            if (!patch || Object.keys(patch).length === 0) return;\n            if (this._updateSceneSettings({ atmosphere: patch })) return;\n            if (this.sceneInitializer?.setAtmosphereCloudsConfig) {\n                this.sceneInitializer.setAtmosphereCloudsConfig(patch);\n            }\n        };\n\n        const syncFromSettings = () => {\n            const atmosphere = this._getSettingValue('scene.atmosphere', {}) || {};\n            if (cfgAtmosphereEnabled && typeof atmosphere.enabled === 'boolean') {\n                cfgAtmosphereEnabled.checked = atmosphere.enabled;\n            }\n\n            const baseOffset = toNumber(atmosphere.baseOffsetMeters, toNumber(cfgAtmBaseOffset?.value, 0));\n            const irradianceScale = toNumber(\n                atmosphere.irradianceScale,\n                toNumber(\n                    cfgAtmIrradianceScale?.value,\n                    PHOTOREAL_ALBEDO_SCALE_DEFAULT\n                )\n            );\n            const shadowRadius = toNumber(atmosphere.shadowRadius, toNumber(cfgAtmShadowRadius?.value, 3));\n\n            this._setRangeNumber(cfgAtmBaseOffsetRange, cfgAtmBaseOffset, baseOffset);\n            this._setRangeNumber(cfgAtmIrradianceScaleRange, cfgAtmIrradianceScale, irradianceScale);\n            this._setRangeNumber(cfgAtmShadowRadiusRange, cfgAtmShadowRadius, shadowRadius);\n\n            const skyTuning = atmosphere.skyTuning || {};\n            const skyAlphaScale = toNumber(skyTuning.alphaScale, toNumber(cfgAtmSkyAlphaScale?.value, 1));\n            const skyAlphaClamp = toNumber(skyTuning.alphaClamp, toNumber(cfgAtmSkyAlphaClamp?.value, 0.85));\n            const skyLimbBoost = toNumber(skyTuning.limbBoost, toNumber(cfgAtmSkyLimbBoost?.value, 2.5));\n            const skyPathShort = toNumber(skyTuning.pathShort, toNumber(cfgAtmSkyPathShort?.value, 0.25));\n            const skyLimbMax = toNumber(skyTuning.limbMax, toNumber(cfgAtmSkyLimbMax?.value, 6));\n            const skyDensityScale = toNumber(skyTuning.densityScale, toNumber(cfgAtmSkyDensityScale?.value, 2));\n            const skyScaleHeight = toNumber(skyTuning.scaleHeight, toNumber(cfgAtmSkyScaleHeight?.value, 0.08));\n            const skyVerticalFadeStart = toNumber(\n                skyTuning.verticalFadeStart,\n                toNumber(cfgAtmSkyVerticalFadeStart?.value, 0.05)\n            );\n            const skyVerticalFadeEnd = toNumber(\n                skyTuning.verticalFadeEnd,\n                toNumber(cfgAtmSkyVerticalFadeEnd?.value, 0.4)\n            );\n            const skyAltitudeFadeStart = toNumber(\n                skyTuning.altitudeFadeStart,\n                toNumber(cfgAtmSkyAltitudeFadeStart?.value, 0.5)\n            );\n            const skyAltitudeFadeEnd = toNumber(\n                skyTuning.altitudeFadeEnd,\n                toNumber(cfgAtmSkyAltitudeFadeEnd?.value, 1.0)\n            );\n            const skyOutsideFadeStart = toNumber(\n                skyTuning.outsideFadeStart,\n                toNumber(cfgAtmSkyOutsideFadeStart?.value, 0.0)\n            );\n            const skyOutsideFadeEnd = toNumber(\n                skyTuning.outsideFadeEnd,\n                toNumber(cfgAtmSkyOutsideFadeEnd?.value, 0.1)\n            );\n            const skyDepthThreshold = toNumber(\n                skyTuning.depthThreshold,\n                toNumber(cfgAtmSkyDepthThreshold?.value, 0.9999999)\n            );\n\n            this._setRangeNumber(cfgAtmSkyAlphaScaleRange, cfgAtmSkyAlphaScale, skyAlphaScale);\n            this._setRangeNumber(cfgAtmSkyAlphaClampRange, cfgAtmSkyAlphaClamp, skyAlphaClamp);\n            this._setRangeNumber(cfgAtmSkyLimbBoostRange, cfgAtmSkyLimbBoost, skyLimbBoost);\n            this._setRangeNumber(cfgAtmSkyPathShortRange, cfgAtmSkyPathShort, skyPathShort);\n            this._setRangeNumber(cfgAtmSkyLimbMaxRange, cfgAtmSkyLimbMax, skyLimbMax);\n            this._setRangeNumber(cfgAtmSkyDensityScaleRange, cfgAtmSkyDensityScale, skyDensityScale);\n            this._setRangeNumber(cfgAtmSkyScaleHeightRange, cfgAtmSkyScaleHeight, skyScaleHeight);\n            this._setRangeNumber(\n                cfgAtmSkyVerticalFadeStartRange,\n                cfgAtmSkyVerticalFadeStart,\n                skyVerticalFadeStart\n            );\n            this._setRangeNumber(\n                cfgAtmSkyVerticalFadeEndRange,\n                cfgAtmSkyVerticalFadeEnd,\n                skyVerticalFadeEnd\n            );\n            this._setRangeNumber(\n                cfgAtmSkyAltitudeFadeStartRange,\n                cfgAtmSkyAltitudeFadeStart,\n                skyAltitudeFadeStart\n            );\n            this._setRangeNumber(\n                cfgAtmSkyAltitudeFadeEndRange,\n                cfgAtmSkyAltitudeFadeEnd,\n                skyAltitudeFadeEnd\n            );\n            this._setRangeNumber(\n                cfgAtmSkyOutsideFadeStartRange,\n                cfgAtmSkyOutsideFadeStart,\n                skyOutsideFadeStart\n            );\n            this._setRangeNumber(\n                cfgAtmSkyOutsideFadeEndRange,\n                cfgAtmSkyOutsideFadeEnd,\n                skyOutsideFadeEnd\n            );\n            this._setRangeNumber(\n                cfgAtmSkyDepthThresholdRange,\n                cfgAtmSkyDepthThreshold,\n                skyDepthThreshold\n            );\n\n            if (cfgAtmPhotometric && typeof atmosphere.photometric === 'boolean') {\n                cfgAtmPhotometric.checked = atmosphere.photometric;\n            }\n            if (cfgAtmSunIrradiance && typeof atmosphere.sunIrradiance === 'boolean') {\n                cfgAtmSunIrradiance.checked = atmosphere.sunIrradiance;\n            }\n            if (cfgAtmSkyIrradiance && typeof atmosphere.skyIrradiance === 'boolean') {\n                cfgAtmSkyIrradiance.checked = atmosphere.skyIrradiance;\n            }\n            if (cfgAtmTransmittance && typeof atmosphere.transmittance === 'boolean') {\n                cfgAtmTransmittance.checked = atmosphere.transmittance;\n            }\n            if (cfgAtmInscatter && typeof atmosphere.inscatter === 'boolean') {\n                cfgAtmInscatter.checked = atmosphere.inscatter;\n            }\n            if (cfgAtmSky && typeof atmosphere.sky === 'boolean') cfgAtmSky.checked = atmosphere.sky;\n            if (cfgAtmSun && typeof atmosphere.sun === 'boolean') cfgAtmSun.checked = atmosphere.sun;\n            if (cfgAtmMoon && typeof atmosphere.moon === 'boolean') cfgAtmMoon.checked = atmosphere.moon;\n\n            const cloudSettings = atmosphere.clouds || {};\n            if (cfgCloudsEnabled && typeof cloudSettings.enabled === 'boolean') {\n                cfgCloudsEnabled.checked = cloudSettings.enabled;\n            }\n            const cloudCoverage = toNumber(cloudSettings.coverage, toNumber(cfgCloudCoverage?.value, 0.3));\n            const scattering = toNumber(cloudSettings.scatteringCoefficient, toNumber(cfgCloudScattering?.value, 1));\n            const absorption = toNumber(cloudSettings.absorptionCoefficient, toNumber(cfgCloudAbsorption?.value, 0));\n            const turbulenceDisp = toNumber(\n                cloudSettings.turbulenceDisplacement,\n                toNumber(cfgCloudTurbulenceDisp?.value, 350)\n            );\n\n            this._setRangeNumber(cfgCloudCoverageRange, cfgCloudCoverage, cloudCoverage);\n            this._setRangeNumber(cfgCloudScatteringRange, cfgCloudScattering, scattering);\n            this._setRangeNumber(cfgCloudAbsorptionRange, cfgCloudAbsorption, absorption);\n            this._setRangeNumber(cfgCloudTurbulenceDispRange, cfgCloudTurbulenceDisp, turbulenceDisp);\n\n            if (cfgCloudLightShafts && typeof cloudSettings.lightShafts === 'boolean') {\n                cfgCloudLightShafts.checked = cloudSettings.lightShafts;\n            }\n            if (cfgCloudShapeDetail && typeof cloudSettings.shapeDetail === 'boolean') {\n                cfgCloudShapeDetail.checked = cloudSettings.shapeDetail;\n            }\n            if (cfgCloudTurbulence && typeof cloudSettings.turbulence === 'boolean') {\n                cfgCloudTurbulence.checked = cloudSettings.turbulence;\n            }\n            if (cfgCloudHaze && typeof cloudSettings.haze === 'boolean') {\n                cfgCloudHaze.checked = cloudSettings.haze;\n            }\n\n            const layerSettings = atmosphere.cloudLayers || {};\n            const low = layerSettings.low || {};\n            const mid = layerSettings.mid || {};\n            const high = layerSettings.high || {};\n\n            this._setRangeNumber(\n                cfgCloudLowAltitudeRange,\n                cfgCloudLowAltitude,\n                toNumber(low.altitude, toNumber(cfgCloudLowAltitude?.value, 750))\n            );\n            this._setRangeNumber(\n                cfgCloudLowHeightRange,\n                cfgCloudLowHeight,\n                toNumber(low.height, toNumber(cfgCloudLowHeight?.value, 650))\n            );\n            this._setRangeNumber(\n                cfgCloudMidAltitudeRange,\n                cfgCloudMidAltitude,\n                toNumber(mid.altitude, toNumber(cfgCloudMidAltitude?.value, 1000))\n            );\n            this._setRangeNumber(\n                cfgCloudMidHeightRange,\n                cfgCloudMidHeight,\n                toNumber(mid.height, toNumber(cfgCloudMidHeight?.value, 1200))\n            );\n            this._setRangeNumber(\n                cfgCloudHighAltitudeRange,\n                cfgCloudHighAltitude,\n                toNumber(high.altitude, toNumber(cfgCloudHighAltitude?.value, 7500))\n            );\n            this._setRangeNumber(\n                cfgCloudHighHeightRange,\n                cfgCloudHighHeight,\n                toNumber(high.height, toNumber(cfgCloudHighHeight?.value, 500))\n            );\n        };\n\n        const setAtmosphereEnabled = (visible) => {\n            if (this._updateSceneSettings({ atmosphere: { enabled: visible } })) return;\n            if (this.onAtmosphereToggle) {\n                this.onAtmosphereToggle(visible);\n            }\n        };\n\n        if (cfgAtmosphereEnabled) {\n            cfgAtmosphereEnabled.addEventListener('change', () => {\n                setAtmosphereEnabled(cfgAtmosphereEnabled.checked);\n            });\n        }\n\n        const setCloudsEnabled = (enabled) => {\n            if (this._updateSceneSettings({ atmosphere: { clouds: { enabled } } })) return;\n            if (this.sceneInitializer?.atmosphereClouds?.setEnabled) {\n                this.sceneInitializer.atmosphereClouds.setEnabled(enabled);\n            }\n        };\n\n        if (cfgCloudsEnabled) {\n            cfgCloudsEnabled.addEventListener('change', () => {\n                setCloudsEnabled(cfgCloudsEnabled.checked);\n            });\n        }\n\n        const applyAtmosphere = () => {\n            const updates = {};\n            const baseOffset = parseFloat(cfgAtmBaseOffset?.value);\n            const irradianceScale = parseFloat(cfgAtmIrradianceScale?.value);\n            const shadowRadius = parseFloat(cfgAtmShadowRadius?.value);\n\n            if (Number.isFinite(baseOffset)) updates.baseOffsetMeters = baseOffset;\n            if (Number.isFinite(irradianceScale)) updates.irradianceScale = irradianceScale;\n            if (Number.isFinite(shadowRadius)) updates.shadowRadius = shadowRadius;\n\n            const skyTuning = {};\n            const skyAlphaScale = parseFloat(cfgAtmSkyAlphaScale?.value);\n            const skyAlphaClamp = parseFloat(cfgAtmSkyAlphaClamp?.value);\n            const skyLimbBoost = parseFloat(cfgAtmSkyLimbBoost?.value);\n            const skyPathShort = parseFloat(cfgAtmSkyPathShort?.value);\n            const skyLimbMax = parseFloat(cfgAtmSkyLimbMax?.value);\n            const skyDensityScale = parseFloat(cfgAtmSkyDensityScale?.value);\n            const skyScaleHeight = parseFloat(cfgAtmSkyScaleHeight?.value);\n            const skyVerticalFadeStart = parseFloat(cfgAtmSkyVerticalFadeStart?.value);\n            const skyVerticalFadeEnd = parseFloat(cfgAtmSkyVerticalFadeEnd?.value);\n            const skyAltitudeFadeStart = parseFloat(cfgAtmSkyAltitudeFadeStart?.value);\n            const skyAltitudeFadeEnd = parseFloat(cfgAtmSkyAltitudeFadeEnd?.value);\n            const skyOutsideFadeStart = parseFloat(cfgAtmSkyOutsideFadeStart?.value);\n            const skyOutsideFadeEnd = parseFloat(cfgAtmSkyOutsideFadeEnd?.value);\n            const skyDepthThreshold = parseFloat(cfgAtmSkyDepthThreshold?.value);\n\n            if (Number.isFinite(skyAlphaScale)) skyTuning.alphaScale = skyAlphaScale;\n            if (Number.isFinite(skyAlphaClamp)) skyTuning.alphaClamp = skyAlphaClamp;\n            if (Number.isFinite(skyLimbBoost)) skyTuning.limbBoost = skyLimbBoost;\n            if (Number.isFinite(skyPathShort)) skyTuning.pathShort = skyPathShort;\n            if (Number.isFinite(skyLimbMax)) skyTuning.limbMax = skyLimbMax;\n            if (Number.isFinite(skyDensityScale)) skyTuning.densityScale = skyDensityScale;\n            if (Number.isFinite(skyScaleHeight)) skyTuning.scaleHeight = skyScaleHeight;\n            if (Number.isFinite(skyVerticalFadeStart)) skyTuning.verticalFadeStart = skyVerticalFadeStart;\n            if (Number.isFinite(skyVerticalFadeEnd)) skyTuning.verticalFadeEnd = skyVerticalFadeEnd;\n            if (Number.isFinite(skyAltitudeFadeStart)) skyTuning.altitudeFadeStart = skyAltitudeFadeStart;\n            if (Number.isFinite(skyAltitudeFadeEnd)) skyTuning.altitudeFadeEnd = skyAltitudeFadeEnd;\n            if (Number.isFinite(skyOutsideFadeStart)) skyTuning.outsideFadeStart = skyOutsideFadeStart;\n            if (Number.isFinite(skyOutsideFadeEnd)) skyTuning.outsideFadeEnd = skyOutsideFadeEnd;\n            if (Number.isFinite(skyDepthThreshold)) skyTuning.depthThreshold = skyDepthThreshold;\n\n            if (Object.keys(skyTuning).length > 0) {\n                updates.skyTuning = skyTuning;\n            }\n\n            if (cfgAtmPhotometric) updates.photometric = cfgAtmPhotometric.checked;\n            if (cfgAtmSunIrradiance) updates.sunIrradiance = cfgAtmSunIrradiance.checked;\n            if (cfgAtmSkyIrradiance) updates.skyIrradiance = cfgAtmSkyIrradiance.checked;\n            if (cfgAtmTransmittance) updates.transmittance = cfgAtmTransmittance.checked;\n            if (cfgAtmInscatter) updates.inscatter = cfgAtmInscatter.checked;\n            if (cfgAtmSky) updates.sky = cfgAtmSky.checked;\n            if (cfgAtmSun) updates.sun = cfgAtmSun.checked;\n            if (cfgAtmMoon) updates.moon = cfgAtmMoon.checked;\n\n            applyAtmospherePatch(updates);\n        };\n\n        const applyClouds = () => {\n            const updates = {};\n            const coverage = parseFloat(cfgCloudCoverage?.value);\n            const scattering = parseFloat(cfgCloudScattering?.value);\n            const absorption = parseFloat(cfgCloudAbsorption?.value);\n            const turbulenceDisp = parseFloat(cfgCloudTurbulenceDisp?.value);\n\n            if (Number.isFinite(coverage)) updates.coverage = coverage;\n            if (Number.isFinite(scattering)) updates.scatteringCoefficient = scattering;\n            if (Number.isFinite(absorption)) updates.absorptionCoefficient = absorption;\n            if (Number.isFinite(turbulenceDisp)) updates.turbulenceDisplacement = turbulenceDisp;\n\n            if (cfgCloudLightShafts) updates.lightShafts = cfgCloudLightShafts.checked;\n            if (cfgCloudShapeDetail) updates.shapeDetail = cfgCloudShapeDetail.checked;\n            if (cfgCloudTurbulence) updates.turbulence = cfgCloudTurbulence.checked;\n            if (cfgCloudHaze) updates.haze = cfgCloudHaze.checked;\n\n            if (Object.keys(updates).length > 0) {\n                applyAtmospherePatch({ clouds: updates });\n            }\n        };\n\n        const applyCloudLayers = () => {\n            const layers = {};\n            const low = {};\n            const mid = {};\n            const high = {};\n\n            const lowAlt = parseFloat(cfgCloudLowAltitude?.value);\n            const lowHeight = parseFloat(cfgCloudLowHeight?.value);\n            const midAlt = parseFloat(cfgCloudMidAltitude?.value);\n            const midHeight = parseFloat(cfgCloudMidHeight?.value);\n            const highAlt = parseFloat(cfgCloudHighAltitude?.value);\n            const highHeight = parseFloat(cfgCloudHighHeight?.value);\n\n            if (Number.isFinite(lowAlt)) low.altitude = lowAlt;\n            if (Number.isFinite(lowHeight)) low.height = lowHeight;\n            if (Number.isFinite(midAlt)) mid.altitude = midAlt;\n            if (Number.isFinite(midHeight)) mid.height = midHeight;\n            if (Number.isFinite(highAlt)) high.altitude = highAlt;\n            if (Number.isFinite(highHeight)) high.height = highHeight;\n\n            if (Object.keys(low).length) layers.low = low;\n            if (Object.keys(mid).length) layers.mid = mid;\n            if (Object.keys(high).length) layers.high = high;\n\n            if (Object.keys(layers).length > 0) {\n                applyAtmospherePatch({ cloudLayers: layers });\n            }\n        };\n\n        const bindRangeNumberPair = (rangeEl, numberEl, onChange) => {\n            if (!rangeEl && !numberEl) return;\n            if (rangeEl) {\n                if (numberEl) rangeEl.value = numberEl.value;\n                const syncFromRange = () => {\n                    if (numberEl) numberEl.value = rangeEl.value;\n                    if (onChange) onChange();\n                };\n                const syncFromNumber = () => {\n                    if (rangeEl) rangeEl.value = numberEl.value;\n                    if (onChange) onChange();\n                };\n                ['input', 'change'].forEach(ev => rangeEl.addEventListener(ev, syncFromRange));\n                if (numberEl) {\n                    ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, syncFromNumber));\n                }\n            } else if (numberEl && onChange) {\n                ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, onChange));\n            }\n        };\n\n        bindRangeNumberPair(cfgAtmBaseOffsetRange, cfgAtmBaseOffset, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmIrradianceScaleRange, cfgAtmIrradianceScale, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmShadowRadiusRange, cfgAtmShadowRadius, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyAlphaScaleRange, cfgAtmSkyAlphaScale, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyAlphaClampRange, cfgAtmSkyAlphaClamp, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyLimbBoostRange, cfgAtmSkyLimbBoost, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyPathShortRange, cfgAtmSkyPathShort, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyLimbMaxRange, cfgAtmSkyLimbMax, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyDensityScaleRange, cfgAtmSkyDensityScale, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyScaleHeightRange, cfgAtmSkyScaleHeight, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyVerticalFadeStartRange, cfgAtmSkyVerticalFadeStart, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyVerticalFadeEndRange, cfgAtmSkyVerticalFadeEnd, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyAltitudeFadeStartRange, cfgAtmSkyAltitudeFadeStart, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyAltitudeFadeEndRange, cfgAtmSkyAltitudeFadeEnd, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyOutsideFadeStartRange, cfgAtmSkyOutsideFadeStart, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyOutsideFadeEndRange, cfgAtmSkyOutsideFadeEnd, applyAtmosphere);\n        bindRangeNumberPair(cfgAtmSkyDepthThresholdRange, cfgAtmSkyDepthThreshold, applyAtmosphere);\n\n        bindRangeNumberPair(cfgCloudCoverageRange, cfgCloudCoverage, applyClouds);\n        bindRangeNumberPair(cfgCloudScatteringRange, cfgCloudScattering, applyClouds);\n        bindRangeNumberPair(cfgCloudAbsorptionRange, cfgCloudAbsorption, applyClouds);\n        bindRangeNumberPair(cfgCloudTurbulenceDispRange, cfgCloudTurbulenceDisp, applyClouds);\n\n        bindRangeNumberPair(cfgCloudLowAltitudeRange, cfgCloudLowAltitude, applyCloudLayers);\n        bindRangeNumberPair(cfgCloudLowHeightRange, cfgCloudLowHeight, applyCloudLayers);\n        bindRangeNumberPair(cfgCloudMidAltitudeRange, cfgCloudMidAltitude, applyCloudLayers);\n        bindRangeNumberPair(cfgCloudMidHeightRange, cfgCloudMidHeight, applyCloudLayers);\n        bindRangeNumberPair(cfgCloudHighAltitudeRange, cfgCloudHighAltitude, applyCloudLayers);\n        bindRangeNumberPair(cfgCloudHighHeightRange, cfgCloudHighHeight, applyCloudLayers);\n\n        const toggleTargets = [\n            [cfgAtmPhotometric, applyAtmosphere],\n            [cfgAtmSunIrradiance, applyAtmosphere],\n            [cfgAtmSkyIrradiance, applyAtmosphere],\n            [cfgAtmTransmittance, applyAtmosphere],\n            [cfgAtmInscatter, applyAtmosphere],\n            [cfgAtmSky, applyAtmosphere],\n            [cfgAtmSun, applyAtmosphere],\n            [cfgAtmMoon, applyAtmosphere],\n            [cfgCloudLightShafts, applyClouds],\n            [cfgCloudShapeDetail, applyClouds],\n            [cfgCloudTurbulence, applyClouds],\n            [cfgCloudHaze, applyClouds]\n        ];\n        toggleTargets.forEach(([el, handler]) => {\n            if (!el) return;\n            el.addEventListener('change', handler);\n        });\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n\n        applyAtmosphere();\n        applyClouds();\n        applyCloudLayers();\n\n        this._applyAtmosphereSettings = applyAtmosphere;\n        this._applyCloudSettings = applyClouds;\n        this._applyCloudLayerSettings = applyCloudLayers;\n    }\n\n    /**\n     * Apply all atmosphere initial values after materials are created.\n     * This ensures that UI control values are properly synchronized with shader uniforms.\n     */\n    applyInitialAtmosphereValues() {\n        if (this.settings?.getSection) {\n            const atmosphere = this.settings.getSection('scene.atmosphere');\n            if (atmosphere) this.sceneInitializer?.setAtmosphereCloudsConfig?.(atmosphere);\n            return;\n        }\n        if (typeof this._applyAtmosphereSettings === 'function') {\n            this._applyAtmosphereSettings();\n        }\n        if (typeof this._applyCloudSettings === 'function') {\n            this._applyCloudSettings();\n        }\n        if (typeof this._applyCloudLayerSettings === 'function') {\n            this._applyCloudLayerSettings();\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Weather Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupWeatherControls() {\n        const {\n            cfgWeatherEnabled,\n            cfgWeatherAuto,\n            cfgWeatherRadius,\n            cfgWeatherRadiusRange,\n            cfgWeatherInfluence,\n            cfgWeatherInfluenceRange,\n            cfgWeatherInterval,\n            cfgWeatherIntervalRange,\n            cfgWeatherMinDelta,\n            cfgWeatherMinDeltaRange\n        } = this.elements;\n\n        if (!cfgWeatherEnabled && !cfgWeatherAuto && !cfgWeatherRadius && !cfgWeatherRadiusRange) return;\n\n        const toNumber = (value, fallback) => {\n            const num = Number(value);\n            return Number.isFinite(num) ? num : fallback;\n        };\n\n        const applyWeatherPatch = (patch) => {\n            if (!patch || Object.keys(patch).length === 0) return;\n            if (this._updateSceneSettings({ weather: patch })) return;\n            if (this.sceneInitializer?.setWeatherConfig) {\n                this.sceneInitializer.setWeatherConfig(patch);\n            }\n        };\n\n        const syncFromSettings = () => {\n            const weather = this._getSettingValue('scene.weather', {}) || {};\n            if (cfgWeatherEnabled && typeof weather.enabled === 'boolean') {\n                cfgWeatherEnabled.checked = weather.enabled;\n            }\n            if (cfgWeatherAuto && typeof weather.autoTarget === 'boolean') {\n                cfgWeatherAuto.checked = weather.autoTarget;\n            }\n\n            const radiusKm = toNumber(weather.regionRadiusKm, toNumber(cfgWeatherRadius?.value, 400));\n            const influence = toNumber(weather.cloudInfluence, toNumber(cfgWeatherInfluence?.value, 0.6));\n            const intervalMin = Number.isFinite(weather.updateIntervalMs)\n                ? weather.updateIntervalMs / 60000\n                : toNumber(cfgWeatherInterval?.value, 10);\n            const minDelta = toNumber(weather.minDeltaDeg, toNumber(cfgWeatherMinDelta?.value, 0.05));\n\n            this._setRangeNumber(cfgWeatherRadiusRange, cfgWeatherRadius, radiusKm);\n            this._setRangeNumber(cfgWeatherInfluenceRange, cfgWeatherInfluence, influence);\n            this._setRangeNumber(cfgWeatherIntervalRange, cfgWeatherInterval, intervalMin);\n            this._setRangeNumber(cfgWeatherMinDeltaRange, cfgWeatherMinDelta, minDelta);\n        };\n\n        const applyWeather = () => {\n            const patch = {};\n            const radiusKm = parseFloat(cfgWeatherRadius?.value);\n            const influence = parseFloat(cfgWeatherInfluence?.value);\n            const intervalMin = parseFloat(cfgWeatherInterval?.value);\n            const minDelta = parseFloat(cfgWeatherMinDelta?.value);\n\n            if (Number.isFinite(radiusKm)) patch.regionRadiusKm = Math.max(1, radiusKm);\n            if (Number.isFinite(influence)) {\n                patch.cloudInfluence = THREE.MathUtils.clamp(influence, -1, 1);\n            }\n            if (Number.isFinite(intervalMin)) {\n                patch.updateIntervalMs = Math.max(1, intervalMin) * 60000;\n            }\n            if (Number.isFinite(minDelta)) patch.minDeltaDeg = Math.max(0, minDelta);\n\n            applyWeatherPatch(patch);\n        };\n\n        const bindRangeNumberPair = (rangeEl, numberEl, onChange) => {\n            if (!rangeEl && !numberEl) return;\n            if (rangeEl) {\n                if (numberEl) rangeEl.value = numberEl.value;\n                const syncFromRange = () => {\n                    if (numberEl) numberEl.value = rangeEl.value;\n                    if (onChange) onChange();\n                };\n                const syncFromNumber = () => {\n                    if (rangeEl) rangeEl.value = numberEl.value;\n                    if (onChange) onChange();\n                };\n                ['input', 'change'].forEach(ev => rangeEl.addEventListener(ev, syncFromRange));\n                if (numberEl) {\n                    ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, syncFromNumber));\n                }\n            } else if (numberEl && onChange) {\n                ['input', 'change'].forEach(ev => numberEl.addEventListener(ev, onChange));\n            }\n        };\n\n        if (cfgWeatherEnabled) {\n            cfgWeatherEnabled.addEventListener('change', () => {\n                applyWeatherPatch({ enabled: cfgWeatherEnabled.checked });\n            });\n        }\n        if (cfgWeatherAuto) {\n            cfgWeatherAuto.addEventListener('change', () => {\n                applyWeatherPatch({ autoTarget: cfgWeatherAuto.checked });\n            });\n        }\n\n        bindRangeNumberPair(cfgWeatherRadiusRange, cfgWeatherRadius, applyWeather);\n        bindRangeNumberPair(cfgWeatherInfluenceRange, cfgWeatherInfluence, applyWeather);\n        bindRangeNumberPair(cfgWeatherIntervalRange, cfgWeatherInterval, applyWeather);\n        bindRangeNumberPair(cfgWeatherMinDeltaRange, cfgWeatherMinDelta, applyWeather);\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyWeather();\n        this._wireWeatherSidebar();\n    }\n\n    _wireWeatherSidebar() {\n        if (!this.weatherSystem || this._weatherSidebarHandler) return;\n        const handler = (event) => {\n            const detail = event?.detail || null;\n            this._updateWeatherSidebar(detail);\n        };\n        window.addEventListener('weather-status', handler);\n        this._weatherSidebarHandler = handler;\n        this._updateWeatherSidebar();\n    }\n\n    _updateWeatherSidebar(detail = null) {\n        const {\n            weatherLocation,\n            weatherCondition,\n            weatherTemp,\n            weatherClouds,\n            weatherHumidity,\n            weatherWind,\n            weatherPrecip,\n            weatherUpdated\n        } = this.elements;\n        const system = this.weatherSystem;\n        if (!system) return;\n\n        const payload = detail || {};\n        const enabled = typeof payload.enabled === 'boolean' ? payload.enabled : system.enabled;\n        const target = payload.target || system.getTargetCoords?.() || null;\n        const current = payload.weather || system.getWeatherData?.()?.current || null;\n        const lastUpdate = payload.lastUpdate || system.getWeatherData?.()?.lastUpdate || null;\n\n        const setText = (el, value) => {\n            if (!el) return;\n            el.textContent = value;\n        };\n\n        if (!enabled) {\n            setText(weatherLocation, '—');\n            setText(weatherCondition, '—');\n            setText(weatherTemp, '—');\n            setText(weatherClouds, '—');\n            setText(weatherHumidity, '—');\n            setText(weatherWind, '—');\n            setText(weatherPrecip, '—');\n            setText(weatherUpdated, '—');\n            this._applyWeatherCloudUi(null);\n            return;\n        }\n\n        if (target && Number.isFinite(target.lat) && Number.isFinite(target.lon)) {\n            setText(weatherLocation, `${target.lat.toFixed(3)}°, ${target.lon.toFixed(3)}°`);\n        } else {\n            setText(weatherLocation, '—');\n        }\n\n        if (current) {\n            const code = Number.isFinite(current.weather_code) ? current.weather_code : null;\n            const desc = code != null ? (system.getWeatherDescription?.(code) || 'Unknown') : 'Unknown';\n            setText(weatherCondition, desc);\n\n            const temp = Number.isFinite(current.temperature_2m)\n                ? `${Math.round(current.temperature_2m)}°C`\n                : '—';\n            setText(weatherTemp, temp);\n\n            const clouds = Number.isFinite(current.cloud_cover)\n                ? `${Math.round(current.cloud_cover)}%`\n                : '—';\n            setText(weatherClouds, clouds);\n\n            const humidity = Number.isFinite(current.relative_humidity_2m)\n                ? `${Math.round(current.relative_humidity_2m)}%`\n                : '—';\n            setText(weatherHumidity, humidity);\n\n            const wind = Number.isFinite(current.wind_speed_10m)\n                ? `${Math.round(current.wind_speed_10m)} km/h`\n                : '—';\n            setText(weatherWind, wind);\n\n            const precipValue = Number.isFinite(current.precipitation)\n                ? current.precipitation\n                : (Number.isFinite(current.rain) ? current.rain : null);\n            const precip = Number.isFinite(precipValue) ? `${precipValue.toFixed(1)} mm` : '—';\n            setText(weatherPrecip, precip);\n        } else {\n            setText(weatherCondition, 'Loading...');\n            setText(weatherTemp, '—');\n            setText(weatherClouds, '—');\n            setText(weatherHumidity, '—');\n            setText(weatherWind, '—');\n            setText(weatherPrecip, '—');\n        }\n\n        if (Number.isFinite(lastUpdate)) {\n            const ageMs = Date.now() - lastUpdate;\n            const minutes = Math.max(0, Math.round(ageMs / 60000));\n            const label = minutes < 1 ? 'Just now' : `${minutes}m ago`;\n            setText(weatherUpdated, label);\n        } else {\n            setText(weatherUpdated, '—');\n        }\n\n        const cloudTuneables = payload.cloudTuneables || system.getCloudTuneables?.();\n        this._applyWeatherCloudUi(cloudTuneables);\n    }\n\n    _applyWeatherCloudUi(tuneables) {\n        const {\n            cfgCloudCoverage,\n            cfgCloudCoverageRange,\n            cfgCloudScattering,\n            cfgCloudScatteringRange,\n            cfgCloudAbsorption,\n            cfgCloudAbsorptionRange,\n            cfgCloudTurbulenceDisp,\n            cfgCloudTurbulenceDispRange,\n            cfgCloudLightShafts,\n            cfgCloudShapeDetail,\n            cfgCloudTurbulence,\n            cfgCloudHaze\n        } = this.elements;\n\n        if (!tuneables) {\n            this.syncUIFromSettings();\n            return;\n        }\n\n        if (Number.isFinite(tuneables.coverage)) {\n            this._setRangeNumber(cfgCloudCoverageRange, cfgCloudCoverage, tuneables.coverage);\n        }\n        if (Number.isFinite(tuneables.scatteringCoefficient)) {\n            this._setRangeNumber(cfgCloudScatteringRange, cfgCloudScattering, tuneables.scatteringCoefficient);\n        }\n        if (Number.isFinite(tuneables.absorptionCoefficient)) {\n            this._setRangeNumber(cfgCloudAbsorptionRange, cfgCloudAbsorption, tuneables.absorptionCoefficient);\n        }\n        if (Number.isFinite(tuneables.turbulenceDisplacement)) {\n            this._setRangeNumber(cfgCloudTurbulenceDispRange, cfgCloudTurbulenceDisp, tuneables.turbulenceDisplacement);\n        }\n\n        if (typeof tuneables.lightShafts === 'boolean') {\n            this._setChecked(cfgCloudLightShafts, tuneables.lightShafts);\n        }\n        if (typeof tuneables.shapeDetail === 'boolean') {\n            this._setChecked(cfgCloudShapeDetail, tuneables.shapeDetail);\n        }\n        if (typeof tuneables.turbulence === 'boolean') {\n            this._setChecked(cfgCloudTurbulence, tuneables.turbulence);\n        }\n        if (typeof tuneables.haze === 'boolean') {\n            this._setChecked(cfgCloudHaze, tuneables.haze);\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Render Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupRenderControls() {\n        const { cfgRenderScale, cfgRenderScaleRange, cfgAutoRenderScale } = this.elements;\n        if (!cfgRenderScale && !cfgRenderScaleRange) return;\n\n        const clampScale = (value) => {\n            const num = parseFloat(value);\n            if (!Number.isFinite(num)) return null;\n            return THREE.MathUtils.clamp(num, 0.5, 2);\n        };\n\n        const applyScale = (value) => {\n            const next = clampScale(value);\n            if (next === null) return;\n            if (cfgRenderScale) cfgRenderScale.value = next;\n            if (cfgRenderScaleRange) cfgRenderScaleRange.value = next;\n            if (this.sceneInitializer && typeof this.sceneInitializer.setRenderScale === 'function') {\n                this.sceneInitializer.setRenderScale(next);\n            }\n        };\n\n        const syncFromSettings = () => {\n            const rendererSettings = this._getSettingValue('scene.renderer', {}) || {};\n            const initial = Number.isFinite(rendererSettings.renderScale)\n                ? rendererSettings.renderScale\n                : (this.renderer ? this.renderer.getPixelRatio() : 1);\n            if (cfgRenderScale) cfgRenderScale.value = initial;\n            if (cfgRenderScaleRange) cfgRenderScaleRange.value = initial;\n            if (cfgAutoRenderScale && rendererSettings.autoRenderScale) {\n                cfgAutoRenderScale.checked = false;\n                cfgAutoRenderScale.disabled = true;\n                if (cfgRenderScale) cfgRenderScale.disabled = false;\n                if (cfgRenderScaleRange) cfgRenderScaleRange.disabled = false;\n            }\n        };\n\n        if (cfgRenderScaleRange) {\n            ['input', 'change'].forEach(ev => cfgRenderScaleRange.addEventListener(ev, () => {\n                const next = clampScale(cfgRenderScaleRange.value);\n                if (next === null) return;\n                if (this._updateSceneSettings({ renderer: { renderScale: next } })) return;\n                applyScale(next);\n            }));\n        }\n        if (cfgRenderScale) {\n            ['input', 'change'].forEach(ev => cfgRenderScale.addEventListener(ev, () => {\n                const next = clampScale(cfgRenderScale.value);\n                if (next === null) return;\n                if (this._updateSceneSettings({ renderer: { renderScale: next } })) return;\n                applyScale(next);\n            }));\n        }\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n        applyScale(cfgRenderScale?.value ?? cfgRenderScaleRange?.value ?? 1);\n        this.applyRenderScale = applyScale;\n\n        if (cfgAutoRenderScale) {\n            cfgAutoRenderScale.checked = false;\n            cfgAutoRenderScale.disabled = true;\n            cfgAutoRenderScale.addEventListener('change', () => {\n                cfgAutoRenderScale.checked = false;\n                if (cfgRenderScale) cfgRenderScale.disabled = false;\n                if (cfgRenderScaleRange) cfgRenderScaleRange.disabled = false;\n                if (this._updateSceneSettings({ renderer: { autoRenderScale: { enabled: false } } })) return;\n                if (this.onAutoRenderScaleToggle) {\n                    this.onAutoRenderScaleToggle(false);\n                }\n            });\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Debug Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupDebugControls() {\n        const { debugToggle, debugPanel } = this.elements;\n\n        // Debug toggle callback (will be set by main initialization with perf monitor)\n        this.onDebugToggle = null;\n\n        debugToggle.addEventListener('click', () => {\n            if (this.onDebugToggle) {\n                this.onDebugToggle();\n            }\n        });\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Debug Sign Flip Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupSignFlipDebugControls() {\n        const {\n            cfgFlipRotation180, cfgNegateSunX, cfgNegateSunZ,\n            cfgInvertFocusDir, cfgNegateFocusX, cfgNegateFocusZ,\n            cfgInvertCameraDir, cfgInvertCameraPos, cfgNegateCamPosX, cfgNegateCamPosZ,\n            cfgInvertQuaternion, cfgDisableViewportCulling, cfgNeighborDetection\n        } = this.elements;\n\n        const syncFromSettings = () => {\n            const debug = this._getSettingValue('scene.debug', {}) || {};\n            this._setChecked(cfgFlipRotation180, debug.flipRotation180);\n            this._setChecked(cfgNegateSunX, debug.negateSunX);\n            this._setChecked(cfgNegateSunZ, debug.negateSunZ);\n            this._setChecked(cfgInvertFocusDir, debug.invertFocusDir);\n            this._setChecked(cfgNegateFocusX, debug.negateFocusX);\n            this._setChecked(cfgNegateFocusZ, debug.negateFocusZ);\n            this._setChecked(cfgInvertCameraDir, debug.invertCameraDir);\n            this._setChecked(cfgInvertCameraPos, debug.invertCameraPos);\n            this._setChecked(cfgNegateCamPosX, debug.negateCamPosX);\n            this._setChecked(cfgNegateCamPosZ, debug.negateCamPosZ);\n            this._setChecked(cfgInvertQuaternion, debug.invertQuaternion);\n            this._setChecked(cfgDisableViewportCulling, debug.disableViewportCulling);\n            this._setChecked(cfgNeighborDetection, debug.neighborDetection);\n        };\n\n        const bindDebugToggle = (el, key, fallback) => {\n            if (!el) return;\n            el.addEventListener('change', () => {\n                const value = el.checked;\n                if (this._updateSceneSettings({ debug: { [key]: value } })) return;\n                if (typeof fallback === 'function') fallback(value);\n            });\n        };\n\n        bindDebugToggle(cfgFlipRotation180, 'flipRotation180', (value) => {\n            if (this.lightingSystem) this.lightingSystem.debugFlipRotation180 = value;\n        });\n        bindDebugToggle(cfgNegateSunX, 'negateSunX', (value) => {\n            if (this.lightingSystem) this.lightingSystem.debugNegateSunX = value;\n        });\n        bindDebugToggle(cfgNegateSunZ, 'negateSunZ', (value) => {\n            if (this.lightingSystem) this.lightingSystem.debugNegateSunZ = value;\n        });\n        bindDebugToggle(cfgInvertFocusDir, 'invertFocusDir', (value) => {\n            if (this.triTree) this.triTree.debugInvertFocusDir = value;\n        });\n        bindDebugToggle(cfgNegateFocusX, 'negateFocusX', (value) => {\n            if (this.triTree) this.triTree.debugNegateFocusX = value;\n        });\n        bindDebugToggle(cfgNegateFocusZ, 'negateFocusZ', (value) => {\n            if (this.triTree) this.triTree.debugNegateFocusZ = value;\n        });\n        bindDebugToggle(cfgInvertCameraDir, 'invertCameraDir', (value) => {\n            if (this.triTree) this.triTree.debugInvertCameraDir = value;\n        });\n        bindDebugToggle(cfgInvertCameraPos, 'invertCameraPos', (value) => {\n            if (this.triTree) this.triTree.debugInvertCameraPos = value;\n        });\n        bindDebugToggle(cfgNegateCamPosX, 'negateCamPosX', (value) => {\n            if (this.triTree) this.triTree.debugNegateCamPosX = value;\n        });\n        bindDebugToggle(cfgNegateCamPosZ, 'negateCamPosZ', (value) => {\n            if (this.triTree) this.triTree.debugNegateCamPosZ = value;\n        });\n        bindDebugToggle(cfgInvertQuaternion, 'invertQuaternion', (value) => {\n            if (this.triTree) this.triTree.debugInvertQuaternion = value;\n        });\n        bindDebugToggle(cfgDisableViewportCulling, 'disableViewportCulling', (value) => {\n            if (this.triTree) this.triTree.debugDisableViewportCulling = value;\n        });\n        bindDebugToggle(cfgNeighborDetection, 'neighborDetection', (value) => {\n            if (this.triTree) {\n                this.triTree.enableNeighborDetection = value;\n                console.log(`[LOD] Neighbor detection ${value ? 'enabled' : 'disabled'}`);\n            }\n        });\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Pathfinding Controls\n    // ─────────────────────────────────────────────────────────────\n\n    setupPathfindingControls() {\n        const e = this.elements;\n        if (!e.cfgPathLateralMaxDeg) return;\n\n        const defaults = {\n            lateralMaxDeg: 1,\n            stepsS: 200,\n            stepsT: 33,\n            weightUphill: 4,\n            weightDownhill: 1.1,\n            weightElevDelta: 3.3,\n            weightSlopeSq: 0,\n            weightLateral: 2,\n            weightDistance: 4,\n            weightHigh: 1.1,\n            weightRough: 1.75,\n            smoothIterations: 5\n        };\n\n        const loadProfile = () => {\n            const stored = this._getSettingValue('pathfinding', null);\n            if (stored) {\n                return { ...defaults, ...stored };\n            }\n            try {\n                const raw = localStorage.getItem(this.LS_PATH);\n                if (!raw) return { ...defaults };\n                const parsed = JSON.parse(raw);\n                return { ...defaults, ...parsed };\n            } catch {\n                return { ...defaults };\n            }\n        };\n\n        const profile = loadProfile();\n\n        const applyProfileToUI = () => {\n            const setVal = (el, v) => { if (el) el.value = v; };\n            setVal(e.cfgPathLateralMaxDeg, profile.lateralMaxDeg);\n            setVal(e.cfgPathStepsS, profile.stepsS);\n            setVal(e.cfgPathStepsT, profile.stepsT);\n            setVal(e.cfgPathUphill, profile.weightUphill);\n            setVal(e.cfgPathDownhill, profile.weightDownhill);\n            setVal(e.cfgPathElevDelta, profile.weightElevDelta);\n            setVal(e.cfgPathSlopeSq, profile.weightSlopeSq);\n            setVal(e.cfgPathLateral, profile.weightLateral);\n            setVal(e.cfgPathDistance, profile.weightDistance);\n            setVal(e.cfgPathHigh, profile.weightHigh);\n            setVal(e.cfgPathRough, profile.weightRough);\n            setVal(e.cfgPathSmooth, profile.smoothIterations);\n        };\n\n        const syncToScene = () => {\n            if (this.sceneInitializer) {\n                this.sceneInitializer.pathWeights = { ...profile };\n            }\n        };\n\n        const saveProfile = () => {\n            this._updateSettings({ pathfinding: { ...profile } }, { apply: false });\n            try {\n                localStorage.setItem(this.LS_PATH, JSON.stringify(profile));\n            } catch { /* ignore */ }\n        };\n\n        const onChange = () => {\n            profile.lateralMaxDeg = parseFloat(e.cfgPathLateralMaxDeg?.value) || defaults.lateralMaxDeg;\n            profile.stepsS = parseInt(e.cfgPathStepsS?.value, 10) || defaults.stepsS;\n            profile.stepsT = parseInt(e.cfgPathStepsT?.value, 10) || defaults.stepsT;\n            profile.weightUphill = parseFloat(e.cfgPathUphill?.value) || defaults.weightUphill;\n            profile.weightDownhill = parseFloat(e.cfgPathDownhill?.value) || defaults.weightDownhill;\n            profile.weightElevDelta = parseFloat(e.cfgPathElevDelta?.value) || defaults.weightElevDelta;\n            profile.weightSlopeSq = parseFloat(e.cfgPathSlopeSq?.value) || defaults.weightSlopeSq;\n            profile.weightLateral = parseFloat(e.cfgPathLateral?.value) || defaults.weightLateral;\n            profile.weightDistance = parseFloat(e.cfgPathDistance?.value) || defaults.weightDistance;\n            profile.weightHigh = parseFloat(e.cfgPathHigh?.value) || defaults.weightHigh;\n            profile.weightRough = parseFloat(e.cfgPathRough?.value) || defaults.weightRough;\n            profile.smoothIterations = parseInt(e.cfgPathSmooth?.value, 10) || defaults.smoothIterations;\n            saveProfile();\n            syncToScene();\n        };\n\n        const fields = [\n            'cfgPathLateralMaxDeg', 'cfgPathStepsS', 'cfgPathStepsT',\n            'cfgPathUphill', 'cfgPathDownhill', 'cfgPathElevDelta', 'cfgPathSlopeSq',\n            'cfgPathLateral', 'cfgPathDistance', 'cfgPathHigh', 'cfgPathRough', 'cfgPathSmooth'\n        ];\n        for (const key of fields) {\n            e[key]?.addEventListener('input', onChange);\n            e[key]?.addEventListener('change', onChange);\n        }\n\n        const syncFromSettings = () => {\n            const next = loadProfile();\n            Object.assign(profile, next);\n            applyProfileToUI();\n            syncToScene();\n        };\n\n        this._registerSettingsSync(syncFromSettings);\n        syncFromSettings();\n\n        this.onPathWeightsChange = null;\n        this.setPathRedrawCallback = (fn) => {\n            this.onPathWeightsChange = (typeof fn === 'function') ? fn : null;\n        };\n        const maybeRedraw = () => {\n            if (this.onPathWeightsChange) this.onPathWeightsChange();\n        };\n\n        const rangeBindings = [\n            ['cfgPathLateralMaxDegRange', 'cfgPathLateralMaxDeg'],\n            ['cfgPathStepsSRange', 'cfgPathStepsS'],\n            ['cfgPathStepsTRange', 'cfgPathStepsT'],\n            ['cfgPathUphillRange', 'cfgPathUphill'],\n            ['cfgPathDownhillRange', 'cfgPathDownhill'],\n            ['cfgPathElevDeltaRange', 'cfgPathElevDelta'],\n            ['cfgPathSlopeSqRange', 'cfgPathSlopeSq'],\n            ['cfgPathLateralRange', 'cfgPathLateral'],\n            ['cfgPathDistanceRange', 'cfgPathDistance'],\n            ['cfgPathHighRange', 'cfgPathHigh'],\n            ['cfgPathRoughRange', 'cfgPathRough'],\n            ['cfgPathSmoothRange', 'cfgPathSmooth']\n        ];\n\n        for (const [rangeKey, numKey] of rangeBindings) {\n            const rangeEl = e[rangeKey];\n            const numEl = e[numKey];\n            if (!rangeEl || !numEl) continue;\n            const syncRangeToNum = () => {\n                numEl.value = rangeEl.value;\n                onChange();\n                maybeRedraw();\n            };\n            const syncNumToRange = () => {\n                rangeEl.value = numEl.value;\n                onChange();\n                maybeRedraw();\n            };\n            rangeEl.addEventListener('input', syncRangeToNum);\n            rangeEl.addEventListener('change', syncRangeToNum);\n            numEl.addEventListener('input', syncNumToRange);\n            numEl.addEventListener('change', syncNumToRange);\n            // initialize\n            rangeEl.value = numEl.value;\n        }\n    }\n\n    // ─────────────────────────────────────────────────────────────\n    // Public API\n    // ─────────────────────────────────────────────────────────────\n\n    getMultiClient() {\n        return this.multiClient;\n    }\n}\n"],"file":"assets/66614499192c/ui-controller-BvVAxRwa.js"}