
    (() => {
      const $ = (s) => document.querySelector(s);
      const $$ = (s) => Array.from(document.querySelectorAll(s));
      const search = $('#tool-search');
      const count = $('#tool-count');
      const pills = $$('#tool-pills .tool-cat-pill');
      const tools = $$('[data-tool]');
      const index = JSON.parse(document.getElementById('tools-index-i18n')?.textContent || '{"tools":{},"categories":{}}');
      const bySlug = {};
      for (const [locale, list] of Object.entries(index.tools || {})) {
        bySlug[locale] = Object.fromEntries((list || []).map((tool) => [tool.slug, tool]));
      }
      const localeCategories = index.categories || {};
      let activeCat = '';
      let kw = '';
      let firstHref = '';
      const normalizeLocale = (value) => {
        const lower = String(value || '').toLowerCase();
        if (lower === 'zh-tw' || lower === 'zh-hk') return 'zh-TW';
        if (lower.startsWith('zh-')) return 'zh-CN';
        if (lower.startsWith('en')) return 'en';
        return ['fr', 'de', 'ru', 'th'].includes(lower) ? lower : 'zh-CN';
      };
      let currentLocale = normalizeLocale(document.documentElement.lang);
      const tr = (value) => window.__taitanI18n?.t?.(value) ?? value;
      const toolMeta = (el) => bySlug[currentLocale]?.[el.dataset.slug] || bySlug['zh-CN']?.[el.dataset.slug];
      const categoryFor = (sourceCat) => {
        const zhCats = localeCategories['zh-CN'] || [];
        const localizedCats = localeCategories[currentLocale] || zhCats;
        const idx = zhCats.indexOf(sourceCat);
        return idx >= 0 ? localizedCats[idx] : sourceCat;
      };
      const updateUrl = () => {
        const url = new URL(window.location.href);
        if (activeCat) url.searchParams.set('cat', activeCat);
        else url.searchParams.delete('cat');
        if (kw) url.searchParams.set('q', kw);
        else url.searchParams.delete('q');
        history.replaceState(null, '', `${url.pathname}${url.search}${url.hash}`);
      };
      const syncLocalizedIndex = () => {
        for (const el of tools) {
          const meta = toolMeta(el);
          if (!meta) continue;
          el.dataset.title = (meta.title || '').toLowerCase();
          el.dataset.desc = (meta.desc || '').toLowerCase();
          el.dataset.keywords = (meta.keywords || []).join(' ').toLowerCase();
          el.dataset.cat = meta.category || '';
        }
        for (const p of pills) {
          const sourceCat = p.dataset.sourceCat ?? p.dataset.cat ?? '';
          p.dataset.sourceCat = sourceCat;
          p.dataset.cat = sourceCat ? categoryFor(sourceCat) : '';
        }
        for (const sec of $$('[data-group]')) {
          const sourceGroup = sec.dataset.sourceGroup ?? sec.dataset.group ?? '';
          sec.dataset.sourceGroup = sourceGroup;
          sec.dataset.group = categoryFor(sourceGroup);
        }
        if (activeCat) activeCat = categoryFor(pills.find((p) => p.classList.contains('is-active'))?.dataset.sourceCat || activeCat);
      };
      if (document.body) document.body.dataset.i18nMode = 'marked';
      const setActiveCatFromSource = (sourceCat) => {
        activeCat = sourceCat ? categoryFor(sourceCat) : '';
        for (const x of pills) {
          const isActive = (x.dataset.sourceCat || '') === (sourceCat || '');
          x.classList.toggle('is-active', isActive);
          x.setAttribute('aria-selected', String(isActive));
        }
      };
      const apply = () => {
        let visible = 0;
        firstHref = '';
        for (const el of tools) {
          const ok =
            (!activeCat || el.dataset.cat === activeCat) &&
            (!kw ||
              el.dataset.title.includes(kw) ||
              el.dataset.desc.includes(kw) ||
              (el.dataset.keywords || '').includes(kw));
          el.style.display = ok ? '' : 'none';
          if (ok) {
            visible++;
            firstHref ||= el.getAttribute('href') || '';
          }
        }
        for (const sec of $$('[data-group]')) {
          const grid = sec.querySelector('[data-grid]');
          if (!grid) continue;
          const anyVisible = Array.from(grid.children).some((c) => c.style.display !== 'none');
          sec.style.display = anyVisible ? '' : 'none';
        }
        if (count) count.textContent = `${tr('显示')} ${visible} / ${tools.length} ${tr('个工具')}`;
        updateUrl();
      };
      search?.addEventListener('input', () => {
        kw = (search.value || '').trim().toLowerCase();
        apply();
      });
      search?.addEventListener('keydown', (e) => {
        if (e.key !== 'Enter' || !firstHref) return;
        e.preventDefault();
        window.location.href = firstHref;
      });
      for (const p of pills) {
        p.setAttribute('role', 'tab');
        p.addEventListener('click', () => {
          setActiveCatFromSource(p.dataset.sourceCat || '');
          apply();
        });
      }
      syncLocalizedIndex();
      const params = new URLSearchParams(window.location.search);
      const initialCat = params.get('cat') || params.get('toolCat') || '';
      const initialQuery = params.get('q') || params.get('toolQ') || '';
      const initialSourceCat = pills.find((p) => (p.dataset.cat || '') === initialCat || (p.dataset.sourceCat || '') === initialCat)?.dataset.sourceCat || '';
      if (initialSourceCat) activeCat = categoryFor(initialSourceCat);
      if (search && initialQuery) {
        kw = initialQuery.trim().toLowerCase();
        search.value = initialQuery;
      }
      for (const p of pills) {
        const isActive = (p.dataset.cat || '') === activeCat;
        p.classList.toggle('is-active', isActive);
        p.setAttribute('aria-selected', String(isActive));
      }
      apply();
      window.addEventListener('keydown', (e) => {
        if (e.key === '/' && document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') {
          e.preventDefault();
          search?.focus();
        }
      });
      window.addEventListener('taitan:locale-change', async (event) => {
        currentLocale = normalizeLocale(event.detail?.locale);
        await window.__taitanI18n?.loadToolMessages?.(currentLocale);
        window.__taitanI18n?.translateDOM?.(document.body);
        syncLocalizedIndex();
        setActiveCatFromSource(pills.find((p) => p.classList.contains('is-active'))?.dataset.sourceCat || '');
        kw = (search?.value || '').trim().toLowerCase();
        apply();
      });
    })();
  
