Better Search ⭐

Clean up your search results! Highlights preferred websites and fades or completely hides sites you dislike on Google, Bing, DuckDuckGo, Brave, and Yandex.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

// ==UserScript==
// @name         Better Search ⭐
// @namespace    https://github.com/quantavil/userscript/better-search
// @version      3.8
// @author       quantavil
// @description  Clean up your search results! Highlights preferred websites and fades or completely hides sites you dislike on Google, Bing, DuckDuckGo, Brave, and Yandex.
// @license      MIT
// @homepage     https://github.com/quantavil/userscript
// @homepageURL  https://github.com/quantavil/userscript
// @include      /^https?:\/\/(?:www\.)?google\.[a-z]{2,6}(?:\.[a-z]{2,3})?\/search/
// @include      *://www.bing.com/search*
// @include      *://*.bing.com/search*
// @include      *://duckduckgo.com/*
// @include      *://*.duckduckgo.com/*
// @include      *://search.brave.com/search*
// @include      /^https?:\/\/(?:[a-z]+\.)?yandex\.[a-z]{2,}\/search/
// @include      /^https?:\/\/(?:[a-z]+\.)?ya\.ru\/search/
// @connect      gist.githubusercontent.com
// @connect      api.github.com
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_setClipboard
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  const SVF_CONFIG = {
    /** Prefix for all localStorage / GM storage keys */
    STORAGE_PREFIX: "svf_",
    /** data-attribute written to result items for identification */
    ITEM_ATTR: "data-svf-id",
    /** How long (ms) to debounce the scanner after DOM mutations */
    SCAN_DEBOUNCE_MS: 120,
    /** How long (ms) to debounce settings saves */
    SAVE_DEBOUNCE_MS: 800,
    /** Default liked domains prepopulated on first install */
    DEFAULT_LIKED: [],
    /** Default disliked domains prepopulated on first install */
    DEFAULT_DISLIKED: [],
    /** Debounce (ms) before auto-pushing to Gist after a domain change */
    SYNC_PUSH_DEBOUNCE_MS: 1e4,
    /** Filename used inside the Gist */
    GIST_FILENAME: "domains.json",
    /** Always-latest raw URL for quick import (no token needed) */
    GIST_IMPORT_URL: "https://gist.githubusercontent.com/quantavil/12880b87fd1ebd497469455d1898088b/raw/domains.json"
  };
  function gmGet(key, fallback) {
    try {
      if (typeof GM_getValue === "function") {
        const v2 = GM_getValue(SVF_CONFIG.STORAGE_PREFIX + key, void 0);
        return v2 !== void 0 && v2 !== null ? v2 : fallback;
      }
      const raw = localStorage.getItem(SVF_CONFIG.STORAGE_PREFIX + key);
      return raw ? JSON.parse(raw) : fallback;
    } catch (err) {
      console.error("[SVF] Failed to read from storage:", err);
      return fallback;
    }
  }
  function gmSet(key, value) {
    try {
      if (typeof GM_setValue === "function") {
        GM_setValue(SVF_CONFIG.STORAGE_PREFIX + key, value);
        return;
      }
      localStorage.setItem(SVF_CONFIG.STORAGE_PREFIX + key, JSON.stringify(value));
    } catch (err) {
      console.error("[SVF] Failed to write to storage:", err);
    }
  }
  class Store {
    constructor() {
      this._saveTimers = {};
      this._listeners = /* @__PURE__ */ new Set();
      this._settings = {
        liked: gmGet("liked", SVF_CONFIG.DEFAULT_LIKED),
        disliked: gmGet("disliked", SVF_CONFIG.DEFAULT_DISLIKED),
        dislikeMode: gmGet("dislikeMode", "fade"),
        showTrigger: gmGet("showTrigger", true),
        accent: gmGet("accent", "emerald"),
        gistToken: gmGet("gistToken", ""),
        gistId: gmGet("gistId", ""),
        syncEnabled: gmGet("syncEnabled", false)
      };
      this._pagehideHandler = () => {
        for (const key of Object.keys(this._saveTimers)) {
          const timer = this._saveTimers[key];
          if (timer) {
            clearTimeout(timer);
            gmSet(key, this._settings[key]);
          }
        }
      };
      window.addEventListener("pagehide", this._pagehideHandler);
    }
    // ── Accessors ─────────────────────────────────────────────────────────────
    get liked() {
      return this._settings.liked;
    }
    get disliked() {
      return this._settings.disliked;
    }
    get dislikeMode() {
      return this._settings.dislikeMode;
    }
    get showTrigger() {
      return this._settings.showTrigger;
    }
    get accent() {
      return this._settings.accent;
    }
    get gistToken() {
      return this._settings.gistToken;
    }
    get gistId() {
      return this._settings.gistId;
    }
    get syncEnabled() {
      return this._settings.syncEnabled;
    }
    /** Returns 'liked' | 'disliked' | 'normal' for a given bare domain. Supports wildcards. */
    matchDomain(domain) {
      const d2 = domain.toLowerCase();
      const hit = (list) => list.some((rule) => {
        if (rule.startsWith("*.")) {
          const r2 = rule.slice(2);
          return d2 === r2 || d2.endsWith("." + r2);
        }
        return d2 === rule;
      });
      if (hit(this._settings.liked)) return "liked";
      if (hit(this._settings.disliked)) return "disliked";
      return "normal";
    }
    // ── Mutations ─────────────────────────────────────────────────────────────
    addDomain(list, domain) {
      const d2 = normalizeDomain(domain);
      const otherList = list === "liked" ? "disliked" : "liked";
      if (!d2 || this._settings[list].includes(d2)) return;
      this._settings[otherList] = this._settings[otherList].filter((x2) => x2 !== d2);
      this._settings[list] = [...this._settings[list], d2].sort();
      this._persist("liked");
      this._persist("disliked");
      this._notify();
    }
    removeDomain(list, domain) {
      const d2 = normalizeDomain(domain);
      this._settings[list] = this._settings[list].filter((x2) => x2 !== d2);
      this._persist(list);
      this._notify();
    }
    setDomains(list, domains) {
      const normalized = domains.map((x2) => normalizeDomain(x2)).filter(Boolean);
      const otherList = list === "liked" ? "disliked" : "liked";
      this._settings[list] = [...new Set(normalized)];
      this._settings[otherList] = this._settings[otherList].filter((x2) => !this._settings[list].includes(x2));
      this._persist("liked");
      this._persist("disliked");
      this._notify();
    }
    setDislikeMode(mode) {
      this._settings.dislikeMode = mode;
      this._persist("dislikeMode");
      this._notify();
    }
    setShowTrigger(show) {
      this._settings.showTrigger = show;
      this._persist("showTrigger");
      this._notify();
    }
    setAccent(accent) {
      this._settings.accent = accent;
      this._persist("accent");
      this._notify();
    }
    setGistToken(token) {
      this._settings.gistToken = token.trim();
      this._persist("gistToken");
      this._notify();
    }
    setGistId(id) {
      this._settings.gistId = id.trim();
      this._persist("gistId");
      this._notify();
    }
    setSyncEnabled(enabled) {
      this._settings.syncEnabled = enabled;
      this._persist("syncEnabled");
      this._notify();
    }
    replaceDomains(data) {
      const liked = Array.isArray(data.liked) ? data.liked.map(normalizeDomain).filter(Boolean) : [];
      const disliked = Array.isArray(data.disliked) ? data.disliked.map(normalizeDomain).filter(Boolean) : [];
      const dedupedLiked = [...new Set(liked)].sort();
      const dedupedDisliked = [...new Set(disliked)].filter((x2) => !dedupedLiked.includes(x2)).sort();
      this._settings.liked = dedupedLiked;
      this._settings.disliked = dedupedDisliked;
      this._persistDirect("liked");
      this._persistDirect("disliked");
      this._notify();
    }
    setSyncPushCallback(fn) {
      this._onSyncPush = fn;
    }
    /** Export current domain lists as a plain object. */
    exportDomains() {
      return {
        liked: [...this._settings.liked],
        disliked: [...this._settings.disliked]
      };
    }
    /** Merge imported domains into current lists (additive, deduplicated). */
    importDomains(data) {
      let added = 0;
      if (Array.isArray(data.liked)) {
        for (const raw of data.liked) {
          const d2 = normalizeDomain(raw);
          if (d2 && !this._settings.liked.includes(d2)) {
            this._settings.disliked = this._settings.disliked.filter((x2) => x2 !== d2);
            this._settings.liked = [...this._settings.liked, d2];
            added++;
          }
        }
      }
      if (Array.isArray(data.disliked)) {
        for (const raw of data.disliked) {
          const d2 = normalizeDomain(raw);
          if (d2 && !this._settings.disliked.includes(d2)) {
            this._settings.liked = this._settings.liked.filter((x2) => x2 !== d2);
            this._settings.disliked = [...this._settings.disliked, d2];
            added++;
          }
        }
      }
      if (added > 0) {
        this._persist("liked");
        this._persist("disliked");
        this._notify();
      }
      return added;
    }
    // ── Subscriptions ─────────────────────────────────────────────────────────
    /** Subscribe to any settings change. Returns an unsubscribe fn. */
    subscribe(fn) {
      this._listeners.add(fn);
      return () => this._listeners.delete(fn);
    }
    destroy() {
      window.removeEventListener("pagehide", this._pagehideHandler);
      for (const key of Object.keys(this._saveTimers)) {
        const timer = this._saveTimers[key];
        if (timer) {
          clearTimeout(timer);
          gmSet(key, this._settings[key]);
        }
      }
      this._saveTimers = {};
      this._listeners.clear();
    }
    // ── Internal ──────────────────────────────────────────────────────────────
    _notify() {
      this._listeners.forEach((fn) => {
        try {
          fn();
        } catch (err) {
          console.error("[SVF] Subscriber error during notify:", err);
        }
      });
    }
    _persistDirect(key) {
      clearTimeout(this._saveTimers[key]);
      gmSet(key, this._settings[key]);
    }
    _persist(key) {
      clearTimeout(this._saveTimers[key]);
      this._saveTimers[key] = setTimeout(() => {
        gmSet(key, this._settings[key]);
        if ((key === "liked" || key === "disliked") && this._settings.syncEnabled) {
          this._onSyncPush?.();
        }
      }, SVF_CONFIG.SAVE_DEBOUNCE_MS);
    }
  }
  function normalizeDomain(input) {
    let s2 = input.trim().toLowerCase();
    if (!s2) return "";
    const hasWildcard = s2.startsWith("*.");
    if (hasWildcard) {
      s2 = s2.slice(2);
    }
    try {
      if (!s2.includes("://")) {
        s2 = "http://" + s2;
      }
      s2 = new URL(s2).hostname;
    } catch {
      return "";
    }
    s2 = s2.startsWith("www.") ? s2.slice(4) : s2;
    return hasWildcard ? "*." + s2 : s2;
  }
  const ACCENT_RAW = {
    emerald: { hex: "#10b981", rgb: "16, 185, 129" },
    indigo: { hex: "#6366f1", rgb: "99, 102, 241" },
    blue: { hex: "#3b82f6", rgb: "59, 130, 246" },
    teal: { hex: "#06b6d4", rgb: "6, 182, 212" },
    rose: { hex: "#f43f5e", rgb: "244, 63, 94" },
    amber: { hex: "#f59e0b", rgb: "245, 158, 11" }
  };
  const ACCENT_COLORS = Object.keys(ACCENT_RAW).reduce((acc, key) => {
    const { hex, rgb } = ACCENT_RAW[key];
    acc[key] = {
      primary: hex,
      glow: `rgba(${rgb}, 0.15)`,
      bg: `rgba(${rgb}, 0.04)`,
      bgHover: `rgba(${rgb}, 0.08)`,
      border: `rgba(${rgb}, 0.25)`,
      statusBg: `rgba(${rgb}, 0.1)`,
      dotGlow: `rgba(${rgb}, 0.6)`
    };
    return acc;
  }, {});
  const ACCENT_VARS = [
    "--svf-primary",
    "--svf-primary-glow",
    "--svf-primary-bg",
    "--svf-primary-bg-hover",
    "--svf-primary-border",
    "--svf-primary-status-bg"
  ];
  function applyAccentVariables(el, accent) {
    const current = ACCENT_COLORS[accent] || ACCENT_COLORS.emerald;
    el.style.setProperty("--svf-primary", current.primary);
    el.style.setProperty("--svf-primary-glow", current.glow);
    el.style.setProperty("--svf-primary-bg", current.bg);
    el.style.setProperty("--svf-primary-bg-hover", current.bgHover);
    el.style.setProperty("--svf-primary-border", current.border);
    el.style.setProperty("--svf-primary-status-bg", current.statusBg);
  }
  function removeAccentVariables(el) {
    for (const key of ACCENT_VARS) {
      el.style.removeProperty(key);
    }
  }
  const BASE_CSS = '@layer svf-filters{[data-svf-id].svf-liked{position:relative!important;border-left:4px solid var(--svf-primary, #10b981)!important;border-radius:0 6px 6px 0!important;padding-left:12px!important;background:var(--svf-primary-bg, rgba(16, 185, 129, .04))!important;transition:border-color .2s,background .2s!important}[data-svf-id].svf-liked:after{content:"✦";position:absolute;top:6px;right:10px;font-size:10px;font-weight:700;letter-spacing:.4px;color:var(--svf-primary, #10b981);background:var(--svf-primary-glow, rgba(16, 185, 129, .12));padding:2px 8px;border-radius:10px;pointer-events:none;z-index:1;font-family:system-ui,sans-serif}[data-svf-id].svf-fade{opacity:.14!important;filter:grayscale(.8)!important;transition:opacity .25s,filter .25s!important}[data-svf-id].svf-fade:hover{opacity:.9!important;filter:none!important}[data-svf-id].svf-hide{position:relative!important;max-height:36px!important;overflow:hidden!important;opacity:1!important;cursor:pointer!important;border:1px dashed rgba(239,68,68,.25)!important;border-radius:6px!important;background:#ef444408!important;transition:max-height .3s ease,background .2s!important;margin:4px 0!important}[data-svf-id].svf-hide:before{content:"⊘  " attr(data-svf-id-domain) " — blocked (click to reveal)";display:block!important;padding:9px 14px!important;font-size:11.5px!important;font-weight:500!important;color:#ef4444b3!important;font-family:system-ui,sans-serif!important;white-space:nowrap!important;overflow:hidden!important;text-overflow:ellipsis!important;pointer-events:none!important}[data-svf-id].svf-hide>*{display:none!important}[data-svf-id].svf-hide:hover{background:#ef44440f!important}[data-svf-id].svf-revealed{max-height:none!important;cursor:auto!important;border:none!important;background:transparent!important}[data-svf-id].svf-revealed:before{display:none!important}[data-svf-id].svf-revealed>*{pointer-events:auto!important;user-select:auto!important}[data-svf-id].svf-swipe-active{position:relative!important;z-index:2!important;box-shadow:0 4px 12px #0000001f!important;user-select:none!important;-webkit-user-select:none!important;touch-action:pan-y!important}[data-svf-id].svf-swipe-transition{transition:transform .2s cubic-bezier(.16,1,.3,1)!important}.svf-swipe-bg{position:absolute!important;z-index:1!important;display:flex!important;justify-content:flex-end!important;align-items:stretch!important;background:#1e1e24!important;border-radius:8px!important;overflow:hidden!important;box-shadow:inset 0 2px 8px #0003!important;pointer-events:auto!important}.svf-swipe-btn-container{display:flex!important;height:100%!important;align-items:stretch!important}.svf-swipe-btn{display:flex!important;flex-direction:column!important;justify-content:center!important;align-items:center!important;width:64px!important;border:none!important;background:transparent!important;color:#ffffffb3!important;cursor:pointer!important;padding:0!important;margin:0!important;transition:background .15s,color .15s!important;-webkit-tap-highlight-color:transparent!important}.svf-swipe-btn.like-btn{background:#10b98126!important;color:var(--svf-primary, #10b981)!important}.svf-swipe-btn.like-btn.active{background:var(--svf-primary, #10b981)!important;color:#fff!important}.svf-swipe-btn.dislike-btn{background:#ef444426!important;color:#ef4444!important}.svf-swipe-btn.dislike-btn.active{background:#ef4444!important;color:#fff!important}.svf-swipe-btn svg{width:20px!important;height:20px!important;display:block!important}.svf-swipe-btn-label{font-size:9px!important;font-weight:700!important;margin-top:4px!important;text-transform:uppercase!important;letter-spacing:.5px!important}.svf-swipe-btn.compact .svf-swipe-btn-label{display:none!important}}';
  class FilterStyleSheet {
    constructor(store) {
      this._store = store;
      this._el = document.createElement("style");
      this._el.id = "svf-styles";
      this._el.textContent = BASE_CSS;
      document.head.appendChild(this._el);
      this._updateVariables();
      this._unsub = this._store.subscribe(() => this._updateVariables());
    }
    _updateVariables() {
      const accent = this._store.accent;
      applyAccentVariables(document.documentElement, accent);
    }
    destroy() {
      this._unsub();
      this._el.remove();
      removeAccentVariables(document.documentElement);
    }
  }
  const ATTR$2 = SVF_CONFIG.ITEM_ATTR;
  const DOMAIN_ATTR$2 = `${ATTR$2}-domain`;
  let _counter = 0;
  const nextId = () => `${++_counter}`;
  class Scanner {
    constructor(store, engine, abortSignal) {
      this._container = null;
      this._observer = null;
      this._debounce = null;
      this._revealedElements = /* @__PURE__ */ new WeakSet();
      this._store = store;
      this._engine = engine;
      this._abortSignal = abortSignal;
    }
    /** Find the container and start observing. Returns false if not found yet. */
    attach() {
      const container = document.querySelector(this._engine.containerSelector);
      if (!container) return false;
      if (this._container === container) return true;
      this._disconnect();
      this._container = container;
      this._observer = new MutationObserver((mutations) => {
        let shouldScan = false;
        for (const m2 of mutations) {
          if (m2.addedNodes.length > 0) {
            shouldScan = true;
            break;
          }
          if (m2.type === "attributes" && m2.attributeName === "href") {
            shouldScan = true;
            break;
          }
        }
        if (!shouldScan) return;
        this._scheduleScan();
      });
      this._observer.observe(container, {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ["href"]
      });
      this.scanAll();
      return true;
    }
    /** Full re-scan of all items. Called on init and on settings change. */
    scanAll() {
      if (!this._container) return;
      const items = this._container.querySelectorAll(this._engine.itemSelector);
      items.forEach((item) => this._processItem(item));
    }
    /** Re-apply classes to all already-scanned items (e.g. after settings change). */
    reapply() {
      if (!this._container) return;
      const items = this._container.querySelectorAll(`[${ATTR$2}]`);
      items.forEach((item) => {
        const domain = item.getAttribute(DOMAIN_ATTR$2) ?? "";
        this._applyClass(item, domain);
      });
    }
    destroy() {
      this._disconnect();
      if (this._debounce) clearTimeout(this._debounce);
    }
    // ── Private ───────────────────────────────────────────────────────────────
    _scheduleScan() {
      if (this._debounce) clearTimeout(this._debounce);
      this._debounce = setTimeout(() => this.scanAll(), SVF_CONFIG.SCAN_DEBOUNCE_MS);
    }
    _processItem(item) {
      if (!(item instanceof HTMLElement)) return;
      if (item.parentElement && item.parentElement.closest(this._engine.itemSelector)) {
        return;
      }
      if (item.hasAttribute(ATTR$2)) {
        const domain2 = item.getAttribute(DOMAIN_ATTR$2) ?? "";
        this._applyClass(item, domain2);
        return;
      }
      const href = this._engine.extractUrl(item);
      if (!href) return;
      const domain = normalizeDomain(href);
      if (!domain) return;
      const id = nextId();
      item.setAttribute(ATTR$2, id);
      item.setAttribute(DOMAIN_ATTR$2, domain);
      this._applyClass(item, domain);
      this._bindReveal(item);
    }
    _applyClass(item, domain) {
      item.getAttribute(ATTR$2) ?? "";
      const match = this._store.matchDomain(domain);
      const mode = this._store.dislikeMode;
      item.classList.remove(
        `svf-liked`,
        `svf-fade`,
        `svf-hide`,
        `svf-revealed`
      );
      if (match === "liked") {
        item.classList.add(`svf-liked`);
      } else if (match === "disliked") {
        if (mode === "hide") {
          if (this._revealedElements.has(item)) {
            item.classList.add(`svf-revealed`);
          } else {
            item.classList.add(`svf-hide`);
          }
        } else {
          item.classList.add(`svf-fade`);
        }
      }
    }
    _bindReveal(item) {
      item.addEventListener("click", (e2) => {
        if (!item.classList.contains(`svf-hide`)) return;
        e2.preventDefault();
        e2.stopPropagation();
        this._revealedElements.add(item);
        item.classList.remove(`svf-hide`);
        item.classList.add(`svf-revealed`);
      }, { capture: true, signal: this._abortSignal });
    }
    _disconnect() {
      this._observer?.disconnect();
      this._observer = null;
      this._container = null;
    }
  }
  const t$3 = globalThis, e$6 = t$3.ShadowRoot && (void 0 === t$3.ShadyCSS || t$3.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$3 = /* @__PURE__ */ Symbol(), o$7 = /* @__PURE__ */ new WeakMap();
  let n$5 = class n {
    constructor(t2, e2, o2) {
      if (this._$cssResult$ = true, o2 !== s$3) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
      this.cssText = t2, this.t = e2;
    }
    get styleSheet() {
      let t2 = this.o;
      const s2 = this.t;
      if (e$6 && void 0 === t2) {
        const e2 = void 0 !== s2 && 1 === s2.length;
        e2 && (t2 = o$7.get(s2)), void 0 === t2 && ((this.o = t2 = new CSSStyleSheet()).replaceSync(this.cssText), e2 && o$7.set(s2, t2));
      }
      return t2;
    }
    toString() {
      return this.cssText;
    }
  };
  const r$6 = (t2) => new n$5("string" == typeof t2 ? t2 : t2 + "", void 0, s$3), S$1 = (s2, o2) => {
    if (e$6) s2.adoptedStyleSheets = o2.map((t2) => t2 instanceof CSSStyleSheet ? t2 : t2.styleSheet);
    else for (const e2 of o2) {
      const o3 = document.createElement("style"), n3 = t$3.litNonce;
      void 0 !== n3 && o3.setAttribute("nonce", n3), o3.textContent = e2.cssText, s2.appendChild(o3);
    }
  }, c$3 = e$6 ? (t2) => t2 : (t2) => t2 instanceof CSSStyleSheet ? ((t3) => {
    let e2 = "";
    for (const s2 of t3.cssRules) e2 += s2.cssText;
    return r$6(e2);
  })(t2) : t2;
  const { is: i$3, defineProperty: e$5, getOwnPropertyDescriptor: h$2, getOwnPropertyNames: r$5, getOwnPropertySymbols: o$6, getPrototypeOf: n$4 } = Object, a$1 = globalThis, c$2 = a$1.trustedTypes, l$1 = c$2 ? c$2.emptyScript : "", p$1 = a$1.reactiveElementPolyfillSupport, d$1 = (t2, s2) => t2, u$1 = { toAttribute(t2, s2) {
    switch (s2) {
      case Boolean:
        t2 = t2 ? l$1 : null;
        break;
      case Object:
      case Array:
        t2 = null == t2 ? t2 : JSON.stringify(t2);
    }
    return t2;
  }, fromAttribute(t2, s2) {
    let i3 = t2;
    switch (s2) {
      case Boolean:
        i3 = null !== t2;
        break;
      case Number:
        i3 = null === t2 ? null : Number(t2);
        break;
      case Object:
      case Array:
        try {
          i3 = JSON.parse(t2);
        } catch (t3) {
          i3 = null;
        }
    }
    return i3;
  } }, f$2 = (t2, s2) => !i$3(t2, s2), b$1 = { attribute: true, type: String, converter: u$1, reflect: false, useDefault: false, hasChanged: f$2 };
  Symbol.metadata ??= /* @__PURE__ */ Symbol("metadata"), a$1.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap();
  let y$1 = class y extends HTMLElement {
    static addInitializer(t2) {
      this._$Ei(), (this.l ??= []).push(t2);
    }
    static get observedAttributes() {
      return this.finalize(), this._$Eh && [...this._$Eh.keys()];
    }
    static createProperty(t2, s2 = b$1) {
      if (s2.state && (s2.attribute = false), this._$Ei(), this.prototype.hasOwnProperty(t2) && ((s2 = Object.create(s2)).wrapped = true), this.elementProperties.set(t2, s2), !s2.noAccessor) {
        const i3 = /* @__PURE__ */ Symbol(), h2 = this.getPropertyDescriptor(t2, i3, s2);
        void 0 !== h2 && e$5(this.prototype, t2, h2);
      }
    }
    static getPropertyDescriptor(t2, s2, i3) {
      const { get: e2, set: r2 } = h$2(this.prototype, t2) ?? { get() {
        return this[s2];
      }, set(t3) {
        this[s2] = t3;
      } };
      return { get: e2, set(s3) {
        const h2 = e2?.call(this);
        r2?.call(this, s3), this.requestUpdate(t2, h2, i3);
      }, configurable: true, enumerable: true };
    }
    static getPropertyOptions(t2) {
      return this.elementProperties.get(t2) ?? b$1;
    }
    static _$Ei() {
      if (this.hasOwnProperty(d$1("elementProperties"))) return;
      const t2 = n$4(this);
      t2.finalize(), void 0 !== t2.l && (this.l = [...t2.l]), this.elementProperties = new Map(t2.elementProperties);
    }
    static finalize() {
      if (this.hasOwnProperty(d$1("finalized"))) return;
      if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) {
        const t3 = this.properties, s2 = [...r$5(t3), ...o$6(t3)];
        for (const i3 of s2) this.createProperty(i3, t3[i3]);
      }
      const t2 = this[Symbol.metadata];
      if (null !== t2) {
        const s2 = litPropertyMetadata.get(t2);
        if (void 0 !== s2) for (const [t3, i3] of s2) this.elementProperties.set(t3, i3);
      }
      this._$Eh = /* @__PURE__ */ new Map();
      for (const [t3, s2] of this.elementProperties) {
        const i3 = this._$Eu(t3, s2);
        void 0 !== i3 && this._$Eh.set(i3, t3);
      }
      this.elementStyles = this.finalizeStyles(this.styles);
    }
    static finalizeStyles(s2) {
      const i3 = [];
      if (Array.isArray(s2)) {
        const e2 = new Set(s2.flat(1 / 0).reverse());
        for (const s3 of e2) i3.unshift(c$3(s3));
      } else void 0 !== s2 && i3.push(c$3(s2));
      return i3;
    }
    static _$Eu(t2, s2) {
      const i3 = s2.attribute;
      return false === i3 ? void 0 : "string" == typeof i3 ? i3 : "string" == typeof t2 ? t2.toLowerCase() : void 0;
    }
    constructor() {
      super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev();
    }
    _$Ev() {
      this._$ES = new Promise((t2) => this.enableUpdating = t2), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t2) => t2(this));
    }
    addController(t2) {
      (this._$EO ??= /* @__PURE__ */ new Set()).add(t2), void 0 !== this.renderRoot && this.isConnected && t2.hostConnected?.();
    }
    removeController(t2) {
      this._$EO?.delete(t2);
    }
    _$E_() {
      const t2 = /* @__PURE__ */ new Map(), s2 = this.constructor.elementProperties;
      for (const i3 of s2.keys()) this.hasOwnProperty(i3) && (t2.set(i3, this[i3]), delete this[i3]);
      t2.size > 0 && (this._$Ep = t2);
    }
    createRenderRoot() {
      const t2 = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
      return S$1(t2, this.constructor.elementStyles), t2;
    }
    connectedCallback() {
      this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(true), this._$EO?.forEach((t2) => t2.hostConnected?.());
    }
    enableUpdating(t2) {
    }
    disconnectedCallback() {
      this._$EO?.forEach((t2) => t2.hostDisconnected?.());
    }
    attributeChangedCallback(t2, s2, i3) {
      this._$AK(t2, i3);
    }
    _$ET(t2, s2) {
      const i3 = this.constructor.elementProperties.get(t2), e2 = this.constructor._$Eu(t2, i3);
      if (void 0 !== e2 && true === i3.reflect) {
        const h2 = (void 0 !== i3.converter?.toAttribute ? i3.converter : u$1).toAttribute(s2, i3.type);
        this._$Em = t2, null == h2 ? this.removeAttribute(e2) : this.setAttribute(e2, h2), this._$Em = null;
      }
    }
    _$AK(t2, s2) {
      const i3 = this.constructor, e2 = i3._$Eh.get(t2);
      if (void 0 !== e2 && this._$Em !== e2) {
        const t3 = i3.getPropertyOptions(e2), h2 = "function" == typeof t3.converter ? { fromAttribute: t3.converter } : void 0 !== t3.converter?.fromAttribute ? t3.converter : u$1;
        this._$Em = e2;
        const r2 = h2.fromAttribute(s2, t3.type);
        this[e2] = r2 ?? this._$Ej?.get(e2) ?? r2, this._$Em = null;
      }
    }
    requestUpdate(t2, s2, i3, e2 = false, h2) {
      if (void 0 !== t2) {
        const r2 = this.constructor;
        if (false === e2 && (h2 = this[t2]), i3 ??= r2.getPropertyOptions(t2), !((i3.hasChanged ?? f$2)(h2, s2) || i3.useDefault && i3.reflect && h2 === this._$Ej?.get(t2) && !this.hasAttribute(r2._$Eu(t2, i3)))) return;
        this.C(t2, s2, i3);
      }
      false === this.isUpdatePending && (this._$ES = this._$EP());
    }
    C(t2, s2, { useDefault: i3, reflect: e2, wrapped: h2 }, r2) {
      i3 && !(this._$Ej ??= /* @__PURE__ */ new Map()).has(t2) && (this._$Ej.set(t2, r2 ?? s2 ?? this[t2]), true !== h2 || void 0 !== r2) || (this._$AL.has(t2) || (this.hasUpdated || i3 || (s2 = void 0), this._$AL.set(t2, s2)), true === e2 && this._$Em !== t2 && (this._$Eq ??= /* @__PURE__ */ new Set()).add(t2));
    }
    async _$EP() {
      this.isUpdatePending = true;
      try {
        await this._$ES;
      } catch (t3) {
        Promise.reject(t3);
      }
      const t2 = this.scheduleUpdate();
      return null != t2 && await t2, !this.isUpdatePending;
    }
    scheduleUpdate() {
      return this.performUpdate();
    }
    performUpdate() {
      if (!this.isUpdatePending) return;
      if (!this.hasUpdated) {
        if (this.renderRoot ??= this.createRenderRoot(), this._$Ep) {
          for (const [t4, s3] of this._$Ep) this[t4] = s3;
          this._$Ep = void 0;
        }
        const t3 = this.constructor.elementProperties;
        if (t3.size > 0) for (const [s3, i3] of t3) {
          const { wrapped: t4 } = i3, e2 = this[s3];
          true !== t4 || this._$AL.has(s3) || void 0 === e2 || this.C(s3, void 0, i3, e2);
        }
      }
      let t2 = false;
      const s2 = this._$AL;
      try {
        t2 = this.shouldUpdate(s2), t2 ? (this.willUpdate(s2), this._$EO?.forEach((t3) => t3.hostUpdate?.()), this.update(s2)) : this._$EM();
      } catch (s3) {
        throw t2 = false, this._$EM(), s3;
      }
      t2 && this._$AE(s2);
    }
    willUpdate(t2) {
    }
    _$AE(t2) {
      this._$EO?.forEach((t3) => t3.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t2)), this.updated(t2);
    }
    _$EM() {
      this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = false;
    }
    get updateComplete() {
      return this.getUpdateComplete();
    }
    getUpdateComplete() {
      return this._$ES;
    }
    shouldUpdate(t2) {
      return true;
    }
    update(t2) {
      this._$Eq &&= this._$Eq.forEach((t3) => this._$ET(t3, this[t3])), this._$EM();
    }
    updated(t2) {
    }
    firstUpdated(t2) {
    }
  };
  y$1.elementStyles = [], y$1.shadowRootOptions = { mode: "open" }, y$1[d$1("elementProperties")] = /* @__PURE__ */ new Map(), y$1[d$1("finalized")] = /* @__PURE__ */ new Map(), p$1?.({ ReactiveElement: y$1 }), (a$1.reactiveElementVersions ??= []).push("2.1.2");
  const t$2 = globalThis, i$2 = (t2) => t2, s$2 = t$2.trustedTypes, e$4 = s$2 ? s$2.createPolicy("lit-html", { createHTML: (t2) => t2 }) : void 0, h$1 = "$lit$", o$5 = `lit$${Math.random().toFixed(9).slice(2)}$`, n$3 = "?" + o$5, r$4 = `<${n$3}>`, l = document, c$1 = () => l.createComment(""), a = (t2) => null === t2 || "object" != typeof t2 && "function" != typeof t2, u = Array.isArray, d = (t2) => u(t2) || "function" == typeof t2?.[Symbol.iterator], f$1 = "[ 	\n\f\r]", v = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, _ = /-->/g, m = />/g, p = RegExp(`>|${f$1}(?:([^\\s"'>=/]+)(${f$1}*=${f$1}*(?:[^ 	
\f\r"'\`<>=]|("|')|))|$)`, "g"), g = /'/g, $ = /"/g, y2 = /^(?:script|style|textarea|title)$/i, x = (t2) => (i3, ...s2) => ({ _$litType$: t2, strings: i3, values: s2 }), b = x(1), E = /* @__PURE__ */ Symbol.for("lit-noChange"), A = /* @__PURE__ */ Symbol.for("lit-nothing"), C = /* @__PURE__ */ new WeakMap(), P = l.createTreeWalker(l, 129);
  function V(t2, i3) {
    if (!u(t2) || !t2.hasOwnProperty("raw")) throw Error("invalid template strings array");
    return void 0 !== e$4 ? e$4.createHTML(i3) : i3;
  }
  const N = (t2, i3) => {
    const s2 = t2.length - 1, e2 = [];
    let n3, l2 = 2 === i3 ? "<svg>" : 3 === i3 ? "<math>" : "", c2 = v;
    for (let i4 = 0; i4 < s2; i4++) {
      const s3 = t2[i4];
      let a2, u2, d2 = -1, f2 = 0;
      for (; f2 < s3.length && (c2.lastIndex = f2, u2 = c2.exec(s3), null !== u2); ) f2 = c2.lastIndex, c2 === v ? "!--" === u2[1] ? c2 = _ : void 0 !== u2[1] ? c2 = m : void 0 !== u2[2] ? (y2.test(u2[2]) && (n3 = RegExp("</" + u2[2], "g")), c2 = p) : void 0 !== u2[3] && (c2 = p) : c2 === p ? ">" === u2[0] ? (c2 = n3 ?? v, d2 = -1) : void 0 === u2[1] ? d2 = -2 : (d2 = c2.lastIndex - u2[2].length, a2 = u2[1], c2 = void 0 === u2[3] ? p : '"' === u2[3] ? $ : g) : c2 === $ || c2 === g ? c2 = p : c2 === _ || c2 === m ? c2 = v : (c2 = p, n3 = void 0);
      const x2 = c2 === p && t2[i4 + 1].startsWith("/>") ? " " : "";
      l2 += c2 === v ? s3 + r$4 : d2 >= 0 ? (e2.push(a2), s3.slice(0, d2) + h$1 + s3.slice(d2) + o$5 + x2) : s3 + o$5 + (-2 === d2 ? i4 : x2);
    }
    return [V(t2, l2 + (t2[s2] || "<?>") + (2 === i3 ? "</svg>" : 3 === i3 ? "</math>" : "")), e2];
  };
  class S {
    constructor({ strings: t2, _$litType$: i3 }, e2) {
      let r2;
      this.parts = [];
      let l2 = 0, a2 = 0;
      const u2 = t2.length - 1, d2 = this.parts, [f2, v2] = N(t2, i3);
      if (this.el = S.createElement(f2, e2), P.currentNode = this.el.content, 2 === i3 || 3 === i3) {
        const t3 = this.el.content.firstChild;
        t3.replaceWith(...t3.childNodes);
      }
      for (; null !== (r2 = P.nextNode()) && d2.length < u2; ) {
        if (1 === r2.nodeType) {
          if (r2.hasAttributes()) for (const t3 of r2.getAttributeNames()) if (t3.endsWith(h$1)) {
            const i4 = v2[a2++], s2 = r2.getAttribute(t3).split(o$5), e3 = /([.?@])?(.*)/.exec(i4);
            d2.push({ type: 1, index: l2, name: e3[2], strings: s2, ctor: "." === e3[1] ? I : "?" === e3[1] ? L : "@" === e3[1] ? z : H }), r2.removeAttribute(t3);
          } else t3.startsWith(o$5) && (d2.push({ type: 6, index: l2 }), r2.removeAttribute(t3));
          if (y2.test(r2.tagName)) {
            const t3 = r2.textContent.split(o$5), i4 = t3.length - 1;
            if (i4 > 0) {
              r2.textContent = s$2 ? s$2.emptyScript : "";
              for (let s2 = 0; s2 < i4; s2++) r2.append(t3[s2], c$1()), P.nextNode(), d2.push({ type: 2, index: ++l2 });
              r2.append(t3[i4], c$1());
            }
          }
        } else if (8 === r2.nodeType) if (r2.data === n$3) d2.push({ type: 2, index: l2 });
        else {
          let t3 = -1;
          for (; -1 !== (t3 = r2.data.indexOf(o$5, t3 + 1)); ) d2.push({ type: 7, index: l2 }), t3 += o$5.length - 1;
        }
        l2++;
      }
    }
    static createElement(t2, i3) {
      const s2 = l.createElement("template");
      return s2.innerHTML = t2, s2;
    }
  }
  function M(t2, i3, s2 = t2, e2) {
    if (i3 === E) return i3;
    let h2 = void 0 !== e2 ? s2._$Co?.[e2] : s2._$Cl;
    const o2 = a(i3) ? void 0 : i3._$litDirective$;
    return h2?.constructor !== o2 && (h2?._$AO?.(false), void 0 === o2 ? h2 = void 0 : (h2 = new o2(t2), h2._$AT(t2, s2, e2)), void 0 !== e2 ? (s2._$Co ??= [])[e2] = h2 : s2._$Cl = h2), void 0 !== h2 && (i3 = M(t2, h2._$AS(t2, i3.values), h2, e2)), i3;
  }
  class R {
    constructor(t2, i3) {
      this._$AV = [], this._$AN = void 0, this._$AD = t2, this._$AM = i3;
    }
    get parentNode() {
      return this._$AM.parentNode;
    }
    get _$AU() {
      return this._$AM._$AU;
    }
    u(t2) {
      const { el: { content: i3 }, parts: s2 } = this._$AD, e2 = (t2?.creationScope ?? l).importNode(i3, true);
      P.currentNode = e2;
      let h2 = P.nextNode(), o2 = 0, n3 = 0, r2 = s2[0];
      for (; void 0 !== r2; ) {
        if (o2 === r2.index) {
          let i4;
          2 === r2.type ? i4 = new k(h2, h2.nextSibling, this, t2) : 1 === r2.type ? i4 = new r2.ctor(h2, r2.name, r2.strings, this, t2) : 6 === r2.type && (i4 = new Z(h2, this, t2)), this._$AV.push(i4), r2 = s2[++n3];
        }
        o2 !== r2?.index && (h2 = P.nextNode(), o2++);
      }
      return P.currentNode = l, e2;
    }
    p(t2) {
      let i3 = 0;
      for (const s2 of this._$AV) void 0 !== s2 && (void 0 !== s2.strings ? (s2._$AI(t2, s2, i3), i3 += s2.strings.length - 2) : s2._$AI(t2[i3])), i3++;
    }
  }
  class k {
    get _$AU() {
      return this._$AM?._$AU ?? this._$Cv;
    }
    constructor(t2, i3, s2, e2) {
      this.type = 2, this._$AH = A, this._$AN = void 0, this._$AA = t2, this._$AB = i3, this._$AM = s2, this.options = e2, this._$Cv = e2?.isConnected ?? true;
    }
    get parentNode() {
      let t2 = this._$AA.parentNode;
      const i3 = this._$AM;
      return void 0 !== i3 && 11 === t2?.nodeType && (t2 = i3.parentNode), t2;
    }
    get startNode() {
      return this._$AA;
    }
    get endNode() {
      return this._$AB;
    }
    _$AI(t2, i3 = this) {
      t2 = M(this, t2, i3), a(t2) ? t2 === A || null == t2 || "" === t2 ? (this._$AH !== A && this._$AR(), this._$AH = A) : t2 !== this._$AH && t2 !== E && this._(t2) : void 0 !== t2._$litType$ ? this.$(t2) : void 0 !== t2.nodeType ? this.T(t2) : d(t2) ? this.k(t2) : this._(t2);
    }
    O(t2) {
      return this._$AA.parentNode.insertBefore(t2, this._$AB);
    }
    T(t2) {
      this._$AH !== t2 && (this._$AR(), this._$AH = this.O(t2));
    }
    _(t2) {
      this._$AH !== A && a(this._$AH) ? this._$AA.nextSibling.data = t2 : this.T(l.createTextNode(t2)), this._$AH = t2;
    }
    $(t2) {
      const { values: i3, _$litType$: s2 } = t2, e2 = "number" == typeof s2 ? this._$AC(t2) : (void 0 === s2.el && (s2.el = S.createElement(V(s2.h, s2.h[0]), this.options)), s2);
      if (this._$AH?._$AD === e2) this._$AH.p(i3);
      else {
        const t3 = new R(e2, this), s3 = t3.u(this.options);
        t3.p(i3), this.T(s3), this._$AH = t3;
      }
    }
    _$AC(t2) {
      let i3 = C.get(t2.strings);
      return void 0 === i3 && C.set(t2.strings, i3 = new S(t2)), i3;
    }
    k(t2) {
      u(this._$AH) || (this._$AH = [], this._$AR());
      const i3 = this._$AH;
      let s2, e2 = 0;
      for (const h2 of t2) e2 === i3.length ? i3.push(s2 = new k(this.O(c$1()), this.O(c$1()), this, this.options)) : s2 = i3[e2], s2._$AI(h2), e2++;
      e2 < i3.length && (this._$AR(s2 && s2._$AB.nextSibling, e2), i3.length = e2);
    }
    _$AR(t2 = this._$AA.nextSibling, s2) {
      for (this._$AP?.(false, true, s2); t2 !== this._$AB; ) {
        const s3 = i$2(t2).nextSibling;
        i$2(t2).remove(), t2 = s3;
      }
    }
    setConnected(t2) {
      void 0 === this._$AM && (this._$Cv = t2, this._$AP?.(t2));
    }
  }
  class H {
    get tagName() {
      return this.element.tagName;
    }
    get _$AU() {
      return this._$AM._$AU;
    }
    constructor(t2, i3, s2, e2, h2) {
      this.type = 1, this._$AH = A, this._$AN = void 0, this.element = t2, this.name = i3, this._$AM = e2, this.options = h2, s2.length > 2 || "" !== s2[0] || "" !== s2[1] ? (this._$AH = Array(s2.length - 1).fill(new String()), this.strings = s2) : this._$AH = A;
    }
    _$AI(t2, i3 = this, s2, e2) {
      const h2 = this.strings;
      let o2 = false;
      if (void 0 === h2) t2 = M(this, t2, i3, 0), o2 = !a(t2) || t2 !== this._$AH && t2 !== E, o2 && (this._$AH = t2);
      else {
        const e3 = t2;
        let n3, r2;
        for (t2 = h2[0], n3 = 0; n3 < h2.length - 1; n3++) r2 = M(this, e3[s2 + n3], i3, n3), r2 === E && (r2 = this._$AH[n3]), o2 ||= !a(r2) || r2 !== this._$AH[n3], r2 === A ? t2 = A : t2 !== A && (t2 += (r2 ?? "") + h2[n3 + 1]), this._$AH[n3] = r2;
      }
      o2 && !e2 && this.j(t2);
    }
    j(t2) {
      t2 === A ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t2 ?? "");
    }
  }
  class I extends H {
    constructor() {
      super(...arguments), this.type = 3;
    }
    j(t2) {
      this.element[this.name] = t2 === A ? void 0 : t2;
    }
  }
  class L extends H {
    constructor() {
      super(...arguments), this.type = 4;
    }
    j(t2) {
      this.element.toggleAttribute(this.name, !!t2 && t2 !== A);
    }
  }
  class z extends H {
    constructor(t2, i3, s2, e2, h2) {
      super(t2, i3, s2, e2, h2), this.type = 5;
    }
    _$AI(t2, i3 = this) {
      if ((t2 = M(this, t2, i3, 0) ?? A) === E) return;
      const s2 = this._$AH, e2 = t2 === A && s2 !== A || t2.capture !== s2.capture || t2.once !== s2.once || t2.passive !== s2.passive, h2 = t2 !== A && (s2 === A || e2);
      e2 && this.element.removeEventListener(this.name, this, s2), h2 && this.element.addEventListener(this.name, this, t2), this._$AH = t2;
    }
    handleEvent(t2) {
      "function" == typeof this._$AH ? this._$AH.call(this.options?.host ?? this.element, t2) : this._$AH.handleEvent(t2);
    }
  }
  class Z {
    constructor(t2, i3, s2) {
      this.element = t2, this.type = 6, this._$AN = void 0, this._$AM = i3, this.options = s2;
    }
    get _$AU() {
      return this._$AM._$AU;
    }
    _$AI(t2) {
      M(this, t2);
    }
  }
  const B = t$2.litHtmlPolyfillSupport;
  B?.(S, k), (t$2.litHtmlVersions ??= []).push("3.3.3");
  const D = (t2, i3, s2) => {
    const e2 = s2?.renderBefore ?? i3;
    let h2 = e2._$litPart$;
    if (void 0 === h2) {
      const t3 = s2?.renderBefore ?? null;
      e2._$litPart$ = h2 = new k(i3.insertBefore(c$1(), t3), t3, void 0, s2 ?? {});
    }
    return h2._$AI(t2), h2;
  };
  const s$1 = globalThis;
  let i$1 = class i extends y$1 {
    constructor() {
      super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
    }
    createRenderRoot() {
      const t2 = super.createRenderRoot();
      return this.renderOptions.renderBefore ??= t2.firstChild, t2;
    }
    update(t2) {
      const r2 = this.render();
      this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t2), this._$Do = D(r2, this.renderRoot, this.renderOptions);
    }
    connectedCallback() {
      super.connectedCallback(), this._$Do?.setConnected(true);
    }
    disconnectedCallback() {
      super.disconnectedCallback(), this._$Do?.setConnected(false);
    }
    render() {
      return E;
    }
  };
  i$1._$litElement$ = true, i$1["finalized"] = true, s$1.litElementHydrateSupport?.({ LitElement: i$1 });
  const o$4 = s$1.litElementPolyfillSupport;
  o$4?.({ LitElement: i$1 });
  (s$1.litElementVersions ??= []).push("4.2.2");
  const t$1 = (t2) => (e2, o2) => {
    void 0 !== o2 ? o2.addInitializer(() => {
      customElements.define(t2, e2);
    }) : customElements.define(t2, e2);
  };
  const o$3 = { attribute: true, type: String, converter: u$1, reflect: false, hasChanged: f$2 }, r$3 = (t2 = o$3, e2, r2) => {
    const { kind: n3, metadata: i3 } = r2;
    let s2 = globalThis.litPropertyMetadata.get(i3);
    if (void 0 === s2 && globalThis.litPropertyMetadata.set(i3, s2 = /* @__PURE__ */ new Map()), "setter" === n3 && ((t2 = Object.create(t2)).wrapped = true), s2.set(r2.name, t2), "accessor" === n3) {
      const { name: o2 } = r2;
      return { set(r3) {
        const n4 = e2.get.call(this);
        e2.set.call(this, r3), this.requestUpdate(o2, n4, t2, true, r3);
      }, init(e3) {
        return void 0 !== e3 && this.C(o2, void 0, t2, e3), e3;
      } };
    }
    if ("setter" === n3) {
      const { name: o2 } = r2;
      return function(r3) {
        const n4 = this[o2];
        e2.call(this, r3), this.requestUpdate(o2, n4, t2, true, r3);
      };
    }
    throw Error("Unsupported decorator location: " + n3);
  };
  function n$2(t2) {
    return (e2, o2) => "object" == typeof o2 ? r$3(t2, e2, o2) : ((t3, e3, o3) => {
      const r2 = e3.hasOwnProperty(o3);
      return e3.constructor.createProperty(o3, t3), r2 ? Object.getOwnPropertyDescriptor(e3, o3) : void 0;
    })(t2, e2, o2);
  }
  function r$2(r2) {
    return n$2({ ...r2, state: true, attribute: false });
  }
  const e$3 = (e2, t2, c2) => (c2.configurable = true, c2.enumerable = true, Reflect.decorate && "object" != typeof t2 && Object.defineProperty(e2, t2, c2), c2);
  function e$2(e2, r2) {
    return (n3, s2, i3) => {
      const o2 = (t2) => t2.renderRoot?.querySelector(e2) ?? null;
      return e$3(n3, s2, { get() {
        return o2(this);
      } });
    };
  }
  const t = { CHILD: 2 }, e$1 = (t2) => (...e2) => ({ _$litDirective$: t2, values: e2 });
  class i2 {
    constructor(t2) {
    }
    get _$AU() {
      return this._$AM._$AU;
    }
    _$AT(t2, e2, i3) {
      this._$Ct = t2, this._$AM = e2, this._$Ci = i3;
    }
    _$AS(t2, e2) {
      return this.update(t2, e2);
    }
    update(t2, e2) {
      return this.render(...e2);
    }
  }
  class e extends i2 {
    constructor(i3) {
      if (super(i3), this.it = A, i3.type !== t.CHILD) throw Error(this.constructor.directiveName + "() can only be used in child bindings");
    }
    render(r2) {
      if (r2 === A || null == r2) return this._t = void 0, this.it = r2;
      if (r2 === E) return r2;
      if ("string" != typeof r2) throw Error(this.constructor.directiveName + "() called with a non-string value");
      if (r2 === this.it) return this._t;
      this.it = r2;
      const s2 = [r2];
      return s2.raw = s2, this._t = { _$litType$: this.constructor.resultType, strings: s2, values: [] };
    }
  }
  e.directiveName = "unsafeHTML", e.resultType = 1;
  const o$2 = e$1(e);
  const HOVER_CSS = ":host{position:fixed;z-index:2147483640;display:flex;gap:3px;align-items:center;background:#16161ae6;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);border-radius:8px;padding:4px 6px;box-shadow:0 4px 16px #0000004d;opacity:0;pointer-events:none;transition:opacity .15s ease,visibility .15s ease;font-family:system-ui,sans-serif;visibility:hidden;user-select:none;-webkit-user-select:none}:host(.visible){opacity:1;visibility:visible;pointer-events:none}.svf-hb-btn{background:transparent;border:none;cursor:pointer;width:24px;height:24px;border-radius:5px;display:grid;place-items:center;color:#fff9;transition:background .15s,color .15s,transform .1s;padding:0;pointer-events:auto}.svf-hb-btn:hover{background:#ffffff1a;color:#fff;transform:scale(1.1)}.svf-hb-btn.like-active{color:var(--svf-primary, #10b981)}.svf-hb-btn.dislike-active{color:#ef4444}.svf-hb-sep{width:1px;height:16px;background:#ffffff1a;margin:0 2px}.svf-hb-label{font-size:10px;color:#fff6;max-width:120px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0 4px}";
  function svgIcon(path, size = 14, viewBox = "0 0 24 24", strokeWidth = "2.5") {
    return `<svg width="${size}" height="${size}" viewBox="${viewBox}" fill="none" stroke="currentColor" stroke-width="${strokeWidth}" stroke-linecap="round" stroke-linejoin="round">${path}</svg>`;
  }
  const ICON_CLOSE = svgIcon('<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>', 16, "0 0 24 24", "2.5");
  const ICON_SEARCH = svgIcon('<circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line>', 14, "0 0 24 24", "2.5");
  const ICON_CLEAR = svgIcon('<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>', 12, "0 0 24 24", "2.5");
  const ICON_DOWNLOAD = svgIcon('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>', 14, "0 0 24 24", "2");
  const ICON_IMPORT = svgIcon('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>', 14, "0 0 24 24", "2");
  const ICON_EDIT = svgIcon('<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>');
  const ICON_DELETE = svgIcon('<polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>');
  const ICON_TRIGGER = svgIcon('<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"></path><circle cx="12" cy="12" r="3"></circle>', 20, "0 0 24 24", "2.2");
  const STAR_FILLED = svgIcon('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" fill="currentColor" stroke="none"/>', 14, "0 0 24 24", "2.2");
  const STAR_EMPTY = svgIcon('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>', 14, "0 0 24 24", "2.2");
  const BAN_ICON = svgIcon('<circle cx="12" cy="12" r="10"/><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/>', 14, "0 0 24 24", "2.2");
  const ICON_EYE = svgIcon('<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle>', 14, "0 0 24 24", "2");
  const ICON_EYE_OFF = svgIcon('<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line>', 14, "0 0 24 24", "2");
  var __defProp$2 = Object.defineProperty;
  var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
  var __decorateClass$2 = (decorators, target, key, kind) => {
    var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
    for (var i3 = decorators.length - 1, decorator; i3 >= 0; i3--)
      if (decorator = decorators[i3])
        result = (kind ? decorator(target, key, result) : decorator(result)) || result;
    if (kind && result) __defProp$2(target, key, result);
    return result;
  };
  const ATTR$1 = SVF_CONFIG.ITEM_ATTR;
  const DOMAIN_ATTR$1 = `${ATTR$1}-domain`;
  let HoverOverlayElement = class extends i$1 {
    constructor() {
      super(...arguments);
      this._activeDomain = "";
      this._matchState = "normal";
      this._activeItem = null;
      this._hideTimer = null;
      this._HIDE_DELAY = 350;
      this._rafId = null;
      this._lastEvent = null;
    }
    connectedCallback() {
      super.connectedCallback();
      this._unsubscribe?.();
      if (this.store) {
        this._unsubscribe = this.store.subscribe(() => {
          this._updateMatchState();
        });
      }
      this._connectedAbortController?.abort();
      this._connectedAbortController = new AbortController();
      const signal = this._connectedAbortController.signal;
      const docOpts = { signal, passive: true, capture: true };
      document.addEventListener("pointermove", (e2) => {
        this._lastEvent = e2;
        if (this._rafId === null) {
          this._rafId = requestAnimationFrame(() => {
            if (this._lastEvent) {
              this._onPointerMove(this._lastEvent);
            }
            this._rafId = null;
          });
        }
      }, docOpts);
      document.addEventListener("pointerleave", () => {
        this._scheduleHide();
      }, docOpts);
      this.addEventListener("pointerenter", () => this._cancelHide(), { signal });
      this.addEventListener("pointerleave", () => this._scheduleHide(), { signal });
    }
    disconnectedCallback() {
      super.disconnectedCallback();
      this._unsubscribe?.();
      if (this._connectedAbortController) {
        this._connectedAbortController.abort();
        this._connectedAbortController = void 0;
      }
      if (this._rafId !== null) {
        cancelAnimationFrame(this._rafId);
        this._rafId = null;
      }
      if (this._hideTimer) {
        clearTimeout(this._hideTimer);
        this._hideTimer = null;
      }
    }
    updated(changedProperties) {
      super.updated(changedProperties);
      if (this.store) {
        applyAccentVariables(this, this.store.accent);
      }
    }
    _onPointerMove(e2) {
      if (e2.pointerType === "touch") return;
      const shadowHost = document.getElementById("svf-shadow-host");
      const panel = (shadowHost?.shadowRoot || shadowHost)?.querySelector("svf-panel");
      if (panel?.isOpen?.()) {
        this._scheduleHide();
        return;
      }
      let target = document.elementFromPoint(e2.clientX, e2.clientY);
      if (!target) {
        this._scheduleHide();
        return;
      }
      while (target && target.shadowRoot) {
        const inner = target.shadowRoot.elementFromPoint(e2.clientX, e2.clientY);
        if (!inner || inner === target) break;
        target = inner;
      }
      const item = target.closest(`[${ATTR$1}]`);
      if (!item) {
        if (target === shadowHost || this === target || this.shadowRoot?.contains(target)) {
          this._cancelHide();
        } else {
          this._scheduleHide();
        }
        return;
      }
      this._cancelHide();
      if (item === this._activeItem) return;
      this._activeItem = item;
      this._activeDomain = item.getAttribute(DOMAIN_ATTR$1) ?? "";
      this._updateMatchState();
      this._positionBar(item);
    }
    _positionBar(item) {
      const rect = item.getBoundingClientRect();
      const barW = this.offsetWidth || 160;
      const barH = this.offsetHeight || 32;
      let top = rect.top + 4;
      if (rect.top < 0) {
        top = Math.max(4, rect.bottom - barH - 4);
      }
      let left = rect.right - barW - 4;
      if (left < 8) left = rect.left + 8;
      if (left + barW > window.innerWidth - 8) left = window.innerWidth - barW - 8;
      this.style.top = `${top}px`;
      this.style.left = `${left}px`;
      this.classList.add("visible");
    }
    _updateMatchState() {
      if (!this._activeDomain || !this.store) return;
      this._matchState = this.store.matchDomain(this._activeDomain);
    }
    _scheduleHide() {
      if (this._hideTimer) return;
      this._hideTimer = setTimeout(() => {
        this.classList.remove("visible");
        this._activeItem = null;
        this._activeDomain = "";
        this._hideTimer = null;
      }, this._HIDE_DELAY);
    }
    _cancelHide() {
      if (this._hideTimer) {
        clearTimeout(this._hideTimer);
        this._hideTimer = null;
      }
    }
    _toggle(list, e2) {
      e2.stopPropagation();
      if (!this._activeDomain) return;
      if (this._matchState === list) {
        this.store.removeDomain(list, this._activeDomain);
      } else {
        this.store.addDomain(list, this._activeDomain);
      }
      this.scanner.reapply();
    }
    render() {
      return b`
            <button
                class="svf-hb-btn ${this._matchState === "liked" ? "like-active" : ""}"
                title=${this._matchState === "liked" ? "Remove from Liked" : "Add to Liked"}
                @click=${(e2) => this._toggle("liked", e2)}
            >
                ${o$2(this._matchState === "liked" ? STAR_FILLED : STAR_EMPTY)}
            </button>
            
            <button
                class="svf-hb-btn ${this._matchState === "disliked" ? "dislike-active" : ""}"
                title=${this._matchState === "disliked" ? "Remove from Disliked" : "Add to Disliked"}
                @click=${(e2) => this._toggle("disliked", e2)}
            >
                ${o$2(BAN_ICON)}
            </button>
            
            <div class="svf-hb-sep"></div>
            
            <span class="svf-hb-label" title=${this._activeDomain}>${this._activeDomain}</span>
        `;
    }
  };
  HoverOverlayElement.styles = r$6(HOVER_CSS);
  __decorateClass$2([
    n$2({ attribute: false })
  ], HoverOverlayElement.prototype, "store", 2);
  __decorateClass$2([
    n$2({ attribute: false })
  ], HoverOverlayElement.prototype, "scanner", 2);
  __decorateClass$2([
    n$2({ attribute: false })
  ], HoverOverlayElement.prototype, "signal", 2);
  __decorateClass$2([
    r$2()
  ], HoverOverlayElement.prototype, "_activeDomain", 2);
  __decorateClass$2([
    r$2()
  ], HoverOverlayElement.prototype, "_matchState", 2);
  HoverOverlayElement = __decorateClass$2([
    t$1("svf-hover-overlay")
  ], HoverOverlayElement);
  const ATTR = SVF_CONFIG.ITEM_ATTR;
  const DOMAIN_ATTR = `${ATTR}-domain`;
  const REVEAL_WIDTH = 128;
  class MobileSwipe {
    constructor(store, scanner, signal) {
      this._activeItem = null;
      this._activeBg = null;
      this._startX = 0;
      this._startY = 0;
      this._isSwiping = false;
      this._isScrolling = false;
      this._swipeConfirmed = false;
      this._initialTranslate = 0;
      this._wasOpen = false;
      this._store = store;
      this._scanner = scanner;
      this._signal = signal;
      this._initListeners();
    }
    _initListeners() {
      document.addEventListener("touchstart", (e2) => this._onTouchStart(e2), { signal: this._signal, passive: true });
      document.addEventListener("touchmove", (e2) => this._onTouchMove(e2), { signal: this._signal, passive: false });
      document.addEventListener("touchend", (e2) => this._onTouchEnd(e2), { signal: this._signal, passive: false });
      document.addEventListener("touchcancel", (e2) => this._onTouchEnd(e2), { signal: this._signal, passive: false });
    }
    _onTouchStart(e2) {
      if (e2.touches.length > 1) return;
      const touch = e2.touches[0];
      const target = e2.target;
      if (this._activeItem && !this._activeItem.contains(target) && (!this._activeBg || !this._activeBg.contains(target))) {
        const itemToClose = this._activeItem;
        const bgToClose = this._activeBg;
        this._animateClose(itemToClose, bgToClose);
        this._activeItem = null;
        this._activeBg = null;
      }
      const item = target.closest(`[${ATTR}]`);
      if (!item) return;
      if (item.classList.contains("svf-hide")) return;
      this._startX = touch.clientX;
      this._startY = touch.clientY;
      this._isSwiping = false;
      this._isScrolling = false;
      this._swipeConfirmed = false;
      this._initialTranslate = this._getTranslationX(item);
      this._wasOpen = this._initialTranslate < -10;
      if (item !== this._activeItem) {
        if (this._activeItem) {
          this._animateClose(this._activeItem, this._activeBg);
        }
        this._activeItem = item;
        this._activeBg = null;
      }
    }
    _onTouchMove(e2) {
      if (!this._activeItem || e2.touches.length > 1) return;
      const touch = e2.touches[0];
      const dx = touch.clientX - this._startX;
      const dy = touch.clientY - this._startY;
      if (this._isScrolling) return;
      if (!this._swipeConfirmed) {
        const absDx = Math.abs(dx);
        const absDy = Math.abs(dy);
        if (absDy > absDx && absDy > 8) {
          this._isScrolling = true;
          this._activeItem = null;
          return;
        }
        if (absDx > absDy && absDx > 8) {
          this._swipeConfirmed = true;
          this._isSwiping = true;
          this._prepareSwipeBg(this._activeItem);
        }
      }
      if (this._isSwiping && this._activeItem && this._activeBg) {
        e2.preventDefault();
        let targetX = this._initialTranslate + dx;
        if (targetX > 0) {
          targetX = targetX * 0.2;
        } else if (targetX < -REVEAL_WIDTH) {
          targetX = -REVEAL_WIDTH + (targetX + REVEAL_WIDTH) * 0.3;
        }
        this._activeItem.style.transform = `translateX(${targetX}px)`;
      }
    }
    _onTouchEnd(e2) {
      if (!this._activeItem) return;
      const item = this._activeItem;
      const bg = this._activeBg;
      const target = e2.target;
      if (this._isSwiping && bg) {
        const currentTranslate = this._getTranslationX(item);
        const threshold = -REVEAL_WIDTH / 2;
        if (currentTranslate < threshold) {
          this._animateOpen(item, bg);
        } else {
          this._animateClose(item, bg);
          if (item === this._activeItem) {
            this._activeItem = null;
            this._activeBg = null;
          }
        }
      } else if (this._wasOpen && bg && !bg.contains(target)) {
        e2.preventDefault();
        this._animateClose(item, bg);
        this._activeItem = null;
        this._activeBg = null;
      }
      this._isSwiping = false;
      this._isScrolling = false;
      this._swipeConfirmed = false;
    }
    _getTranslationX(el) {
      const style = window.getComputedStyle(el);
      const transform = style.transform;
      if (!transform || transform === "none") return 0;
      const matrix = new DOMMatrix(transform);
      return matrix.m41;
    }
    _prepareSwipeBg(item) {
      if (this._activeBg) return;
      const domain = item.getAttribute(DOMAIN_ATTR) || "";
      const match = this._store.matchDomain(domain);
      let bg = item.previousElementSibling;
      if (!bg || !bg.classList.contains("svf-swipe-bg")) {
        bg = document.createElement("div");
        bg.className = "svf-swipe-bg";
        item.parentNode?.insertBefore(bg, item);
      }
      bg.style.top = `${item.offsetTop}px`;
      bg.style.left = `${item.offsetLeft}px`;
      bg.style.width = `${item.offsetWidth}px`;
      bg.style.height = `${item.offsetHeight}px`;
      const isLiked = match === "liked";
      const isDisliked = match === "disliked";
      const isCompact = item.offsetHeight < 54;
      bg.innerHTML = `
            <div class="svf-swipe-btn-container">
                <button class="svf-swipe-btn like-btn ${isLiked ? "active" : ""} ${isCompact ? "compact" : ""}" title="${isLiked ? "Remove from Liked" : "Add to Liked"}">
                    ${STAR_FILLED}
                    <span class="svf-swipe-btn-label">Star</span>
                </button>
                <button class="svf-swipe-btn dislike-btn ${isDisliked ? "active" : ""} ${isCompact ? "compact" : ""}" title="${isDisliked ? "Remove from Disliked" : "Add to Disliked"}">
                    ${BAN_ICON}
                    <span class="svf-swipe-btn-label">Block</span>
                </button>
            </div>
        `;
      item.classList.add("svf-swipe-active");
      const opaqueBg = this._getOpaqueBackground(item);
      item.style.backgroundColor = opaqueBg;
      const likeBtn = bg.querySelector(".like-btn");
      const dislikeBtn = bg.querySelector(".dislike-btn");
      likeBtn?.addEventListener("click", (e2) => {
        e2.stopPropagation();
        this._toggleLike(domain);
        this._animateClose(item, bg);
        if (this._activeItem === item) {
          this._activeItem = null;
          this._activeBg = null;
        }
      });
      dislikeBtn?.addEventListener("click", (e2) => {
        e2.stopPropagation();
        this._toggleDislike(domain);
        this._animateClose(item, bg);
        if (this._activeItem === item) {
          this._activeItem = null;
          this._activeBg = null;
        }
      });
      this._activeBg = bg;
    }
    _getOpaqueBackground(el) {
      let current = el;
      while (current) {
        const bg = window.getComputedStyle(current).backgroundColor;
        if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
          return bg;
        }
        current = current.parentElement;
      }
      return "#fff";
    }
    _toggleLike(domain) {
      const match = this._store.matchDomain(domain);
      if (match === "liked") {
        this._store.removeDomain("liked", domain);
      } else {
        this._store.addDomain("liked", domain);
      }
      this._scanner.reapply();
    }
    _toggleDislike(domain) {
      const match = this._store.matchDomain(domain);
      if (match === "disliked") {
        this._store.removeDomain("disliked", domain);
      } else {
        this._store.addDomain("disliked", domain);
      }
      this._scanner.reapply();
    }
    _animateOpen(item, bg) {
      item.classList.add("svf-swipe-transition");
      item.style.transform = `translateX(-${REVEAL_WIDTH}px)`;
      setTimeout(() => {
        item.classList.remove("svf-swipe-transition");
      }, 200);
    }
    _animateClose(item, bg) {
      item.classList.add("svf-swipe-transition");
      item.style.transform = "";
      setTimeout(() => {
        item.classList.remove("svf-swipe-transition");
        item.classList.remove("svf-swipe-active");
        item.style.backgroundColor = "";
        if (bg && bg.parentNode) {
          bg.remove();
        }
      }, 200);
    }
    destroy() {
      if (this._activeBg && this._activeBg.parentNode) {
        this._activeBg.remove();
      }
      if (this._activeItem) {
        this._activeItem.classList.remove("svf-swipe-active", "svf-swipe-transition");
        this._activeItem.style.transform = "";
        this._activeItem.style.backgroundColor = "";
      }
      this._activeItem = null;
      this._activeBg = null;
    }
  }
  const r$1 = (o2) => void 0 === o2.strings;
  const s = (i3, t2) => {
    const e2 = i3._$AN;
    if (void 0 === e2) return false;
    for (const i4 of e2) i4._$AO?.(t2, false), s(i4, t2);
    return true;
  }, o$1 = (i3) => {
    let t2, e2;
    do {
      if (void 0 === (t2 = i3._$AM)) break;
      e2 = t2._$AN, e2.delete(i3), i3 = t2;
    } while (0 === e2?.size);
  }, r = (i3) => {
    for (let t2; t2 = i3._$AM; i3 = t2) {
      let e2 = t2._$AN;
      if (void 0 === e2) t2._$AN = e2 = /* @__PURE__ */ new Set();
      else if (e2.has(i3)) break;
      e2.add(i3), c(t2);
    }
  };
  function h(i3) {
    void 0 !== this._$AN ? (o$1(this), this._$AM = i3, r(this)) : this._$AM = i3;
  }
  function n$1(i3, t2 = false, e2 = 0) {
    const r2 = this._$AH, h2 = this._$AN;
    if (void 0 !== h2 && 0 !== h2.size) if (t2) if (Array.isArray(r2)) for (let i4 = e2; i4 < r2.length; i4++) s(r2[i4], false), o$1(r2[i4]);
    else null != r2 && (s(r2, false), o$1(r2));
    else s(this, i3);
  }
  const c = (i3) => {
    i3.type == t.CHILD && (i3._$AP ??= n$1, i3._$AQ ??= h);
  };
  class f extends i2 {
    constructor() {
      super(...arguments), this._$AN = void 0;
    }
    _$AT(i3, t2, e2) {
      super._$AT(i3, t2, e2), r(this), this.isConnected = i3._$AU;
    }
    _$AO(i3, t2 = true) {
      i3 !== this.isConnected && (this.isConnected = i3, i3 ? this.reconnected?.() : this.disconnected?.()), t2 && (s(this, i3), o$1(this));
    }
    setValue(t2) {
      if (r$1(this._$Ct)) this._$Ct._$AI(t2, this);
      else {
        const i3 = [...this._$Ct._$AH];
        i3[this._$Ci] = t2, this._$Ct._$AI(i3, this, 0);
      }
    }
    disconnected() {
    }
    reconnected() {
    }
  }
  const o = /* @__PURE__ */ new WeakMap(), n2 = e$1(class extends f {
    render(i3) {
      return A;
    }
    update(i3, [s2]) {
      const e2 = s2 !== this.G;
      return e2 && this.rt(void 0), (e2 || this.lt !== this.ct) && (this.G = s2, this.ht = i3.options?.host, this.rt(this.ct = i3.element)), A;
    }
    rt(t2) {
      if (void 0 !== this.G) if (this.isConnected || (t2 = void 0), "function" == typeof this.G) {
        const i3 = this.ht ?? globalThis;
        let s2 = o.get(i3);
        void 0 === s2 && (s2 = /* @__PURE__ */ new WeakMap(), o.set(i3, s2)), void 0 !== s2.get(this.G) && this.G.call(this.ht, void 0), s2.set(this.G, t2), void 0 !== t2 && this.G.call(this.ht, t2);
      } else this.G.value = t2;
    }
    get lt() {
      return "function" == typeof this.G ? o.get(this.ht ?? globalThis)?.get(this.G) : this.G?.value;
    }
    disconnected() {
      this.lt === this.ct && this.rt(void 0);
    }
    reconnected() {
      this.rt(this.ct);
    }
  });
  function parseJsonRobust(text) {
    if (text.charCodeAt(0) === 65279) {
      text = text.slice(1);
    }
    let inString = false;
    let escape = false;
    let out = "";
    let lastCommaIdx = -1;
    for (let i3 = 0; i3 < text.length; i3++) {
      const char = text[i3];
      if (inString) {
        out += char;
        if (escape) {
          escape = false;
        } else if (char === "\\") {
          escape = true;
        } else if (char === '"') {
          inString = false;
        }
      } else {
        if (char === "/" && text[i3 + 1] === "/") {
          while (i3 < text.length && text[i3] !== "\n" && text[i3] !== "\r") {
            i3++;
          }
          out += "\n";
        } else if (char === "/" && text[i3 + 1] === "*") {
          i3 += 2;
          while (i3 < text.length && !(text[i3] === "*" && text[i3 + 1] === "/")) {
            i3++;
          }
          i3++;
        } else {
          if (char === '"') {
            inString = true;
          }
          if (char === ",") {
            lastCommaIdx = out.length;
            out += char;
          } else if ((char === "}" || char === "]") && lastCommaIdx !== -1) {
            let onlyWhitespace = true;
            for (let j = lastCommaIdx + 1; j < out.length; j++) {
              if (!/\s/.test(out[j])) {
                onlyWhitespace = false;
                break;
              }
            }
            if (onlyWhitespace) {
              out = out.slice(0, lastCommaIdx) + out.slice(lastCommaIdx + 1);
            }
            lastCommaIdx = -1;
            out += char;
          } else {
            if (!/\s/.test(char)) {
              lastCommaIdx = -1;
            }
            out += char;
          }
        }
      }
    }
    return JSON.parse(out);
  }
  function getRegisterableDomain(domain) {
    let clean = domain.toLowerCase().trim();
    if (clean.startsWith("*.")) {
      clean = clean.slice(2);
    }
    if (/^\d+\.\d+\.\d+\.\d+$/.test(clean)) {
      return clean;
    }
    const parts = clean.split(".");
    if (parts.length <= 2) return clean;
    const tld = parts[parts.length - 1];
    const sld = parts[parts.length - 2];
    const isCcTld = tld.length === 2;
    const isCommonSld = /^(co|com|org|net|gov|edu|ac|or|ne|ltd|plc|sch|asn)$/.test(sld);
    if (isCcTld && isCommonSld && parts.length >= 3) {
      return parts.slice(-3).join(".");
    }
    return parts.slice(-2).join(".");
  }
  const PANEL_CSS = ':host{--svf-bg: rgba(18, 18, 22, .85);--svf-border: rgba(255, 255, 255, .08);--svf-border-hover: rgba(255, 255, 255, .16);--svf-primary: #10b981;--svf-primary-glow: rgba(16, 185, 129, .15);--svf-primary-bg-hover: rgba(16, 185, 129, .08);--svf-primary-border: rgba(16, 185, 129, .25);--svf-primary-status-bg: rgba(16, 185, 129, .1);--svf-danger: #ef4444;--svf-text: #f3f4f6;--svf-text-muted: #9ca3af;--svf-font: "Outfit", "Inter", system-ui, -apple-system, sans-serif;--svf-glow: 0 24px 50px rgba(0, 0, 0, .6);user-select:none;-webkit-user-select:none}*,*:before,*:after{box-sizing:border-box}.svf-color-picker-row{display:flex;gap:10px;margin-bottom:6px;padding:4px 0}.svf-color-dot{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .2s cubic-bezier(.4,0,.2,1)}.svf-color-dot:hover{transform:scale(1.15)}.svf-color-dot.active{border-color:#fff;box-shadow:0 0 10px var(--dot-glow)}.svf-backdrop{position:fixed;inset:0;background:#0009;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .3s ease,visibility .3s ease;will-change:opacity;z-index:2147483645}.svf-backdrop.open{opacity:1;visibility:visible;pointer-events:auto}.svf-card{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(.9);width:90%;max-width:480px;max-height:85vh;background:var(--svf-bg);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);border:1px solid var(--svf-border);border-radius:20px;box-shadow:var(--svf-glow);color:var(--svf-text);display:flex;flex-direction:column;overflow:hidden;opacity:0;visibility:hidden;pointer-events:none;transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .3s ease,visibility .3s ease;will-change:transform,opacity;z-index:2147483646;font-family:var(--svf-font)}.svf-card.open{transform:translate(-50%,-50%) scale(1);opacity:1;visibility:visible;pointer-events:auto}.svf-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid var(--svf-border)}.svf-title-group{display:flex;flex-direction:column}.svf-title{font-size:20px;font-weight:800;letter-spacing:-.4px;background:linear-gradient(135deg,#ffffff 15%,var(--svf-primary) 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}.svf-close-btn{background:transparent;border:none;color:#ef4444b3;cursor:pointer;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;transition:background .2s ease,color .2s ease,transform .2s ease;padding:0}.svf-close-btn:hover{background:#ef44441f;color:var(--svf-danger);transform:rotate(90deg)}.svf-body{padding:24px;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:24px;max-height:calc(85vh - 140px)}.svf-control-group{display:flex;flex-direction:column;gap:8px}.svf-label{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--svf-text-muted)}.svf-segmented{display:flex;background:#0000004d;border:1px solid var(--svf-border);padding:4px;border-radius:12px}.svf-seg-btn{flex:1;background:transparent;border:none;color:var(--svf-text-muted);padding:9px 16px;font-size:13px;font-weight:600;border-radius:9px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);font-family:var(--svf-font)}.svf-seg-btn.active{background:var(--svf-primary);color:#0c0d10;box-shadow:0 4px 12px var(--svf-primary-glow);font-weight:700}.svf-section{display:flex;flex-direction:column;gap:12px}.svf-section-header{display:flex;justify-content:space-between;align-items:center}.svf-badge{font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;background:#ffffff14}.svf-section.liked .svf-badge{background:var(--svf-primary-glow);color:var(--svf-primary)}.svf-section.disliked .svf-badge{background:#ef444426;color:var(--svf-danger)}.svf-textarea{width:100%;height:120px;background:#00000059;border:1px solid var(--svf-border);border-radius:12px;padding:10px 12px;color:var(--svf-text);font-family:var(--svf-mono, monospace);font-size:12.5px;line-height:1.5;resize:none;outline:none;transition:border-color .2s ease,box-shadow .2s ease;overflow-x:hidden;white-space:pre-wrap;word-break:break-all}.svf-textarea:focus{border-color:var(--svf-primary);box-shadow:0 0 0 2px var(--svf-primary-glow)}.svf-textarea-status-row{display:flex;justify-content:space-between;align-items:center;margin-top:6px}.svf-textarea-msg-info{font-size:11px;color:var(--svf-text-muted)}.svf-apply-btn{background:var(--svf-primary-bg-hover);border:1px solid var(--svf-primary-border);color:var(--svf-primary);padding:6px 14px;border-radius:8px;font-family:var(--svf-font);font-size:12px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.svf-apply-btn:hover{background:var(--svf-primary);border-color:var(--svf-primary);color:#0c0d10;box-shadow:0 0 12px var(--svf-primary-glow)}.svf-merger-card{background:#f59e0b14;border:1px solid rgba(245,158,11,.25);border-radius:12px;padding:10px 14px;display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;box-shadow:0 4px 12px #f59e0b0d;animation:svf-fade-in .25s cubic-bezier(.4,0,.2,1)}@keyframes svf-fade-in{0%{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:translateY(0)}}.svf-merger-info{display:flex;flex-direction:column;gap:2px}.svf-merger-title{font-size:12px;font-weight:700;color:#f59e0b}.svf-merger-desc{font-size:11px;color:var(--svf-text-muted)}.svf-merger-btn{background:#f59e0b;border:none;color:#0f1015;padding:6px 12px;border-radius:8px;font-family:var(--svf-font);font-size:11.5px;font-weight:700;cursor:pointer;transition:all .2s;box-shadow:0 2px 6px #f59e0b4d;flex-shrink:0}.svf-merger-btn:hover{opacity:.95;transform:translateY(-1px);box-shadow:0 4px 10px #f59e0b80}.svf-io-section{display:flex;flex-direction:column;gap:12px;border-top:1px solid var(--svf-border);padding-top:20px}.svf-io-row{display:flex;gap:8px}.svf-io-btn{flex:1;border:1px solid var(--svf-border);background:#ffffff08;color:var(--svf-text);border-radius:12px;padding:10px 14px;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);font-family:var(--svf-font);display:flex;align-items:center;justify-content:center;gap:8px}.svf-io-btn:hover{background:#ffffff14;border-color:var(--svf-border-hover);box-shadow:0 4px 12px #00000026}.svf-io-btn:active{transform:scale(.97)}.svf-io-btn.primary{background:var(--svf-primary-bg-hover);border-color:var(--svf-primary-border);color:var(--svf-primary)}.svf-io-btn.primary:hover{background:var(--svf-primary);border-color:var(--svf-primary);color:#0c0d10;box-shadow:0 4px 12px var(--svf-primary-glow)}.svf-io-url-form{display:flex;gap:8px}.svf-io-url-input{flex:1;background:#00000040;border:1px solid var(--svf-border);color:var(--svf-text);border-radius:12px;padding:10px 14px;font-size:12.5px;outline:none;transition:all .2s;font-family:var(--svf-font)}.svf-io-url-input:focus{border-color:#fff3;box-shadow:0 0 0 2px #ffffff0d}.svf-io-status{font-size:11.5px;padding:6px 10px;border-radius:8px;transition:opacity .3s}.svf-io-status.success{background:var(--svf-primary-status-bg);color:var(--svf-primary)}.svf-io-status.error{background:#ef44441a;color:var(--svf-danger)}.svf-io-file{display:none}.svf-body::-webkit-scrollbar,.svf-textarea::-webkit-scrollbar,.svf-filtered-list::-webkit-scrollbar{width:6px;height:6px}.svf-body::-webkit-scrollbar-track,.svf-textarea::-webkit-scrollbar-track,.svf-filtered-list::-webkit-scrollbar-track{background:transparent}.svf-body::-webkit-scrollbar-thumb,.svf-textarea::-webkit-scrollbar-thumb,.svf-filtered-list::-webkit-scrollbar-thumb{background:#ffffff26;border-radius:3px}.svf-body::-webkit-scrollbar-thumb:hover,.svf-textarea::-webkit-scrollbar-thumb:hover,.svf-filtered-list::-webkit-scrollbar-thumb:hover{background:#ffffff4d}.svf-body,.svf-textarea,.svf-filtered-list{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}.svf-switch-row{display:flex;justify-content:space-between;align-items:center;padding:6px 0}.svf-switch-label-group{display:flex;flex-direction:column}.svf-switch-title{font-size:13px;font-weight:600;color:var(--svf-text)}.svf-switch-desc{font-size:11px;color:var(--svf-text-muted);margin-top:1px}.svf-switch{position:relative;display:inline-block;width:40px;height:22px;flex-shrink:0}.svf-switch input{opacity:0;width:0;height:0}.svf-slider{position:absolute;cursor:pointer;inset:0;background-color:#ffffff14;border:1px solid var(--svf-border);transition:.3s cubic-bezier(.4,0,.2,1);border-radius:34px}.svf-slider:before{position:absolute;content:"";height:14px;width:14px;left:3px;bottom:3px;background-color:var(--svf-text-muted);transition:.3s cubic-bezier(.4,0,.2,1);border-radius:50%}input:checked+.svf-slider{background-color:var(--svf-primary);border-color:var(--svf-primary)}input:checked+.svf-slider:before{transform:translate(18px);background-color:#0c0d10}@keyframes svf-shake{0%,to{transform:translate(0)}25%{transform:translate(-4px)}75%{transform:translate(4px)}}.svf-io-url-input.invalid{border-color:var(--svf-danger)!important;animation:svf-shake .2s ease-in-out 2}.svf-tab-nav{display:flex;background:#00000026;border-bottom:1px solid var(--svf-border);padding:0 12px}.svf-tab-btn{flex:1;background:transparent;border:none;color:var(--svf-text-muted);padding:14px 8px;font-family:var(--svf-font);font-weight:600;font-size:12.5px;cursor:pointer;border-bottom:2px solid transparent;transition:all .2s ease;text-align:center;white-space:nowrap}.svf-tab-btn:hover{color:var(--svf-text)}.svf-tab-btn.active{color:var(--svf-primary);border-bottom-color:var(--svf-primary)}.svf-tab-content{display:flex;flex-direction:column;gap:20px;width:100%}.svf-search-wrapper{position:relative;display:flex;align-items:center;margin-bottom:2px}.svf-search-input{width:100%;background:#00000040;border:1px solid var(--svf-border);border-radius:12px;padding:10px 14px 10px 36px;color:var(--svf-text);font-family:var(--svf-font);font-size:13px;outline:none;transition:all .2s cubic-bezier(.4,0,.2,1)}.svf-search-input:focus{border-color:var(--svf-primary);box-shadow:0 0 0 2px var(--svf-primary-glow)}.svf-search-icon{position:absolute;left:14px;color:var(--svf-text-muted);pointer-events:none;display:flex;align-items:center;justify-content:center}.svf-clear-btn{position:absolute;right:12px;background:transparent;border:none;color:var(--svf-text-muted);cursor:pointer;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;transition:background .2s,color .2s;padding:0}.svf-clear-btn:hover{background:#ffffff14;color:#fff}.svf-filtered-list{display:flex;flex-direction:column;gap:8px;background:#00000026;border:1px solid var(--svf-border);border-radius:12px;padding:10px;max-height:180px;overflow-y:auto;scrollbar-width:thin}.svf-filtered-item{background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:8px;padding:8px 12px;display:flex;align-items:center;justify-content:space-between;font-family:var(--svf-mono, monospace);font-size:12px;transition:all .2s cubic-bezier(.4,0,.2,1)}.svf-filtered-item:hover{background:#ffffff0a;border-color:var(--svf-border-hover)}.svf-filtered-text{color:var(--svf-text);word-break:break-all}.svf-filtered-actions{display:flex;gap:6px;flex-shrink:0}.svf-filtered-btn{background:transparent;border:none;color:var(--svf-text-muted);cursor:pointer;width:28px;height:28px;border-radius:6px;display:grid;place-items:center;transition:all .15s ease;padding:0}.svf-filtered-btn:hover{color:#fff;background:#ffffff14}.svf-filtered-btn.delete:hover{color:var(--svf-danger);background:#ef44441a}.svf-filtered-input{width:100%;background:#00000080;border:1px solid var(--svf-primary);border-radius:6px;padding:4px 8px;color:#fff;font-family:var(--svf-mono, monospace);font-size:12px;outline:none}.svf-filtered-empty{padding:12px;font-size:12px;color:var(--svf-text-muted);text-align:center}.svf-textarea,.svf-search-input,.svf-filtered-input,.svf-io-url-input,.svf-sync-input{user-select:text;-webkit-user-select:text}.svf-sync-section{display:flex;flex-direction:column;gap:12px}.svf-sync-field{display:flex;flex-direction:column;gap:4px}.svf-sync-field-label{font-size:11px;font-weight:600;color:var(--svf-text-muted)}.svf-sync-input-row{display:flex;position:relative;align-items:center;width:100%}.svf-sync-input{width:100%;background:#00000040;border:1px solid var(--svf-border);color:var(--svf-text);border-radius:12px;padding:10px 40px 10px 14px;font-size:12.5px;outline:none;transition:all .2s;font-family:var(--svf-font)}#svf-sync-gistid{padding-right:14px}.svf-sync-input:focus{border-color:var(--svf-primary);box-shadow:0 0 0 2px var(--svf-primary-glow)}.svf-sync-icon-btn{position:absolute;right:8px;background:transparent;border:none;color:var(--svf-text-muted);cursor:pointer;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;transition:background .2s,color .2s;padding:0}.svf-sync-icon-btn:hover{background:#ffffff14;color:#fff}.svf-sync-actions-row{display:flex;gap:8px;margin-top:4px}.svf-io-btn:disabled,.svf-switch input:disabled+.svf-slider{opacity:.4;cursor:not-allowed;pointer-events:none}';
  var __defProp$1 = Object.defineProperty;
  var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
  var __decorateClass$1 = (decorators, target, key, kind) => {
    var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
    for (var i3 = decorators.length - 1, decorator; i3 >= 0; i3--)
      if (decorator = decorators[i3])
        result = (kind ? decorator(target, key, result) : decorator(result)) || result;
    if (kind && result) __defProp$1(target, key, result);
    return result;
  };
  let PanelElement = class extends i$1 {
    constructor() {
      super(...arguments);
      this._isOpen = false;
      this._activeTab = "filters";
      this._searchQuery = "";
      this._ioStatus = null;
      this._isFetchingUrl = false;
      this._isSyncing = false;
      this._syncStatus = null;
      this._tokenVisible = false;
      this._likedText = "";
      this._dislikedText = "";
      this._editingMatches = {};
      this._lastActiveElement = null;
      this._isTextareaFocused = { liked: false, disliked: false };
      this._handleKeydown = (e2) => {
        if (!this._isOpen) return;
        if (e2.key === "Escape") {
          this.close();
        } else if (e2.key === "Tab") {
          this._handleTab(e2);
        }
      };
    }
    connectedCallback() {
      super.connectedCallback();
      if (!document.querySelector('link[href*="fonts.googleapis.com/css2?family=Outfit"]')) {
        const fontLink = document.createElement("link");
        fontLink.rel = "stylesheet";
        fontLink.href = "https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap";
        document.head.appendChild(fontLink);
      }
      this.style.display = "none";
      this._unsubscribe?.();
      if (this.store) {
        this._syncTextFromStore();
        this._unsubscribe = this.store.subscribe(() => {
          this.requestUpdate();
          this._syncTextFromStore();
        });
      }
      window.removeEventListener("keydown", this._handleKeydown);
      window.addEventListener("keydown", this._handleKeydown);
    }
    disconnectedCallback() {
      super.disconnectedCallback();
      this._unsubscribe?.();
      window.removeEventListener("keydown", this._handleKeydown);
    }
    _syncTextFromStore() {
      if (!this._isTextareaFocused.liked) {
        this._likedText = this.store.liked.join("\n");
      }
      if (!this._isTextareaFocused.disliked) {
        this._dislikedText = this.store.disliked.join("\n");
      }
    }
    updated(changedProperties) {
      super.updated(changedProperties);
      if (this.store) {
        applyAccentVariables(this, this.store.accent);
      }
      const textChanged = changedProperties.has("_likedText") || changedProperties.has("_dislikedText");
      const tabChangedToFilters = changedProperties.has("_activeTab") && this._activeTab === "filters";
      const panelOpened = changedProperties.has("_isOpen") && this._isOpen;
      if (textChanged || tabChangedToFilters || panelOpened) {
        if (this._activeTab === "filters") {
          const delay = panelOpened ? 200 : 0;
          if (this._likedTextarea) this._autoResize(this._likedTextarea, delay);
          if (this._dislikedTextarea) this._autoResize(this._dislikedTextarea, delay);
        }
      }
    }
    open() {
      this.style.display = "block";
      this.offsetHeight;
      this._lastActiveElement = document.activeElement;
      this._isOpen = true;
      this._syncTextFromStore();
      setTimeout(() => {
        this._closeBtn?.focus();
      }, 50);
    }
    close() {
      this._isOpen = false;
      if (this._lastActiveElement) {
        this._lastActiveElement.focus();
        this._lastActiveElement = null;
      }
      const card = this.shadowRoot?.querySelector(".svf-card");
      if (card) {
        card.addEventListener("transitionend", (e2) => {
          if (!this._isOpen && e2.propertyName === "opacity") {
            this.style.display = "none";
          }
        }, { once: true });
      } else {
        this.style.display = "none";
      }
    }
    isOpen() {
      return this._isOpen;
    }
    _handleTab(e2) {
      const focusables = Array.from(
        this.shadowRoot.querySelectorAll(
          'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
        )
      ).filter((el) => {
        if (el.disabled) return false;
        const rect = el.getBoundingClientRect();
        if (rect.width === 0 || rect.height === 0) return false;
        const style = window.getComputedStyle(el);
        return style.visibility !== "hidden" && style.opacity !== "0";
      });
      if (focusables.length === 0) return;
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      const active = this.shadowRoot.activeElement;
      if (e2.shiftKey) {
        if (active === first || !focusables.includes(active)) {
          last.focus();
          e2.preventDefault();
        }
      } else {
        if (active === last || !focusables.includes(active)) {
          first.focus();
          e2.preventDefault();
        }
      }
    }
    render() {
      return b`
            <div class="svf-backdrop ${this._isOpen ? "open" : ""}" @click=${this.close}></div>
            <div class="svf-card ${this._isOpen ? "open" : ""}">
                <div class="svf-header">
                    <div class="svf-title-group">
                        <div class="svf-title">Better Search ⭐</div>
                    </div>
                    <button class="svf-close-btn" @click=${this.close}>${o$2(ICON_CLOSE)}</button>
                </div>
                
                <div class="svf-tab-nav">
                    <button class="svf-tab-btn ${this._activeTab === "filters" ? "active" : ""}" @click=${() => this._activeTab = "filters"}>Domain Filter</button>
                    <button class="svf-tab-btn ${this._activeTab === "io" ? "active" : ""}" @click=${() => this._activeTab = "io"}>Import/Export/Sync</button>
                    <button class="svf-tab-btn ${this._activeTab === "settings" ? "active" : ""}" @click=${() => this._activeTab = "settings"}>Settings</button>
                </div>
                
                <div class="svf-body">
                    <div class="svf-tab-content ${this._activeTab === "filters" ? "active" : ""}" style="display: ${this._activeTab === "filters" ? "flex" : "none"}">
                        ${this._renderFiltersTab()}
                    </div>
                    <div class="svf-tab-content ${this._activeTab === "io" ? "active" : ""}" style="display: ${this._activeTab === "io" ? "flex" : "none"}">
                        ${this._renderIOTab()}
                    </div>
                    <div class="svf-tab-content ${this._activeTab === "settings" ? "active" : ""}" style="display: ${this._activeTab === "settings" ? "flex" : "none"}">
                        ${this._renderSettingsTab()}
                    </div>
                </div>
            </div>
        `;
    }
    _renderFiltersTab() {
      return b`
            <div class="svf-search-wrapper">
                <span class="svf-search-icon">${o$2(ICON_SEARCH)}</span>
                <input type="text" id="svf-unified-search" class="svf-search-input" placeholder="Filter all domains (e.g. github)..." .value=${this._searchQuery} @input=${(e2) => this._searchQuery = e2.target.value.trim().toLowerCase()}>
                <button type="button" class="svf-clear-btn" style="display: ${this._searchQuery ? "block" : "none"}" @click=${() => {
      this._searchQuery = "";
      this.shadowRoot?.querySelector("#svf-unified-search")?.focus();
    }}>
                    ${o$2(ICON_CLEAR)}
                </button>
            </div>
            ${this._renderSection("liked", "Preferred Domains")}
            ${this._renderSection("disliked", "Disliked Domains")}
        `;
    }
    _renderSection(type, titleText) {
      const domains = type === "liked" ? this.store.liked : this.store.disliked;
      const textValue = type === "liked" ? this._likedText : this._dislikedText;
      const lines = this._getLines(textValue);
      const uniques = new Set(lines);
      const duplicateCount = lines.length - uniques.size;
      let proposalFound = false;
      let activeProposal = null;
      if (!this._searchQuery) {
        const tree = {};
        lines.forEach((dom) => {
          const root = getRegisterableDomain(dom);
          if (!tree[root]) tree[root] = [];
          tree[root].push(dom);
        });
        for (const root of Object.keys(tree)) {
          const subCount = tree[root].length;
          const isWildcardRule = tree[root].includes(`*.${root}`);
          if (subCount >= 3 && !isWildcardRule) {
            activeProposal = root;
            proposalFound = true;
            break;
          }
        }
      }
      const matches = this._searchQuery ? domains.filter((d2) => d2.toLowerCase().includes(this._searchQuery)) : [];
      const badgeText = this._searchQuery ? `${matches.length} match${matches.length !== 1 ? "es" : ""}` : String(domains.length);
      return b`
            <div class="svf-section ${type}">
                <div class="svf-section-header">
                    <div class="svf-label">${titleText}</div>
                    <span class="svf-badge" id="svf-${type}-count">${badgeText}</span>
                </div>
                
                ${!this._searchQuery && proposalFound && activeProposal ? b`
                    <div class="svf-merger-card" id="svf-${type}-proposal-card" style="display: flex">
                        <div class="svf-merger-info">
                            <div class="svf-merger-title">💡 Wildcard Suggestion</div>
                            <div class="svf-merger-desc">${lines.filter((l2) => getRegisterableDomain(l2) === activeProposal).length} subdomains of '${activeProposal}' found. Merge to *.${activeProposal}?</div>
                        </div>
                        <button class="svf-merger-btn" type="button" @click=${() => {
      const rule = `*.${activeProposal}`;
      const filtered = lines.filter((line) => getRegisterableDomain(line) !== activeProposal);
      if (!filtered.includes(rule)) filtered.push(rule);
      this._saveAndReapply(type, filtered);
      if (type === "liked") this._likedText = filtered.join("\n");
      else this._dislikedText = filtered.join("\n");
    }}>Consolidate</button>
                    </div>
                ` : A}
                
                ${this._searchQuery ? b`
                    <div class="svf-filtered-list" id="svf-${type}-filtered-list" style="display: flex">
                        ${matches.length === 0 ? b`
                            <div class="svf-filtered-empty">No matching domains</div>
                        ` : matches.map((match) => {
      const isEditing = this._editingMatches[`${type}:${match}`] !== void 0;
      return b`
                                <div class="svf-filtered-item">
                                    ${isEditing ? b`
                                        <input type="text" class="svf-filtered-input" .value=${this._editingMatches[`${type}:${match}`]}
                                            @blur=${(e2) => this._saveEdit(type, match, e2.target.value)}
                                            @keydown=${(e2) => {
        if (e2.key === "Enter") this._saveEdit(type, match, e2.target.value);
        if (e2.key === "Escape") this._cancelEdit(type, match);
      }}
                                            ${n2((el) => {
        if (el) setTimeout(() => el.focus(), 0);
      })}
                                        >
                                    ` : b`
                                        <span class="svf-filtered-text">${match}</span>
                                        <div class="svf-filtered-actions">
                                            <button type="button" class="svf-filtered-btn" title="Edit" @click=${() => this._startEdit(type, match)}>
                                                ${o$2(ICON_EDIT)}
                                            </button>
                                            <button type="button" class="svf-filtered-btn delete" title="Remove" @click=${() => this._deleteMatch(type, match)}>
                                                ${o$2(ICON_DELETE)}
                                            </button>
                                        </div>
                                    `}
                                </div>
                            `;
    })}
                    </div>
                ` : b`
                        <textarea class="svf-textarea" id="svf-${type}-textarea" placeholder="e.g.\nstackoverflow.com\ngithub.com"
                        style="display: block"
                        .value=${textValue}
                        @input=${(e2) => {
      if (type === "liked") this._likedText = e2.target.value;
      else this._dislikedText = e2.target.value;
    }}
                        @focus=${() => this._isTextareaFocused[type] = true}
                        @blur=${() => {
      this._isTextareaFocused[type] = false;
    }}
                    ></textarea>
                    
                    <div class="svf-textarea-status-row" style="display: flex">
                        <div class="svf-textarea-msg-info" id="svf-${type}-msg-info">
                            ${duplicateCount > 0 ? b`<span style="color: var(--svf-danger)">⚠️ ${duplicateCount} duplicates found (will merge on apply)</span>` : b`${lines.length} domains configured`}
                        </div>
                        <button class="svf-apply-btn" id="svf-${type}-apply" type="button" @click=${() => this._saveAndReapply(type, lines)}>
                            Apply Changes
                        </button>
                    </div>
                `}
            </div>
        `;
    }
    _renderSettingsTab() {
      const accent = this.store.accent;
      const mode = this.store.dislikeMode;
      return b`
            <div class="svf-control-group">
                <div class="svf-label">Dislike Filter Mode</div>
                <div class="svf-segmented">
                    <button class="svf-seg-btn ${mode === "fade" ? "active" : ""}" @click=${() => {
      this.store.setDislikeMode("fade");
      this.scanner.reapply();
    }}>Fade Results</button>
                    <button class="svf-seg-btn ${mode === "hide" ? "active" : ""}" @click=${() => {
      this.store.setDislikeMode("hide");
      this.scanner.reapply();
    }}>Hide (Reveal-on-click)</button>
                </div>
            </div>

            <div class="svf-control-group">
                <div class="svf-label">Theme Accent Color</div>
                <div class="svf-color-picker-row">
                    ${Object.keys(ACCENT_COLORS).map((name) => {
      const acc = ACCENT_COLORS[name];
      return b`
                            <div class="svf-color-dot ${name === accent ? "active" : ""}" data-accent="${name}" style="background-color: ${acc.primary}; --dot-glow: ${acc.dotGlow}" @click=${() => this.store.setAccent(name)}></div>
                        `;
    })}
                </div>
            </div>

            <div class="svf-control-group">
                <div class="svf-label">Preferences</div>
                <div class="svf-switch-row">
                    <div class="svf-switch-label-group">
                        <div class="svf-switch-title">Show floating button</div>
                        <div class="svf-switch-desc">Toggle settings icon visibility in the bottom right</div>
                    </div>
                    <label class="svf-switch">
                        <input type="checkbox" id="svf-pref-show-trigger" .checked=${this.store.showTrigger} @change=${(e2) => this.store.setShowTrigger(e2.target.checked)}>
                        <span class="svf-slider"></span>
                    </label>
                </div>
            </div>
        `;
    }
    _renderIOTab() {
      return b`
            <div class="svf-io-section" style="border-top: none; padding-top: 0">
                <div class="svf-label">Import / Export File</div>
                
                <div class="svf-io-row">
                    <input type="file" accept=".json,application/json" class="svf-io-file" id="svf-io-file" @change=${this._importFile}>
                    <button class="svf-io-btn" @click=${() => this.shadowRoot?.querySelector("#svf-io-file")?.click()}>
                        ${o$2(ICON_IMPORT)} Import File
                    </button>
                    <button class="svf-io-btn" @click=${this._downloadJson}>
                        ${o$2(ICON_DOWNLOAD)} Export File
                    </button>
                </div>

                <div class="svf-label" style="margin-top: 4px">Import from Gist</div>
                <form class="svf-io-url-form" @submit=${(e2) => {
      e2.preventDefault();
      this._quickImportGist();
    }}>
                    <input type="url" class="svf-io-url-input" id="svf-io-url-input" .value=${SVF_CONFIG.GIST_IMPORT_URL} placeholder="https://gist.githubusercontent.com/…/domains.json" ?disabled=${this._isFetchingUrl} @input=${(e2) => e2.target.classList.remove("invalid")}>
                    <button type="submit" class="svf-io-btn primary" id="svf-url-fetch-btn" style="flex: 0 0 auto" ?disabled=${this._isFetchingUrl}>${this._isFetchingUrl ? "Importing..." : "Import"}</button>
                </form>
                
                ${this._ioStatus ? b`<div class="svf-io-status ${this._ioStatus.type}" style="display: block">${this._ioStatus.msg}</div>` : b`<div class="svf-io-status" style="display: none"></div>`}
            </div>

            <div class="svf-io-section svf-sync-section">
                <div class="svf-label">Gist Sync (optional)</div>
                <div class="svf-sync-field">
                    <div class="svf-sync-field-label">GitHub Token</div>
                    <div class="svf-sync-input-row">
                        <input type="${this._tokenVisible ? "text" : "password"}" 
                               id="svf-sync-token" 
                               class="svf-sync-input" 
                               .value=${this.store.gistToken} 
                               placeholder="ghp_..."
                               @change=${(e2) => {
      this.store.setGistToken(e2.target.value);
      this.gistSync.enableAutoSync();
    }}>
                        <button class="svf-sync-icon-btn" @click=${() => this._tokenVisible = !this._tokenVisible}>
                            ${o$2(this._tokenVisible ? ICON_EYE_OFF : ICON_EYE)}
                        </button>
                    </div>
                </div>

                <div class="svf-sync-field">
                    <div class="svf-sync-field-label">Gist ID</div>
                    <div class="svf-sync-input-row">
                        <input type="text" 
                               id="svf-sync-gistid" 
                               class="svf-sync-input" 
                               .value=${this.store.gistId} 
                               placeholder="Leave empty to create new"
                               @change=${(e2) => {
      this.store.setGistId(e2.target.value);
      this.gistSync.enableAutoSync();
    }}>
                    </div>
                </div>

                <div class="svf-sync-actions-row">
                    <button class="svf-io-btn primary" @click=${this._syncPull} ?disabled=${this._isSyncing || !this.store.gistToken || !this.store.gistId}>
                        Pull (Replace)
                    </button>
                    <button class="svf-io-btn primary" @click=${this._syncPush} ?disabled=${this._isSyncing || !this.store.gistToken}>
                        Push (Merge)
                    </button>
                </div>

                <div class="svf-switch-row" style="margin-top: 12px; border-top: 1px solid var(--svf-border); padding-top: 12px;">
                    <div class="svf-switch-label-group">
                        <div class="svf-switch-title">Auto-sync</div>
                        <div class="svf-switch-desc">Push 10s after changes · Pull every 1hr · Pull before push</div>
                    </div>
                    <label class="svf-switch">
                        <input type="checkbox" 
                               id="svf-sync-enabled" 
                               .checked=${this.store.syncEnabled} 
                               ?disabled=${!this.store.gistToken}
                               @change=${(e2) => {
      const en = e2.target.checked;
      this.store.setSyncEnabled(en);
      if (en) this.gistSync.enableAutoSync();
      else this.gistSync.disableAutoSync();
    }}>
                        <span class="svf-slider"></span>
                    </label>
                </div>

                ${this._syncStatus ? b`<div class="svf-io-status ${this._syncStatus.type}" style="display: block">${this._syncStatus.msg}</div>` : A}
            </div>
        `;
    }
    _showStatus(msg, type) {
      this._ioStatus = { msg, type };
      clearTimeout(this._ioTimeout);
      this._ioTimeout = window.setTimeout(() => {
        this._ioStatus = null;
      }, 3500);
    }
    _downloadJson() {
      const json = JSON.stringify(this.store.exportDomains(), null, 2);
      const blob = new Blob([json], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const a2 = document.createElement("a");
      a2.href = url;
      a2.download = "svf-domains.json";
      a2.click();
      URL.revokeObjectURL(url);
      this._showStatus("Downloaded svf-domains.json", "success");
    }
    _importFile(e2) {
      const fileInput = e2.target;
      const file = fileInput.files?.[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = () => {
        this._applyImport(reader.result, "file");
        fileInput.value = "";
      };
      reader.readAsText(file);
    }
    _quickImportGist() {
      const urlInput = this.shadowRoot?.querySelector("#svf-io-url-input");
      const url = urlInput?.value.trim() || SVF_CONFIG.GIST_IMPORT_URL;
      this._isFetchingUrl = true;
      this._fetchAndImport(url, () => {
        this._isFetchingUrl = false;
      });
    }
    _showSyncStatus(msg, type) {
      this._syncStatus = { msg, type };
      clearTimeout(this._syncStatusTimeout);
      this._syncStatusTimeout = window.setTimeout(() => {
        this._syncStatus = null;
      }, 4e3);
    }
    async _runSync(action, errPrefix) {
      this._isSyncing = true;
      try {
        const msg = await action();
        this._showSyncStatus(msg, "success");
      } catch (err) {
        this._showSyncStatus(err?.message || errPrefix, "error");
      } finally {
        this._isSyncing = false;
      }
    }
    _syncPull() {
      this._runSync(async () => {
        const count = await this.gistSync.pull("replace");
        this.scanner.reapply();
        return `Successfully pulled ${count} domains (replaced local lists)`;
      }, "Failed to pull from Gist");
    }
    _syncPush() {
      this._runSync(async () => {
        await this.gistSync.push();
        return "Successfully pushed domains to Gist";
      }, "Failed to push to Gist");
    }
    _applyImport(text, source) {
      try {
        const data = parseJsonRobust(text);
        const n3 = this.store.importDomains(data);
        this.scanner.reapply();
        const suffix = source === "url" ? " from URL" : "";
        this._showStatus(`Imported ${n3} new domain${n3 !== 1 ? "s" : ""}${suffix}`, "success");
      } catch {
        const errorMsg = source === "url" ? "Invalid JSON at URL" : "Invalid JSON file";
        this._showStatus(errorMsg, "error");
      }
    }
    _fetchAndImport(url, onDone) {
      const TIMEOUT_MS = 1e4;
      if (typeof GM_xmlhttpRequest === "function") {
        let timedOut = false;
        const timeoutId = setTimeout(() => {
          timedOut = true;
          this._showStatus("Request timed out", "error");
          onDone();
        }, TIMEOUT_MS);
        GM_xmlhttpRequest({
          method: "GET",
          url,
          timeout: TIMEOUT_MS,
          onload: (resp) => {
            if (timedOut) return;
            clearTimeout(timeoutId);
            if (resp.status >= 200 && resp.status < 300) {
              this._applyImport(resp.responseText, "url");
            } else {
              this._showStatus(`Fetch failed: ${resp.status} ${resp.statusText}`, "error");
            }
            onDone();
          },
          onerror: () => {
            if (timedOut) return;
            clearTimeout(timeoutId);
            this._showStatus("Network error fetching URL", "error");
            onDone();
          },
          ontimeout: () => {
            if (timedOut) return;
            clearTimeout(timeoutId);
            this._showStatus("Request timed out", "error");
            onDone();
          }
        });
      } else {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
        fetch(url, { signal: controller.signal }).then((r2) => {
          if (!r2.ok) throw new Error(String(r2.status));
          return r2.text();
        }).then((text) => {
          this._applyImport(text, "url");
        }).catch((err) => {
          if (err?.name === "AbortError") {
            this._showStatus("Request timed out", "error");
          } else {
            this._showStatus("Failed to fetch or parse URL", "error");
          }
        }).finally(() => {
          clearTimeout(timeoutId);
          onDone();
        });
      }
    }
    _startEdit(type, match) {
      this._editingMatches = { ...this._editingMatches, [`${type}:${match}`]: match };
    }
    _cancelEdit(type, match) {
      if (this._editingMatches[`${type}:${match}`] === void 0) return;
      const next = { ...this._editingMatches };
      delete next[`${type}:${match}`];
      this._editingMatches = next;
    }
    _saveEdit(type, oldMatch, newValRaw) {
      if (this._editingMatches[`${type}:${oldMatch}`] === void 0) return;
      const newVal = newValRaw.trim().toLowerCase();
      if (newVal && newVal !== oldMatch) {
        const domains = type === "liked" ? this.store.liked : this.store.disliked;
        const updated = domains.map((d2) => d2 === oldMatch ? newVal : d2);
        this._saveAndReapply(type, updated);
      }
      this._cancelEdit(type, oldMatch);
    }
    _deleteMatch(type, match) {
      const domains = type === "liked" ? this.store.liked : this.store.disliked;
      const updated = domains.filter((d2) => d2 !== match);
      this._saveAndReapply(type, updated);
    }
    _getLines(text) {
      return text.split("\n").map((l2) => l2.trim().toLowerCase()).filter(Boolean);
    }
    _saveAndReapply(type, domains) {
      const deduped = [...new Set(domains)];
      deduped.sort();
      this.store.setDomains(type, deduped);
      this.scanner.reapply();
    }
    _autoResize(textarea, delay = 0) {
      const resize = () => {
        if (!textarea) return;
        textarea.style.height = "auto";
        textarea.style.height = `${Math.min(Math.max(textarea.scrollHeight + 2, 60), 150)}px`;
      };
      if (delay > 0) setTimeout(resize, delay);
      else resize();
    }
  };
  PanelElement.styles = r$6(PANEL_CSS);
  __decorateClass$1([
    n$2({ attribute: false })
  ], PanelElement.prototype, "store", 2);
  __decorateClass$1([
    n$2({ attribute: false })
  ], PanelElement.prototype, "scanner", 2);
  __decorateClass$1([
    n$2({ attribute: false })
  ], PanelElement.prototype, "gistSync", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_isOpen", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_activeTab", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_searchQuery", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_ioStatus", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_isFetchingUrl", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_isSyncing", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_syncStatus", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_tokenVisible", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_likedText", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_dislikedText", 2);
  __decorateClass$1([
    r$2()
  ], PanelElement.prototype, "_editingMatches", 2);
  __decorateClass$1([
    e$2(".svf-close-btn")
  ], PanelElement.prototype, "_closeBtn", 2);
  __decorateClass$1([
    e$2("#svf-liked-textarea")
  ], PanelElement.prototype, "_likedTextarea", 2);
  __decorateClass$1([
    e$2("#svf-disliked-textarea")
  ], PanelElement.prototype, "_dislikedTextarea", 2);
  PanelElement = __decorateClass$1([
    t$1("svf-panel")
  ], PanelElement);
  const TRIGGER_CSS = ":host{user-select:none;-webkit-user-select:none}.svf-trigger{position:fixed;bottom:24px;right:24px;width:48px;height:48px;border-radius:50%;background:#121216d9;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.08);box-shadow:0 8px 32px #0000004d,0 0 0 1px #ffffff05;color:#ffffffb3;cursor:pointer;display:grid;place-items:center;z-index:2147483640;transition:transform .25s cubic-bezier(.25,.8,.25,1),border-color .2s ease,box-shadow .2s ease,color .2s ease;will-change:transform;pointer-events:auto;padding:0;outline:none}.svf-trigger:hover{transform:translateY(-3px) scale(1.05);border-color:var(--svf-primary);box-shadow:0 12px 36px var(--svf-primary-glow),0 0 0 1px var(--svf-primary-glow);color:var(--svf-primary)}.svf-trigger:active{transform:translateY(0) scale(.95)}.svf-trigger svg{transition:transform .4s ease}.svf-trigger:hover svg{transform:rotate(30deg) scale(1.05)}";
  var __defProp = Object.defineProperty;
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  var __decorateClass = (decorators, target, key, kind) => {
    var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
    for (var i3 = decorators.length - 1, decorator; i3 >= 0; i3--)
      if (decorator = decorators[i3])
        result = (kind ? decorator(target, key, result) : decorator(result)) || result;
    if (kind && result) __defProp(target, key, result);
    return result;
  };
  let TriggerElement = class extends i$1 {
    constructor() {
      super(...arguments);
      this._show = false;
    }
    updated(changedProperties) {
      super.updated(changedProperties);
      if (this.store) {
        applyAccentVariables(this, this.store.accent);
      }
    }
    connectedCallback() {
      super.connectedCallback();
      this._unsubscribe?.();
      if (this.store) {
        this._show = this.store.showTrigger;
        this._unsubscribe = this.store.subscribe(() => {
          this._show = this.store.showTrigger;
        });
      }
    }
    disconnectedCallback() {
      super.disconnectedCallback();
      this._unsubscribe?.();
    }
    render() {
      return b`
            <button
                class="svf-trigger"
                aria-label="Open Better Search Settings"
                title="Better Search Settings"
                style="display: ${this._show ? "grid" : "none"}"
                @click=${this._handleClick}
            >
                ${o$2(ICON_TRIGGER)}
            </button>
        `;
    }
    _handleClick(e2) {
      e2.stopPropagation();
      if (this.panel) {
        if (this.panel.isOpen()) {
          this.panel.close();
        } else {
          this.panel.open();
        }
      }
    }
  };
  TriggerElement.styles = r$6(TRIGGER_CSS);
  __decorateClass([
    n$2({ attribute: false })
  ], TriggerElement.prototype, "store", 2);
  __decorateClass([
    n$2({ attribute: false })
  ], TriggerElement.prototype, "panel", 2);
  __decorateClass([
    r$2()
  ], TriggerElement.prototype, "_show", 2);
  TriggerElement = __decorateClass([
    t$1("svf-trigger")
  ], TriggerElement);
  const GOOGLE_INTERNAL_HOSTS = /* @__PURE__ */ new Set([
    "www.google.com",
    "accounts.google.com",
    "maps.google.com",
    "webcache.googleusercontent.com"
  ]);
  function extractUrl$4(item) {
    const candidates = item.querySelectorAll("a[href]");
    for (const a2 of candidates) {
      const href = a2.href;
      if (!href || href.startsWith("javascript") || href.startsWith("#")) continue;
      try {
        const u2 = new URL(href);
        if (GOOGLE_INTERNAL_HOSTS.has(u2.hostname) || u2.pathname.startsWith("/search") || u2.hostname.includes("gstatic.")) {
          continue;
        }
        return href;
      } catch (err) {
        console.debug("[SVF] Skipped malformed Google result URL:", href, err);
      }
    }
    return null;
  }
  const googleEngine = {
    name: "google",
    // The element that contains all organic .g cards — stable across layout changes
    containerSelector: '#search, #rso, [data-async-context] [id="search"]',
    // Each organic result card
    itemSelector: ".g, .tF2Cxc, .MjjYud",
    extractUrl: extractUrl$4
  };
  function decodeBingUrl(href) {
    try {
      if (!href.includes("bing.com/ck/a")) return href;
      const uObj = new URL(href);
      let u2 = uObj.searchParams.get("u");
      if (u2) {
        u2 = u2.replace(/^a[0-9]/, "");
        let normalized = u2.replace(/-/g, "+").replace(/_/g, "/");
        normalized = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
        const decoded = decodeURIComponent(
          atob(normalized).split("").map((c2) => "%" + ("00" + c2.charCodeAt(0).toString(16)).slice(-2)).join("")
        );
        if (decoded && decoded.startsWith("http")) {
          return decoded;
        }
      }
    } catch (err) {
      console.debug("[SVF] Failed to decode Bing URL:", href, err);
    }
    return null;
  }
  function extractUrl$3(item) {
    const h2a = item.querySelector("h2 a[href]");
    if (h2a?.href) {
      const decoded = decodeBingUrl(h2a.href);
      if (decoded) return decoded;
    }
    const cite = item.querySelector("cite");
    if (cite?.textContent) {
      let t2 = cite.textContent.trim();
      if (t2.includes("›")) {
        t2 = t2.split("›")[0].trim();
      }
      if (t2.startsWith("http")) return t2;
      if (!t2.includes(".")) return null;
      return "https://" + t2;
    }
    return null;
  }
  const bingEngine = {
    name: "bing",
    containerSelector: "#b_results",
    itemSelector: ".b_algo",
    extractUrl: extractUrl$3
  };
  function extractUrl$2(item) {
    const titleA = item.querySelector(
      'a[data-testid="result-title-a"], h2 a[href], a.result__a[href]'
    );
    let url = null;
    if (titleA?.href) {
      url = titleA.href;
    } else {
      for (const a2 of item.querySelectorAll("a[href]")) {
        const href = a2.href;
        if (!href || href.startsWith("#") || href.startsWith("javascript")) continue;
        if (!href.includes("duckduckgo.com") || href.includes("/l/")) {
          url = href;
          break;
        }
      }
    }
    if (url && url.includes("/l/")) {
      try {
        const u2 = new URL(url);
        const uddg = u2.searchParams.get("uddg");
        if (uddg) {
          return decodeURIComponent(uddg);
        }
      } catch (err) {
        console.debug("[SVF] Failed to parse DDG redirect URL:", url, err);
      }
    }
    return url;
  }
  const ddgEngine = {
    name: "ddg",
    containerSelector: ".react-results--main, #links, .serp__results",
    itemSelector: 'article[data-testid="result"], .result.results_links_deep, .nrn-react-div[data-nr]',
    extractUrl: extractUrl$2
  };
  function extractUrl$1(item) {
    const a2 = item.querySelector(
      "a.result-header[href], a.svelte-1dh4yef[href], .snippet-title a[href]"
    );
    if (a2?.href) return a2.href;
    for (const link of item.querySelectorAll("a[href]")) {
      const h2 = link.href;
      if (h2 && !h2.includes("search.brave.com") && !h2.startsWith("#")) return h2;
    }
    return null;
  }
  const braveEngine = {
    name: "brave",
    containerSelector: "#results, .results",
    itemSelector: ".snippet[data-pos], .result[data-pos]",
    extractUrl: extractUrl$1
  };
  function extractUrl(item) {
    const a2 = item.querySelector(
      "a.link.organic__url[href], h2 a.link[href], .OrganicTitle a[href]"
    );
    if (a2?.href) return a2.href;
    for (const link of item.querySelectorAll("a[href]")) {
      const h2 = link.href;
      if (!h2 || h2.startsWith("#") || h2.startsWith("javascript")) continue;
      if (!h2.includes("yandex.") && !h2.includes("ya.ru")) return h2;
    }
    return null;
  }
  const yandexEngine = {
    name: "yandex",
    containerSelector: '#search-result, .content__left, .main__content, .content, [data-layout-part="cl"], body',
    itemSelector: '.serp-item.organic, li.serp-item[data-cid], li:has(.Organic), .Organic, [class*="__card"]',
    extractUrl,
    shouldActivate: (url) => url.pathname.startsWith("/search")
  };
  const ENGINES = [
    { pattern: /(?:^|\.)google\.[a-z]{2,6}(?:\.[a-z]{2,3})?$/i, config: googleEngine },
    { pattern: /(?:^|\.)bing\.com$/i, config: bingEngine },
    { pattern: /(?:^|\.)duckduckgo\.com$/i, config: ddgEngine },
    { pattern: /(?:^|\.)search\.brave\.com$/i, config: braveEngine },
    { pattern: /(?:^|\.)(?:yandex\.[a-z]{2,}|ya\.ru)$/i, config: yandexEngine }
  ];
  function detectEngine() {
    const host = window.location.hostname;
    for (const { pattern, config } of ENGINES) {
      if (pattern.test(host)) {
        if (config.shouldActivate && !config.shouldActivate(new URL(window.location.href))) {
          continue;
        }
        return config;
      }
    }
    return null;
  }
  class GistSync {
    constructor(store) {
      this._pushTimer = null;
      this._pullInterval = null;
      this._isSyncing = false;
      this._store = store;
      this._store.setSyncPushCallback(() => this._schedulePush());
    }
    /** Helper for GM_xmlhttpRequest wrapped in a Promise */
    _xhr(method, url, token, body) {
      return new Promise((resolve, reject) => {
        if (typeof GM_xmlhttpRequest !== "function") {
          reject(new Error("GM_xmlhttpRequest not available"));
          return;
        }
        const headers = {
          "Accept": "application/vnd.github+json",
          "X-GitHub-Api-Version": "2022-11-28"
        };
        if (token) {
          headers["Authorization"] = `token ${token}`;
        }
        if (body) {
          headers["Content-Type"] = "application/json";
        }
        GM_xmlhttpRequest({
          method,
          url,
          headers,
          data: body ? JSON.stringify(body) : void 0,
          onload: (resp) => {
            if (resp.status >= 200 && resp.status < 300) {
              resolve(resp);
            } else {
              reject(new Error(`GitHub API Error: ${resp.status} ${resp.responseText}`));
            }
          },
          onerror: (resp) => reject(new Error(`Network error: ${resp.statusText || "Unknown"}`)),
          ontimeout: () => reject(new Error("Request timed out")),
          timeout: 15e3
        });
      });
    }
    /** Pulls domains from Gist.
     * Mode 'replace' completely replaces local lists.
     * Mode 'union' merges remote into local lists.
     */
    async pull(mode = "replace", isInternal = false) {
      const token = this._store.gistToken;
      const gistId = this._store.gistId;
      if (!token) throw new Error("No GitHub token configured");
      if (!gistId) throw new Error("No Gist ID configured");
      if (!isInternal) this._isSyncing = true;
      try {
        const url = `https://api.github.com/gists/${gistId}`;
        const resp = await this._xhr("GET", url, token);
        const data = JSON.parse(resp.responseText);
        const fileObj = data.files[SVF_CONFIG.GIST_FILENAME];
        if (!fileObj || !fileObj.content) {
          throw new Error(`File ${SVF_CONFIG.GIST_FILENAME} not found in Gist`);
        }
        const remote = parseJsonRobust(fileObj.content);
        const rLiked = Array.isArray(remote.liked) ? remote.liked : [];
        const rDisliked = Array.isArray(remote.disliked) ? remote.disliked : [];
        let liked = rLiked;
        let disliked = rDisliked;
        const local = this._store.exportDomains();
        if (mode === "union") {
          liked = [.../* @__PURE__ */ new Set([...local.liked, ...rLiked])].sort();
          disliked = [.../* @__PURE__ */ new Set([...local.disliked, ...rDisliked])].filter((x2) => !liked.includes(x2)).sort();
        }
        this._store.replaceDomains({ liked, disliked });
        return mode === "replace" ? liked.length + disliked.length : liked.length + disliked.length - local.liked.length - local.disliked.length;
      } finally {
        if (!isInternal) this._isSyncing = false;
      }
    }
    /** Pushes domains to Gist. Pulls first to perform a union merge to avoid conflict.
     * Creates Gist if gistId is not set.
     */
    async push() {
      const token = this._store.gistToken;
      const gistId = this._store.gistId;
      if (!token) throw new Error("No GitHub token configured");
      this._isSyncing = true;
      try {
        if (gistId) {
          try {
            await this.pull("union", true);
          } catch (err) {
            console.warn("[SVF] Pre-push pull failed, continuing push directly:", err);
          }
        }
        const localData = this._store.exportDomains();
        const body = {
          description: "Better Search Domain Filters Backup",
          files: {
            [SVF_CONFIG.GIST_FILENAME]: {
              content: JSON.stringify(localData, null, 2)
            }
          }
        };
        const url = gistId ? `https://api.github.com/gists/${gistId}` : "https://api.github.com/gists";
        const method = gistId ? "PATCH" : "POST";
        const resp = await this._xhr(method, url, token, gistId ? body : { ...body, public: false });
        if (!gistId) {
          const resData = JSON.parse(resp.responseText);
          if (resData && resData.id) {
            this._store.setGistId(resData.id);
          } else {
            throw new Error("Gist created but no ID was returned by GitHub");
          }
        }
      } finally {
        this._isSyncing = false;
      }
    }
    /** Enable automatic periodic pull (every 1 hour) and setup change listeners */
    enableAutoSync() {
      this.disableAutoSync();
      if (this._store.syncEnabled && this._store.gistToken && this._store.gistId) {
        (async () => {
          try {
            console.log("[SVF] Initial auto-sync pull starting...");
            await this.pull("union");
            console.log("[SVF] Initial auto-sync pull successful");
          } catch (err) {
            console.error("[SVF] Initial auto-sync pull failed:", err);
          }
        })();
        this._pullInterval = setInterval(async () => {
          if (this._isSyncing) return;
          try {
            console.log("[SVF] Periodic Gist pull starting...");
            await this.pull("union");
            console.log("[SVF] Periodic Gist pull successful");
          } catch (err) {
            console.error("[SVF] Periodic Gist pull failed:", err);
          }
        }, 36e5);
      }
    }
    disableAutoSync() {
      if (this._pullInterval) {
        clearInterval(this._pullInterval);
        this._pullInterval = null;
      }
      if (this._pushTimer) {
        clearTimeout(this._pushTimer);
        this._pushTimer = null;
      }
    }
    _schedulePush() {
      if (this._pushTimer) {
        clearTimeout(this._pushTimer);
      }
      this._pushTimer = setTimeout(async () => {
        if (!this._store.syncEnabled || !this._store.gistToken) return;
        if (this._isSyncing) {
          this._schedulePush();
          return;
        }
        try {
          console.log("[SVF] Auto Gist push starting...");
          await this.push();
          console.log("[SVF] Auto Gist push successful");
        } catch (err) {
          console.error("[SVF] Auto Gist push failed:", err);
        }
      }, SVF_CONFIG.SYNC_PUSH_DEBOUNCE_MS);
    }
    destroy() {
      this.disableAutoSync();
      this._store.setSyncPushCallback(void 0);
    }
  }
  let historyHooked = false;
  function hookHistoryEvents() {
    if (historyHooked) return;
    historyHooked = true;
    const patch = (type) => {
      const orig = history[type];
      history[type] = function(...args) {
        const res = orig.apply(this, args);
        window.dispatchEvent(new Event("svf-location-change"));
        return res;
      };
    };
    patch("pushState");
    patch("replaceState");
  }
  class Controller {
    constructor() {
      this._store = null;
      this._gistSync = null;
      this._styleSheet = null;
      this._scanner = null;
      this._hoverOverlay = null;
      this._mobileSwipe = null;
      this._panel = null;
      this._trigger = null;
      this._shadowHost = null;
      this._abortController = null;
      this._engine = null;
      this._attachInterval = null;
      this._locationTimeout = null;
      this._onLocationChange = this._onLocationChange.bind(this);
    }
    init() {
      const globalKey = "__svf_controller";
      const prevController = window[globalKey];
      if (prevController && prevController !== this) {
        try {
          prevController.destroy();
        } catch (err) {
          console.error("[SVF] Error destroying previous controller instance:", err);
        }
      }
      this.destroy();
      window[globalKey] = this;
      try {
        this._abortController = new AbortController();
        const signal = this._abortController.signal;
        this._engine = detectEngine();
        if (!this._engine) {
          return;
        }
        this._store = new Store();
        this._gistSync = new GistSync(this._store);
        this._styleSheet = new FilterStyleSheet(this._store);
        this._scanner = new Scanner(this._store, this._engine, signal);
        this._store.subscribe(() => {
          this._scanner?.reapply();
        });
        this._shadowHost = document.createElement("div");
        this._shadowHost.id = "svf-shadow-host";
        this._shadowHost.style.position = "fixed";
        this._shadowHost.style.zIndex = "2147483644";
        this._shadowHost.style.pointerEvents = "none";
        this._shadowHost.style.userSelect = "none";
        this._shadowHost.style.webkitUserSelect = "none";
        const shadow = this._shadowHost.attachShadow({ mode: "open" });
        (document.body || document.documentElement).appendChild(this._shadowHost);
        this._panel = document.createElement("svf-panel");
        this._panel.store = this._store;
        this._panel.scanner = this._scanner;
        this._panel.gistSync = this._gistSync;
        shadow.appendChild(this._panel);
        if (this._store.syncEnabled) {
          this._gistSync.enableAutoSync();
        }
        this._trigger = document.createElement("svf-trigger");
        this._trigger.store = this._store;
        this._trigger.panel = this._panel;
        shadow.appendChild(this._trigger);
        this._hoverOverlay = document.createElement("svf-hover-overlay");
        this._hoverOverlay.store = this._store;
        this._hoverOverlay.scanner = this._scanner;
        this._hoverOverlay.signal = signal;
        shadow.appendChild(this._hoverOverlay);
        this._mobileSwipe = new MobileSwipe(this._store, this._scanner, signal);
        if (typeof GM_registerMenuCommand === "function") {
          GM_registerMenuCommand("Better Search Settings", () => {
            this._panel?.open();
          });
        }
        if (!this._scanner?.attach()) {
          this._startAttachInterval();
        }
        window.addEventListener("popstate", this._onLocationChange, { signal });
        window.addEventListener("svf-location-change", this._onLocationChange, { signal });
        hookHistoryEvents();
      } catch (err) {
        this.destroy();
        throw err;
      }
    }
    destroy() {
      if (this._locationTimeout) {
        clearTimeout(this._locationTimeout);
        this._locationTimeout = null;
      }
      if (this._attachInterval) {
        clearInterval(this._attachInterval);
        this._attachInterval = null;
      }
      if (this._abortController) {
        this._abortController.abort();
        this._abortController = null;
      }
      if (this._scanner) {
        this._scanner.destroy();
        this._scanner = null;
      }
      if (this._hoverOverlay) {
        this._hoverOverlay.remove();
        this._hoverOverlay = null;
      }
      if (this._mobileSwipe) {
        this._mobileSwipe.destroy();
        this._mobileSwipe = null;
      }
      if (this._styleSheet) {
        this._styleSheet.destroy();
        this._styleSheet = null;
      }
      if (this._shadowHost) {
        this._shadowHost.remove();
        this._shadowHost = null;
      }
      if (this._gistSync) {
        this._gistSync.destroy();
        this._gistSync = null;
      }
      if (this._store) {
        this._store.destroy();
        this._store = null;
      }
      this._panel = null;
      this._trigger = null;
      this._engine = null;
      const globalKey = "__svf_controller";
      if (window[globalKey] === this) {
        window[globalKey] = null;
      }
    }
    _onLocationChange() {
      if (this._locationTimeout) {
        clearTimeout(this._locationTimeout);
      }
      this._locationTimeout = setTimeout(() => {
        this._locationTimeout = null;
        const nextEngine = detectEngine();
        if (!nextEngine) {
          this.destroy();
          return;
        }
        if (!this._engine || this._engine.name !== nextEngine.name) {
          this.init();
        } else {
          if (!this._scanner?.attach()) {
            this._startAttachInterval();
          }
        }
      }, 150);
    }
    _startAttachInterval() {
      this._clearAttachInterval();
      let attempts = 0;
      this._attachInterval = setInterval(() => {
        if (this._scanner?.attach()) {
          this._clearAttachInterval();
        } else if (++attempts > 40) {
          this._clearAttachInterval();
        }
      }, 500);
    }
    _clearAttachInterval() {
      if (this._attachInterval) {
        clearInterval(this._attachInterval);
        this._attachInterval = null;
      }
    }
  }
  try {
    const controller = new Controller();
    controller.init();
  } catch (err) {
    console.error("[SVF] Init error:", err);
  }

})();