{"version":3,"file":"EnviroAtlasControl-BNXqf28d.cjs","names":[],"sources":["../src/lib/api/urls.ts","../src/lib/api/catalog.ts","../src/lib/api/extent.ts","../src/lib/api/search.ts","../src/lib/ui/dom.ts","../src/lib/ui/panelView.ts","../src/lib/ui/treeView.ts","../src/lib/ui/resultsView.ts","../src/lib/ui/legendView.ts","../src/lib/ui/addedLayersView.ts","../src/lib/utils/helpers.ts","../src/lib/core/mapLayers.ts","../src/lib/core/EnviroAtlasControl.ts"],"sourcesContent":["/**\n * Pure URL builders for the EnviroAtlas ArcGIS REST API.\n *\n * All builders are side-effect free so they can be unit tested\n * without any network access.\n */\nimport type { ServiceRef } from './types';\n\n/** Default EnviroAtlas ArcGIS REST services root */\nexport const DEFAULT_SERVICES_URL = 'https://enviroatlas.epa.gov/arcgis/rest/services';\n\n/** Placeholder MapLibre replaces with the tile bounding box (EPSG:3857) */\nexport const BBOX_PLACEHOLDER = '{bbox-epsg-3857}';\n\n/**\n * Options shared by the raster export URL builders.\n */\nexport interface ExportUrlOptions {\n  /** Tile size in pixels @default 256 */\n  tileSize?: number;\n  /** ArcGIS image format @default 'png32' */\n  imageFormat?: string;\n}\n\nfunction trimTrailingSlash(url: string): string {\n  return url.replace(/\\/+$/, '');\n}\n\n/**\n * Builds the catalog root URL returning the folder list.\n *\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The catalog JSON URL\n */\nexport function buildCatalogUrl(servicesUrl: string = DEFAULT_SERVICES_URL): string {\n  return `${trimTrailingSlash(servicesUrl)}?f=json`;\n}\n\n/**\n * Builds the URL listing services within a folder.\n *\n * @param folder - The folder name (e.g. \"Communities\")\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The folder JSON URL\n */\nexport function buildFolderUrl(folder: string, servicesUrl: string = DEFAULT_SERVICES_URL): string {\n  return `${trimTrailingSlash(servicesUrl)}/${encodeURIComponent(folder)}?f=json`;\n}\n\n/**\n * Builds the metadata URL for a service (layer list, description, ...).\n *\n * @param service - The service reference\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The service metadata JSON URL\n */\nexport function buildServiceUrl(service: ServiceRef, servicesUrl: string = DEFAULT_SERVICES_URL): string {\n  return `${trimTrailingSlash(servicesUrl)}/${service.fullName}/${service.type}?f=json`;\n}\n\n/**\n * Builds the legend URL for a service.\n *\n * @param service - The service reference\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The legend JSON URL\n */\nexport function buildLegendUrl(service: ServiceRef, servicesUrl: string = DEFAULT_SERVICES_URL): string {\n  return `${trimTrailingSlash(servicesUrl)}/${service.fullName}/${service.type}/legend?f=json`;\n}\n\n/**\n * Builds a MapServer dynamic export tile template for use as a\n * MapLibre raster source `tiles` entry. The `{bbox-epsg-3857}`\n * placeholder is substituted by MapLibre per tile request.\n *\n * @param service - The MapServer service reference\n * @param sublayerId - Optional layer (or group layer) id to render exclusively\n * @param options - Tile size and image format options\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The export tile URL template\n */\nexport function buildExportUrl(\n  service: ServiceRef,\n  sublayerId?: number,\n  options: ExportUrlOptions = {},\n  servicesUrl: string = DEFAULT_SERVICES_URL\n): string {\n  const { tileSize = 256, imageFormat = 'png32' } = options;\n  const base = `${trimTrailingSlash(servicesUrl)}/${service.fullName}/MapServer/export`;\n  const params =\n    `bbox=${BBOX_PLACEHOLDER}&bboxSR=3857&imageSR=3857` +\n    `&size=${tileSize},${tileSize}&format=${imageFormat}&transparent=true&f=image` +\n    (sublayerId !== undefined ? `&layers=show:${sublayerId}` : '');\n  return `${base}?${params}`;\n}\n\n/**\n * Builds an ImageServer exportImage tile template for use as a\n * MapLibre raster source `tiles` entry.\n *\n * @param service - The ImageServer service reference\n * @param options - Tile size and image format options\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The exportImage tile URL template\n */\nexport function buildExportImageUrl(\n  service: ServiceRef,\n  options: ExportUrlOptions = {},\n  servicesUrl: string = DEFAULT_SERVICES_URL\n): string {\n  const { tileSize = 256, imageFormat = 'png32' } = options;\n  const base = `${trimTrailingSlash(servicesUrl)}/${service.fullName}/ImageServer/exportImage`;\n  const params =\n    `bbox=${BBOX_PLACEHOLDER}&bboxSR=3857&imageSR=3857` +\n    `&size=${tileSize},${tileSize}&format=${imageFormat}&transparent=true&f=image`;\n  return `${base}?${params}`;\n}\n\n/**\n * Builds the raster tile template for any service type.\n *\n * @param service - The service reference\n * @param sublayerId - Optional MapServer sublayer id (ignored for ImageServers)\n * @param options - Tile size and image format options\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The tile URL template for a MapLibre raster source\n */\nexport function buildTileTemplate(\n  service: ServiceRef,\n  sublayerId?: number,\n  options: ExportUrlOptions = {},\n  servicesUrl: string = DEFAULT_SERVICES_URL\n): string {\n  return service.type === 'ImageServer'\n    ? buildExportImageUrl(service, options, servicesUrl)\n    : buildExportUrl(service, sublayerId, options, servicesUrl);\n}\n\n/**\n * Builds a single concrete export request for a specific view.\n *\n * Unlike {@link buildTileTemplate}, the bounding box and image size\n * are fixed values: one request renders the whole visible area. This\n * is much faster against dynamic ArcGIS services than per-tile\n * exports, since every export is a server-side render job.\n *\n * @param service - The service reference\n * @param sublayerId - Optional MapServer sublayer id (ignored for ImageServers)\n * @param bbox3857 - View bounding box [xmin, ymin, xmax, ymax] in EPSG:3857 meters\n * @param width - Image width in pixels\n * @param height - Image height in pixels\n * @param options - Image format options\n * @param servicesUrl - The ArcGIS REST services root\n * @returns The export image URL for the view\n */\nexport function buildViewExportUrl(\n  service: ServiceRef,\n  sublayerId: number | undefined,\n  bbox3857: [number, number, number, number],\n  width: number,\n  height: number,\n  options: ExportUrlOptions = {},\n  servicesUrl: string = DEFAULT_SERVICES_URL\n): string {\n  const { imageFormat = 'png32' } = options;\n  const operation = service.type === 'ImageServer' ? 'ImageServer/exportImage' : 'MapServer/export';\n  const base = `${trimTrailingSlash(servicesUrl)}/${service.fullName}/${operation}`;\n  const params =\n    `bbox=${bbox3857.join(',')}&bboxSR=3857&imageSR=3857` +\n    `&size=${Math.round(width)},${Math.round(height)}&format=${imageFormat}&transparent=true&f=image` +\n    (service.type === 'MapServer' && sublayerId !== undefined ? `&layers=show:${sublayerId}` : '');\n  return `${base}?${params}`;\n}\n","/**\n * Catalog client for the EnviroAtlas ArcGIS REST services directory.\n *\n * Fetches and caches the folder list, per-folder service lists,\n * per-service layer metadata, and legends. All responses are cached\n * in memory for the lifetime of the client.\n */\nimport type { ArcGISExtent } from './extent';\nimport type { LayerLegend, ServiceLayer, ServiceMetadata, ServiceRef, ServiceType } from './types';\nimport { buildCatalogUrl, buildFolderUrl, buildLegendUrl, buildServiceUrl, DEFAULT_SERVICES_URL } from './urls';\n\n/** Folders hidden from the catalog by default */\nexport const DEFAULT_EXCLUDED_FOLDERS = ['test_services', 'Utilities', 'monitor'];\n\n/**\n * Options for creating a {@link CatalogClient}.\n */\nexport interface CatalogClientOptions {\n  /** ArcGIS REST services root @default DEFAULT_SERVICES_URL */\n  servicesUrl?: string;\n  /** Folder names to hide @default DEFAULT_EXCLUDED_FOLDERS */\n  excludedFolders?: string[];\n  /** Max concurrent requests when prefetching layer lists @default 6 */\n  prefetchConcurrency?: number;\n}\n\n/**\n * Parses the catalog root response into a folder list, applying exclusions.\n *\n * @param json - The catalog root JSON response\n * @param excludedFolders - Folder names to filter out\n * @returns Folder names sorted alphabetically\n */\nexport function parseFolderList(json: unknown, excludedFolders: string[] = DEFAULT_EXCLUDED_FOLDERS): string[] {\n  const folders = (json as { folders?: unknown })?.folders;\n  if (!Array.isArray(folders)) return [];\n  const excluded = new Set(excludedFolders.map((f) => f.toLowerCase()));\n  return folders\n    .filter((f): f is string => typeof f === 'string' && !excluded.has(f.toLowerCase()))\n    .sort((a, b) => a.localeCompare(b));\n}\n\n/**\n * Parses a folder listing response into service references.\n *\n * @param json - The folder JSON response\n * @param folder - The folder that was listed\n * @returns Service references for supported service types\n */\nexport function parseServiceList(json: unknown, folder: string): ServiceRef[] {\n  const services = (json as { services?: unknown })?.services;\n  if (!Array.isArray(services)) return [];\n  const refs: ServiceRef[] = [];\n  for (const entry of services) {\n    const { name, type } = (entry ?? {}) as { name?: unknown; type?: unknown };\n    if (typeof name !== 'string' || (type !== 'MapServer' && type !== 'ImageServer')) continue;\n    const shortName = name.includes('/') ? name.slice(name.lastIndexOf('/') + 1) : name;\n    refs.push({ folder, name: shortName, fullName: name, type: type as ServiceType });\n  }\n  return refs;\n}\n\n/**\n * Parses a service metadata response into {@link ServiceMetadata}.\n *\n * @param json - The service JSON response\n * @returns Parsed metadata with a normalized layer list\n */\nexport function parseServiceMetadata(json: unknown): ServiceMetadata {\n  const raw = (json ?? {}) as {\n    mapName?: unknown;\n    description?: unknown;\n    layers?: unknown;\n    fullExtent?: unknown;\n    extent?: unknown;\n  };\n  const layers: ServiceLayer[] = [];\n  if (Array.isArray(raw.layers)) {\n    for (const entry of raw.layers) {\n      const { id, name, parentLayerId, subLayerIds } = (entry ?? {}) as Record<string, unknown>;\n      if (typeof id !== 'number' || typeof name !== 'string') continue;\n      layers.push({\n        id,\n        name,\n        parentLayerId: typeof parentLayerId === 'number' ? parentLayerId : -1,\n        subLayerIds: Array.isArray(subLayerIds) ? (subLayerIds as number[]) : null,\n      });\n    }\n  }\n  // MapServers report fullExtent; ImageServers report extent\n  const rawExtent = (raw.fullExtent ?? raw.extent) as ArcGISExtent | undefined;\n  const extent =\n    rawExtent &&\n    typeof rawExtent === 'object' &&\n    [rawExtent.xmin, rawExtent.ymin, rawExtent.xmax, rawExtent.ymax].every((v) => typeof v === 'number')\n      ? rawExtent\n      : undefined;\n\n  return {\n    mapName: typeof raw.mapName === 'string' ? raw.mapName : undefined,\n    description: typeof raw.description === 'string' ? raw.description : undefined,\n    layers,\n    extent,\n  };\n}\n\n/**\n * Parses a legend response into per-layer legends.\n *\n * @param json - The legend JSON response\n * @returns Legends keyed by layer, empty when unavailable\n */\nexport function parseLegend(json: unknown): LayerLegend[] {\n  const layers = (json as { layers?: unknown })?.layers;\n  if (!Array.isArray(layers)) return [];\n  const result: LayerLegend[] = [];\n  for (const entry of layers) {\n    const { layerId, layerName, legend } = (entry ?? {}) as Record<string, unknown>;\n    if (typeof layerId !== 'number' || !Array.isArray(legend)) continue;\n    result.push({\n      layerId,\n      layerName: typeof layerName === 'string' ? layerName : `Layer ${layerId}`,\n      legend: legend\n        .filter((item) => item && typeof (item as Record<string, unknown>).imageData === 'string')\n        .map((item) => {\n          const raw = item as Record<string, unknown>;\n          return {\n            label: typeof raw.label === 'string' ? raw.label : '',\n            imageData: raw.imageData as string,\n            contentType: typeof raw.contentType === 'string' ? raw.contentType : 'image/png',\n            width: typeof raw.width === 'number' ? raw.width : 20,\n            height: typeof raw.height === 'number' ? raw.height : 20,\n          };\n        }),\n    });\n  }\n  return result;\n}\n\n/**\n * Client for browsing the EnviroAtlas services catalog with caching.\n */\nexport class CatalogClient {\n  private readonly _servicesUrl: string;\n  private readonly _excludedFolders: string[];\n  private readonly _prefetchConcurrency: number;\n\n  private _folders?: Promise<string[]>;\n  private readonly _services = new Map<string, Promise<ServiceRef[]>>();\n  private readonly _metadata = new Map<string, Promise<ServiceMetadata>>();\n  private readonly _legends = new Map<string, Promise<LayerLegend[]>>();\n  private _prefetchAll?: Promise<void>;\n  private _abortController = new AbortController();\n\n  /**\n   * Creates a new catalog client.\n   *\n   * @param options - Client configuration\n   */\n  constructor(options: CatalogClientOptions = {}) {\n    this._servicesUrl = options.servicesUrl ?? DEFAULT_SERVICES_URL;\n    this._excludedFolders = options.excludedFolders ?? DEFAULT_EXCLUDED_FOLDERS;\n    this._prefetchConcurrency = options.prefetchConcurrency ?? 6;\n  }\n\n  /** The ArcGIS REST services root this client reads from. */\n  get servicesUrl(): string {\n    return this._servicesUrl;\n  }\n\n  /**\n   * Lists catalog folders (cached after the first call).\n   *\n   * @returns Folder names, excluding configured folders\n   */\n  listFolders(): Promise<string[]> {\n    this._folders ??= this._fetchJson(buildCatalogUrl(this._servicesUrl)).then((json) =>\n      parseFolderList(json, this._excludedFolders)\n    );\n    return this._folders.catch((err) => {\n      this._folders = undefined;\n      throw err;\n    });\n  }\n\n  /**\n   * Lists services within a folder (cached per folder).\n   *\n   * @param folder - The folder name\n   * @returns Service references in the folder\n   */\n  listServices(folder: string): Promise<ServiceRef[]> {\n    let promise = this._services.get(folder);\n    if (!promise) {\n      promise = this._fetchJson(buildFolderUrl(folder, this._servicesUrl)).then((json) =>\n        parseServiceList(json, folder)\n      );\n      this._services.set(folder, promise);\n    }\n    return promise.catch((err) => {\n      this._services.delete(folder);\n      throw err;\n    });\n  }\n\n  /**\n   * Fetches metadata (layer list) for a service (cached per service).\n   *\n   * @param service - The service reference\n   * @returns Parsed service metadata\n   */\n  getServiceMetadata(service: ServiceRef): Promise<ServiceMetadata> {\n    let promise = this._metadata.get(service.fullName);\n    if (!promise) {\n      promise = this._fetchJson(buildServiceUrl(service, this._servicesUrl)).then(parseServiceMetadata);\n      this._metadata.set(service.fullName, promise);\n    }\n    return promise.catch((err) => {\n      this._metadata.delete(service.fullName);\n      throw err;\n    });\n  }\n\n  /**\n   * Returns cached metadata for a service if already fetched.\n   *\n   * @param service - The service reference\n   * @returns The cached metadata promise or undefined\n   */\n  getCachedMetadata(service: ServiceRef): Promise<ServiceMetadata> | undefined {\n    return this._metadata.get(service.fullName);\n  }\n\n  /**\n   * Fetches the legend for a service (cached per service).\n   *\n   * @param service - The service reference\n   * @returns Per-layer legends, empty when the service has none\n   */\n  getLegend(service: ServiceRef): Promise<LayerLegend[]> {\n    let promise = this._legends.get(service.fullName);\n    if (!promise) {\n      promise = this._fetchJson(buildLegendUrl(service, this._servicesUrl))\n        .then(parseLegend)\n        .catch(() => [] as LayerLegend[]);\n      this._legends.set(service.fullName, promise);\n    }\n    return promise;\n  }\n\n  /**\n   * Lists all services across all folders (cached).\n   *\n   * @returns All service references in the catalog\n   */\n  async listAllServices(): Promise<ServiceRef[]> {\n    const folders = await this.listFolders();\n    const lists = await Promise.all(\n      folders.map((folder) => this.listServices(folder).catch(() => [] as ServiceRef[]))\n    );\n    return lists.flat();\n  }\n\n  /**\n   * Prefetches layer metadata for all MapServer services so sublayer\n   * search has data. Runs once; subsequent calls return the same promise.\n   *\n   * @param onProgress - Called after each service's metadata resolves\n   * @returns A promise resolving when all metadata is fetched\n   */\n  prefetchAllLayers(onProgress?: () => void): Promise<void> {\n    this._prefetchAll ??= (async () => {\n      const services = await this.listAllServices();\n      const mapServers = services.filter((s) => s.type === 'MapServer');\n      const queue = [...mapServers];\n      const workers = Array.from({ length: Math.min(this._prefetchConcurrency, queue.length) }, async () => {\n        for (let service = queue.shift(); service; service = queue.shift()) {\n          await this.getServiceMetadata(service).catch(() => undefined);\n          onProgress?.();\n        }\n      });\n      await Promise.all(workers);\n    })();\n    return this._prefetchAll;\n  }\n\n  /**\n   * Clears all cached data so the next calls re-fetch from the server.\n   */\n  clearCache(): void {\n    this._folders = undefined;\n    this._services.clear();\n    this._metadata.clear();\n    this._legends.clear();\n    this._prefetchAll = undefined;\n  }\n\n  /**\n   * Aborts all in-flight requests and resets the abort controller.\n   */\n  abort(): void {\n    this._abortController.abort();\n    this._abortController = new AbortController();\n    this.clearCache();\n  }\n\n  private async _fetchJson(url: string): Promise<unknown> {\n    const response = await fetch(url, { signal: this._abortController.signal });\n    if (!response.ok) {\n      throw new Error(`Request failed (${response.status}): ${url}`);\n    }\n    const json = (await response.json()) as { error?: { message?: string } };\n    // ArcGIS reports errors in a 200 body\n    if (json && typeof json === 'object' && json.error) {\n      throw new Error(json.error.message ?? `ArcGIS error: ${url}`);\n    }\n    return json;\n  }\n}\n","/**\n * Converts ArcGIS service extents to geographic (EPSG:4326) bounds.\n *\n * EnviroAtlas services publish extents in Web Mercator, geographic\n * coordinates, or one of several Albers Equal Area projections (the\n * server's GeometryServer project endpoint is unavailable, so the\n * inverse projection is computed client-side with a spherical\n * approximation, then padded). The resulting bounds are used both to\n * limit raster tile requests (the server times out with a 504 on\n * far-out-of-extent exports) and to zoom the map to newly added layers.\n */\n\n/** Geographic bounds as [west, south, east, north] */\nexport type LngLatBoundsArray = [number, number, number, number];\n\n/**\n * An ArcGIS extent object (subset).\n */\nexport interface ArcGISExtent {\n  xmin: number;\n  ymin: number;\n  xmax: number;\n  ymax: number;\n  spatialReference?: {\n    wkid?: number;\n    latestWkid?: number;\n    wkt?: string;\n    wkt2?: string;\n  };\n}\n\ninterface AlbersParams {\n  /** Central meridian in degrees */\n  centralMeridian: number;\n  /** First standard parallel in degrees */\n  standardParallel1: number;\n  /** Second standard parallel in degrees */\n  standardParallel2: number;\n  /** Latitude of origin in degrees */\n  latitudeOfOrigin: number;\n}\n\ntype Projection =\n  | { kind: 'geographic' }\n  | { kind: 'webmercator' }\n  | { kind: 'albers'; params: AlbersParams };\n\nconst R = 6378137;\nconst DEG = Math.PI / 180;\nconst MAX_MERCATOR_LAT = 85.051129;\n\n/** Known Albers wkids used by EnviroAtlas services */\nconst ALBERS_WKIDS: Record<number, AlbersParams> = {\n  // USA Contiguous Albers (USGS / NAD83)\n  102039: { centralMeridian: -96, standardParallel1: 29.5, standardParallel2: 45.5, latitudeOfOrigin: 23 },\n  5070: { centralMeridian: -96, standardParallel1: 29.5, standardParallel2: 45.5, latitudeOfOrigin: 23 },\n  102003: { centralMeridian: -96, standardParallel1: 29.5, standardParallel2: 45.5, latitudeOfOrigin: 37.5 },\n  // North America Albers\n  102008: { centralMeridian: -96, standardParallel1: 20, standardParallel2: 60, latitudeOfOrigin: 40 },\n  // Alaska Albers\n  102006: { centralMeridian: -154, standardParallel1: 55, standardParallel2: 65, latitudeOfOrigin: 50 },\n  3338: { centralMeridian: -154, standardParallel1: 55, standardParallel2: 65, latitudeOfOrigin: 50 },\n  // Hawaii Albers\n  102007: { centralMeridian: -157, standardParallel1: 8, standardParallel2: 18, latitudeOfOrigin: 13 },\n};\n\nconst GEOGRAPHIC_WKIDS = new Set([4326, 4269, 4267]);\nconst WEBMERCATOR_WKIDS = new Set([3857, 102100, 102113, 900913]);\n\nfunction parseWktParameter(wkt: string, name: string): number | undefined {\n  const match = new RegExp(`PARAMETER\\\\[\"${name}\"\\\\s*,\\\\s*(-?[\\\\d.]+)`, 'i').exec(wkt);\n  return match ? Number(match[1]) : undefined;\n}\n\n/**\n * Resolves a supported projection from an ArcGIS spatial reference.\n *\n * @param sr - The spatial reference (wkid and/or WKT)\n * @returns The projection definition or null when unsupported\n */\nexport function resolveProjection(sr: ArcGISExtent['spatialReference']): Projection | null {\n  const wkid = sr?.latestWkid ?? sr?.wkid;\n  if (wkid !== undefined) {\n    if (GEOGRAPHIC_WKIDS.has(wkid)) return { kind: 'geographic' };\n    if (WEBMERCATOR_WKIDS.has(wkid)) return { kind: 'webmercator' };\n    const albers = ALBERS_WKIDS[wkid];\n    if (albers) return { kind: 'albers', params: albers };\n  }\n\n  const wkt = sr?.wkt ?? sr?.wkt2;\n  if (wkt) {\n    if (/PROJECTION\\[\"(Albers|Albers_Conic_Equal_Area)\"\\]/i.test(wkt)) {\n      const centralMeridian = parseWktParameter(wkt, 'central_meridian');\n      const standardParallel1 = parseWktParameter(wkt, 'standard_parallel_1');\n      const standardParallel2 = parseWktParameter(wkt, 'standard_parallel_2');\n      const latitudeOfOrigin = parseWktParameter(wkt, 'latitude_of_origin') ?? 0;\n      if (centralMeridian !== undefined && standardParallel1 !== undefined && standardParallel2 !== undefined) {\n        return {\n          kind: 'albers',\n          params: { centralMeridian, standardParallel1, standardParallel2, latitudeOfOrigin },\n        };\n      }\n    }\n    if (/PROJECTION\\[\"Mercator/i.test(wkt)) return { kind: 'webmercator' };\n    if (/^GEOGCS|^GEOGCRS/i.test(wkt.trim())) return { kind: 'geographic' };\n  }\n\n  return null;\n}\n\n/**\n * Inverse-projects a coordinate to [lon, lat] degrees.\n * Spherical formulas (Snyder); accuracy is sufficient for bounds.\n */\nfunction inverseProject(projection: Projection, x: number, y: number): [number, number] {\n  switch (projection.kind) {\n    case 'geographic':\n      return [x, y];\n\n    case 'webmercator': {\n      const lon = (x / R) / DEG;\n      const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) / DEG;\n      return [lon, lat];\n    }\n\n    case 'albers': {\n      const { centralMeridian, standardParallel1, standardParallel2, latitudeOfOrigin } = projection.params;\n      const phi1 = standardParallel1 * DEG;\n      const phi2 = standardParallel2 * DEG;\n      const phi0 = latitudeOfOrigin * DEG;\n      const n = (Math.sin(phi1) + Math.sin(phi2)) / 2;\n      const C = Math.cos(phi1) ** 2 + 2 * n * Math.sin(phi1);\n      const rho0 = (R * Math.sqrt(C - 2 * n * Math.sin(phi0))) / n;\n      const rho = Math.sign(n) * Math.sqrt(x * x + (rho0 - y) * (rho0 - y));\n      const theta = Math.atan2(Math.sign(n) * x, Math.sign(n) * (rho0 - y));\n      const rhoN = (rho * n) / R;\n      const sinPhi = (C - rhoN * rhoN) / (2 * n);\n      const phi = Math.asin(Math.max(-1, Math.min(1, sinPhi)));\n      const lon = centralMeridian + theta / n / DEG;\n      return [lon, phi / DEG];\n    }\n  }\n}\n\n/**\n * Projects a longitude/latitude to EPSG:3857 meters.\n *\n * @param lon - Longitude in degrees\n * @param lat - Latitude in degrees (clamped to the Mercator range)\n * @returns [x, y] in meters\n */\nexport function lngLatToMercator(lon: number, lat: number): [number, number] {\n  const clampedLat = Math.max(-MAX_MERCATOR_LAT, Math.min(MAX_MERCATOR_LAT, lat));\n  const x = R * lon * DEG;\n  const y = R * Math.log(Math.tan(Math.PI / 4 + (clampedLat * DEG) / 2));\n  return [x, y];\n}\n\n/**\n * Intersects two geographic bounds.\n *\n * @param a - First bounds [west, south, east, north]\n * @param b - Second bounds [west, south, east, north]\n * @returns The intersection, or null when the bounds do not overlap\n */\nexport function intersectBounds(a: LngLatBoundsArray, b: LngLatBoundsArray): LngLatBoundsArray | null {\n  const west = Math.max(a[0], b[0]);\n  const south = Math.max(a[1], b[1]);\n  const east = Math.min(a[2], b[2]);\n  const north = Math.min(a[3], b[3]);\n  if (west >= east || south >= north) return null;\n  return [west, south, east, north];\n}\n\n/**\n * Converts an ArcGIS extent to padded geographic bounds.\n *\n * Edge midpoints are sampled in addition to corners because conic\n * projections bow edges outward in geographic space. The result is\n * padded and clamped to valid Web Mercator latitudes.\n *\n * @param extent - The ArcGIS extent with its spatial reference\n * @returns [west, south, east, north] in degrees, or null when the\n *   spatial reference is unsupported or the extent is invalid\n */\nexport function extentToBounds(extent: ArcGISExtent | undefined | null): LngLatBoundsArray | null {\n  if (!extent) return null;\n  const { xmin, ymin, xmax, ymax } = extent;\n  if (![xmin, ymin, xmax, ymax].every(Number.isFinite) || xmin >= xmax || ymin >= ymax) {\n    return null;\n  }\n\n  const projection = resolveProjection(extent.spatialReference);\n  if (!projection) return null;\n\n  // Sample each edge so conic edge bowing is captured\n  const samplesPerEdge = 8;\n  const points: Array<[number, number]> = [];\n  for (let i = 0; i <= samplesPerEdge; i++) {\n    const fx = xmin + ((xmax - xmin) * i) / samplesPerEdge;\n    const fy = ymin + ((ymax - ymin) * i) / samplesPerEdge;\n    points.push([fx, ymin], [fx, ymax], [xmin, fy], [xmax, fy]);\n  }\n\n  let west = Infinity;\n  let south = Infinity;\n  let east = -Infinity;\n  let north = -Infinity;\n  for (const [x, y] of points) {\n    const [lon, lat] = inverseProject(projection, x, y);\n    if (!Number.isFinite(lon) || !Number.isFinite(lat)) return null;\n    west = Math.min(west, lon);\n    south = Math.min(south, lat);\n    east = Math.max(east, lon);\n    north = Math.max(north, lat);\n  }\n\n  // Pad to absorb the spherical approximation, then clamp\n  const padLon = Math.max(0.3, (east - west) * 0.03);\n  const padLat = Math.max(0.3, (north - south) * 0.03);\n  west = Math.max(-180, west - padLon);\n  east = Math.min(180, east + padLon);\n  south = Math.max(-MAX_MERCATOR_LAT, south - padLat);\n  north = Math.min(MAX_MERCATOR_LAT, north + padLat);\n\n  if (west >= east || south >= north) return null;\n  return [west, south, east, north];\n}\n","/**\n * Pure search helpers over the EnviroAtlas catalog.\n */\nimport type { SearchResult, ServiceMetadata, ServiceRef } from './types';\n\n/**\n * Normalizes a service or layer name for matching: lowercase with\n * underscores treated as spaces.\n */\nfunction normalize(text: string): string {\n  return text.toLowerCase().replace(/_/g, ' ');\n}\n\n/**\n * Filters the catalog against a search query.\n *\n * Matches are case-insensitive substring matches against service\n * names (folder-qualified) and, when layer metadata is available in\n * `layerCache`, sublayer names within MapServer services.\n *\n * @param query - The raw user query\n * @param services - All known service references\n * @param layerCache - Resolved metadata keyed by service fullName\n * @param limit - Maximum number of results @default 200\n * @returns Matching services first, then matching sublayers\n */\nexport function filterCatalog(\n  query: string,\n  services: ServiceRef[],\n  layerCache: ReadonlyMap<string, ServiceMetadata>,\n  limit = 200\n): SearchResult[] {\n  const terms = normalize(query.trim()).split(/\\s+/).filter(Boolean);\n  if (terms.length === 0) return [];\n\n  const matches = (text: string): boolean => {\n    const normalized = normalize(text);\n    return terms.every((term) => normalized.includes(term));\n  };\n\n  const serviceResults: SearchResult[] = [];\n  const sublayerResults: SearchResult[] = [];\n\n  for (const service of services) {\n    if (matches(`${service.folder} ${service.name}`)) {\n      serviceResults.push({ kind: 'service', service });\n    }\n    const metadata = layerCache.get(service.fullName);\n    if (!metadata) continue;\n    for (const layer of metadata.layers) {\n      if (matches(layer.name)) {\n        sublayerResults.push({ kind: 'sublayer', service, layer });\n      }\n    }\n  }\n\n  return [...serviceResults, ...sublayerResults].slice(0, limit);\n}\n","/**\n * Minimal DOM helpers shared by the panel views.\n */\n\n/**\n * Creates an element with a class name and optional text content.\n *\n * @param tag - The HTML tag name\n * @param className - CSS class name(s)\n * @param text - Optional text content\n * @returns The created element\n */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n  tag: K,\n  className?: string,\n  text?: string\n): HTMLElementTagNameMap[K] {\n  const element = document.createElement(tag);\n  if (className) element.className = className;\n  if (text !== undefined) element.textContent = text;\n  return element;\n}\n\n/**\n * Creates a small icon button.\n *\n * @param className - CSS class name(s)\n * @param label - Accessible label\n * @param html - Inner HTML (e.g. an SVG icon)\n * @returns The created button\n */\nexport function iconButton(className: string, label: string, html: string): HTMLButtonElement {\n  const button = el('button', className);\n  button.type = 'button';\n  button.setAttribute('aria-label', label);\n  button.title = label;\n  button.innerHTML = html;\n  return button;\n}\n\n/** Chevron icon used for expand/collapse carets */\nexport const CHEVRON_SVG =\n  '<svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" stroke=\"currentColor\" stroke-width=\"2.5\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"9 6 15 12 9 18\"/></svg>';\n\n/** Plus icon used for add buttons */\nexport const PLUS_SVG =\n  '<svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" stroke=\"currentColor\" stroke-width=\"2.5\" fill=\"none\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>';\n","/**\n * Panel skeleton: header, search input, browse region, and a slot\n * for the added layers section.\n */\nimport { el } from './dom';\n\n/**\n * Options for building the panel skeleton.\n */\nexport interface PanelViewOptions {\n  /** Panel title text */\n  title: string;\n  /** Panel width in pixels (capped to the viewport via CSS) */\n  panelWidth: number;\n  /** Called when the close button is clicked */\n  onClose: () => void;\n  /** Called on every search input change (not debounced) */\n  onSearchInput: (query: string) => void;\n}\n\n/**\n * References to the panel elements.\n */\nexport interface PanelView {\n  /** The panel root element */\n  panel: HTMLElement;\n  /** The search input */\n  searchInput: HTMLInputElement;\n  /** Inline notice element for transient messages */\n  notice: HTMLElement;\n  /** Scrollable region hosting the tree or search results */\n  browse: HTMLElement;\n  /** Container for the added layers section */\n  addedSlot: HTMLElement;\n  /** Drag handle for resizing the panel width */\n  resizer: HTMLElement;\n  /** \"Insert before\" layer select */\n  beforeSelect: HTMLSelectElement;\n}\n\n/**\n * Builds the panel skeleton.\n *\n * @param options - Panel options and callbacks\n * @returns References to the created elements\n */\nexport function createPanelView(options: PanelViewOptions): PanelView {\n  const panel = el('div', 'enviroatlas-panel');\n  panel.style.setProperty('--ea-panel-width', `${options.panelWidth}px`);\n\n  // Header with title and close button\n  const header = el('div', 'enviroatlas-header');\n  const title = el('span', 'enviroatlas-title', options.title);\n  const closeBtn = el('button', 'enviroatlas-close');\n  closeBtn.type = 'button';\n  closeBtn.setAttribute('aria-label', 'Close panel');\n  closeBtn.innerHTML = '&times;';\n  closeBtn.addEventListener('click', options.onClose);\n  header.append(title, closeBtn);\n\n  // Search input\n  const searchWrap = el('div', 'enviroatlas-search');\n  const searchInput = el('input', 'enviroatlas-search-input');\n  searchInput.type = 'search';\n  searchInput.placeholder = 'Search services and layers...';\n  searchInput.setAttribute('aria-label', 'Search EnviroAtlas services and layers');\n  searchInput.addEventListener('input', () => options.onSearchInput(searchInput.value));\n  searchWrap.append(searchInput);\n\n  const notice = el('div', 'enviroatlas-notice');\n  notice.hidden = true;\n\n  // \"Insert before\" select: where newly added layers go in the layer\n  // stack (e.g. below a label layer). Populated from the map style.\n  const beforeRow = el('div', 'enviroatlas-before-row');\n  const beforeLabel = el('span', 'enviroatlas-before-label', 'Insert before');\n  const beforeSelect = el('select', 'enviroatlas-before-select');\n  beforeSelect.setAttribute('aria-label', 'Insert added layers before this map layer');\n  beforeRow.append(beforeLabel, beforeSelect);\n\n  const browse = el('div', 'enviroatlas-browse');\n  const addedSlot = el('div', 'enviroatlas-added-slot');\n\n  // Drag handle for resizing the panel width; which edge it sits on\n  // depends on the control corner and is set via a panel class.\n  const resizer = el('div', 'enviroatlas-resizer');\n  resizer.setAttribute('role', 'separator');\n  resizer.setAttribute('aria-orientation', 'vertical');\n  resizer.setAttribute('aria-label', 'Resize panel');\n\n  panel.append(header, searchWrap, beforeRow, notice, browse, addedSlot, resizer);\n  return { panel, searchInput, notice, browse, addedSlot, resizer, beforeSelect };\n}\n","/**\n * Folder > service > sublayer tree view for browsing the catalog.\n *\n * Folders and service layer lists are fetched lazily on expand and\n * cached by the catalog client.\n */\nimport type { CatalogClient } from '../api/catalog';\nimport type { ServiceLayer, ServiceMetadata, ServiceRef } from '../api/types';\nimport { el, iconButton, CHEVRON_SVG, PLUS_SVG } from './dom';\n\n/**\n * Callbacks and dependencies for the tree view.\n */\nexport interface TreeViewContext {\n  /** Catalog client used to fetch folders, services, and layers */\n  catalog: CatalogClient;\n  /** Called when the user adds a service or sublayer */\n  onAdd: (service: ServiceRef, sublayerId?: number, label?: string) => void;\n  /** Called when service metadata resolves (feeds the search cache) */\n  onMetadata: (service: ServiceRef, metadata: ServiceMetadata) => void;\n  /** Called when a fetch fails */\n  onError: (error: Error) => void;\n}\n\n/**\n * The tree view instance.\n */\nexport interface TreeView {\n  /** Root element to insert into the panel */\n  el: HTMLElement;\n  /** Loads the folder list if not yet loaded */\n  load: () => void;\n}\n\nfunction addButton(label: string, onClick: () => void): HTMLButtonElement {\n  const button = iconButton('enviroatlas-add-btn', `Add ${label} to map`, PLUS_SVG);\n  button.addEventListener('click', (e) => {\n    e.stopPropagation();\n    onClick();\n  });\n  return button;\n}\n\nfunction statusRow(text: string, kind: 'loading' | 'error' | 'empty' = 'loading'): HTMLElement {\n  return el('div', `enviroatlas-status enviroatlas-status-${kind}`, text);\n}\n\n/**\n * Creates the browse tree view.\n *\n * @param ctx - Dependencies and callbacks\n * @returns The tree view instance\n */\nexport function createTreeView(ctx: TreeViewContext): TreeView {\n  const root = el('div', 'enviroatlas-tree');\n  let loaded = false;\n\n  function renderSublayers(service: ServiceRef, layers: ServiceLayer[], parentId: number): HTMLElement {\n    const list = el('div', 'enviroatlas-sublayers');\n    for (const layer of layers.filter((l) => l.parentLayerId === parentId)) {\n      const row = el('div', 'enviroatlas-row enviroatlas-sublayer-row');\n      const isGroup = !!layer.subLayerIds?.length;\n\n      if (isGroup) {\n        const caret = iconButton('enviroatlas-caret', `Expand ${layer.name}`, CHEVRON_SVG);\n        const name = el('span', 'enviroatlas-row-name', layer.name);\n        name.title = layer.name;\n        row.append(caret, name, addButton(layer.name, () => ctx.onAdd(service, layer.id, layer.name)));\n\n        const children = renderSublayers(service, layers, layer.id);\n        children.hidden = true;\n        const toggleGroup = () => {\n          children.hidden = !children.hidden;\n          caret.classList.toggle('expanded', !children.hidden);\n        };\n        caret.addEventListener('click', toggleGroup);\n        name.addEventListener('click', toggleGroup);\n        list.append(row, children);\n      } else {\n        const name = el('span', 'enviroatlas-row-name enviroatlas-leaf', layer.name);\n        name.title = layer.name;\n        row.append(name, addButton(layer.name, () => ctx.onAdd(service, layer.id, layer.name)));\n        list.append(row);\n      }\n    }\n    return list;\n  }\n\n  function renderService(service: ServiceRef): HTMLElement {\n    const wrapper = el('div', 'enviroatlas-service');\n    const row = el('div', 'enviroatlas-row enviroatlas-service-row');\n    const name = el('span', 'enviroatlas-row-name', service.name);\n    name.title = `${service.fullName} (${service.type})`;\n\n    const badge = el('span', 'enviroatlas-badge', service.type === 'ImageServer' ? 'IMG' : 'MAP');\n\n    if (service.type === 'MapServer') {\n      const caret = iconButton('enviroatlas-caret', `Expand ${service.name}`, CHEVRON_SVG);\n      row.append(caret, name, badge, addButton(service.name, () => ctx.onAdd(service, undefined, service.name)));\n\n      let layersEl: HTMLElement | null = null;\n      const toggleService = () => {\n        if (layersEl) {\n          layersEl.hidden = !layersEl.hidden;\n          caret.classList.toggle('expanded', !layersEl.hidden);\n          return;\n        }\n        const loading = statusRow('Loading layers...');\n        wrapper.append(loading);\n        caret.classList.add('expanded');\n        ctx.catalog\n          .getServiceMetadata(service)\n          .then((metadata) => {\n            ctx.onMetadata(service, metadata);\n            loading.remove();\n            layersEl = metadata.layers.length\n              ? renderSublayers(service, metadata.layers, -1)\n              : statusRow('No sublayers', 'empty');\n            wrapper.append(layersEl);\n          })\n          .catch((error: Error) => {\n            loading.remove();\n            caret.classList.remove('expanded');\n            wrapper.append(statusRow('Failed to load layers', 'error'));\n            ctx.onError(error);\n          });\n      };\n      caret.addEventListener('click', toggleService);\n      name.addEventListener('click', toggleService);\n    } else {\n      name.classList.add('enviroatlas-leaf');\n      row.append(name, badge, addButton(service.name, () => ctx.onAdd(service, undefined, service.name)));\n    }\n\n    wrapper.prepend(row);\n    return wrapper;\n  }\n\n  function renderFolder(folder: string): HTMLElement {\n    const wrapper = el('div', 'enviroatlas-folder');\n    const row = el('div', 'enviroatlas-row enviroatlas-folder-row');\n    const caret = iconButton('enviroatlas-caret', `Expand ${folder}`, CHEVRON_SVG);\n    const name = el('span', 'enviroatlas-row-name', folder);\n    const count = el('span', 'enviroatlas-count');\n    count.title = `Services in ${folder}`;\n    row.append(caret, name, count);\n    wrapper.append(row);\n\n    // Service counts come from the same cached folder listings the\n    // expand action uses, so this costs one request per folder.\n    ctx.catalog\n      .listServices(folder)\n      .then((services) => {\n        count.textContent = String(services.length);\n      })\n      .catch(() => {\n        count.textContent = '';\n      });\n\n    let servicesEl: HTMLElement | null = null;\n    const toggleFolder = () => {\n      if (servicesEl) {\n        servicesEl.hidden = !servicesEl.hidden;\n        caret.classList.toggle('expanded', !servicesEl.hidden);\n        return;\n      }\n      const loading = statusRow('Loading services...');\n      wrapper.append(loading);\n      caret.classList.add('expanded');\n      ctx.catalog\n        .listServices(folder)\n        .then((services) => {\n          loading.remove();\n          servicesEl = el('div', 'enviroatlas-services');\n          if (services.length === 0) {\n            servicesEl.append(statusRow('No services', 'empty'));\n          }\n          for (const service of services) {\n            servicesEl.append(renderService(service));\n          }\n          wrapper.append(servicesEl);\n        })\n        .catch((error: Error) => {\n          loading.remove();\n          caret.classList.remove('expanded');\n          wrapper.append(statusRow('Failed to load services', 'error'));\n          ctx.onError(error);\n        });\n    };\n    caret.addEventListener('click', toggleFolder);\n    name.addEventListener('click', toggleFolder);\n\n    return wrapper;\n  }\n\n  function load(): void {\n    if (loaded) return;\n    loaded = true;\n    const loading = statusRow('Loading catalog...');\n    root.append(loading);\n    ctx.catalog\n      .listFolders()\n      .then((folders) => {\n        loading.remove();\n        if (folders.length === 0) {\n          root.append(statusRow('No folders found', 'empty'));\n          return;\n        }\n        for (const folder of folders) {\n          root.append(renderFolder(folder));\n        }\n      })\n      .catch((error: Error) => {\n        loading.remove();\n        loaded = false;\n        root.append(statusRow('Failed to load catalog. Click to retry.', 'error'));\n        root.lastElementChild?.addEventListener('click', () => {\n          root.replaceChildren();\n          load();\n        });\n        ctx.onError(error);\n      });\n  }\n\n  return { el: root, load };\n}\n","/**\n * Flat search results view shown while a query is active.\n */\nimport type { SearchResult, ServiceRef } from '../api/types';\nimport { el, iconButton, PLUS_SVG } from './dom';\n\n/**\n * Callbacks for the results view.\n */\nexport interface ResultsViewContext {\n  /** Called when the user adds a result */\n  onAdd: (service: ServiceRef, sublayerId?: number, label?: string) => void;\n}\n\n/**\n * The results view instance.\n */\nexport interface ResultsView {\n  /** Root element to insert into the panel */\n  el: HTMLElement;\n  /** Replaces the rendered results */\n  setResults: (results: SearchResult[], note?: string) => void;\n  /** Shows a status message instead of results */\n  setStatus: (text: string) => void;\n}\n\n/**\n * Creates the search results view.\n *\n * @param ctx - Callbacks\n * @returns The results view instance\n */\nexport function createResultsView(ctx: ResultsViewContext): ResultsView {\n  const root = el('div', 'enviroatlas-results');\n\n  function addButton(service: ServiceRef, sublayerId: number | undefined, label: string): HTMLButtonElement {\n    const button = iconButton('enviroatlas-add-btn', `Add ${label} to map`, PLUS_SVG);\n    button.addEventListener('click', () => ctx.onAdd(service, sublayerId, label));\n    return button;\n  }\n\n  function setResults(results: SearchResult[], note?: string): void {\n    root.replaceChildren();\n    if (note) {\n      root.append(el('div', 'enviroatlas-status enviroatlas-status-loading', note));\n    }\n    if (results.length === 0) {\n      root.append(el('div', 'enviroatlas-status enviroatlas-status-empty', 'No matching services or layers'));\n      return;\n    }\n    for (const result of results) {\n      const row = el('div', 'enviroatlas-row enviroatlas-result-row');\n      const text = el('div', 'enviroatlas-result-text');\n      if (result.kind === 'service') {\n        text.append(\n          el('div', 'enviroatlas-row-name', result.service.name),\n          el('div', 'enviroatlas-breadcrumb', `${result.service.folder} · ${result.service.type}`)\n        );\n        row.append(text, addButton(result.service, undefined, result.service.name));\n      } else {\n        text.append(\n          el('div', 'enviroatlas-row-name', result.layer.name),\n          el('div', 'enviroatlas-breadcrumb', `${result.service.folder} › ${result.service.name}`)\n        );\n        row.append(text, addButton(result.service, result.layer.id, result.layer.name));\n      }\n      const title = result.kind === 'service' ? result.service.fullName : result.layer.name;\n      text.title = title;\n      root.append(row);\n    }\n  }\n\n  function setStatus(text: string): void {\n    root.replaceChildren(el('div', 'enviroatlas-status enviroatlas-status-loading', text));\n  }\n\n  return { el: root, setResults, setStatus };\n}\n","/**\n * Legend renderer for added layers.\n *\n * Fetches the service legend lazily and renders base64 swatches.\n * Hidden gracefully when a service exposes no legend.\n */\nimport type { CatalogClient } from '../api/catalog';\nimport type { LayerLegend } from '../api/types';\nimport type { AddedLayer } from '../core/types';\nimport { el } from './dom';\n\n/**\n * Renders the legend for an added layer into a container.\n *\n * @param container - The element to render into\n * @param layer - The added layer\n * @param catalog - Catalog client used to fetch the legend\n */\nexport function renderLegend(container: HTMLElement, layer: AddedLayer, catalog: CatalogClient): void {\n  container.replaceChildren(el('div', 'enviroatlas-status enviroatlas-status-loading', 'Loading legend...'));\n\n  catalog\n    .getLegend(layer.service)\n    .then((legends) => {\n      container.replaceChildren();\n      const relevant = pickLegends(legends, layer.sublayerId);\n      if (relevant.length === 0) {\n        container.append(el('div', 'enviroatlas-status enviroatlas-status-empty', 'No legend available'));\n        return;\n      }\n      for (const layerLegend of relevant) {\n        if (relevant.length > 1) {\n          container.append(el('div', 'enviroatlas-legend-layer', layerLegend.layerName));\n        }\n        for (const entry of layerLegend.legend) {\n          const item = el('div', 'enviroatlas-legend-item');\n          const swatch = el('img', 'enviroatlas-legend-swatch');\n          swatch.src = `data:${entry.contentType};base64,${entry.imageData}`;\n          swatch.width = entry.width;\n          swatch.height = entry.height;\n          swatch.alt = entry.label || 'legend swatch';\n          item.append(swatch, el('span', 'enviroatlas-legend-label', entry.label || layerLegend.layerName));\n          container.append(item);\n        }\n      }\n    })\n    .catch(() => {\n      container.replaceChildren(el('div', 'enviroatlas-status enviroatlas-status-empty', 'No legend available'));\n    });\n}\n\nfunction pickLegends(legends: LayerLegend[], sublayerId?: number): LayerLegend[] {\n  if (sublayerId === undefined) return legends;\n  const match = legends.filter((legend) => legend.layerId === sublayerId);\n  // Group layers have no legend entries of their own; fall back to all\n  return match.length > 0 ? match : legends;\n}\n","/**\n * \"Added layers\" management section: visibility, opacity, legend,\n * and removal for each layer added through the control.\n */\nimport type { CatalogClient } from '../api/catalog';\nimport type { AddedLayer } from '../core/types';\nimport { el, iconButton } from './dom';\nimport { renderLegend } from './legendView';\n\nconst LEGEND_SVG =\n  '<svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\"><line x1=\"8\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"8\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"8\" y1=\"18\" x2=\"20\" y2=\"18\"/><rect x=\"3\" y=\"5\" width=\"2\" height=\"2\"/><rect x=\"3\" y=\"11\" width=\"2\" height=\"2\"/><rect x=\"3\" y=\"17\" width=\"2\" height=\"2\"/></svg>';\n\nconst TRASH_SVG =\n  '<svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6M14 11v6\"/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/></svg>';\n\n/**\n * Callbacks and dependencies for the added layers view.\n */\nexport interface AddedLayersViewContext {\n  /** Catalog client used to fetch legends */\n  catalog: CatalogClient;\n  /** Called when the user toggles layer visibility */\n  onVisibilityChange: (id: string, visible: boolean) => void;\n  /** Called when the user changes layer opacity */\n  onOpacityChange: (id: string, opacity: number) => void;\n  /** Called when the user removes a layer */\n  onRemove: (id: string) => void;\n}\n\n/**\n * The added layers view instance.\n */\nexport interface AddedLayersView {\n  /** Root element to insert into the panel */\n  el: HTMLElement;\n  /** Re-renders the section for the given layers */\n  update: (layers: AddedLayer[]) => void;\n}\n\n/**\n * Creates the added layers management section.\n *\n * @param ctx - Dependencies and callbacks\n * @returns The added layers view instance\n */\nexport function createAddedLayersView(ctx: AddedLayersViewContext): AddedLayersView {\n  const root = el('div', 'enviroatlas-added');\n  const heading = el('div', 'enviroatlas-section-title', 'Added layers');\n  const list = el('div', 'enviroatlas-added-list');\n  root.append(heading, list);\n\n  const expandedLegends = new Set<string>();\n\n  function renderRow(layer: AddedLayer): HTMLElement {\n    const wrapper = el('div', 'enviroatlas-added-item');\n    const row = el('div', 'enviroatlas-row enviroatlas-added-row');\n\n    const visibility = el('input', 'enviroatlas-visibility');\n    visibility.type = 'checkbox';\n    visibility.checked = layer.visible;\n    visibility.title = layer.visible ? 'Hide layer' : 'Show layer';\n    visibility.setAttribute('aria-label', `Toggle visibility of ${layer.label}`);\n    visibility.addEventListener('change', () => ctx.onVisibilityChange(layer.id, visibility.checked));\n\n    const label = el('span', 'enviroatlas-row-name', layer.label);\n    label.title = `${layer.service.fullName}${layer.sublayerId !== undefined ? ` (layer ${layer.sublayerId})` : ''}`;\n\n    const legendBtn = iconButton('enviroatlas-icon-btn enviroatlas-legend-btn', `Toggle legend for ${layer.label}`, LEGEND_SVG);\n    const removeBtn = iconButton('enviroatlas-icon-btn enviroatlas-remove-btn', `Remove ${layer.label}`, TRASH_SVG);\n    removeBtn.addEventListener('click', () => ctx.onRemove(layer.id));\n\n    row.append(visibility, label, legendBtn, removeBtn);\n\n    const controls = el('div', 'enviroatlas-added-controls');\n    const opacity = el('input', 'enviroatlas-opacity');\n    opacity.type = 'range';\n    opacity.min = '0';\n    opacity.max = '100';\n    opacity.step = '1';\n    opacity.value = String(Math.round(layer.opacity * 100));\n    opacity.setAttribute('aria-label', `Opacity of ${layer.label}`);\n    const opacityValue = el('span', 'enviroatlas-opacity-value', `${Math.round(layer.opacity * 100)}%`);\n    opacity.addEventListener('input', () => {\n      opacityValue.textContent = `${opacity.value}%`;\n      ctx.onOpacityChange(layer.id, Number(opacity.value) / 100);\n    });\n    controls.append(el('span', 'enviroatlas-opacity-label', 'Opacity'), opacity, opacityValue);\n\n    const legendContainer = el('div', 'enviroatlas-legend');\n    legendContainer.hidden = !expandedLegends.has(layer.id);\n    if (!legendContainer.hidden) {\n      renderLegend(legendContainer, layer, ctx.catalog);\n    }\n    legendBtn.classList.toggle('active', !legendContainer.hidden);\n    legendBtn.addEventListener('click', () => {\n      const show = legendContainer.hidden === true;\n      legendContainer.hidden = !show;\n      legendBtn.classList.toggle('active', show);\n      if (show) {\n        expandedLegends.add(layer.id);\n        renderLegend(legendContainer, layer, ctx.catalog);\n      } else {\n        expandedLegends.delete(layer.id);\n      }\n    });\n\n    wrapper.append(row, controls, legendContainer);\n    return wrapper;\n  }\n\n  function update(layers: AddedLayer[]): void {\n    list.replaceChildren();\n    for (const id of [...expandedLegends]) {\n      if (!layers.some((layer) => layer.id === id)) expandedLegends.delete(id);\n    }\n    if (layers.length === 0) {\n      root.hidden = true;\n      return;\n    }\n    root.hidden = false;\n    for (const layer of layers) {\n      list.append(renderRow(layer));\n    }\n  }\n\n  update([]);\n  return { el: root, update };\n}\n","/**\n * Clamps a value between a minimum and maximum.\n *\n * @param value - The value to clamp\n * @param min - The minimum allowed value\n * @param max - The maximum allowed value\n * @returns The clamped value\n *\n * @example\n * ```typescript\n * clamp(5, 0, 10);  // returns 5\n * clamp(-5, 0, 10); // returns 0\n * clamp(15, 0, 10); // returns 10\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n  return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Formats a numeric value with appropriate decimal places based on step size.\n *\n * @param value - The value to format\n * @param step - The step size to determine decimal places\n * @returns The formatted value as a string\n *\n * @example\n * ```typescript\n * formatNumericValue(5, 1);     // returns \"5\"\n * formatNumericValue(0.5, 0.1); // returns \"0.5\"\n * formatNumericValue(0.55, 0.01); // returns \"0.55\"\n * ```\n */\nexport function formatNumericValue(value: number, step: number): string {\n  if (step === 0) return value.toString();\n  const decimals = Math.max(0, -Math.floor(Math.log10(step)));\n  return value.toFixed(decimals);\n}\n\n/**\n * Generates a unique ID string.\n *\n * @param prefix - Optional prefix for the ID\n * @returns A unique ID string\n *\n * @example\n * ```typescript\n * generateId('control'); // returns \"control-abc123\"\n * generateId();          // returns \"abc123\"\n * ```\n */\nexport function generateId(prefix?: string): string {\n  const id = Math.random().toString(36).substring(2, 9);\n  return prefix ? `${prefix}-${id}` : id;\n}\n\n/**\n * Debounces a function call.\n *\n * @param fn - The function to debounce\n * @param delay - The delay in milliseconds\n * @returns A debounced version of the function\n *\n * @example\n * ```typescript\n * const debouncedUpdate = debounce(() => updateMap(), 100);\n * window.addEventListener('resize', debouncedUpdate);\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => void>(\n  fn: T,\n  delay: number\n): (...args: Parameters<T>) => void {\n  let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n  return (...args: Parameters<T>) => {\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n    }\n    timeoutId = setTimeout(() => {\n      fn(...args);\n      timeoutId = null;\n    }, delay);\n  };\n}\n\n/**\n * Throttles a function call.\n *\n * @param fn - The function to throttle\n * @param limit - The minimum time between calls in milliseconds\n * @returns A throttled version of the function\n *\n * @example\n * ```typescript\n * const throttledScroll = throttle(() => handleScroll(), 100);\n * window.addEventListener('scroll', throttledScroll);\n * ```\n */\nexport function throttle<T extends (...args: unknown[]) => void>(\n  fn: T,\n  limit: number\n): (...args: Parameters<T>) => void {\n  let inThrottle = false;\n\n  return (...args: Parameters<T>) => {\n    if (!inThrottle) {\n      fn(...args);\n      inThrottle = true;\n      setTimeout(() => {\n        inThrottle = false;\n      }, limit);\n    }\n  };\n}\n\n/**\n * Creates a CSS class string from an object of class names.\n *\n * @param classes - Object with class names as keys and boolean values\n * @returns A space-separated string of class names\n *\n * @example\n * ```typescript\n * classNames({ active: true, disabled: false, visible: true });\n * // returns \"active visible\"\n * ```\n */\nexport function classNames(classes: Record<string, boolean>): string {\n  return Object.entries(classes)\n    .filter(([, value]) => value)\n    .map(([key]) => key)\n    .join(' ');\n}\n","import type { ImageSource, Map as MapLibreMap, RasterSourceSpecification } from 'maplibre-gl';\nimport { intersectBounds, lngLatToMercator } from '../api/extent';\nimport type { LngLatBoundsArray } from '../api/extent';\nimport type { ServiceRef } from '../api/types';\nimport { buildTileTemplate, buildViewExportUrl } from '../api/urls';\nimport { generateId } from '../utils/helpers';\nimport type { AddedLayer } from './types';\n\n/** How each added layer is rendered */\nexport type RenderMode = 'image' | 'tiles';\n\n/** Maximum pixels requested per export axis */\nconst MAX_IMAGE_SIZE = 2048;\n\n/** 1x1 transparent PNG shown when a layer is outside the current view */\nconst BLANK_IMAGE =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';\n\n/** Geographic bounds of the Web Mercator world */\nconst WORLD_BOUNDS: LngLatBoundsArray = [-180, -85.051129, 180, 85.051129];\n\n/**\n * Options for creating a {@link MapLayerManager}.\n */\nexport interface MapLayerManagerOptions {\n  /** ArcGIS REST services root */\n  servicesUrl: string;\n  /** Raster tile size in pixels (tiles mode) */\n  tileSize: number;\n  /** ArcGIS export image format */\n  imageFormat: string;\n  /** Attribution attached to raster sources */\n  attribution: string;\n  /**\n   * How layers are rendered. 'image' issues a single export request\n   * per map view (fast against dynamic ArcGIS services); 'tiles'\n   * requests one export per 256px tile.\n   */\n  renderMode: RenderMode;\n  /** Existing layer id to insert added layers before (skipped when absent) */\n  beforeId?: string;\n}\n\n/**\n * Manages MapLibre raster sources and layers created from\n * EnviroAtlas services. Pure map mutation, no UI concerns.\n */\nexport class MapLayerManager {\n  private readonly _map: MapLibreMap;\n  private readonly _options: MapLayerManagerOptions;\n  private readonly _layers = new globalThis.Map<string, AddedLayer>();\n  private _viewHandler: (() => void) | null = null;\n\n  /**\n   * Creates a manager bound to a map instance.\n   *\n   * @param map - The MapLibre GL map\n   * @param options - Source creation options\n   */\n  constructor(map: MapLibreMap, options: MapLayerManagerOptions) {\n    this._map = map;\n    this._options = options;\n  }\n\n  /** All layers currently managed, in insertion order. */\n  getLayers(): AddedLayer[] {\n    return [...this._layers.values()];\n  }\n\n  /**\n   * Finds an existing entry for the same service and sublayer.\n   *\n   * @param service - The service reference\n   * @param sublayerId - Optional sublayer id\n   * @returns The matching entry or undefined\n   */\n  findLayer(service: ServiceRef, sublayerId?: number): AddedLayer | undefined {\n    return this.getLayers().find(\n      (layer) => layer.service.fullName === service.fullName && layer.sublayerId === sublayerId\n    );\n  }\n\n  /**\n   * Adds a service (or a single MapServer sublayer) to the map.\n   *\n   * In 'image' mode (default) a single export request covers the\n   * visible map area and is refreshed when the view settles; in\n   * 'tiles' mode a raster tile source requests one export per tile.\n   *\n   * @param service - The service to add\n   * @param label - Display label for the added layer\n   * @param sublayerId - Optional MapServer sublayer id\n   * @param opacity - Initial raster opacity (0 to 1)\n   * @param bounds - Optional geographic bounds limiting requests\n   * @returns The created added-layer entry\n   */\n  addLayer(\n    service: ServiceRef,\n    label: string,\n    sublayerId?: number,\n    opacity = 1,\n    bounds?: LngLatBoundsArray\n  ): AddedLayer {\n    const id = generateId('enviroatlas');\n    const entry: AddedLayer = {\n      id,\n      sourceId: id,\n      layerId: id,\n      service,\n      sublayerId,\n      label,\n      visible: true,\n      opacity,\n      bounds,\n    };\n\n    this._createSource(entry);\n    this._createLayer(entry);\n\n    this._layers.set(id, entry);\n    return entry;\n  }\n\n  /**\n   * Re-registers a previously persisted layer, reusing native source\n   * and layer objects the host application may have already recreated.\n   *\n   * Host applications that persist {@link AddedLayer} entries (for\n   * example in a saved project) often recreate the native MapLibre\n   * source and layer themselves before re-activating the control. This\n   * method hands those layers back to the manager without duplicating\n   * the natives: existing source/layer objects are kept and only the\n   * missing ones are created, while opacity and visibility are\n   * reconciled to match the entry.\n   *\n   * @param entry - The persisted added-layer entry to restore\n   * @returns The tracked added-layer entry (an existing one when the id\n   *   was already managed, otherwise the newly registered copy)\n   */\n  restoreLayer(entry: AddedLayer): AddedLayer {\n    const existing = this._layers.get(entry.id);\n    if (existing) return existing;\n\n    const copy: AddedLayer = { ...entry };\n\n    if (!this._map.getSource(copy.sourceId)) {\n      this._createSource(copy);\n    } else if (this._options.renderMode === 'image') {\n      // The host recreated the source; still ensure the shared view\n      // listener that refreshes image layers is registered.\n      this._ensureViewHandler();\n    }\n\n    if (!this._map.getLayer(copy.layerId)) {\n      this._createLayer(copy);\n    } else {\n      // The host recreated the native layer; reconcile paint and layout\n      // so manager state and the map agree.\n      this._map.setPaintProperty(copy.layerId, 'raster-opacity', copy.opacity);\n      this._map.setLayoutProperty(copy.layerId, 'visibility', copy.visible ? 'visible' : 'none');\n    }\n\n    this._layers.set(copy.id, copy);\n    return copy;\n  }\n\n  /**\n   * Creates the native MapLibre source for an added layer according to\n   * the current render mode.\n   *\n   * @param entry - The added layer to create a source for\n   */\n  private _createSource(entry: AddedLayer): void {\n    if (this._options.renderMode === 'image') {\n      const view = this._computeView(entry);\n      this._map.addSource(entry.sourceId, {\n        type: 'image',\n        url: view?.url ?? BLANK_IMAGE,\n        coordinates: view?.coordinates ?? [\n          [0, 1],\n          [1, 1],\n          [1, 0],\n          [0, 0],\n        ],\n      });\n      this._ensureViewHandler();\n    } else {\n      const tileTemplate = buildTileTemplate(\n        entry.service,\n        entry.sublayerId,\n        { tileSize: this._options.tileSize, imageFormat: this._options.imageFormat },\n        this._options.servicesUrl\n      );\n      const source: RasterSourceSpecification = {\n        type: 'raster',\n        tiles: [tileTemplate],\n        tileSize: this._options.tileSize,\n        attribution: this._options.attribution,\n      };\n      // Bounds keep MapLibre from requesting tiles far outside the data\n      // extent, which the EnviroAtlas server answers with slow 504s.\n      if (entry.bounds) source.bounds = entry.bounds;\n      this._map.addSource(entry.sourceId, source);\n    }\n  }\n\n  /**\n   * Creates the native MapLibre raster layer for an added layer,\n   * removing the source if layer creation fails.\n   *\n   * @param entry - The added layer to create a layer for\n   */\n  private _createLayer(entry: AddedLayer): void {\n    // Insert below the configured layer when it exists on the map\n    const beforeId =\n      this._options.beforeId && this._map.getLayer(this._options.beforeId) ? this._options.beforeId : undefined;\n    try {\n      this._map.addLayer(\n        {\n          id: entry.layerId,\n          type: 'raster',\n          source: entry.sourceId,\n          paint: {\n            'raster-opacity': entry.opacity,\n            // Image-mode sources swap the whole picture on view changes;\n            // fading would flash the old extent during the swap.\n            ...(this._options.renderMode === 'image' ? { 'raster-fade-duration': 0 } : {}),\n          },\n          layout: { visibility: entry.visible ? 'visible' : 'none' },\n        },\n        beforeId\n      );\n    } catch (error) {\n      // Avoid orphaning the source when layer creation fails\n      if (this._map.getSource(entry.sourceId)) {\n        this._map.removeSource(entry.sourceId);\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Removes a managed layer and its source from the map.\n   *\n   * @param id - The added-layer id\n   * @returns The removed entry or undefined when unknown\n   */\n  removeLayer(id: string): AddedLayer | undefined {\n    const entry = this._layers.get(id);\n    if (!entry) return undefined;\n\n    if (this._map.getLayer(entry.layerId)) {\n      this._map.removeLayer(entry.layerId);\n    }\n    if (this._map.getSource(entry.sourceId)) {\n      this._map.removeSource(entry.sourceId);\n    }\n    this._layers.delete(id);\n    if (this._layers.size === 0) {\n      this._removeViewHandler();\n    }\n    return entry;\n  }\n\n  /**\n   * Updates the raster opacity of a managed layer.\n   *\n   * @param id - The added-layer id\n   * @param opacity - New opacity (0 to 1)\n   * @returns The updated entry or undefined when unknown\n   */\n  setOpacity(id: string, opacity: number): AddedLayer | undefined {\n    const entry = this._layers.get(id);\n    if (!entry) return undefined;\n\n    entry.opacity = opacity;\n    if (this._map.getLayer(entry.layerId)) {\n      this._map.setPaintProperty(entry.layerId, 'raster-opacity', opacity);\n    }\n    return entry;\n  }\n\n  /**\n   * Toggles the visibility of a managed layer.\n   *\n   * @param id - The added-layer id\n   * @param visible - Whether the layer should be visible\n   * @returns The updated entry or undefined when unknown\n   */\n  setVisibility(id: string, visible: boolean): AddedLayer | undefined {\n    const entry = this._layers.get(id);\n    if (!entry) return undefined;\n\n    entry.visible = visible;\n    if (this._map.getLayer(entry.layerId)) {\n      this._map.setLayoutProperty(entry.layerId, 'visibility', visible ? 'visible' : 'none');\n    }\n    // The image may be stale if the view moved while hidden\n    if (visible) {\n      this._updateImageLayer(entry);\n    }\n    return entry;\n  }\n\n  /**\n   * Changes the layer that added layers are inserted before, moving\n   * the already-added layers accordingly.\n   *\n   * @param beforeId - The target layer id, or undefined for top of map\n   */\n  setBeforeId(beforeId?: string): void {\n    this._options.beforeId = beforeId;\n    const valid = beforeId && this._map.getLayer(beforeId) ? beforeId : undefined;\n    for (const entry of this._layers.values()) {\n      if (this._map.getLayer(entry.layerId)) {\n        this._map.moveLayer(entry.layerId, valid);\n      }\n    }\n  }\n\n  /**\n   * Removes all managed layers and sources from the map.\n   */\n  removeAll(): void {\n    for (const id of [...this._layers.keys()]) {\n      this.removeLayer(id);\n    }\n  }\n\n  /**\n   * Computes the export request and image placement for the current\n   * map view, clamped to the layer bounds.\n   *\n   * @param entry - The added layer\n   * @returns The export url and image corner coordinates, or null when\n   *   the layer is entirely outside the current view\n   */\n  private _computeView(\n    entry: AddedLayer\n  ): { url: string; coordinates: [[number, number], [number, number], [number, number], [number, number]] } | null {\n    const mapBounds = this._map.getBounds();\n    const view: LngLatBoundsArray = [\n      Math.max(mapBounds.getWest(), WORLD_BOUNDS[0]),\n      Math.max(mapBounds.getSouth(), WORLD_BOUNDS[1]),\n      Math.min(mapBounds.getEast(), WORLD_BOUNDS[2]),\n      Math.min(mapBounds.getNorth(), WORLD_BOUNDS[3]),\n    ];\n    const clamped = intersectBounds(view, entry.bounds ?? WORLD_BOUNDS);\n    if (!clamped) return null;\n\n    const [xmin, ymin] = lngLatToMercator(clamped[0], clamped[1]);\n    const [xmax, ymax] = lngLatToMercator(clamped[2], clamped[3]);\n    if (xmin >= xmax || ymin >= ymax) return null;\n\n    // Match the on-screen pixel density of the clamped area\n    const container = this._map.getContainer();\n    const viewWidth = Math.max(container.clientWidth, 1);\n    const [viewXmin] = lngLatToMercator(view[0], view[1]);\n    const [viewXmax] = lngLatToMercator(view[2], view[3]);\n    const metersPerPixel = (viewXmax - viewXmin) / viewWidth;\n    let width = (xmax - xmin) / metersPerPixel;\n    let height = (ymax - ymin) / metersPerPixel;\n    const scale = Math.min(1, MAX_IMAGE_SIZE / Math.max(width, height));\n    width = Math.max(1, Math.round(width * scale));\n    height = Math.max(1, Math.round(height * scale));\n\n    const url = buildViewExportUrl(\n      entry.service,\n      entry.sublayerId,\n      [xmin, ymin, xmax, ymax],\n      width,\n      height,\n      { imageFormat: this._options.imageFormat },\n      this._options.servicesUrl\n    );\n    return {\n      url,\n      coordinates: [\n        [clamped[0], clamped[3]],\n        [clamped[2], clamped[3]],\n        [clamped[2], clamped[1]],\n        [clamped[0], clamped[1]],\n      ],\n    };\n  }\n\n  /**\n   * Refreshes the export image of a single layer for the current view.\n   *\n   * @param entry - The added layer\n   */\n  private _updateImageLayer(entry: AddedLayer): void {\n    if (this._options.renderMode !== 'image' || !entry.visible) return;\n    const source = this._map.getSource(entry.sourceId) as ImageSource | undefined;\n    if (!source || typeof source.updateImage !== 'function') return;\n\n    const view = this._computeView(entry);\n    if (!view) {\n      // Out of view: swap in a blank image so nothing stale lingers\n      source.updateImage({\n        url: BLANK_IMAGE,\n        coordinates: [\n          [0, 1],\n          [1, 1],\n          [1, 0],\n          [0, 0],\n        ],\n      });\n      return;\n    }\n    source.updateImage({ url: view.url, coordinates: view.coordinates });\n  }\n\n  /** Registers the shared view listener that refreshes image layers. */\n  private _ensureViewHandler(): void {\n    if (this._viewHandler) return;\n    this._viewHandler = () => {\n      for (const entry of this._layers.values()) {\n        this._updateImageLayer(entry);\n      }\n    };\n    this._map.on('moveend', this._viewHandler);\n    this._map.on('resize', this._viewHandler);\n  }\n\n  /** Removes the shared view listener. */\n  private _removeViewHandler(): void {\n    if (!this._viewHandler) return;\n    this._map.off('moveend', this._viewHandler);\n    this._map.off('resize', this._viewHandler);\n    this._viewHandler = null;\n  }\n}\n","import type { IControl, Map as MapLibreMap } from 'maplibre-gl';\nimport { CatalogClient, DEFAULT_EXCLUDED_FOLDERS } from '../api/catalog';\nimport { extentToBounds } from '../api/extent';\nimport { filterCatalog } from '../api/search';\nimport type { ServiceMetadata, ServiceRef } from '../api/types';\nimport { DEFAULT_SERVICES_URL } from '../api/urls';\nimport { createAddedLayersView, createPanelView, createResultsView, createTreeView } from '../ui';\nimport type { AddedLayersView, PanelView, ResultsView, TreeView } from '../ui';\nimport { clamp, debounce } from '../utils/helpers';\nimport { MapLayerManager } from './mapLayers';\nimport type {\n  AddedLayer,\n  EnviroAtlasControlEvent,\n  EnviroAtlasControlEventHandler,\n  EnviroAtlasControlOptions,\n  EnviroAtlasState,\n  EnviroAtlasTheme,\n} from './types';\n\n/**\n * Default options for the EnviroAtlasControl\n */\nconst DEFAULT_OPTIONS: Required<EnviroAtlasControlOptions> = {\n  collapsed: true,\n  position: 'top-right',\n  title: 'US EPA EnviroAtlas',\n  panelWidth: 360,\n  className: '',\n  theme: 'auto',\n  servicesUrl: DEFAULT_SERVICES_URL,\n  excludedFolders: DEFAULT_EXCLUDED_FOLDERS,\n  defaultOpacity: 1,\n  renderMode: 'image',\n  tileSize: 256,\n  imageFormat: 'png32',\n  attribution: 'U.S. EPA EnviroAtlas',\n  beforeId: '',\n  searchDebounceMs: 250,\n  fitBoundsOnAdd: true,\n  quietTileErrors: true,\n};\n\n/** Minimum panel width in pixels when resizing */\nconst MIN_PANEL_WIDTH = 240;\n\n/**\n * Event handlers map type\n */\ntype EventHandlersMap = globalThis.Map<EnviroAtlasControlEvent, Set<EnviroAtlasControlEventHandler>>;\n\n/**\n * A MapLibre GL control for searching and adding EPA EnviroAtlas\n * web services to the map.\n *\n * The control renders as a 29x29 toggle button (matching the\n * navigation control) that expands into a floating panel with a\n * catalog tree, search, and a management section for added layers.\n *\n * @example\n * ```typescript\n * const control = new EnviroAtlasControl({\n *   collapsed: false,\n *   theme: 'auto',\n * });\n * map.addControl(control, 'top-right');\n * control.on('layeradd', (event) => console.log('Added', event.layer));\n * ```\n */\nexport class EnviroAtlasControl implements IControl {\n  private _map?: MapLibreMap;\n  private _mapContainer?: HTMLElement;\n  private _container?: HTMLElement;\n  private _panel?: HTMLElement;\n  private _options: Required<EnviroAtlasControlOptions>;\n  private _state: EnviroAtlasState;\n  private _eventHandlers: EventHandlersMap = new globalThis.Map();\n\n  private _catalog?: CatalogClient;\n  private _layerManager?: MapLayerManager;\n  private _panelView?: PanelView;\n  private _treeView?: TreeView;\n  private _resultsView?: ResultsView;\n  private _addedView?: AddedLayersView;\n\n  /** Resolved layer metadata available for synchronous search */\n  private readonly _metadataCache = new globalThis.Map<string, ServiceMetadata>();\n  private _allServices: ServiceRef[] = [];\n  private _prefetchStarted = false;\n  private _searchEpoch = 0;\n  private _noticeTimer: ReturnType<typeof setTimeout> | null = null;\n  private _debouncedSearch?: (query: string) => void;\n  /** Layers handed to restoreLayers before the control was added to a map */\n  private _pendingRestore: AddedLayer[] = [];\n\n  // Panel positioning handlers\n  private _resizeHandler: (() => void) | null = null;\n  private _mapResizeHandler: (() => void) | null = null;\n  private _clickOutsideHandler: ((e: MouseEvent) => void) | null = null;\n  private _clickCaptureHandler: ((e: MouseEvent) => void) | null = null;\n  private _mapErrorHandler: ((e: { error?: Error }) => void) | null = null;\n  /** Whether the panel was expanded when the current click dispatch began */\n  private _expandedAtClickStart = false;\n  /** Suppresses the click fired when a resize drag ends outside the panel */\n  private _suppressNextClickOutside = false;\n\n  /**\n   * Creates a new EnviroAtlasControl instance.\n   *\n   * @param options - Configuration options for the control\n   */\n  constructor(options?: Partial<EnviroAtlasControlOptions>) {\n    this._options = { ...DEFAULT_OPTIONS, ...options };\n    this._state = {\n      collapsed: this._options.collapsed,\n      panelWidth: this._options.panelWidth,\n      theme: this._options.theme,\n      query: '',\n      addedLayers: [],\n      data: {},\n    };\n  }\n\n  /**\n   * Called when the control is added to the map.\n   * Implements the IControl interface.\n   *\n   * @param map - The MapLibre GL map instance\n   * @returns The control's container element\n   */\n  onAdd(map: MapLibreMap): HTMLElement {\n    this._map = map;\n    this._mapContainer = map.getContainer();\n    this._catalog = new CatalogClient({\n      servicesUrl: this._options.servicesUrl,\n      excludedFolders: this._options.excludedFolders,\n    });\n    this._layerManager = new MapLayerManager(map, {\n      servicesUrl: this._options.servicesUrl,\n      tileSize: this._options.tileSize,\n      imageFormat: this._options.imageFormat,\n      attribution: this._options.attribution,\n      renderMode: this._options.renderMode,\n      beforeId: this._options.beforeId,\n    });\n    this._debouncedSearch = debounce(\n      (...args: unknown[]) => this._runSearch(args[0] as string),\n      this._options.searchDebounceMs\n    );\n\n    this._container = this._createContainer();\n    this._panel = this._createPanel();\n    this._applyTheme();\n\n    // Append panel to map container for independent positioning (avoids overlap with other controls)\n    this._mapContainer.appendChild(this._panel);\n\n    // Setup event listeners for panel positioning and click-outside\n    this._setupEventListeners();\n\n    // Apply any layers handed to restoreLayers before the control was\n    // added to a map.\n    if (this._pendingRestore.length > 0) {\n      const pending = this._pendingRestore;\n      this._pendingRestore = [];\n      this.restoreLayers(pending);\n    }\n\n    // Set initial panel state\n    if (!this._state.collapsed) {\n      this._panel.classList.add('expanded');\n      this._treeView?.load();\n      this._refreshBeforeSelect();\n      // Update position after control is added to DOM\n      requestAnimationFrame(() => {\n        this._updatePanelPosition();\n      });\n    }\n\n    return this._container;\n  }\n\n  /**\n   * Called when the control is removed from the map.\n   * Implements the IControl interface.\n   */\n  onRemove(): void {\n    // Remove event listeners\n    if (this._resizeHandler) {\n      window.removeEventListener('resize', this._resizeHandler);\n      this._resizeHandler = null;\n    }\n    if (this._mapResizeHandler && this._map) {\n      this._map.off('resize', this._mapResizeHandler);\n      this._mapResizeHandler = null;\n    }\n    if (this._mapErrorHandler && this._map) {\n      this._map.off('error', this._mapErrorHandler);\n      this._mapErrorHandler = null;\n    }\n    if (this._clickOutsideHandler) {\n      document.removeEventListener('click', this._clickOutsideHandler);\n      this._clickOutsideHandler = null;\n    }\n    if (this._clickCaptureHandler) {\n      document.removeEventListener('click', this._clickCaptureHandler, true);\n      this._clickCaptureHandler = null;\n    }\n    if (this._noticeTimer) {\n      clearTimeout(this._noticeTimer);\n      this._noticeTimer = null;\n    }\n\n    // Remove added layers and abort in-flight catalog requests\n    this._layerManager?.removeAll();\n    this._catalog?.abort();\n    this._metadataCache.clear();\n    this._allServices = [];\n    this._prefetchStarted = false;\n    this._state.addedLayers = [];\n    this._pendingRestore = [];\n\n    // Remove panel from map container\n    this._panel?.parentNode?.removeChild(this._panel);\n\n    // Remove button container from control stack\n    this._container?.parentNode?.removeChild(this._container);\n\n    this._map = undefined;\n    this._mapContainer = undefined;\n    this._container = undefined;\n    this._panel = undefined;\n    this._panelView = undefined;\n    this._treeView = undefined;\n    this._resultsView = undefined;\n    this._addedView = undefined;\n    this._layerManager = undefined;\n    this._catalog = undefined;\n    this._eventHandlers.clear();\n  }\n\n  /**\n   * Gets the current state of the control.\n   *\n   * @returns The current control state\n   */\n  getState(): EnviroAtlasState {\n    return { ...this._state, addedLayers: [...this._state.addedLayers] };\n  }\n\n  /**\n   * Updates the control state.\n   *\n   * @param newState - Partial state to merge with current state\n   */\n  setState(newState: Partial<EnviroAtlasState>): void {\n    this._state = { ...this._state, ...newState };\n    this._emit('statechange');\n  }\n\n  /**\n   * Toggles the collapsed state of the control panel.\n   */\n  toggle(): void {\n    this._state.collapsed = !this._state.collapsed;\n\n    if (this._panel) {\n      if (this._state.collapsed) {\n        this._panel.classList.remove('expanded');\n        this._emit('collapse');\n      } else {\n        this._panel.classList.add('expanded');\n        this._treeView?.load();\n        this._refreshBeforeSelect();\n        this._updatePanelPosition();\n        this._emit('expand');\n      }\n    }\n\n    this._emit('statechange');\n  }\n\n  /**\n   * Expands the control panel.\n   */\n  expand(): void {\n    if (this._state.collapsed) {\n      this.toggle();\n    }\n  }\n\n  /**\n   * Collapses the control panel.\n   */\n  collapse(): void {\n    if (!this._state.collapsed) {\n      this.toggle();\n    }\n  }\n\n  /**\n   * Sets the panel width in pixels (clamped to the map width).\n   *\n   * @param width - The new panel width\n   */\n  setPanelWidth(width: number): void {\n    // clientWidth can be 0 before layout (e.g. detached containers)\n    const mapWidth = this._mapContainer?.clientWidth || 0;\n    const maxWidth = mapWidth > 0 ? Math.max(MIN_PANEL_WIDTH, mapWidth - 20) : Number.POSITIVE_INFINITY;\n    const clamped = Math.round(clamp(width, MIN_PANEL_WIDTH, maxWidth));\n    this._state.panelWidth = clamped;\n    this._panel?.style.setProperty('--ea-panel-width', `${clamped}px`);\n    this._emit('statechange');\n  }\n\n  /**\n   * Sets the color theme of the control.\n   *\n   * @param theme - The theme to apply\n   */\n  setTheme(theme: EnviroAtlasTheme): void {\n    this._state.theme = theme;\n    this._applyTheme();\n    this._emit('statechange');\n  }\n\n  /**\n   * Adds a service (or a single MapServer sublayer) to the map.\n   *\n   * The service extent is fetched (and cached) to limit tile requests\n   * to the data area and, unless `fitBoundsOnAdd` is disabled, to zoom\n   * the map to the added layer.\n   *\n   * @param service - The service to add\n   * @param sublayerId - Optional MapServer sublayer id\n   * @param label - Optional display label (defaults to the service name)\n   * @returns The added layer entry, or the existing entry when already added\n   */\n  async addServiceLayer(service: ServiceRef, sublayerId?: number, label?: string): Promise<AddedLayer | undefined> {\n    if (!this._layerManager) return undefined;\n\n    const existing = this._layerManager.findLayer(service, sublayerId);\n    if (existing) {\n      this._showNotice(`\"${existing.label}\" is already on the map`);\n      return existing;\n    }\n\n    // Resolve the service extent (cached); ignore failures and add\n    // the layer without bounds.\n    const bounds = await this._catalog\n      ?.getServiceMetadata(service)\n      .then((metadata) => {\n        this._metadataCache.set(service.fullName, metadata);\n        return extentToBounds(metadata.extent);\n      })\n      .catch(() => null);\n    // The control may have been removed or the layer added while the\n    // metadata request was in flight.\n    if (!this._layerManager) return undefined;\n    const raced = this._layerManager.findLayer(service, sublayerId);\n    if (raced) return raced;\n\n    try {\n      const entry = this._layerManager.addLayer(\n        service,\n        label ?? service.name,\n        sublayerId,\n        clamp(this._options.defaultOpacity, 0, 1),\n        bounds ?? undefined\n      );\n      this._state.addedLayers = this._layerManager.getLayers();\n      this._addedView?.update(this._state.addedLayers);\n      this._showNotice(`Added \"${entry.label}\"`);\n      this._emit('layeradd', { layer: entry });\n      this._emit('statechange');\n      if (this._options.fitBoundsOnAdd && entry.bounds && this._map) {\n        this._map.fitBounds(entry.bounds, { padding: 40 });\n      }\n      return entry;\n    } catch (error) {\n      this._handleError(error instanceof Error ? error : new Error(String(error)));\n      return undefined;\n    }\n  }\n\n  /**\n   * Re-registers layers that were previously added and persisted by a\n   * host application.\n   *\n   * Host applications that save and restore map state (for example a\n   * project file) typically recreate the native MapLibre source and\n   * layer for each persisted {@link AddedLayer} themselves and then need\n   * to hand those layers back to the control so it tracks them again.\n   * This method does exactly that without duplicating the natives: when\n   * the source/layer already exist they are reused (and opacity and\n   * visibility reconciled), otherwise they are created.\n   *\n   * Entries that are already tracked, or that match an existing layer by\n   * service and sublayer, are skipped. Unlike {@link addServiceLayer},\n   * this method never fits the map bounds and shows no notices.\n   *\n   * When the control has not been added to a map yet the entries are\n   * stored and applied automatically in {@link onAdd}.\n   *\n   * @param entries - The persisted added-layer entries to restore\n   */\n  restoreLayers(entries: AddedLayer[]): void {\n    if (!this._layerManager) {\n      this._pendingRestore.push(...entries);\n      return;\n    }\n\n    let restored = false;\n    for (const entry of entries) {\n      if (this._layerManager.findLayer(entry.service, entry.sublayerId)) continue;\n      const layer = this._layerManager.restoreLayer(entry);\n      restored = true;\n      this._emit('layeradd', { layer });\n    }\n\n    if (!restored) return;\n    this._state.addedLayers = this._layerManager.getLayers();\n    this._addedView?.update(this._state.addedLayers);\n    this._emit('statechange');\n  }\n\n  /**\n   * Removes a layer previously added through the control.\n   *\n   * @param id - The added-layer id\n   */\n  removeLayer(id: string): void {\n    const entry = this._layerManager?.removeLayer(id);\n    if (!entry) return;\n    this._state.addedLayers = this._layerManager?.getLayers() ?? [];\n    this._addedView?.update(this._state.addedLayers);\n    this._emit('layerremove', { layer: entry });\n    this._emit('statechange');\n  }\n\n  /**\n   * Sets the opacity of an added layer.\n   *\n   * @param id - The added-layer id\n   * @param opacity - New opacity (0 to 1)\n   */\n  setLayerOpacity(id: string, opacity: number): void {\n    const entry = this._layerManager?.setOpacity(id, clamp(opacity, 0, 1));\n    if (!entry) return;\n    this._state.addedLayers = this._layerManager?.getLayers() ?? [];\n    this._emit('layerchange', { layer: entry });\n    this._emit('statechange');\n  }\n\n  /**\n   * Sets the visibility of an added layer.\n   *\n   * @param id - The added-layer id\n   * @param visible - Whether the layer should be visible\n   */\n  setLayerVisibility(id: string, visible: boolean): void {\n    const entry = this._layerManager?.setVisibility(id, visible);\n    if (!entry) return;\n    this._state.addedLayers = this._layerManager?.getLayers() ?? [];\n    this._emit('layerchange', { layer: entry });\n    this._emit('statechange');\n  }\n\n  /**\n   * Clears the catalog cache and reloads the folder tree.\n   */\n  refreshCatalog(): void {\n    if (!this._catalog || !this._panelView) return;\n    this._catalog.clearCache();\n    this._metadataCache.clear();\n    this._allServices = [];\n    this._prefetchStarted = false;\n\n    const tree = createTreeView(this._treeContext());\n    this._treeView = tree;\n    if (!this._state.query) {\n      this._panelView.browse.replaceChildren(tree.el);\n      tree.load();\n    }\n  }\n\n  /**\n   * Registers an event handler.\n   *\n   * @param event - The event type to listen for\n   * @param handler - The callback function\n   */\n  on(event: EnviroAtlasControlEvent, handler: EnviroAtlasControlEventHandler): void {\n    if (!this._eventHandlers.has(event)) {\n      this._eventHandlers.set(event, new Set());\n    }\n    this._eventHandlers.get(event)!.add(handler);\n  }\n\n  /**\n   * Removes an event handler.\n   *\n   * @param event - The event type\n   * @param handler - The callback function to remove\n   */\n  off(event: EnviroAtlasControlEvent, handler: EnviroAtlasControlEventHandler): void {\n    this._eventHandlers.get(event)?.delete(handler);\n  }\n\n  /**\n   * Gets the map instance.\n   *\n   * @returns The MapLibre GL map instance or undefined if not added to a map\n   */\n  getMap(): MapLibreMap | undefined {\n    return this._map;\n  }\n\n  /**\n   * Gets the control container element.\n   *\n   * @returns The container element or undefined if not added to a map\n   */\n  getContainer(): HTMLElement | undefined {\n    return this._container;\n  }\n\n  /**\n   * Emits an event to all registered handlers.\n   *\n   * @param event - The event type to emit\n   * @param extra - Extra payload (layer or error)\n   */\n  private _emit(event: EnviroAtlasControlEvent, extra?: { layer?: AddedLayer; error?: Error }): void {\n    const handlers = this._eventHandlers.get(event);\n    if (handlers) {\n      const eventData = { type: event, state: this.getState(), ...extra };\n      handlers.forEach((handler) => handler(eventData));\n    }\n  }\n\n  private _handleError(error: Error): void {\n    if (error.name === 'AbortError') return;\n    this._showNotice(error.message, true);\n    this._emit('error', { error });\n  }\n\n  private _showNotice(message: string, isError = false): void {\n    const notice = this._panelView?.notice;\n    if (!notice) return;\n    notice.textContent = message;\n    notice.classList.toggle('enviroatlas-notice-error', isError);\n    notice.hidden = false;\n    if (this._noticeTimer) clearTimeout(this._noticeTimer);\n    this._noticeTimer = setTimeout(() => {\n      notice.hidden = true;\n    }, 4000);\n  }\n\n  /**\n   * Applies the current theme via a data-theme attribute on both the\n   * control container and the floating panel. In 'auto' mode no\n   * attribute is set, letting the prefers-color-scheme media query\n   * drive the palette.\n   */\n  private _applyTheme(): void {\n    for (const element of [this._container, this._panel]) {\n      if (!element) continue;\n      if (this._state.theme === 'auto') {\n        element.removeAttribute('data-theme');\n      } else {\n        element.setAttribute('data-theme', this._state.theme);\n      }\n    }\n  }\n\n  private _treeContext() {\n    return {\n      catalog: this._catalog!,\n      onAdd: (service: ServiceRef, sublayerId?: number, label?: string) =>\n        this.addServiceLayer(service, sublayerId, label),\n      onMetadata: (service: ServiceRef, metadata: ServiceMetadata) => {\n        this._metadataCache.set(service.fullName, metadata);\n      },\n      onError: (error: Error) => this._handleError(error),\n    };\n  }\n\n  /**\n   * Handles (debounced) search input: shows the tree when the query\n   * is empty, otherwise filters the catalog and renders flat results.\n   *\n   * @param query - The raw search query\n   */\n  private _runSearch(query: string): void {\n    if (!this._panelView || !this._catalog || !this._resultsView || !this._treeView) return;\n    this._state.query = query;\n    const epoch = ++this._searchEpoch;\n\n    if (!query.trim()) {\n      this._panelView.browse.replaceChildren(this._treeView.el);\n      this._emit('statechange');\n      return;\n    }\n\n    this._panelView.browse.replaceChildren(this._resultsView.el);\n\n    const renderResults = (note?: string) => {\n      if (epoch !== this._searchEpoch || !this._resultsView) return;\n      const results = filterCatalog(this._state.query, this._allServices, this._metadataCache);\n      this._resultsView.setResults(results, note);\n    };\n\n    if (this._allServices.length === 0) {\n      this._resultsView.setStatus('Loading catalog...');\n    }\n\n    this._catalog\n      .listAllServices()\n      .then((services) => {\n        this._allServices = services;\n        const prefetching = this._startPrefetch(() => renderResults(undefined));\n        renderResults(prefetching ? 'Indexing sublayers...' : undefined);\n      })\n      .catch((error: Error) => this._handleError(error));\n\n    this._emit('statechange');\n  }\n\n  /**\n   * Starts the one-time sublayer metadata prefetch used for deep search.\n   *\n   * @param onUpdate - Called as metadata resolves and when done\n   * @returns True when a prefetch is currently running\n   */\n  private _startPrefetch(onUpdate: () => void): boolean {\n    if (!this._catalog) return false;\n    if (this._prefetchStarted) {\n      return this._metadataCache.size < this._allServices.filter((s) => s.type === 'MapServer').length;\n    }\n    this._prefetchStarted = true;\n\n    const syncCache = () => {\n      for (const service of this._allServices) {\n        if (this._metadataCache.has(service.fullName)) continue;\n        const cached = this._catalog?.getCachedMetadata(service);\n        cached?.then((metadata) => this._metadataCache.set(service.fullName, metadata)).catch(() => undefined);\n      }\n    };\n\n    const refresh = debounce(() => {\n      syncCache();\n      // Allow promises captured in syncCache to settle before rendering\n      setTimeout(onUpdate, 0);\n    }, 300);\n\n    this._catalog\n      .prefetchAllLayers(() => {\n        syncCache();\n        refresh();\n      })\n      .then(() => {\n        syncCache();\n        setTimeout(onUpdate, 0);\n      })\n      .catch((error: Error) => this._handleError(error));\n    return true;\n  }\n\n  /**\n   * Creates the main container element for the control.\n   * Contains a toggle button (29x29) matching navigation control size.\n   *\n   * @returns The container element\n   */\n  private _createContainer(): HTMLElement {\n    const container = document.createElement('div');\n    container.className = `maplibregl-ctrl maplibregl-ctrl-group enviroatlas-control${\n      this._options.className ? ` ${this._options.className}` : ''\n    }`;\n\n    // Create toggle button (29x29 to match navigation control)\n    const toggleBtn = document.createElement('button');\n    toggleBtn.className = 'enviroatlas-toggle';\n    toggleBtn.type = 'button';\n    toggleBtn.setAttribute('aria-label', this._options.title);\n    toggleBtn.title = this._options.title;\n    toggleBtn.innerHTML = `\n      <span class=\"enviroatlas-icon\">\n        <svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n          <path d=\"M12 3a9 9 0 1 0 9 9\"/>\n          <path d=\"M21 3c-5 0-9 4-9 9 5 0 9-4 9-9z\"/>\n          <path d=\"M12 12c0 3 1 6 3 9\"/>\n        </svg>\n      </span>\n    `;\n    toggleBtn.addEventListener('click', () => this.toggle());\n\n    container.appendChild(toggleBtn);\n\n    return container;\n  }\n\n  /**\n   * Creates the panel element with header, search, browse region,\n   * and the added layers section.\n   *\n   * @returns The panel element\n   */\n  private _createPanel(): HTMLElement {\n    const panelView = createPanelView({\n      title: this._options.title,\n      panelWidth: this._options.panelWidth,\n      onClose: () => this.collapse(),\n      onSearchInput: (query) => this._debouncedSearch?.(query),\n    });\n    this._panelView = panelView;\n\n    this._treeView = createTreeView(this._treeContext());\n    panelView.browse.appendChild(this._treeView.el);\n\n    this._resultsView = createResultsView({\n      onAdd: (service, sublayerId, label) => this.addServiceLayer(service, sublayerId, label),\n    });\n\n    this._addedView = createAddedLayersView({\n      catalog: this._catalog!,\n      onVisibilityChange: (id, visible) => this.setLayerVisibility(id, visible),\n      onOpacityChange: (id, opacity) => this.setLayerOpacity(id, opacity),\n      onRemove: (id) => this.removeLayer(id),\n    });\n    panelView.addedSlot.appendChild(this._addedView.el);\n\n    panelView.beforeSelect.addEventListener('change', () => {\n      const value = panelView.beforeSelect.value || undefined;\n      this._options = { ...this._options, beforeId: value ?? '' };\n      this._layerManager?.setBeforeId(value);\n    });\n\n    this._setupResize(panelView);\n\n    return panelView.panel;\n  }\n\n  /**\n   * Populates the \"Insert before\" select with the map's current style\n   * layers, keeping the active selection when still present.\n   */\n  private _refreshBeforeSelect(): void {\n    const select = this._panelView?.beforeSelect;\n    if (!select || !this._map) return;\n\n    let layers: Array<{ id: string }>;\n    try {\n      layers = this._map.getStyle()?.layers ?? [];\n    } catch {\n      layers = [];\n    }\n\n    const current = this._options.beforeId;\n    select.replaceChildren();\n    const top = document.createElement('option');\n    top.value = '';\n    top.textContent = 'Top of map';\n    select.append(top);\n    for (const layer of layers) {\n      // Skip layers added by this control\n      if (layer.id.startsWith('enviroatlas-')) continue;\n      const option = document.createElement('option');\n      option.value = layer.id;\n      option.textContent = layer.id;\n      select.append(option);\n    }\n    select.value = current && layers.some((layer) => layer.id === current) ? current : '';\n  }\n\n  /**\n   * Wires the resize handle: dragging it horizontally adjusts the\n   * panel width. The growth direction follows the panel anchor (a\n   * left-anchored panel grows rightward, a right-anchored panel grows\n   * leftward), so resizing works in every control corner.\n   *\n   * @param panelView - The panel view holding the resizer element\n   */\n  private _setupResize(panelView: PanelView): void {\n    const { resizer, panel } = panelView;\n\n    resizer.addEventListener('pointerdown', (down: PointerEvent) => {\n      down.preventDefault();\n      const startX = down.clientX;\n      const startWidth = panel.getBoundingClientRect().width;\n      // A right-anchored panel (resizer on its left edge) grows as the\n      // pointer moves left; a left-anchored one as it moves right.\n      const rightAnchored = panel.classList.contains('enviroatlas-resize-left');\n      panel.classList.add('enviroatlas-resizing');\n\n      const onMove = (move: PointerEvent) => {\n        const delta = move.clientX - startX;\n        this.setPanelWidth(startWidth + (rightAnchored ? -delta : delta));\n      };\n      const onUp = () => {\n        panel.classList.remove('enviroatlas-resizing');\n        document.removeEventListener('pointermove', onMove);\n        document.removeEventListener('pointerup', onUp);\n        document.removeEventListener('pointercancel', onUp);\n        // The click that follows this pointerup may land outside the\n        // panel; swallow it so the panel does not collapse.\n        this._suppressNextClickOutside = true;\n        setTimeout(() => {\n          this._suppressNextClickOutside = false;\n        }, 0);\n      };\n      document.addEventListener('pointermove', onMove);\n      document.addEventListener('pointerup', onUp);\n      document.addEventListener('pointercancel', onUp);\n    });\n  }\n\n  /**\n   * Setup event listeners for panel positioning and click-outside behavior.\n   */\n  private _setupEventListeners(): void {\n    // Click outside to close (check both container and panel since they're now separate).\n    // The capture-phase listener snapshots the expanded state before any other\n    // handler runs, so a handler that expands the panel during the same click\n    // (e.g. an external \"expand\" button) does not get undone by the bubbling\n    // outside-click handler.\n    this._clickCaptureHandler = () => {\n      this._expandedAtClickStart = !this._state.collapsed;\n    };\n    document.addEventListener('click', this._clickCaptureHandler, true);\n\n    this._clickOutsideHandler = (e: MouseEvent) => {\n      // Releasing a resize drag outside the panel fires a click whose\n      // target is outside; that is not an intent to close.\n      if (this._suppressNextClickOutside) return;\n      const target = e.target as Node;\n      // A target detached mid-dispatch (e.g. a remove button whose row was\n      // re-rendered by its own click handler) cannot be classified as\n      // outside the panel; ignore it.\n      if (!target.isConnected) return;\n      if (\n        this._expandedAtClickStart &&\n        this._container &&\n        this._panel &&\n        !this._container.contains(target) &&\n        !this._panel.contains(target)\n      ) {\n        this.collapse();\n      }\n    };\n    document.addEventListener('click', this._clickOutsideHandler);\n\n    // Update panel position on window resize\n    this._resizeHandler = () => {\n      if (!this._state.collapsed) {\n        this._updatePanelPosition();\n      }\n    };\n    window.addEventListener('resize', this._resizeHandler);\n\n    // Update panel position on map resize (e.g., sidebar toggle)\n    this._mapResizeHandler = () => {\n      if (!this._state.collapsed) {\n        this._updatePanelPosition();\n      }\n    };\n    this._map?.on('resize', this._mapResizeHandler);\n\n    // The EnviroAtlas server intermittently fails tile requests (504s\n    // or responses without CORS headers); keep those out of the console\n    // while preserving MapLibre's default logging for other errors.\n    if (this._options.quietTileErrors) {\n      this._mapErrorHandler = (e) => {\n        const url = (e?.error as { url?: unknown } | undefined)?.url;\n        if (typeof url === 'string' && url.startsWith(this._options.servicesUrl)) {\n          this._emit('error', { error: e.error });\n          return;\n        }\n        // Mimic MapLibre's default behavior for unrelated errors\n        console.error(e?.error);\n      };\n      this._map?.on('error', this._mapErrorHandler);\n    }\n  }\n\n  /**\n   * Detect which corner the control is positioned in.\n   *\n   * @returns The position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n   */\n  private _getControlPosition(): 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' {\n    const parent = this._container?.parentElement;\n    if (!parent) return 'top-right'; // Default\n\n    if (parent.classList.contains('maplibregl-ctrl-top-left')) return 'top-left';\n    if (parent.classList.contains('maplibregl-ctrl-top-right')) return 'top-right';\n    if (parent.classList.contains('maplibregl-ctrl-bottom-left')) return 'bottom-left';\n    if (parent.classList.contains('maplibregl-ctrl-bottom-right')) return 'bottom-right';\n\n    return 'top-right'; // Default\n  }\n\n  /**\n   * Update the panel position based on button location and control corner.\n   * Positions the panel next to the button, expanding in the appropriate\n   * direction, and caps the panel height to the map container so the\n   * content scrolls vertically on small screens.\n   */\n  private _updatePanelPosition(): void {\n    if (!this._container || !this._panel || !this._mapContainer) return;\n\n    // Get the toggle button (first child of container)\n    const button = this._container.querySelector('.enviroatlas-toggle');\n    if (!button) return;\n\n    const buttonRect = button.getBoundingClientRect();\n    const mapRect = this._mapContainer.getBoundingClientRect();\n    const position = this._getControlPosition();\n\n    // Put the resize handle on the panel's free edge: right-anchored\n    // panels (top/bottom-right) resize from their left edge.\n    this._panel.classList.toggle('enviroatlas-resize-left', position.endsWith('right'));\n\n    // Calculate button position relative to map container\n    const buttonTop = buttonRect.top - mapRect.top;\n    const buttonBottom = mapRect.bottom - buttonRect.bottom;\n    const buttonLeft = buttonRect.left - mapRect.left;\n    const buttonRight = mapRect.right - buttonRect.right;\n\n    const panelGap = 5; // Gap between button and panel\n    const edgeMargin = 10; // Minimum distance from the map edge\n\n    // Reset all positioning\n    this._panel.style.top = '';\n    this._panel.style.bottom = '';\n    this._panel.style.left = '';\n    this._panel.style.right = '';\n\n    // Cap the panel height to the space between the button and the\n    // opposite map edge so the content scrolls instead of overflowing.\n    const offset = (position.startsWith('top') ? buttonTop : buttonBottom) + buttonRect.height + panelGap;\n    const maxHeight = Math.max(120, mapRect.height - offset - edgeMargin);\n    this._panel.style.setProperty('--ea-panel-max-h', `${Math.round(maxHeight)}px`);\n    // Cap the panel width to the map width\n    const maxWidth = Math.max(200, mapRect.width - 2 * edgeMargin);\n    this._panel.style.setProperty('--ea-panel-max-w', `${Math.round(maxWidth)}px`);\n\n    switch (position) {\n      case 'top-left':\n        // Panel expands down and to the right\n        this._panel.style.top = `${buttonTop + buttonRect.height + panelGap}px`;\n        this._panel.style.left = `${buttonLeft}px`;\n        break;\n\n      case 'top-right':\n        // Panel expands down and to the left\n        this._panel.style.top = `${buttonTop + buttonRect.height + panelGap}px`;\n        this._panel.style.right = `${buttonRight}px`;\n        break;\n\n      case 'bottom-left':\n        // Panel expands up and to the right\n        this._panel.style.bottom = `${buttonBottom + buttonRect.height + panelGap}px`;\n        this._panel.style.left = `${buttonLeft}px`;\n        break;\n\n      case 'bottom-right':\n        // Panel expands up and to the left\n        this._panel.style.bottom = `${buttonBottom + buttonRect.height + panelGap}px`;\n        this._panel.style.right = `${buttonRight}px`;\n        break;\n    }\n  }\n}\n"],"mappings":"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"}