(() => {
  "use strict";
  const bridge = window.chrome && window.chrome.webview ? window.chrome.webview : null;
  let settings = null;
  let dirty = false;
  let forcedDark = false; // true in incognito — the page stays dark regardless of settings.data

  // ---- Monochrome Lucide figures (stroke icons, currentColor) ----
  const FIG = {
    sun: "M 12 2 L 12 4 M 12 20 L 12 22 M 4.93 4.93 L 6.34 6.34 M 17.66 17.66 L 19.07 19.07 M 2 12 L 4 12 M 20 12 L 22 12 M 6.34 17.66 L 4.93 19.07 M 19.07 4.93 L 17.66 6.34 M 8,12 A 4,4 0 1 0 16,12 A 4,4 0 1 0 8,12 Z",
    search: "M 21 21 L 16.66 16.66 M 3,11 A 8,8 0 1 0 19,11 A 8,8 0 1 0 3,11 Z",
    home: "M 15 21 L 15 13 A 1 1 0 0 0 14 12 L 10 12 A 1 1 0 0 0 9 13 L 9 21 M 3 10 A 2 2 0 0 1 3.709 8.472 L 10.709 2.472 A 2 2 0 0 1 13.291 2.472 L 20.291 8.472 A 2 2 0 0 1 21 10 L 21 19 A 2 2 0 0 1 19 21 L 5 21 A 2 2 0 0 1 3 19 Z",
    shield: "M 20 13 C 20 18 16.5 20.5 12.34 21.95 A 1 1 0 0 1 11.67 21.94 C 7.5 20.5 4 18 4 13 L 4 6 A 1 1 0 0 1 5 5 C 7 5 9.5 3.8 11.24 2.28 A 1.17 1.17 0 0 1 12.76 2.28 C 14.51 3.81 17 5 19 5 A 1 1 0 0 1 20 6 Z",
    zap: "M 15.914 4 A 1.5 1.5 0 0 0 13.44 2.439 L 4.44 11.439 A 1.5 1.5 0 0 0 5.5 14 L 9.502 14 A 0.5 0.5 0 0 1 9.973 14.666 L 8.086 20 A 1.5 1.5 0 0 0 10.561 21.56 L 19.561 12.56 A 1.5 1.5 0 0 0 18.5 10 L 14.503 10 A 0.5 0.5 0 0 1 14.031 9.333 Z",
    star: "M 11.525 2.295 A 0.53 0.53 0 0 1 12.475 2.295 L 14.785 6.974 A 2.123 2.123 0 0 0 16.38 8.134 L 21.546 8.89 A 0.53 0.53 0 0 1 21.84 9.794 L 18.104 13.432 A 2.123 2.123 0 0 0 17.493 15.31 L 18.375 20.45 A 0.53 0.53 0 0 1 17.604 21.01 L 12.986 18.582 A 2.122 2.122 0 0 0 11.013 18.582 L 6.396 21.01 A 0.53 0.53 0 0 1 5.626 20.45 L 6.507 15.311 A 2.122 2.122 0 0 0 5.896 13.432 L 2.16 9.795 A 0.53 0.53 0 0 1 2.454 8.889 L 7.619 8.134 A 2.122 2.122 0 0 0 9.216 6.974 Z",
    clock: "M 12 6 L 12 12 L 16 14 M 2,12 A 10,10 0 1 0 22,12 A 10,10 0 1 0 2,12 Z",
    key: "M 21 2 L 19 4 M 11.39 9.61 A 5.5 5.5 0 1 0 3.612 17.388 A 5.5 5.5 0 0 0 11.389 9.611 Z M 11.39 9.61 L 15.5 7.5 M 15.5 7.5 L 18.5 10.5 L 22 7 L 19 4 M 15.5 7.5 L 19 4",
    download: "M 12 15 L 12 3 M 21 15 L 21 19 A 2 2 0 0 1 19 21 L 5 21 A 2 2 0 0 1 3 19 L 3 15 M 7 10 L 12 15 L 17 10",
    globe: "M 12 2 A 14.5 14.5 0 0 0 12 22 A 14.5 14.5 0 0 0 12 2 M 2 12 L 22 12 M 2,12 A 10,10 0 1 0 22,12 A 10,10 0 1 0 2,12 Z",
    info: "M 12 16 L 12 12 M 12 8 L 12.01 8 M 2,12 A 10,10 0 1 0 22,12 A 10,10 0 1 0 2,12 Z",
    reset: "M 3 12 A 9 9 0 1 0 12 3 A 9.75 9.75 0 0 0 5.26 5.74 L 3 8 M 3 3 L 3 8 L 8 8",
    refresh: "M 21 12 A 9 9 0 1 1 12 3 A 9.75 9.75 0 0 1 18.74 5.74 L 21 3 M 21 8 L 21 3 L 16 3",
  };
  function icoSVG(fig, size) {
    const s = size || 16;
    return `<svg viewBox="0 0 24 24" width="${s}" height="${s}" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${fig}"/></svg>`;
  }
  document.querySelectorAll(".ico[data-fig]").forEach((el) => {
    const f = FIG[el.dataset.fig];
    if (f) el.innerHTML = icoSVG(f);
  });

  const ENGINES = [
    { id: "niguro", name: "Niguro" },
    { id: "google", name: "Google" },
    { id: "bing", name: "Bing" },
    { id: "startpage", name: "Startpage" },
    { id: "duckduckgo", name: "DuckDuckGo" },
  ];
  const WALLS = [
    { id: "g1", label: "Blue burst", css: "linear-gradient(160deg,#396afc 0%,#2948ff 100%)" },
    { id: "g2", label: "Sunset", css: "linear-gradient(160deg,#eb3349 0%,#f45c43 100%)" },
    { id: "g3", label: "Deep sky", css: "linear-gradient(160deg,#091e3a 0%,#2f80ed 50%,#2d9ee0 100%)" },
    { id: "g4", label: "Pink fusion", css: "linear-gradient(160deg,#ec008c 0%,#fc6767 100%)" },
    { id: "g5", label: "Berry dusk", css: "linear-gradient(160deg,#c04848 0%,#480048 100%)" },
    { id: "g6", label: "Mint calm", css: "linear-gradient(160deg,#81ff8a 0%,#64965e 100%)" },
    { id: "g7", label: "Lagoon", css: "linear-gradient(160deg,#59cde9 0%,#0a2a88 100%)" },
    { id: "g8", label: "Slate", css: "linear-gradient(160deg,#0f2027 0%,#2c5364 100%)" },
  ];

  // ---------- bridge ----------
  function post(msg) { if (bridge) bridge.postMessage(msg); }
  function ask(type) { post({ type }); }

  // Page-side diagnostics → error.log (so bridge/JS failures are visible).
  window.addEventListener("error", (e) => post({ type: "log", msg: "JS error: " + (e.message || "") + " @" + (e.lineno || "") + ":" + (e.colno || "") }));
  window.addEventListener("unhandledrejection", (e) => post({ type: "log", msg: "unhandled: " + ((e.reason && e.reason.message) || e.reason) }));

  // IMPORTANT: WebView2 delivers host→page messages on `window.chrome.webview`'s
  // message event — NOT the window's. Listen on both so pages work in and out of WebView2.
  function onHostMessage(e) {
    let msg;
    try { msg = typeof e.data === "string" ? JSON.parse(e.data) : e.data; } catch { return; }
    if (!msg || !msg.type) return;
    if (msg.type === "settings.data") { settings = msg.data; renderAll(); }
    else if (msg.type === "settings.changed") { settings = msg.data; renderAll(); }
    else if (msg.type === "settings.reset") {
      // Factory reset — drop page-side state on this origin (settings/apps theme) and
      // re-render from the freshly-reset snapshot. History/bookmarks/passwords stay.
      try {
        localStorage.removeItem("pako-settings-theme");
        localStorage.removeItem("pako-apps-theme");
      } catch (e) {}
      settings = msg.data;
      renderAll();
      toast("Settings reset to defaults");
    }
    else if (msg.type === "theme") {
      // Instant answer to browser.theme — covers System mode with the computed flag.
      settings = settings || {};
      settings.Theme = msg.theme || settings.Theme;
      settings.Accent = msg.accent || settings.Accent;
      if (msg.forced === true) forcedDark = true; // incognito window: always dark
      applyTheme();
    }
    else if (msg.type === "bookmarks.data") renderBookmarks(msg.items || []);
    else if (msg.type === "history.data") renderHistory(msg.items || []);
    else if (msg.type === "passwords.data") { pwPrefs = msg.prefs || {}; renderPasswords(msg.items || []); }
    else if (msg.type === "passwords.reveal") revealPassword(msg);
    else if (msg.type === "downloads.data") renderDownloads(msg.items || []);
    else if (msg.type === "adblock.stats") document.getElementById("adblockStats").textContent = `${msg.blocked?.toLocaleString?.() || msg.blocked || 0} requests blocked · ${msg.rules || 0} rules loaded`;
    else if (msg.type === "cleardata.done") toast("Browsing data cleared");
    else if (msg.type === "update.available") applyUpdateStatus(msg);
  }
  if (bridge) bridge.addEventListener("message", onHostMessage);
  window.addEventListener("message", onHostMessage);

  ask("settings.get");
  ask("browser.theme");
  ask("adblock.stats");
  ask("bookmarks.get");
  ask("update.status");
  ask("history.get");
  ask("downloads.get");
  ask("passwords.list");

  // ---------- theme ----------
  // Accent-hued dark surfaces (like niguro.com's dark mode) — tinted, not flat grey.
  function hexToRgb(hex) {
    let h = String(hex).replace("#", "");
    if (h.length === 3) h = h.split("").map((c) => c + c).join("");
    const n = parseInt(h, 16);
    if (isNaN(n)) return { r: 4, g: 180, b: 48 };
    return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
  }
  function tinted(c, k) { return `rgb(${Math.round(c.r * k)},${Math.round(c.g * k)},${Math.round(c.b * k)})`; }
  function applyAccentSurfaces() {
    const dark = document.documentElement.dataset.theme === "dark";
    const d = document.documentElement;
    const accent = getComputedStyle(d).getPropertyValue("--accent").trim() || settings?.Accent || "#04B430";
    if (dark && accent) {
      const c = hexToRgb(accent);
      d.style.setProperty("--bg", tinted(c, 0.05));
      d.style.setProperty("--panel", tinted(c, 0.10));
      d.style.setProperty("--border", `rgba(${c.r},${c.g},${c.b},0.18)`);
    } else {
      d.style.removeProperty("--bg");
      d.style.removeProperty("--panel");
      d.style.removeProperty("--border");
    }
  }
  function applyTheme() {
    if (!settings) return;
    const dark = forcedDark || settings.Theme === "Dark" ||
      (settings.Theme === "System" && window.matchMedia("(prefers-color-scheme: dark)").matches);
    document.documentElement.dataset.theme = dark ? "dark" : "light";
    // Persist so the very next landing paints the right theme (no white flash).
    try { localStorage.setItem("pako-settings-theme", dark ? "dark" : "light"); } catch (e) {}
    if (settings.Accent) document.documentElement.style.setProperty("--accent", settings.Accent);
    applyAccentSurfaces();
  }
  window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => { if (settings?.Theme === "System") applyTheme(); });

  // ---------- sidebar nav + search ----------
  const navItems = document.querySelectorAll(".side-item");
  navItems.forEach((it) => it.addEventListener("click", () => activate(it.dataset.sec)));
  function activate(sec) {
    navItems.forEach((n) => n.classList.toggle("active", n.dataset.sec === sec));
    document.querySelectorAll(".section").forEach((s) => s.classList.toggle("active", s.id === "sec-" + sec));
  }
  // Deep-link: ?sec=passwords opens that sidebar section directly (used by the
  // quick-settings "Passwords" shortcut and the incognito page's privacy card).
  try {
    const bootSec = new URLSearchParams(location.search).get("sec");
    if (bootSec && document.querySelector('.side-item[data-sec="' + bootSec + '"]'))
      activate(bootSec);
  } catch (e) {}

  const sideSearch = document.getElementById("sideSearch");
  sideSearch.addEventListener("input", () => {
    const q = sideSearch.value.trim().toLowerCase();
    if (!q) { navItems.forEach((n) => n.style.display = ""); return; }
    navItems.forEach((n) => {
      const label = n.textContent.toLowerCase();
      n.style.display = label.includes(q) ? "" : "none";
    });
  });

  // ---------- render ----------
  function renderAll() {
    if (!settings) return;
    applyTheme();
    renderPills("themePills", ["System", "Light", "Dark"], settings.Theme, (v) => save({ Theme: v }));
    renderEnginePills();
    // On-startup choice: new tab page / homepage / Niguro Bhitta. The explicit choice
    // lives in StartupChoice so "New tab page" really opens a fresh new tab — and
    // picking "homepage" keeps your configured homepage instead of clobbering it.
    const startPick = settings.StartupChoice
      || (settings.StartOnHomepage
        ? (settings.Homepage || "").includes("/bhitta") ? "bhitta" : "homepage"
        : "newtab");
    renderPills("startPills", ["newtab", "homepage", "bhitta"], startPick, (v) => {
      if (v === "newtab") save({ StartupChoice: "newtab", StartOnHomepage: false });
      else if (v === "bhitta") save({ StartupChoice: "bhitta", StartOnHomepage: true, Homepage: "https://www.niguro.com/bhitta" });
      else save({ StartupChoice: "homepage", StartOnHomepage: true });
    });
    document.getElementById("homepage").value = settings.Homepage || "";
    document.getElementById("accentColor").value = settings.Accent || "#04B430";
    setToggle("showShortcuts", settings.ShowShortcuts);
    setToggle("showDate", settings.NewTabShowDate);
    setToggle("showQuickLinks", settings.NewTabShowQuickLinks);
    setToggle("showEvents", settings.NewTabShowEvents);
    setToggle("showNews", settings.NewTabShowNews);
    setToggle("blockAds", settings.BlockAds);
    setToggle("blockTrackers", settings.BlockTrackers);
    setToggle("spellCheck", settings.SpellCheck);
    setToggle("incogClear", settings.IncognitoClearsOnClose);
    setToggle("memSaver", settings.MemorySaver);
    setToggle("showBookmarksBar", settings.ShowBookmarksBar);
    document.getElementById("suspendAfter").value = settings.SuspendAfterSeconds || 60;
    renderWalls();
    renderCustomEngines();
  }

  function renderPills(id, values, current, onPick) {
    const wrap = document.getElementById(id);
    wrap.innerHTML = "";
    values.forEach((v) => {
      const b = document.createElement("button");
      b.className = "pill" + (String(current) === String(v) ? " active" : "");
      b.textContent = v === "newtab" ? "New tab page" : v;
      b.addEventListener("click", () => {
        wrap.querySelectorAll(".pill").forEach((p) => p.classList.remove("active"));
        b.classList.add("active");
        onPick(v);
      });
      wrap.appendChild(b);
    });
  }

  function renderEnginePills() {
    const wrap = document.getElementById("enginePills");
    wrap.innerHTML = "";
    ENGINES.forEach((eng) => {
      const b = document.createElement("button");
      b.className = "pill" + (settings.SearchEngineId === eng.id ? " active" : "");
      b.textContent = eng.name;
      b.addEventListener("click", () => {
        wrap.querySelectorAll(".pill").forEach((p) => p.classList.remove("active"));
        b.classList.add("active");
        save({ SearchEngineId: eng.id });
      });
      wrap.appendChild(b);
    });
    renderCustomEngines();
  }

  // ---- Custom search engines ----
  function renderCustomEngines() {
    const list = document.getElementById("customEnginesList");
    const customs = settings.CustomEngines || [];
    if (!customs.length) { list.innerHTML = '<div class="empty">No custom engines yet — add one below</div>'; return; }
    list.innerHTML = "";
    customs.forEach((c) => {
      const row = document.createElement("div");
      row.className = "ce-row";
      row.innerHTML = `<div style="min-width:0;flex:1"><div class="li-title">${esc(c.Name)}</div><div class="li-sub">${esc(c.Template)}</div></div>`;
      const actions = document.createElement("div");
      actions.className = "li-actions";
      const def = document.createElement("button");
      def.className = "btn sm" + (settings.SearchEngineId === c.Id ? " primary" : "");
      def.textContent = settings.SearchEngineId === c.Id ? "Default" : "Set default";
      def.addEventListener("click", () => save({ SearchEngineId: c.Id }));
      actions.appendChild(def);
      const rm = document.createElement("button");
      rm.className = "btn sm danger";
      rm.textContent = "Remove";
      rm.addEventListener("click", () => {
        askConfirm(`Remove “${c.Name}”?`, () => {
          const filtered = customs.filter((x) => x.Id !== c.Id);
          const patch = { CustomEngines: filtered };
          if (settings.SearchEngineId === c.Id) patch.SearchEngineId = "niguro";
          save(patch);
        });
      });
      actions.appendChild(rm);
      row.appendChild(actions);
      list.appendChild(row);
    });
  }

  function addCustomEngine() {
    const name = document.getElementById("ceName").value.trim();
    const tpl = document.getElementById("ceTemplate").value.trim();
    if (!name || !tpl) { toast("Name and search URL are required"); return; }
    if (!tpl.includes("{q}")) { toast("Search URL must contain {q} where the query goes"); return; }
    const suggest = document.getElementById("ceSuggest").value.trim();
    const customs = (settings.CustomEngines || []).slice();
    customs.push({ Id: "custom-" + Date.now().toString(36), Name: name, Template: tpl, SuggestUrl: suggest });
    save({ CustomEngines: customs });
    document.getElementById("ceName").value = "";
    document.getElementById("ceTemplate").value = "";
    document.getElementById("ceSuggest").value = "";
    toast("Engine added");
  }

  function setToggle(id, on) {
    const el = document.getElementById(id);
    el.classList.toggle("on", !!on);
    el.setAttribute("aria-pressed", on ? "true" : "false");
  }

  function renderWalls() {
    const grid = document.getElementById("wallGrid");
    grid.innerHTML = "";
    const cur = settings.NewTabWallpaper || "";
    // "No background" tile — active when no wallpaper is set. Clicking it clears.
    const none = document.createElement("div");
    none.className = "wall-tile wall-none-tile" + (cur ? "" : " active");
    none.textContent = "✕";
    none.title = "No background";
    none.addEventListener("click", () => {
      grid.querySelectorAll(".wall-tile").forEach((x) => x.classList.remove("active"));
      none.classList.add("active");
      save({ NewTabWallpaper: "" });
    });
    grid.appendChild(none);
    WALLS.forEach((w) => {
      const t = document.createElement("div");
      t.className = "wall-tile" + (cur === "gradient:" + w.id ? " active" : "");
      t.style.background = w.css;
      t.title = w.label;
      t.addEventListener("click", () => {
        grid.querySelectorAll(".wall-tile").forEach((x) => x.classList.remove("active"));
        t.classList.add("active");
        save({ NewTabWallpaper: "gradient:" + w.id });
      });
      grid.appendChild(t);
    });
  }

  // ---------- saves ----------
  let saveTimer = null;
  function save(patch) {
    // Never block on the snapshot — post the patch even if settings.data hasn't arrived.
    if (!settings) settings = {};
    Object.assign(settings, patch);
    dirty = true;
    post({ type: "settings.set", data: patch });
    applyTheme();
    clearTimeout(saveTimer);
    saveTimer = setTimeout(() => { if (dirty) { dirty = false; toast("Settings saved"); } }, 700);
  }

  // Toggle helper — flip from the BUTTON's own state, so clicks work even before
  // the first snapshot renders (no dependency on `settings` being populated).
  function flipToggle(id, key) {
    const el = document.getElementById(id);
    const v = !el.classList.contains("on");
    save({ [key]: v });
    setToggle(id, v);
  }

  function toast(text) {
    const t = document.getElementById("toast");
    t.textContent = text;
    t.classList.add("show");
    setTimeout(() => t.classList.remove("show"), 1600);
  }

  // ---------- event wiring ----------
  document.getElementById("accentColor").addEventListener("input", (e) => save({ Accent: e.target.value }));
  document.getElementById("homepage").addEventListener("change", (e) => save({ Homepage: e.target.value.trim() }));
  document.getElementById("suspendAfter").addEventListener("change", (e) => save({ SuspendAfterSeconds: parseInt(e.target.value, 10) || 60 }));
  document.getElementById("showShortcuts").addEventListener("click", () => flipToggle("showShortcuts", "ShowShortcuts"));
  document.getElementById("showDate").addEventListener("click", () => flipToggle("showDate", "NewTabShowDate"));
  document.getElementById("showQuickLinks").addEventListener("click", () => flipToggle("showQuickLinks", "NewTabShowQuickLinks"));
  document.getElementById("showEvents").addEventListener("click", () => flipToggle("showEvents", "NewTabShowEvents"));
  document.getElementById("showNews").addEventListener("click", () => flipToggle("showNews", "NewTabShowNews"));
  document.getElementById("blockAds").addEventListener("click", () => { flipToggle("blockAds", "BlockAds"); ask("adblock.stats"); });
  document.getElementById("blockTrackers").addEventListener("click", () => { flipToggle("blockTrackers", "BlockTrackers"); ask("adblock.stats"); });
  document.getElementById("spellCheck").addEventListener("click", () => flipToggle("spellCheck", "SpellCheck"));
  document.getElementById("incogClear").addEventListener("click", () => flipToggle("incogClear", "IncognitoClearsOnClose"));
  document.getElementById("memSaver").addEventListener("click", () => flipToggle("memSaver", "MemorySaver"));
  document.getElementById("showBookmarksBar").addEventListener("click", () => flipToggle("showBookmarksBar", "ShowBookmarksBar"));

  // ---------- Updates ----------
  let updData = null;
  function applyUpdateStatus(msg) {
    if (!msg) return;
    if (msg.current) document.getElementById("updVersion").textContent = msg.current;
    if (typeof msg.autoCheck === "boolean") setToggle("updAuto", msg.autoCheck);
    if (msg.lastChecked) {
      const d = new Date(msg.lastChecked);
      document.getElementById("updLastChecked").textContent = "Last checked: " + (isNaN(d) ? "—" : d.toLocaleString());
    }
    updData = msg.data || null;
    const card = document.getElementById("updResult");
    const title = document.getElementById("updResultTitle");
    const desc = document.getElementById("updResultDesc");
    if (updData) {
      card.classList.remove("hidden");
      title.textContent = "Pako " + updData.version + " is ready";
      desc.textContent = (updData.notes || "A new version of Pako is available.") + "\n\nYour version: " + (msg.current || "—");
      document.getElementById("updApply").style.display = "";
    } else if (msg.checked === true) {
      card.classList.remove("hidden");
      title.textContent = "You're up to date";
      desc.textContent = "Pako " + (msg.current || "—") + " is the latest version.";
      document.getElementById("updApply").style.display = "none";
    }
  }
  document.getElementById("updAuto").addEventListener("click", () => flipToggle("updAuto", "UpdateAutoCheck"));
  document.getElementById("updCheck").addEventListener("click", () => {
    const b = document.getElementById("updCheck");
    b.disabled = true;
    b.textContent = "Checking…";
    post({ type: "update.check" });
    setTimeout(() => { b.disabled = false; b.textContent = "Check now"; }, 15000);
  });
  document.getElementById("updApply").addEventListener("click", () => {
    if (updData) post({ type: "update.apply" });
  });
  document.getElementById("updWhatsNew").addEventListener("click", () => post({ type: "nav.whatsnew" }));

  // ---------- passwords ----------
  let pwPrefs = {};
  let pwRevealId = null;
  let pwRevealPass = "";
  let pwCopyId = null;
  let pwItemsCache = [];
  function renderPasswords(items) {
    pwItemsCache = items || [];
    const list = document.getElementById("passwordsList");
    setToggle("pwOffer", !!pwPrefs.offerSave);
    setToggle("pwAutofill", !!pwPrefs.autofill);
    if (!items.length) { list.innerHTML = '<div class="empty">No saved passwords yet — Pako offers to save when you sign in to a site</div>'; return; }
    list.innerHTML = "";
    items.forEach((p) => {
      const row = document.createElement("div");
      row.className = "list-item";
      const host = ((p.origin || "").replace(/^https?:\/\//, "") || p.site || "");
      const fav = `https://www.google.com/s2/favicons?domain=${encodeURIComponent(host)}&sz=32`;
      const show = pwRevealId === p.id;
      row.innerHTML =
        `<span class="li-ico" style="overflow:hidden;border-radius:6px"><img src="${fav}" alt="" width="16" height="16" style="display:block" onerror="this.style.display='none'"></span>` +
        `<div style="min-width:0"><div class="li-title">${esc(p.site || host)}</div><div class="li-sub">${esc(p.username)} · ${esc(host)}</div></div>` +
        `<span class="li-actions" style="display:flex;align-items:center;gap:6px">` +
          `<span style="font-family:monospace;font-size:13px;letter-spacing:1px;color:var(--muted)">${show ? esc(pwRevealPass) : "••••••••"}</span>` +
          `<button class="btn sm" data-pw="reveal" data-id="${p.id}">${show ? "Hide" : "Show"}</button>` +
          `<button class="btn sm" data-pw="copy" data-id="${p.id}">Copy</button>` +
          `<button class="btn sm danger" data-pw="delete" data-id="${p.id}">Delete</button>` +
        `</span>`;
      list.appendChild(row);
    });
    list.querySelectorAll("[data-pw]").forEach((b) => {
      b.addEventListener("click", () => {
        const id = b.getAttribute("data-id");
        const act = b.getAttribute("data-pw");
        if (act === "reveal") {
          if (pwRevealId === id) { pwRevealId = null; pwRevealPass = ""; renderPasswords(items); }
          else { pwRevealId = id; pwRevealPass = ""; renderPasswords(items); post({ type: "passwords.reveal", id }); }
        } else if (act === "copy") {
          if (pwRevealId === id && pwRevealPass) { copyText(pwRevealPass); toast("Password copied"); }
          else { pwCopyId = id; post({ type: "passwords.reveal", id }); }
        } else if (act === "delete") {
          post({ type: "passwords.delete", id });
        }
      });
    });
  }
  function revealPassword(msg) {
    if (!msg.ok || !msg.id) return;
    if (msg.id === pwRevealId) { pwRevealPass = msg.password || ""; renderPasswords(pwItemsCache || []); }
    if (msg.id === pwCopyId) {
      copyText(msg.password || "");
      pwCopyId = null;
      toast("Password copied");
    }
  }
  function copyText(t) { try { navigator.clipboard.writeText(t); } catch (e) { const ta = document.createElement("textarea"); ta.value = t; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); ta.remove(); } }

  document.getElementById("pwOffer").addEventListener("click", () => {
    const v = !document.getElementById("pwOffer").classList.contains("on");
    setToggle("pwOffer", v);
    post({ type: "passwords.setPref", prefs: { offerSave: v } });
  });
  document.getElementById("pwAutofill").addEventListener("click", () => {
    const v = !document.getElementById("pwAutofill").classList.contains("on");
    setToggle("pwAutofill", v);
    post({ type: "passwords.setPref", prefs: { autofill: v } });
  });
  document.getElementById("addPasswordBtn").addEventListener("click", () => {
    document.getElementById("pwAddCard").classList.toggle("hidden");
  });
  document.getElementById("pwAddCancel").addEventListener("click", () => {
    document.getElementById("pwAddCard").classList.add("hidden");
  });
  document.getElementById("pwAddSave").addEventListener("click", () => {
    const url = document.getElementById("pwAddUrl").value.trim();
    const user = document.getElementById("pwAddUser").value.trim();
    const pass = document.getElementById("pwAddPass").value;
    if (!url || !user || !pass) { toast("Fill URL, username and password"); return; }
    let origin = url;
    try {
      const u = new URL(url.includes("://") ? url : "https://" + url);
      origin = u.origin;
      if (u.pathname && u.pathname !== "/" && !document.getElementById("pwAddSite").value.trim())
        document.getElementById("pwAddSite").value = u.hostname;
    } catch (e) {}
    post({ type: "passwords.save", entry: { origin, site: document.getElementById("pwAddSite").value.trim(), username: user, password: pass } });
    document.getElementById("pwAddUrl").value = "";
    document.getElementById("pwAddUser").value = "";
    document.getElementById("pwAddPass").value = "";
    document.getElementById("pwAddCard").classList.add("hidden");
    toast("Login saved");
  });

  document.getElementById("wallUrl").addEventListener("keydown", (e) => {
    if (e.key === "Enter" && e.target.value.trim()) {
      save({ NewTabWallpaper: e.target.value.trim() });
      toast("Wallpaper set");
    }
  });

  // Free wallpaper search — Wikimedia Commons (no key needed).
  const wallSuggest = document.getElementById("wallSuggest");
  const wallKeyword = document.getElementById("wallKeyword");
  let wallSeq = 0;
  function searchWalls() {
    const kw = wallKeyword.value.trim();
    if (!kw) return;
    const seq = ++wallSeq;
    wallSuggest.innerHTML = `<div class="empty">Searching Wikimedia Commons…</div>`;
    const api = "https://commons.wikimedia.org/w/api.php?action=query&format=json&origin=*"
      + "&generator=search&gsrnamespace=6&gsrlimit=12"
      + "&gsrsearch=" + encodeURIComponent("filetype:bitmap " + kw)
      + "&prop=imageinfo&iiprop=url|mime|size&iiurlwidth=1920";
    fetch(api)
      .then((r) => r.json())
      .then((j) => {
        if (seq !== wallSeq) return;
        const pages = (j.query && j.query.pages) ? Object.values(j.query.pages) : [];
        wallSuggest.innerHTML = "";
        let shown = 0;
        pages.forEach((p) => {
          if (shown >= 8) return;
          const ii = p.imageinfo && p.imageinfo[0];
          if (!ii) return;
          const mime = (ii.mime || "").toLowerCase();
          if (mime !== "image/jpeg" && mime !== "image/png") return;
          const w = ii.width || 0, h = ii.height || 0;
          if (w < 1200 || h < 600) return; // too small to be a wallpaper
          const full = ii.thumburl || ii.url;
          const thumb = ii.thumburl ? ii.thumburl.replace(/\/\d+px-/, "/400px-") : ii.url;
          const t = document.createElement("div");
          t.className = "wall-tile";
          t.style.backgroundImage = `url('${thumb}')`;
          t.title = (p.title || "Apply wallpaper").replace(/^File:/, "").replace(/_/g, " ");
          t.addEventListener("click", () => {
            save({ NewTabWallpaper: full });
            toast("Wallpaper set");
          });
          wallSuggest.appendChild(t);
          shown++;
        });
        if (shown === 0) wallSuggest.innerHTML = `<div class="empty">No photos found for “${kw}” — try another keyword.</div>`;
      })
      .catch(() => {
        if (seq === wallSeq) wallSuggest.innerHTML = `<div class="empty">Search failed — check your connection.</div>`;
      });
  }
  document.getElementById("wallSearch").addEventListener("click", searchWalls);
  wallKeyword.addEventListener("keydown", (e) => { if (e.key === "Enter") searchWalls(); });
  document.getElementById("wallEdit").addEventListener("click", () => {
    const cur = settings.NewTabWallpaper?.startsWith("http") ? settings.NewTabWallpaper : "";
    askPrompt(cur, (v) => {
      save({ NewTabWallpaper: v });
      renderWalls();
      if (v) toast("Wallpaper set"); else toast("Wallpaper removed");
    });
  });

  document.getElementById("clearData").addEventListener("click", () => {
    askConfirm("Clear cookies, cache, site data and permissions? This signs you out of most websites.", () => post({ type: "cleardata" }));
  });
  document.getElementById("clearHistory").addEventListener("click", () => {
    askConfirm("Clear your entire browsing history?", () => {
      post({ type: "history.clear" });
      ask("history.get");
      toast("History cleared");
    });
  });
  document.getElementById("ceAdd").addEventListener("click", addCustomEngine);
  document.getElementById("ceTemplate").addEventListener("keydown", (e) => { if (e.key === "Enter") addCustomEngine(); });

  // ---- Custom confirm / prompt dialogs (no browser alert) ----
  let dlgOnOk = null;
  function askConfirm(message, onOk) {
    document.getElementById("dlgMsg").textContent = message;
    dlgOnOk = onOk;
    document.getElementById("dlgOverlay").classList.remove("hidden");
  }
  document.getElementById("dlgOk").addEventListener("click", () => {
    const fn = dlgOnOk; dlgOnOk = null;
    document.getElementById("dlgOverlay").classList.add("hidden");
    if (fn) fn();
  });
  document.getElementById("dlgCancel").addEventListener("click", () => {
    dlgOnOk = null;
    document.getElementById("dlgOverlay").classList.add("hidden");
  });

  let prmOnOk = null;
  function askPrompt(initial, onOk) {
    document.getElementById("prmInput").value = initial || "";
    prmOnOk = onOk;
    document.getElementById("prmOverlay").classList.remove("hidden");
    setTimeout(() => document.getElementById("prmInput").focus(), 60);
  }
  document.getElementById("prmOk").addEventListener("click", () => {
    const v = document.getElementById("prmInput").value.trim();
    const fn = prmOnOk; prmOnOk = null;
    document.getElementById("prmOverlay").classList.add("hidden");
    if (fn) fn(v);
  });
  document.getElementById("prmCancel").addEventListener("click", () => {
    prmOnOk = null;
    document.getElementById("prmOverlay").classList.add("hidden");
  });
  document.getElementById("prmInput").addEventListener("keydown", (e) => { if (e.key === "Enter") document.getElementById("prmOk").click(); });
  document.addEventListener("keydown", (e) => {
    if (e.key !== "Escape") return;
    if (!document.getElementById("dlgOverlay").classList.contains("hidden")) document.getElementById("dlgCancel").click();
    else if (!document.getElementById("prmOverlay").classList.contains("hidden")) document.getElementById("prmCancel").click();
  });
  document.getElementById("openDownloads").addEventListener("click", () => {
    if (bridge) bridge.postMessage({ type: "nav.downloads" });
    else window.location.href = "downloads.html";
  });

  // ---- Reset all settings to factory defaults (custom confirm, no browser alert) ----
  document.getElementById("resetAll").addEventListener("click", () => {
    askConfirm("Restore every Pako setting to its default? Your history, bookmarks, saved passwords and downloads will be kept.", () => {
      post({ type: "settings.reset" });
    });
  });
  document.getElementById("makeDefault").addEventListener("click", () => {
    if (bridge) bridge.postMessage({ type: "nav.defaultapps" });
    else toast("Open Windows Settings → Apps → Default apps");
  });

  // ---------- lists ----------
  function renderBookmarks(items) {
    const list = document.getElementById("bookmarksList");
    if (!items.length) { list.innerHTML = '<div class="empty">No bookmarks yet — press Ctrl+D on any page</div>'; return; }
    list.innerHTML = "";
    items.forEach((b) => {
      const row = document.createElement("div");
      row.className = "list-item";
      row.innerHTML = `<span class="li-ico">${icoSVG(FIG.star, 15)}</span><div style="min-width:0"><div class="li-title">${esc(b.title)}</div><div class="li-sub">${esc(b.url)}</div></div>`;
      const del = document.createElement("button");
      del.className = "btn sm danger li-actions";
      del.textContent = "Remove";
      del.addEventListener("click", () => post({ type: "bookmark.remove", url: b.url }));
      row.appendChild(del);
      list.appendChild(row);
    });
  }

  function renderHistory(items) {
    const list = document.getElementById("historyList");
    if (!items.length) { list.innerHTML = '<div class="empty">No history yet</div>'; return; }
    list.innerHTML = "";
    items.slice(0, 100).forEach((h) => {
      const row = document.createElement("div");
      row.className = "list-item";
      row.innerHTML = `<span class="li-ico">${icoSVG(FIG.clock, 15)}</span><div style="min-width:0"><div class="li-title">${esc(h.title)}</div><div class="li-sub">${esc(h.url)}</div></div><span class="li-actions" style="font-size:11px;color:var(--muted)">${new Date(h.visited).toLocaleString()}</span>`;
      list.appendChild(row);
    });
  }

  function renderDownloads(items) {
    const list = document.getElementById("downloadsList");
    if (!items.length) { list.innerHTML = '<div class="empty">No downloads yet</div>'; return; }
    list.innerHTML = "";
    items.slice(0, 50).forEach((d) => {
      const row = document.createElement("div");
      row.className = "list-item";
      row.innerHTML = `<span class="li-ico">${icoSVG(FIG.download, 15)}</span><div style="min-width:0;flex:1"><div class="li-title">${esc(d.name)}</div><div class="li-sub">${d.done ? (d.state === "interrupted" ? "Interrupted" : "Completed") : Math.round(d.progress) + "%"}</div></div>`;
      const actions = document.createElement("div");
      actions.className = "li-actions";
      if (d.done && d.state !== "interrupted") {
        const open = document.createElement("button");
        open.className = "btn sm";
        open.textContent = "Open";
        open.addEventListener("click", () => post({ type: "downloads.open", path: d.path }));
        actions.appendChild(open);
      }
      const folder = document.createElement("button");
      folder.className = "btn sm";
      folder.textContent = "Folder";
      folder.addEventListener("click", () => post({ type: "downloads.openfolder", path: d.path }));
      actions.appendChild(folder);
      row.appendChild(actions);
      list.appendChild(row);
    });
  }

  // ---------- nav messages from app ----------
  function onNavMessage(e) {
    let msg;
    try { msg = typeof e.data === "string" ? JSON.parse(e.data) : e.data; } catch { return; }
    if (!msg || !msg.type) return;
    if (msg.type === "nav.downloads") window.location.href = "downloads.html";
    else if (msg.type === "nav.defaultapps") toast("Open Windows Settings → Apps → Default apps");
  }
  if (bridge) bridge.addEventListener("message", onNavMessage);
  window.addEventListener("message", onNavMessage);

  function esc(s) {
    return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]));
  }

  // ---- Hidden dev self-test: launch the browser with `Pako.exe selftest` to drive
  // the settings page end-to-end and report bridge/toggle behavior to error.log. ----
  try {
    if (new URLSearchParams(location.search).has("selftest")) {
      const log = (m) => post({ type: "log", msg: "selftest: " + m });
      log("boot OK, bridge=" + !!bridge);
      function onSelftestMessage(e) {
        let msg;
        try { msg = typeof e.data === "string" ? JSON.parse(e.data) : e.data; } catch { return; }
        if (!msg || !msg.type) return;
        if (msg.type === "settings.data") {
          setTimeout(() => {
            try {
              log("data arrived: ShowShortcuts=" + settings.ShowShortcuts + " Theme=" + settings.Theme);
              const el = document.getElementById("showShortcuts");
              log("toggle class before: " + el.className);
              el.click();
              setTimeout(() => {
                try {
                  log("toggle class after click: " + el.className + " settings.ShowShortcuts=" + settings.ShowShortcuts);
                } catch (ex) { log("after-click error: " + ex.message); }
              }, 500);
            } catch (ex) { log("test error: " + ex.message); }
          }, 900);
        }
      }
      if (bridge) bridge.addEventListener("message", onSelftestMessage);
      window.addEventListener("message", onSelftestMessage);
      // Probe: re-ask after 2.5s to tell a boot-time race from a systemic reply failure.
      setTimeout(() => { log("re-asking settings.get"); ask("settings.get"); }, 2500);
    }
  } catch (ex) { post({ type: "log", msg: "selftest setup error: " + ex.message }); }
})();