(() => {
  "use strict";

  const WELCOME_HTML = "Welcome to the dodo: application launcher, think of it as your desktop environment. You can launch applications from left-hand side dock. You should setup VPN clients on your devices, so you can install applications from Application Manager and access your private network. Instructions on how to do that can be viewed by clicking <b>Help</b> button after hovering over <b>Headscale</b> icon in the dock.";
  const POLL_INTERVAL_MS = 5000;
  const SLOW_LOAD_MS = 12000;
  const DOCK_COLLAPSED_KEY = "launcher:dock-collapsed";
  const HELP_WIDTH_KEY = "launcher:help-width:v1";
  const HELP_DEFAULT_WIDTH = 480;
  const HELP_MIN_WIDTH = 320;
  const HELP_MAX_WIDTH = 960;
  const HELP_MIN_WORKSPACE_WIDTH = 360;
  const DESKTOP_DOCK_QUERY = "(min-width: 48rem)";

  const state = {
    activeAppId: null,
    dockCollapsed: false,
    iframes: new Map(),
    signatures: new Map(),
    helpSignatures: new Map(),
    helpOpen: false,
    helpPinned: false,
    helpTargetAppId: null,
    helpOpener: null,
    helpPreferredWidth: HELP_DEFAULT_WIDTH,
    helpEffectiveWidth: HELP_DEFAULT_WIDTH,
    helpResize: null,
    helpControlFocus: null,
    captionAppId: null,
    captionFocusAppId: null,
    suppressedCaptionAppId: null,
    keyboardInput: true,
    polling: false,
  };

  let appList;
  let rightPanel;
  let workspacePane;
  let welcomeFrame;
  let accountButton;
  let dock;
  let dockContent;
  let dockHelpButton;
  let dockToggleButton;
  let dockMediaQuery;
  let captionMediaQuery;
  let workspaceStatus;
  let workspaceStatusMessage;
  let workspaceStatusActions;
  let loadingIndicator;
  let workspaceOpenExternal;
  let helpSidebar;
  let helpContents;
  let helpContentsNav;
  let helpOutlineList;
  let helpDocument;
  let helpPinButton;
  let helpCloseButton;
  let helpResizer;
  let helpResizeObserver;

  function appEntries(root = document) {
    return Array.from(root.querySelectorAll(".app-container"));
  }

  function entryId(entry) {
    return entry.dataset.appId;
  }

  function appButton(entry) {
    return entry.querySelector(".app-button");
  }

  function findAppButton(appId) {
    if (accountButton && accountButton.dataset.appId === appId) {
      return accountButton;
    }
    return Array.from(document.querySelectorAll(".app-button")).find(
      (button) => button.dataset.appId === appId,
    );
  }

  function captionKey(button) {
    return button.dataset.launcherCaption || button.dataset.appId;
  }

  function findCaptionButton(key) {
    return Array.from(document.querySelectorAll("[data-launcher-caption]")).find(
      (button) => captionKey(button) === key,
    );
  }

  function positionAppLabel(button) {
    if (!button || !dockContent.contains(button)) {
      return;
    }
    const label = button.nextElementSibling;
    if (!label || !label.classList.contains("app-label")) {
      return;
    }
    const buttonRect = button.getBoundingClientRect();
    const labelWidth = label.offsetWidth;
    const labelHeight = label.offsetHeight;
    if (dockMediaQuery.matches) {
      const top = Math.min(
        Math.max(buttonRect.top + (buttonRect.height - labelHeight) / 2, 8),
        Math.max(8, window.innerHeight - labelHeight - 8),
      );
      const dockRect = dock.getBoundingClientRect();
      const left = Math.min(
        Math.max(dockRect.right + 8, 8),
        Math.max(8, window.innerWidth - labelWidth - 8),
      );
      label.style.left = `${left}px`;
      label.style.top = `${top}px`;
      return;
    }
    const left = Math.min(
      Math.max(buttonRect.left + (buttonRect.width - labelWidth) / 2, 8),
      Math.max(8, window.innerWidth - labelWidth - 8),
    );
    label.style.left = `${left}px`;
    label.style.top = `${Math.max(8, buttonRect.top - labelHeight - 10)}px`;
  }

  function hideAppLabel(suppress = false) {
    const button = state.captionAppId ? findCaptionButton(state.captionAppId) : null;
    if (suppress && state.captionAppId) {
      state.suppressedCaptionAppId = state.captionAppId;
    }
    if (button) {
      button.classList.remove("is-caption-visible");
    }
    state.captionAppId = null;
    state.captionFocusAppId = null;
  }

  function showAppLabel(button) {
    const appId = captionKey(button);
    if (state.suppressedCaptionAppId === appId) {
      return;
    }
    if (state.suppressedCaptionAppId && state.suppressedCaptionAppId !== appId) {
      state.suppressedCaptionAppId = null;
    }
    if (state.captionAppId !== appId) {
      hideAppLabel();
    }
    positionAppLabel(button);
    button.classList.add("is-caption-visible");
    state.captionAppId = appId;
  }

  function resetCaptionSuppression(button) {
    if (state.suppressedCaptionAppId === captionKey(button)) {
      state.suppressedCaptionAppId = null;
    }
  }

  function clearAppLabelState(appId) {
    if (state.captionAppId === appId) {
      hideAppLabel();
    }
    if (state.suppressedCaptionAppId === appId) {
      state.suppressedCaptionAppId = null;
    }
  }

  function handleAppPointerOver(event) {
    const button = event.target.closest("[data-launcher-caption]");
    if (
      !button ||
      event.pointerType === "touch" ||
      !captionMediaQuery.matches ||
      (event.relatedTarget && button.contains(event.relatedTarget))
    ) {
      return;
    }
    showAppLabel(button);
  }

  function handleAppPointerOut(event) {
    const button = event.target.closest("[data-launcher-caption]");
    if (!button || (event.relatedTarget && button.contains(event.relatedTarget))) {
      return;
    }
    resetCaptionSuppression(button);
    if (document.activeElement !== button && state.captionAppId === captionKey(button)) {
      hideAppLabel();
    }
  }

  function handleAppFocusIn(event) {
    const button = event.target.closest("[data-launcher-caption]");
    if (!button || (!state.keyboardInput && !button.matches(":focus-visible"))) {
      return;
    }
    showAppLabel(button);
    const key = captionKey(button);
    state.captionFocusAppId = key;
    window.requestAnimationFrame(() => {
      window.requestAnimationFrame(() => {
        if (state.captionFocusAppId === key) {
          state.captionFocusAppId = null;
        }
      });
    });
  }

  function handleAppFocusOut(event) {
    const button = event.target.closest("[data-launcher-caption]");
    if (!button || (event.relatedTarget && button.contains(event.relatedTarget))) {
      return;
    }
    resetCaptionSuppression(button);
    if (
      (!captionMediaQuery.matches || !button.matches(":hover")) &&
      state.captionAppId === captionKey(button)
    ) {
      hideAppLabel();
    }
  }

  function handleAppListScroll() {
    const focusedButton = document.activeElement.closest(".app-button");
    if (
      focusedButton &&
      state.captionAppId === captionKey(focusedButton) &&
      state.captionFocusAppId === captionKey(focusedButton)
    ) {
      state.captionFocusAppId = null;
      positionAppLabel(focusedButton);
      return;
    }
    hideAppLabel(true);
  }

  function suppressVisibleAppLabel() {
    hideAppLabel(true);
  }

  function readDockCollapsed() {
    try {
      return window.localStorage.getItem(DOCK_COLLAPSED_KEY) === "true";
    } catch (_) {
      return false;
    }
  }

  function persistDockCollapsed(collapsed) {
    try {
      window.localStorage.setItem(DOCK_COLLAPSED_KEY, String(collapsed));
    } catch (_) {
      // The dock remains usable when storage is unavailable.
    }
  }

  function clamp(value, minimum, maximum) {
    return Math.min(Math.max(value, minimum), maximum);
  }

  function readHelpPreferredWidth() {
    try {
      const stored = window.localStorage.getItem(HELP_WIDTH_KEY);
      if (stored === null || stored.trim() === "") {
        return HELP_DEFAULT_WIDTH;
      }
      const value = Number(stored);
      if (!Number.isFinite(value)) {
        return HELP_DEFAULT_WIDTH;
      }
      return clamp(value, HELP_MIN_WIDTH, HELP_MAX_WIDTH);
    } catch (_) {
      return HELP_DEFAULT_WIDTH;
    }
  }

  function persistHelpPreferredWidth() {
    try {
      window.localStorage.setItem(HELP_WIDTH_KEY, String(state.helpPreferredWidth));
    } catch (_) {
      // Resizing remains available when storage is unavailable.
    }
  }

  function helpAvailableWidth() {
    return rightPanel.getBoundingClientRect().width;
  }

  function helpModeMaximum() {
    const availableWidth = helpAvailableWidth();
    const modeMaximum = state.helpPinned
      ? Math.min(
          HELP_MAX_WIDTH,
          availableWidth * 0.75,
          availableWidth - HELP_MIN_WORKSPACE_WIDTH,
        )
      : Math.min(HELP_MAX_WIDTH, availableWidth * 0.75);
    return Math.max(HELP_MIN_WIDTH, modeMaximum);
  }

  function applyHelpWidth() {
    const maximum = helpModeMaximum();
    state.helpEffectiveWidth = clamp(
      state.helpPreferredWidth,
      HELP_MIN_WIDTH,
      maximum,
    );
    helpSidebar.style.setProperty("--help-sidebar-width", `${state.helpEffectiveWidth}px`);
    helpResizer.setAttribute("aria-valuemin", String(HELP_MIN_WIDTH));
    helpResizer.setAttribute("aria-valuemax", String(Math.round(maximum)));
    helpResizer.setAttribute("aria-valuenow", String(Math.round(state.helpEffectiveWidth)));
  }

  function setExplicitHelpWidth(width) {
    const effective = clamp(width, HELP_MIN_WIDTH, helpModeMaximum());
    state.helpPreferredWidth = effective;
    applyHelpWidth();
    persistHelpPreferredWidth();
  }

  function setDockCollapsed(collapsed, persist = true) {
    endHelpResize();
    state.dockCollapsed = collapsed;
    dock.dataset.collapsed = String(collapsed);
    dockContent.inert = collapsed;
    dockContent.setAttribute("aria-hidden", String(collapsed));
    dockToggleButton.setAttribute("aria-expanded", String(!collapsed));
    dockToggleButton.setAttribute(
      "aria-label",
      collapsed ? "Expand application dock" : "Collapse application dock",
    );
    if (collapsed) {
      const dockOwnedFocus = dockContent.contains(document.activeElement);
      hideAppLabel();
      if (dockOwnedFocus) {
        dockToggleButton.focus();
      }
    }
    if (persist) {
      persistDockCollapsed(collapsed);
    }
  }

  function handleDockBreakpointChange() {
    hideAppLabel();
    syncHelpResponsiveState();
  }

  function writeWelcome() {
    const frameDocument = welcomeFrame.contentDocument;
    frameDocument.open();
    frameDocument.write(WELCOME_HTML);
    frameDocument.close();
    welcomeFrame.style.backgroundColor = "#d6d6d6";
  }

  function helpSectionFor(appId) {
    return Array.from(helpDocument.querySelectorAll(".help-app-section")).find(
      (section) => section.dataset.helpAppId === appId,
    );
  }

  function helpOwners(root = helpDocument) {
    return Array.from(root.querySelectorAll(".help-app-section")).map(
      (section) => section.dataset.helpAppId,
    );
  }

  function helpHeadingFor(appId) {
    const section = helpSectionFor(appId);
    return section ? section.querySelector("h2") : null;
  }

  function focusIsEligible(candidate) {
    if (
      !candidate ||
      !candidate.isConnected ||
      candidate.disabled ||
      candidate.closest("[inert]")
    ) {
      return false;
    }
    const style = window.getComputedStyle(candidate);
    return (
      style.display !== "none" &&
      style.visibility !== "hidden" &&
      candidate.getClientRects().length > 0
    );
  }

  function defaultHelpTarget() {
    if (state.activeAppId && helpSectionFor(state.activeAppId)) {
      return state.activeAppId;
    }
    if (state.helpTargetAppId && helpSectionFor(state.helpTargetAppId)) {
      return state.helpTargetAppId;
    }
    return helpOwners()[0] || null;
  }

  function updateHelpTriggers() {
    dockHelpButton.setAttribute("aria-expanded", String(state.helpOpen));
    document.querySelectorAll('.app-button[aria-controls="help-sidebar"]').forEach((button) => {
      button.setAttribute(
        "aria-expanded",
        String(state.helpOpen && button.dataset.appId === state.helpTargetAppId),
      );
    });
    helpOutlineList.querySelectorAll(".help-app-link").forEach((link) => {
      if (state.helpOpen && link.dataset.helpAppId === state.helpTargetAppId) {
        link.setAttribute("aria-current", "location");
      } else {
        link.removeAttribute("aria-current");
      }
    });
  }

  function projectHelpPinnedState() {
    const pinned = state.helpOpen && state.helpPinned && dockMediaQuery.matches;
    state.helpPinned = pinned;
    helpSidebar.dataset.helpPinned = String(pinned);
    rightPanel.dataset.helpPinned = String(pinned);
    helpPinButton.setAttribute("aria-pressed", String(pinned));
    helpPinButton.setAttribute("aria-label", pinned ? "Unpin Help sidebar" : "Pin Help sidebar");
    updateHelpTriggers();
  }

  function focusHelpResponsiveFallback() {
    const scrollTop = helpDocument.scrollTop;
    const heading = helpHeadingFor(state.helpTargetAppId);
    const candidate = heading || document.getElementById("help-sidebar-title") || helpCloseButton;
    if (candidate) {
      candidate.focus({ preventScroll: true });
      helpDocument.scrollTop = scrollTop;
    }
  }

  function setHelpPinned(pinned) {
    if (!state.helpOpen || !dockMediaQuery.matches || state.helpPinned === pinned) {
      return;
    }
    endHelpResize();
    const documentScrollTop = helpDocument.scrollTop;
    const outlineScrollTop = helpContentsNav.scrollTop;
    if (!pinned && workspacePane.contains(document.activeElement)) {
      focusHelpResponsiveFallback();
    }
    state.helpPinned = pinned;
    projectHelpPinnedState();
    setWorkspaceHelpOverlay(!pinned);
    applyHelpWidth();
    helpDocument.scrollTop = documentScrollTop;
    helpContentsNav.scrollTop = outlineScrollTop;
  }

  function syncHelpResponsiveState() {
    endHelpResize();
    const desktop = dockMediaQuery.matches;
    if (
      !desktop &&
      state.helpOpen &&
      (state.helpControlFocus || workspacePane.contains(document.activeElement))
    ) {
      focusHelpResponsiveFallback();
    }
    helpPinButton.tabIndex = desktop ? 0 : -1;
    helpResizer.tabIndex = desktop ? 0 : -1;
    if (!desktop) {
      state.helpPinned = false;
    }
    projectHelpPinnedState();
    if (state.helpOpen) {
      setWorkspaceHelpOverlay(!state.helpPinned);
    }
    applyHelpWidth();
  }

  function endHelpResize(pointerId = null) {
    const resize = state.helpResize;
    if (!resize || (pointerId !== null && resize.pointerId !== pointerId)) {
      return false;
    }
    state.helpResize = null;
    delete workspacePane.dataset.helpResizing;
    if (helpResizer && helpResizer.hasPointerCapture(resize.pointerId)) {
      helpResizer.releasePointerCapture(resize.pointerId);
    }
    return true;
  }

  function handleHelpResizePointerDown(event) {
    if (!state.helpOpen || !dockMediaQuery.matches || event.button !== 0) {
      return;
    }
    event.preventDefault();
    endHelpResize();
    state.helpResize = {
      pointerId: event.pointerId,
      startX: event.clientX,
      startWidth: state.helpEffectiveWidth,
    };
    workspacePane.dataset.helpResizing = "true";
    helpResizer.setPointerCapture(event.pointerId);
  }

  function handleHelpResizePointerMove(event) {
    const resize = state.helpResize;
    if (!resize || resize.pointerId !== event.pointerId) {
      return;
    }
    event.preventDefault();
    setExplicitHelpWidth(resize.startWidth + resize.startX - event.clientX);
  }

  function handleHelpResizePointerEnd(event) {
    endHelpResize(event.pointerId);
  }

  function handleHelpResizeKeydown(event) {
    if (!state.helpOpen || !dockMediaQuery.matches) {
      return;
    }
    const step = event.shiftKey ? 64 : 16;
    let width = null;
    if (event.key === "ArrowLeft") {
      width = state.helpEffectiveWidth + step;
    } else if (event.key === "ArrowRight") {
      width = state.helpEffectiveWidth - step;
    } else if (event.key === "Home") {
      width = HELP_MIN_WIDTH;
    } else if (event.key === "End") {
      width = helpModeMaximum();
    } else if (event.key === "Enter") {
      width = HELP_DEFAULT_WIDTH;
    }
    if (width === null) {
      return;
    }
    event.preventDefault();
    setExplicitHelpWidth(width);
  }

  function trackHelpControlFocus(event) {
    if (event.target === helpPinButton) {
      state.helpControlFocus = "pin";
    } else if (event.target === helpResizer) {
      state.helpControlFocus = "separator";
    } else {
      state.helpControlFocus = null;
    }
  }

  function setWorkspaceHelpOverlay(open) {
    if (open) {
      workspacePane.inert = true;
      workspacePane.setAttribute("aria-hidden", "true");
      workspacePane.dataset.helpCovered = "true";
      workspaceStatus.setAttribute("aria-live", "off");
      return;
    }
    workspacePane.inert = false;
    workspacePane.removeAttribute("aria-hidden");
    delete workspacePane.dataset.helpCovered;
    workspaceStatus.setAttribute("aria-live", "polite");
  }

  function focusHelpHeading(heading) {
    if (!heading) {
      return;
    }
    heading.focus({ preventScroll: true });
    heading.scrollIntoView({ block: "start" });
  }

  function jumpToHelp(appId, headingId = "", opener = null) {
    const appHeading = helpHeadingFor(appId);
    if (!appHeading) {
      return false;
    }
    const opening = !state.helpOpen;
    if (opening) {
      hideAppLabel();
      state.helpOpener = opener;
      state.helpOpen = true;
      state.helpPinned = false;
      helpSidebar.hidden = false;
      helpSidebar.dataset.helpOpen = "true";
      projectHelpPinnedState();
      applyHelpWidth();
    }
    state.helpTargetAppId = appId;
    updateHelpTriggers();
    const requested = headingId ? document.getElementById(headingId) : null;
    const heading = requested && helpSectionFor(appId).contains(requested) ? requested : appHeading;
    focusHelpHeading(heading);
    if (opening) {
      setWorkspaceHelpOverlay(true);
    }
    if (!dockMediaQuery.matches) {
      helpContents.open = false;
    }
    return true;
  }

  function helpFocusFallback() {
    const ids = [state.helpTargetAppId, state.activeAppId].filter(Boolean);
    for (const id of ids) {
      const button = findAppButton(id);
      if (focusIsEligible(button)) {
        return button;
      }
    }
    for (const candidate of [dockHelpButton, accountButton, dockToggleButton]) {
      if (focusIsEligible(candidate)) {
        return candidate;
      }
    }
    return null;
  }

  function closeHelp(restoreFocus = true) {
    if (!state.helpOpen) {
      return;
    }
    const opener = state.helpOpener;
    endHelpResize();
    setWorkspaceHelpOverlay(false);
    state.helpOpen = false;
    state.helpPinned = false;
    state.helpOpener = null;
    helpSidebar.dataset.helpOpen = "false";
    projectHelpPinnedState();
    helpSidebar.hidden = true;
    applyHelpWidth();
    if (!restoreFocus) {
      return;
    }
    const candidate = focusIsEligible(opener) ? opener : helpFocusFallback();
    if (candidate) {
      candidate.focus();
    }
  }

  function updateDockHelp() {
    const hasHelp = helpOwners().length > 0;
    dockHelpButton.disabled = !hasHelp;
    dockHelpButton.setAttribute("aria-label", hasHelp ? "Open Help" : "Help unavailable");
    updateHelpTriggers();
  }

  function applyActiveState() {
    document.querySelectorAll(".app-button").forEach((button) => {
      const appId = button.dataset.appId;
      const launchable = Boolean(button.dataset.appUrl);
      const active = Boolean(launchable && state.activeAppId === appId);
      const running = Boolean(launchable && !active && state.iframes.has(appId));
      button.classList.toggle("is-active", active);
      button.classList.toggle("is-running", running);
      if (active) {
        button.setAttribute("aria-current", "page");
        button.setAttribute("aria-label", `Open ${button.dataset.appName}, current app`);
      } else {
        button.removeAttribute("aria-current");
        button.setAttribute(
          "aria-label",
          launchable
            ? `Open ${button.dataset.appName}${running ? ", running in background" : ""}`
            : `Open Help for ${button.dataset.appName}`,
        );
      }
    });
    const accountActive = state.activeAppId === accountButton.dataset.appId;
    accountButton.classList.toggle("is-active", accountActive);
    if (accountActive) {
      accountButton.setAttribute("aria-current", "page");
    } else {
      accountButton.removeAttribute("aria-current");
    }
    updateDockHelp();
  }

  function clearRecordTimer(record) {
    if (record.timeoutID !== null) {
      window.clearTimeout(record.timeoutID);
      record.timeoutID = null;
    }
  }

  function renderWorkspaceStatus() {
    const record = state.activeAppId ? state.iframes.get(state.activeAppId) : null;
    if (!record || record.loaded) {
      workspaceStatus.hidden = true;
      workspaceStatus.removeAttribute("data-phase");
      workspaceStatusMessage.textContent = "";
      workspaceStatusActions.hidden = true;
      loadingIndicator.hidden = true;
      workspaceOpenExternal.removeAttribute("href");
      return;
    }

    workspaceStatus.hidden = false;
    workspaceStatus.dataset.phase = record.phase;
    workspaceStatusMessage.textContent =
      record.phase === "slow"
        ? `${record.name} is taking longer than expected`
        : `Loading ${record.name}…`;
    const slow = record.phase === "slow";
    workspaceStatusActions.hidden = !slow;
    loadingIndicator.hidden = slow;
    if (slow) {
      workspaceOpenExternal.href = record.url;
    } else {
      workspaceOpenExternal.removeAttribute("href");
    }
  }

  function markIframeLoaded(record) {
    if (state.iframes.get(record.appId) !== record) {
      return;
    }
    clearRecordTimer(record);
    record.loaded = true;
    record.phase = "loaded";
    if (state.activeAppId === record.appId) {
      renderWorkspaceStatus();
    }
  }

  function startIframeLoad(record) {
    clearRecordTimer(record);
    record.loaded = false;
    record.phase = "loading";
    record.iframe.src = record.url;
    record.timeoutID = window.setTimeout(() => {
      record.timeoutID = null;
      if (state.iframes.get(record.appId) !== record || record.loaded) {
        return;
      }
      record.phase = "slow";
      if (state.activeAppId === record.appId) {
        renderWorkspaceStatus();
      }
    }, SLOW_LOAD_MS);
    if (state.activeAppId === record.appId) {
      renderWorkspaceStatus();
    }
  }

  function showWelcome() {
    state.activeAppId = null;
    welcomeFrame.hidden = false;
    state.iframes.forEach((record) => {
      record.iframe.hidden = true;
    });
    applyActiveState();
    renderWorkspaceStatus();
  }

  function createIframe(button) {
    const appId = button.dataset.appId;
    const iframe = document.createElement("iframe");
    iframe.id = `appFrame-${encodeURIComponent(appId)}`;
    iframe.className = "appFrame";
    iframe.title = `${button.dataset.appName} application`;
    iframe.hidden = true;
    iframe.dataset.appId = appId;
    const record = {
      appId,
      iframe,
      loaded: false,
      phase: "loading",
      timeoutID: null,
      url: button.dataset.appUrl,
      name: button.dataset.appName,
      loadHandler: null,
    };
    record.loadHandler = () => markIframeLoaded(record);
    iframe.addEventListener("load", record.loadHandler);
    state.iframes.set(appId, record);
    startIframeLoad(record);
    workspacePane.appendChild(iframe);
    return record;
  }

  function retireIframe(appId) {
    const record = state.iframes.get(appId);
    if (!record) {
      return;
    }
    clearRecordTimer(record);
    record.iframe.removeEventListener("load", record.loadHandler);
    record.iframe.remove();
    state.iframes.delete(appId);
    if (state.activeAppId === appId) {
      renderWorkspaceStatus();
    }
  }

  function activateApp(button, closeOpenHelp = true) {
    if (!button.dataset.appUrl) {
      jumpToHelp(button.dataset.appId, "", button);
      return;
    }
    if (state.helpOpen && closeOpenHelp && !state.helpPinned) {
      closeHelp(false);
    }
    const appId = button.dataset.appId;
    const record = state.iframes.get(appId) || createIframe(button);
    state.activeAppId = appId;
    welcomeFrame.hidden = true;
    state.iframes.forEach((candidate, candidateId) => {
      candidate.iframe.hidden = candidateId !== appId;
    });
    record.iframe.hidden = false;
    applyActiveState();
    renderWorkspaceStatus();
  }

  function retryActiveIframe() {
    const record = state.activeAppId ? state.iframes.get(state.activeAppId) : null;
    if (!record) {
      return;
    }
    startIframeLoad(record);
  }

  function removalFocusId(removedId, oldIds, incomingIds) {
    const oldIndex = oldIds.indexOf(removedId);
    const survivors = new Set(incomingIds);
    for (let index = oldIndex + 1; index < oldIds.length; index += 1) {
      if (survivors.has(oldIds[index])) {
        return oldIds[index];
      }
    }
    for (let index = oldIndex - 1; index >= 0; index -= 1) {
      if (survivors.has(oldIds[index])) {
        return oldIds[index];
      }
    }
    return null;
  }

  function focusAfterReconcile(request) {
    if (!request) {
      return;
    }
    const target = request.appId ? findAppButton(request.appId) : null;
    if (target) {
      target.focus();
      return;
    }
    if (accountButton) {
      accountButton.focus();
      return;
    }
    dockHelpButton.focus();
  }

  function helpSignature(outline, section) {
    return `${outline ? outline.outerHTML : ""}\n${section ? section.outerHTML : ""}`;
  }

  function firstEligibleDockControl() {
    return (
      Array.from(document.querySelectorAll(".app-button")).find(focusIsEligible) ||
      (focusIsEligible(accountButton) ? accountButton : null) ||
      (focusIsEligible(dockToggleButton) ? dockToggleButton : null)
    );
  }

  function reconcileHelp(snapshot) {
    const {
      incomingSections,
      incomingOutlineById,
      incomingHelpIds: incomingIds,
      incomingHelpSignatures,
      oldOwners,
    } = snapshot;
    const incomingIdSet = new Set(incomingIds);
    const currentSections = new Map(
      Array.from(helpDocument.querySelectorAll(".help-app-section")).map((section) => [
        section.dataset.helpAppId,
        section,
      ]),
    );
    const currentOutlines = new Map(
      Array.from(helpOutlineList.querySelectorAll(".help-outline-app")).map((outline) => [
        outline.dataset.helpAppId,
        outline,
      ]),
    );
    const scrollTop = helpDocument.scrollTop;
    const focusedHeading = document.activeElement.closest(
      ".help-app-section h2, .help-app-section h3, .help-app-section h4, .help-app-section h5, .help-app-section h6",
    );
    const focusedSection = document.activeElement.closest(".help-app-section");
    const focusedOutline = document.activeElement.closest(".help-outline-app");
    const focusedOutlineLink = document.activeElement.closest("a[data-help-heading-id]");
    const focusedOwner = focusedSection
      ? focusedSection.dataset.helpAppId
      : focusedOutline && focusedOutline.dataset.helpAppId;
    const focusedHeadingId = focusedHeading ? focusedHeading.id : "";
    const focusedOutlineHeadingId = focusedOutlineLink
      ? focusedOutlineLink.dataset.helpHeadingId
      : "";
    const outlineScrollTop = helpContentsNav.scrollTop;
    let replacedFocusedOwner = false;

    currentSections.forEach((section, id) => {
      if (incomingIdSet.has(id)) {
        return;
      }
      section.remove();
      const outline = currentOutlines.get(id);
      if (outline) {
        outline.remove();
      }
      state.helpSignatures.delete(id);
      currentSections.delete(id);
      currentOutlines.delete(id);
    });

    incomingSections.forEach((incomingSection, index) => {
      const id = incomingSection.dataset.helpAppId;
      const incomingOutline = incomingOutlineById.get(id);
      const signature = incomingHelpSignatures.get(id);
      let section = currentSections.get(id);
      let outline = currentOutlines.get(id);
      if (!section || !outline) {
        section = document.importNode(incomingSection, true);
        outline = document.importNode(incomingOutline, true);
        currentSections.set(id, section);
        currentOutlines.set(id, outline);
      } else if (state.helpSignatures.get(id) !== signature) {
        const replacementSection = document.importNode(incomingSection, true);
        const replacementOutline = document.importNode(incomingOutline, true);
        if (focusedOwner === id) {
          replacedFocusedOwner = true;
        }
        section.replaceWith(replacementSection);
        outline.replaceWith(replacementOutline);
        section = replacementSection;
        outline = replacementOutline;
        currentSections.set(id, section);
        currentOutlines.set(id, outline);
      }
      state.helpSignatures.set(id, signature);
      if (helpOutlineList.children[index] !== outline) {
        helpOutlineList.insertBefore(outline, helpOutlineList.children[index] || null);
      }
      if (helpDocument.children[index] !== section) {
        helpDocument.insertBefore(section, helpDocument.children[index] || null);
      }
    });

    const targetLost = Boolean(
      state.helpTargetAppId && !incomingIdSet.has(state.helpTargetAppId),
    );
    const focusedOwnerLost = Boolean(focusedOwner && !incomingIdSet.has(focusedOwner));
    if (targetLost) {
      let fallback =
        state.activeAppId && incomingIdSet.has(state.activeAppId) ? state.activeAppId : null;
      const oldIndex = oldOwners.indexOf(state.helpTargetAppId);
      if (!fallback) {
        for (let index = oldIndex + 1; index < oldOwners.length; index += 1) {
          if (incomingIdSet.has(oldOwners[index])) {
            fallback = oldOwners[index];
            break;
          }
        }
      }
      if (!fallback) {
        for (let index = oldIndex - 1; index >= 0; index -= 1) {
          if (incomingIdSet.has(oldOwners[index])) {
            fallback = oldOwners[index];
            break;
          }
        }
      }
      if (!fallback) {
        const wasOpen = state.helpOpen;
        closeHelp(false);
        state.helpTargetAppId = null;
        updateHelpTriggers();
        if (wasOpen) {
          const candidate = firstEligibleDockControl();
          if (candidate) {
            candidate.focus();
          }
        }
      } else {
        state.helpTargetAppId = fallback;
        updateHelpTriggers();
        if (state.helpOpen && focusedOwnerLost) {
          focusHelpHeading(helpHeadingFor(fallback));
        } else {
          helpDocument.scrollTop = scrollTop;
        }
      }
    } else if (
      state.helpOpen &&
      focusedOwnerLost &&
      state.helpTargetAppId &&
      incomingIdSet.has(state.helpTargetAppId)
    ) {
      focusHelpHeading(helpHeadingFor(state.helpTargetAppId));
    } else if (replacedFocusedOwner) {
      const replacementOutline = currentOutlines.get(focusedOwner);
      const replacementLink =
        focusedOutlineHeadingId && replacementOutline
          ? Array.from(replacementOutline.querySelectorAll("a[data-help-heading-id]")).find(
              (link) => link.dataset.helpHeadingId === focusedOutlineHeadingId,
            )
          : null;
      const replacementHeading =
        (focusedOutlineHeadingId && document.getElementById(focusedOutlineHeadingId)) ||
        (focusedHeadingId && document.getElementById(focusedHeadingId)) ||
        helpHeadingFor(focusedOwner);
      if (replacementLink) {
        replacementLink.focus({ preventScroll: true });
      } else if (replacementHeading) {
        replacementHeading.focus({ preventScroll: true });
      }
      helpContentsNav.scrollTop = outlineScrollTop;
      helpDocument.scrollTop = scrollTop;
    } else {
      helpDocument.scrollTop = scrollTop;
    }
    updateDockHelp();
  }

  function keyedOrderChanged(currentIds, incomingIds) {
    return (
      currentIds.length !== incomingIds.length ||
      currentIds.some((id, index) => id !== incomingIds[index])
    );
  }

  function reconciliationSnapshot(parsedDocument) {
    const incomingEntries = appEntries(parsedDocument);
    const incomingIds = incomingEntries.map(entryId);
    const incomingEntrySignatures = new Map(
      incomingEntries.map((entry) => [entryId(entry), entry.outerHTML]),
    );
    const incomingSections = Array.from(parsedDocument.querySelectorAll(".help-app-section"));
    const incomingOutlines = Array.from(parsedDocument.querySelectorAll(".help-outline-app"));
    const incomingOutlineById = new Map(
      incomingOutlines.map((outline) => [outline.dataset.helpAppId, outline]),
    );
    const incomingHelpIds = incomingSections.map((section) => section.dataset.helpAppId);
    const incomingHelpSignatures = new Map(
      incomingSections.map((section) => {
        const id = section.dataset.helpAppId;
        return [id, helpSignature(incomingOutlineById.get(id), section)];
      }),
    );
    const oldEntries = appEntries();
    const oldIds = oldEntries.map(entryId);
    const oldOwners = helpOwners();
    const dockChanged =
      keyedOrderChanged(oldIds, incomingIds) ||
      incomingIds.some((id) => state.signatures.get(id) !== incomingEntrySignatures.get(id));
    const helpChanged =
      keyedOrderChanged(oldOwners, incomingHelpIds) ||
      incomingHelpIds.some(
        (id) => state.helpSignatures.get(id) !== incomingHelpSignatures.get(id),
      );
    return {
      incomingEntries,
      incomingIds,
      incomingEntrySignatures,
      incomingSections,
      incomingOutlineById,
      incomingHelpIds,
      incomingHelpSignatures,
      oldEntries,
      oldIds,
      oldOwners,
      willMutate: dockChanged || helpChanged,
    };
  }

  function reconcileCatalog(parsedDocument) {
    const snapshot = reconciliationSnapshot(parsedDocument);
    if (snapshot.willMutate) {
      endHelpResize();
    }
    const dockHelpHadFocus = document.activeElement === dockHelpButton;
    const { incomingEntries, incomingIds, oldEntries, oldIds } = snapshot;
    const incomingIdSet = new Set(incomingIds);
    const oldById = new Map(oldEntries.map((entry) => [entryId(entry), entry]));
    let focusRequest = null;

    oldEntries.forEach((entry) => {
      const id = entryId(entry);
      if (incomingIdSet.has(id)) {
        return;
      }
      const ownedFocus = entry.contains(document.activeElement);
      const removedActiveApp = state.activeAppId === id;
      if (ownedFocus || (dockHelpHadFocus && removedActiveApp)) {
        focusRequest = { appId: removalFocusId(id, oldIds, incomingIds) };
      }
      clearAppLabelState(id);
      retireIframe(id);
      if (removedActiveApp) {
        showWelcome();
      }
      state.signatures.delete(id);
      entry.remove();
      oldById.delete(id);
    });

    incomingEntries.forEach((incomingEntry, index) => {
      const id = entryId(incomingEntry);
      const incomingSignature = snapshot.incomingEntrySignatures.get(id);
      let currentEntry = oldById.get(id);
      if (!currentEntry) {
        currentEntry = document.importNode(incomingEntry, true);
        state.signatures.set(id, incomingSignature);
      } else if (state.signatures.get(id) !== incomingSignature) {
        const oldButton = appButton(currentEntry);
        const incomingButton = appButton(incomingEntry);
        const ownedFocus = currentEntry.contains(document.activeElement);
        const oldURL = oldButton.dataset.appUrl;
        const newURL = incomingButton.dataset.appUrl;
        const oldName = oldButton.dataset.appName;
        const newName = incomingButton.dataset.appName;
        const losesActiveHelp =
          dockHelpHadFocus &&
          state.activeAppId === id &&
          oldButton.dataset.hasHelp === "true" &&
          incomingButton.dataset.hasHelp !== "true";
        const replacement = document.importNode(incomingEntry, true);
        clearAppLabelState(id);
        currentEntry.replaceWith(replacement);
        currentEntry = replacement;
        state.signatures.set(id, incomingSignature);
        oldById.set(id, replacement);

        const record = state.iframes.get(id);
        if (record && oldName !== newName && oldURL === newURL) {
          record.name = newName;
          record.iframe.title = `${newName} application`;
          if (state.activeAppId === id) {
            renderWorkspaceStatus();
          }
        }
        if (oldURL !== newURL) {
          retireIframe(id);
          if (state.activeAppId === id) {
            if (newURL) {
              activateApp(appButton(replacement), false);
            } else {
              showWelcome();
            }
          }
        }
        if (ownedFocus || losesActiveHelp) {
          focusRequest = { appId: id };
        }
      }
      if (appList.children[index] !== currentEntry) {
        appList.insertBefore(currentEntry, appList.children[index] || null);
      }
    });

    if (state.activeAppId && !findAppButton(state.activeAppId)) {
      showWelcome();
    } else {
      applyActiveState();
    }
    focusAfterReconcile(focusRequest);
    reconcileHelp(snapshot);
  }

  async function pollCatalog() {
    if (state.polling) {
      return;
    }
    state.polling = true;
    try {
      const response = await fetch("/", { cache: "no-store" });
      if (!response.ok) {
        throw new Error(`catalog request failed: ${response.status}`);
      }
      const html = await response.text();
      const parsedDocument = new DOMParser().parseFromString(html, "text/html");
      reconcileCatalog(parsedDocument);
    } catch (_) {
      // Keep the last good catalog and retry on the normal schedule.
    } finally {
      state.polling = false;
      window.setTimeout(pollCatalog, POLL_INTERVAL_MS);
    }
  }

  function handleClick(event) {
    const target = event.target;
    if (
      state.helpOpen &&
      !state.helpPinned &&
      rightPanel.contains(target) &&
      !helpSidebar.contains(target)
    ) {
      closeHelp(true);
      return;
    }
    if (
      state.helpOpen &&
      helpContents.open &&
      helpSidebar.contains(target) &&
      !helpContents.contains(target)
    ) {
      helpContents.open = false;
    }

    const accountTrigger = target.closest("#account-button");
    if (accountTrigger) {
      activateApp(accountTrigger);
      return;
    }

    const dockToggleTrigger = target.closest("#dock-toggle-button");
    if (dockToggleTrigger) {
      setDockCollapsed(!state.dockCollapsed);
      return;
    }

    const appTrigger = target.closest(".app-button");
    if (appTrigger) {
      activateApp(appTrigger);
      return;
    }

    const retryTrigger = target.closest("[data-retry-active-app]");
    if (retryTrigger) {
      retryActiveIframe();
      return;
    }

    const helpTrigger = target.closest("#dock-help-button");
    if (helpTrigger && !helpTrigger.disabled) {
      const targetAppId = defaultHelpTarget();
      if (targetAppId) {
        jumpToHelp(targetAppId, "", helpTrigger);
      }
      return;
    }

    const pinTrigger = target.closest("#help-pin-button");
    if (pinTrigger) {
      setHelpPinned(!state.helpPinned);
      return;
    }

    const contentsLink = target.closest("a[data-help-heading-id]");
    if (contentsLink && helpSidebar.contains(contentsLink)) {
      event.preventDefault();
      jumpToHelp(
        contentsLink.dataset.helpAppId,
        contentsLink.dataset.helpHeadingId,
        contentsLink,
      );
      return;
    }

    if (target.closest("#help-close-button")) {
      closeHelp(true);
    }
  }

  function handlePointerDown() {
    state.keyboardInput = false;
  }

  function handleKeydown(event) {
    state.keyboardInput = true;
    if (event.key !== "Escape") {
      return;
    }
    if (state.captionAppId) {
      suppressVisibleAppLabel();
      return;
    }
    if (state.helpResize) {
      endHelpResize();
      return;
    }
    if (state.helpOpen) {
      closeHelp(true);
    }
  }

  function initialize() {
    appList = document.querySelector(".app-list");
    rightPanel = document.getElementById("right-panel");
    workspacePane = document.getElementById("workspace-pane");
    welcomeFrame = document.getElementById("appFrame-default");
    accountButton = document.getElementById("account-button");
    dock = document.getElementById("left-panel");
    dockContent = document.getElementById("dock-content");
    dockHelpButton = document.getElementById("dock-help-button");
    dockToggleButton = document.getElementById("dock-toggle-button");
    dockMediaQuery = window.matchMedia(DESKTOP_DOCK_QUERY);
    captionMediaQuery = window.matchMedia("(hover: hover) and (pointer: fine)");
    workspaceStatus = document.getElementById("workspace-status");
    workspaceStatusMessage = document.getElementById("workspace-status-message");
    workspaceStatusActions = document.getElementById("workspace-status-actions");
    loadingIndicator = document.getElementById("loading-indicator");
    workspaceOpenExternal = document.getElementById("workspace-open-external");
    helpSidebar = document.getElementById("help-sidebar");
    helpContents = document.getElementById("help-contents");
    helpContentsNav = document.getElementById("help-contents-nav");
    helpOutlineList = document.getElementById("help-outline-list");
    helpDocument = document.getElementById("help-document");
    helpPinButton = document.getElementById("help-pin-button");
    helpCloseButton = document.getElementById("help-close-button");
    helpResizer = document.getElementById("help-resizer");

    state.helpPreferredWidth = readHelpPreferredWidth();
    setDockCollapsed(readDockCollapsed(), false);
    syncHelpResponsiveState();
    appEntries().forEach((entry) => {
      state.signatures.set(entryId(entry), entry.outerHTML);
    });
    helpDocument.querySelectorAll(".help-app-section").forEach((section) => {
      const id = section.dataset.helpAppId;
      const outline = Array.from(helpOutlineList.querySelectorAll(".help-outline-app")).find(
        (candidate) => candidate.dataset.helpAppId === id,
      );
      state.helpSignatures.set(id, helpSignature(outline, section));
    });
    writeWelcome();
    applyActiveState();

    document.addEventListener("click", handleClick);
    document.addEventListener("pointerdown", handlePointerDown);
    document.addEventListener("keydown", handleKeydown);
    document.addEventListener("focusin", trackHelpControlFocus);
    dockContent.addEventListener("pointerover", handleAppPointerOver);
    dockContent.addEventListener("pointerout", handleAppPointerOut);
    dockContent.addEventListener("focusin", handleAppFocusIn);
    dockContent.addEventListener("focusout", handleAppFocusOut);
    appList.addEventListener("scroll", handleAppListScroll);
    helpResizer.addEventListener("pointerdown", handleHelpResizePointerDown);
    helpResizer.addEventListener("pointermove", handleHelpResizePointerMove);
    helpResizer.addEventListener("pointerup", handleHelpResizePointerEnd);
    helpResizer.addEventListener("pointercancel", handleHelpResizePointerEnd);
    helpResizer.addEventListener("keydown", handleHelpResizeKeydown);
    dockMediaQuery.addEventListener("change", handleDockBreakpointChange);
    helpResizeObserver = new ResizeObserver(() => applyHelpWidth());
    helpResizeObserver.observe(rightPanel);
    window.addEventListener("blur", () => endHelpResize());
    window.setTimeout(pollCatalog, POLL_INTERVAL_MS);
  }

  document.addEventListener("DOMContentLoaded", initialize, { once: true });
})();
