(() => {
  const PAGE_SIZE = 10;

  const ICONS = {
    map: `<svg class="mapsMirMapIcon" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true"><rect x="2" y="2" width="14" height="14" rx="1" fill="none" stroke="currentColor" stroke-width="1.2"/><path d="M2 6h14M6 2v14M12 2v14" stroke="currentColor" stroke-width=".8" opacity=".5"/></svg>`,
    edit: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M9.5 2.5l2 2L5 11H3v-2L9.5 2.5z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>`,
    view: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z" fill="none" stroke="currentColor" stroke-width="1.2"/><circle cx="7" cy="7" r="1.8" fill="none" stroke="currentColor" stroke-width="1.2"/></svg>`,
    delete: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M3 4h8M5 4V2.5h4V4M5.5 6v4M8.5 6v4M4.5 4l.5 7.5h4L9.5 4" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
    active: `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><path d="M2 5l2.2 2.2L8 3.5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
  };

  const el = (id) => document.getElementById(id);
  const t = (key, vars) => window.I18n?.t(key, vars) ?? key;

  const listViewEl = el("mapsListView");
  const createViewEl = el("mapsCreateView");
  const editorViewEl = el("mapEditorView");
  const listEl = el("mapsList");
  const listEmptyEl = el("mapsListEmpty");
  const tableEl = el("mapsTable");
  const activeHintEl = el("mapsActiveHint");
  const filterInputEl = el("mapsFilterInput");
  const filterCountEl = el("mapsFilterCount");
  const pageLabelEl = el("mapsPageLabel");
  const sitesDialogEl = el("mapsSitesDialog");
  const sitesListEl = el("mapsSitesList");
  const siteFormDialogEl = el("mapsSiteFormDialog");
  const deleteDialogEl = el("mapsDeleteDialog");
  const createSiteSelectEl = el("mapsCreateSite");

  let deleteDialogResolve = null;

  const SITE_ICONS = {
    chevron: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M4 3l3 4-3 4M8 3l3 4-3 4" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
    edit: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M9.5 2.5l2 2L5 11H3v-2L9.5 2.5z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>`,
    delete: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M4 4l6 6M10 4l-6 6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>`,
  };

  const store = {
    maps: [],
    sites: [],
    activeMapId: null,
    filter: "",
    page: 1,
    editingSiteId: null,
    sitesDialogSelectedId: null,
    sitesDialogSnapshotId: null,
  };

  function canWrite() {
    return window.AuthApp?.canWrite?.("maps") ?? true;
  }

  function currentUser() {
    return window.AuthApp?.getUser?.() || null;
  }

  function canDeleteMap(map) {
    if (!canWrite() || !map) return false;
    const user = currentUser();
    if (!user) return true;
    const mapGroup = map.created_by_group;
    if (mapGroup) return mapGroup === user.group_id;
    return true;
  }

  function escapeHtml(str) {
    return String(str)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  async function api(path, opts = {}) {
    const res = await fetch(path, { credentials: "include", ...opts });
    if (!res.ok) {
      let msg = res.statusText;
      try {
        const err = await res.json();
        if (err.error) msg = err.error;
      } catch {
        /* ignore */
      }
      throw new Error(msg);
    }
    if (res.status === 204) return null;
    return res.json();
  }

  function findMap(id) {
    return store.maps.find((m) => m.id === id) || null;
  }

  function findSite(id) {
    return store.sites.find((s) => s.id === id) || null;
  }

  function siteName(siteId) {
    return findSite(siteId)?.name || siteId || "—";
  }

  function mapImageUrl(map) {
    if (!map?.id || !map.image_file) return null;
    return `/api/maps/${encodeURIComponent(map.id)}/image?t=${encodeURIComponent(map.updated_at || "")}`;
  }

  function filteredMaps() {
    const q = store.filter.trim().toLowerCase();
    let items = [...store.maps].sort((a, b) => {
      const sa = siteName(a.site_id).localeCompare(siteName(b.site_id));
      if (sa !== 0) return sa;
      return (a.name || "").localeCompare(b.name || "");
    });
    if (q) {
      items = items.filter((m) => {
        const name = (m.name || "").toLowerCase();
        const site = siteName(m.site_id).toLowerCase();
        return name.includes(q) || site.includes(q);
      });
    }
    return items;
  }

  function pageCount(total) {
    return Math.max(1, Math.ceil(total / PAGE_SIZE));
  }

  function pagedMaps(items) {
    const totalPages = pageCount(items.length);
    if (store.page > totalPages) store.page = totalPages;
    if (store.page < 1) store.page = 1;
    const start = (store.page - 1) * PAGE_SIZE;
    return items.slice(start, start + PAGE_SIZE);
  }

  function updatePagerUi(totalItems) {
    const totalPages = pageCount(totalItems);
    if (filterCountEl) {
      filterCountEl.textContent = t("maps.itemsFound", { n: totalItems });
    }
    if (pageLabelEl) {
      pageLabelEl.textContent = t("maps.pageOf", { page: store.page, total: totalPages });
    }
    const atStart = store.page <= 1;
    const atEnd = store.page >= totalPages;
    el("mapsPageFirst")?.toggleAttribute("disabled", atStart);
    el("mapsPagePrev")?.toggleAttribute("disabled", atStart);
    el("mapsPageNext")?.toggleAttribute("disabled", atEnd);
    el("mapsPageLast")?.toggleAttribute("disabled", atEnd);
  }

  async function loadSites() {
    const data = await api("/api/sites");
    store.sites = Array.isArray(data.sites) ? data.sites : [];
  }

  async function loadMaps() {
    const data = await api("/api/maps");
    store.maps = Array.isArray(data.maps) ? data.maps : [];
  }

  async function loadActiveMap() {
    try {
      const status = await api("/api/robot/status");
      store.activeMapId = status.active_map_id || null;
    } catch {
      store.activeMapId = null;
    }
  }

  function renderActiveHint() {
    if (!activeHintEl) return;
    const active = findMap(store.activeMapId);
    if (active) {
      activeHintEl.hidden = false;
      activeHintEl.textContent = t("maps.activeHint", { name: active.name });
    } else {
      activeHintEl.hidden = true;
      activeHintEl.textContent = "";
    }
  }

  function renderSiteSelect(selectedId) {
    if (!createSiteSelectEl) return;
    createSiteSelectEl.innerHTML = "";
    store.sites.forEach((site) => {
      const opt = document.createElement("option");
      opt.value = site.id;
      opt.textContent = site.name || site.id;
      createSiteSelectEl.appendChild(opt);
    });
    if (selectedId) createSiteSelectEl.value = selectedId;
    else if (store.sites[0]) createSiteSelectEl.value = store.sites[0].id;
  }

  function renderList() {
    if (!listEl) return;
    const items = filteredMaps();
    const pageItems = pagedMaps(items);
    updatePagerUi(items.length);

    listEl.innerHTML = "";
    const showEmpty = items.length === 0;
    if (tableEl) tableEl.hidden = showEmpty;
    if (listEmptyEl) {
      listEmptyEl.hidden = !showEmpty;
      listEmptyEl.textContent = store.filter.trim() ? t("maps.emptyFilter") : t("maps.empty");
    }

    let lastSiteId = null;
    pageItems.forEach((map) => {
      const siteId = map.site_id || "";
      if (siteId !== lastSiteId) {
        lastSiteId = siteId;
        const siteTr = document.createElement("tr");
        siteTr.className = "mapsMirSiteRow";
        siteTr.innerHTML = `<td colspan="3">${escapeHtml(siteName(siteId))}</td>`;
        listEl.appendChild(siteTr);
      }

      const isActive = map.id === store.activeMapId;
      const tr = document.createElement("tr");
      tr.className = "mapsMirRow";
      tr.dataset.mapId = map.id;

      const activeBadge = isActive
        ? `<span class="mapsActiveBadge">${ICONS.active}<span>${escapeHtml(t("maps.activeBadge"))}</span></span>`
        : "";

      const actions = canWrite()
        ? `<div class="mapsMirRowActions">
            <button type="button" class="mapsMirIconBtn" data-edit="${map.id}" data-i18n-title="common.edit" title="${escapeHtml(t("common.edit"))}">${ICONS.edit}</button>
            <button type="button" class="mapsMirIconBtn" data-view="${map.id}" data-i18n-title="maps.view" title="${escapeHtml(t("maps.view"))}">${ICONS.view}</button>
            ${canDeleteMap(map) ? `<button type="button" class="mapsMirIconBtn mapsMirIconBtn--danger" data-delete="${map.id}" data-i18n-title="common.delete" title="${escapeHtml(t("common.delete"))}">${ICONS.delete}</button>` : ""}
          </div>`
        : `<div class="mapsMirRowActions">
            <button type="button" class="mapsMirIconBtn" data-view="${map.id}" data-i18n-title="maps.view" title="${escapeHtml(t("maps.view"))}">${ICONS.view}</button>
          </div>`;

      tr.innerHTML = `
        <td class="mapsMirCellName">
          <div class="mapsMirNameCell">
            ${ICONS.map}
            <button type="button" class="mapsMirNameLink" data-open="${map.id}">${escapeHtml(map.name || map.id)}</button>
            ${activeBadge}
          </div>
        </td>
        <td class="mapsMirCellCreatedBy">${escapeHtml(map.created_by || "—")}</td>
        <td class="mapsMirCellActions">${actions}</td>`;

      tr.querySelector("[data-open]")?.addEventListener("click", () => openEditor(map.id));
      tr.querySelector("[data-edit]")?.addEventListener("click", () => openEditor(map.id));
      tr.querySelector("[data-view]")?.addEventListener("click", () => openEditor(map.id, { readOnly: !canWrite() }));
      tr.querySelector("[data-delete]")?.addEventListener("click", () => {
        void deleteMapFromList(map.id);
      });
      tr.addEventListener("dblclick", () => openEditor(map.id));
      listEl.appendChild(tr);
    });
    renderActiveHint();
  }

  function hideAllViews() {
    [listViewEl, createViewEl, editorViewEl].forEach((view) => {
      if (!view) return;
      view.hidden = true;
      view.setAttribute("aria-hidden", "true");
    });
  }

  function showList() {
    hideAllViews();
    if (listViewEl) {
      listViewEl.hidden = false;
      listViewEl.removeAttribute("aria-hidden");
    }
    window.MapEditorApp?.close?.();
  }

  function showCreate() {
    if (!canWrite()) return;
    hideAllViews();
    renderSiteSelect();
    const nameEl = el("mapsCreateName");
    if (nameEl) nameEl.value = "";
    if (createViewEl) {
      createViewEl.hidden = false;
      createViewEl.removeAttribute("aria-hidden");
    }
    nameEl?.focus();
  }

  function openEditor(mapId, opts = {}) {
    const map = findMap(mapId);
    if (!map) return;
    hideAllViews();
    if (editorViewEl) {
      editorViewEl.hidden = false;
      editorViewEl.removeAttribute("aria-hidden");
    }
    window.MapEditorApp?.open?.(mapId, {
      readOnly: opts.readOnly,
      pathPreview: opts.pathPreview || null,
      onMapUpdated: (updated) => {
        const idx = store.maps.findIndex((m) => m.id === updated.id);
        if (idx >= 0) store.maps[idx] = updated;
        else store.maps.push(updated);
      },
      onMapDeleted: (id) => {
        store.maps = store.maps.filter((m) => m.id !== id);
        if (store.activeMapId === id) store.activeMapId = null;
        showList();
        renderList();
      },
      onActivated: (id) => {
        store.activeMapId = id;
        renderList();
      },
      onClose: () => {
        showList();
        renderList();
      },
      getSiteName: siteName,
      getActiveMapId: () => store.activeMapId,
      canWrite: canWrite(),
    });
  }

  function openEditorWithPath(path) {
    if (!path?.map_id) return;
    openEditor(path.map_id, {
      readOnly: !canWrite(),
      pathPreview: {
        points: Array.isArray(path.points) ? path.points : [],
        fromPositionId: path.from_position_id,
        toPositionId: path.to_position_id,
      },
    });
  }

  function confirmDeleteMap(map) {
    return new Promise((resolve) => {
      deleteDialogResolve = resolve;
      const textEl = el("mapsDeleteDialogText");
      const activeWarnEl = el("mapsDeleteDialogActiveWarn");
      if (textEl) textEl.textContent = t("maps.deleteDialog.text", { name: map.name || map.id });
      if (activeWarnEl) {
        const isActive = map.id === store.activeMapId;
        activeWarnEl.hidden = !isActive;
        if (isActive) activeWarnEl.textContent = t("maps.deleteDialog.activeWarning");
      }
      deleteDialogEl?.showModal();
    });
  }

  async function deleteMapFromList(mapId) {
    const map = findMap(mapId);
    if (!map || !canDeleteMap(map)) return;
    if (!(await confirmDeleteMap(map))) return;
    try {
      await api(`/api/maps/${encodeURIComponent(map.id)}`, { method: "DELETE" });
    } catch (e) {
      alert(e.message || t("maps.deleteForbidden"));
      return;
    }
    store.maps = store.maps.filter((m) => m.id !== map.id);
    if (store.activeMapId === map.id) store.activeMapId = null;
    renderList();
  }

  async function activateMap(mapId) {
    const map = findMap(mapId);
    if (!map) return;
    if (!map.image_file) {
      alert(t("maps.error.noImage"));
      return;
    }
    await api("/api/robot/active_map", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ map_id: mapId }),
    });
    store.activeMapId = mapId;
    renderList();
  }

  function openCreatePage() {
    showCreate();
  }

  function renderSitesDialogList() {
    if (!sitesListEl) return;
    sitesListEl.innerHTML = "";
    if (store.sites.length === 0) {
      const empty = document.createElement("li");
      empty.className = "mapsMirSitesEmpty";
      empty.textContent = t("maps.sitesDialog.empty");
      sitesListEl.appendChild(empty);
      return;
    }
    store.sites.forEach((site) => {
      const li = document.createElement("li");
      li.className = "mapsMirSitesItem";
      if (site.id === store.sitesDialogSelectedId) li.classList.add("is-selected");
      li.dataset.siteId = site.id;
      li.innerHTML = `
        <button type="button" class="mapsMirSitesItemMain" data-select-site="${site.id}">
          <span class="mapsMirSitesChevron">${SITE_ICONS.chevron}</span>
          <span class="mapsMirSitesItemName">${escapeHtml(site.name || site.id)}</span>
        </button>
        <div class="mapsMirSitesItemActions">
          <button type="button" class="mapsMirSitesIconBtn" data-edit-site="${site.id}" data-i18n-title="common.edit" title="${escapeHtml(t("common.edit"))}">${SITE_ICONS.edit}</button>
          <button type="button" class="mapsMirSitesIconBtn mapsMirSitesIconBtn--danger" data-delete-site="${site.id}" data-i18n-title="common.delete" title="${escapeHtml(t("common.delete"))}">${SITE_ICONS.delete}</button>
        </div>`;
      li.querySelector("[data-select-site]")?.addEventListener("click", () => {
        store.sitesDialogSelectedId = site.id;
        renderSitesDialogList();
      });
      li.querySelector("[data-edit-site]")?.addEventListener("click", (evt) => {
        evt.stopPropagation();
        openSiteFormDialog(site.id);
      });
      li.querySelector("[data-delete-site]")?.addEventListener("click", (evt) => {
        evt.stopPropagation();
        void deleteSite(site.id);
      });
      sitesListEl.appendChild(li);
    });
  }

  async function openSitesDialog() {
    await loadSites();
    store.sitesDialogSnapshotId = createSiteSelectEl?.value || store.sites[0]?.id || null;
    store.sitesDialogSelectedId = store.sitesDialogSnapshotId;
    renderSitesDialogList();
    sitesDialogEl?.showModal();
  }

  function closeSitesDialog(apply) {
    if (apply && store.sitesDialogSelectedId) {
      renderSiteSelect(store.sitesDialogSelectedId);
    }
    sitesDialogEl?.close();
  }

  function openSiteFormDialog(siteId) {
    store.editingSiteId = siteId || null;
    const site = siteId ? findSite(siteId) : null;
    const titleEl = el("mapsSiteFormTitle");
    const nameEl = el("mapsSiteName");
    if (titleEl) {
      titleEl.textContent = site ? t("maps.siteForm.edit") : t("maps.siteForm.create");
    }
    if (nameEl) nameEl.value = site?.name || "";
    siteFormDialogEl?.showModal();
    nameEl?.focus();
  }

  async function saveSite(evt) {
    evt.preventDefault();
    const name = el("mapsSiteName")?.value.trim();
    if (!name) return;
    if (store.editingSiteId) {
      const updated = await api(`/api/sites/${encodeURIComponent(store.editingSiteId)}`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name }),
      });
      const idx = store.sites.findIndex((s) => s.id === store.editingSiteId);
      if (idx >= 0) store.sites[idx] = updated;
    } else {
      const created = await api("/api/sites", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name }),
      });
      store.sites.push(created);
      store.sitesDialogSelectedId = created.id;
    }
    siteFormDialogEl?.close();
    renderSitesDialogList();
    renderList();
  }

  async function deleteSite(siteId) {
    const site = findSite(siteId);
    if (!site) return;
    if (!confirm(t("maps.sitesDialog.deleteConfirm", { name: site.name }))) return;
    try {
      await api(`/api/sites/${encodeURIComponent(siteId)}`, { method: "DELETE" });
    } catch (e) {
      alert(e.message);
      return;
    }
    store.sites = store.sites.filter((s) => s.id !== siteId);
    if (store.sitesDialogSelectedId === siteId) {
      store.sitesDialogSelectedId = store.sites[0]?.id || null;
    }
    renderSitesDialogList();
    renderList();
  }

  async function createMap(evt) {
    evt.preventDefault();
    const name = el("mapsCreateName")?.value.trim();
    const site_id = createSiteSelectEl?.value;
    if (!name || !site_id) return;
    const user = window.AuthApp?.getUser?.();
    const created = await api("/api/maps", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        name,
        site_id,
        created_by: user?.display_name || user?.username || "",
        created_by_user: user?.id || "",
        created_by_group: user?.group_id || "",
        resolution: 0.05,
        origin_x: 0,
        origin_y: 0,
        origin_yaw: 0,
      }),
    });
    store.maps.push(created);
    store.filter = "";
    if (filterInputEl) filterInputEl.value = "";
    store.page = 1;
    renderList();
    openEditor(created.id);
  }

  function clearFilters() {
    store.filter = "";
    store.page = 1;
    if (filterInputEl) filterInputEl.value = "";
    renderList();
  }

  function goToPage(page) {
    const total = pageCount(filteredMaps().length);
    store.page = Math.min(Math.max(1, page), total);
    renderList();
  }

  async function importSiteBundle() {
    const site_id = createSiteSelectEl?.value || store.sites[0]?.id;
    if (!site_id) {
      alert(t("maps.importNoSite"));
      return;
    }
    const input = document.createElement("input");
    input.type = "file";
    input.accept = ".json,application/json";
    input.addEventListener("change", async () => {
      const file = input.files?.[0];
      if (!file) return;
      try {
        const text = await file.text();
        const result = await api(`/api/sites/${encodeURIComponent(site_id)}/import`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: text,
        });
        await loadMaps();
        const counts = [
          Array.isArray(result.maps) ? result.maps.length : 0,
          Array.isArray(result.io_modules) ? result.io_modules.length : 0,
          Array.isArray(result.transitions) ? result.transitions.length : 0,
          Array.isArray(result.paths) ? result.paths.length : 0,
        ];
        alert(
          t("maps.importSuccess", {
            maps: counts[0],
            io: counts[1],
            transitions: counts[2],
            paths: counts[3],
          }),
        );
      } catch (e) {
        alert(e.message);
      }
    });
    input.click();
  }

  function bindEvents() {
    el("mapsCreateOpenBtn")?.addEventListener("click", openCreatePage);
    el("mapsCreateGoBackBtn")?.addEventListener("click", showList);
    el("mapsCreateCancelBtn")?.addEventListener("click", showList);
    el("mapsCreateHelpBtn")?.addEventListener("click", () => alert(t("maps.createPage.helpText")));
    el("mapsImportSiteBtn")?.addEventListener("click", () => importSiteBundle().catch((e) => alert(e.message)));
    el("mapsClearFiltersBtn")?.addEventListener("click", clearFilters);
    el("mapsHelpBtn")?.addEventListener("click", () => alert(t("maps.helpText")));

    filterInputEl?.addEventListener("input", () => {
      store.filter = filterInputEl.value;
      store.page = 1;
      renderList();
    });

    el("mapsPageFirst")?.addEventListener("click", () => goToPage(1));
    el("mapsPagePrev")?.addEventListener("click", () => goToPage(store.page - 1));
    el("mapsPageNext")?.addEventListener("click", () => goToPage(store.page + 1));
    el("mapsPageLast")?.addEventListener("click", () => goToPage(pageCount(filteredMaps().length)));

    el("mapsCreateForm")?.addEventListener("submit", (evt) => {
      createMap(evt).catch((e) => alert(e.message));
    });
    el("mapsDeleteYesBtn")?.addEventListener("click", () => {
      deleteDialogEl?.close();
      deleteDialogResolve?.(true);
      deleteDialogResolve = null;
    });
    el("mapsDeleteNoBtn")?.addEventListener("click", () => {
      deleteDialogEl?.close();
      deleteDialogResolve?.(false);
      deleteDialogResolve = null;
    });
    deleteDialogEl?.addEventListener("cancel", (evt) => {
      evt.preventDefault();
      deleteDialogEl.close();
      deleteDialogResolve?.(false);
      deleteDialogResolve = null;
    });
    el("mapsSiteForm")?.addEventListener("submit", (evt) => {
      saveSite(evt).catch((e) => alert(e.message));
    });
    el("mapsCreateSiteBtn")?.addEventListener("click", () => {
      openSitesDialog().catch((e) => alert(e.message));
    });
    el("mapsSitesCreateBtn")?.addEventListener("click", () => openSiteFormDialog(null));
    el("mapsSitesOkBtn")?.addEventListener("click", () => closeSitesDialog(true));
    el("mapsSitesCancelBtn")?.addEventListener("click", () => closeSitesDialog(false));
    sitesDialogEl?.addEventListener("cancel", (evt) => {
      evt.preventDefault();
      closeSitesDialog(false);
    });

    document.querySelectorAll("[data-close-dialog]").forEach((btn) => {
      btn.addEventListener("click", () => {
        const id = btn.getAttribute("data-close-dialog");
        el(id)?.close();
      });
    });
  }

  function applyReadOnly() {
    document.body.classList.toggle("auth-readonly-maps-page", !canWrite());
  }

  async function refresh() {
    await Promise.all([loadSites(), loadMaps(), loadActiveMap()]);
    renderList();
  }

  async function init() {
    applyReadOnly();
    showList();
    bindEvents();
    try {
      await refresh();
    } catch (e) {
      if (listEmptyEl) {
        listEmptyEl.hidden = false;
        listEmptyEl.textContent = t("common.error", { msg: e.message });
      }
      if (tableEl) tableEl.hidden = true;
    }
  }

  window.MapsApp = {
    init,
    refresh,
    onPageShow() {
      applyReadOnly();
      showList();
      refresh().catch(() => {});
    },
    getMaps: () => [...store.maps],
    getMapById: findMap,
    activateMap,
    openEditorWithPath,
  };

  function boot() {
    init();
  }

  if (window.AuthApp?.isReady()) boot();
  else window.addEventListener("lm:auth-ready", boot, { once: true });
  window.addEventListener("lm:locale-change", () => {
    renderList();
    renderActiveHint();
  });
})();
