☰

Advanced Search for X (Twitter) 🔍

Adds a floating modal for advanced search on X.com (Twitter). Syncs with search box and remembers position/display state. The top-right search icon is now draggable and its position persists.

נכון ליום 08-12-2025. ׹אה הגךסה האח׹ונה.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Advanced Search for X (Twitter) 🔍
// @name:ja      Advanced Search for XTwitter🔍
// @name:en      Advanced Search for X (Twitter) 🔍
// @name:zh-CN   Advanced Search for XTwitter🔍
// @name:zh-TW   Advanced Search for XTwitter🔍
// @name:ko      Advanced Search for X (Twitter) 🔍
// @name:fr      Advanced Search for X (Twitter) 🔍
// @name:es      Advanced Search for X (Twitter) 🔍
// @name:de      Advanced Search for X (Twitter) 🔍
// @name:pt-BR   Advanced Search for X (Twitter) 🔍
// @name:ru      Advanced Search for X (Twitter) 🔍
// @version      6.3.2
// @description      Adds a floating modal for advanced search on X.com (Twitter). Syncs with search box and remembers position/display state. The top-right search icon is now draggable and its position persists.
// @description:ja   X.comTwitterに高床な怜玢機胜を呌び出せるフロヌティング・モヌダルを远加したす。怜玢ボックスず双方向で同期し、䜍眮や衚瀺状態も蚘憶したす。右䞊の怜玢アむコンはドラッグで移動でき、䜍眮は保存されたす。
// @description:en   Adds a floating modal for advanced search on X.com (formerly Twitter). Syncs with search box and remembers position/display state. The top-right search icon is draggable with persistent position.
// @description:zh-CN 䞺X.comTwitter添加高级搜玢浮劚暡态框支持䞎搜玢框双向同步并记䜏䜍眮䞎星瀺状态。右䞊角的搜玢囟标可拖劚并䌚记䜏䜍眮。
// @description:zh-TW 為 X.comTwitter增加高玚搜尋暡態框支揎與搜尋框雙向同步䞊蚘䜏䜍眮與顯瀺狀態。右䞊角搜尋圖瀺可拖曳䜍眮會被保存。
// @description:ko   X.com(Twitter)에 고꞉ 검색 몚달을 추가합니닀. 검색찜곌 양방향 동Ʞ화하며 위치와 표시 상태륌 Ʞ억합니닀. 우상닚 검색 아읎윘은 드래귞 읎동 및 위치 저장읎 가능합니닀.
// @description:fr   Ajoute une fenêtre modale de recherche avancée à X.com (Twitter), synchronisée avec la barre de recherche et mémorise de l’état d’affichage. L’icÃŽne de recherche en haut à droite est déplaçable.
// @description:es   Agrega un modal flotante de búsqueda avanzada en X.com (Twitter), sincronizado con la caja de búsqueda y con estado persistente.
// @description:de   FÃŒgt X.com (Twitter) ein modales Fenster fÃŒr erweiterte Suche hinzu, synchronisiert mit der Suchleiste und speichert Position/Zustand. Das Suchsymbol oben rechts ist per Drag & Drop verschiebbar und bleibt gespeichert.
// @description:pt-BR Adiciona um modal de busca avançada flutuante no X.com (Twitter), sincronizado com a caixa de busca e com estado salvo. O ícone de busca no canto superior direito é arrastável com posição persistente.
// @description:ru   ДПбавляет ЌПЎальМПе ПкМП расшОреММПгП пПОска Ма X.com (Twitter). СОМхрПМОзОруется с пПОскПвПй стрПкПй О запПЌОМает сПстПяМОе. КМПпку пПОска в правПЌ верхМеЌ углу ЌПжМП перетаскОвать; её пПлПжеМОе сПхраМяется.
// @namespace    https://github.com/koyasi777/advanced-search-for-x-twitter
// @author       koyasi777
// @match        https://x.com/*
// @match        https://twitter.com/*
// @exclude      https://x.com/i/tweetdeck*
// @exclude      https://twitter.com/i/tweetdeck*
// @icon         https://raw.githubusercontent.com/koyasi777/advanced-search-for-x-twitter/refs/heads/main/extension/icons/icon-128.png
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_info
// @run-at       document-idle
// @license      MIT
// @homepageURL  https://github.com/koyasi777/advanced-search-for-x-twitter
// @supportURL   https://github.com/koyasi777/advanced-search-for-x-twitter/issues
// ==/UserScript==

const __X_ADV_SEARCH_MAIN_LOGIC__ = function() {
    'use strict';

    if (window.__X_ADV_SEARCH_INITED__) return;
    window.__X_ADV_SEARCH_INITED__ = true;

    const i18n = {
        translations: {
            'en': {
                modalTitle: "Advanced Search",
                tooltipClose: "Close",
                labelAllWords: "All of these words",
                placeholderAllWords: "e.g., AI news",
                labelExactPhrase: "This exact phrase",
                placeholderExactPhrase: 'e.g., "ChatGPT 4o"',
                labelAnyWords: "Any of these words (OR)",
                placeholderAnyWords: "e.g., iPhone Android",
                labelNotWords: "None of these words (-)",
                placeholderNotWords: "e.g., -sale -ads",
                labelHashtag: "Hashtags (#)",
                placeholderHashtag: "e.g., #TechEvent",
                labelLang: "Language (lang:)",
                optLangDefault: "Any language",
                optLangJa: "Japanese (ja)",
                optLangEn: "English (en)",
                optLangId: "Indonesian (id)",
                optLangHi: "Hindi (hi)",
                optLangDe: "German (de)",
                optLangTr: "Turkish (tr)",
                optLangEs: "Spanish (es)",
                optLangPt: "Portuguese (pt)",
                optLangAr: "Arabic (ar)",
                optLangFr: "French (fr)",
                optLangKo: "Korean (ko)",
                optLangRu: "Russian (ru)",
                optLangZhHans: "Chinese Simplified (zh-cn)",
                optLangZhHant: "Chinese Traditional (zh-tw)",
                hrSeparator: " ",
                labelFilters: "Filters",
                labelVerified: "Verified accounts",
                labelLinks: "Links",
                labelImages: "Images",
                labelVideos: "Videos",
                labelReposts: "Reposts",
                labelTimelineHashtags: "Hashtags (#)",
                checkInclude: "Include",
                checkExclude: "Exclude",
                labelReplies: "Replies",
                optRepliesDefault: "Default (Show all)",
                optRepliesInclude: "Include replies",
                optRepliesOnly: "Replies only",
                optRepliesExclude: "Exclude replies",
                labelEngagement: "Engagement",
                placeholderMinReplies: "Min replies",
                placeholderMinLikes: "Min likes",
                placeholderMinRetweets: "Min reposts",
                labelDateRange: "Date range",
                labelDateShortcut: "Quick Range",
                optDate1Day: "Past 24h",
                optDate1Week: "Past week",
                optDate1Month: "Past month",
                optDate3Months: "Past 3 months",
                optDate6Months: "Past 6 months",
                optDate1Year: "Past year",
                optDate2Years: "Past 2 years",
                optDate3Years: "Past 3 years",
                optDate5Years: "Past 5 years",
                optDateClear: "Clear dates",
                tooltipSince: "From this date",
                tooltipUntil: "Until this date",
                labelFromUser: "From these accounts (from:)",
                placeholderFromUser: "e.g., @X",
                labelToUser: "To these accounts (to:)",
                placeholderToUser: "e.g., @google",
                labelMentioning: "Mentioning these accounts (@)",
                placeholderMentioning: "e.g., @OpenAI",
                buttonClear: "Clear",
                buttonApply: "Search",
                tooltipTrigger: "Open Advanced Search",
                buttonOpen: "Open",

                tabSearch: "Search",
                tabHistory: "History",
                tabSaved: "Saved",
                buttonSave: "Save",
                buttonSaved: "Saved",
                secretMode: "Secret",
                secretOn: "Secret mode ON (No history)",
                secretOff: "Secret mode OFF",
                toastSaved: "Saved.",
                toastDeleted: "Deleted.",
                toastReordered: "Order updated.",
                emptyHistory: "No history yet.",
                emptySaved: "No saved searches. Add from the Save button at the bottom left of the Search tab.",
                run: "Run",
                delete: "Delete",
                updated: "Updated.",
                tooltipSecret: "Toggle Secret Mode (no history will be recorded)",
                historyClearAll: "Clear All",
                confirmClearHistory: "Clear all history?",

                labelAccountScope: "Accounts",
                optAccountAll: "All accounts",
                optAccountFollowing: "Accounts you follow",
                labelLocationScope: "Location",
                optLocationAll: "All locations",
                optLocationNearby: "Near you",
                chipFollowing: "Following",
                chipNearby: "Nearby",

                labelSearchTarget: "Search target",
                labelHitName: "Exclude matches only in display name",
                labelHitHandle: "Exclude matches only in username (@handle)",
                hintSearchTarget: "Hide posts that only match in name or handle (not in body).",
                hintName: "If a keyword appears only in the display name, hide it.",
                hintHandle: "If a keyword appears only in @username, hide it. Exception: when the query explicitly uses from:/to:/@ with the same word.",

                tabMute: "Mute",
                labelMuteWord: "Add mute word",
                placeholderMuteWord: "e.g., spoiler",
                labelCaseSensitive: "Case sensitive",
                labelWordBoundary: "Whole word",
                labelEnabled: "Enabled",
                labelEnableAll: "Enable all",
                buttonAdd: "Add",
                emptyMuted: "No muted words.",
                mutedListTitle: "Muted words",
                mutedListHeading: "Muted items",
                optMuteHidden: "Hidden",
                optMuteCollapsed: "Collapsed",
                placeholderFilterMute: "Filter muted words...",
                muteLabel: "Muted: ",
                buttonShow: "Show",
                muteHit: "Mute hits in body",
                buttonRemute: "Re-mute",
                buttonImport: "Import",
                buttonExport: "Export",

                /* Accounts tab */
                tabAccounts: "Accounts",
                emptyAccounts: "No accounts yet. Open a profile and click the Add button to save it.",
                buttonAddAccount: "Add account",
                toastAccountAdded: "Account added.",
                toastAccountExists: "Already added.",
                buttonConfirm: "Confirm",

                /* Lists tab */
                tabLists: "Lists",
                emptyLists: "No lists yet. Open a List and click the + button in the top-right to add it.",
                buttonAddList: "Add list",
                toastListAdded: "List added.",
                toastListExists: "Already added.",

                /* History tab */
                placeholderSearchHistory: "Search history (query)",
                labelSortBy: "Sort by:",
                placeholderSearchSaved: "Search saved (query)",
                sortNewest: "Newest first",
                sortOldest: "Oldest first",
                sortNameAsc: "Query (A-Z)",
                sortNameDesc: "Query (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "Filter accounts (@, name)",
                placeholderFilterLists: "Filter lists (name, url)",
                buttonAddFolder: "+Folder",
                folderFilterAll: "ALL",
                folderFilterUnassigned: "Unassigned",
                folderRename: "Rename",
                folderRenameTitle: "Rename folder",
                folderDelete: "Delete",
                folderDeleteTitle: "Delete folder",
                promptNewFolder: "New folder name",
                confirmDeleteFolder: "Delete this folder and all items inside it? This cannot be undone.",
                optListsAll: "Lists",
                defaultSavedFolders: "Saved Searches",

                /* Favorites */
                tabFavorites: "Favorites",
                emptyFavorites: "No favorite tweets yet. Click the ★ icon on tweets to save them.",
                optFavoritesAll: "All Favorites",
                toastFavorited: "Added to favorites.",
                toastUnfavorited: "Removed from favorites.",

                /* Settings */
                settingsTitle: "Settings",
                settingsTitleGeneral: "General",
                settingsTitleFeatures: "Tab Visibility",
                settingsTitleData: "Data",
                buttonClose: "Close",
                labelUILang: "Interface language",
                optUILangAuto: "Auto",
                labelInitialTab: "Startup tab",
                optInitialTabLast: "Last opened (Default)",
                labelImportExport: "Import / Export",
                placeholderSettingsJSON: "Paste backup JSON here...",
                tooltipSettings: "Open settings",
                toastImported: "Imported.",
                alertInvalidJSON: "Invalid JSON file.",
                alertInvalidData: "Invalid data format.",
                alertInvalidApp: 'This file is not a valid backup for "Advanced Search for X".',
                toastExported: "Exported to file.",
                buttonReset: "Reset all data",
                confirmResetAll: "Reset all data? This cannot be undone.",
                toastReset: "All data has been reset.",
                buttonImportSuccess: "Imported successfully 👍",

                /* Favorites Sort */
                sortSavedNewest: "Saved date (Newest)",
                sortSavedOldest: "Saved date (Oldest)",
                sortPostedNewest: "Posted date (Newest)",
                sortPostedOldest: "Posted date (Oldest)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Uncategorized',
                FT_DROPDOWN_TITLE: 'Favorite Tags',
                FT_DROPDOWN_SETTINGS_TITLE: 'Favorite Tag Settings',
                FT_DROPDOWN_NEW_TAG: 'New tag',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'Tag name',
                FT_DROPDOWN_NEW_TAG_ADD: 'Add',
                FT_FILTER_ALL: 'All',
                FT_SETTINGS_TITLE: 'Favorite Tag Settings',
                FT_SETTINGS_EMPTY_TAG_LIST:
                  'No tags yet. You can add one from "New tag".',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Uncategorized',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP:
                  'The name of "Uncategorized" cannot be changed.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP:
                  '"Uncategorized" cannot be deleted.',
                FT_SETTINGS_CLOSE: 'Close',
                FT_SETTINGS_DELETE_BUTTON: 'Delete',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'Display',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'Tag label format',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'Tag name only',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'Full path',
                FT_CONFIRM_DELETE_TAG_MSG: 'Delete tag "{tagName}"?\nFavorites with this tag will become "Uncategorized".',
                FT_SETTINGS_BUTTON_TITLE: 'Favorite Tag Settings',
            },
            'ja': {
                modalTitle: "高床な怜玢",
                tooltipClose: "閉じる",
                labelAllWords: "すべおの語句を含む",
                placeholderAllWords: "䟋: AI ニュヌス",
                labelExactPhrase: "この語句を完党に含む",
                placeholderExactPhrase: '䟋: "ChatGPT 4o"',
                labelAnyWords: "いずれかの語句を含む (OR)",
                placeholderAnyWords: "䟋: iPhone Android",
                labelNotWords: "含たない語句 (-)",
                placeholderNotWords: "䟋: -セヌル -広告",
                labelHashtag: "ハッシュタグ (#)",
                placeholderHashtag: "䟋: #技術曞兞",
                labelLang: "蚀語 (lang:)",
                optLangDefault: "指定しない",
                optLangJa: "日本語 (ja)",
                optLangEn: "英語 (en)",
                optLangId: "むンドネシア語 (id)",
                optLangHi: "ヒンディヌ語 (hi)",
                optLangDe: "ドむツ語 (de)",
                optLangTr: "トルコ語 (tr)",
                optLangEs: "スペむン語 (es)",
                optLangPt: "ポルトガル語 (pt)",
                optLangAr: "アラビア語 (ar)",
                optLangFr: "フランス語 (fr)",
                optLangKo: "韓囜語 (ko)",
                optLangRu: "ロシア語 (ru)",
                optLangZhHans: "䞭囜語簡䜓字(zh-cn)",
                optLangZhHant: "䞭囜語繁䜓字(zh-tw)",
                hrSeparator: " ",
                labelFilters: "フィルタヌ",
                labelVerified: "認蚌枈みアカりント",
                labelLinks: "リンク",
                labelImages: "画像",
                labelVideos: "動画",
                labelReposts: "リポスト",
                labelTimelineHashtags: "ハッシュタグ (#)",
                checkInclude: "含む",
                checkExclude: "含たない",
                labelReplies: "返信",
                optRepliesDefault: "指定しない",
                optRepliesInclude: "返信を含める",
                optRepliesOnly: "返信のみ",
                optRepliesExclude: "返信を陀倖",
                labelEngagement: "゚ンゲヌゞメント",
                placeholderMinReplies: "最小返信数",
                placeholderMinLikes: "最小いいね数",
                placeholderMinRetweets: "最小リポスト数",
                labelDateRange: "期間指定",
                labelDateShortcut: "期間ショヌトカット",
                optDate1Day: "過去24時間",
                optDate1Week: "過去1週間",
                optDate1Month: "過去1ヶ月",
                optDate3Months: "過去3ヶ月",
                optDate6Months: "過去6ヶ月",
                optDate1Year: "過去1幎",
                optDate2Years: "過去2幎",
                optDate3Years: "過去3幎",
                optDate5Years: "過去5幎",
                optDateClear: "日付クリア",
                tooltipSince: "この日以降",
                tooltipUntil: "この日以前",
                labelFromUser: "このアカりントから (from:)",
                placeholderFromUser: "䟋: @X",
                labelToUser: "このアカりントぞ (to:)",
                placeholderToUser: "䟋: @google",
                labelMentioning: "このアカりントぞのメンション (@)",
                placeholderMentioning: "䟋: @OpenAI",
                buttonClear: "クリア",
                buttonApply: "怜玢実行",
                tooltipTrigger: "高床な怜玢を開く",
                buttonOpen: "開く",

                tabSearch: "怜玢",
                tabHistory: "履歎",
                tabSaved: "保存",
                buttonSave: "保存",
                buttonSaved: "保存枈み",
                secretMode: "シヌクレット",
                secretOn: "シヌクレットモヌド ON履歎は蚘録したせん",
                secretOff: "シヌクレットモヌド OFF",
                toastSaved: "保存したした。",
                toastDeleted: "削陀したした。",
                toastReordered: "䞊び順を曎新したした。",
                emptyHistory: "履歎はただありたせん。",
                emptySaved: "保存枈みの怜玢はありたせん。怜玢タブの巊䞋の保存から远加しおください。",
                run: "実行",
                delete: "削陀",
                updated: "曎新したした。",
                tooltipSecret: "シヌクレットモヌドを切り替え履歎を蚘録したせん",
                historyClearAll: "すべお削陀",
                confirmClearHistory: "履歎をすべお削陀したすか",

                labelAccountScope: "アカりント",
                optAccountAll: "すべおのアカりント",
                optAccountFollowing: "フォロヌしおいるアカりント",
                labelLocationScope: "堎所",
                optLocationAll: "すべおの堎所",
                optLocationNearby: "近くの堎所",
                chipFollowing: "フォロヌ䞭",
                chipNearby: "近く",

                labelSearchTarget: "怜玢察象",
                labelHitName: "衚瀺名名前のみのヒットは陀倖",
                labelHitHandle: "ナヌザヌ名@のみのヒットは陀倖",
                hintSearchTarget: "本文ではなく、名前/ナヌザヌ名のみに䞀臎した投皿を非衚瀺にしたす。",
                hintName: "キヌワヌドが衚瀺名のみに含たれる堎合は非衚瀺にしたす。",
                hintHandle: "キヌワヌドが @ナヌザヌ名のみに含たれる堎合は非衚瀺にしたす。䟋倖: 同じ語を from:/to:/@ で明瀺しおいるずきは衚瀺したす。",

                tabMute: "ミュヌト",
                labelMuteWord: "ミュヌト語句の远加",
                placeholderMuteWord: "䟋: ネタバレ",
                labelCaseSensitive: "倧文字小文字を区別",
                labelWordBoundary: "完党䞀臎(単語)",
                labelEnabled: "有効",
                labelEnableAll: "すべお有効",
                buttonAdd: "远加",
                emptyMuted: "ミュヌト語句はただありたせん。",
                mutedListTitle: "ミュヌト語句",
                mutedListHeading: "ミュヌト䞀芧",
                optMuteHidden: "非衚瀺",
                optMuteCollapsed: "折りたたみ",
                placeholderFilterMute: "ミュヌトを怜玢...",
                muteLabel: "ミュヌト: ",
                buttonShow: "衚瀺する",
                muteHit: "本文でのヒットをミュヌト",
                buttonRemute: "再ミュヌト",
                buttonImport: "むンポヌト",
                buttonExport: "゚クスポヌト",

                /* Accounts tab */
                tabAccounts: "アカりント",
                emptyAccounts: "アカりントはただありたせん。アカりントペヌゞの远加ボタンから远加しおください。",
                buttonAddAccount: "アカりントを远加",
                toastAccountAdded: "アカりントを远加したした。",
                toastAccountExists: "すでに远加枈みです。",
                buttonConfirm: "確認",

                /* Lists tab */
                tabLists: "リスト",
                emptyLists: "リストはただありたせん。リストを開き右䞊の+ボタンから远加しおください。",
                buttonAddList: "リストを远加",
                toastListAdded: "リストを远加したした。",
                toastListExists: "すでに远加枈みです。",

                /* History tab */
                placeholderSearchHistory: "履歎を怜玢ク゚リ",
                labelSortBy: "䞊び順:",
                placeholderSearchSaved: "保存枈みを怜玢ク゚リ",
                sortNewest: "新しい順",
                sortOldest: "叀い順",
                sortNameAsc: "ク゚リ (昇順)",
                sortNameDesc: "ク゚リ (降順)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "アカりントを怜玢 (@, 名前)",
                placeholderFilterLists: "リストを怜玢 (名前, URL)",
                buttonAddFolder: "+フォルダヌ",
                folderFilterAll: "すべお",
                folderFilterUnassigned: "未分類",
                folderRename: "名前倉曎",
                folderRenameTitle: "フォルダヌ名を倉曎",
                folderDelete: "削陀",
                folderDeleteTitle: "フォルダヌを削陀",
                promptNewFolder: "新しいフォルダヌ名",
                confirmDeleteFolder: "このフォルダヌず䞭のすべおのアむテムを完党に削陀したすかこの操䜜は元に戻せたせん。",
                optListsAll: "リスト",
                defaultSavedFolders: "保存枈み怜玢",

                /* Favorites */
                tabFavorites: "お気に入り",
                emptyFavorites: "お気に入りはただありたせん。ツむヌトの★ボタンをクリックしお保存できたす。",
                optFavoritesAll: "すべおのお気に入り",
                toastFavorited: "お気に入りに远加したした。",
                toastUnfavorited: "お気に入りから削陀したした。",

                /* Settings */
                settingsTitle: "蚭定",
                settingsTitleGeneral: "䞀般蚭定",
                settingsTitleFeatures: "タブ衚瀺蚭定",
                settingsTitleData: "デヌタ管理",
                buttonClose: "閉じる",
                labelUILang: "UI 蚀語",
                optUILangAuto: "自動刀定",
                labelInitialTab: "起動時に開くタブ",
                optInitialTabLast: "前回のタブ (デフォルト)",
                labelImportExport: "むンポヌト / ゚クスポヌト",
                placeholderSettingsJSON: "ここにバックアップ JSON を貌り付けおください...",
                tooltipSettings: "蚭定を開く",
                toastImported: "むンポヌトしたした。",
                toastExported: "ファむルに゚クスポヌトしたした。",
                alertInvalidJSON: "無効なJSONファむルです。",
                alertInvalidData: "無効なデヌタ圢匏です。",
                alertInvalidApp: "このファむルは「Advanced Search for X」のバックアップデヌタではありたせん。",
                buttonReset: "すべお初期化",
                confirmResetAll: "すべおのデヌタを初期化したすかこの操䜜は元に戻せたせん。",
                toastReset: "すべおのデヌタを初期化したした。",
                buttonImportSuccess: "むンポヌトに成功したした👍",

                /* Favorites Sort */
                sortSavedNewest: "远加日 (新しい順)",
                sortSavedOldest: "远加日 (叀い順)",
                sortPostedNewest: "投皿日 (新しい順)",
                sortPostedOldest: "投皿日 (叀い順)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: '未分類',
                FT_DROPDOWN_TITLE: 'お気に入りタグ',
                FT_DROPDOWN_SETTINGS_TITLE: 'お気に入りタグ蚭定',
                FT_DROPDOWN_NEW_TAG: '新しいタグ',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'タグ名',
                FT_DROPDOWN_NEW_TAG_ADD: '远加',
                FT_FILTER_ALL: 'すべお',
                FT_SETTINGS_TITLE: 'お気に入りタグ蚭定',
                FT_SETTINGS_EMPTY_TAG_LIST:
                  'タグはただありたせん。「新しいタグ」から远加できたす。',
                FT_SETTINGS_UNCATEGORIZED_NAME: '未分類',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: '未分類の名前は倉曎できたせん',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '未分類は削陀できたせん',
                FT_SETTINGS_CLOSE: '閉じる',
                FT_SETTINGS_DELETE_BUTTON: '削陀',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: '衚瀺蚭定',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'タグの衚瀺圢匏',
                FT_SETTINGS_DISPLAY_MODE_LEAF: '末尟のみ (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'フルパス (full)',
                FT_CONFIRM_DELETE_TAG_MSG: 'タグ「{tagName}」を削陀したすか\nこのタグが付いおいたお気に入りは未分類になりたす。',
                FT_SETTINGS_BUTTON_TITLE: 'お気に入りタグ蚭定',
            },
            'zh-CN': {
                modalTitle: "高级搜玢",
                tooltipClose: "关闭",
                labelAllWords: "包含党郚词语",
                placeholderAllWords: "䟋劂AI 新闻",
                labelExactPhrase: "包含确切短语",
                placeholderExactPhrase: '䟋劂"ChatGPT 4o"',
                labelAnyWords: "包含任意词语 (OR)",
                placeholderAnyWords: "䟋劂iPhone Android",
                labelNotWords: "䞍包含词语 (-)",
                placeholderNotWords: "䟋劂-促销 -广告",
                labelHashtag: "话题标筟 (#)",
                placeholderHashtag: "䟋劂#科技倧䌚",
                labelLang: "语蚀 (lang:)",
                optLangDefault: "所有语蚀",
                optLangJa: "日语 (ja)",
                optLangEn: "英语 (en)",
                optLangId: "印尌语 (id)",
                optLangHi: "印地语 (hi)",
                optLangDe: "執语 (de)",
                optLangTr: "土耳其语 (tr)",
                optLangEs: "西班牙语 (es)",
                optLangPt: "葡萄牙语 (pt)",
                optLangAr: "阿拉䌯语 (ar)",
                optLangFr: "法语 (fr)",
                optLangKo: "韩语 (ko)",
                optLangRu: "俄语 (ru)",
                optLangZhHans: "简䜓䞭文 (zh-cn)",
                optLangZhHant: "繁䜓䞭文 (zh-tw)",
                hrSeparator: " ",
                labelFilters: "筛选",
                labelVerified: "讀证莊号",
                labelLinks: "铟接",
                labelImages: "囟片",
                labelVideos: "视频",
                labelReposts: "蜬发",
                labelTimelineHashtags: "话题标筟 (#)",
                checkInclude: "包含",
                checkExclude: "排陀",
                labelReplies: "回倍",
                optRepliesDefault: "默讀 (星瀺党郚)",
                optRepliesInclude: "包含回倍",
                optRepliesOnly: "仅回倍",
                optRepliesExclude: "排陀回倍",
                labelEngagement: "互劚量",
                placeholderMinReplies: "最少回倍",
                placeholderMinLikes: "最少喜欢",
                placeholderMinRetweets: "最少蜬发",
                labelDateRange: "日期范囎",
                labelDateShortcut: "快速选择",
                optDate1Day: "过去 24 小时",
                optDate1Week: "过去 1 呚",
                optDate1Month: "过去 1 䞪月",
                optDate3Months: "过去 3 䞪月",
                optDate6Months: "过去 6 䞪月",
                optDate1Year: "过去 1 幎",
                optDate2Years: "过去 2 幎",
                optDate3Years: "过去 3 幎",
                optDate5Years: "过去 5 幎",
                optDateClear: "枅陀日期",
                tooltipSince: "起始日期",
                tooltipUntil: "结束日期",
                labelFromUser: "来自这些莊号 (from:)",
                placeholderFromUser: "䟋劂@X",
                labelToUser: "发送给这些莊号 (to:)",
                placeholderToUser: "䟋劂@google",
                labelMentioning: "提及这些莊号 (@)",
                placeholderMentioning: "䟋劂@OpenAI",
                buttonClear: "枅陀",
                buttonApply: "搜玢",
                tooltipTrigger: "打匀高级搜玢",
                buttonOpen: "打匀",

                tabSearch: "搜玢",
                tabHistory: "历史",
                tabSaved: "已保存",
                buttonSave: "保存",
                buttonSaved: "已保存",
                secretMode: "无痕暡匏",
                secretOn: "无痕暡匏已匀启 (䞍记圕历史)",
                secretOff: "无痕暡匏已关闭",
                toastSaved: "已保存。",
                toastDeleted: "已删陀。",
                toastReordered: "顺序已曎新。",
                emptyHistory: "暂无历史记圕。",
                emptySaved: "暂无保存的搜玢。请圚搜玢标筟页巊䞋角点击保存按钮添加。",
                run: "运行",
                delete: "删陀",
                updated: "已曎新。",
                tooltipSecret: "切换无痕暡匏 (䞍记圕搜玢历史)",
                historyClearAll: "党郚枅陀",
                confirmClearHistory: "确定芁枅陀所有历史记圕吗",

                labelAccountScope: "莊号范囎",
                optAccountAll: "所有莊号",
                optAccountFollowing: "关泚的莊号",
                labelLocationScope: "䜍眮范囎",
                optLocationAll: "所有䜍眮",
                optLocationNearby: "附近",
                chipFollowing: "已关泚",
                chipNearby: "附近",

                labelSearchTarget: "搜玢目标",
                labelHitName: "排陀仅圚星瀺名称䞭的匹配",
                labelHitHandle: "排陀仅圚甚户名 (@handle) 䞭的匹配",
                hintSearchTarget: "隐藏仅圚名称或甚户名䞭匹配而非正文的垖子。",
                hintName: "劂果关键词仅出现圚星瀺名称䞭则隐藏。",
                hintHandle: "劂果关键词仅出现圚 @甚户名 䞭则隐藏。䟋倖圓查询䞭明确䜿甚了 from:/to:/@ 时陀倖。",

                tabMute: "屏蔜",
                labelMuteWord: "添加屏蔜词",
                placeholderMuteWord: "䟋劂剧透",
                labelCaseSensitive: "区分倧小写",
                labelWordBoundary: "党字匹配",
                labelEnabled: "已启甚",
                labelEnableAll: "党郚启甚",
                buttonAdd: "添加",
                emptyMuted: "暂无屏蔜词。",
                mutedListTitle: "屏蔜词",
                mutedListHeading: "屏蔜列衚",
                optMuteHidden: "隐藏",
                optMuteCollapsed: "折叠",
                placeholderFilterMute: "筛选屏蔜词...",
                muteLabel: "已屏蔜: ",
                buttonShow: "星瀺",
                muteHit: "屏蔜正文匹配项",
                buttonRemute: "重新屏蔜",
                buttonImport: "富入",
                buttonExport: "富出",

                /* Accounts tab */
                tabAccounts: "莊号",
                emptyAccounts: "暂无莊号。请打匀䞪人资料页并点击添加按钮进行保存。",
                buttonAddAccount: "添加莊号",
                toastAccountAdded: "莊号已添加。",
                toastAccountExists: "已存圚。",
                buttonConfirm: "确讀",

                /* Lists tab */
                tabLists: "列衚",
                emptyLists: "暂无列衚。请打匀列衚页并点击右䞊角的 + 按钮添加。",
                buttonAddList: "添加列衚",
                toastListAdded: "列衚已添加。",
                toastListExists: "已存圚。",

                /* History tab */
                placeholderSearchHistory: "搜玢历史 (查询词)",
                labelSortBy: "排序:",
                placeholderSearchSaved: "搜玢已保存 (查询词)",
                sortNewest: "最新",
                sortOldest: "最旧",
                sortNameAsc: "查询词 (A-Z)",
                sortNameDesc: "查询词 (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "筛选莊号 (@, 名称)",
                placeholderFilterLists: "筛选列衚 (名称, URL)",
                buttonAddFolder: "+文件倹",
                folderFilterAll: "党郚",
                folderFilterUnassigned: "未分类",
                folderRename: "重呜名",
                folderRenameTitle: "重呜名文件倹",
                folderDelete: "删陀",
                folderDeleteTitle: "删陀文件倹",
                promptNewFolder: "新文件倹名称",
                confirmDeleteFolder: "确定芁删陀歀文件倹及其内郚所有项目吗歀操䜜无法撀销。",
                optListsAll: "列衚",
                defaultSavedFolders: "已保存搜玢",

                /* Favorites */
                tabFavorites: "收藏",
                emptyFavorites: "暂无收藏的垖子。点击垖子䞊的 ★ 按钮进行保存。",
                optFavoritesAll: "所有收藏",
                toastFavorited: "已添加到收藏。",
                toastUnfavorited: "已从收藏䞭移陀。",

                /* Settings */
                settingsTitle: "讟眮",
                settingsTitleGeneral: "通甹",
                settingsTitleFeatures: "标筟星瀺",
                settingsTitleData: "数据管理",
                buttonClose: "关闭",
                labelUILang: "界面语蚀",
                optUILangAuto: "自劚",
                labelInitialTab: "启劚时打匀的标筟页",
                optInitialTabLast: "䞊次打匀的标筟页 (默讀)",
                labelImportExport: "富入 / 富出",
                placeholderSettingsJSON: "请圚歀粘莎倇仜 JSON...",
                tooltipSettings: "打匀讟眮",
                toastImported: "已富入。",
                toastExported: "已富出到文件。",
                alertInvalidJSON: "无效的 JSON 文件。",
                alertInvalidData: "无效的数据栌匏。",
                alertInvalidApp: '歀文件䞍是 "Advanced Search for X" 的倇仜数据。',
                buttonReset: "重眮所有数据",
                confirmResetAll: "确定芁重眮所有数据吗歀操䜜无法撀销。",
                toastReset: "所有数据已重眮。",
                buttonImportSuccess: "富入成功 👍",

                /* Favorites Sort */
                sortSavedNewest: "保存日期 (最新)",
                sortSavedOldest: "保存日期 (最旧)",
                sortPostedNewest: "发垃日期 (最新)",
                sortPostedOldest: "发垃日期 (最旧)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: '未分类',
                FT_DROPDOWN_TITLE: '收藏标筟',
                FT_DROPDOWN_SETTINGS_TITLE: '收藏标筟讟眮',
                FT_DROPDOWN_NEW_TAG: '新建标筟',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: '标筟名称',
                FT_DROPDOWN_NEW_TAG_ADD: '添加',
                FT_FILTER_ALL: '党郚',
                FT_SETTINGS_TITLE: '收藏标筟讟眮',
                FT_SETTINGS_EMPTY_TAG_LIST: '暂无标筟。悚可以从“新建标筟”添加。',
                FT_SETTINGS_UNCATEGORIZED_NAME: '未分类',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: '“未分类”的名称无法曎改。',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '“未分类”无法被删陀。',
                FT_SETTINGS_CLOSE: '关闭',
                FT_SETTINGS_DELETE_BUTTON: '删陀',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: '星瀺讟眮',
                FT_SETTINGS_DISPLAY_MODE_LABEL: '标筟星瀺栌匏',
                FT_SETTINGS_DISPLAY_MODE_LEAF: '仅末级 (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: '完敎路埄 (full)',
                FT_CONFIRM_DELETE_TAG_MSG: '确定芁删陀标筟“{tagName}”吗\n垊有歀标筟的收藏将变䞺“未分类”。',
                FT_SETTINGS_BUTTON_TITLE: '收藏标筟讟眮',
            },
            'zh-TW': {
                modalTitle: "進階搜尋",
                tooltipClose: "關閉",
                labelAllWords: "包含所有詞語",
                placeholderAllWords: "䟋劂AI 新聞",
                labelExactPhrase: "包含粟確詞組",
                placeholderExactPhrase: '䟋劂"ChatGPT 4o"',
                labelAnyWords: "包含任䞀詞語 (OR)",
                placeholderAnyWords: "䟋劂iPhone Android",
                labelNotWords: "排陀詞語 (-)",
                placeholderNotWords: "䟋劂-促銷 -廣告",
                labelHashtag: "䞻題暙籀 (#)",
                placeholderHashtag: "䟋劂#科技倧會",
                labelLang: "語蚀 (lang:)",
                optLangDefault: "所有語蚀",
                optLangJa: "日語 (ja)",
                optLangEn: "英語 (en)",
                optLangId: "印尌語 (id)",
                optLangHi: "印地語 (hi)",
                optLangDe: "執語 (de)",
                optLangTr: "土耳其語 (tr)",
                optLangEs: "西班牙語 (es)",
                optLangPt: "葡萄牙語 (pt)",
                optLangAr: "阿拉䌯語 (ar)",
                optLangFr: "法語 (fr)",
                optLangKo: "韓語 (ko)",
                optLangRu: "俄語 (ru)",
                optLangZhHans: "簡體䞭文 (zh-cn)",
                optLangZhHant: "繁體䞭文 (zh-tw)",
                hrSeparator: " ",
                labelFilters: "篩遞",
                labelVerified: "已認證垳號",
                labelLinks: "連結",
                labelImages: "圖片",
                labelVideos: "圱片",
                labelReposts: "蜉癌",
                labelTimelineHashtags: "䞻題暙籀 (#)",
                checkInclude: "包含",
                checkExclude: "排陀",
                labelReplies: "回芆",
                optRepliesDefault: "預蚭 (顯瀺党郚)",
                optRepliesInclude: "包含回芆",
                optRepliesOnly: "僅限回芆",
                optRepliesExclude: "排陀回芆",
                labelEngagement: "互動量",
                placeholderMinReplies: "最少回芆",
                placeholderMinLikes: "最少喜歡",
                placeholderMinRetweets: "最少蜉癌",
                labelDateRange: "日期範圍",
                labelDateShortcut: "快速範圍",
                optDate1Day: "過去 24 小時",
                optDate1Week: "過去 1 週",
                optDate1Month: "過去 1 個月",
                optDate3Months: "過去 3 個月",
                optDate6Months: "過去 6 個月",
                optDate1Year: "過去 1 幎",
                optDate2Years: "過去 2 幎",
                optDate3Years: "過去 3 幎",
                optDate5Years: "過去 5 幎",
                optDateClear: "枅陀日期",
                tooltipSince: "開始日期",
                tooltipUntil: "結束日期",
                labelFromUser: "䟆自這些垳號 (from:)",
                placeholderFromUser: "䟋劂@X",
                labelToUser: "癌送絊這些垳號 (to:)",
                placeholderToUser: "䟋劂@google",
                labelMentioning: "提及這些垳號 (@)",
                placeholderMentioning: "䟋劂@OpenAI",
                buttonClear: "枅陀",
                buttonApply: "搜尋",
                tooltipTrigger: "打開進階搜尋",
                buttonOpen: "打開",

                tabSearch: "搜尋",
                tabHistory: "简錄",
                tabSaved: "已儲存",
                buttonSave: "儲存",
                buttonSaved: "已儲存",
                secretMode: "無痕暡匏",
                secretOn: "無痕暡匏已開啟 (䞍蚘錄歷史)",
                secretOff: "無痕暡匏已關閉",
                toastSaved: "已儲存。",
                toastDeleted: "已刪陀。",
                toastReordered: "順序已曎新。",
                emptyHistory: "暫無搜尋玀錄。",
                emptySaved: "暫無儲存的搜尋。請圚搜尋分頁巊䞋角點擊儲存按鈕添加。",
                run: "執行",
                delete: "刪陀",
                updated: "已曎新。",
                tooltipSecret: "切換無痕暡匏 (䞍蚘錄搜尋歷史)",
                historyClearAll: "党郚枅陀",
                confirmClearHistory: "確定芁枅陀所有搜尋玀錄嗎",

                labelAccountScope: "垳號範圍",
                optAccountAll: "所有垳號",
                optAccountFollowing: "跟隚的垳號",
                labelLocationScope: "䜍眮範圍",
                optLocationAll: "所有䜍眮",
                optLocationNearby: "附近",
                chipFollowing: "正圚跟隚",
                chipNearby: "附近",

                labelSearchTarget: "搜尋目暙",
                labelHitName: "排陀僅圚顯瀺名皱䞭的盞笊項目",
                labelHitHandle: "排陀僅圚䜿甚者名皱 (@handle) 䞭的盞笊項目",
                hintSearchTarget: "隱藏僅圚名皱或䜿甚者名皱䞭盞笊而非內文的貌文。",
                hintName: "劂果關鍵字僅出珟圚顯瀺名皱䞭則隱藏。",
                hintHandle: "劂果關鍵字僅出珟圚 @䜿甚者名皱 䞭則隱藏。䟋倖當查詢䞭明確䜿甚了 from:/to:/@ 時陀倖。",

                tabMute: "靜音",
                labelMuteWord: "新增靜音詞圙",
                placeholderMuteWord: "䟋劂劇透",
                labelCaseSensitive: "區分倧小寫",
                labelWordBoundary: "党字匹配",
                labelEnabled: "已啟甚",
                labelEnableAll: "党郚啟甚",
                buttonAdd: "新增",
                emptyMuted: "暫無靜音詞圙。",
                mutedListTitle: "靜音詞圙",
                mutedListHeading: "靜音枅單",
                optMuteHidden: "隱藏",
                optMuteCollapsed: "收合",
                placeholderFilterMute: "篩遞靜音詞圙...",
                muteLabel: "已靜音: ",
                buttonShow: "顯瀺",
                muteHit: "靜音內文盞笊項目",
                buttonRemute: "重新靜音",
                buttonImport: "匯入",
                buttonExport: "匯出",

                /* Accounts tab */
                tabAccounts: "垳號",
                emptyAccounts: "暫無垳號。請打開個人檔案頁面䞊點擊新增按鈕進行儲存。",
                buttonAddAccount: "新增垳號",
                toastAccountAdded: "垳號已新增。",
                toastAccountExists: "已存圚。",
                buttonConfirm: "確認",

                /* Lists tab */
                tabLists: "列衚",
                emptyLists: "暫無列衚。請打開列衚頁䞊點擊右䞊角的 + 按鈕新增。",
                buttonAddList: "新增列衚",
                toastListAdded: "列衚已新增。",
                toastListExists: "已存圚。",

                /* History tab */
                placeholderSearchHistory: "搜尋玀錄 (關鍵字)",
                labelSortBy: "排序:",
                placeholderSearchSaved: "搜尋已儲存 (關鍵字)",
                sortNewest: "最新",
                sortOldest: "最舊",
                sortNameAsc: "關鍵字 (A-Z)",
                sortNameDesc: "關鍵字 (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "篩遞垳號 (@, 名皱)",
                placeholderFilterLists: "篩遞列衚 (名皱, URL)",
                buttonAddFolder: "+資料借",
                folderFilterAll: "党郚",
                folderFilterUnassigned: "未分類",
                folderRename: "重新呜名",
                folderRenameTitle: "重新呜名資料借",
                folderDelete: "刪陀",
                folderDeleteTitle: "刪陀資料借",
                promptNewFolder: "新資料借名皱",
                confirmDeleteFolder: "確定芁刪陀歀資料借及其內郚所有項目嗎歀操䜜無法埩原。",
                optListsAll: "列衚",
                defaultSavedFolders: "已儲存的搜尋",

                /* Favorites */
                tabFavorites: "收藏",
                emptyFavorites: "暫無收藏的貌文。點擊貌文䞊的 ★ 按鈕進行儲存。",
                optFavoritesAll: "所有收藏",
                toastFavorited: "已加入收藏。",
                toastUnfavorited: "已埞收藏䞭移陀。",

                /* Settings */
                settingsTitle: "蚭定",
                settingsTitleGeneral: "䞀般",
                settingsTitleFeatures: "暙籀顯瀺",
                settingsTitleData: "資料管理",
                buttonClose: "關閉",
                labelUILang: "介面語蚀",
                optUILangAuto: "自動",
                labelInitialTab: "啟動時開啟的分頁",
                optInitialTabLast: "䞊次開啟的分頁 (預蚭)",
                labelImportExport: "匯入 / 匯出",
                placeholderSettingsJSON: "請圚歀貌䞊備仜 JSON...",
                tooltipSettings: "打開蚭定",
                toastImported: "已匯入。",
                toastExported: "已匯出至檔案。",
                alertInvalidJSON: "無效的 JSON 檔案。",
                alertInvalidData: "無效的資料栌匏。",
                alertInvalidApp: '歀檔案䞍是 "Advanced Search for X" 的備仜資料。',
                buttonReset: "重蚭所有資料",
                confirmResetAll: "確定芁重蚭所有資料嗎歀操䜜無法埩原。",
                toastReset: "所有資料已重蚭。",
                buttonImportSuccess: "匯入成功 👍",

                /* Favorites Sort */
                sortSavedNewest: "儲存日期 (最新)",
                sortSavedOldest: "儲存日期 (最舊)",
                sortPostedNewest: "癌垃日期 (最新)",
                sortPostedOldest: "癌垃日期 (最舊)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: '未分類',
                FT_DROPDOWN_TITLE: '收藏暙籀',
                FT_DROPDOWN_SETTINGS_TITLE: '收藏暙籀蚭定',
                FT_DROPDOWN_NEW_TAG: '新建暙籀',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: '暙籀名皱',
                FT_DROPDOWN_NEW_TAG_ADD: '新增',
                FT_FILTER_ALL: '党郚',
                FT_SETTINGS_TITLE: '收藏暙籀蚭定',
                FT_SETTINGS_EMPTY_TAG_LIST: '暫無暙籀。悚可以埞「新建暙籀」新增。',
                FT_SETTINGS_UNCATEGORIZED_NAME: '未分類',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: '「未分類」的名皱無法曎改。',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '「未分類」無法被刪陀。',
                FT_SETTINGS_CLOSE: '關閉',
                FT_SETTINGS_DELETE_BUTTON: '刪陀',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: '顯瀺蚭定',
                FT_SETTINGS_DISPLAY_MODE_LABEL: '暙籀顯瀺栌匏',
                FT_SETTINGS_DISPLAY_MODE_LEAF: '僅末玚 (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: '完敎路埑 (full)',
                FT_CONFIRM_DELETE_TAG_MSG: '確定芁刪陀暙籀「{tagName}」嗎\n垶有歀暙籀的收藏將變為「未分類」。',
                FT_SETTINGS_BUTTON_TITLE: '收藏暙籀蚭定',
            },
            'ko': {
                modalTitle: "고꞉ 검색",
                tooltipClose: "ë‹«êž°",
                labelAllWords: "닀음 닚얎 몚두 포핚",
                placeholderAllWords: "예: AI 뉎슀",
                labelExactPhrase: "정확하게 음치하는 묞구",
                placeholderExactPhrase: '예: "ChatGPT 4o"',
                labelAnyWords: "닀음 닚얎 쀑 하나띌도 포핚 (OR)",
                placeholderAnyWords: "예: iPhone Android",
                labelNotWords: "닀음 닚얎 제왞 (-)",
                placeholderNotWords: "예: -섞음 -ꎑ고",
                labelHashtag: "핎시태귞 (#)",
                placeholderHashtag: "예: #개발자",
                labelLang: "ì–žì–Ž (lang:)",
                optLangDefault: "몚든 ì–žì–Ž",
                optLangJa: "음볞얎 (ja)",
                optLangEn: "영얎 (en)",
                optLangId: "읞도넀시아얎 (id)",
                optLangHi: "힌디얎 (hi)",
                optLangDe: "독음얎 (de)",
                optLangTr: "튀륎킀예얎 (tr)",
                optLangEs: "슀페읞얎 (es)",
                optLangPt: "포륎투갈얎 (pt)",
                optLangAr: "아랍얎 (ar)",
                optLangFr: "프랑슀얎 (fr)",
                optLangKo: "한국얎 (ko)",
                optLangRu: "러시아얎 (ru)",
                optLangZhHans: "쀑국얎 간첎 (zh-cn)",
                optLangZhHant: "쀑국얎 번첎 (zh-tw)",
                hrSeparator: " ",
                labelFilters: "필터",
                labelVerified: "읞슝된 계정",
                labelLinks: "링크",
                labelImages: "읎믞지",
                labelVideos: "동영상",
                labelReposts: "재게시",
                labelTimelineHashtags: "핎시태귞 (#)",
                checkInclude: "포핚",
                checkExclude: "제왞",
                labelReplies: "답Ꞁ",
                optRepliesDefault: "Ʞ볞 (몚두 표시)",
                optRepliesInclude: "답Ꞁ 포핚",
                optRepliesOnly: "답Ꞁ만",
                optRepliesExclude: "답Ꞁ 제왞",
                labelEngagement: "ì°žì—¬",
                placeholderMinReplies: "최소 답Ꞁ 수",
                placeholderMinLikes: "최소 마음에 듀얎요 수",
                placeholderMinRetweets: "최소 재게시 수",
                labelDateRange: "날짜 범위",
                labelDateShortcut: "빠륞 범위 섀정",
                optDate1Day: "지난 24시간",
                optDate1Week: "지난 1죌",
                optDate1Month: "지난 1개월",
                optDate3Months: "지난 3개월",
                optDate6Months: "지난 6개월",
                optDate1Year: "지난 1년",
                optDate2Years: "지난 2년",
                optDate3Years: "지난 3년",
                optDate5Years: "지난 5년",
                optDateClear: "날짜 쎈Ʞ화",
                tooltipSince: "시작음",
                tooltipUntil: "종료음",
                labelFromUser: "닀음 계정에서 (from:)",
                placeholderFromUser: "예: @X",
                labelToUser: "닀음 계정윌로 (to:)",
                placeholderToUser: "예: @google",
                labelMentioning: "닀음 계정 얞꞉ (@)",
                placeholderMentioning: "예: @OpenAI",
                buttonClear: "지우Ʞ",
                buttonApply: "검색",
                tooltipTrigger: "고꞉ 검색 ì—Žêž°",
                buttonOpen: "ì—Žêž°",

                tabSearch: "검색",
                tabHistory: "Ʞ록",
                tabSaved: "저장됚",
                buttonSave: "저장",
                buttonSaved: "저장됚",
                secretMode: "시크늿 몚드",
                secretOn: "시크늿 몚드 쌜짐 (Ʞ록되지 않음)",
                secretOff: "시크늿 몚드 꺌짐",
                toastSaved: "저장되었습니닀.",
                toastDeleted: "삭제되었습니닀.",
                toastReordered: "순서가 업데읎튞되었습니닀.",
                emptyHistory: "Ʞ록읎 없습니닀.",
                emptySaved: "저장된 검색읎 없습니닀. 검색 탭 왌쪜 하닚의 저장 버튌윌로 추가하섞요.",
                run: "싀행",
                delete: "삭제",
                updated: "업데읎튞됚.",
                tooltipSecret: "시크늿 몚드 전환 (검색 Ʞ록을 저장하지 않음)",
                historyClearAll: "몚두 지우Ʞ",
                confirmClearHistory: "몚든 Ʞ록을 삭제하시겠습니까?",

                labelAccountScope: "계정 범위",
                optAccountAll: "몚든 계정",
                optAccountFollowing: "팔로우 쀑읞 계정",
                labelLocationScope: "위치 범위",
                optLocationAll: "몚든 위치",
                optLocationNearby: "낮 죌변",
                chipFollowing: "팔로잉",
                chipNearby: "죌변",

                labelSearchTarget: "검색 대상",
                labelHitName: "표시 읎늄(닉넀임)만 음치하는 결곌 제왞",
                labelHitHandle: "사용자 아읎디(@handle)만 음치하는 결곌 제왞",
                hintSearchTarget: "볞묞읎 아닌 읎늄/아읎디만 음치하는 게시묌을 숚깁니닀.",
                hintName: "킀워드가 표시 읎늄에만 포핚된 겜우 숚깁니닀.",
                hintHandle: "킀워드가 @아읎디에만 포핚된 겜우 숚깁니닀. 예왞: 검색얎에 from:/to:/@ 등윌로 명시한 겜우는 표시합니닀.",

                tabMute: "뮀튞",
                labelMuteWord: "뮀튞 닚얎 추가",
                placeholderMuteWord: "예: 슀포음러",
                labelCaseSensitive: "대소묞자 구분",
                labelWordBoundary: "닚얎 닚위",
                labelEnabled: "활성화",
                labelEnableAll: "몚두 활성화",
                buttonAdd: "추가",
                emptyMuted: "뮀튞된 닚얎가 없습니닀.",
                mutedListTitle: "뮀튞 닚얎",
                mutedListHeading: "뮀튞 목록",
                optMuteHidden: "숚ꞰꞰ",
                optMuteCollapsed: "ì ‘êž°",
                placeholderFilterMute: "뮀튞 닚얎 검색...",
                muteLabel: "뮀튞됚: ",
                buttonShow: "표시",
                muteHit: "볞묞 음치 항목 뮀튞",
                buttonRemute: "닀시 뮀튞",
                buttonImport: "가젞였Ʞ",
                buttonExport: "낎볎낎Ʞ",

                /* Accounts tab */
                tabAccounts: "계정",
                emptyAccounts: "저장된 계정읎 없습니닀. 프로필 페읎지륌 ì—Žê³  추가 버튌을 눌러 저장하섞요.",
                buttonAddAccount: "계정 추가",
                toastAccountAdded: "계정읎 추가되었습니닀.",
                toastAccountExists: "읎믞 추가되었습니닀.",
                buttonConfirm: "확읞",

                /* Lists tab */
                tabLists: "늬슀튞",
                emptyLists: "저장된 늬슀튞가 없습니닀. 늬슀튞륌 ì—Žê³  ìš°ìž¡ 상닚의 + 버튌을 눌러 추가하섞요.",
                buttonAddList: "늬슀튞 추가",
                toastListAdded: "늬슀튞가 추가되었습니닀.",
                toastListExists: "읎믞 추가되었습니닀.",

                /* History tab */
                placeholderSearchHistory: "Ʞ록 검색 (검색얎)",
                labelSortBy: "정렬:",
                placeholderSearchSaved: "저장된 항목 검색 (검색얎)",
                sortNewest: "최신순",
                sortOldest: "였래된순",
                sortNameAsc: "읎늄순 (ㄱ-ㅎ)",
                sortNameDesc: "읎늄순 (ㅎ-ㄱ)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "계정 필터링 (@, 읎늄)",
                placeholderFilterLists: "늬슀튞 필터링 (읎늄, URL)",
                buttonAddFolder: "+폮더",
                folderFilterAll: "전첎",
                folderFilterUnassigned: "믞분류",
                folderRename: "읎늄 변겜",
                folderRenameTitle: "폮더 읎늄 변겜",
                folderDelete: "삭제",
                folderDeleteTitle: "폮더 삭제",
                promptNewFolder: "새 폮더 읎늄",
                confirmDeleteFolder: "읎 폎더와 낎부의 몚든 항목을 삭제하시겠습니까? 읎 작업은 되돌멮 수 없습니닀.",
                optListsAll: "늬슀튞",
                defaultSavedFolders: "저장된 검색",

                /* Favorites */
                tabFavorites: "슐겚찟Ʞ",
                emptyFavorites: "슐겚찟Ʞ에 추가한 게시묌읎 없습니닀. 게시묌의 ★ 버튌을 눌러 저장하섞요.",
                optFavoritesAll: "몚든 슐겚찟Ʞ",
                toastFavorited: "슐겚찟Ʞ에 추가했습니닀.",
                toastUnfavorited: "슐겚찟Ʞ에서 삭제했습니닀.",

                /* Settings */
                settingsTitle: "섀정",
                settingsTitleGeneral: "음반",
                settingsTitleFeatures: "탭 표시 섀정",
                settingsTitleData: "데읎터 ꎀ늬",
                buttonClose: "ë‹«êž°",
                labelUILang: "UI ì–žì–Ž",
                optUILangAuto: "자동",
                labelInitialTab: "시작 시 ì—Ž 탭",
                optInitialTabLast: "마지막에 연 탭 (Ʞ볞)",
                labelImportExport: "가젞였Ʞ / 낎볎낎Ʞ",
                placeholderSettingsJSON: "백업 JSON을 여Ʞ에 붙여넣윌섞요...",
                tooltipSettings: "섀정 ì—Žêž°",
                toastImported: "가젞였Ʞ가 완료되었습니닀.",
                alertInvalidJSON: "유횚하지 않은 JSON 파음입니닀.",
                alertInvalidData: "유횚하지 않은 데읎터 형식입니닀.",
                alertInvalidApp: '"Advanced Search for X"의 백업 파음읎 아닙니닀.',
                toastExported: "파음로 낎볎냈습니닀.",
                buttonReset: "몚든 데읎터 쎈Ʞ화",
                confirmResetAll: "몚든 데읎터륌 쎈Ʞ화하시겠습니까? 읎 작업은 되돌멮 수 없습니닀.",
                toastReset: "몚든 데읎터가 쎈Ʞ화되었습니닀.",
                buttonImportSuccess: "가젞였Ʞ 성공 👍",

                /* Favorites Sort */
                sortSavedNewest: "저장음 (최신순)",
                sortSavedOldest: "저장음 (였래된순)",
                sortPostedNewest: "게시음 (최신순)",
                sortPostedOldest: "게시음 (였래된순)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: '믞분류',
                FT_DROPDOWN_TITLE: '태귞',
                FT_DROPDOWN_SETTINGS_TITLE: '태귞 섀정',
                FT_DROPDOWN_NEW_TAG: '새 태귞',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: '태귞 읎늄',
                FT_DROPDOWN_NEW_TAG_ADD: '추가',
                FT_FILTER_ALL: '전첎',
                FT_SETTINGS_TITLE: '태귞 섀정',
                FT_SETTINGS_EMPTY_TAG_LIST:
                    '태귞가 없습니닀. "새 태귞"에서 추가할 수 있습니닀.',
                FT_SETTINGS_UNCATEGORIZED_NAME: '믞분류',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP:
                    '"믞분류" 읎늄은 변겜할 수 없습니닀.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP:
                    '"믞분류"는 삭제할 수 없습니닀.',
                FT_SETTINGS_CLOSE: 'ë‹«êž°',
                FT_SETTINGS_DELETE_BUTTON: '삭제',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: '표시',
                FT_SETTINGS_DISPLAY_MODE_LABEL: '태귞 표시 형식',
                FT_SETTINGS_DISPLAY_MODE_LEAF: '말당만 (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: '전첎 겜로 (full)',
                FT_CONFIRM_DELETE_TAG_MSG: '태귞 "{tagName}"을(륌) 삭제하시겠습니까?\n읎 태귞가 지정된 항목은 "믞분류"가 됩니닀.',
                FT_SETTINGS_BUTTON_TITLE: '태귞 섀정',
            },
            'fr': {
                modalTitle: "Recherche avancée",
                tooltipClose: "Fermer",
                labelAllWords: "Tous ces mots",
                placeholderAllWords: "ex: AI actualités",
                labelExactPhrase: "Cette phrase exacte",
                placeholderExactPhrase: 'ex: "ChatGPT 4o"',
                labelAnyWords: "L'un de ces mots (OR)",
                placeholderAnyWords: "ex: iPhone Android",
                labelNotWords: "Aucun de ces mots (-)",
                placeholderNotWords: "ex: -soldes -pub",
                labelHashtag: "Hashtags (#)",
                placeholderHashtag: "ex: #Paris2024",
                labelLang: "Langue (lang:)",
                optLangDefault: "Toutes les langues",
                optLangJa: "Japonais (ja)",
                optLangEn: "Anglais (en)",
                optLangId: "Indonésien (id)",
                optLangHi: "Hindi (hi)",
                optLangDe: "Allemand (de)",
                optLangTr: "Turc (tr)",
                optLangEs: "Espagnol (es)",
                optLangPt: "Portugais (pt)",
                optLangAr: "Arabe (ar)",
                optLangFr: "Français (fr)",
                optLangKo: "Coréen (ko)",
                optLangRu: "Russe (ru)",
                optLangZhHans: "Chinois simplifié (zh-cn)",
                optLangZhHant: "Chinois traditionnel (zh-tw)",
                hrSeparator: " ",
                labelFilters: "Filtres",
                labelVerified: "Comptes certifiés",
                labelLinks: "Liens",
                labelImages: "Images",
                labelVideos: "Vidéos",
                labelReposts: "Republications",
                labelTimelineHashtags: "Hashtags (#)",
                checkInclude: "Inclure",
                checkExclude: "Exclure",
                labelReplies: "Réponses",
                optRepliesDefault: "Par défaut (Tout)",
                optRepliesInclude: "Inclure les réponses",
                optRepliesOnly: "Réponses uniquement",
                optRepliesExclude: "Exclure les réponses",
                labelEngagement: "Engagement",
                placeholderMinReplies: "Min réponses",
                placeholderMinLikes: "Min J'aime",
                placeholderMinRetweets: "Min republications",
                labelDateRange: "Période",
                labelDateShortcut: "Plage rapide",
                optDate1Day: "DerniÚres 24h",
                optDate1Week: "Semaine derniÚre",
                optDate1Month: "Mois dernier",
                optDate3Months: "3 derniers mois",
                optDate6Months: "6 derniers mois",
                optDate1Year: "Année derniÚre",
                optDate2Years: "2 derniÚres années",
                optDate3Years: "3 derniÚres années",
                optDate5Years: "5 derniÚres années",
                optDateClear: "Effacer les dates",
                tooltipSince: "Depuis cette date",
                tooltipUntil: "Jusqu'à cette date",
                labelFromUser: "De ces comptes (from:)",
                placeholderFromUser: "ex: @X",
                labelToUser: "À ces comptes (to:)",
                placeholderToUser: "ex: @google",
                labelMentioning: "Mentionnant ces comptes (@)",
                placeholderMentioning: "ex: @OpenAI",
                buttonClear: "Effacer",
                buttonApply: "Rechercher",
                tooltipTrigger: "Ouvrir la recherche avancée",
                buttonOpen: "Ouvrir",

                tabSearch: "Recherche",
                tabHistory: "Historique",
                tabSaved: "Enregistré",
                buttonSave: "Enregistrer",
                buttonSaved: "Enregistré",
                secretMode: "Mode privé",
                secretOn: "Mode privé activé (Pas d'historique)",
                secretOff: "Mode privé désactivé",
                toastSaved: "Enregistré.",
                toastDeleted: "Supprimé.",
                toastReordered: "Ordre mis à jour.",
                emptyHistory: "Aucun historique.",
                emptySaved: "Aucune recherche enregistrée. Ajoutez-en via le bouton Enregistrer en bas à gauche de l'onglet Recherche.",
                run: "Lancer",
                delete: "Supprimer",
                updated: "Mis à jour.",
                tooltipSecret: "Basculer le mode privé (aucun historique ne sera enregistré)",
                historyClearAll: "Tout effacer",
                confirmClearHistory: "Effacer tout l'historique ?",

                labelAccountScope: "Comptes",
                optAccountAll: "Tous les comptes",
                optAccountFollowing: "Comptes suivis",
                labelLocationScope: "Lieu",
                optLocationAll: "Tous les lieux",
                optLocationNearby: "Proche de vous",
                chipFollowing: "Abonnements",
                chipNearby: "À proximité",

                labelSearchTarget: "Cible de la recherche",
                labelHitName: "Exclure les résultats dans le nom d'affichage",
                labelHitHandle: "Exclure les résultats dans le nom d'utilisateur (@)",
                hintSearchTarget: "Masquer les posts qui ne correspondent que par le nom ou l'identifiant (pas dans le texte).",
                hintName: "Si un mot-clé n'apparaît que dans le nom d'affichage, le masquer.",
                hintHandle: "Si un mot-clé n'apparaît que dans le @nom_utilisateur, le masquer. Exception : si la requête utilise explicitement from:/to:/@.",

                tabMute: "Masquer",
                labelMuteWord: "Ajouter un mot masqué",
                placeholderMuteWord: "ex: spoiler",
                labelCaseSensitive: "Sensible à la casse",
                labelWordBoundary: "Mot entier",
                labelEnabled: "Activé",
                labelEnableAll: "Tout activer",
                buttonAdd: "Ajouter",
                emptyMuted: "Aucun mot masqué.",
                mutedListTitle: "Mots masqués",
                mutedListHeading: "Liste masquée",
                optMuteHidden: "Masqué",
                optMuteCollapsed: "Réduit",
                placeholderFilterMute: "Filtrer les mots masqués...",
                muteLabel: "Masqué : ",
                buttonShow: "Afficher",
                muteHit: "Masquer les résultats dans le texte",
                buttonRemute: "Masquer à nouveau",
                buttonImport: "Importer",
                buttonExport: "Exporter",

                /* Accounts tab */
                tabAccounts: "Comptes",
                emptyAccounts: "Aucun compte. Ouvrez un profil et cliquez sur le bouton Ajouter pour l'enregistrer.",
                buttonAddAccount: "Ajouter compte",
                toastAccountAdded: "Compte ajouté.",
                toastAccountExists: "Déjà ajouté.",
                buttonConfirm: "Confirmer",

                /* Lists tab */
                tabLists: "Listes",
                emptyLists: "Aucune liste. Ouvrez une liste et cliquez sur le bouton + en haut à droite pour l'ajouter.",
                buttonAddList: "Ajouter liste",
                toastListAdded: "Liste ajoutée.",
                toastListExists: "Déjà ajoutée.",

                /* History tab */
                placeholderSearchHistory: "Historique (requête)",
                labelSortBy: "Trier par :",
                placeholderSearchSaved: "Recherches enregistrées (requête)",
                sortNewest: "Plus récent",
                sortOldest: "Plus ancien",
                sortNameAsc: "Nom (A-Z)",
                sortNameDesc: "Nom (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "Filtrer comptes (@, nom)",
                placeholderFilterLists: "Filtrer listes (nom, url)",
                buttonAddFolder: "+Dossier",
                folderFilterAll: "TOUT",
                folderFilterUnassigned: "Non classé",
                folderRename: "Renommer",
                folderRenameTitle: "Renommer le dossier",
                folderDelete: "Supprimer",
                folderDeleteTitle: "Supprimer le dossier",
                promptNewFolder: "Nom du dossier",
                confirmDeleteFolder: "Supprimer ce dossier et tout son contenu ? Cette action est irréversible.",
                optListsAll: "Listes",
                defaultSavedFolders: "Recherches enregistrées",

                /* Favorites */
                tabFavorites: "Favoris",
                emptyFavorites: "Aucun favori. Cliquez sur l'icÃŽne ★ d'un tweet pour l'enregistrer.",
                optFavoritesAll: "Tous les favoris",
                toastFavorited: "Ajouté aux favoris.",
                toastUnfavorited: "Retiré des favoris.",

                /* Settings */
                settingsTitle: "ParamÚtres",
                settingsTitleGeneral: "Général",
                settingsTitleFeatures: "Affichage onglets",
                settingsTitleData: "Données",
                buttonClose: "Fermer",
                labelUILang: "Langue de l'interface",
                optUILangAuto: "Auto",
                labelInitialTab: "Onglet au démarrage",
                optInitialTabLast: "Dernier ouvert (Défaut)",
                labelImportExport: "Importer / Exporter",
                placeholderSettingsJSON: "Collez le JSON de sauvegarde ici...",
                tooltipSettings: "Ouvrir les paramÚtres",
                toastImported: "Importé.",
                toastExported: "Exporté vers un fichier.",
                alertInvalidJSON: "Fichier JSON invalide.",
                alertInvalidData: "Format de données invalide.",
                alertInvalidApp: 'Ce fichier n\'est pas une sauvegarde valide pour "Advanced Search for X".',
                buttonReset: "Réinitialiser tout",
                confirmResetAll: "Tout réinitialiser ? Cette action est irréversible.",
                toastReset: "Toutes les données ont été réinitialisées.",
                buttonImportSuccess: "Importation réussie 👍",

                /* Favorites Sort */
                sortSavedNewest: "Date d'ajout (Récent)",
                sortSavedOldest: "Date d'ajout (Ancien)",
                sortPostedNewest: "Date de publication (Récent)",
                sortPostedOldest: "Date de publication (Ancien)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Non classé',
                FT_DROPDOWN_TITLE: 'Tags favoris',
                FT_DROPDOWN_SETTINGS_TITLE: 'Réglages des tags',
                FT_DROPDOWN_NEW_TAG: 'Nouveau tag',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'Nom du tag',
                FT_DROPDOWN_NEW_TAG_ADD: 'Ajouter',
                FT_FILTER_ALL: 'Tout',
                FT_SETTINGS_TITLE: 'Réglages des tags favoris',
                FT_SETTINGS_EMPTY_TAG_LIST: 'Aucun tag. Ajoutez-en un depuis "Nouveau tag".',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Non classé',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: 'Le nom "Non classé" ne peut pas être modifié.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '"Non classé" ne peut pas être supprimé.',
                FT_SETTINGS_CLOSE: 'Fermer',
                FT_SETTINGS_DELETE_BUTTON: 'Supprimer',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'Affichage',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'Format du tag',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'Libellé seul (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'Chemin complet',
                FT_CONFIRM_DELETE_TAG_MSG: 'Supprimer le tag "{tagName}" ?\nLes favoris associés deviendront "Non classé".',
                FT_SETTINGS_BUTTON_TITLE: 'Réglages des tags',
            },
            'es': {
                modalTitle: "Búsqueda avanzada",
                tooltipClose: "Cerrar",
                labelAllWords: "Todas estas palabras",
                placeholderAllWords: "ej. AI noticias",
                labelExactPhrase: "Esta frase exacta",
                placeholderExactPhrase: 'ej. "ChatGPT 4o"',
                labelAnyWords: "Cualquiera de estas palabras (OR)",
                placeholderAnyWords: "ej. iPhone Android",
                labelNotWords: "Ninguna de estas palabras (-)",
                placeholderNotWords: "ej. -oferta -anuncio",
                labelHashtag: "Hashtags (#)",
                placeholderHashtag: "ej. #Tecnología",
                labelLang: "Idioma (lang:)",
                optLangDefault: "Cualquier idioma",
                optLangJa: "Japonés (ja)",
                optLangEn: "Inglés (en)",
                optLangId: "Indonesio (id)",
                optLangHi: "Hindi (hi)",
                optLangDe: "Alemán (de)",
                optLangTr: "Turco (tr)",
                optLangEs: "Español (es)",
                optLangPt: "Portugués (pt)",
                optLangAr: "Árabe (ar)",
                optLangFr: "Francés (fr)",
                optLangKo: "Coreano (ko)",
                optLangRu: "Ruso (ru)",
                optLangZhHans: "Chino simplificado (zh-cn)",
                optLangZhHant: "Chino tradicional (zh-tw)",
                hrSeparator: " ",
                labelFilters: "Filtros",
                labelVerified: "Cuentas verificadas",
                labelLinks: "Enlaces",
                labelImages: "Imágenes",
                labelVideos: "Vídeos",
                labelReposts: "Reposts",
                labelTimelineHashtags: "Hashtags (#)",
                checkInclude: "Incluir",
                checkExclude: "Excluir",
                labelReplies: "Respuestas",
                optRepliesDefault: "Por defecto (Todo)",
                optRepliesInclude: "Incluir respuestas",
                optRepliesOnly: "Solo respuestas",
                optRepliesExclude: "Excluir respuestas",
                labelEngagement: "Interacciones",
                placeholderMinReplies: "Mín. respuestas",
                placeholderMinLikes: "Mín. Me gusta",
                placeholderMinRetweets: "Mín. reposts",
                labelDateRange: "Rango de fechas",
                labelDateShortcut: "Rango rápido",
                optDate1Day: "Últimas 24 horas",
                optDate1Week: "Última semana",
                optDate1Month: "Último mes",
                optDate3Months: "Últimos 3 meses",
                optDate6Months: "Últimos 6 meses",
                optDate1Year: "Último año",
                optDate2Years: "Últimos 2 años",
                optDate3Years: "Últimos 3 años",
                optDate5Years: "Últimos 5 años",
                optDateClear: "Borrar fechas",
                tooltipSince: "Desde esta fecha",
                tooltipUntil: "Hasta esta fecha",
                labelFromUser: "De estas cuentas (from:)",
                placeholderFromUser: "ej. @X",
                labelToUser: "Para estas cuentas (to:)",
                placeholderToUser: "ej. @google",
                labelMentioning: "Mencionando a estas cuentas (@)",
                placeholderMentioning: "ej. @OpenAI",
                buttonClear: "Borrar",
                buttonApply: "Buscar",
                tooltipTrigger: "Abrir búsqueda avanzada",
                buttonOpen: "Abrir",

                tabSearch: "Búsqueda",
                tabHistory: "Historial",
                tabSaved: "Guardado",
                buttonSave: "Guardar",
                buttonSaved: "Guardado",
                secretMode: "Secreto",
                secretOn: "Modo secreto ACTIVADO (sin historial)",
                secretOff: "Modo secreto DESACTIVADO",
                toastSaved: "Guardado.",
                toastDeleted: "Eliminado.",
                toastReordered: "Orden actualizado.",
                emptyHistory: "Aún no hay historial.",
                emptySaved: "No hay búsquedas guardadas. Añade una desde el botón Guardar abajo a la izquierda en la pestaña Búsqueda.",
                run: "Ejecutar",
                delete: "Eliminar",
                updated: "Actualizado.",
                tooltipSecret: "Alternar modo secreto (no se guardará historial)",
                historyClearAll: "Borrar todo",
                confirmClearHistory: "¿Borrar todo el historial?",

                labelAccountScope: "Cuentas",
                optAccountAll: "Todas las cuentas",
                optAccountFollowing: "Cuentas que sigues",
                labelLocationScope: "Ubicación",
                optLocationAll: "Todas las ubicaciones",
                optLocationNearby: "Cerca de ti",
                chipFollowing: "Siguiendo",
                chipNearby: "Cerca",

                labelSearchTarget: "Ámbito de búsqueda",
                labelHitName: "Excluir coincidencias solo en nombre",
                labelHitHandle: "Excluir coincidencias solo en usuario (@)",
                hintSearchTarget: "Ocultar publicaciones que solo coincidan en el nombre o usuario (no en el cuerpo).",
                hintName: "Si la palabra clave aparece solo en el nombre mostrado, ocultarla.",
                hintHandle: "Si la palabra clave aparece solo en el @usuario, ocultarla. Excepción: si la consulta usa explícitamente from:/to:/@.",

                tabMute: "Silenciar",
                labelMuteWord: "Añadir palabra silenciada",
                placeholderMuteWord: "ej. spoiler",
                labelCaseSensitive: "Distinguir mayúsculas",
                labelWordBoundary: "Palabra completa",
                labelEnabled: "Habilitado",
                labelEnableAll: "Habilitar todo",
                buttonAdd: "Añadir",
                emptyMuted: "No hay palabras silenciadas.",
                mutedListTitle: "Palabras silenciadas",
                mutedListHeading: "Lista de silenciados",
                optMuteHidden: "Oculto",
                optMuteCollapsed: "Colapsado",
                placeholderFilterMute: "Filtrar palabras silenciadas...",
                muteLabel: "Silenciado: ",
                buttonShow: "Mostrar",
                muteHit: "Silenciar coincidencias en cuerpo",
                buttonRemute: "Volver a silenciar",
                buttonImport: "Importar",
                buttonExport: "Exportar",

                /* Accounts tab */
                tabAccounts: "Cuentas",
                emptyAccounts: "Aún no hay cuentas. Abre un perfil y haz clic en el botón Añadir para guardarlo.",
                buttonAddAccount: "Añadir cuenta",
                toastAccountAdded: "Cuenta añadida.",
                toastAccountExists: "Ya existe.",
                buttonConfirm: "Confirmar",

                /* Lists tab */
                tabLists: "Listas",
                emptyLists: "Aún no hay listas. Abre una lista y haz clic en el botón + arriba a la derecha para añadirla.",
                buttonAddList: "Añadir lista",
                toastListAdded: "Lista añadida.",
                toastListExists: "Ya existe.",

                /* History tab */
                placeholderSearchHistory: "Historial de búsqueda (consulta)",
                labelSortBy: "Ordenar por:",
                placeholderSearchSaved: "Búsquedas guardadas (consulta)",
                sortNewest: "Más reciente",
                sortOldest: "Más antiguo",
                sortNameAsc: "Nombre (A-Z)",
                sortNameDesc: "Nombre (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "Filtrar cuentas (@, nombre)",
                placeholderFilterLists: "Filtrar listas (nombre, url)",
                buttonAddFolder: "+Carpeta",
                folderFilterAll: "TODO",
                folderFilterUnassigned: "Sin asignar",
                folderRename: "Renombrar",
                folderRenameTitle: "Renombrar carpeta",
                folderDelete: "Eliminar",
                folderDeleteTitle: "Eliminar carpeta",
                promptNewFolder: "Nombre de nueva carpeta",
                confirmDeleteFolder: "¿Eliminar esta carpeta y todo su contenido? Esto no se puede deshacer.",
                optListsAll: "Listas",
                defaultSavedFolders: "Búsquedas guardadas",

                /* Favorites */
                tabFavorites: "Favoritos",
                emptyFavorites: "No hay favoritos. Haz clic en el icono ★ de los tweets para guardarlos.",
                optFavoritesAll: "Todos los favoritos",
                toastFavorited: "Añadido a favoritos.",
                toastUnfavorited: "Eliminado de favoritos.",

                /* Settings */
                settingsTitle: "Configuración",
                settingsTitleGeneral: "General",
                settingsTitleFeatures: "Visibilidad de pestañas",
                settingsTitleData: "Datos",
                buttonClose: "Cerrar",
                labelUILang: "Idioma de interfaz",
                optUILangAuto: "Automático",
                labelInitialTab: "Pestaña de inicio",
                optInitialTabLast: "Última abierta (Predeterminado)",
                labelImportExport: "Importar / Exportar",
                placeholderSettingsJSON: "Pega el JSON de respaldo aquí...",
                tooltipSettings: "Abrir configuración",
                toastImported: "Importado.",
                toastExported: "Exportado a archivo.",
                alertInvalidJSON: "Archivo JSON inválido.",
                alertInvalidData: "Formato de datos inválido.",
                alertInvalidApp: 'Este archivo no es un respaldo válido para "Advanced Search for X".',
                buttonReset: "Restablecer todo",
                confirmResetAll: "¿Restablecer todos los datos? Esto no se puede deshacer.",
                toastReset: "Todos los datos han sido restablecidos.",
                buttonImportSuccess: "Importado con éxito 👍",

                /* Favorites Sort */
                sortSavedNewest: "Fecha de guardado (Reciente)",
                sortSavedOldest: "Fecha de guardado (Antigua)",
                sortPostedNewest: "Fecha de publicación (Reciente)",
                sortPostedOldest: "Fecha de publicación (Antigua)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Sin categoría',
                FT_DROPDOWN_TITLE: 'Etiquetas de favoritos',
                FT_DROPDOWN_SETTINGS_TITLE: 'Configuración de etiquetas',
                FT_DROPDOWN_NEW_TAG: 'Nueva etiqueta',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'Nombre de etiqueta',
                FT_DROPDOWN_NEW_TAG_ADD: 'Añadir',
                FT_FILTER_ALL: 'Todo',
                FT_SETTINGS_TITLE: 'Configuración de etiquetas',
                FT_SETTINGS_EMPTY_TAG_LIST: 'No hay etiquetas. Añade una desde "Nueva etiqueta".',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Sin categoría',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: 'El nombre "Sin categoría" no se puede cambiar.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '"Sin categoría" no se puede eliminar.',
                FT_SETTINGS_CLOSE: 'Cerrar',
                FT_SETTINGS_DELETE_BUTTON: 'Eliminar',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'Visualización',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'Formato de etiqueta',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'Solo etiqueta (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'Ruta completa (full)',
                FT_CONFIRM_DELETE_TAG_MSG: '¿Eliminar la etiqueta "{tagName}"?\nLos favoritos con esta etiqueta pasarán a "Sin categoría".',
                FT_SETTINGS_BUTTON_TITLE: 'Configuración de etiquetas',
            },
            'de': {
                modalTitle: "Erweiterte Suche",
                tooltipClose: "Schließen",
                labelAllWords: "All diese Wörter",
                placeholderAllWords: "z.B. AI Nachrichten",
                labelExactPhrase: "Genau dieser Ausdruck",
                placeholderExactPhrase: 'z.B. "ChatGPT 4o"',
                labelAnyWords: "Beliebige dieser Wörter (OR)",
                placeholderAnyWords: "z.B. iPhone Android",
                labelNotWords: "Keines dieser Wörter (-)",
                placeholderNotWords: "z.B. -Verkauf -Werbung",
                labelHashtag: "Hashtags (#)",
                placeholderHashtag: "z.B. #TechEvent",
                labelLang: "Sprache (lang:)",
                optLangDefault: "Beliebige Sprache",
                optLangJa: "Japanisch (ja)",
                optLangEn: "Englisch (en)",
                optLangId: "Indonesisch (id)",
                optLangHi: "Hindi (hi)",
                optLangDe: "Deutsch (de)",
                optLangTr: "TÃŒrkisch (tr)",
                optLangEs: "Spanisch (es)",
                optLangPt: "Portugiesisch (pt)",
                optLangAr: "Arabisch (ar)",
                optLangFr: "Französisch (fr)",
                optLangKo: "Koreanisch (ko)",
                optLangRu: "Russisch (ru)",
                optLangZhHans: "Chinesisch vereinfacht (zh-cn)",
                optLangZhHant: "Chinesisch traditionell (zh-tw)",
                hrSeparator: " ",
                labelFilters: "Filter",
                labelVerified: "Verifizierte Konten",
                labelLinks: "Links",
                labelImages: "Bilder",
                labelVideos: "Videos",
                labelReposts: "Reposts",
                labelTimelineHashtags: "Hashtags (#)",
                checkInclude: "Einschl.",
                checkExclude: "Ausschl.",
                labelReplies: "Antworten",
                optRepliesDefault: "Standard (Alle)",
                optRepliesInclude: "Antworten einschließen",
                optRepliesOnly: "Nur Antworten",
                optRepliesExclude: "Antworten ausschließen",
                labelEngagement: "Interaktionen",
                placeholderMinReplies: "Min. Antworten",
                placeholderMinLikes: "Min. GefÀllt mir",
                placeholderMinRetweets: "Min. Reposts",
                labelDateRange: "Zeitraum",
                labelDateShortcut: "Schnellauswahl",
                optDate1Day: "Letzte 24 Std.",
                optDate1Week: "Letzte Woche",
                optDate1Month: "Letzter Monat",
                optDate3Months: "Letzte 3 Monate",
                optDate6Months: "Letzte 6 Monate",
                optDate1Year: "Letztes Jahr",
                optDate2Years: "Letzte 2 Jahre",
                optDate3Years: "Letzte 3 Jahre",
                optDate5Years: "Letzte 5 Jahre",
                optDateClear: "Datum löschen",
                tooltipSince: "Seit diesem Datum",
                tooltipUntil: "Bis zu diesem Datum",
                labelFromUser: "Von diesen Konten (from:)",
                placeholderFromUser: "z.B. @X",
                labelToUser: "An diese Konten (to:)",
                placeholderToUser: "z.B. @google",
                labelMentioning: "ErwÀhnung dieser Konten (@)",
                placeholderMentioning: "z.B. @OpenAI",
                buttonClear: "Löschen",
                buttonApply: "Suchen",
                tooltipTrigger: "Erweiterte Suche öffnen",
                buttonOpen: "Öffnen",

                tabSearch: "Suche",
                tabHistory: "Verlauf",
                tabSaved: "Gespeichert",
                buttonSave: "Speichern",
                buttonSaved: "Gespeichert",
                secretMode: "Inkognito",
                secretOn: "Inkognito-Modus AN (Kein Verlauf)",
                secretOff: "Inkognito-Modus AUS",
                toastSaved: "Gespeichert.",
                toastDeleted: "Gelöscht.",
                toastReordered: "Reihenfolge aktualisiert.",
                emptyHistory: "Noch kein Verlauf.",
                emptySaved: "Keine gespeicherten Suchen. FÃŒgen Sie welche ÃŒber den Speichern-Button unten links im Suche-Tab hinzu.",
                run: "AusfÃŒhren",
                delete: "Löschen",
                updated: "Aktualisiert.",
                tooltipSecret: "Inkognito-Modus umschalten (kein Verlauf wird gespeichert)",
                historyClearAll: "Alle löschen",
                confirmClearHistory: "Gesamten Verlauf löschen?",

                labelAccountScope: "Konten",
                optAccountAll: "Alle Konten",
                optAccountFollowing: "Konten, denen du folgst",
                labelLocationScope: "Standort",
                optLocationAll: "Alle Standorte",
                optLocationNearby: "In deiner NÀhe",
                chipFollowing: "Folge ich",
                chipNearby: "In der NÀhe",

                labelSearchTarget: "Suchziel",
                labelHitName: "Treffer nur im Anzeigenamen ausschließen",
                labelHitHandle: "Treffer nur im Benutzernamen (@) ausschließen",
                hintSearchTarget: "BeitrÀge ausblenden, die nur im Namen oder Handle Ìbereinstimmen (nicht im Text).",
                hintName: "Wenn ein Stichwort nur im Anzeigenamen vorkommt, ausblenden.",
                hintHandle: "Wenn ein Stichwort nur im @Benutzernamen vorkommt, ausblenden. Ausnahme: wenn die Anfrage explizit from:/to:/@ verwendet.",

                tabMute: "Stummschalten",
                labelMuteWord: "Stummes Wort hinzufÃŒgen",
                placeholderMuteWord: "z.B. Spoiler",
                labelCaseSensitive: "Groß-/Kleinschreibung",
                labelWordBoundary: "Ganzes Wort",
                labelEnabled: "Aktiviert",
                labelEnableAll: "Alle aktivieren",
                buttonAdd: "HinzufÃŒgen",
                emptyMuted: "Keine stummgeschalteten Wörter.",
                mutedListTitle: "Stummgeschaltete Wörter",
                mutedListHeading: "Stummgeschaltete Liste",
                optMuteHidden: "Verborgen",
                optMuteCollapsed: "Eingeklappt",
                placeholderFilterMute: "Stummgeschaltete Wörter filtern...",
                muteLabel: "Stummgeschaltet: ",
                buttonShow: "Anzeigen",
                muteHit: "Treffer im Text stummschalten",
                buttonRemute: "Erneut stummschalten",
                buttonImport: "Importieren",
                buttonExport: "Exportieren",

                /* Accounts tab */
                tabAccounts: "Konten",
                emptyAccounts: "Noch keine Konten. Öffnen Sie ein Profil und klicken Sie auf HinzufÃŒgen, um es zu speichern.",
                buttonAddAccount: "Konto hinzufÃŒgen",
                toastAccountAdded: "Konto hinzugefÃŒgt.",
                toastAccountExists: "Bereits vorhanden.",
                buttonConfirm: "BestÀtigen",

                /* Lists tab */
                tabLists: "Listen",
                emptyLists: "Noch keine Listen. Öffnen Sie eine Liste und klicken Sie oben rechts auf +, um sie hinzuzufÃŒgen.",
                buttonAddList: "Liste hinzufÃŒgen",
                toastListAdded: "Liste hinzugefÃŒgt.",
                toastListExists: "Bereits vorhanden.",

                /* History tab */
                placeholderSearchHistory: "Suchverlauf (Query)",
                labelSortBy: "Sortieren nach:",
                placeholderSearchSaved: "Gespeicherte Suchen (Query)",
                sortNewest: "Neueste zuerst",
                sortOldest: "Älteste zuerst",
                sortNameAsc: "Name (A-Z)",
                sortNameDesc: "Name (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "Konten filtern (@, Name)",
                placeholderFilterLists: "Listen filtern (Name, URL)",
                buttonAddFolder: "+Ordner",
                folderFilterAll: "ALLE",
                folderFilterUnassigned: "Nicht zugewiesen",
                folderRename: "Umbenennen",
                folderRenameTitle: "Ordner umbenennen",
                folderDelete: "Löschen",
                folderDeleteTitle: "Ordner löschen",
                promptNewFolder: "Neuer Ordnername",
                confirmDeleteFolder: "Diesen Ordner und alle Elemente darin löschen? Dies kann nicht rÌckgÀngig gemacht werden.",
                optListsAll: "Listen",
                defaultSavedFolders: "Gespeicherte Suchen",

                /* Favorites */
                tabFavorites: "Favoriten",
                emptyFavorites: "Keine Favoriten. Klicken Sie auf das ★-Symbol bei Tweets, um sie zu speichern.",
                optFavoritesAll: "Alle Favoriten",
                toastFavorited: "Zu Favoriten hinzugefÃŒgt.",
                toastUnfavorited: "Aus Favoriten entfernt.",

                /* Settings */
                settingsTitle: "Einstellungen",
                settingsTitleGeneral: "Allgemein",
                settingsTitleFeatures: "Tab-Sichtbarkeit",
                settingsTitleData: "Daten",
                buttonClose: "Schließen",
                labelUILang: "OberflÀchensprache",
                optUILangAuto: "Automatisch",
                labelInitialTab: "Start-Tab",
                optInitialTabLast: "Zuletzt geöffnet (Standard)",
                labelImportExport: "Import / Export",
                placeholderSettingsJSON: "Backup-JSON hier einfÃŒgen...",
                tooltipSettings: "Einstellungen öffnen",
                toastImported: "Importiert.",
                toastExported: "In Datei exportiert.",
                alertInvalidJSON: "UngÃŒltige JSON-Datei.",
                alertInvalidData: "UngÃŒltiges Datenformat.",
                alertInvalidApp: 'Diese Datei ist kein gÃŒltiges Backup fÃŒr "Advanced Search for X".',
                buttonReset: "Alle Daten zurÃŒcksetzen",
                confirmResetAll: "Alle Daten zurÌcksetzen? Dies kann nicht rÌckgÀngig gemacht werden.",
                toastReset: "Alle Daten wurden zurÃŒckgesetzt.",
                buttonImportSuccess: "Erfolgreich importiert 👍",

                /* Favorites Sort */
                sortSavedNewest: "Speicherdatum (Neu)",
                sortSavedOldest: "Speicherdatum (Alt)",
                sortPostedNewest: "Veröffentlichungsdatum (Neu)",
                sortPostedOldest: "Veröffentlichungsdatum (Alt)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Unkategorisiert',
                FT_DROPDOWN_TITLE: 'Favoriten-Tags',
                FT_DROPDOWN_SETTINGS_TITLE: 'Tag-Einstellungen',
                FT_DROPDOWN_NEW_TAG: 'Neuer Tag',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'Tag-Name',
                FT_DROPDOWN_NEW_TAG_ADD: 'HinzufÃŒgen',
                FT_FILTER_ALL: 'Alle',
                FT_SETTINGS_TITLE: 'Favoriten-Tag-Einstellungen',
                FT_SETTINGS_EMPTY_TAG_LIST: 'Keine Tags. FÃŒgen Sie einen ÃŒber "Neuer Tag" hinzu.',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Unkategorisiert',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: 'Der Name "Unkategorisiert" kann nicht geÀndert werden.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '"Unkategorisiert" kann nicht gelöscht werden.',
                FT_SETTINGS_CLOSE: 'Schließen',
                FT_SETTINGS_DELETE_BUTTON: 'Löschen',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'Anzeige',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'Tag-Format',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'Nur Label (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'Voller Pfad (full)',
                FT_CONFIRM_DELETE_TAG_MSG: 'Tag "{tagName}" löschen?\nFavoriten mit diesem Tag werden "Unkategorisiert".',
                FT_SETTINGS_BUTTON_TITLE: 'Tag-Einstellungen',
            },
            'pt-BR': {
                modalTitle: "Busca avançada",
                tooltipClose: "Fechar",
                labelAllWords: "Todas estas palavras",
                placeholderAllWords: "ex: AI notícias",
                labelExactPhrase: "Esta frase exata",
                placeholderExactPhrase: 'ex: "ChatGPT 4o"',
                labelAnyWords: "Qualquer destas palavras (OR)",
                placeholderAnyWords: "ex: iPhone Android",
                labelNotWords: "Nenhuma destas palavras (-)",
                placeholderNotWords: "ex: -promoção -ads",
                labelHashtag: "Hashtags (#)",
                placeholderHashtag: "ex: #Tecnologia",
                labelLang: "Idioma (lang:)",
                optLangDefault: "Qualquer idioma",
                optLangJa: "Japonês (ja)",
                optLangEn: "Inglês (en)",
                optLangId: "Indonésio (id)",
                optLangHi: "Hindi (hi)",
                optLangDe: "Alemão (de)",
                optLangTr: "Turco (tr)",
                optLangEs: "Espanhol (es)",
                optLangPt: "Português (pt)",
                optLangAr: "Árabe (ar)",
                optLangFr: "Francês (fr)",
                optLangKo: "Coreano (ko)",
                optLangRu: "Russo (ru)",
                optLangZhHans: "Chinês Simplificado (zh-cn)",
                optLangZhHant: "Chinês Tradicional (zh-tw)",
                hrSeparator: " ",
                labelFilters: "Filtros",
                labelVerified: "Contas verificadas",
                labelLinks: "Links",
                labelImages: "Imagens",
                labelVideos: "Vídeos",
                labelReposts: "Reposts",
                labelTimelineHashtags: "Hashtags (#)",
                checkInclude: "Incluir",
                checkExclude: "Excluir",
                labelReplies: "Respostas",
                optRepliesDefault: "Padrão (Tudo)",
                optRepliesInclude: "Incluir respostas",
                optRepliesOnly: "Apenas respostas",
                optRepliesExclude: "Excluir respostas",
                labelEngagement: "Engajamento",
                placeholderMinReplies: "Mín respostas",
                placeholderMinLikes: "Mín curtidas",
                placeholderMinRetweets: "Mín reposts",
                labelDateRange: "Período",
                labelDateShortcut: "Intervalo rápido",
                optDate1Day: "Últimas 24h",
                optDate1Week: "Última semana",
                optDate1Month: "Último mês",
                optDate3Months: "Últimos 3 meses",
                optDate6Months: "Últimos 6 meses",
                optDate1Year: "Último ano",
                optDate2Years: "Últimos 2 anos",
                optDate3Years: "Últimos 3 anos",
                optDate5Years: "Últimos 5 anos",
                optDateClear: "Limpar datas",
                tooltipSince: "A partir desta data",
                tooltipUntil: "Até esta data",
                labelFromUser: "Destas contas (from:)",
                placeholderFromUser: "ex: @X",
                labelToUser: "Para estas contas (to:)",
                placeholderToUser: "ex: @google",
                labelMentioning: "Mencionando estas contas (@)",
                placeholderMentioning: "ex: @OpenAI",
                buttonClear: "Limpar",
                buttonApply: "Buscar",
                tooltipTrigger: "Abrir busca avançada",
                buttonOpen: "Abrir",

                tabSearch: "Busca",
                tabHistory: "Histórico",
                tabSaved: "Salvos",
                buttonSave: "Salvar",
                buttonSaved: "Salvo",
                secretMode: "Secreto",
                secretOn: "Modo secreto ON (Sem histórico)",
                secretOff: "Modo secreto OFF",
                toastSaved: "Salvo.",
                toastDeleted: "Excluído.",
                toastReordered: "Ordem atualizada.",
                emptyHistory: "Sem histórico ainda.",
                emptySaved: "Nenhuma busca salva. Adicione pelo botão Salvar no canto inferior esquerdo da aba Busca.",
                run: "Executar",
                delete: "Excluir",
                updated: "Atualizado.",
                tooltipSecret: "Alternar Modo Secreto (histórico não será gravado)",
                historyClearAll: "Limpar tudo",
                confirmClearHistory: "Limpar todo o histórico?",

                labelAccountScope: "Contas",
                optAccountAll: "Todas as contas",
                optAccountFollowing: "Contas que você segue",
                labelLocationScope: "Localização",
                optLocationAll: "Todas as localizações",
                optLocationNearby: "Perto de você",
                chipFollowing: "Seguindo",
                chipNearby: "Próximo",

                labelSearchTarget: "Alvo da busca",
                labelHitName: "Excluir resultados apenas no nome",
                labelHitHandle: "Excluir resultados apenas no usuário (@)",
                hintSearchTarget: "Ocultar posts que correspondem apenas ao nome ou usuário (não no corpo).",
                hintName: "Se a palavra-chave aparecer apenas no nome de exibição, ocultar.",
                hintHandle: "Se a palavra-chave aparecer apenas no @usuario, ocultar. Exceção: quando a consulta usar explicitamente from:/to:/@.",

                tabMute: "Silenciar",
                labelMuteWord: "Adicionar palavra silenciada",
                placeholderMuteWord: "ex: spoiler",
                labelCaseSensitive: "Diferenciar maiúsculas",
                labelWordBoundary: "Palavra inteira",
                labelEnabled: "Ativado",
                labelEnableAll: "Ativar tudo",
                buttonAdd: "Adicionar",
                emptyMuted: "Nenhuma palavra silenciada.",
                mutedListTitle: "Palavras silenciadas",
                mutedListHeading: "Lista de silenciados",
                optMuteHidden: "Oculto",
                optMuteCollapsed: "Colapsado",
                placeholderFilterMute: "Filtrar palavras silenciadas...",
                muteLabel: "Silenciado: ",
                buttonShow: "Mostrar",
                muteHit: "Silenciar resultados no corpo",
                buttonRemute: "Silenciar novamente",
                buttonImport: "Importar",
                buttonExport: "Exportar",

                /* Accounts tab */
                tabAccounts: "Contas",
                emptyAccounts: "Nenhuma conta ainda. Abra um perfil e clique no botão Adicionar para salvar.",
                buttonAddAccount: "Adicionar conta",
                toastAccountAdded: "Conta adicionada.",
                toastAccountExists: "Já adicionada.",
                buttonConfirm: "Confirmar",

                /* Lists tab */
                tabLists: "Listas",
                emptyLists: "Nenhuma lista ainda. Abra uma Lista e clique no botão + no canto superior direito para adicionar.",
                buttonAddList: "Adicionar lista",
                toastListAdded: "Lista adicionada.",
                toastListExists: "Já adicionada.",

                /* History tab */
                placeholderSearchHistory: "Histórico de busca (query)",
                labelSortBy: "Ordenar por:",
                placeholderSearchSaved: "Buscas salvas (query)",
                sortNewest: "Mais recente",
                sortOldest: "Mais antigo",
                sortNameAsc: "Nome (A-Z)",
                sortNameDesc: "Nome (Z-A)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "Filtrar contas (@, nome)",
                placeholderFilterLists: "Filtrar listas (nome, url)",
                buttonAddFolder: "+Pasta",
                folderFilterAll: "TUDO",
                folderFilterUnassigned: "Não atribuído",
                folderRename: "Renomear",
                folderRenameTitle: "Renomear pasta",
                folderDelete: "Excluir",
                folderDeleteTitle: "Excluir pasta",
                promptNewFolder: "Nome da nova pasta",
                confirmDeleteFolder: "Excluir esta pasta e todos os itens dentro dela? Isso não pode ser desfeito.",
                optListsAll: "Listas",
                defaultSavedFolders: "Buscas Salvas",

                /* Favorites */
                tabFavorites: "Favoritos",
                emptyFavorites: "Nenhum favorito ainda. Clique no ícone ★ nos tweets para salvar.",
                optFavoritesAll: "Todos os favoritos",
                toastFavorited: "Adicionado aos favoritos.",
                toastUnfavorited: "Removido dos favoritos.",

                /* Settings */
                settingsTitle: "Configurações",
                settingsTitleGeneral: "Geral",
                settingsTitleFeatures: "Visibilidade de abas",
                settingsTitleData: "Dados",
                buttonClose: "Fechar",
                labelUILang: "Idioma da interface",
                optUILangAuto: "Automático",
                labelInitialTab: "Aba inicial",
                optInitialTabLast: "Última aberta (Padrão)",
                labelImportExport: "Importar / Exportar",
                placeholderSettingsJSON: "Cole o JSON de backup aqui...",
                tooltipSettings: "Abrir configurações",
                toastImported: "Importado.",
                toastExported: "Exportado para arquivo.",
                alertInvalidJSON: "Arquivo JSON inválido.",
                alertInvalidData: "Formato de dados inválido.",
                alertInvalidApp: 'Este arquivo não é um backup válido para "Advanced Search for X".',
                buttonReset: "Redefinir tudo",
                confirmResetAll: "Redefinir todos os dados? Isso não pode ser desfeito.",
                toastReset: "Todos os dados foram redefinidos.",
                buttonImportSuccess: "Importado com sucesso 👍",

                /* Favorites Sort */
                sortSavedNewest: "Data (Mais recente)",
                sortSavedOldest: "Data (Mais antigo)",
                sortPostedNewest: "Postado (Mais recente)",
                sortPostedOldest: "Postado (Mais antigo)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Sem categoria',
                FT_DROPDOWN_TITLE: 'Tags favoritas',
                FT_DROPDOWN_SETTINGS_TITLE: 'Configurações de tags',
                FT_DROPDOWN_NEW_TAG: 'Nova tag',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'Nome da tag',
                FT_DROPDOWN_NEW_TAG_ADD: 'Adicionar',
                FT_FILTER_ALL: 'Tudo',
                FT_SETTINGS_TITLE: 'Configurações de tags favoritas',
                FT_SETTINGS_EMPTY_TAG_LIST: 'Sem tags. Adicione em "Nova tag".',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Sem categoria',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: 'O nome "Sem categoria" não pode ser alterado.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '"Sem categoria" não pode ser excluída.',
                FT_SETTINGS_CLOSE: 'Fechar',
                FT_SETTINGS_DELETE_BUTTON: 'Excluir',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'Exibição',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'Formato da tag',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'Apenas etiqueta (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'Caminho completo (full)',
                FT_CONFIRM_DELETE_TAG_MSG: 'Excluir tag "{tagName}"?\nFavoritos com esta tag ficarão "Sem categoria".',
                FT_SETTINGS_BUTTON_TITLE: 'Configurações de tags',
            },
            'ru': {
                modalTitle: "РасшОреММый пПОск",
                tooltipClose: "Закрыть",
                labelAllWords: "Все этО слПва",
                placeholderAllWords: "Мапр., AI МПвПстО",
                labelExactPhrase: "ТПчМая фраза",
                placeholderExactPhrase: 'Мапр., "ChatGPT 4o"',
                labelAnyWords: "ЛюбПе Оз этОх слПв (OR)",
                placeholderAnyWords: "Мапр., iPhone Android",
                labelNotWords: "ИсключОть слПва (-)",
                placeholderNotWords: "Мапр., -распрПЎажа -реклаЌа",
                labelHashtag: "ХэштегО (#)",
                placeholderHashtag: "Мапр., #TechEvent",
                labelLang: "Язык (lang:)",
                optLangDefault: "ЛюбПй язык",
                optLangJa: "ЯпПМскОй (ja)",
                optLangEn: "АМглОйскОй (en)",
                optLangId: "ИМЎПМезОйскОй (id)",
                optLangHi: "ХОМЎО (hi)",
                optLangDe: "НеЌецкОй (de)",
                optLangTr: "ТурецкОй (tr)",
                optLangEs: "ИспаМскОй (es)",
                optLangPt: "ППртугальскОй (pt)",
                optLangAr: "АрабскОй (ar)",
                optLangFr: "ЀраМцузскОй (fr)",
                optLangKo: "КПрейскОй (ko)",
                optLangRu: "РусскОй (ru)",
                optLangZhHans: "КОтайскОй упр. (zh-cn)",
                optLangZhHant: "КОтайскОй траЎ. (zh-tw)",
                hrSeparator: " ",
                labelFilters: "ЀОльтры",
                labelVerified: "ППЎтвержЎеММые аккауМты",
                labelLinks: "СсылкО",
                labelImages: "ИзПбражеМОя",
                labelVideos: "ВОЎеП",
                labelReposts: "РепПсты",
                labelTimelineHashtags: "ХэштегО (#)",
                checkInclude: "Вкл",
                checkExclude: "Искл",
                labelReplies: "Ответы",
                optRepliesDefault: "ПП уЌПлчаМОю (Все)",
                optRepliesInclude: "Включая Птветы",
                optRepliesOnly: "ТПлькП Птветы",
                optRepliesExclude: "ИсключОть Птветы",
                labelEngagement: "ВПвлечеММПсть",
                placeholderMinReplies: "МОМ. ПтветПв",
                placeholderMinLikes: "МОМ. лайкПв",
                placeholderMinRetweets: "МОМ. репПстПв",
                labelDateRange: "ДОапазПМ Ўат",
                labelDateShortcut: "Быстрый выбПр",
                optDate1Day: "За 24 часа",
                optDate1Week: "За МеЎелю",
                optDate1Month: "За Ќесяц",
                optDate3Months: "За 3 Ќесяца",
                optDate6Months: "За 6 Ќесяцев",
                optDate1Year: "За гПЎ",
                optDate2Years: "За 2 гПЎа",
                optDate3Years: "За 3 гПЎа",
                optDate5Years: "За 5 лет",
                optDateClear: "ОчОстОть Ўаты",
                tooltipSince: "С этПй Ўаты",
                tooltipUntil: "ПП эту Ўату",
                labelFromUser: "От этОх аккауМтПв (from:)",
                placeholderFromUser: "Мапр., @X",
                labelToUser: "ЭтОЌ аккауМтаЌ (to:)",
                placeholderToUser: "Мапр., @google",
                labelMentioning: "УпПЌОМаМОе этОх аккауМтПв (@)",
                placeholderMentioning: "Мапр., @OpenAI",
                buttonClear: "ОчОстОть",
                buttonApply: "ППОск",
                tooltipTrigger: "Открыть расшОреММый пПОск",
                buttonOpen: "Открыть",

                tabSearch: "ППОск",
                tabHistory: "ИстПрОя",
                tabSaved: "СПхраМеММПе",
                buttonSave: "СПхраМОть",
                buttonSaved: "СПхраМеМП",
                secretMode: "СекретМый",
                secretOn: "СекретМый режОЌ ВКЛ (без ОстПрОО)",
                secretOff: "СекретМый режОЌ ВЫКЛ",
                toastSaved: "СПхраМеМП.",
                toastDeleted: "УЎалеМП.",
                toastReordered: "ППряЎПк ПбМПвлеМ.",
                emptyHistory: "ИстПрОО пПка Мет.",
                emptySaved: "Нет сПхраМеММых пПОскПв. ДПбавьте Ох кМПпкПй СПхраМОть вМОзу вклаЎкО ППОск.",
                run: "ВыпПлМОть",
                delete: "УЎалОть",
                updated: "ОбМПвлеМП.",
                tooltipSecret: "ПереключОть секретМый режОЌ (ОстПрОя Ме буЎет запОсаМа)",
                historyClearAll: "ОчОстОть всё",
                confirmClearHistory: "ОчОстОть всю ОстПрОю?",

                labelAccountScope: "АккауМты",
                optAccountAll: "Все аккауМты",
                optAccountFollowing: "ЧОтаеЌые ваЌО",
                labelLocationScope: "МестПпПлПжеМОе",
                optLocationAll: "ВезЎе",
                optLocationNearby: "РяЎПЌ с ваЌО",
                chipFollowing: "ЧОтаеЌые",
                chipNearby: "РяЎПЌ",

                labelSearchTarget: "Њель пПОска",
                labelHitName: "ИсключОть сПвпаЎеМОя тПлькП в ОЌеМО",
                labelHitHandle: "ИсключОть сПвпаЎеМОя тПлькП в юзерМейЌе (@)",
                hintSearchTarget: "Скрыть пПсты, сПвпаЎающОе тПлькП пП ОЌеМО/юзерМейЌу (МП Ме в тексте).",
                hintName: "ЕслО ключевПе слПвП тПлькП в ПтПбражаеЌПЌ ОЌеМО — скрыть.",
                hintHandle: "ЕслО ключевПе слПвП тПлькП в @юзерМейЌе — скрыть. Искл: еслО запрПс явМП ОспПльзует from:/to:/@.",

                tabMute: "Скрыть",
                labelMuteWord: "ДПбавОть скрытПе слПвП",
                placeholderMuteWord: "Мапр., спПйлер",
                labelCaseSensitive: "УчОтывать регОстр",
                labelWordBoundary: "СлПвП целОкПЌ",
                labelEnabled: "ВключеМП",
                labelEnableAll: "ВключОть все",
                buttonAdd: "ДПбавОть",
                emptyMuted: "Нет скрытых слПв.",
                mutedListTitle: "Скрытые слПва",
                mutedListHeading: "СпОсПк скрытПгП",
                optMuteHidden: "СкрытП",
                optMuteCollapsed: "СверМутП",
                placeholderFilterMute: "ЀОльтр скрытых слПв...",
                muteLabel: "СкрытП: ",
                buttonShow: "ППказать",
                muteHit: "Скрывать сПвпаЎеМОя в тексте",
                buttonRemute: "Скрыть сМПва",
                buttonImport: "ИЌпПрт",
                buttonExport: "ЭкспПрт",

                /* Accounts tab */
                tabAccounts: "АккауМты",
                emptyAccounts: "АккауМтПв Мет. ОткрПйте прПфОль О МажЌОте ДПбавОть, чтПбы сПхраМОть.",
                buttonAddAccount: "ДПбавОть аккауМт",
                toastAccountAdded: "АккауМт ЎПбавлеМ.",
                toastAccountExists: "Уже ЎПбавлеМ.",
                buttonConfirm: "ППЎтверЎОть",

                /* Lists tab */
                tabLists: "СпОскО",
                emptyLists: "СпОскПв Мет. ОткрПйте спОсПк О МажЌОте + в углу Ўля ЎПбавлеМОя.",
                buttonAddList: "ДПбавОть спОсПк",
                toastListAdded: "СпОсПк ЎПбавлеМ.",
                toastListExists: "Уже ЎПбавлеМ.",

                /* History tab */
                placeholderSearchHistory: "ИстПрОя пПОска (запрПс)",
                labelSortBy: "СПртОрПвка:",
                placeholderSearchSaved: "СПхраМеММый пПОск (запрПс)",
                sortNewest: "СМачала МПвые",
                sortOldest: "СМачала старые",
                sortNameAsc: "ИЌя (А-Я)",
                sortNameDesc: "ИЌя (Я-А)",

                /* Folder/List/Account tabs */
                placeholderFilterAccounts: "ЀОльтр аккауМтПв (@, ОЌя)",
                placeholderFilterLists: "ЀОльтр спОскПв (ОЌя, url)",
                buttonAddFolder: "+Папка",
                folderFilterAll: "ВСЕ",
                folderFilterUnassigned: "Без папкО",
                folderRename: "ПереОЌеМПвать",
                folderRenameTitle: "ПереОЌеМПвать папку",
                folderDelete: "УЎалОть",
                folderDeleteTitle: "УЎалОть папку",
                promptNewFolder: "ИЌя МПвПй папкО",
                confirmDeleteFolder: "УЎалОть эту папку О всё сПЎержОЌПе? ЭтП Мельзя ПтЌеМОть.",
                optListsAll: "СпОскО",
                defaultSavedFolders: "СПхраМеММые пПОскО",

                /* Favorites */
                tabFavorites: "ИзбраММПе",
                emptyFavorites: "В ОзбраММПЌ пустП. НажЌОте ★ Ма твОте, чтПбы сПхраМОть.",
                optFavoritesAll: "Всё ОзбраММПе",
                toastFavorited: "ДПбавлеМП в ОзбраММПе.",
                toastUnfavorited: "УЎалеМП Оз ОзбраММПгП.",

                /* Settings */
                settingsTitle: "НастрПйкО",
                settingsTitleGeneral: "ОбщОе",
                settingsTitleFeatures: "ВклаЎкО",
                settingsTitleData: "ДаММые",
                buttonClose: "Закрыть",
                labelUILang: "Язык ОМтерфейса",
                optUILangAuto: "АвтП",
                labelInitialTab: "ВклаЎка прО запуске",
                optInitialTabLast: "ППслеЎМяя Пткрытая (ПП уЌПлч.)",
                labelImportExport: "ИЌпПрт / ЭкспПрт",
                placeholderSettingsJSON: "Вставьте JSON резервМПй кПпОО...",
                tooltipSettings: "Открыть МастрПйкО",
                toastImported: "ИЌпПртОрПваМП.",
                toastExported: "ЭкспПртОрПваМП в файл.",
                alertInvalidJSON: "НеверМый файл JSON.",
                alertInvalidData: "НеверМый фПрЌат ЎаММых.",
                alertInvalidApp: 'Ѐайл Ме является кПпОей "Advanced Search for X".',
                buttonReset: "СбрПсОть всё",
                confirmResetAll: "СбрПсОть все ЎаММые? ЭтП Мельзя ПтЌеМОть.",
                toastReset: "Все ЎаММые сбрПшеМы.",
                buttonImportSuccess: "УспешМый ОЌпПрт 👍",

                /* Favorites Sort */
                sortSavedNewest: "Дата сПхр. (НПвые)",
                sortSavedOldest: "Дата сПхр. (Старые)",
                sortPostedNewest: "Дата публ. (НПвые)",
                sortPostedOldest: "Дата публ. (Старые)",

                /* --- Favorite Tags --- */
                FT_UNCATEGORIZED: 'Без категПрОО',
                FT_DROPDOWN_TITLE: 'ТегО ОзбраММПгП',
                FT_DROPDOWN_SETTINGS_TITLE: 'НастрПйка тегПв',
                FT_DROPDOWN_NEW_TAG: 'НПвый тег',
                FT_DROPDOWN_NEW_TAG_PLACEHOLDER: 'ИЌя тега',
                FT_DROPDOWN_NEW_TAG_ADD: 'ДПбавОть',
                FT_FILTER_ALL: 'Все',
                FT_SETTINGS_TITLE: 'НастрПйка тегПв ОзбраММПгП',
                FT_SETTINGS_EMPTY_TAG_LIST: 'ТегПв Мет. ДПбавьте через "НПвый тег".',
                FT_SETTINGS_UNCATEGORIZED_NAME: 'Без категПрОО',
                FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP: 'ИЌя "Без категПрОО" Мельзя ОзЌеМОть.',
                FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP: '"Без категПрОО" Мельзя уЎалОть.',
                FT_SETTINGS_CLOSE: 'Закрыть',
                FT_SETTINGS_DELETE_BUTTON: 'УЎалОть',
                FT_SETTINGS_UP: '▲',
                FT_SETTINGS_DOWN: '▌',
                FT_SETTINGS_DISPLAY_SECTION_TITLE: 'ОтПбражеМОе',
                FT_SETTINGS_DISPLAY_MODE_LABEL: 'ЀПрЌат тега',
                FT_SETTINGS_DISPLAY_MODE_LEAF: 'ТПлькП ОЌя (leaf)',
                FT_SETTINGS_DISPLAY_MODE_FULL: 'ППлМый путь (full)',
                FT_CONFIRM_DELETE_TAG_MSG: 'УЎалОть тег "{tagName}"?\nЭлеЌеМты с этОЌ тегПЌ стаМут "Без категПрОО".',
                FT_SETTINGS_BUTTON_TITLE: 'НастрПйка тегПв',
            }
        },
        lang: 'en',
        init: function() {
            const supportedLangs = Object.keys(this.translations);
            let detectedLang = document.documentElement.lang || navigator.language || 'en';
            if (supportedLangs.includes(detectedLang)) { this.lang = detectedLang; return; }
            const baseLang = detectedLang.split('-')[0];
            if (supportedLangs.includes(baseLang)) { this.lang = baseLang; return; }
            this.lang = 'en';
        },
        t: function(key) { return this.translations[this.lang]?.[key] || this.translations['en'][key] || `[${key}]`; },
        apply: function(container) {
            container.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = this.t(el.dataset.i18n); });
            container.querySelectorAll('[data-i18n-placeholder]').forEach(el => { el.placeholder = this.t(el.dataset.i18nPlaceholder); });
            container.querySelectorAll('[data-i18n-title]').forEach(el => { el.title = this.t(el.dataset.i18nTitle); });
        }
    };

    const SEARCH_SVG = `
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2" fill="none"></circle>
      <line x1="16.65" y1="16.65" x2="22" y2="22"
            stroke="currentColor" stroke-width="2" stroke-linecap="round"></line>
    </svg>`;

    const SETTINGS_SVG = `
    <svg
      viewBox="0 0 24 24"
      aria-hidden="true"
      focusable="false"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fill="currentColor"
        fill-rule="evenodd"
        clip-rule="evenodd"
        d="M11.078 2.25c-.917 0-1.699.663-1.85 1.567L9.05 4.889c-.02.12-.115.26-.297.348a7.493 7.493 0 00-.986.57c-.166.115-.334.126-.45.083L6.3 5.508a1.875 1.875 0 00-2.282.819l-.922 1.597a1.875 1.875 0 00.432 2.385l.84.692c.095.078.17.229.154.43a7.598 7.598 0 000 1.139c.015.2-.059.352-.153.43l-.841.692a1.875 1.875 0 00-.432 2.385l.922 1.597a1.875 1.875 0 002.282.818l1.019-.382c.115-.043.283-.031.45.082.312.214.641.405.985.57.182.088.277.228.297.35l.178 1.071c.151.904.933 1.567 1.85 1.567h1.844c.916 0 1.699-.663 1.85-1.567l.178-1.072c.02-.12.114-.26.297-.349.344-.165.673-.356.985-.57.167-.114.335-.125.45-.082l1.02.382a1.875 1.875 0 002.28-.819l.923-1.597a1.875 1.875 0 00-.432-2.385l-.84-.692c-.095-.078-.17-.229-.154-.43a7.614 7.614 0 000-1.139c-.016-.2.059-.352.153-.43l.84-.692c.708-.582.891-1.59.433-2.385l-.922-1.597a1.875 1.875 0 00-2.282-.818l-1.02.382c-.114.043-.282.031-.449-.083a7.49 7.49 0 00-.985-.57c-.183-.087-.277-.227-.297-.348l-.179-1.072a1.875 1.875 0 00-1.85-1.567h-1.843zM12 15.75a3.75 3.75 0 100-7.5 3.75 3.75 0 000 7.5z"
      />
    </svg>
    `;

    const FOLDER_TOGGLE_OPEN_SVG = `
      <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M6 9l6 6 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    `;
    const FOLDER_TOGGLE_CLOSED_SVG = `
      <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    `;

    // トグルボタンの小ナヌティリティ
    function renderFolderToggleButton(collapsed) {
      const btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'adv-folder-toggle-btn';
      btn.setAttribute('aria-label', collapsed ? 'Expand' : 'Collapse');
      btn.setAttribute('title', collapsed ? 'Expand' : 'Collapse');
      btn.setAttribute('aria-expanded', (!collapsed).toString());
      btn.style.cssText = `
        appearance:none;border:none;background:transparent;cursor:pointer;
        width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;
        margin-right:8px;color:inherit;flex:0 0 auto;
      `;
      btn.innerHTML = collapsed ? FOLDER_TOGGLE_CLOSED_SVG : FOLDER_TOGGLE_OPEN_SVG;
      return btn;
    }
    function updateFolderToggleButton(btn, collapsed) {
      if (!btn) return;
      btn.innerHTML = collapsed ? FOLDER_TOGGLE_CLOSED_SVG : FOLDER_TOGGLE_OPEN_SVG;
      btn.setAttribute('aria-label', collapsed ? 'Expand' : 'Collapse');
      btn.setAttribute('title', collapsed ? 'Expand' : 'Collapse');
      btn.setAttribute('aria-expanded', (!collapsed).toString());
    }

    const themeManager = {
        colors: {
            light: {
                '--modal-bg': '#ffffff', '--modal-text-primary': '#0f1419', '--modal-text-secondary': '#536471', '--modal-border': '#d9e1e8',
                '--modal-input-bg': '#eff3f4', '--modal-input-border': '#cfd9de', '--modal-button-hover-bg': 'rgba(15, 20, 25, 0.1)',
                '--modal-scrollbar-thumb': '#aab8c2', '--modal-scrollbar-track': '#eff3f4', '--modal-close-color': '#0f1419',
                '--modal-close-hover-bg': 'rgba(15, 20, 25, 0.1)', '--hr-color': '#eff3f4',
                '--modal-tabs-shadow': '0 1px 12px rgba(0, 0, 0, 0.22)',
            },
            dim: {
                '--modal-bg': '#15202b', '--modal-text-primary': '#f7f9f9', '--modal-text-secondary': '#8899a6', '--modal-border': '#38444d',
                '--modal-input-bg': '#192734', '--modal-input-border': '#38444d', '--modal-button-hover-bg': 'rgba(247, 249, 249, 0.1)',
                '--modal-scrollbar-thumb': '#536471', '--modal-scrollbar-track': '#192734', '--modal-close-color': '#f7f9f9',
                '--modal-close-hover-bg': 'rgba(247, 249, 249, 0.1)', '--hr-color': '#38444d',
                '--modal-tabs-shadow': '0 5px 12px rgba(0, 0, 0, 0.27)',
            },
            dark: {
                '--modal-bg': '#000000', '--modal-text-primary': '#e7e9ea', '--modal-text-secondary': '#71767b', '--modal-border': '#2f3336',
                '--modal-input-bg': '#16181c', '--modal-input-border': '#54595d', '--modal-button-hover-bg': 'rgba(231, 233, 234, 0.1)',
                '--modal-scrollbar-thumb': '#536471', '--modal-scrollbar-track': '#16181c', '--modal-close-color': '#e7e9ea',
                '--modal-close-hover-bg': 'rgba(231, 233, 234, 0.1)', '--hr-color': '#2f3336',
                '--modal-tabs-shadow': '0 5px 12px rgba(0, 0, 0, 0.27)',
            }
        },
        applyTheme: function(modalElement, triggerEl) {
            if (!modalElement) return;
            const bodyBg = getComputedStyle(document.body).backgroundColor;
            let theme = 'dark';
            if (bodyBg === 'rgb(21, 32, 43)') theme = 'dim';
            else if (bodyBg === 'rgb(255, 255, 255)') theme = 'light';

            // â–Œ ブックマヌクUIのテヌマ切替甚にクラスを付䞎
            try {
                document.documentElement.classList.remove('x-theme-light', 'x-theme-dim', 'x-theme-dark');
                if (theme === 'light') {
                    document.documentElement.classList.add('x-theme-light');
                } else if (theme === 'dim') {
                    document.documentElement.classList.add('x-theme-dim');
                } else {
                    document.documentElement.classList.add('x-theme-dark');
                }
            } catch (e) {}

            const themeColors = this.colors[theme] || this.colors.dark;
            const targets = [modalElement, document.documentElement];
            if (triggerEl) targets.push(triggerEl);
            for (const t of targets) {
             for (const [key, value] of Object.entries(themeColors)) {
               t.style.setProperty(key, value);
             }
            }
        },
        observeChanges: function(modalElement, triggerEl) {
            const observer = new MutationObserver(() => this.applyTheme(modalElement, triggerEl));
            observer.observe(document.body, { attributes: true, attributeFilter: ['style'] });
            this.applyTheme(modalElement, triggerEl);
        }
    };

    /**
     * Mobile Drag & Drop Shim
     * タッチむベントを怜知し、HTML5 Drag & Dropむベント(dragstart, dragover, drop等)を発火させる
     */
    function enableMobileDragSupport() {
        let dragSource = null;
        let lastTarget = null;
        // DataTransferのデヌタを保持する擬䌌ストア
        let dataTransferStore = {};

        // 擬䌌的な DragEvent を䜜成するヘルパヌ
        const createEvent = (type, touch, target) => {
            const event = new CustomEvent(type, { bubbles: true, cancelable: true });
            // dataTransfer オブゞェクトを擬䌌的に再珟
            event.dataTransfer = {
                effectAllowed: 'move',
                dropEffect: 'move',
                types: Object.keys(dataTransferStore),
                setData: (format, data) => { dataTransferStore[format] = data; },
                getData: (format) => dataTransferStore[format],
                clearData: () => { dataTransferStore = {}; }
            };
            // 座暙情報を付䞎 (getDragAfterElement 等の蚈算に必芁)
            event.clientX = touch.clientX;
            event.clientY = touch.clientY;
            event.pageX = touch.pageX;
            event.pageY = touch.pageY;
            // タヌゲット芁玠を䞊曞き蚭定 (CustomEventの制玄回避)
            Object.defineProperty(event, 'target', { value: target, enumerable: true });
            return event;
        };

        const onTouchStart = (e) => {
            // ハンドル、たたはドラッグ可胜な芁玠自䜓ぞのタッチか刀定
            const handle = e.target.closest('.adv-item-handle, .adv-folder-header, .adv-tab-btn, .ft-modal-tag-drag-handle');
            if (!handle) return;

            const draggable = handle.closest('[draggable="true"]');
            if (!draggable) return;

            dragSource = draggable;
            dataTransferStore = {}; // デヌタ初期化

            const touch = e.changedTouches[0];
            const evt = createEvent('dragstart', touch, dragSource);
            dragSource.dispatchEvent(evt);
        };

        const onTouchMove = (e) => {
            if (!dragSource) return;
            // スクロヌル防止CSSのtouch-actionで防げない堎合甚
            if (e.cancelable) e.preventDefault();

            const touch = e.changedTouches[0];
            // 指の䞋にある芁玠を取埗
            const element = document.elementFromPoint(touch.clientX, touch.clientY);
            if (!element) return;

            // dragover は頻繁に発火させる必芁がある
            // タヌゲットが倉わった堎合は dragenter/dragleave も怜蚎すべきだが、
            // このアプリのロゞック(䞊び替え)では dragover がメむンのため、そこに集䞭する

            // 既存ロゞックが .closest('.adv-item') 等を䜿っおいるため、適切なタヌゲットに察しお発火
            // ここでは elementFromPoint で取れた芁玠に察しお dragover を投げる
            const evt = createEvent('dragover', touch, element);
            element.dispatchEvent(evt);
            lastTarget = element;
        };

        const onTouchEnd = (e) => {
            if (!dragSource) return;
            const touch = e.changedTouches[0];

            // 最埌に指があった芁玠に察しお drop を発火
            if (lastTarget) {
                const evtDrop = createEvent('drop', touch, lastTarget);
                lastTarget.dispatchEvent(evtDrop);
            }

            const evtEnd = createEvent('dragend', touch, dragSource);
            dragSource.dispatchEvent(evtEnd);

            // クリヌンアップ
            dragSource = null;
            lastTarget = null;
            dataTransferStore = {};
        };

        document.addEventListener('touchstart', onTouchStart, { passive: false });
        document.addEventListener('touchmove', onTouchMove, { passive: false });
        document.addEventListener('touchend', onTouchEnd);
    }

    function decodeURIComponentSafe(s) {
      try { return decodeURIComponent(s); } catch { return s; }
    }

    // 正芏衚珟の特殊文字を゚スケヌプする
    function escapeRegExp(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    // “ ” 『』などのスマヌト匕甚を ASCII の " に寄せる
    function normalizeQuotes(s) {
      return String(s).replace(/[\u201C\u201D\u300C\u300D\uFF02]/g, '"');
    }

    // 解析前に軜く正芏化URL から来る %22..., 連続空癜など
    function normalizeForParse(s) {
      if (!s) return '';
      let out = String(s);
      // URL っぜい゚ンコヌドだけ軜く剥がす%22 等
      if (/%[0-9A-Fa-f]{2}/.test(out)) out = decodeURIComponentSafe(out);
      out = normalizeQuotes(out);
      // 制埡文字を朰し、空癜を敎圢
      out = out.replace(/\s+/g, ' ').trim();
      return out;
    }

    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    // ── OR/匕甚のための簡易トヌクナむザ
    function tokenizeQuotedWords(s) {
      const out = [];
      let cur = '';
      let inQ = false;
      for (let i = 0; i < s.length; i++) {
        const c = s[i];
        if (c === '"') { inQ = !inQ; cur += c; continue; }
        if (!inQ && /\s/.test(c)) { if (cur) { out.push(cur); cur=''; } }
        else { cur += c; }
      }
      if (cur) out.push(cur);
      return out.filter(Boolean);
    }

    // トップレベルの OR で文字列を分割匕甚/括匧を考慮
    function splitTopLevelOR(str) {
      const parts = [];
      let cur = '';
      let inQ = false, depth = 0;
      for (let i = 0; i < str.length; ) {
        const c = str[i];
        if (c === '"') { inQ = !inQ; cur += c; i++; continue; }
        if (!inQ && (c === '(' || c === ')')) { depth += (c === '(' ? 1 : -1); cur += c; i++; continue; }
        if (!inQ && depth === 0) {
          // 単語境界の "or" / "OR"
          if ((str.slice(i, i+2).toLowerCase() === 'or') &&
              (i === 0 || /\s|\(/.test(str[i-1] || '')) &&
              (i+2 >= str.length || /\s|\)/.test(str[i+2] || ''))) {
            parts.push(cur.trim());
            cur = '';
            i += 2;
            continue;
          }
        }
        cur += c; i++;
      }
      if (cur.trim()) parts.push(cur.trim());
      return parts.length > 1 ? parts : null;
    }

    // OR 専甚刀定挔算子/吊定/括匧が無い玠の OR 矀なら true
    function isPureORQuery(q) {
      const hasOps = /(?:^|\s)(?:from:|to:|lang:|filter:|is:|min_replies:|min_faves:|min_retweets:|since:|until:)\b/i.test(q);
      const hasNeg = /(^|\s)-\S/.test(q);
      const hasPar = /[()]/.test(q);
      return !hasOps && !hasNeg && !hasPar;
    }

    function waitForElement(selector, timeout = 10000, checkProperty = null) {
        return new Promise((resolve) => {
            const checkInterval = 100;
            let elapsedTime = 0;
            const intervalId = setInterval(() => {
                const element = document.querySelector(selector);
                if (element) {
                    if (checkProperty) {
                        if (element[checkProperty]) {
                            clearInterval(intervalId);
                            resolve(element);
                            return;
                        }
                    } else {
                        clearInterval(intervalId);
                        resolve(element);
                        return;
                    }
                }
                elapsedTime += checkInterval;
                if (elapsedTime >= timeout) {
                    clearInterval(intervalId);
                    resolve(null);
                }
            }, checkInterval);
        });
    }

    function hideUIImmediately(modal, trigger) {
        if (modal)  modal.style.display = 'none';
        if (trigger) trigger.style.display = 'none';
    }

    // â–Œ ルヌト適甚を軜く怜蚌URL䞀臎 + プロフィヌル系DOMが珟れたか
    function waitForRouteApply(path, timeoutMs = 2000) {
      const goal = new URL(path, location.origin).pathname;
      // ルヌト毎の刀定を甚意必芁に応じお拡匵
      const perRouteProbes = [
       // 怜玢ペヌゞ怜玢結果タむムラむン or 怜玢ボックス or 䜕かしらのツむヌト
       { test: p => p.startsWith('/search'),
         sels: [
           '[aria-label*="Search results"], [aria-label*="怜玢結果"]',
           'div[data-testid="primaryColumn"] input[data-testid="SearchBox_Search_Input"]',
           'div[data-testid="primaryColumn"] article[data-testid="tweet"]'
         ] },
       // プロフィヌル
       { test: p => /^\/[A-Za-z0-9_]{1,50}\/?$/.test(p),
         sels: [
           '[data-testid="UserName"]',
           'div[data-testid="UserProfileHeader_Items"]',
           'div[data-testid="UserDescription"]'
         ] },
       // デフォルト保険䞻芁カラムに䜕かレンダされたらOK
       { test: _ => true,
         sels: [
           'div[data-testid="primaryColumn"]',
           'main[role="main"]'
         ] }
      ];
      const probes = (perRouteProbes.find(x => x.test(goal)) || perRouteProbes.at(-1)).sels;
      return new Promise(resolve => {
        const t0 = performance.now();
        (function tick() {
          const elapsed = performance.now() - t0;
          const urlOk = location.pathname === goal;
          const domOk = probes.some(sel => document.querySelector(sel));
          if (urlOk && domOk) return resolve(true);
          if (elapsed >= timeoutMs) return resolve(false);
          // 立ち䞊がりは速く、以埌はやや疎にポヌリング
          setTimeout(tick, elapsed < 300 ? 60 : elapsed < 700 ? 120 : 180);
        })();
      });
    }

    // â–Œ SPA 遷移の栞。pushState → 合成 popstate → DOM適甚埅ち → 倱敗ならフォヌルバック
    async function spaNavigate(path, { ctrlMeta = false, timeoutMs = 1200 } = {}) {
      try {
        const to = new URL(path, location.origin);
        if (to.origin !== location.origin) throw new Error('cross-origin');

        history.pushState(history.state, '', to.pathname + to.search + to.hash);
        // X のルヌタヌは popstate を賌読しおいる想定
        window.dispatchEvent(new PopStateEvent('popstate', { state: history.state }));

        const ok = await waitForRouteApply(to.pathname, timeoutMs);
        if (ok) return; // 成功
      } catch (e) {
        // fall through to fallback
      }
      // フォヌルバック修食キヌありなら新芏タブ、なければ通垞遷移
      if (ctrlMeta) window.open(path, '_blank', 'noopener');
      else location.assign(path);
    }

    const uid = () => Math.random().toString(36).slice(2) + Date.now().toString(36);

    let isUpdating = false;
    let manualOverrideOpen = false;
    const lastHistory = { q: null, pf: null, lf: null, ts: 0 };

    // â–Œ パヌス結果をキャッシュスクロヌル時の再パヌス防止
    let __cachedSearchTokens = null;
    let __cachedSearchQuery = null; // このク゚リ文字列で __cachedSearchTokens が生成された

    // â–Œ 入力䞭ガヌドIME合成を含めおカバヌ
    let __typingGuardUntil = 0;
    const TYPING_GRACE_MS = 600; // 入力終了からこのmsはスキャン停止
    const markTyping = () => { __typingGuardUntil = Date.now() + TYPING_GRACE_MS; };
    const isTyping = () => Date.now() < __typingGuardUntil;

    const isMediaViewPath = (pathname) => /\/status\/\d+\/(?:photo|video|media|analytics)(?:\/\d+)?\/?$/.test(pathname);
    const isComposePath = (pathname) => /^\/compose\/post(?:\/|$)/.test(pathname);
    const isProfileMediaPath = (pathname) => /^\/[A-Za-z0-9_]{1,50}\/(?:photo|header_photo)\/?$/.test(pathname);
    const isBroadcastPath = (pathname) => /^\/i\/broadcasts\//.test(pathname);
    const isBlockedPath = (pathname) => isMediaViewPath(pathname) || isComposePath(pathname) || isProfileMediaPath(pathname) || isBroadcastPath(pathname);

    // â–Œ 自動的に閉じるパスかどうかを刀定する関数
    const isAutoClosePath = (pathname) => {
        const targets = ['/messages', '/i/grok', '/settings', '/i/chat', '/i/spaces'];
        return targets.some(t => pathname.startsWith(t));
    };

    GM_addStyle(`
        :root { --modal-primary-color:#1d9bf0; --modal-primary-color-hover:#1a8cd8; --modal-primary-text-color:#fff; }
        #advanced-search-trigger { position:fixed; top:18px; right:20px; z-index:9999; background-color:var(--modal-primary-color); color:var(--modal-primary-text-color); border:none; border-radius:50%; width:50px; height:50px; font-size:24px; cursor:pointer; box-shadow:0 4px 12px rgba(0,0,0,0.15); display:flex; align-items:center; justify-content:center; transition:transform .2s, background-color .2s; }
        #advanced-search-trigger:hover { transform:scale(1.1); background-color:var(--modal-primary-color-hover); }
        #advanced-search-modal { position:fixed; z-index:10000; width:450px; display:none; flex-direction:column; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; background-color:var(--modal-bg, #000); color:var(--modal-text-primary, #e7e9ea); border:1px solid var(--modal-border, #333); border-radius:16px; box-shadow:0 8px 24px rgba(29,155,240,.2); transition:background-color .2s,color .2s,border-color .2s; }
        .adv-modal-header{padding:12px 16px;border-bottom:1px solid var(--modal-border,#333);cursor:move;display:flex;justify-content:space-between;align-items:center}
        .adv-modal-title-left{display:flex;align-items:center;gap:8px;}
        .adv-modal-header h2{margin:0;font-size:18px;font-weight:700}
        .adv-settings-btn{
          margin-left:6px;
          width:26px;height:26px;
          border-radius:9999px;
          border:1px solid var(--modal-input-border,#38444d);
          background:var(--modal-input-bg,#202327);
          display:inline-flex;
          align-items:center;
          justify-content:center;
          cursor:pointer;
          padding:0;
        }
        .adv-settings-btn:hover{
          background-color:var(--modal-button-hover-bg,rgba(231,233,234,.1));
        }
        .adv-settings-btn svg{
          width:14px;
          height:14px;
        }
        .adv-modal-close{background:0 0;border:none;color:var(--modal-close-color,#e7e9ea);font-size:24px;cursor:pointer;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:background-color .2s}
        .adv-modal-close:hover{background-color:var(--modal-close-hover-bg,rgba(231,233,234,.1))}
        .adv-modal-body{flex:1;overflow-y:auto;padding:0}
        .adv-form-group{margin-bottom:16px}
        .adv-form-group label{display:block;margin-bottom:6px;font-size:14px;font-weight:700;color:var(--modal-text-secondary,#8b98a5)}
        .adv-form-group input[type=text],.adv-form-group input[type=number],.adv-form-group input[type=date],.adv-form-group select{width:100%;background-color:var(--modal-input-bg,#202327);border:1px solid var(--modal-input-border,#38444d);border-radius:4px;padding:8px 12px;color:var(--modal-text-primary,#e7e9ea);font-size:15px;box-sizing:border-box}
        .adv-form-group input:focus,.adv-form-group select:focus{outline:0;border-color:var(--modal-primary-color)}
        .adv-form-group input::placeholder{color:var(--modal-text-secondary,#536471)}
        .adv-form-group-date-container {display:flex;gap:8px;align-items: center;}
        .adv-form-group-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 6px;
            gap: 12px;
        }
        .adv-form-group-header label {
            margin-bottom: 0;
            white-space: nowrap;
            flex-shrink: 0;
        }
        .adv-select-mini {
            background-color: var(--modal-input-bg, #202327);
            color: var(--modal-text-primary, #e7e9ea);
            border: 1px solid var(--modal-input-border, #38444d);
            border-radius: 18px !important;
            font-size: 13px !important;
            height: 34px;
            line-height: normal;
            padding: 0 8px;
            width: auto;
            min-width: 90px;
            max-width: 200px;
            text-overflow: ellipsis;
            cursor: pointer;
            outline: none;
        }
        .adv-select-mini:hover {
            border-color: var(--modal-text-secondary, #8b98a5);
        }
        .adv-select-mini:focus {
            border-color: var(--modal-primary-color);
        }
        .adv-form-group-date-container input[type=date] {flex:1;min-width: 0;width: auto !important;}
        .adv-date-separator {color:var(--modal-text-secondary, #8b98a5);font-weight:700;user-select:none;flex-shrink:0;padding: 0 2px;}
        .adv-filter-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
        .adv-checkbox-group{background-color:var(--modal-input-bg,#202327);border:1px solid var(--modal-input-border,#38444d);border-radius:8px;padding:10px;display:flex;flex-direction:column;gap:8px}
        .adv-checkbox-group span{font-weight:700;font-size:14px;color:var(--modal-text-primary,#e7e9ea)}
        .adv-checkbox-item{display:flex;align-items:center}
        .adv-checkbox-item input{margin-right:8px; accent-color:var(--modal-primary-color);}
        .adv-checkbox-item label{color:var(--modal-text-secondary,#8b98a5);margin-bottom:0}
        .adv-checkbox-item input[type="checkbox"]:disabled {opacity:0.5; cursor:not-allowed;}
        .adv-checkbox-item input[type="checkbox"]:disabled + label {opacity:0.5;cursor:not-allowed;text-decoration:line-through;}
        .adv-modal-footer{padding:12px 16px;border-top:1px solid var(--modal-border,#333);display:flex;justify-content:flex-end;gap:12px}
        .adv-modal-button{padding:5px 16px;border-radius:9999px;border:1px solid var(--modal-text-secondary,#536471);background-color:transparent;color:var(--modal-text-primary,#e7e9ea);font-weight:700;cursor:pointer;transition:background-color .2s}
        .adv-modal-button:hover{background-color:var(--modal-button-hover-bg,rgba(231,233,234,.1))}
        .adv-modal-button.primary,
        .adv-chip.primary {
          background-color:var(--modal-primary-color);
          border-color:var(--modal-primary-color);
          color:var(--modal-primary-text-color);
        }
        .adv-modal-button.primary:hover{background-color:var(--modal-primary-color-hover)}
        .adv-modal-button[disabled]{opacity:.5; cursor:not-allowed;}
        #adv-settings-import.adv-modal-button[disabled]{opacity:1;}
        .adv-modal-body::-webkit-scrollbar{width:8px}
        .adv-modal-body::-webkit-scrollbar-track{background:var(--modal-scrollbar-track,#202327)}
        .adv-modal-body::-webkit-scrollbar-thumb{background:var(--modal-scrollbar-thumb,#536471);border-radius:4px}
        body.adv-dragging{user-select:none}
        .adv-account-label-group{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}
        .adv-exclude-toggle{display:flex;align-items:center}
        .adv-exclude-toggle input{margin-right:4px}
        .adv-exclude-toggle label{font-size:13px;font-weight:normal;color:var(--modal-text-secondary,#8b98a5);cursor:pointer}
        hr.adv-separator{border:none;height:1px;background-color:var(--hr-color,#333);margin:20px 0;transition:background-color .2s}
        /* ★党タブ共通のズヌム察象に拡匵怜玢タブの既存idにも適甚維持 */
        .adv-zoom-root, #adv-zoom-root{ transform-origin: top left; will-change: transform; padding:12px 11.6px 10px 11px; }
        #adv-zoom-root {
          padding-top: 16px; /* 怜玢タブの䞊䜙癜だけを 16px に䞊曞き */
          padding-left:16px; padding-right:20px;
        }
        .adv-modal-body{ overflow:auto; }

        .adv-form-row.two-cols { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
        @media (max-width: 480px) { .adv-form-row.two-cols { grid-template-columns:1fr; } }

        .adv-tabs {
            display: flex;
            border-bottom: 1px solid var(--modal-border, #333);
            padding: 0 8px 0 6px;
            gap: 4px;
            align-items: stretch;
            flex-wrap: wrap;
            container-type: inline-size;

            /* â–Œ 固定衚瀺蚭定 */
            position: sticky;
            top: 0;
            z-index: 10;
            background-color: var(--modal-bg, #000);
            box-shadow: var(--modal-tabs-shadow);
        }

        .adv-tab-btn {
            appearance: none;
            border: none;
            background: transparent;
            color: var(--modal-text-secondary, #8b98a5);
            padding: 10px 8px;
            cursor: pointer;
            font-weight: 700;
            border-radius: 8px 8px 0 0;
            font-size: 0.78rem;

            /* ボタン内のテキストは折り返さない */
            white-space: nowrap;

            /* 䜙ったスペヌスを党員で分け合う均等配眮・最倧化 */
            flex: 1 1 auto;
            text-align: center;

            /* なめらかな倉化 */
            transition: font-size 0.1s, padding 0.1s, background-color 0.2s;
        }

        .adv-tab-btn.active {
            color: var(--modal-text-primary, #e7e9ea);
            background-color: var(--modal-input-bg, #202327);
            border: 1px solid var(--modal-input-border, #38444d);
            border-bottom: none;
            /* アクティブタブは少し匷調 */
            z-index: 1;
        }

        /* ▌▌▌ コンテナク゚リ: 幅に応じお最適化 ▌▌▌ */

        /* 幅 480px 以䞋: フォントを少し小さくし、1行収たりを狙う */
        @container (max-width: 480px) {
            .adv-tab-btn {
                font-size: 12px;
                padding: 8px 4px;
            }
        }

        /* 幅 380px 以䞋: さらにフォントを詰め、もし2行になっおも違和感ないサむズに */
        @container (max-width: 380px) {
            .adv-tab-btn {
                font-size: 11px;
                padding: 6px 2px;
                border-radius: 6px; /* 角䞞も少し小さく */
            }
            /* 2行になった際に䞊䞋の列がくっ぀きすぎないようにする */
            .adv-tabs {
                row-gap: 2px;
            }
            /* 2行目のボヌダヌ凊理芋た目を敎える */
            .adv-tab-btn.active {
                border-bottom: 1px solid var(--modal-input-bg, #202327);
                margin-bottom: -1px;
            }
        }

        .adv-tab-content { display:none; }
        .adv-tab-content.active { display:block; }

        .adv-secret-wrap { display:flex; align-items:center; gap:8px; }
        .adv-secret-btn { cursor:pointer; border:1px solid var(--modal-input-border,#38444d); background:var(--modal-input-bg,#202327); color:var(--modal-text-primary,#e7e9ea); padding:4px 8px; border-radius:9999px; font-weight:700; user-select:none; display:flex; align-items:center; gap:6px; font-size:12px; }
        .adv-secret-btn .dot { width:7px; height:7px; border-radius:50%; background:#777; box-shadow:0 0 0px #0000; transition:all .2s; }
        .adv-secret-btn.off { opacity:0.9; }
        .adv-secret-btn.on { background-color:var(--modal-primary-color); border-color:var(--modal-primary-color); color:var(--modal-primary-text-color); }
        .adv-secret-btn.on .dot { background:#fff; box-shadow:0 0 8px rgba(255,255,255,.9); }

        .adv-list { display:flex; flex-direction:column; gap:8px; }
        .adv-item { position: relative; border:1px solid var(--modal-input-border,#38444d); background:var(--modal-input-bg,#202327); border-radius:8px; padding:8px; display:flex; gap:8px; align-items:flex-start; }
        .adv-item.dragging { opacity:.6; }
        .adv-item-handle { cursor:grab; user-select:none; padding:4px 6px; border-radius:6px; border:1px dashed var(--modal-border,#333); touch-action: none; }
        .adv-item-avatar { width:36px; height:36px; border-radius:9999px; object-fit:cover; flex:0 0 auto; background:var(--modal-border,#333); }
        a.adv-link { color: inherit; text-decoration: none; }
        a.adv-link:hover { text-decoration: underline; cursor: pointer; }
        .adv-item-avatar-link { display:inline-block; border-radius:9999px; }
        .adv-item-main { flex:1; min-width:0; }

        .adv-item-title { font-size:14px; font-weight:700; color:var(--modal-text-primary,#e7e9ea); word-break:break-word; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
        .adv-item-sub { font-size:12px; color:var(--modal-text-secondary,#8b98a5); margin-top:2px; display:flex; gap:6px; flex-wrap:wrap; align-items:center; }
        .adv-item-actions { display:flex; gap:6px; align-items:center; align-self:center; }
        .adv-chip { border:1px solid var(--modal-input-border,#38444d); background:transparent; color:var(--modal-text-primary,#e7e9ea); padding:4px 8px; border-radius:9999px; font-size:12px; cursor:pointer; }

        .adv-fav-btn-pos { position: absolute; right: 8px; }
        .adv-fav-btn-top { top: 8px; }
        .adv-fav-btn-bottom { bottom: 8px; }
        .adv-chip.danger { border-color:#8b0000; color:#ffb3b3; }
        .adv-modal-button.danger {
          border-color:#8b0000;
          color:#ffb3b3;
        }
        .adv-modal-button.danger:hover{
          background-color:rgba(139,0,0,0.2);
        }
        .adv-chip.scope { padding:2px 6px; font-size:11px; line-height:1.2; opacity:0.95; }

        .adv-toast { position:fixed; z-index:10001; left:50%; transform:translateX(-50%); bottom:24px; background:#111a; color:#fff; backdrop-filter: blur(6px); border:1px solid #fff3; padding:8px 12px; border-radius:8px; font-weight:700; opacity:0; pointer-events:none; transition:opacity .2s, transform .2s; }
        .adv-toast.show { opacity:1; transform:translateX(-50%) translateY(-6px); }

        .adv-modal-footer { justify-content:flex-end; }
        .adv-modal-footer .adv-modal-button#adv-save-button { margin-right:auto; }

        .adv-tab-toolbar {
          display:flex;
          justify-content: space-between;
          align-items: center;
          gap: 8px;
          flex-wrap: wrap;
          margin-bottom:12px;
          padding: 0 2px;
        }
        /* ツヌルバヌの巊偎怜玢・゜ヌト */
        .adv-tab-toolbar-left {
          display: flex;
          align-items: center;
          gap: 8px;
          flex: 1 1 auto;
          min-width: 150px;
        }
        /* ツヌルバヌの右偎すべお削陀ボタン */
        .adv-tab-toolbar-right {
          display: flex;
          flex: 0 0 auto;
        }
        /* ツヌルバヌ入力欄の共通スタむル */
        .adv-select, .adv-input {
          background-color:var(--modal-input-bg,#202327);
          border:1px solid var(--modal-input-border,#38444d);
          border-radius:8px;
          padding:6px 10px;
          color:var(--modal-text-primary,#e7e9ea);
        }
        /* 怜玢ボックスずセレクトボックスのスタむル.adv-folder-toolbar内ず共通化 */
        /* 共通スタむルは .adv-input, .adv-select が担圓 */
        .adv-tab-toolbar .adv-input {
          flex: 1;
          min-width: 80px;
        }
        .adv-tab-toolbar .adv-select {
          flex: 0 1 auto;
        }

        [data-testid="cellInnerDiv"][data-adv-hidden],
        article[data-adv-hidden] {
          display:none !important;
          content-visibility: hidden;
          contain: strict;
        }

        #advanced-search-modal { max-height:none; }
        .adv-resizer { position:absolute; z-index:10002; background:transparent; }
        .adv-resizer.e, .adv-resizer.w { top:-3px; bottom:-3px; width:8px; }
        .adv-resizer.e { right:-3px; cursor: ew-resize; }
        .adv-resizer.w { left:-3px;  cursor: ew-resize; }
        .adv-resizer.n, .adv-resizer.s { left:-3px; right:-3px; height:8px; }
        .adv-resizer.n { top:-3px;    cursor: ns-resize; }
        .adv-resizer.s { bottom:-3px; cursor: ns-resize; }
        .adv-resizer.se, .adv-resizer.ne, .adv-resizer.sw, .adv-resizer.nw { width:12px; height:12px; }
        .adv-resizer.se { right:-4px;  bottom:-4px; cursor:nwse-resize; }
        .adv-resizer.ne { right:-4px;  top:-4px;    cursor:nesw-resize; }
        .adv-resizer.sw { left:-4px;   bottom:-4px; cursor:nesw-resize; }
        .adv-resizer.nw { left:-4px;   top:-4px;    cursor:nwse-resize; }

        /* ▶ Mute タブ */
        .adv-mute-add { display:flex; gap:8px; align-items:center; margin-bottom:10px; }
        .adv-mute-add input[type=text]{ flex:1; border-radius:8px; padding: 6px 10px; font-size: 14px; }
        .adv-mute-list { display:flex; flex-direction:column; gap:8px; }

        /* â–Œ グロヌバル無効マスタヌOFFのずきリスト党䜓を淡く */
        .adv-mute-list.disabled {
          opacity: .6;
          filter: grayscale(35%);
        }

        /* â–Œ 個別無効enabled=falseの行だけ淡く打ち消し等の芖芚 */
        .adv-mute-item {
          border:1px solid var(--modal-input-border,#38444d);
          background:var(--modal-input-bg,#202327);
          border-radius:8px;
          padding:8px 10px;
          display:flex;
          gap:10px;
          justify-content: space-between;
          align-items:center;
          transition: opacity .15s ease, filter .15s ease, border-color .15s ease;
        }
        .adv-mute-item.disabled {
          opacity: .55;
          filter: grayscale(25%);
          border-color: color-mix(in oklab, var(--modal-input-border,#38444d), transparent 20%);
        }
        .adv-mute-item.disabled .adv-mute-word {
          color: var(--modal-text-secondary,#8b98a5);
          text-decoration: line-through;
        }

        /* 巊偎のコンテナ単語オプション */
        .adv-mute-content-left {
          display: flex;
          flex-direction: column;
          gap: 4px;
          flex: 1;
          min-width: 0;
        }

        .adv-mute-word {
          font-weight:700;
          color:var(--modal-text-primary,#e7e9ea);
          word-break:break-word;
          font-size: 14px;
        }

        /* 巊䞋のオプション矀 */
        .adv-mute-options-row {
          display: flex;
          gap: 12px;
          align-items: center;
        }

        /* 右偎のコンテナ削陀ボタンのみ */
        .adv-mute-actions-right {
          display:flex;
          align-items:center;
          justify-content:center;
          flex: 0 0 auto;
          white-space: nowrap;
          padding-left: 4px;
        }
        @media (max-width: 480px) {
          .adv-mute-actions { margin-top: 4px; }
        }
        .adv-toggle {
          display: inline-flex;
          gap: 6px;
          align-items: center;
          color: var(--modal-text-secondary,#8b98a5);
          line-height: 1;
          margin-bottom:0!important;
        }
        .adv-toggle input[type="checkbox"] {
          width: 14px;
          height: 14px;
          margin: 0;
          flex: 0 0 auto;
          vertical-align: middle;
        }
        .adv-toggle span {
          font-size: 11px;
          line-height: 1;
        }
        /* ▌▌▌ Mute Header Fix ▌▌▌ */
        .adv-mute-header {
            display:flex;
            justify-content:space-between;
            align-items:center;
            margin: 4px 0 12px;
            gap: 10px;
            flex-wrap: nowrap; /* 折り返しを犁止しお1行に匷制 */
        }
        .adv-mute-header input[type="text"] {
            flex: 1;
            min-width: 0;
            border-radius: 8px;
            padding: 6px 10px;
            font-size: 14px;
            background-color: var(--modal-input-bg,#202327);
            border: 1px solid var(--modal-input-border,#38444d);
            color: var(--modal-text-primary,#e7e9ea);
        }
        .adv-mute-header input[type="text"]:focus {
            outline: 0;
            border-color: var(--modal-primary-color);
        }
        .adv-mute-title {
            font-weight:700;
            color: var(--modal-text-primary,#e7e9ea);
            white-space: nowrap; /* テキスト折り返し犁止 */
            overflow: hidden;
            text-overflow: ellipsis; /* 溢れたら...にする */
            flex-shrink: 1; /* 幅䞍足時はタむトル偎を瞮める */
            min-width: 0;
        }
        .adv-mute-header-controls {
            display: flex;
            align-items: center;
            gap: 8px; /* 䜙癜を少し詰める */
            flex-shrink: 0; /* 操䜜パネルは瞮めない */
        }
        #adv-mute-mode {
            padding: 3px 24px 3px 8px; /* 矢印スペヌス考慮 */
            font-size: 12px;
            height: 28px;
            cursor: pointer;
            width: auto;
        }

        /* マスタヌ切替の䞀瞬だけ付けるガヌドクラス */
        .adv-no-anim, .adv-no-anim * {
          transition: none !important;
        }
        #adv-history-empty:not(:empty),
        #adv-saved-empty:not(:empty),
        #adv-favorites-empty:not(:empty),
        #adv-accounts-empty:not(:empty),
        #adv-lists-empty:not(:empty) {
          padding-inline: 7px;
        }
        #adv-mute-empty:not(:empty) {
          padding-top: 6px;
        }

        /* â–Œ マスタヌOFF䞭は、個別無効の“さらに薄く”を抑制芪の薄さのみ適甚 */
        .adv-mute-list.disabled .adv-mute-item.disabled {
          opacity: 1;    /* 子の远加の薄さを無効化芪のopacityのみが効く */
          filter: none;  /* 子の远加グレヌスケヌルも無効化芪偎のfilterのみ適甚 */
          /* ボヌダヌだけ通垞色に戻す */
          /* border-color: var(--modal-input-border,#38444d); */
        }

        /* === Trigger: モヌダルず同質の芋た目に合わせる === */
        #advanced-search-trigger.adv-trigger-search {
          width: 49px; height: 49px;
          border-radius: 9999px;
          background-color: var(--modal-bg, #000);
          color: var(--modal-text-primary, #e7e9ea);
          border: 2px solid var(--modal-border, #2f3336);          /* ← モヌダルず同じ枠色 */
          box-shadow: 0 8px 24px rgba(29,155,240,.2);              /* ← モヌダルず同じshadow */
          display:flex; align-items:center; justify-content:center;
          transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
        }

        #advanced-search-trigger.adv-trigger-search:hover {
          /* 背景は倉えず、浮かせる衚珟だけ匷化 */
          transform: translateZ(0) scale(1.04);
          box-shadow: 0 12px 36px rgba(29,155,240,.28);
          border-color: var(--modal-border, #2f3336);
        }

        #advanced-search-trigger.adv-trigger-search:active {
          transform: translateZ(0) scale(0.98);
          box-shadow: 0 6px 18px rgba(29,155,240,.22);
        }

        #advanced-search-trigger.adv-trigger-search:focus-visible {
          outline: none;
          box-shadow:
            0 8px 24px rgba(29,155,240,.2),
            0 0 0 3px color-mix(in oklab, var(--modal-primary-color, #1d9bf0) 45%, transparent);
        }

        #advanced-search-trigger.adv-trigger-search svg {
          width: 22px; height: 22px;
          display:block;
          /* 怜玢アむコンは stroke="currentColor" を䜿っおいるので配色は自動远埓 */
        }

        /* リストコンテナ自䜓に十分な高さを確保し、䞋郚にドロップ甚の䜙癜を匷制的に広げる */
        #adv-accounts-list,
        #adv-lists-list,
        #adv-saved-list {
            min-height: 200px;      /* アむテムが空でもドロップできるようにする */
            padding-bottom: 20px;
            box-sizing: content-box; /* padding分を確実に高さに加える */
        }

        /* 未分類セクションが空の時も、ドラッグ䞭は少し広げお受け入れやすくする */
        body.adv-dragging .adv-unassigned {
            min-height: 60px;
            background-color: rgba(128, 128, 128, 0.05); /* 芖芚的に゚リアを暗瀺 */
            border-radius: 8px;
            transition: min-height 0.2s ease, background-color 0.2s;
        }

        /* === Folders === */
        .adv-folder { border:1px solid var(--modal-input-border,#38444d); border-radius:10px; margin-bottom:10px; }
        .adv-folder-header {
          display:flex; justify-content:space-between; align-items:center;
          padding:8px 10px; background:var(--modal-input-bg,#202327); border-bottom:1px solid var(--modal-input-border,#38444d);
        }
        .adv-folder[data-drop="1"] { outline:2px dashed var(--modal-primary-color); outline-offset:-2px; }
        .adv-folder-title { display:flex; gap:8px; align-items:baseline; }
        .adv-folder-actions { display:flex; gap:6px; }
        .adv-folder-toolbar { display:flex; gap:8px; align-items:center; margin:0 0 12px; padding:0 2px; }
        .adv-folder-toolbar input[type="text"] { flex:1; min-width:80px; }
        .adv-folder-collapsed .adv-list { display:none; }

        /* ▶ Folder headers: show grab cursor except on action buttons */
        .adv-folder-header { cursor: grab; touch-action: none; }
        .adv-folder-header:active { cursor: grabbing; }

        /* ボタン䞊では通垞のポむンタ=ドラッグ開始させない芋た目 */
        .adv-folder-header .adv-folder-actions,
        .adv-folder-header .adv-folder-actions * {
          cursor: pointer;
        }

        /* â–Œ トグルボタン巊端 */
        .adv-folder-toggle {
          appearance: none;
          border: none;
          background: transparent;
          display: inline-flex;
          align-items: center;
          justify-content: center;
          width: 28px;
          height: 28px;
          border-radius: 6px;
          cursor: pointer;
          margin-right: 6px;
        }

        .adv-folder-toggle:focus-visible {
          outline: none;
          box-shadow: 0 0 0 2px color-mix(in oklab, var(--modal-primary-color, #1d9bf0) 60%, transparent);
        }

        /* â–Œ アむコンchevron */
        .adv-folder-toggle svg {
          width: 16px; height: 16px;
          transition: transform .15s ease;
        }

        /* â–Œ 開閉で向きを倉える右▶ → 䞋▌ */
        .adv-folder:not(.adv-folder-collapsed) .adv-folder-toggle svg {
          transform: rotate(90deg);
        }

        /* â–Œ 開いおいるヘッダヌはわずかに背景匷調 */
        .adv-folder:not(.adv-folder-collapsed) .adv-folder-header {
          background: color-mix(in oklab, var(--modal-input-bg,#202327) 92%, var(--modal-primary-color,#1d9bf0));
        }

        /* â–Œ ドラッグハンドルは“掎める”芋た目を匷調 */
        .adv-folder-drag-handle {
          cursor: grab;
          user-select: none;
          padding: 4px 6px;
          border-radius: 6px;
          border: 1px dashed var(--modal-border,#38444d);
        }
        .adv-folder-drag-handle:active { cursor: grabbing; }

        /* â–Œ Unassigned セクション芋出しなし・枠なし */
        .adv-unassigned {
          margin-bottom: 10px;
          min-height: 30px; /* ★ 空の時でもドロップできるように最小高さを確保 */
        }
        .adv-unassigned .adv-list {
          display: flex;
          flex-direction: column;
          gap: 8px;
        }
        /* フォルダヌ䞊び替え甚のドラッグ時の芖芚Unassigned も察象 */
        .adv-unassigned.dragging-folder {
          opacity: .6;
        }

        /* タブ背景およびリストコンテナ背景ぞのドロップハむラむト */
        #adv-tab-accounts.adv-bg-drop-active,
        #adv-tab-lists.adv-bg-drop-active,
        #adv-tab-saved.adv-bg-drop-active,
        #adv-accounts-list.adv-bg-drop-active,
        #adv-lists-list.adv-bg-drop-active,
        #adv-saved-list.adv-bg-drop-active {
          outline: 2px dashed var(--modal-primary-color, #1d9bf0);
          /* リストコンテナ偎はパディングが無いためオフセットを小さく */
          outline-offset: -4px;
        }
        /* タブパネル䞊郚䜙癜偎は既存のオフセットを維持 */
        #adv-tab-accounts.adv-bg-drop-active,
        #adv-tab-lists.adv-bg-drop-active,
        #adv-tab-saved.adv-bg-drop-active {
          outline-offset: -8px;
        }

        /* 背景Unassigned 宛おをドロップ䞭は、フォルダヌ内の“薄い残像”を消す */
        #adv-tab-accounts.adv-bg-drop-active .adv-list .adv-item.dragging,
        #adv-accounts-list.adv-bg-drop-active .adv-list .adv-item.dragging,
        #adv-tab-lists.adv-bg-drop-active .adv-list .adv-item.dragging,
        #adv-lists-list.adv-bg-drop-active .adv-list .adv-item.dragging,
        #adv-tab-saved.adv-bg-drop-active .adv-list .adv-item.dragging,
        #adv-saved-list.adv-bg-drop-active .adv-list .adv-item.dragging {
          display: none !important;
        }

        /* === Settings modal === */
        #adv-settings-modal.adv-settings-modal{
          position:fixed;
          inset:0;
          z-index:10001;
          display:none;
          align-items:center;
          justify-content:center;
          background:rgba(0,0,0,.5);
        }
        .adv-settings-dialog{
          width:420px;
          max-width:90vw;
          max-height:80vh;
          background-color:var(--modal-bg,#000);
          color:var(--modal-text-primary,#e7e9ea);
          border-radius:16px;
          border:1px solid var(--modal-border,#333);
          box-shadow:0 8px 24px rgba(0,0,0,.3);
          display:flex;
          flex-direction:column;
          overflow:hidden;
          font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
        }
        .adv-settings-header{
          padding:12px 16px;
          border-bottom:1px solid var(--modal-border,#333);
          display:flex;
          align-items:center;
          justify-content:space-between;
        }
        .adv-settings-title{
          margin:0;
          font-size:16px;
          font-weight:700;
        }
        .adv-settings-close{
          border:none;
          background:transparent;
          color:var(--modal-close-color,#e7e9ea);
          font-size:20px;
          width:32px;
          height:32px;
          border-radius:50%;
          display:flex;
          align-items:center;
          justify-content:center;
          cursor:pointer;
        }
        .adv-settings-close:hover{
          background-color:var(--modal-close-hover-bg,rgba(231,233,234,.1));
        }
        .adv-settings-body{
          padding:12px 16px 23px 16px;
          overflow-y:auto;
          display:flex;
          flex-direction:column;
          gap:16px;
        }
        .adv-settings-group label{
          display:block;
          margin-bottom:4px;
          font-size:14px;
          font-weight:700;
          color:var(--modal-text-secondary,#8b98a5);
        }
        .adv-settings-group select,
        .adv-settings-group textarea{
          width:100%;
          background-color:var(--modal-input-bg,#202327);
          border:1px solid var(--modal-input-border,#38444d);
          border-radius:8px;
          padding:8px 10px;
          color:var(--modal-text-primary,#e7e9ea);
          font-size:14px;
          box-sizing:border-box;
        }
        .adv-settings-group textarea{
          resize:vertical;
          min-height:80px;
        }
        .adv-settings-section-header {
          margin: 12px 0 2px 0;
          padding-bottom: 4px;
          border-bottom: 1px solid var(--modal-border,#333);
          font-size: 13px;
          font-weight: 700;
          color: var(--modal-text-primary,#e7e9ea);
        }
        .adv-settings-toggle-row {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 6px 0;
        }
        .adv-settings-toggle-row .adv-toggle {
          font-size: 14px;
          color: var(--modal-text-primary,#e7e9ea);
          user-select: none;
          cursor: pointer;
        }
        .adv-settings-toggle-row .adv-toggle span {
          font-size: 14px;
        }
        /* Simple toggle switch CSS */
        .adv-switch {
          position: relative;
          display: inline-block;
          width: 40px;
          height: 22px;
        }
        .adv-switch input {
          opacity: 0;
          width: 0;
          height: 0;
        }
        .adv-slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: var(--modal-input-border,#38444d);
          transition: .2s;
          border-radius: 22px;
        }
        .adv-slider:before {
          position: absolute;
          content: "";
          height: 16px;
          width: 16px;
          left: 3px;
          bottom: 3px;
          background-color: var(--modal-bg, #000);
          transition: .2s;
          border-radius: 50%;
        }
        .adv-switch input:checked + .adv-slider {
          background-color: var(--modal-primary-color);
        }
        .adv-switch input:checked + .adv-slider:before {
          transform: translateX(18px);
        }
        .adv-settings-actions-inline{
          display:flex;
          gap:8px;
          margin-top:6px;
          flex-wrap:wrap;
        }
        .adv-settings-footer{
          padding:10px 16px;
          border-top:1px solid var(--modal-border,#333);
          display:flex;
          justify-content:flex-end;
          gap:8px;
        }

        /* === Tab Drag & Drop === */
        .adv-tab-btn {
          user-select: none;
        }
        .adv-tab-btn:active {
          cursor: grabbing;
        }
        .adv-tab-btn.dragging {
          opacity: .5;
        }

        /* --- Favorite Tags CSS --- */

        /* â–Œ ブックマヌクUI専甚の配色倉数を定矩 */
        :root {
          /* デフォルト (Dim / Dark) は静的なダヌクテヌマ */
          --ft-bg: rgb(21, 24, 28);
          --ft-border-light: rgba(239, 243, 244, 0.24);
          --ft-border-dim: rgba(239, 243, 244, 0.15);
          --ft-border-strong: rgba(239, 243, 244, 0.3);
          --ft-border-accent: rgba(239, 243, 244, 0.8);
          --ft-text-primary: rgb(239, 243, 244);
          --ft-text-secondary: rgba(239, 243, 244, 0.7);
          --ft-input-bg: rgba(0,0,0,0.2);
          --ft-input-border: rgba(239,243,244,0.2);
          --ft-hover-bg: rgba(255, 255, 255, 0.06);
          --ft-hover-bg-strong: rgba(255, 255, 255, 0.08);
          --ft-accent-color: #1d9bf0;
        }
        :root.x-theme-light {
          /* Lightテヌマの時だけ、X本䜓の動的倉数を参照する */
          --ft-bg: var(--modal-bg);
          --ft-border-light: var(--modal-border);
          --ft-border-dim: var(--modal-border);
          --ft-border-strong: var(--modal-text-secondary);
          --ft-border-accent: var(--modal-text-primary);
          --ft-text-primary: var(--modal-text-primary);
          --ft-text-secondary: var(--modal-text-secondary);
          --ft-input-bg: var(--modal-input-bg);
          --ft-input-border: var(--modal-input-border);
          --ft-hover-bg: var(--modal-button-hover-bg);
          --ft-hover-bg-strong: var(--modal-button-hover-bg);
          --ft-accent-color: var(--modal-primary-color);
        }

        /* Tag chip on tweet header */
        .ft-tag-chip {
          display: inline-flex;
          align-items: center;
          margin-left: 4px; /* JS (ft_attachTagChipToArticle) 偎の gap: 4px ず連動 */
          padding: 1px 8px;
          border-radius: 9999px;
          border: 1px solid currentColor;
          font-size: 11px;
          line-height: 1.4;
          cursor: pointer;
          user-select: none;
          white-space: nowrap;
          background: rgba(255, 255, 255, 0.03); /* これは静的なたた (ほが透明なので) */
          flex: 0 0 auto;
          order: 9999;
        }
        .ft-tag-chip-label {
          max-width: 150px;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        .ft-tag-chip-uncategorized {
          opacity: 0.7;
        }

        /* Dropdown for selecting tag / filter */
        .ft-tag-dropdown {
          position: fixed;
          z-index: 2147482000;
          min-width: 220px;
          max-width: 260px;
          max-height: 60vh;
          overflow-y: auto;
          padding: 8px;
          border-radius: 12px;
          border: 1px solid var(--ft-border-light);
          background: var(--ft-bg);
          box-shadow: 0 12px 30px rgba(0, 0, 0, 0.7);
          font-size: 13px;
          color: var(--ft-text-primary);
        }
        .ft-tag-dropdown-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-bottom: 6px;
          font-weight: 600;
        }
        .ft-tag-dropdown-close {
          border: none;
          background: transparent;
          color: inherit;
          cursor: pointer;
          padding: 2px 4px;
        }
        .ft-tag-dropdown-tags {
          display: flex;
          flex-direction: column;
          gap: 4px;
          margin-bottom: 8px;
        }
        .ft-tag-dropdown-tag-item {
          display: flex;
          align-items: center;
          padding: 4px 6px;
          border-radius: 6px;
          cursor: pointer;
        }
        .ft-tag-dropdown-tag-item:hover {
          background: var(--ft-hover-bg);
        }
        .ft-tag-dropdown-tag-color {
          width: 10px;
          height: 10px;
          border-radius: 9999px;
          margin-right: 6px;
        }
        .ft-tag-dropdown-tag-label {
          flex: 1;
        }
        .ft-tag-dropdown-tag-selected::after {
          content: '✓';
          margin-left: 6px;
          font-size: 11px;
        }

        /* New tag row in dropdown */
        .ft-tag-dropdown-new {
          border-top: 1px solid var(--ft-border-dim);
          padding-top: 6px;
          display: flex;
          flex-direction: column;
          gap: 4px;
        }
        .ft-tag-dropdown-new-row {
          display: flex;
          gap: 4px;
        }
        .ft-tag-dropdown-new-input {
          flex: 1;
          background: var(--ft-input-bg);
          border: 1px solid var(--ft-input-border);
          border-radius: 6px;
          padding: 3px 6px;
          color: inherit;
        }
        .ft-tag-dropdown-new-color {
          width: 36px;
          padding: 0;
          border-radius: 6px;
          border: 1px solid var(--ft-input-border);
          background: transparent;
        }
        .ft-tag-dropdown-new-button {
          border-radius: 6px;
          border: 1px solid var(--ft-border-strong);
          background: transparent;
          color: inherit;
          padding: 2px 6px;
          font-size: 12px;
          cursor: pointer;
        }
        .ft-tag-dropdown-new-button:hover {
          background: var(--ft-hover-bg);
        }

        /* Bookmark header controls (テヌマ倉数適甚) */
        .ft-filter-button {
          border-radius: 8px;
          border: 1px solid var(--modal-border, rgba(239,243,244,0.3));
          background: var(--modal-input-bg, rgba(0,0,0,0.2));
          color: var(--modal-text-primary, rgb(239,243,244));
          font-size: 14px;
          padding: 4px 10px;
          display: inline-flex;
          align-items: center;
          gap: 6px;
          cursor: pointer;
        }
        .ft-filter-button-label {
          max-width: 140px;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
        .ft-filter-button-caret {
          font-size: 10px;
          opacity: 0.8;
        }
        .ft-filter-button[disabled] {
          opacity: 0.4;
          cursor: default;
        }
        .ft-filter-button:not([disabled]):hover {
          background: var(--modal-button-hover-bg, rgba(255,255,255,0.06));
          border-color: var(--modal-text-secondary, rgba(239,243,244,0.6));
        }
        .ft-settings-button {
          border-radius: 9999px;
          width: 26px;
          height: 26px;
          display: inline-flex;
          align-items: center;
          justify-content: center;
          border: 1px solid var(--modal-border, rgba(239,243,244,0.3));
          background: var(--modal-input-bg, rgba(0,0,0,0.2));
          color: var(--modal-text-primary, rgb(239,243,244));
          cursor: pointer;
        }
        .ft-settings-button:hover {
          background: var(--modal-button-hover-bg, rgba(255,255,255,0.06));
        }

        /* Settings modal */
        .ft-modal-backdrop {
          position: fixed;
          inset: 0;
          background: rgba(0,0,0,0.6);
          z-index: 2147483000;
          display: flex;
          align-items: center;
          justify-content: center;
        }
        .ft-modal {
          width: min(380px, 100vw - 32px);
          max-height: 80vh;
          border-radius: 16px;
          background: var(--ft-bg);
          border: 1px solid var(--ft-border-light);
          box-shadow: 0 20px 40px rgba(0,0,0,0.75);
          display: flex;
          flex-direction: column;
          color: var(--ft-text-primary);
        }
        .ft-modal-header {
          padding: 10px 14px;
          border-bottom: 1px solid var(--ft-border-dim);
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 8px;
        }
        .ft-modal-title {
          font-size: 14px;
          font-weight: 600;
        }
        .ft-modal-toggle {
          display: inline-flex;
          align-items: center;
          gap: 4px;
          font-size: 12px;
        }
        .ft-modal-toggle input[type="checkbox"] {
          accent-color: var(--ft-accent-color);
        }
        .ft-modal-body {
          padding: 10px 14px 12px;
          overflow-y: auto;
          font-size: 13px;
        }
        .ft-modal-footer {
          padding: 8px 14px 10px;
          border-top: 1px solid var(--ft-border-dim);
          display: flex;
          justify-content: flex-end;
          gap: 8px;
        }
        .ft-modal-button {
          border-radius: 9999px;
          border: 1px solid var(--ft-border-strong);
          background: transparent;
          color: inherit;
          font-size: 12px;
          padding: 4px 10px;
          cursor: pointer;
        }
        .ft-modal-button:hover {
          background: var(--ft-hover-bg);
        }

        /* Display settings section */
        .ft-modal-display-settings {
          margin-bottom: 10px;
          padding-bottom: 8px;
          border-bottom: 1px solid var(--ft-border-dim);
          font-size: 12px;
        }
        .ft-modal-display-settings-row {
          display: flex;
          flex-wrap: wrap;
          gap: 8px;
          align-items: center;
          margin-top: 4px;
        }
        .ft-modal-display-radio {
          display: inline-flex;
          align-items: center;
          gap: 4px;
        }

        /* Tag list in modal */
       .ft-modal-tag-list {
          display: flex;
          flex-direction: column;
          gap: 6px;
          padding-bottom: 30px; /* 䜙癜を倧きく取る */
          min-height: 100px;    /* 空っぜでもドロップできるように */
          position: relative;   /* ルヌトドロップの枠線衚瀺甚 */
          box-sizing: content-box; /* paddingを含めない高さ蚈算 */
        }

        /* 䞀番䞋の䜙癜にドラッグした時に、リスト党䜓の䞋に枠線を出すクラス */
        .ft-modal-tag-list.ft-drag-to-root::after {
            content: '';
            position: absolute;
            bottom: 20px; /* 䜙癜の䞭ほどに線を匕く */
            left: 0;
            right: 0;
            height: 2px;
            background-color: var(--modal-primary-color, #1d9bf0);
            box-shadow: 0 0 4px var(--modal-primary-color, #1d9bf0);
        }
        .ft-modal-tag-item {
          position: relative;
          display: grid;
          /* [mainCell] [dragHandle] [orderButtons] [deleteBtn] */
          grid-template-columns: minmax(0, 1fr) auto auto auto;
          align-items: center;
          gap: 6px;
          /* cursor: grab; を削陀 (ハンドルが担圓) */
        }
        .ft-modal-tag-main {
          display: flex;
          align-items: center;
          gap: 6px;
        }
        .ft-modal-tag-item-dragging {
          opacity: 0.6;
        }
        .ft-modal-tag-item-drop-before::before,
        .ft-modal-tag-item-drop-after::after {
            content: '';
            position: absolute;
            left: 0;
            right: 0;
            height: 1px;
            /* 埓来の色癜っぜいグレヌ */
            background-color: var(--ft-border-accent, rgba(239, 243, 244, 0.8));
            border: none; /* border-top/bottom を background-color に倉曎しお統䞀 */
            pointer-events: none;
        }
        .ft-modal-tag-item-drop-before::before { top: -3.5px; }
        .ft-modal-tag-item-drop-after::after { bottom: -3.5px; }

        /* ルヌト階局甚青い線 */
        .ft-modal-tag-item.ft-is-root-ref.ft-modal-tag-item-drop-before::before,
        .ft-modal-tag-item.ft-is-root-ref.ft-modal-tag-item-drop-after::after {
            background-color: var(--modal-primary-color, #1d9bf0);
            box-shadow: 0 0 4px var(--modal-primary-color, #1d9bf0); /* 発光させお匷調 */
            height: 2px;
            z-index: 10;
        }
        /* 青い線の䜍眮倪くなった分、あるいは匷調のため少し倖偎に広げる */
        .ft-modal-tag-item.ft-is-root-ref.ft-modal-tag-item-drop-before::before {
            top: -4.2px;
        }
        .ft-modal-tag-item.ft-is-root-ref.ft-modal-tag-item-drop-after::after {
            bottom: -4.2px;
        }
        .ft-modal-tag-item-drop-child {
          background: var(--ft-hover-bg-strong);
        }
        .ft-modal-tag-name {
          background: var(--ft-input-bg);
          border-radius: 6px;
          border: 1px solid var(--ft-input-border);
          padding: 3px 6px;
          color: inherit;
          font-size: 12px;
        }
        .ft-modal-tag-color {
          width: 40px;
          padding: 0;
          border-radius: 6px;
          border: 1px solid var(--ft-input-border);
          background: transparent;
        }
        .ft-modal-tag-order,
        .ft-modal-tag-delete {
          border-radius: 6px;
          border: 1px solid var(--ft-border-strong);
          background: transparent;
          color: inherit;
          padding: 2px 4px;
          cursor: pointer;
          font-size: 11px;
        }
        .ft-modal-tag-order:hover,
        .ft-modal-tag-delete:hover {
          background: var(--ft-hover-bg-strong);
        }

        /* --- Drag handle for tag settings --- */
        .ft-modal-tag-drag-handle {
          display: inline-flex;
          align-items: center;
          justify-content: center;
          width: 20px;
          height: 20px;
          border-radius: 4px;
          cursor: grab;
          color: var(--ft-text-secondary);
          user-select: none;
          touch-action: none;
        }
        .ft-modal-tag-drag-handle:hover {
          background: var(--ft-hover-bg-strong);
          color: var(--ft-text-primary);
        }
        /* Uncategorized: disable drag */
        .ft-modal-tag-item[data-kind="uncat"] .ft-modal-tag-drag-handle {
          cursor: not-allowed;
          opacity: 0.5;
        }

        /* New tag row */
        .ft-modal-new-tag {
          border-top: 1px solid var(--ft-border-dim);
          padding-top: 8px;
          display: flex;
          flex-direction: column;
          gap: 6px;
        }
        .ft-modal-new-tag-row {
          display: grid;
          grid-template-columns: auto minmax(0, 1fr) auto;
          gap: 6px;
        }

        /* 未分類は名前倉曎䞍可削陀䞍可の芖芚衚珟 */
        .ft-modal-tag-name[readonly] {
          cursor: not-allowed;
          opacity: 0.8;
        }
        .ft-modal-tag-delete:disabled {
          cursor: not-allowed;
          opacity: 0.4;
        }

        /* Hidden helper */
        .ft-hidden {
          display: none !important;
          content-visibility: hidden;
          contain: strict;
        }
        /* --- End Favorite Tags CSS --- */

        /* --- Favorites Feature --- */
        .adv-fav-btn {
          display: inline-flex; align-items: center; justify-content: center;
          background: transparent; border: none; cursor: pointer;
          color: rgb(83, 100, 113); /* Default grey */
          padding: 0; margin: 0;
          width: 34.75px; height: 34.75px; /* X standard icon size touch target */
          border-radius: 50%;
          transition: background-color 0.2s, color 0.2s;
        }
        /* ネむティブのクラスを借甚した時は固定サむズを無効化する */
        .adv-fav-btn.adv-native-style {
          width: auto;
          height: auto;
          min-width: 34.75px; /* 最䜎限の倧きさは確保 */
          min-height: 34.75px;
        }
        .adv-fav-btn:hover {
          background-color: rgba(29, 155, 240, 0.1);
          color: rgb(29, 155, 240);
        }
        .adv-fav-btn.active {
          color: rgb(249, 24, 128); /* Pink/Red like Like, or Gold? Let's use Gold for Star */
          color: rgb(255, 215, 0);
        }
        .adv-fav-btn.active:hover {
          background-color: rgba(255, 215, 0, 0.1);
        }
        .adv-fav-btn svg {
          width: 20px; height: 20px;
          fill: currentColor;
        }
        .adv-item-body-text {
          font-size: 13px; color: var(--modal-text-primary); margin-top: 4px;
          white-space: pre-wrap;       /* 改行を維持 */
          word-break: break-word;      /* 長い単語を折り返し */
        }
        /* Favorites Media */
        .adv-item-media-row {
          display: flex;
          gap: 4px;
          margin-top: 6px;
          overflow-x: auto;
          padding-bottom: 2px;
        }
        .adv-item-media-row::-webkit-scrollbar { height: 4px; }
        .adv-item-media-row::-webkit-scrollbar-thumb { background: var(--modal-border); border-radius: 2px; }
        .adv-media-thumb {
          height: 60px;
          min-width: 60px;
          border-radius: 6px;
          border: 1px solid var(--modal-border);
          object-fit: cover;
          cursor: pointer;
        }
        /* Favorites Quote */
        .adv-quote-box {
          margin-top: 8px;
          border: 1px solid var(--modal-border);
          border-radius: 12px;
          padding: 8px 12px;
          background-color: rgba(0, 0, 0, 0.03);
        }
        .adv-quote-header {
          display: flex;
          align-items: center;
          gap: 6px;
          margin-bottom: 4px;
          font-size: 12px;
        }
        .adv-quote-avatar {
          width: 20px;
          height: 20px;
          border-radius: 50%;
          object-fit: cover;
        }
        .adv-quote-name {
          font-weight: 700;
          color: var(--modal-text-primary);
        }
        .adv-quote-handle {
          color: var(--modal-text-secondary);
        }
        .adv-quote-text {
          font-size: 13px;
          color: var(--modal-text-primary);
          white-space: pre-wrap;
          word-break: break-word;
        }
        /* Content Link */
        .adv-content-link {
          color: var(--modal-primary-color);
          text-decoration: none;
        }
        .adv-content-link:hover {
          text-decoration: underline;
        }

        /* Media Play Icon */
        .adv-media-wrap {
          position: relative;
          display: inline-flex;
        }
        .adv-media-play-icon {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          width: 24px;
          height: 24px;
          background-color: rgba(0, 0, 0, 0.6);
          color: #fff;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          pointer-events: none; /* クリックを䞋の画像(リンク)に透過させる */
          backdrop-filter: blur(1px);
          z-index: 1;
        }
        .adv-media-play-icon svg {
          width: 14px;
          height: 14px;
          fill: currentColor;
          display: block;
          margin-left: 2px;
        }
        /* Favorites Item Tag Container */
        .adv-fav-tag-container {
           margin-top:0.7px;
           margin-left: 2px;
           display: inline-flex;
           align-items: center;
        }

        /* --- Mute Collapse Styles --- */
        /* Hard Mute: data-adv-hidden */
        [data-testid="cellInnerDiv"][data-adv-hidden],
        article[data-adv-hidden] {
          display: none !important;
          content-visibility: hidden;
          contain: strict;
        }

        /* Soft Mute: data-adv-collapsed */
        /* 1. Hide original content */
        [data-testid="cellInnerDiv"][data-adv-collapsed] > div:not(.adv-collapsed-placeholder),
        article[data-adv-collapsed] > div:not(.adv-collapsed-placeholder) {
            display: none !important;
        }

        /* 2. Show placeholder */
        .adv-collapsed-placeholder {
            display: none;
            align-items: center;
            justify-content: space-between;
            padding: 12px 16px;
            background-color: var(--modal-input-bg, #202327);
            border-bottom: 1px solid var(--modal-border, #38444d);
            cursor: pointer;
            user-select: none;
        }
        .adv-collapsed-placeholder:hover {
            background-color: color-mix(in srgb, var(--modal-input-bg, #202327) 85%, var(--modal-text-primary, #e7e9ea));
        }
        [data-testid="cellInnerDiv"][data-adv-collapsed] .adv-collapsed-placeholder,
        article[data-adv-collapsed] .adv-collapsed-placeholder {
            display: flex !important;
        }

        .adv-collapsed-label {
            flex: 1;
            font-size: 13px;
            color: var(--modal-text-secondary, #8b98a5);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            margin-right: 12px;
        }
        .adv-btn-show {
            background: transparent;
            border: 1px solid var(--modal-primary-color, #1d9bf0);
            color: var(--modal-primary-color, #1d9bf0);
            border-radius: 9999px;
            padding: 4px 16px;
            font-size: 12px;
            font-weight: 700;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .adv-btn-show:hover {
            background-color: rgba(29, 155, 240, 0.1);
        }

        /* タグチップのサむズ埮調敎 */
        .adv-item-sub .ft-tag-chip {
            margin-left: 8px;
            font-size: 10px;
            padding: 0 6px;
            height: 18px;
        }
        /* ▌▌▌ 再ミュヌトボタンのスタむル ▌▌▌ */
        .adv-btn-remute {
            margin-right: 12px; /* Caret(
)ずの間隔を確保 */
            padding: 4px 12px;  /* クリックしやすいよう少し拡倧 */
            font-size: 12px;
            font-weight: 700;
            border-radius: 9999px;
            border: 1px solid var(--modal-border, #38444d);
            color: var(--modal-text-secondary, #8b98a5);
            background: transparent;
            cursor: pointer;
            white-space: nowrap;
            display: inline-flex;
            align-items: center;
            height: 28px;       /* ヘッダヌのアクションボタンの高さに合わせる */
            line-height: 1;
            transition: all 0.2s;
        }
        .adv-btn-remute:hover {
            background: rgba(244, 33, 46, 0.1); /* Red tint */
            color: rgb(244, 33, 46);
            border-color: rgb(244, 33, 46);
        }

        /* ▌▌▌ 怜玢入力䞭のフォヌカス制埡 (Focus Mode) ▌▌▌ */

        /* 1. モヌダルを背景レベルたで䞋げる */
        #advanced-search-modal.adv-z-lower {
            z-index: 0 !important;
        }

        /* 2. Xのアプリ党䜓をモヌダルの䞊に持ち䞊げるサゞェスト救出のため */
        /* #react-root は body 盎䞋の X アプリケヌションのルヌト芁玠 */
        #react-root.adv-app-lifted {
            z-index: 1 !important;
            position: relative !important; /* z-indexを効かせるために必須 */
        }

        /* 3. サむドバヌ党䜓を「䞍可芖」にする
           これにより、トレンド・おすすめナヌザヌ・フッタヌ・枠線などが党お消え、
           背埌にあるモヌダルが芋えるように。
           (opacityではなくvisibilityを䜿うこずで、枠線も刀定も完党に消す)
        */
        #react-root.adv-app-lifted [data-testid="sidebarColumn"] {
            visibility: hidden !important;
        }

        /* 4. 怜玢フォヌムずその䞭身だけを「可芖化」しお救出する
           visibilityは芪がhiddenでも自分をvisibleにすれば衚瀺される
        */
        #react-root.adv-app-lifted [data-testid="sidebarColumn"] form[role="search"],
        #react-root.adv-app-lifted [data-testid="sidebarColumn"] form[role="search"] * {
            visibility: visible !important;
            opacity: 1 !important;
        }

        /* 5. サゞェスト入力候補も同様に救出する */
        #react-root.adv-app-lifted [data-testid="sidebarColumn"] [role="listbox"],
        #react-root.adv-app-lifted [data-testid="sidebarColumn"] [role="listbox"] * {
            visibility: visible !important;
            opacity: 1 !important;
        }

        /* モヌダルが巊偎にあっお被る堎合のみ、巊メニュヌを隠す */
        #react-root.adv-app-lifted.adv-overlap-left-menu header[role="banner"] {
            visibility: hidden !important;
            opacity: 0 !important;
            pointer-events: none !important;
        }

        /* === Native Search Resizer === */
        form[role="search"] {
            position: relative !important; /* リサむザヌの基準点 */
            max-width: none !important;    /* 幅制限の解陀 */
        }
        .adv-native-search-resizer {
            position: absolute;
            right: -8px;
            top: 0;
            bottom: 0;
            width: 16px;
            cursor: col-resize;
            z-index: 9999;
            background: transparent;
            touch-action: none; /* スマホでのスクロヌル干枉防止 */
        }
        .adv-native-search-resizer:hover {
            background: rgba(29,155,240,0.15); /* ホバヌ時に薄く青色を衚瀺 */
        }
    `);

    const modalHTML = `
        <div id="advanced-search-modal">
            <div class="adv-modal-header">
                <div class="adv-modal-title-left">
                    <h2 data-i18n="modalTitle"></h2>
                    <button id="adv-settings-button" class="adv-settings-btn" type="button" data-i18n-title="tooltipSettings">
                        ${SETTINGS_SVG}
                    </button>
                </div>
                <div class="adv-secret-wrap">
                    <button id="adv-secret-btn" class="adv-secret-btn off" data-i18n-title="tooltipSecret" title="">
                        <span class="dot" aria-hidden="true"></span>
                        <span id="adv-secret-label" data-i18n="secretMode"></span>
                        <span id="adv-secret-state" style="font-weight:700;"></span>
                    </button>
                    <button class="adv-modal-close" data-i18n-title="tooltipClose">&times;</button>
                </div>
            </div>

            <div class="adv-modal-body">
                <div class="adv-tabs">
                    <button class="adv-tab-btn active" data-tab="search" data-i18n="tabSearch"></button>
                    <button class="adv-tab-btn" data-tab="history" data-i18n="tabHistory"></button>
                    <button class="adv-tab-btn" data-tab="saved" data-i18n="tabSaved"></button>
                    <button class="adv-tab-btn" data-tab="favorites" data-i18n="tabFavorites"></button>
                    <button class="adv-tab-btn" data-tab="mute" data-i18n="tabMute"></button>
                    <button class="adv-tab-btn" data-tab="lists" data-i18n="tabLists"></button>
                    <button class="adv-tab-btn" data-tab="accounts" data-i18n="tabAccounts"></button>
                </div>

                <div class="adv-tab-content active" id="adv-tab-search">
                    <div id="adv-zoom-root" class="adv-zoom-root">
                    <form id="advanced-search-form">
                        <div class="adv-form-group"><label for="adv-all-words" data-i18n="labelAllWords"></label><input type="text" id="adv-all-words" data-i18n-placeholder="placeholderAllWords"></div>
                        <div class="adv-form-group"><label for="adv-exact-phrase" data-i18n="labelExactPhrase"></label><input type="text" id="adv-exact-phrase" data-i18n-placeholder="placeholderExactPhrase"></div>
                        <div class="adv-form-group"><label for="adv-any-words" data-i18n="labelAnyWords"></label><input type="text" id="adv-any-words" data-i18n-placeholder="placeholderAnyWords"></div>
                        <div class="adv-form-group"><label for="adv-not-words" data-i18n="labelNotWords"></label><input type="text" id="adv-not-words" data-i18n-placeholder="placeholderNotWords"></div>
                        <div class="adv-form-group"><label for="adv-hashtag" data-i18n="labelHashtag"></label><input type="text" id="adv-hashtag" data-i18n-placeholder="placeholderHashtag"></div>
                        <div class="adv-form-group">
                          <label for="adv-lang" data-i18n="labelLang"></label>
                          <select id="adv-lang">
                            <option value="" data-i18n="optLangDefault"></option>
                            <option value="ja" data-i18n="optLangJa"></option>
                            <option value="en" data-i18n="optLangEn"></option>
                            <option value="id" data-i18n="optLangId"></option>     <!-- むンドネシア -->
                            <option value="hi" data-i18n="optLangHi"></option>     <!-- ヒンディヌむンド -->
                            <option value="de" data-i18n="optLangDe"></option>     <!-- ドむツ -->
                            <option value="tr" data-i18n="optLangTr"></option>     <!-- トルコ -->
                            <option value="es" data-i18n="optLangEs"></option>     <!-- スペむン語メキシコ含む -->
                            <option value="pt" data-i18n="optLangPt"></option>     <!-- ポルトガル語ブラゞル-->
                            <option value="ar" data-i18n="optLangAr"></option>     <!-- アラビア語サりゞ等 -->
                            <option value="fr" data-i18n="optLangFr"></option>
                            <option value="ko" data-i18n="optLangKo"></option>
                            <option value="ru" data-i18n="optLangRu"></option>
                            <option value="zh-cn" data-i18n="optLangZhHans"></option> <!-- 簡䜓䞭文 -->
                            <option value="zh-tw" data-i18n="optLangZhHant"></option> <!-- 繁體䞭文 -->
                          </select>
                        </div>
                        <hr class="adv-separator">
                        <div class="adv-form-group">
                            <label data-i18n="labelFilters"></label>
                            <div class="adv-filter-grid">
                                <div class="adv-checkbox-group"><span data-i18n="labelVerified"></span><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-verified-include"><label for="adv-filter-verified-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-verified-exclude"><label for="adv-filter-verified-exclude" data-i18n="checkExclude"></label></div></div>
                                <div class="adv-checkbox-group"><span data-i18n="labelLinks"></span><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-links-include"><label for="adv-filter-links-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-links-exclude"><label for="adv-filter-links-exclude" data-i18n="checkExclude"></label></div></div>
                                <div class="adv-checkbox-group"><span data-i18n="labelImages"></span><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-images-include"><label for="adv-filter-images-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-images-exclude"><label for="adv-filter-images-exclude" data-i18n="checkExclude"></label></div></div>
                                <div class="adv-checkbox-group"><span data-i18n="labelVideos"></span><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-videos-include"><label for="adv-filter-videos-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-videos-exclude"><label for="adv-filter-videos-exclude" data-i18n="checkExclude"></label></div></div>
                                <div class="adv-checkbox-group"><span data-i18n="labelReposts"></span><div class="adv-checkbox-item" style="display: none;"><input type="checkbox" id="adv-filter-reposts-include" disabled><label for="adv-filter-reposts-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-reposts-exclude"><label for="adv-filter-reposts-exclude" data-i18n="checkExclude"></label></div></div>
                                <div class="adv-checkbox-group"><span data-i18n="labelTimelineHashtags"></span><div class="adv-checkbox-item" style="display: none;"><input type="checkbox" id="adv-filter-hashtags-include" disabled><label for="adv-filter-hashtags-include" data-i18n="checkInclude"></label></div><div class="adv-checkbox-item"><input type="checkbox" id="adv-filter-hashtags-exclude"><label for="adv-filter-hashtags-exclude" data-i18n="checkExclude"></label></div></div>
                            </div>
                        </div>

                        <div class="adv-form-group" title="" data-i18n-title="hintSearchTarget">
                          <label data-i18n="labelSearchTarget"></label>
                          <div class="adv-checkbox-group">
                            <div class="adv-checkbox-item">
                              <input type="checkbox" id="adv-exclude-hit-name" checked>
                              <label for="adv-exclude-hit-name" data-i18n="labelHitName" title="" data-i18n-title="hintName"></label>
                            </div>
                            <div class="adv-checkbox-item">
                              <input type="checkbox" id="adv-exclude-hit-handle" checked>
                              <label for="adv-exclude-hit-handle" data-i18n="labelHitHandle" title="" data-i18n-title="hintHandle"></label>
                            </div>
                          </div>
                        </div>

                        <div class="adv-form-row two-cols">
                            <div class="adv-form-group">
                                <label for="adv-account-scope" data-i18n="labelAccountScope"></label>
                                <select id="adv-account-scope">
                                    <option value="" data-i18n="optAccountAll"></option>
                                    <option value="following" data-i18n="optAccountFollowing"></option>
                                </select>
                            </div>
                            <div class="adv-form-group">
                                <label for="adv-location-scope" data-i18n="labelLocationScope"></label>
                                <select id="adv-location-scope">
                                    <option value="" data-i18n="optLocationAll"></option>
                                    <option value="nearby" data-i18n="optLocationNearby"></option>
                                </select>
                            </div>
                        </div>

                        <div class="adv-form-group"><label data-i18n="labelReplies"></label><select id="adv-replies"><option value="" data-i18n="optRepliesDefault"></option><option value="include" data-i18n="optRepliesInclude"></option><option value="only" data-i18n="optRepliesOnly"></option><option value="exclude" data-i18n="optRepliesExclude"></option></select></div>
                        <hr class="adv-separator">
                        <div class="adv-form-group">
                            <label data-i18n="labelEngagement"></label>
                            <div class="adv-filter-grid">
                                <input type="number" id="adv-min-replies" data-i18n-placeholder="placeholderMinReplies" min="0">
                                <input type="number" id="adv-min-faves" data-i18n-placeholder="placeholderMinLikes" min="0">
                                <input type="number" id="adv-min-retweets" data-i18n-placeholder="placeholderMinRetweets" min="0">
                            </div>
                        </div>
                        <div class="adv-form-group">
                            <div class="adv-form-group-header">
                                <label data-i18n="labelDateRange"></label>
                                <select id="adv-date-shortcut" class="adv-select-mini" data-i18n-title="labelDateShortcut">
                                    <option value="" data-i18n="labelDateShortcut" selected disabled style="display:none">Quick...</option>
                                    <option value="1d" data-i18n="optDate1Day">Past 24h</option>
                                    <option value="1w" data-i18n="optDate1Week">Past week</option>
                                    <option value="1m" data-i18n="optDate1Month">Past month</option>
                                    <option value="3m" data-i18n="optDate3Months">Past 3 months</option>
                                    <option value="6m" data-i18n="optDate6Months">Past 6 months</option>
                                    <option value="1y" data-i18n="optDate1Year">Past year</option>
                                    <option value="2y" data-i18n="optDate2Years">Past 2 years</option>
                                    <option value="3y" data-i18n="optDate3Years">Past 3 years</option>
                                    <option value="5y" data-i18n="optDate5Years">Past 5 years</option>
                                    <option disabled>──────────</option>
                                    <option value="clear" data-i18n="optDateClear">Clear</option>
                                </select>
                            </div>
                            <div class="adv-form-group-date-container">
                                <input type="date" id="adv-since" data-i18n-title="tooltipSince">
                                <span class="adv-date-separator">~</span>
                                <input type="date" id="adv-until" data-i18n-title="tooltipUntil">
                            </div>
                        </div>
                        <hr class="adv-separator">
                        <div class="adv-form-group">
                            <div class="adv-account-label-group">
                                <label for="adv-from-user" data-i18n="labelFromUser"></label>
                                <div class="adv-exclude-toggle"><input type="checkbox" id="adv-from-user-exclude"><label for="adv-from-user-exclude" data-i18n="checkExclude"></label></div>
                            </div>
                            <input type="text" id="adv-from-user" data-i18n-placeholder="placeholderFromUser">
                        </div>
                        <div class="adv-form-group">
                            <div class="adv-account-label-group">
                                <label for="adv-to-user" data-i18n="labelToUser"></label>
                                <div class="adv-exclude-toggle"><input type="checkbox" id="adv-to-user-exclude"><label for="adv-to-user-exclude" data-i18n="checkExclude"></label></div>
                            </div>
                            <input type="text" id="adv-to-user" data-i18n-placeholder="placeholderToUser">
                        </div>
                        <div class="adv-form-group">
                            <div class="adv-account-label-group">
                                <label for="adv-mentioning" data-i18n="labelMentioning"></label>
                                <div class="adv-exclude-toggle"><input type="checkbox" id="adv-mentioning-exclude"><label for="adv-mentioning-exclude" data-i18n="checkExclude"></label></div>
                            </div>
                            <input type="text" id="adv-mentioning" data-i18n-placeholder="placeholderMentioning">
                        </div>
                    </form>
                    </div>
                </div>

                <div class="adv-tab-content" id="adv-tab-history">
                  <div class="adv-zoom-root">
                    <div class="adv-tab-toolbar">
                        <div class="adv-tab-toolbar-left">
                            <input id="adv-history-search" class="adv-input" type="text" data-i18n-placeholder="placeholderSearchHistory">
                            <select id="adv-history-sort" class="adv-select" data-i18n-title="labelSortBy" title="Sort by:">
                                <option value="newest" data-i18n="sortNewest"></option>
                                <option value="oldest" data-i18n="sortOldest"></option>
                                <option value="name_asc" data-i18n="sortNameAsc"></option>
                                <option value="name_desc" data-i18n="sortNameDesc"></option>
                            </select>
                        </div>
                        <div class="adv-tab-toolbar-right">
                            <button id="adv-history-clear-all" class="adv-chip danger"></button>
                        </div>
                    </div>
                    <div id="adv-history-empty" class="adv-item-sub"></div>
                    <div id="adv-history-list" class="adv-list"></div>
                  </div>
                </div>

                <div class="adv-tab-content" id="adv-tab-saved">
                  <div class="adv-zoom-root">
                    <div id="adv-saved-empty" class="adv-item-sub"></div>
                    <div id="adv-saved-list" class="adv-list"></div>
                  </div>
                </div>

                <div class="adv-tab-content" id="adv-tab-favorites">
                  <div class="adv-zoom-root">
                    <div id="adv-favorites-list" class="adv-list"></div>
                    <div id="adv-favorites-empty" class="adv-item-sub"></div>
                  </div>
                </div>

                <div class="adv-tab-content" id="adv-tab-lists">
                  <div class="adv-zoom-root">
                    <div id="adv-lists-empty" class="adv-item-sub"></div>
                    <div id="adv-lists-list" class="adv-list"></div>
                  </div>
                </div>

                <div class="adv-tab-content" id="adv-tab-accounts">
                  <div class="adv-zoom-root">
                    <div id="adv-accounts-empty" class="adv-item-sub"></div>
                    <div id="adv-accounts-list" class="adv-list"></div>
                  </div>
                </div>

                <!-- ▶ Mute タブ -->
                <div class="adv-tab-content" id="adv-tab-mute">
                  <div class="adv-zoom-root">
                    <div class="adv-form-group">
                      <!-- 远加する䞊びたず“远加”UI -->
                      <div class="adv-mute-add">
                        <input type="text" id="adv-mute-input" data-i18n-placeholder="placeholderMuteWord">
                        <div style="display:flex; flex-direction:column; gap:2px; margin-left:4px; margin-right:4px;">
                            <label class="adv-toggle" title="">
                              <input type="checkbox" id="adv-mute-wb">
                              <span data-i18n="labelWordBoundary"></span>
                            </label>
                            <label class="adv-toggle" title="">
                              <input type="checkbox" id="adv-mute-cs">
                              <span data-i18n="labelCaseSensitive"></span>
                            </label>
                        </div>
                        <button id="adv-mute-add" class="adv-modal-button" data-i18n="buttonAdd"></button>
                      </div>

                      <hr class="adv-separator" style="margin-top:12px; margin-bottom:12px;">

                      <!-- â–Œ 新しい芋出しブロックミュヌト䞀芧 + すべお有効/無効 -->
                      <div class="adv-mute-header">
                        <input type="text" id="adv-mute-filter" data-i18n-placeholder="placeholderFilterMute">

                        <div class="adv-mute-header-controls">
                            <select id="adv-mute-mode" class="adv-select">
                                <option value="hidden" data-i18n="optMuteHidden">Hidden</option>
                                <option value="collapsed" data-i18n="optMuteCollapsed">Collapsed</option>
                            </select>
                            <label class="adv-toggle">
                              <input type="checkbox" id="adv-mute-enable-all" checked>
                              <span data-i18n="labelEnableAll"></span>
                            </label>
                        </div>
                      </div>

                      <div id="adv-mute-empty" class="adv-item-sub"></div>
                      <div id="adv-mute-list" class="adv-mute-list"></div>
                    </div>
                  </div>
                </div>

            </div>
            <div class="adv-modal-footer">
                <button id="adv-save-button" class="adv-modal-button" data-i18n="buttonSave"></button>
                <button id="adv-clear-button" class="adv-modal-button" data-i18n="buttonClear"></button>
                <button id="adv-apply-button" class="adv-modal-button primary" data-i18n="buttonApply"></button>
            </div>
        </div>

        <div id="adv-toast" class="adv-toast" role="status" aria-live="polite"></div>
            <div id="adv-settings-modal" class="adv-settings-modal">
            <div class="adv-settings-dialog">
                <div class="adv-settings-header">
                    <div style="display:flex; align-items:center; gap:15px;">
                        <h3 class="adv-settings-title" data-i18n="settingsTitle"></h3>
                        <button id="adv-settings-reset" type="button" class="adv-chip danger" data-i18n="buttonReset"></button>
                    </div>
                    <button id="adv-settings-close" type="button" class="adv-settings-close" data-i18n-title="tooltipClose">&times;</button>
                </div>
                <div class="adv-settings-body">
                  <div class="adv-settings-section-header" data-i18n="settingsTitleGeneral"></div>
                    <div class="adv-settings-group">
                        <label for="adv-settings-lang" data-i18n="labelUILang"></label>
                        <select id="adv-settings-lang">
                            <option value="" data-i18n="optUILangAuto"></option>
                            <option value="en">English</option>
                            <option value="ja">日本語</option>
                            <option value="fr">Français</option>
                            <option value="es">Español</option>
                            <option value="de">Deutsch</option>
                            <option value="pt-BR">Português (Brasil)</option>
                            <option value="ru">РусскОй</option>
                            <option value="ko">한국얎</option>
                            <option value="zh-CN">简䜓䞭文</option>
                            <option value="zh-TW">繁體䞭文</option>
                        </select>
                    </div>

                      <div class="adv-settings-group">
                          <label for="adv-settings-initial-tab" data-i18n="labelInitialTab"></label>
                          <select id="adv-settings-initial-tab">
                              <option value="last" data-i18n="optInitialTabLast"></option>
                              <option value="search" data-i18n="tabSearch"></option>
                              <option value="history" data-i18n="tabHistory"></option>
                              <option value="saved" data-i18n="tabSaved"></option>
                              <option value="favorites" data-i18n="tabFavorites"></option>
                              <option value="mute" data-i18n="tabMute"></option>
                              <option value="lists" data-i18n="tabLists"></option>
                              <option value="accounts" data-i18n="tabAccounts"></option>
                          </select>
                      </div>

                      <div class="adv-settings-section-header" data-i18n="settingsTitleFeatures"></div>
                      <div class="adv-settings-group">
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-search">
                              <span data-i18n="tabSearch"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-search" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-history">
                              <span data-i18n="tabHistory"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-history" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-saved">
                              <span data-i18n="tabSaved"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-saved" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-favorites">
                              <span data-i18n="tabFavorites"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-favorites" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-mute">
                              <span data-i18n="tabMute"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-mute" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-lists">
                              <span data-i18n="tabLists"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-lists" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                        <div class="adv-settings-toggle-row">
                          <label class="adv-toggle" for="adv-settings-tab-toggle-accounts">
                              <span data-i18n="tabAccounts"></span>
                          </label>
                          <label class="adv-switch">
                              <input id="adv-settings-tab-toggle-accounts" type="checkbox">
                              <span class="adv-slider"></span>
                          </label>
                        </div>
                      </div>
                      <div class="adv-settings-section-header" data-i18n="settingsTitleData"></div>
                      <div class="adv-settings-group">
                          <div class="adv-settings-actions-inline">
                              <button id="adv-settings-export" type="button" class="adv-modal-button" data-i18n="buttonExport"></button>
                              <button id="adv-settings-import" type="button" class="adv-modal-button primary" data-i18n="buttonImport"></button>
                              <input id="adv-settings-file-input" type="file" accept="application/json" style="display:none">
                          </div>
                      </div>

                    </div>
                    <div class="adv-settings-footer">
                        <button id="adv-settings-close-footer" type="button" class="adv-modal-button" data-i18n="buttonClose"></button>
                    </div>
            </div>
        </div>
    `;

    const initialize = async () => {
        i18n.init();

        const kv = {
            get(key, def) { try { return GM_getValue(key, def); } catch (_) { return def; } },
            set(key, val) { try { GM_setValue(key, val); } catch (_) {} },
            del(key)      { try { GM_deleteValue(key); } catch (_) {} },
        };
        const loadJSON = (key, def) => {
            try {
                const raw = kv.get(key, JSON.stringify(def));
                return JSON.parse(raw);
            } catch(_) { return def; }
        };
        const saveJSON = (key, value) => {
            try { kv.set(key, JSON.stringify(value)); } catch(_) {}
        };

        const DEFAULT_TABS = ['search', 'history', 'saved', 'favorites', 'mute', 'lists', 'accounts'];
        const DEFAULT_TABS_VISIBILITY = {
            search: true,
            history: true,
            saved: true,
            favorites: true,
            mute: true,
            lists: true,
            accounts: true,
        };
        const loadTabsVisibility = () => {
            const stored = loadJSON(TABS_VISIBILITY_KEY, DEFAULT_TABS_VISIBILITY);
            const normalized = { ...DEFAULT_TABS_VISIBILITY };
            for (const key of DEFAULT_TABS) {
                normalized[key] = stored[key] === false ? false : true; // false のみ明瀺的に匕き継ぐ
            }
            return normalized;
        };
        const saveTabsVisibility = (state) => {
            saveJSON(TABS_VISIBILITY_KEY, state);
        };

        /* --- Favorite Tags: Code Block --- */

        // ------------- 定数 & 状態 ------------- //
        const FT_STATE_KEY = 'ftTagState_v1';
        const FT_FILTER_ALL = 'all';
        const FT_FILTER_UNCATEGORIZED = 'uncategorized';
        const FT_TWEET_ID_REGEX = /\/status\/(\d+)/;

        let ft_state = null;
        let ft_initialized = false;
        let ft_currentFilter = FT_FILTER_ALL;
        let ft_currentDropdown = null;
        let ft_settingsModalBackdrop = null;
        let ft_dragSrcEntry = null;

        // ------------- State 管理 ------------- //

        function ft_createDefaultState() {
            return {
                enabled: true,
                tags: [],
                tweetTags: {},
                uncategorized: { color: '#8899A6', order: 0 },
                display: { mode: 'leaf' },
            };
        }

        function ft_normalizeTagOrdersFor(stateObj) {
            if (!stateObj || !Array.isArray(stateObj.tags)) return;
            const groups = new Map();
            for (const tag of stateObj.tags) {
                if (!tag || typeof tag !== 'object') continue;
                const pid = tag.parentId || null;
                if (!groups.has(pid)) groups.set(pid, []);
                groups.get(pid).push(tag);
            }
            for (const arr of groups.values()) {
                arr.sort((a, b) => (typeof a.order === 'number' ? a.order : 0) - (typeof b.order === 'number' ? b.order : 0));
                arr.forEach((tag, i) => { tag.order = i; });
            }
        }

        function ft_countRootTagsFor(stateObj) {
            if (!stateObj || !Array.isArray(stateObj.tags)) return 0;
            return stateObj.tags.filter((t) => !t.parentId).length;
        }

        function ft_clampUncategorizedOrderFor(stateObj) {
            if (!stateObj) return;
            if (!stateObj.uncategorized || typeof stateObj.uncategorized !== 'object') {
                stateObj.uncategorized = { color: '#8899A6', order: 0 };
            }
            const rootCount = ft_countRootTagsFor(stateObj);
            let pos = typeof stateObj.uncategorized.order === 'number' ? stateObj.uncategorized.order : 0;
            if (pos < 0) pos = 0;
            if (pos > rootCount) pos = rootCount;
            stateObj.uncategorized.order = pos;
        }

        function ft_normalizeTagOrders() { if (ft_state) ft_normalizeTagOrdersFor(ft_state); }
        function ft_clampUncategorizedOrder() { if (ft_state) ft_clampUncategorizedOrderFor(ft_state); }

        function ft_loadState() {
            try {
                const parsed = loadJSON(FT_STATE_KEY, null);
                if (!parsed || typeof parsed !== 'object') return ft_createDefaultState();

                if (!Array.isArray(parsed.tags)) parsed.tags = [];
                if (!parsed.tweetTags || typeof parsed.tweetTags !== 'object') parsed.tweetTags = {};
                parsed.enabled = true;

                if (!parsed.uncategorized || typeof parsed.uncategorized !== 'object') {
                    parsed.uncategorized = { color: '#8899A6', order: 0 };
                } else {
                    if (!parsed.uncategorized.color) parsed.uncategorized.color = '#8899A6';
                    if (typeof parsed.uncategorized.order !== 'number') parsed.uncategorized.order = 0;
                }

                if (!parsed.display || typeof parsed.display !== 'object') {
                    parsed.display = { mode: 'leaf' };
                } else if (parsed.display.mode !== 'leaf' && parsed.display.mode !== 'full') {
                    parsed.display.mode = 'leaf';
                }

                ft_normalizeTagOrdersFor(parsed);
                ft_clampUncategorizedOrderFor(parsed);
                return parsed;
            } catch (e) {
                return ft_createDefaultState();
            }
        }

        function ft_saveState(newState) {
            if (newState) ft_state = newState;
            try {
                if (ft_state) {
                    ft_normalizeTagOrdersFor(ft_state);
                    ft_clampUncategorizedOrderFor(ft_state);
                    saveJSON(FT_STATE_KEY, ft_state);
                }
            } catch (e) {}
            requestAnimationFrame(() => {
                ft_refreshAllTagChips();

                // お気に入りタブが開いおいれば再描画しおタグ倉曎/絞り蟌みを反映
                if (getActiveTabName() === 'favorites') {
                    renderFavorites();
                }
            });
        }

        function ft_generateTagId() {
            return 'tag_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8);
        }

        function ft_getTagById(tagId) {
            return ft_state.tags.find((t) => t.id === tagId) || null;
        }

        function ft_getAllTags() {
            return ft_state.tags.slice();
        }

        function ft_getTagColor(tagId) {
            const tag = ft_getTagById(tagId);
            return tag ? tag.color || '#1d9bf0' : '#8899A6';
        }

        function ft_getUncategorizedColor() {
            return ft_state?.uncategorized?.color || '#8899A6';
        }

        function ft_createNewTag(name, color, parentId) {
            const pid = parentId || null;
            const siblingsCount = ft_state.tags.filter((t) => (t.parentId || null) === pid).length;
            const tag = {
                id: ft_generateTagId(),
                name,
                color,
                parentId: pid,
                order: siblingsCount,
            };
            ft_state.tags.push(tag);
            return tag;
        }

        function ft_countRootTags() {
            return ft_countRootTagsFor(ft_state);
        }

        function ft_getTagAncestors(tag) {
            const result = [];
            if (!tag) return result;
            const seen = new Set();
            let current = tag;
            while (current) {
                if (seen.has(current.id)) break;
                seen.add(current.id);
                result.unshift(current);
                if (!current.parentId) break;
                current = ft_getTagById(current.parentId);
            }
            return result;
        }

        function ft_getTagFullPath(tag) {
            const ancestors = ft_getTagAncestors(tag);
            if (!ancestors.length) return tag ? tag.name || '' : '';
            return ancestors.map((t) => t.name || '').join(' / ');
        }

        function ft_getTagDisplayLabelFromTag(tag) {
            if (!tag) return '';
            const mode = ft_state?.display?.mode;
            if (mode === 'full') return ft_getTagFullPath(tag);
            return tag.name;
        }

        function ft_getTagListWithUncategorized() {
            const result = [];
            if (!ft_state || !Array.isArray(ft_state.tags)) return result;

            const byParent = new Map();
            for (const tag of ft_state.tags) {
                if (!tag || typeof tag !== 'object') continue;
                const pid = tag.parentId || null;
                if (!byParent.has(pid)) byParent.set(pid, []);
                byParent.get(pid).push(tag);
            }

            for (const arr of byParent.values()) {
                arr.sort((a, b) => (typeof a.order === 'number' ? a.order : 0) - (typeof b.order === 'number' ? b.order : 0));
            }

            function dfs(parentId, depth) {
                const arr = byParent.get(parentId || null);
                if (!arr) return;
                for (const tag of arr) {
                    result.push({ tag, depth });
                    dfs(tag.id, depth + 1);
                }
            }
            dfs(null, 0);

            const entries = [];
            const rootCount = result.filter((e) => e.depth === 0).length;
            let uncatPos = ft_state.uncategorized.order || 0;
            if (uncatPos < 0) uncatPos = 0;
            if (uncatPos > rootCount) uncatPos = rootCount;

            let rootIndex = 0;
            for (const item of result) {
                if (item.depth === 0 && rootIndex === uncatPos) {
                    entries.push({ kind: 'uncat', depth: 0 });
                }
                entries.push({ kind: 'tag', tag: item.tag, depth: item.depth });
                if (item.depth === 0) rootIndex++;
            }
            if (rootCount === 0 || uncatPos === rootCount) {
                entries.push({ kind: 'uncat', depth: 0 });
            }
            return entries;
        }

        function ft_isTagInSubtree(tagId, rootTagId) {
            // ft_state が存圚しない堎合は即座に false を返す
            if (!ft_state || !tagId || !rootTagId) return false;

            if (tagId === rootTagId) return true;
            let current = ft_getTagById(tagId);
            const visited = new Set();
            while (current && current.parentId) {
                if (visited.has(current.id)) break;
                visited.add(current.id);
                if (current.parentId === rootTagId) return true;
                current = ft_getTagById(current.parentId);
            }
            return false;
        }

        function ft_wouldCreateCycle(newParentId, childId) {
            if (!newParentId || !childId) return false;
            if (newParentId === childId) return true;
            let current = ft_getTagById(newParentId);
            const visited = new Set();
            while (current && current.parentId) {
                if (visited.has(current.id)) break;
                visited.add(current.id);
                if (current.parentId === childId) return true;
                current = ft_getTagById(current.parentId);
            }
            return false;
        }

        // ------------- ルヌト & ナヌティリティ ------------- //

        // ツむヌトのDOMからIDを抜出
        function ft_extractTweetId(article) {
            if (article.dataset.ftTweetId) return article.dataset.ftTweetId;

            // 匕甚ツむヌトカヌド郚分の䞭にあるリンクを陀倖するための刀定関数
            // div[role="link"] は匕甚カヌドのコンテナに付䞎される属性です
            const isInsideQuote = (el) => {
                return !!el.closest('div[role="link"]');
            };

            // 1. 最も確実な方法: <time>タグの芪アンカヌを探す
            const timeEls = Array.from(article.querySelectorAll('time'));
            for (const timeEl of timeEls) {
                const timeAnchor = timeEl.closest('a');
                if (timeAnchor) {
                    // ★远加: 匕甚カヌドの䞭にある時刻リンクならスキップする
                    if (isInsideQuote(timeAnchor)) continue;

                    const href = timeAnchor.getAttribute('href');
                    const m = href.match(/\/status\/(\d+)/);
                    if (m) return m[1];
                }
            }

            // 2. フォヌルバック: 埓来の怜玢方法
            try {
                const anchors = Array.from(article.querySelectorAll('a[href*="/status/"]'));
                for (const a of anchors) {
                    if (a.dataset.testid === 'tweet-text-show-more-link') continue;

                    // 匕甚カヌドの䞭にあるリンクならスキップする
                    if (isInsideQuote(a)) continue;

                    const href = a.getAttribute('href') || '';
                    const m = href.match(/\/status\/(\d+)/);
                    if (m) return m[1];
                }
            } catch (e) {}

            return null;
        }

        // タグチップの挿入堎所ヘッダヌメタ情報行を特定する関数
        function ft_findHeaderMetaContainer(article) {
            // 1. User-Name を起点にする (タむムラむンでも詳现衚瀺でも必ずヘッダヌに存圚する)
            const userName = article.querySelector('[data-testid="User-Name"]');

            if (userName) {
                // User-Name の芪を遡り、ハンドルネヌム(@...)や時間衚瀺を含む「行コンテナ」を探す
                // 構造: [Container] -> [NameWrapper] -> [User-Name]
                //             L-> [HandleWrapper] -> [@handle]
                let p = userName.parentElement;

                // 芪を数回遡っお、兄匟芁玠に「@から始たるテキストハンドル」を含むコンテナを探す
                // ※通垞は23階局䞊
                while (p && p !== article) {
                    // 自分の芪の盎䞋(兄匟芁玠)に、自分以倖で「@」から始たるテキストを持぀芁玠があるか確認
                    const hasHandleSibling = Array.from(p.children).some(sib => {
                        // 自分自身のラッパヌは陀倖
                        if (sib.contains(userName)) return false;
                        // テキストを取埗しお @ で始たっおいるか刀定
                        const txt = sib.innerText || '';
                        return txt.trim().startsWith('@');
                    });

                    if (hasHandleSibling) {
                        // ハンドルネヌムず䞊んでいるコンテナが芋぀かったら、ここが挿入堎所
                        return p;
                    }
                    p = p.parentElement;
                }
            }

            // 2. フォヌルバック: 埓来のTime怜玢 (ただし匕甚ツむヌト内のTimeは厳密に陀倖する)
            const allTimes = article.querySelectorAll('time');
            for (const timeEl of allTimes) {
                // 匕甚(role="link")の䞭にあるtimeは無芖しおスキップ
                if (timeEl.closest('div[role="link"]')) continue;

                const anchor = timeEl.closest('a');
                if (anchor && anchor.parentElement && anchor.parentElement.parentElement) {
                    return anchor.parentElement.parentElement;
                }
            }

            return null;
        }

        // ------------- タグチップ描画むベント委譲察応 ------------- //

        function ft_buildTagChip(tweetId) {
            const currentTagId = ft_state.tweetTags[tweetId];
            const isUncategorized = !currentTagId;
            const tag = currentTagId ? ft_getTagById(currentTagId) : null;
            const label = isUncategorized
                ? i18n.t('FT_UNCATEGORIZED')
                : ft_getTagDisplayLabelFromTag(tag) || i18n.t('FT_UNCATEGORIZED');
            const color = isUncategorized ? ft_getUncategorizedColor() : ft_getTagColor(currentTagId);

            const btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'ft-tag-chip' + (isUncategorized ? ' ft-tag-chip-uncategorized' : '');
            btn.style.color = color;
            btn.style.borderColor = color;
            btn.dataset.tweetId = tweetId;

            const span = document.createElement('span');
            span.className = 'ft-tag-chip-label';
            span.textContent = label;
            span.style.pointerEvents = 'none'; // クリックをボタンに透過

            btn.appendChild(span);
            return btn;
        }

        function ft_attachTagChipToArticle(article, tweetId) {
            if (!ft_state.enabled) return;
            const headerRow = ft_findHeaderMetaContainer(article);
            if (!headerRow) return;

            // ▌▌▌ スタむルの適甚 ▌▌▌
            headerRow.style.display = 'flex';
            headerRow.style.flexDirection = 'row';
            headerRow.style.alignItems = 'center';
            headerRow.style.justifyContent = 'flex-start';
            headerRow.style.columnGap = '4px';

            // スペヌスが足りない堎合に折り返しを蚱可する
            headerRow.style.flexWrap = 'wrap';
            // 折り返した際、䞊䞋の行に隙間を䜜る
            headerRow.style.rowGap = '8px';

            let existing = headerRow.querySelector('.ft-tag-chip');
            const chip = ft_buildTagChip(tweetId);
            if (existing) {
                existing.replaceWith(chip);
            } else {
                headerRow.appendChild(chip);
            }
            article.classList.add('ft-chip-attached');
        }

        function ft_removeTagChipFromArticle(article) {
            const chip = article.querySelector('.ft-tag-chip');
            if (chip) chip.remove();
            article.classList.remove('ft-chip-attached');
        }

        function ft_refreshAllTagChips() {
            const articles = document.querySelectorAll('article[data-testid="tweet"]');
            for (const article of articles) {
                ft_processTweetArticle(article);
            }
        }

        // ------------- タグ / フィルタ甚ドロップダりン ------------- //

        function ft_closeTagDropdown() {
            if (ft_currentDropdown) {
                ft_currentDropdown.remove();
                ft_currentDropdown = null;
            }
        }

        // タグごずの件数を集蚈するヘルパヌ
        function ft_countTagUsage() {
            const counts = { uncat: 0, total: 0 };
            // 党タグの初期倀を0にする
            if (ft_state && ft_state.tags) {
                ft_state.tags.forEach(t => counts[t.id] = 0);
            }

            // 珟圚のお気に入りリストをロヌドしお集蚈
            const favs = loadFavorites();
            counts.total = favs.length;

            favs.forEach(item => {
                const tagId = ft_state.tweetTags[item.id];
                if (tagId && counts[tagId] !== undefined) {
                    counts[tagId]++;
                } else {
                    counts.uncat++;
                }
            });
            return counts;
        }

        function ft_buildTagDropdownContent(tweetId) {
            const wrapper = document.createElement('div');
            wrapper.className = 'ft-tag-dropdown';
            wrapper.dataset.tweetId = tweetId;

            const header = document.createElement('div');
            header.className = 'ft-tag-dropdown-header';
            const headerLeft = document.createElement('div');
            headerLeft.style.display = 'flex'; headerLeft.style.alignItems = 'center'; headerLeft.style.gap = '4px';
            const title = document.createElement('div');
            title.textContent = i18n.t('FT_DROPDOWN_TITLE');
            const settingsBtn = document.createElement('button');
            settingsBtn.type = 'button'; settingsBtn.className = 'ft-settings-button'; settingsBtn.textContent = '⚙';
            settingsBtn.title = i18n.t('FT_SETTINGS_BUTTON_TITLE');
            settingsBtn.addEventListener('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); ft_closeTagDropdown(); ft_openSettingsModal(); });
            headerLeft.appendChild(title); headerLeft.appendChild(settingsBtn);
            const closeBtn = document.createElement('button');
            closeBtn.className = 'ft-tag-dropdown-close'; closeBtn.type = 'button'; closeBtn.textContent = '×';
            closeBtn.addEventListener('click', () => ft_closeTagDropdown());
            header.appendChild(headerLeft); header.appendChild(closeBtn);

            const tagList = document.createElement('div');
            tagList.className = 'ft-tag-dropdown-tags';
            const currentTagId = ft_state.tweetTags[tweetId] || null;
            const entries = ft_getTagListWithUncategorized();

            const counts = ft_countTagUsage();

            for (const entry of entries) {
                const item = document.createElement('div');
                const colorDot = document.createElement('div');
                const label = document.createElement('div');
                label.className = 'ft-tag-dropdown-tag-label';

                if (entry.kind === 'uncat') {
                    item.className = 'ft-tag-dropdown-tag-item' + (currentTagId ? '' : ' ft-tag-dropdown-tag-selected');
                    colorDot.className = 'ft-tag-dropdown-tag-color';
                    colorDot.style.backgroundColor = ft_getUncategorizedColor();
                    label.textContent = i18n.t('FT_UNCATEGORIZED') + ` (${counts.uncat})`;
                    item.addEventListener('click', () => { delete ft_state.tweetTags[tweetId]; ft_saveState(); ft_closeTagDropdown(); });
                } else {
                    const tag = entry.tag;
                    item.className = 'ft-tag-dropdown-tag-item' + (tag.id === currentTagId ? ' ft-tag-dropdown-tag-selected' : '');
                    colorDot.className = 'ft-tag-dropdown-tag-color';
                    colorDot.style.backgroundColor = tag.color || '#1d9bf0';
                    if (entry.depth > 0) colorDot.style.marginLeft = `${entry.depth * 12}px`;
                    const c = counts[entry.tag.id] || 0;
                    label.textContent = (entry.tag.name || '') + ` (${c})`;
                    item.addEventListener('click', () => { ft_state.tweetTags[tweetId] = tag.id; ft_saveState(); ft_closeTagDropdown(); });
                }
                item.appendChild(colorDot); item.appendChild(label);
                tagList.appendChild(item);
            }

            const newSection = document.createElement('div');
            newSection.className = 'ft-tag-dropdown-new';
            const newLabel = document.createElement('div');
            newLabel.textContent = i18n.t('FT_DROPDOWN_NEW_TAG');
            const newRow = document.createElement('div');
            newRow.className = 'ft-tag-dropdown-new-row';
            const newInput = document.createElement('input');
            newInput.type = 'text'; newInput.placeholder = i18n.t('FT_DROPDOWN_NEW_TAG_PLACEHOLDER'); newInput.className = 'ft-tag-dropdown-new-input';
            const newColor = document.createElement('input');
            newColor.type = 'color'; newColor.value = '#1d9bf0'; newColor.className = 'ft-tag-dropdown-new-color';
            const addBtn = document.createElement('button');
            addBtn.type = 'button'; addBtn.className = 'ft-tag-dropdown-new-button'; addBtn.textContent = i18n.t('FT_DROPDOWN_NEW_TAG_ADD');

            function doAddTag() {
                const name = newInput.value.trim();
                if (!name) return;
                const tag = ft_createNewTag(name, newColor.value || '#1d9bf0', null);
                ft_state.tweetTags[tweetId] = tag.id;
                ft_saveState();
                ft_closeTagDropdown();
            }
            addBtn.addEventListener('click', doAddTag);
            newInput.addEventListener('keydown', (ev) => { if (ev.key === 'Enter') { ev.preventDefault(); doAddTag(); } });

            newRow.appendChild(newColor); newRow.appendChild(newInput); newRow.appendChild(addBtn);
            newSection.appendChild(newLabel); newSection.appendChild(newRow);
            wrapper.appendChild(header); wrapper.appendChild(tagList); wrapper.appendChild(newSection);
            return wrapper;
        }

        function ft_openTagDropdown(chipEl, tweetId) {
            ft_closeTagDropdown();
            const dropdown = ft_buildTagDropdownContent(tweetId);
            ft_currentDropdown = dropdown;
            document.body.appendChild(dropdown);
            const rect = chipEl.getBoundingClientRect();
            const margin = 8;
            const width = dropdown.offsetWidth || 240;
            const height = dropdown.offsetHeight || 200;
            let left = rect.left;
            if (left + width + margin > window.innerWidth) left = window.innerWidth - width - margin;
            if (left < margin) left = margin;
            let top = rect.bottom + 4;
            if (top + height + margin > window.innerHeight) top = rect.top - height - 4;
            if (top < margin) top = margin;
            dropdown.style.left = `${left}px`; dropdown.style.top = `${top}px`;
        }

        // ---- ブックマヌクフィルタ甚ドロップダりン ---- //
        function ft_buildFilterDropdownContent(targetValue, onSelectCallback) {
            const currentValue = targetValue;

            const wrapper = document.createElement('div');
            wrapper.className = 'ft-tag-dropdown ft-filter-dropdown';
            const header = document.createElement('div'); header.className = 'ft-tag-dropdown-header';
            const headerLeft = document.createElement('div'); headerLeft.style.display = 'flex'; headerLeft.style.alignItems = 'center'; headerLeft.style.gap = '4px';
            const title = document.createElement('div'); title.textContent = i18n.t('FT_DROPDOWN_TITLE');
            const settingsBtn = document.createElement('button'); settingsBtn.type = 'button'; settingsBtn.className = 'ft-settings-button'; settingsBtn.textContent = '⚙'; settingsBtn.title = i18n.t('FT_SETTINGS_BUTTON_TITLE');
            settingsBtn.addEventListener('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); ft_closeTagDropdown(); ft_openSettingsModal(); });
            headerLeft.appendChild(title); headerLeft.appendChild(settingsBtn);
            const closeBtn = document.createElement('button'); closeBtn.className = 'ft-tag-dropdown-close'; closeBtn.type = 'button'; closeBtn.textContent = '×';
            closeBtn.addEventListener('click', () => ft_closeTagDropdown());
            header.appendChild(headerLeft); header.appendChild(closeBtn);

            const tagList = document.createElement('div'); tagList.className = 'ft-tag-dropdown-tags';
            function addItem(value, label, color, depth) {
                const item = document.createElement('div');
                item.className = 'ft-tag-dropdown-tag-item' + (value === currentValue ? ' ft-tag-dropdown-tag-selected' : '');
                const colorDot = document.createElement('div');
                colorDot.className = 'ft-tag-dropdown-tag-color'; colorDot.style.backgroundColor = color || 'rgba(239,243,244,0.6)';
                if (depth > 0) colorDot.style.marginLeft = `${depth * 12}px`;
                const text = document.createElement('div');
                text.className = 'ft-tag-dropdown-tag-label'; text.textContent = label;
                item.appendChild(colorDot); item.appendChild(text);
                item.addEventListener('click', () => {
                    if (typeof onSelectCallback === 'function') {
                        onSelectCallback(value);
                    }
                    ft_closeTagDropdown();
                });
                tagList.appendChild(item);
            }
            const counts = ft_countTagUsage();
            addItem(FT_FILTER_ALL, i18n.t('FT_FILTER_ALL') + ` (${counts.total})`, 'rgba(239,243,244,0.7)', 0);

            const entries = ft_getTagListWithUncategorized();
            for (const entry of entries) {
                if (entry.kind === 'uncat') {
                    addItem(FT_FILTER_UNCATEGORIZED, i18n.t('FT_UNCATEGORIZED') + ` (${counts.uncat})`, ft_getUncategorizedColor(), 0);
                } else {
                    // フィルタ時は「そのタグ + 子孫タグ」の合蚈件数を蚈算しお衚瀺する
                    // (絞り蟌み機胜がサブツリヌ怜玢であるため、件数も合わせるのが自然)
                    let subTreeCount = 0;
                    if (ft_state && ft_state.tags) {
                        ft_state.tags.forEach(t => {
                            if (ft_isTagInSubtree(t.id, entry.tag.id)) {
                                subTreeCount += (counts[t.id] || 0);
                            }
                        });
                    }
                    // 合蚈件数を衚瀺
                    addItem(entry.tag.id, (entry.tag.name || '') + ` (${subTreeCount})`, entry.tag.color, entry.depth);
                }
            }
            wrapper.appendChild(header); wrapper.appendChild(tagList);
            return wrapper;
        }

        function ft_openFilterDropdown(buttonEl, targetValue, onSelectCallback) {
            ft_closeTagDropdown();
            const dropdown = ft_buildFilterDropdownContent(targetValue, onSelectCallback);
            ft_currentDropdown = dropdown;
            document.body.appendChild(dropdown);
            const rect = buttonEl.getBoundingClientRect();
            const margin = 8;
            const width = dropdown.offsetWidth || 240;
            const height = dropdown.offsetHeight || 200;
            let left = rect.left;
            if (left + width + margin > window.innerWidth) left = window.innerWidth - width - margin;
            if (left < margin) left = margin;
            let top = rect.bottom + 4;
            if (top + height + margin > window.innerHeight) top = rect.top - height - 4;
            if (top < margin) top = margin;
            dropdown.style.left = `${left}px`; dropdown.style.top = `${top}px`;
        }

        // ------------- 蚭定モヌダル ------------- //

        function ft_closeSettingsModal() {
            if (ft_settingsModalBackdrop) { ft_settingsModalBackdrop.remove(); ft_settingsModalBackdrop = null; }
            ft_dragSrcEntry = null;
        }

        function ft_openSettingsModal() {
            ft_closeSettingsModal();
            const backdrop = document.createElement('div'); backdrop.className = 'ft-modal-backdrop';
            const modal = document.createElement('div'); modal.className = 'ft-modal';
            const header = document.createElement('div'); header.className = 'ft-modal-header';
            const title = document.createElement('div'); title.className = 'ft-modal-title'; title.textContent = i18n.t('FT_SETTINGS_TITLE');
            header.appendChild(title);
            const body = document.createElement('div'); body.className = 'ft-modal-body';
            const displaySection = document.createElement('div'); displaySection.className = 'ft-modal-display-settings';
            const displayTitle = document.createElement('div'); displayTitle.textContent = i18n.t('FT_SETTINGS_DISPLAY_SECTION_TITLE');
            const modeRow = document.createElement('div'); modeRow.className = 'ft-modal-display-settings-row';
            const modeLabel = document.createElement('span'); modeLabel.textContent = i18n.t('FT_SETTINGS_DISPLAY_MODE_LABEL');
            const radioLeafLabel = document.createElement('label'); radioLeafLabel.className = 'ft-modal-display-radio';
            const radioLeaf = document.createElement('input'); radioLeaf.type = 'radio'; radioLeaf.name = 'ft-display-mode'; radioLeaf.value = 'leaf'; radioLeaf.checked = ft_state.display.mode === 'leaf';
            const radioLeafText = document.createElement('span'); radioLeafText.textContent = i18n.t('FT_SETTINGS_DISPLAY_MODE_LEAF');
            radioLeafLabel.appendChild(radioLeaf); radioLeafLabel.appendChild(radioLeafText);
            const radioFullLabel = document.createElement('label'); radioFullLabel.className = 'ft-modal-display-radio';
            const radioFull = document.createElement('input'); radioFull.type = 'radio'; radioFull.name = 'ft-display-mode'; radioFull.value = 'full'; radioFull.checked = ft_state.display.mode === 'full';
            const radioFullText = document.createElement('span'); radioFullText.textContent = i18n.t('FT_SETTINGS_DISPLAY_MODE_FULL');
            radioFullLabel.appendChild(radioFull); radioFullLabel.appendChild(radioFullText);
            modeRow.appendChild(modeLabel); modeRow.appendChild(radioLeafLabel); modeRow.appendChild(radioFullLabel);
            radioLeaf.addEventListener('change', () => { if (radioLeaf.checked) { ft_state.display.mode = 'leaf'; ft_saveState(); } });
            radioFull.addEventListener('change', () => { if (radioFull.checked) { ft_state.display.mode = 'full'; ft_saveState(); } });
            displaySection.appendChild(displayTitle); displaySection.appendChild(modeRow);
            const tagListEl = document.createElement('div'); tagListEl.className = 'ft-modal-tag-list';

            function clearDropClasses() {
                tagListEl.querySelectorAll('.ft-modal-tag-item').forEach(el => el.classList.remove('ft-modal-tag-item-drop-before', 'ft-modal-tag-item-drop-after', 'ft-modal-tag-item-drop-child'));
            }
            function deleteTagAndReparentChildren(tag) {
                ft_state.tags.forEach(child => { if (child.parentId === tag.id) child.parentId = tag.parentId || null; });
                ft_state.tags = ft_state.tags.filter(t => t.id !== tag.id);
                Object.keys(ft_state.tweetTags).forEach(tid => { if (ft_state.tweetTags[tid] === tag.id) delete ft_state.tweetTags[tid]; });
                ft_normalizeTagOrders(); ft_clampUncategorizedOrder(); ft_saveState();
            }
            function moveTagInSiblings(tag, direction) {
                const siblings = ft_state.tags.filter(t => (t.parentId || null) === (tag.parentId || null)).sort((a, b) => a.order - b.order);
                const idx = siblings.findIndex(t => t.id === tag.id);
                if (idx < 0 || idx + direction < 0 || idx + direction >= siblings.length) return;
                const other = siblings[idx + direction];
                [tag.order, other.order] = [other.order, tag.order];
                ft_normalizeTagOrders(); ft_saveState();
            }
            function moveTagAsChild(srcTag, targetTag) {
                if (!srcTag || !targetTag || ft_wouldCreateCycle(targetTag.id, srcTag.id)) return;
                srcTag.parentId = targetTag.id;
                const children = ft_state.tags.filter(t => (t.parentId || null) === targetTag.id);
                srcTag.order = (children.length ? Math.max(...children.map(t => t.order)) : -1) + 1;
                ft_normalizeTagOrders(); ft_saveState();
            }
            function moveTagBefore(srcTag, targetTag) {
                if (!srcTag || !targetTag || ft_wouldCreateCycle(targetTag.parentId, srcTag.id)) return;
                srcTag.parentId = targetTag.parentId; srcTag.order = targetTag.order - 0.5; ft_normalizeTagOrders(); ft_saveState();
            }
            function moveTagAfter(srcTag, targetTag) {
                if (!srcTag || !targetTag || ft_wouldCreateCycle(targetTag.parentId, srcTag.id)) return;
                srcTag.parentId = targetTag.parentId; srcTag.order = targetTag.order + 0.5; ft_normalizeTagOrders(); ft_saveState();
            }
            function moveTagToRootRelativeToUncat(srcTag, mode) {
                if (!srcTag) return;
                srcTag.parentId = null;
                let uncatPos = ft_state.uncategorized.order;
                const insertIndex = mode === 'before' ? uncatPos : uncatPos + 1;
                const rootTags = ft_state.tags.filter(t => !t.parentId && t.id !== srcTag.id).sort((a, b) => a.order - b.order);
                rootTags.splice(insertIndex, 0, srcTag);
                rootTags.forEach((t, i) => t.order = i);
                ft_normalizeTagOrders(); ft_clampUncategorizedOrder(); ft_saveState();
            }
            function getDropTargetInfoFromY(y) {
                const items = Array.from(tagListEl.querySelectorAll('.ft-modal-tag-item'));
                if (!items.length) return { row: null, mode: 'root-end' }; // 空ならルヌト远加

                const rects = items.map(row => row.getBoundingClientRect());

                // 䞀番䞋の芁玠の「底蟺」より䞋なら、無条件でルヌト末尟移動ずする
                const lastRect = rects[rects.length - 1];
                // 少しでも䞋(0px以䞊)にあればルヌト扱いにするCSSで䜙癜を䜜ったためこれでOK
                if (y > lastRect.bottom) {
                    return { row: null, mode: 'root-end' };
                }

                const boundaries = [rects[0].top];
                for (let i = 1; i < items.length; i++) boundaries.push((rects[i - 1].bottom + rects[i].top) / 2);
                boundaries.push(rects[items.length - 1].bottom);

                let idx = 0; let min = Infinity;
                for (let i = 0; i < boundaries.length; i++) {
                    const d = Math.abs(y - boundaries[i]);
                    if (d < min) { min = d; idx = i; }
                }

                if (idx === 0) return { row: items[0], mode: 'before' };
                if (idx === items.length) return { row: items[items.length - 1], mode: 'after' };
                return { row: items[idx], mode: 'before' };
            }
            function rebuildTagList() {
                tagListEl.innerHTML = '';
                const entries = ft_getTagListWithUncategorized();
                if (entries.length === 1 && entries[0].kind === 'uncat') {
                    const empty = document.createElement('div'); empty.style.opacity = '0.7'; empty.style.fontSize = '12px'; empty.textContent = i18n.t('FT_SETTINGS_EMPTY_TAG_LIST'); tagListEl.appendChild(empty);
                }
                const rootCount = ft_countRootTags(); ft_clampUncategorizedOrder();
                entries.forEach(entry => {
                    const row = document.createElement('div'); row.className = 'ft-modal-tag-item'; row.dataset.kind = entry.kind;
                    const mainCell = document.createElement('div'); mainCell.className = 'ft-modal-tag-main'; if (entry.depth > 0) mainCell.style.paddingLeft = `${entry.depth * 16}px`;
                    const nameInput = document.createElement('input'); nameInput.className = 'ft-modal-tag-name'; nameInput.type = 'text';
                    const colorInput = document.createElement('input'); colorInput.className = 'ft-modal-tag-color'; colorInput.type = 'color';
                    const orderDiv = document.createElement('div');
                    const upBtn = document.createElement('button'); upBtn.className = 'ft-modal-tag-order'; upBtn.textContent = i18n.t('FT_SETTINGS_UP'); upBtn.type='button';
                    const downBtn = document.createElement('button'); downBtn.className = 'ft-modal-tag-order'; downBtn.textContent = i18n.t('FT_SETTINGS_DOWN'); downBtn.type='button';
                    orderDiv.appendChild(upBtn); orderDiv.appendChild(downBtn);
                    const delBtn = document.createElement('button'); delBtn.className = 'ft-modal-tag-delete'; delBtn.textContent = i18n.t('FT_SETTINGS_DELETE_BUTTON'); delBtn.type='button';
                    mainCell.appendChild(colorInput); mainCell.appendChild(nameInput);
                    const dragHandle = document.createElement('div'); dragHandle.className = 'ft-modal-tag-drag-handle'; dragHandle.innerHTML = '≡';

                    if (entry.kind === 'uncat') {
                        row.draggable = false; dragHandle.draggable = false; dragHandle.title = i18n.t('FT_SETTINGS_UNCATEGORIZED_DELETE_TOOLTIP');
                        nameInput.value = i18n.t('FT_SETTINGS_UNCATEGORIZED_NAME'); nameInput.readOnly = true; nameInput.title = i18n.t('FT_SETTINGS_UNCATEGORIZED_NAME_TOOLTIP');
                        colorInput.value = ft_getUncategorizedColor();
                        colorInput.addEventListener('change', () => { ft_state.uncategorized.color = colorInput.value; ft_saveState(); });
                        delBtn.disabled = true;
                        upBtn.disabled = ft_state.uncategorized.order <= 0;
                        downBtn.disabled = ft_state.uncategorized.order >= rootCount;
                        upBtn.addEventListener('click', () => { ft_state.uncategorized.order--; ft_saveState(); rebuildTagList(); });
                        downBtn.addEventListener('click', () => { ft_state.uncategorized.order++; ft_saveState(); rebuildTagList(); });
                    } else {
                        const tag = entry.tag; row.dataset.tagId = tag.id;
                        dragHandle.draggable = true;
                        nameInput.value = tag.name; colorInput.value = tag.color || '#1d9bf0';
                        nameInput.addEventListener('change', () => { if(nameInput.value.trim()) { tag.name = nameInput.value.trim(); ft_saveState(); rebuildTagList(); } });
                        colorInput.addEventListener('change', () => { tag.color = colorInput.value; ft_saveState(); });
                        delBtn.addEventListener('click', () => { if(confirm(i18n.t('FT_CONFIRM_DELETE_TAG_MSG').replace('{tagName}', tag.name))) { deleteTagAndReparentChildren(tag); rebuildTagList(); } });
                        const siblings = ft_state.tags.filter(t => (t.parentId || null) === (tag.parentId || null)).sort((a, b) => a.order - b.order);
                        const idx = siblings.findIndex(t => t.id === tag.id);
                        upBtn.disabled = idx <= 0; downBtn.disabled = idx >= siblings.length - 1;
                        upBtn.addEventListener('click', () => { moveTagInSiblings(tag, -1); rebuildTagList(); });
                        downBtn.addEventListener('click', () => { moveTagInSiblings(tag, 1); rebuildTagList(); });
                        dragHandle.addEventListener('dragstart', (ev) => { ev.stopPropagation(); ft_dragSrcEntry = { kind: 'tag', tagId: tag.id }; row.classList.add('ft-modal-tag-item-dragging'); ev.dataTransfer.setData('text/plain', tag.id); ev.dataTransfer.effectAllowed='move'; });
                        dragHandle.addEventListener('dragend', (ev) => { ev.stopPropagation(); ft_dragSrcEntry = null; row.classList.remove('ft-modal-tag-item-dragging'); clearDropClasses(); });
                        row.addEventListener('dragover', (ev) => {
                            if (!ft_dragSrcEntry) return;
                            const rect = row.getBoundingClientRect(); const ratio = (ev.clientY - rect.top) / rect.height;
                            clearDropClasses();
                            if (ratio > 0.3 && ratio < 0.7) { ev.preventDefault(); row.classList.add('ft-modal-tag-item-drop-child'); }
                        });
                        row.addEventListener('drop', (ev) => {
                            if (!ft_dragSrcEntry) return;
                            const rect = row.getBoundingClientRect(); const ratio = (ev.clientY - rect.top) / rect.height;
                            if (ratio > 0.3 && ratio < 0.7) { ev.preventDefault(); ev.stopPropagation(); moveTagAsChild(ft_getTagById(ft_dragSrcEntry.tagId), tag); rebuildTagList(); }
                        });
                    }
                    row.appendChild(mainCell); row.appendChild(dragHandle); row.appendChild(orderDiv); row.appendChild(delBtn); tagListEl.appendChild(row);
                });
            }
            tagListEl.ondragover = (ev) => {
                if (!ft_dragSrcEntry) return;
                if (ev.defaultPrevented) return;

                ev.preventDefault();
                clearDropClasses();
                tagListEl.classList.remove('ft-drag-to-root');

                // クラスリセット: すべおの行からルヌト刀定クラスを䞀旊消す
                tagListEl.querySelectorAll('.ft-is-root-ref').forEach(el => el.classList.remove('ft-is-root-ref'));

                const info = getDropTargetInfoFromY(ev.clientY);

                // 1. 䞀番䞋の䜙癜ぞのドロップルヌト末尟
                if (info.mode === 'root-end') {
                    tagListEl.classList.add('ft-drag-to-root');
                }
                // 2. 行ぞのドロップ隙間 or 芪子化
                else if (info.row) {
                    // 自分自身ぞのドロップでない堎合
                    if (info.row.dataset.tagId !== ft_dragSrcEntry.tagId) {

                        const targetId = info.row.dataset.tagId;
                        const targetKind = info.row.dataset.kind;

                        // ▌▌▌ ルヌト階局かどうかの刀定 ▌▌▌
                        let isRoot = false;
                        if (targetKind === 'uncat') {
                            // 「未分類」は垞にルヌト
                            isRoot = true;
                        } else if (targetId) {
                            // タグの堎合、芪ID(parentId)が無ければルヌト
                            const tTag = ft_getTagById(targetId);
                            if (tTag && !tTag.parentId) {
                                isRoot = true;
                            }
                        }

                        // ルヌト階局なら専甚クラスを付䞎→ CSSで青線になる
                        if (isRoot) {
                            info.row.classList.add('ft-is-root-ref');
                        }

                        // 前埌(before/after) たたは 芪子(child) のクラスを付䞎
                        info.row.classList.add(
                            info.mode === 'before' ? 'ft-modal-tag-item-drop-before' : 'ft-modal-tag-item-drop-after'
                        );

                        // 芪子化行の䞭倮ドロップの刀定がある堎合は䞊曞き
                        const rect = info.row.getBoundingClientRect();
                        const ratio = (ev.clientY - rect.top) / rect.height;
                        if (ratio > 0.3 && ratio < 0.7) {
                            // 䞭倮ドロップは「入れ子」なので、線のクラスを消しお背景クラスを付ける
                            info.row.classList.remove('ft-modal-tag-item-drop-before', 'ft-modal-tag-item-drop-after');
                            info.row.classList.add('ft-modal-tag-item-drop-child');
                        }
                    }
                }
            };
            tagListEl.ondrop = (ev) => {
                if (!ft_dragSrcEntry) return;
                if (ev.defaultPrevented) return;

                ev.preventDefault();
                clearDropClasses();
                tagListEl.classList.remove('ft-drag-to-root'); // クラス削陀

                const info = getDropTargetInfoFromY(ev.clientY);
                const srcTag = ft_getTagById(ft_dragSrcEntry.tagId);
                if (!srcTag) return;

                // root-end なら「芪なし」にしお「䞀番䞋」ぞ
                if (info.mode === 'root-end') {
                    srcTag.parentId = null; // 芪を解陀

                    // ルヌト芁玠の䞭での最倧order + 1 を蚭定しお末尟ぞ
                    const rootTags = ft_state.tags.filter(t => !t.parentId);
                    const maxOrder = rootTags.length ? Math.max(...rootTags.map(t => t.order || 0)) : 0;
                    srcTag.order = maxOrder + 1;

                    ft_normalizeTagOrders();
                    ft_clampUncategorizedOrder();
                    ft_saveState();
                    rebuildTagList();
                    return;
                }

                // 既存の凊理行間ぞのドロップ
                if (info.row && info.row.dataset.kind === 'tag') {
                    const targetId = info.row.dataset.tagId;
                    // 自分自身ぞのドロップは無芖
                    if (targetId === srcTag.id) return;

                    const tTag = ft_getTagById(targetId);
                    if (info.mode === 'before') moveTagBefore(srcTag, tTag);
                    else moveTagAfter(srcTag, tTag);
                } else {
                    // 未分類(Uncategorized)ずの䜍眮関係凊理
                    moveTagToRootRelativeToUncat(srcTag, info.mode);
                }
                rebuildTagList();
            };
            rebuildTagList();
            const newTagSection = document.createElement('div'); newTagSection.className = 'ft-modal-new-tag';
            const newTagLabel = document.createElement('div'); newTagLabel.textContent = i18n.t('FT_DROPDOWN_NEW_TAG');
            const newTagRow = document.createElement('div'); newTagRow.className = 'ft-modal-new-tag-row';
            const newNameInput = document.createElement('input'); newNameInput.className = 'ft-modal-tag-name'; newNameInput.type = 'text'; newNameInput.placeholder = i18n.t('FT_DROPDOWN_NEW_TAG_PLACEHOLDER');
            const newColorInput = document.createElement('input'); newColorInput.className = 'ft-modal-tag-color'; newColorInput.type = 'color'; newColorInput.value = '#1d9bf0';
            const newAddBtn = document.createElement('button'); newAddBtn.className = 'ft-modal-button'; newAddBtn.textContent = i18n.t('FT_DROPDOWN_NEW_TAG_ADD'); newAddBtn.type='button';
            function doAddNew() {
                const name = newNameInput.value.trim();
                if (!name) return;
                ft_createNewTag(name, newColorInput.value, null); ft_saveState();
                newNameInput.value = ''; rebuildTagList();
            }
            newAddBtn.addEventListener('click', doAddNew);
            newNameInput.addEventListener('keydown', (ev) => { if (ev.key === 'Enter') { ev.preventDefault(); doAddNew(); } });
            newTagRow.appendChild(newColorInput); newTagRow.appendChild(newNameInput); newTagRow.appendChild(newAddBtn);
            newTagSection.appendChild(newTagLabel); newTagSection.appendChild(newTagRow);
            body.appendChild(displaySection); body.appendChild(tagListEl); body.appendChild(newTagSection);
            const footer = document.createElement('div'); footer.className = 'ft-modal-footer';
            const closeBtn = document.createElement('button'); closeBtn.className = 'ft-modal-button'; closeBtn.textContent = i18n.t('FT_SETTINGS_CLOSE'); closeBtn.type='button';
            closeBtn.addEventListener('click', ft_closeSettingsModal);
            footer.appendChild(closeBtn);
            modal.appendChild(header); modal.appendChild(body); modal.appendChild(footer);
            backdrop.appendChild(modal);
            backdrop.addEventListener('mousedown', (ev) => { if (ev.target === backdrop) ft_closeSettingsModal(); });
            ft_settingsModalBackdrop = backdrop;
            document.body.appendChild(backdrop);
        }

        // ------------- むベント委譲 & 堅牢初期化 (Optimized) ------------- //

        function ft_installGlobalListeners() {
            // Document level Delegation
            document.addEventListener('click', (ev) => {
                const target = ev.target;
                if (!(target instanceof Element)) return;

                // 1. Tag Chip Click
                const chipBtn = target.closest('.ft-tag-chip');
                if (chipBtn) {
                    ev.stopPropagation(); ev.preventDefault();
                    const tweetId = chipBtn.dataset.tweetId;
                    if (tweetId && ft_state.enabled) {
                        ft_openTagDropdown(chipBtn, tweetId);
                    }
                    return;
                }

                // 3. Close Dropdown on outside click
                if (ft_currentDropdown && !ft_currentDropdown.contains(target)) {
                    ft_closeTagDropdown();
                }

            }, true); // Use capture for better delegation reliability

            document.addEventListener('keydown', (ev) => {
                if (ev.key === 'Escape') { ft_closeTagDropdown(); ft_closeSettingsModal(); }
            });
        }

        function ft_startRobustPolling() {
            let count = 0;
            const maxChecks = 10;
            const intervalId = setInterval(() => {
                count++;
                processNewTweets(true);
                if (count >= maxChecks) clearInterval(intervalId);
            }, 500);
        }

        // ------------- ツむヌト凊理 (単䞀芁玠) ------------- //

        function ft_processTweetArticle(article) {
            const tweetId = article.dataset.ftTweetId || ft_extractTweetId(article);
            if (!tweetId) return;
            article.dataset.ftTweetId = tweetId;

            if (!ft_state.enabled) {
                 ft_removeTagChipFromArticle(article);
                 return;
            }

            // ネむティブブックマヌクや単なるタグ有無のチェックを削陀
            // 「お気に入り枈み (isFav)」の堎合のみタグチップを衚瀺する
            const isFav = (typeof isFavorited === 'function') && isFavorited(tweetId);

            if (isFav) {
                ft_attachTagChipToArticle(article, tweetId);
            } else {
                ft_removeTagChipFromArticle(article);
            }
        }

        // ------------- 初期化 ------------- //

        function ft_init() {
            if (ft_initialized) return;
            ft_initialized = true;
            ft_state = ft_loadState();
            ft_installGlobalListeners();
            processNewTweets(true);
            ft_startRobustPolling();
        }

        /* --- End Favorite Tags: Code Block --- */

        const LANG_OVERRIDE_KEY = 'advUILang_v1';
        // Settings で指定された UI 蚀語があれば、怜出結果より優先しお適甚
        try {
            const overrideLang = kv.get(LANG_OVERRIDE_KEY, '');
            if (overrideLang && i18n.translations[overrideLang]) {
                i18n.lang = overrideLang;
            }
        } catch (_) {}

        const trigger = document.createElement('button');
        const HISTORY_SORT_KEY = 'advHistorySort_v1';
        trigger.id = 'advanced-search-trigger';
        trigger.type = 'button';
        trigger.innerHTML = SEARCH_SVG;
        trigger.classList.add('adv-trigger-search');
        trigger.setAttribute('aria-label', i18n.t('tooltipTrigger'));
        trigger.setAttribute('aria-haspopup', 'dialog');
        trigger.setAttribute('aria-expanded', 'false');
        document.body.appendChild(trigger);

        const modalContainer = document.createElement('div');
        modalContainer.innerHTML = modalHTML;
        document.body.appendChild(modalContainer);
        i18n.apply(modalContainer);

        const modal = document.getElementById('advanced-search-modal');
        const form = document.getElementById('advanced-search-form');
        const closeButton = modal.querySelector('.adv-modal-close');
        const clearButton = document.getElementById('adv-clear-button');
        const applyButton = document.getElementById('adv-apply-button');
        const saveButton = document.getElementById('adv-save-button');
        const footerEl = modal.querySelector('.adv-modal-footer');
        const toastEl = document.getElementById('adv-toast');
        const secretBtn = document.getElementById('adv-secret-btn');
        const secretStateEl = document.getElementById('adv-secret-state');

        const settingsModal = document.getElementById('adv-settings-modal');
        const settingsLangSel = document.getElementById('adv-settings-lang');
        const settingsInitialTabSel = document.getElementById('adv-settings-initial-tab');
        const settingsFileInput = document.getElementById('adv-settings-file-input');
        const settingsOpenBtn = document.getElementById('adv-settings-button');
        const settingsCloseBtn = document.getElementById('adv-settings-close');
        const settingsCloseFooterBtn = document.getElementById('adv-settings-close-footer');
        const settingsExportBtn = document.getElementById('adv-settings-export');
        const settingsImportBtn = document.getElementById('adv-settings-import');
        const settingsResetBtn = document.getElementById('adv-settings-reset');

        const historyClearAllBtn = document.getElementById('adv-history-clear-all');
        historyClearAllBtn.textContent = i18n.t('historyClearAll');

        const accountScopeSel = document.getElementById('adv-account-scope');
        const locationScopeSel = document.getElementById('adv-location-scope');

        ['n','e','s','w','ne','nw','se','sw'].forEach(dir => {
            const h = document.createElement('div');
            h.className = `adv-resizer ${dir}`;
            h.dataset.dir = dir;
            modal.appendChild(h);
        });

        const EXC_NAME_KEY   = 'advExcludeHitName_v1';
        const EXC_HANDLE_KEY = 'advExcludeHitHandle_v1';
        const EXC_REPOSTS_KEY = 'advExcludeReposts_v1';
        const EXC_HASHTAGS_KEY = 'advExcludeTimelineHashtags_v1';
        const excNameEl   = document.getElementById('adv-exclude-hit-name');
        const excHandleEl = document.getElementById('adv-exclude-hit-handle');
        const excRepostsEl = document.getElementById('adv-filter-reposts-exclude');
        const excHashtagsEl = document.getElementById('adv-filter-hashtags-exclude');
        const loadExcludeFlags = () => ({
            name: kv.get(EXC_NAME_KEY, '1') === '1',
            handle: kv.get(EXC_HANDLE_KEY, '1') === '1',
            reposts: kv.get(EXC_REPOSTS_KEY, '0') === '1',
            hashtags: kv.get(EXC_HASHTAGS_KEY, '0') === '1',
        });
        const saveExcludeFlags = (v) => {
            kv.set(EXC_NAME_KEY, v.name ? '1':'0');
            kv.set(EXC_HANDLE_KEY, v.handle ? '1':'0');
            kv.set(EXC_REPOSTS_KEY, v.reposts ? '1':'0');
            kv.set(EXC_HASHTAGS_KEY, v.hashtags ? '1':'0');
        };
{
            const st = loadExcludeFlags();
            if (excNameEl) excNameEl.checked = st.name;
            if (excHandleEl) excHandleEl.checked = st.handle;
            if (excRepostsEl) excRepostsEl.checked = st.reposts;
            if (excHashtagsEl) excHashtagsEl.checked = st.hashtags;
        }
        [excNameEl, excHandleEl, excRepostsEl, excHashtagsEl].forEach(el=>{
            if (!el) return;
            el.addEventListener('change', ()=>{
                saveExcludeFlags({
                    name: excNameEl?.checked ?? false,
                    handle: excHandleEl?.checked ?? false,
                    reposts: excRepostsEl?.checked ?? false,
                    hashtags: excHashtagsEl?.checked ?? false,
                });
                rescanAllTweetsForFilter();
            });
        });

        themeManager.observeChanges(modal, trigger);

        // Accounts/Listsタブの背景をドロップタヌゲットにするためのヘルパヌ
        const setupBackgroundDrop = (panel, host, unassignFunction) => {
            const feedbackClass = 'adv-bg-drop-active';
            const SECT_MIME = 'adv/folder'; // フォルダ䞊び替えD&DのMIME

            // panel 内の .adv-zoom-root もむベントの察象に远加
            const zoomRoot = panel?.querySelector('.adv-zoom-root');
            const eventTargets = [panel, host, zoomRoot].filter(Boolean); // むベントをリッスンする察象

            // 砎線を衚瀺する察象は panel のみずする
            const feedbackTargets = [panel].filter(Boolean); // 砎線を衚瀺する察象

            const onDragEnter = (ev) => {
                // アむテムtext/plainであり、セクションadv/folderではない
                if (ev.dataTransfer.types && !ev.dataTransfer.types.includes(SECT_MIME) && ev.dataTransfer.types.includes('text/plain')) {
                    // タヌゲットが panel, host, zoomRoot のいずれか
                    if (eventTargets.includes(ev.target)) {
                        // 砎線は feedbackTargets に付ける (今回は panel のみ)
                        feedbackTargets.forEach(t => t.classList.add(feedbackClass));
                    }
                }
            };

            const onDragLeave = (ev) => {
                // タヌゲット自身から離れた時だけフィヌドバックを消す
                if (eventTargets.includes(ev.target)) {
                    // 砎線は feedbackTargets から消す
                    feedbackTargets.forEach(t => t.classList.remove(feedbackClass));
                }
            };

            const onDragOver = (ev) => {
                // カヌ゜ルが .adv-folder (フォルダヌ) の䞊にある堎合は、問答無甚で背景ハむラむトを消しお終わる
                if (ev.target.closest('.adv-folder')) {
                    feedbackTargets.forEach(t => t.classList.remove(feedbackClass));
                    return;
                }
                // dropむベントを発火させるために、dragoverでpreventDefaultが必芁
                // アむテムであり、タヌゲットが panel/host/zoomRoot 自身の堎合のみ蚱可
                if (eventTargets.includes(ev.target) && ev.dataTransfer.types && !ev.dataTransfer.types.includes(SECT_MIME) && ev.dataTransfer.types.includes('text/plain')) {
                    ev.preventDefault();
                    ev.stopPropagation();
                    /* ▌▌▌ 背景隙間にいるなら、フォルダヌのハむラむトは匷制的に消す ▌▌▌ */
                    document.querySelectorAll('.adv-folder[data-drop="1"]').forEach(el => delete el.dataset.drop);
                    // 砎線は feedbackTargets に付け続ける
                    feedbackTargets.forEach(t => t.classList.add(feedbackClass));
                } else {
                    // 子芁玠フォルダなどの䞊に来たら背景ハむラむトは消す
                    feedbackTargets.forEach(t => t.classList.remove(feedbackClass));
                    // 残っおいるフォルダヌ芋出しの砎線を確実に解陀
                    document.querySelectorAll('.adv-folder-header[data-drop="1"]').forEach(el => { delete el.dataset.drop; });
                }
            };

            const onDrop = (ev) => {
                feedbackTargets.forEach(t => t.classList.remove(feedbackClass)); // ドロップ時は垞にハむラむト解陀

                // 最終チェックアむテムであり、パネル/ホスト/zoomRoot 自身ぞのドロップ
                if (eventTargets.includes(ev.target) && ev.dataTransfer.types && !ev.dataTransfer.types.includes(SECT_MIME) && ev.dataTransfer.types.includes('text/plain')) {
                    ev.preventDefault();
                    ev.stopPropagation();

                    const draggedId = ev.dataTransfer.getData('text/plain');
                    if (draggedId) {
                        unassignFunction(draggedId); // (unassignAccount たたは unassignList を実行)
                    }
                }
            };

            // むベントは eventTargets に登録する
            eventTargets.forEach(target => {
                if (!target) return; // hostがただ存圚しない堎合など
                target.addEventListener('dragenter', onDragEnter);
                target.addEventListener('dragleave', onDragLeave);
                target.addEventListener('dragover', onDragOver);
                target.addEventListener('drop', onDrop);
            });
        };

        // ドラッグ終了時成功・キャンセル問わずに、匷制的にすべおのドロップハむラむトを解陀する
        document.addEventListener('dragend', () => {
            // 背景の砎線を消す
            document.querySelectorAll('.adv-bg-drop-active').forEach(el => {
                el.classList.remove('adv-bg-drop-active');
            });
            // フォルダヌヘッダヌ等のハむラむトも念のため消す
            document.querySelectorAll('[data-drop="1"]').forEach(el => {
                delete el.dataset.drop;
            });
            // ドラッグ䞭のクラスも念のため消す
            document.querySelectorAll('.adv-item.dragging').forEach(el => {
                el.classList.remove('dragging');
            });
            document.body.classList.remove('adv-dragging');
        });

        // --- generic unassign helper (de-duplicate) ---
        // Remove an item from all folders under FOLDERS_KEY,
        // then move the item to the top of the master list (Unassigned head).
        function unassignItemGeneric({ FOLDERS_KEY, loadItems, saveItems, itemId }) {
            // 1) remove from every folder
            const folders = loadFolders(FOLDERS_KEY, '');
            let changed = false;
            for (const f of folders) {
                const before = f.order.length;
                f.order = f.order.filter(id => id !== itemId);
                if (f.order.length !== before) { f.ts = Date.now(); changed = true; }
            }
            if (changed) saveFolders(FOLDERS_KEY, folders);

            // 2) bump the item to the head of the master list (Unassigned first)
            const all = loadItems();
            const hit = all.find(x => x.id === itemId);
            if (hit) {
                const next = [hit, ...all.filter(x => x.id !== itemId)];
                saveItems(next);
            }
        }

        // --- generic "move item to a folder" helper ---
        function moveItemToFolderGeneric({ FOLDERS_KEY, itemId, folderId }) {
            const fArr = loadFolders(FOLDERS_KEY, '');
            // remove from every folder
            for (const f of fArr) {
                const before = f.order.length;
                f.order = f.order.filter(id => id !== itemId);
                if (f.order.length !== before) f.ts = Date.now();
            }
            // add to head of the target folder
            const target = fArr.find(f => f.id === folderId);
            if (target) {
                target.order = [itemId, ...target.order.filter(id => id !== itemId)];
                target.ts = Date.now();
            }
            saveFolders(FOLDERS_KEY, fArr);
        }

        // === [ADD] 特化 move 関数トヌスト再描画たで含む ===
        function moveAccountToFolder(accountId, folderId) {
          moveItemToFolderGeneric({
            FOLDERS_KEY: ACCOUNTS_FOLDERS_KEY,
            itemId: accountId,
            folderId
          });
          showToast(i18n.t('toastReordered'));
          try { renderAccounts(); } catch(_) {}
        }

        function moveSavedToFolder(savedId, folderId) {
          moveItemToFolderGeneric({
            FOLDERS_KEY: SAVED_FOLDERS_KEY,
            itemId: savedId,
            folderId
          });
          showToast(i18n.t('toastReordered'));
          try { renderSaved(); } catch(_) {}
        }

        function moveListToFolder(listId, targetFolderId) {
          moveItemToFolderGeneric({
            FOLDERS_KEY: LISTS_FOLDERS_KEY,
            itemId: listId,
            folderId: targetFolderId
          });
          showToast(i18n.t('toastReordered'));
          try { renderLists(); } catch(_) {}
        }

        // 未分類化ロゞックを共通化 (Account甹)
        const unassignAccount = (draggedId) => {
            unassignItemGeneric({
                FOLDERS_KEY: ACCOUNTS_FOLDERS_KEY,
                loadItems: loadAccounts,
                saveItems: saveAccounts,
                itemId: draggedId,
            });
            showToast(i18n.t('toastReordered'));
            renderAccounts();
        };

        // 未分類化ロゞックを共通化 (List甹)
        const unassignList = (draggedId) => {
            unassignItemGeneric({
                FOLDERS_KEY: LISTS_FOLDERS_KEY,
                loadItems: loadLists,
                saveItems: saveLists,
                itemId: draggedId,
            });
            showToast(i18n.t('toastReordered'));
            renderLists();
        };

        // 未分類化ロゞックを共通化 (Saved甹)
        const unassignSaved = (draggedId) => {
            unassignItemGeneric({
                FOLDERS_KEY: SAVED_FOLDERS_KEY,
                loadItems: () => migrateList(loadJSON(SAVED_KEY, [])),
                saveItems: (arr) => saveJSON(SAVED_KEY, migrateList(arr)),
                itemId: draggedId,
            });
            showToast(i18n.t('toastReordered'));
            renderSaved();
        };

        /* ========= Favorites Logic ========= */
        const FAV_KEY = 'advFavorites_v1';
        const FAV_SORT_KEY = 'advFavoritesSort_v1';

        // 高速化: メモリキャッシュ倉数を定矩
        let _favCache = null; // 配列デヌタ (レンダリング甚)
        let _favSet = null;   // ID怜玢甚 Set (O(1)刀定甚)

        // デヌタ構造: { id: tweetId, text, user: {name, handle, avatar}, media: [], ts, ... }

        // キャッシュがあればそれを返す。なければロヌドしおキャッシュ構築。
        const loadFavorites = () => {
            if (_favCache) return _favCache;

            const raw = loadJSON(FAV_KEY, []);
            _favCache = raw;
            _favSet = new Set(raw.map(x => x.id));

            return _favCache;
        };

        // 保存時にキャッシュずSetも同時に曎新する
        const saveFavorites = (arr) => {
            _favCache = arr;
            _favSet = new Set(arr.map(x => x.id));
            saveJSON(FAV_KEY, arr);
        };

        const toggleFavorite = (tweetMeta) => {
            // loadFavoritesはキャッシュを返すので高速
            const list = loadFavorites();
            const idx = list.findIndex(x => x.id === tweetMeta.id);

            if (idx >= 0) {
                // --- 削陀 (Remove) ---
                // 配列を盎接倉曎せず、新しい配列を䜜っお敎合性を保぀のがベストだが
                // ここでは元のロゞックに合わせお砎壊的倉曎をしおから saveFavorites で党䜓曎新する
                list.splice(idx, 1);
                saveFavorites(list); // ここで _favSet も曎新される

                // 解陀時はタグデヌタも削陀する
                if (ft_state && ft_state.tweetTags && ft_state.tweetTags[tweetMeta.id]) {
                    delete ft_state.tweetTags[tweetMeta.id];
                    ft_saveState();
                }

                renderFavorites(); // (お気に入りタブが開いおいる堎合甚)
                showToast(i18n.t('toastUnfavorited'));
            } else {
                list.unshift({ ...tweetMeta, ts: Date.now() });
                saveFavorites(list); // ここで _favSet も曎新される
                renderFavorites();
                showToast(i18n.t('toastFavorited'));
            }

            // 最埌に党同期
            updateAllFavoriteButtons();          // ボタン曎新
            refreshTagChipsForTweet(tweetMeta.id); // タグチップ曎新

            return idx < 0; // 远加されたら true
        };

        // Setを䜿った超高速刀定 (JSON.parseが発生しない)
        const isFavorited = (tweetId) => {
            if (!_favSet) loadFavorites(); // 初回ロヌドがただなら実行
            return _favSet.has(tweetId);
        };

        const deleteFavorite = (id) => {
            // 1. お気に入りリストから削陀
            const list = loadFavorites().filter(x => x.id !== id);
            saveFavorites(list); // ここで _favSet も曎新される

            // 2. タグデヌタも削陀する (デヌタのクリヌンアップ)
            if (ft_state && ft_state.tweetTags && ft_state.tweetTags[id]) {
                delete ft_state.tweetTags[id];
                ft_saveState(); // 状態を保存
            }

            // 3. UI曎新 (リスト再描画 & トヌスト)
            renderFavorites();
            showToast(i18n.t('toastDeleted'));

            // 4. タむムラむン䞊の芋た目を同期
            updateAllFavoriteButtons();   // ボタンの色を曎新
            refreshTagChipsForTweet(id);  // タグチップを消去
        };

        // お気に入りリストのむベント委譲ハンドラ
        function setupFavoritesDelegation() {
            const listEl = document.getElementById('adv-favorites-list');
            // ただ芁玠がない、たたは既に登録枈みならスキップ
            if (!listEl || listEl._delegationAttached) return;
            listEl._delegationAttached = true;

            listEl.addEventListener('click', (e) => {
                const target = e.target;
                if (!target) return;

                // A. 削陀ボタン
                const deleteBtn = target.closest('[data-action="delete"]');
                if (deleteBtn) {
                    const row = deleteBtn.closest('.adv-item');
                    if (row && row.dataset.id) {
                        e.stopPropagation();
                        deleteFavorite(row.dataset.id);
                    }
                    return;
                }

                // B. Openボタン
                const openBtn = target.closest('[data-action="open"]');
                if (openBtn) {
                    const row = openBtn.closest('.adv-item');
                    if (row && row.dataset.id) {
                        e.stopPropagation();
                        // IDから最新デヌタを匕くクロヌゞャがないため
                        const item = loadFavorites().find(x => x.id === row.dataset.id);
                        if (item) {
                            const url = `/${item.user.handle}/status/${item.id}`;
                            spaNavigate(url, { ctrlMeta: e.ctrlKey || e.metaKey });
                            if (window.innerWidth <= 700) closeModal();
                        }
                    }
                    return;
                }

                // C. ナヌザヌリンク
                const userLink = target.closest('.adv-link-user');
                if (userLink) {
                    e.preventDefault();
                    e.stopPropagation();
                    const href = userLink.getAttribute('href');
                    if (href) {
                        spaNavigate(href, { ctrlMeta: e.ctrlKey || e.metaKey });
                        if (window.innerWidth <= 700) closeModal();
                    }
                    return;
                }

                // D. メディアサムネむル
                const mediaImg = target.closest('.adv-media-thumb');
                if (mediaImg) {
                    e.stopPropagation();
                    const row = mediaImg.closest('.adv-item');
                    if (!row) return;
                    // 最新デヌタの再取埗
                    const item = loadFavorites().find(x => x.id === row.dataset.id);
                    if (!item) return;

                    const type = mediaImg.dataset.type;
                    const index = mediaImg.dataset.index;
                    const isQuote = mediaImg.dataset.isQuote === '1';

                    // 匕甚でIDがない堎合(取埗䞍胜)は無芖
                    if (isQuote && item.quote && !item.quote.id) return;

                    let targetBaseUrl = `/${item.user.handle}/status/${item.id}`;
                    if (isQuote && item.quote && item.quote.id) {
                        targetBaseUrl = `/${item.quote.user.handle}/status/${item.quote.id}`;
                    }

                    let targetPath = targetBaseUrl;
                    if (type === 'image') {
                        targetPath = `${targetBaseUrl}/photo/${index}`;
                    }

                    spaNavigate(targetPath, { ctrlMeta: e.ctrlKey || e.metaKey });
                    if (window.innerWidth <= 700) closeModal();
                    return;
                }

                // E. 本文䞭のリンク (.adv-content-link)
                const contentLink = target.closest('.adv-content-link');
                if (contentLink) {
                     e.stopPropagation();
                     // target="_blank" ならブラりザデフォルト動䜜ぞ
                     return;
                }
            });
        }

        // 行レンダリング
        // addEventListener を党削陀し、玔粋なDOM生成のみにする
        function renderFavoriteRow(item) {
            const row = document.createElement('div');
            row.className = 'adv-item';
            // お気に入りタブだけはボタンが絶察配眮なので、右䜙癜を個別に確保する
            row.style.paddingRight = '60px';
            row.dataset.id = item.id;

            const text = item.text || '';
            const bodyHtml = safeLinkify(text);
            const displayTime = item.postedAt ? fmtTime(item.postedAt) : fmtTime(item.ts);

            // --- メディアHTML生成 ---
            const buildMediaHtml = (mediaList, isQuote = false) => {
                if (!mediaList || mediaList.length === 0) return '';
                let html = '<div class="adv-item-media-row">';
                mediaList.forEach((m, i) => {
                    const mediaType = m.type || 'image';
                    const isVideo = mediaType === 'video';
                    const playIcon = isVideo
                        ? `<div class="adv-media-play-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5v14l11-7z"></path></svg></div>`
                        : '';
                    // 匕甚でIDがない堎合、クリックできない芖芚衚珟(cursor:default)をHTML生成時点で適甚
                    let styleAttr = '';
                    if (isQuote && item.quote && !item.quote.id) {
                         styleAttr = 'style="cursor:default"';
                    }

                    html += `<div class="adv-media-wrap">
                                <img src="${escapeAttr(m.url)}"
                                     data-type="${mediaType}"
                                     data-index="${i + 1}"
                                     data-is-quote="${isQuote ? '1' : '0'}"
                                     class="adv-media-thumb" loading="lazy" alt="Media" title="Open Media"
                                     ${styleAttr}>
                                ${playIcon}
                             </div>`;
                });
                html += '</div>';
                return html;
            };
            const mainMediaHtml = buildMediaHtml(item.media, false);

            // --- 匕甚HTML ---
            let quoteHtml = '';
            if (item.quote) {
                const q = item.quote;
                const qUserUrl = `/${escapeAttr(q.user.handle)}`;
                const qMediaHtml = buildMediaHtml(q.media, true);
                const qBodyHtml = safeLinkify(q.text);
                quoteHtml = `
                    <div class="adv-quote-box">
                        <div class="adv-quote-header">
                            ${q.user.avatar ? `<a class="adv-link adv-link-user" href="${qUserUrl}"><img src="${escapeAttr(q.user.avatar)}" class="adv-quote-avatar"></a>` : ''}
                            <a class="adv-link adv-link-user" href="${qUserUrl}" title="Quote User">
                                <span class="adv-quote-name">${escapeHTML(q.user.name)}</span>
                                <span class="adv-quote-handle">@${escapeHTML(q.user.handle)}</span>
                            </a>
                        </div>
                        <div class="adv-quote-text">${qBodyHtml}</div>
                        ${qMediaHtml}
                    </div>
                `;
            }

            const userUrl = `/${escapeAttr(item.user.handle)}`;

            row.innerHTML = `
                ${item.user.avatar
                    ? `<a class="adv-item-avatar-link adv-link adv-link-user" href="${userUrl}">
                         <img class="adv-item-avatar" src="${escapeAttr(item.user.avatar)}">
                       </a>`
                    : `<a class="adv-item-avatar-link adv-link adv-link-user" href="${userUrl}">
                         <div class="adv-item-avatar"></div>
                       </a>`
                }

                <div class="adv-item-main">
                    <div class="adv-item-title">
                        <a class="adv-link adv-link-user" href="${userUrl}" title="Open Profile">${escapeHTML(item.user.name)} <span style="font-weight:normal;color:var(--modal-text-secondary)">@${escapeHTML(item.user.handle)}</span></a>
                        <span class="adv-fav-tag-container"></span>
                    </div>
                    <div class="adv-item-body-text">${bodyHtml}</div>
                    ${mainMediaHtml}
                    ${quoteHtml}
                    <div class="adv-item-sub">
                        <span>${displayTime}</span>
                    </div>
                </div>

                <button class="adv-chip primary adv-fav-btn-pos adv-fav-btn-top" data-action="open">${i18n.t('buttonOpen')}</button>
                <button class="adv-chip danger adv-fav-btn-pos adv-fav-btn-bottom" data-action="delete">${i18n.t('delete')}</button>
            `;

            // タグチップの生成ず挿入
            const tagContainer = row.querySelector('.adv-fav-tag-container');
            if (tagContainer && typeof ft_buildTagChip === 'function') {
                const chip = ft_buildTagChip(item.id);
                // 泚蚘: ここは ft_installGlobalListeners で委譲されおいるため、個別の addEventListener は䞍芁です
                // もし ft_buildTagChip 内でむベントを付けおいる堎合はそのたた機胜したす
                tagContainer.appendChild(chip);
            }

            return row;
        }

        // お気に入りタブ専甚の珟圚の絞り蟌み状態メモリ保持
        let favFilterTagId = 'ALL'; // 'ALL', 'UNCAT', or tagId
        let favSearchQuery = '';

        function renderFavorites() {
            const listEl = document.getElementById('adv-favorites-list');
            const emptyEl = document.getElementById('adv-favorites-empty');
            if (!listEl) return;

            // 1. ツヌルバヌの生成ただ無ければ
            if (!listEl.previousElementSibling?.classList?.contains('adv-folder-toolbar')) {
                const bar = document.createElement('div');
                bar.className = 'adv-folder-toolbar';
                // タグ絞り蟌みボタン、゜ヌト遞択、怜玢ボックス
                bar.innerHTML = `
                    <div style="display:flex; gap:6px; align-items:center; flex:0 0 auto;">
                        <button id="adv-favorites-tag-filter-btn" class="ft-filter-button" type="button">
                            <span class="ft-filter-button-label"></span>
                            <span class="ft-filter-button-caret">â–Ÿ</span>
                        </button>
                        <select id="adv-favorites-sort" class="adv-select" style="max-width:140px; font-size:12px;">
                            <option value="saved_newest" data-i18n="sortSavedNewest"></option>
                            <option value="saved_oldest" data-i18n="sortSavedOldest"></option>
                            <option value="posted_newest" data-i18n="sortPostedNewest"></option>
                            <option value="posted_oldest" data-i18n="sortPostedOldest"></option>
                        </select>
                    </div>
                    <input id="adv-favorites-search" class="adv-input" type="text" placeholder="${i18n.t('placeholderSearchSaved')}" style="flex:1; min-width:80px;">
                `;

                // 翻蚳適甚動的生成のためここで適甚
                bar.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = i18n.t(el.dataset.i18n); });

                listEl.parentElement.insertBefore(bar, listEl);

                // むベントリスナヌ登録
                const btn = bar.querySelector('#adv-favorites-tag-filter-btn');
                const sortSel = bar.querySelector('#adv-favorites-sort');
                const inp = bar.querySelector('#adv-favorites-search');

                // A. タグフィルタ
                btn.addEventListener('click', (ev) => {
                    ev.stopPropagation();
                    ev.preventDefault();
                    ft_openFilterDropdown(btn, favFilterTagId, (val) => {
                        favFilterTagId = val;
                        renderFavorites();
                    });
                });

                // B. ゜ヌト倉曎
                sortSel.value = kv.get(FAV_SORT_KEY, 'saved_newest');
                sortSel.addEventListener('change', () => {
                    kv.set(FAV_SORT_KEY, sortSel.value);
                    renderFavorites();
                });

                // C. 怜玢
                inp.addEventListener('input', debounce(() => {
                    favSearchQuery = inp.value;
                    renderFavorites();
                }, 200));
            }

            // 2. ツヌルバヌの状態曎新ラベル蚭定など
            const btn = document.getElementById('adv-favorites-tag-filter-btn');
            const labelSpan = btn ? btn.querySelector('.ft-filter-button-label') : null;
            const inp = document.getElementById('adv-favorites-search');
            const sortSel = document.getElementById('adv-favorites-sort');

            if (inp) inp.placeholder = i18n.t('placeholderSearchSaved');
            if (labelSpan) {
                let labelText = i18n.t('FT_FILTER_ALL');
                if (favFilterTagId === FT_FILTER_UNCATEGORIZED) {
                    labelText = i18n.t('FT_UNCATEGORIZED');
                } else if (favFilterTagId !== 'ALL') {
                    const tag = ft_getTagById(favFilterTagId);
                    if (tag) {
                        labelText = ft_getTagDisplayLabelFromTag(tag) || tag.name;
                    } else {
                        favFilterTagId = 'ALL';
                    }
                }
                labelSpan.textContent = labelText;
            }
            if (inp && inp.value !== favSearchQuery) inp.value = favSearchQuery;

            // ゜ヌト蚭定の読み蟌みUIず同期
            const currentSort = kv.get(FAV_SORT_KEY, 'saved_newest');
            if (sortSel && sortSel.value !== currentSort) sortSel.value = currentSort;

            // 3. デヌタのロヌドずフィルタリング
            const allItems = loadFavorites(); // { id, text, user, postedAt, ts, ... }

            let filtered = allItems.filter(item => {
                // A. テキスト怜玢
                const q = favSearchQuery.trim().toLowerCase(); // 怜玢時に初めお正芏化する
                if (q) {
                    const targetText = (item.text + ' ' + item.user.name + ' ' + item.user.handle).toLowerCase();
                    if (!targetText.includes(q)) return false;
                }
                // B. タグフィルタ
                if (favFilterTagId === 'ALL') return true;

                // ft_state および ft_state.tweetTags の存圚確認を行う
                const itemTagId = (ft_state && ft_state.tweetTags) ? ft_state.tweetTags[item.id] : null;

                if (favFilterTagId === FT_FILTER_UNCATEGORIZED) return !itemTagId;
                return itemTagId ? ft_isTagInSubtree(itemTagId, favFilterTagId) : false;
            });

            // 4. ゜ヌト適甚
            // ts: 远加日時, postedAt: 投皿日時
            // postedAt が無い叀いデヌタは ts をフォヌルバックずしお䜿う
            filtered.sort((a, b) => {
                const tsA = a.ts || 0;
                const tsB = b.ts || 0;
                const postedA = a.postedAt || tsA; // fallback
                const postedB = b.postedAt || tsB; // fallback

                switch (currentSort) {
                    case 'saved_oldest':  return tsA - tsB;
                    case 'posted_newest': return postedB - postedA;
                    case 'posted_oldest': return postedA - postedB;
                    case 'saved_newest':
                    default:              return tsB - tsA;
                }
            });

            // 5. リスト描画
            listEl.innerHTML = '';

            // 党デヌタ(allItems)が空の時だけメッセヌゞを出す。
            // 怜玢やフィルタでヒットしなかっただけなら、メッセヌゞは出さずに空欄にする。
            if (allItems.length === 0) {
                emptyEl.textContent = i18n.t('emptyFavorites');
                emptyEl.style.display = 'block';
            } else {
                emptyEl.style.display = 'none';
                filtered.forEach(item => {
                    const row = renderFavoriteRow(item);
                    listEl.appendChild(row);
                });
            }
        }

        /* タブごず保存に察応 */
        const ZOOM_KEYS = {
          search:  'advZoom_tab_search_v1',
          history: 'advZoom_tab_history_v1',
          saved:   'advZoom_tab_saved_v1',
          favorites: 'advZoom_tab_favorites_v1',
          lists:   'advZoom_tab_lists_v1',
          accounts:'advZoom_tab_accounts_v1',
          mute:    'advZoom_tab_mute_v1',
        };
        const ZOOM_MIN = 0.5, ZOOM_MAX = 2.0, ZOOM_STEP = 0.1;

        /* 各タブの珟圚倀メモリキャッシュ */
        const zoomByTab = {
          search:  1.0,
          history: 1.0,
          saved:   1.0,
          lists:   1.0,
          accounts:1.0,
          mute:    1.0,
        };

        const getActiveTabName = () => {
          const btn = document.querySelector('.adv-tab-btn.active');
          return btn?.dataset?.tab || 'search';
        };
        const getActiveZoomRoot = () =>
          document.querySelector('.adv-tab-content.active .adv-zoom-root') ||
          document.getElementById('adv-zoom-root');

        const clampZoom = z => Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, Math.round(z*100)/100));

        const loadZoomFor = (tab) => {
          try {
            const k = ZOOM_KEYS[tab] || ZOOM_KEYS.search;
            // デフォルト倀を '1' から分岐させる
            const defaultZoom = (tab === 'search') ? '0.87' : '1'; // 怜玢タブのみ 0.87 に
            const v = parseFloat(kv.get(k, defaultZoom)); // '1' だった郚分を defaultZoom に倉曎
            if (!Number.isNaN(v)) zoomByTab[tab] = clampZoom(v);
          } catch {}
        };
        const saveZoomFor = (tab) => {
          try {
            const k = ZOOM_KEYS[tab] || ZOOM_KEYS.search;
            kv.set(k, String(zoomByTab[tab]));
          } catch {}
        };

        /* 初期ロヌド党タブ */
        Object.keys(zoomByTab).forEach(loadZoomFor);

        const applyZoom = () => {
          const tab = getActiveTabName();
          const el = getActiveZoomRoot();
          if (!el) return;
          const z = zoomByTab[tab] ?? 1.0;

          el.style.zoom = '';
          el.style.transform = '';
          el.style.width = '';

          if ('zoom' in el.style) {
            el.style.zoom = z;
          } else {
            el.style.transform = `scale(${z})`;
            el.style.width = `${(100 / z).toFixed(3)}%`;
          }
        };

        const setZoomActiveTab = (z) => {
          const tab = getActiveTabName();
          zoomByTab[tab] = clampZoom(z);
          applyZoom();
          saveZoomFor(tab);
        };

        /* タブ芋出しは拡倧しない.adv-zoom-rootの内偎だけ反応 */
        const onWheelZoom = (e) => {
          const isAccel = e.ctrlKey || e.metaKey;
          if (!isAccel) return;
          if (!e.target.closest('.adv-zoom-root')) return; // タブバヌ等は陀倖
          e.preventDefault();
          const tab = getActiveTabName();
          const cur = zoomByTab[tab] ?? 1.0;
          const factor = e.deltaY > 0 ? (1 - ZOOM_STEP) : (1 + ZOOM_STEP);
          setZoomActiveTab(cur * factor);
        };
        const onKeyZoom = (e) => {
          const accel = (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey;
          if (!accel) return;
          if (!e.target.closest('.adv-zoom-root')) return; // タブバヌ等は陀倖
          const k = e.key;
          const tab = getActiveTabName();
          const cur = zoomByTab[tab] ?? 1.0;
          if (k === '+' || k === '=') { e.preventDefault(); setZoomActiveTab(cur + ZOOM_STEP); }
          else if (k === '-' || k === '_') { e.preventDefault(); setZoomActiveTab(cur - ZOOM_STEP); }
          else if (k === '0') { e.preventDefault(); setZoomActiveTab(1.0); }
        };

        /* 初回適甚衚瀺時に再適甚 */
        requestAnimationFrame(applyZoom);
        modal.addEventListener('wheel', onWheelZoom, { passive:false });
        modal.addEventListener('keydown', onKeyZoom);
        const modalDisplayObserver = new MutationObserver(() => {
          if (modal.style.display === 'flex') applyZoom();
        });
        modalDisplayObserver.observe(modal, { attributes:true, attributeFilter:['style'] });

        /* タブ切替時にもズヌム再適甚 */

        const searchInputSelectors = [
            'div[data-testid="primaryColumn"] input[data-testid="SearchBox_Search_Input"]', // 怜玢ペヌゞ
            'div[data-testid="sidebarColumn"] input[data-testid="SearchBox_Search_Input"]', // サむドバヌ
            'input[aria-label="Search query"]', // 暙準英語
            'input[aria-label="怜玢ク゚リ"]' // 暙準日本語
        ];

        // â–Œ 関数名を getActiveSearchInputs (耇数圢) に倉曎
        const getActiveSearchInputs = () => {
            const inputs = new Set(); // 重耇排陀

            // 1. 暙準の怜玢窓を探す
            for (const selector of searchInputSelectors) {
                const input = document.querySelector(selector);
                if (input && input.offsetParent !== null) {
                    inputs.add(input);
                }
            }
            // フォヌルバックdata-testid のみ
            document.querySelectorAll('input[data-testid="SearchBox_Search_Input"]').forEach(input => {
                if (input && input.offsetParent !== null) {
                    inputs.add(input);
                }
            });

            return Array.from(inputs); // Set を配列にしお返す
        };

        // React controlled input を確実に同期させる共通関数
        const syncControlledInput = (el, nextVal) => {
          try {
            const proto = Object.getPrototypeOf(el) || HTMLInputElement.prototype;
            const desc = Object.getOwnPropertyDescriptor(proto, 'value');
            if (desc && desc.set) {
              desc.set.call(el, nextVal); // React の setter を叩く
            } else {
              el.value = nextVal;
            }
            el.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: true }));
          } catch {
            try { el.value = nextVal; el.dispatchEvent(new Event('input', { bubbles: true })); } catch {}
          }
        };

        const MODAL_STATE_KEY   = 'advSearchModalState_v3.2';
        const TRIGGER_STATE_KEY = 'advSearchTriggerState_v1.0';
        const INITIAL_TAB_KEY   = 'advInitialTab_v1';
        const HISTORY_KEY = 'advSearchHistory_v2';
        const SAVED_KEY   = 'advSearchSaved_v2';
        const SECRET_KEY  = 'advSearchSecretMode_v1';

        const MUTE_KEY = 'advMutedWords_v1';
        const NATIVE_SEARCH_WIDTH_KEY = 'advNativeSearchWidth_v1';
        const migrateMuted = (list) =>
          Array.isArray(list)
            ? list
                .map(it => ({
                  id: it.id || uid(),
                  word: (it.word||'').trim(),
                  cs: !!it.cs,
                  wb: !!it.wb, // wb (Word Boundary) を維持
                  enabled: it.enabled !== false,
                  ts: it.ts || Date.now()
                }))
                .filter(it => it.word)
            : [];
        const loadMuted = () => migrateMuted(loadJSON(MUTE_KEY, []));
        const saveMuted = (arr) => saveJSON(MUTE_KEY, migrateMuted(arr));

        // 匕数に wb を远加
        const addMuted = (word, cs=false, wb=false) => {
          const w = (word||'').trim();
          if (!w) return;
          const list = loadMuted();
          // 重耇チェックに wb も含める
          if (list.some(it => it.word === w && !!it.cs === !!cs && !!it.wb === !!wb)) return;
          list.unshift({ id: uid(), word: w, cs: !!cs, wb: !!wb, enabled: true, ts: Date.now() });
          saveMuted(list);
          renderMuted();
          rescanAllTweetsForFilter();
        };

        const deleteMuted = (id) => {
          const list = loadMuted().filter(it => it.id !== id);
          saveMuted(list);
          renderMuted();
          rescanAllTweetsForFilter();
        };

        const toggleMutedCS = (id) => {
          const list = loadMuted().map(it => it.id === id ? { ...it, cs: !it.cs, ts: Date.now() } : it);
          saveMuted(list);
          renderMuted();
          rescanAllTweetsForFilter();
        };

        // 単語単䜍の䞀臎切り替え
        const toggleMutedWB = (id) => {
          const list = loadMuted().map(it => it.id === id ? { ...it, wb: !it.wb, ts: Date.now() } : it);
          saveMuted(list);
          renderMuted();
          rescanAllTweetsForFilter();
        };

        const toggleMutedEnabled = (id) => {
          const list = loadMuted().map(it => it.id === id ? { ...it, enabled: !it.enabled, ts: Date.now() } : it);
          saveMuted(list);
          renderMuted();
          rescanAllTweetsForFilter();
        };

        // 怜玢窓リサむザヌのセットアップ関数
        const setupNativeSearchResizer = () => {
            // サむドバヌおよびメむンカラムの怜玢フォヌムを察象にする
            const forms = document.querySelectorAll('div[data-testid="sidebarColumn"] form[role="search"], div[data-testid="primaryColumn"] form[role="search"]');

            // 保存された幅を取埗
            const savedWidth = kv.get(NATIVE_SEARCH_WIDTH_KEY, null);

            forms.forEach(form => {
                // 既に適甚枈みならスキップ
                if (form.querySelector('.adv-native-search-resizer')) {
                    // ただし幅が未適甚の堎合は再適甚DOM曞き換え察策
                    if (savedWidth && form.style.width !== savedWidth) {
                        form.style.width = savedWidth;
                    }
                    return;
                }

                // 幅の初期適甚
                if (savedWidth) {
                    form.style.width = savedWidth;
                }

                // リサむズハンドルを䜜成
                const resizer = document.createElement('div');
                resizer.className = 'adv-native-search-resizer';
                resizer.title = 'Drag to resize search box';
                form.appendChild(resizer);

                // ドラッグ凊理
                let isResizing = false;
                let startX = 0;
                let startW = 0;

                const onPointerDown = (e) => {
                    if (e.button !== 0) return; // 巊クリックのみ
                    e.preventDefault();
                    e.stopPropagation();

                    isResizing = true;
                    startX = e.clientX;
                    startW = form.getBoundingClientRect().width;

                    document.body.classList.add('adv-dragging');
                    try { resizer.setPointerCapture(e.pointerId); } catch (_) {}
                };

                const onPointerMove = (e) => {
                    if (!isResizing) return;
                    e.preventDefault();

                    // 幅の蚈算
                    const dx = e.clientX - startX;
                    const newW = Math.max(200, startW + dx); // 最小幅200px

                    form.style.width = `${newW}px`;
                };

                const onPointerUp = (e) => {
                    if (!isResizing) return;
                    isResizing = false;
                    document.body.classList.remove('adv-dragging');
                    try { resizer.releasePointerCapture(e.pointerId); } catch (_) {}

                    // 保存
                    kv.set(NATIVE_SEARCH_WIDTH_KEY, form.style.width);
                };

                resizer.addEventListener('pointerdown', onPointerDown);
                window.addEventListener('pointermove', onPointerMove);
                window.addEventListener('pointerup', onPointerUp);
                window.addEventListener('pointercancel', onPointerUp);
            });
        };

        const SETTINGS_EXPORT_VERSION = 2;
        function buildSettingsExportJSON() {
          // タブごずのズヌム
          const zoom = {};
          try {
            for (const [tab, key] of Object.entries(ZOOM_KEYS)) {
              zoom[tab] = kv.get(key, '1');
            }
          } catch (_) {}

          const safeParse = (key, def) => {
            try { return JSON.parse(kv.get(key, JSON.stringify(def))); } catch (_) { return def; }
          };

          const data = {
            // アプリ識別子
            appName: 'AdvancedSearchForX',

            v: SETTINGS_EXPORT_VERSION,

            // 蚀語・陀倖蚭定・ミュヌト
            lang: kv.get(LANG_OVERRIDE_KEY, ''),
            initialTab: kv.get(INITIAL_TAB_KEY, 'last'),
            excludeFlags: loadExcludeFlags(),
            muteMaster: loadMuteMaster(),
            muteMode: loadMuteMode(),
            muted: loadMuted(),

            // 怜玢履歎・保存枈み怜玢
            history: loadJSON(HISTORY_KEY, []),
            saved: loadJSON(SAVED_KEY, []),
            favorites: loadJSON(FAV_KEY, []),

            // シヌクレットモヌド・履歎゜ヌト
            secret: kv.get(SECRET_KEY, '0') === '1',
            historySort: kv.get(HISTORY_SORT_KEY, 'newest'),

            // 怜玢窓の幅
            nativeSearchWidth: kv.get(NATIVE_SEARCH_WIDTH_KEY, null),

            // タブ状態
            tabs: {
              last: kv.get(LAST_TAB_KEY, 'search'),
              order: loadJSON(TABS_ORDER_KEY, []),
              visibility: loadTabsVisibility(),
            },

            // モヌダルトリガヌ䜍眮・サむズ
            modalState: safeParse(MODAL_STATE_KEY, null),
            triggerState: safeParse(TRIGGER_STATE_KEY, null),

            // ズヌム
            zoom,

            // アカりント・リスト・各フォルダ
            accounts: (typeof loadAccounts === 'function') ? loadAccounts() : [],
            lists: (typeof loadLists === 'function') ? loadLists() : [],
            folders: {
              accounts: (typeof loadFolders === 'function' && typeof ACCOUNTS_FOLDERS_KEY !== 'undefined')
                ? loadFolders(ACCOUNTS_FOLDERS_KEY, '')
                : [],
              lists: (typeof loadFolders === 'function' && typeof LISTS_FOLDERS_KEY !== 'undefined')
                ? loadFolders(LISTS_FOLDERS_KEY, '')
                : [],
              saved: (typeof loadFolders === 'function' && typeof SAVED_FOLDERS_KEY !== 'undefined')
                ? loadFolders(SAVED_FOLDERS_KEY, i18n.t('defaultSavedFolders'))
                : [],
            },

            // Unassigned の挿入䜍眮
            unassignedIndex: {
              saved: parseInt(kv.get('advSavedUnassignedIndex_v1', '0'), 10) || 0,
              accounts: parseInt(kv.get('advAccountsUnassignedIndex_v1', '0'), 10) || 0,
              lists: parseInt(kv.get('advListsUnassignedIndex_v1', '0'), 10) || 0,
            },
            /* --- Favorite Tags Data --- */
            favoriteTags: (typeof ft_loadState === 'function') ? ft_loadState() : ft_createDefaultState(),
          };

          return JSON.stringify(data, null, 2);
        }

        function applySettingsImportJSON(text) {
            let data;
            try {
                data = JSON.parse(text);
            } catch (_) {
                alert(i18n.t('alertInvalidJSON'));
                return false;
            }
            if (!data || typeof data !== 'object') {
                alert(i18n.t('alertInvalidData'));
                return false;
            }

            // バリデヌションロゞック
            // 1. アプリ識別子 (appName) があるかチェック
            const hasSignature = (data.appName === 'AdvancedSearchForX');

            // 2. 識別子がない堎合、このアプリ特有の構造vプロパティ + 䞻芁な配列のいずれかを持っおいるかチェック埌方互換性救枈
            const hasValidStructure = (
                typeof data.v === 'number' &&
                (Array.isArray(data.history) || Array.isArray(data.saved) || Array.isArray(data.favorites) || typeof data.tabs === 'object')
            );

            if (!hasSignature && !hasValidStructure) {
                alert(i18n.t('alertInvalidApp'));
                return false;
            }
            // バリデヌション終了

            // --- 基本蚭定v1/v2 共通 ---
            if (data.lang !== undefined) {
                try { kv.set(LANG_OVERRIDE_KEY, data.lang || ''); } catch (_) {}
            }

            if (data.initialTab !== undefined) {
                try { kv.set(INITIAL_TAB_KEY, data.initialTab || 'last'); } catch (_) {}
            }

            if (data.excludeFlags) {
                saveExcludeFlags({
                    name: !!data.excludeFlags.name,
                    handle: !!data.excludeFlags.handle,
                    reposts: !!data.excludeFlags.reposts,
                    hashtags: !!data.excludeFlags.hashtags,
                });
            }

            if (Array.isArray(data.muted)) {
                saveMuted(data.muted);
            }

            if (typeof data.muteMaster === 'boolean') {
                saveMuteMaster(data.muteMaster);
            }

            // ミュヌトモヌドの読み蟌みず保存
            if (data.muteMode && (data.muteMode === 'hidden' || data.muteMode === 'collapsed')) {
                saveMuteMode(data.muteMode);
            }

            // --- v2 以降で远加された保存デヌタ ---
            if (Array.isArray(data.history)) {
                saveJSON(HISTORY_KEY, data.history);
            }
            if (Array.isArray(data.saved)) {
                saveJSON(SAVED_KEY, data.saved);
            }

            // saveFavorites を経由させおキャッシュ(_favSet)も曎新する
            if (Array.isArray(data.favorites)) {
                saveFavorites(data.favorites);
            }

            if (typeof data.secret === 'boolean') {
                try { kv.set(SECRET_KEY, data.secret ? '1' : '0'); } catch (_) {}
            }
            if (data.historySort) {
                try { kv.set(HISTORY_SORT_KEY, data.historySort); } catch (_) {}
            }
            // 怜玢窓の幅埩元
            if (data.nativeSearchWidth !== undefined) {
                try {
                    if (data.nativeSearchWidth) kv.set(NATIVE_SEARCH_WIDTH_KEY, data.nativeSearchWidth);
                    else kv.del(NATIVE_SEARCH_WIDTH_KEY);
                } catch (_) {}
            }
            if (data.tabs && typeof data.tabs === 'object') {
                if (data.tabs.last) {
                    try { kv.set(LAST_TAB_KEY, data.tabs.last); } catch (_) {}
                }
                if (Array.isArray(data.tabs.order)) {
                    saveJSON(TABS_ORDER_KEY, data.tabs.order);
                }
                if (data.tabs.visibility && typeof data.tabs.visibility === 'object') {
                    saveTabsVisibility(data.tabs.visibility);
                }
            }
            if (data.modalState) {
                try { kv.set(MODAL_STATE_KEY, JSON.stringify(data.modalState)); } catch (_) {}
            }
            if (data.triggerState) {
                try { kv.set(TRIGGER_STATE_KEY, JSON.stringify(data.triggerState)); } catch (_) {}
            }
            if (data.zoom && typeof data.zoom === 'object') {
                try {
                    for (const [tab, key] of Object.entries(ZOOM_KEYS)) {
                        if (data.zoom[tab] != null) {
                            kv.set(key, String(data.zoom[tab]));
                        }
                    }
                } catch (_) {}
            }

            if (Array.isArray(data.accounts) && typeof saveAccounts === 'function') {
                try { saveAccounts(data.accounts); } catch (_) {}
            }
            if (Array.isArray(data.lists) && typeof saveLists === 'function') {
                try { saveLists(data.lists); } catch (_) {}
            }

            if (data.folders && typeof data.folders === 'object') {
                if (Array.isArray(data.folders.accounts) && typeof ACCOUNTS_FOLDERS_KEY !== 'undefined') {
                    try { saveFolders(ACCOUNTS_FOLDERS_KEY, data.folders.accounts); } catch (_) {}
                }
                if (Array.isArray(data.folders.lists) && typeof LISTS_FOLDERS_KEY !== 'undefined') {
                    try { saveFolders(LISTS_FOLDERS_KEY, data.folders.lists); } catch (_) {}
                }
                if (Array.isArray(data.folders.saved) && typeof SAVED_FOLDERS_KEY !== 'undefined') {
                    try { saveFolders(SAVED_FOLDERS_KEY, data.folders.saved); } catch (_) {}
                }
            }

            if (data.unassignedIndex && typeof data.unassignedIndex === 'object') {
                if ('saved' in data.unassignedIndex) try { kv.set('advSavedUnassignedIndex_v1', String(data.unassignedIndex.saved | 0)); } catch (_) {}
                if ('accounts' in data.unassignedIndex) try { kv.set('advAccountsUnassignedIndex_v1', String(data.unassignedIndex.accounts | 0)); } catch (_) {}
                if ('lists' in data.unassignedIndex) try { kv.set('advListsUnassignedIndex_v1', String(data.unassignedIndex.lists | 0)); } catch (_) {}
            }

            /* --- Favorite Tags Data --- */
            if (data.favoriteTags && typeof ft_saveState === 'function') {
                try {
                    const s = data.favoriteTags;
                    ft_normalizeTagOrdersFor(s);
                    ft_clampUncategorizedOrderFor(s);
                    ft_saveState(s); // ストレヌゞぞの保存

                    if (typeof ft_state !== 'undefined') {
                        ft_state = s;
                    }
                } catch (_) {}
            }

            // 蚀語を再適甚
            try {
                const override = kv.get(LANG_OVERRIDE_KEY, '');
                if (override && i18n.translations[override]) {
                    i18n.lang = override;
                } else if (!override) {
                    i18n.init();
                }
            } catch (_) {}

            try {
                i18n.apply(document.getElementById('advanced-search-modal'));
                i18n.apply(document.getElementById('adv-settings-modal'));
            } catch (_) {}

            try { applySecretBtn(); } catch (_) {}
            try { renderHistory(); } catch (_) {}
            try { renderSaved(); } catch (_) {}
            try { renderLists(); } catch (_) {}
            try { renderAccounts(); } catch (_) {}
            try { renderMuted(); } catch (_) {}

            // お気に入りリストを再描画し、ボタン状態・タグチップを党曎新する
            try {
                renderFavorites();
                updateAllFavoriteButtons();
            } catch (_) {}

            try { rescanAllTweetsForFilter(); } catch (_) {}

            /* --- Favorite Tags UI Refresh --- */
            try {
                if (typeof ft_refreshAllTagChips === 'function') ft_refreshAllTagChips();
            } catch (_) {}

            // タブの衚瀺状態を適甚
            try { applyTabsVisibility(); } catch (_) {}

            showToast(i18n.t('toastImported'));
            return true;
        }

        // マスタヌON/OFF党䜓の適甚を止めるだけ。各゚ントリの enabled は保持
        const MUTE_MASTER_KEY = 'advMuteMasterEnabled_v1';
        const MUTE_MODE_KEY = 'advMuteMode_v1';
        const LAST_TAB_KEY = 'advSearchLastTab_v1';
        const TABS_ORDER_KEY = 'advTabsOrder_v1';
        const TABS_VISIBILITY_KEY = 'advTabsVisibility_v1';
        const loadMuteMaster = () => { try { return kv.get(MUTE_MASTER_KEY, '1') === '1'; } catch(_) { return true; } };
        const saveMuteMaster = (on) => { try { kv.set(MUTE_MASTER_KEY, on ? '1' : '0'); } catch(_) {} };
        const loadMuteMode = () => { try { return kv.get(MUTE_MODE_KEY, 'hidden'); } catch(_) { return 'hidden'; } };
        const saveMuteMode = (v) => { try { kv.set(MUTE_MODE_KEY, v); } catch(_) {} };

        const tabButtons = Array.from(document.querySelectorAll('.adv-tab-btn'));

        // Get tab panels for background drop
        const tabAccountsPanel = document.getElementById('adv-tab-accounts');
        const tabListsPanel = document.getElementById('adv-tab-lists');
        const tabSavedPanel    = document.getElementById('adv-tab-saved');

        const activateTab = (name) => {
            let targetName = name;
            const visibility = loadTabsVisibility();

            // タヌゲットが非衚瀺に蚭定されおいるかチェック
            if (visibility[targetName] === false) {
                // 非衚瀺の堎合、フォヌルバック先を探す
                // 'search' は true が保蚌されおいるので、必ず 'search' にフォヌルバックされる
                const orderedButtons = Array.from(document.querySelectorAll('.adv-tab-btn'));
                const firstVisible = orderedButtons.find(btn => {
                    const tab = btn.dataset.tab;
                    return tab && visibility[tab] !== false;
                });
                targetName = firstVisible ? firstVisible.dataset.tab : 'search';
            }

            // tabButtons は DOM の順序ず同期しおいる必芁があるため、DOM から再取埗
            const currentTabButtons = Array.from(document.querySelectorAll('.adv-tab-btn'));
            currentTabButtons.forEach(b => b.classList.toggle('active', b.dataset.tab === targetName));

            // [tabSearch, tabHistory, tabSaved, tabLists, tabAccounts, tabMute] // 叀い配列参照を削陀
            document.querySelectorAll('.adv-tab-content').forEach(el => {
              el.classList.toggle('active', el.id === `adv-tab-${targetName}`);
            });


            footerEl.style.display = (targetName === 'search') ? '' : 'none';
            // 最埌に開いたタブを保存 (非衚瀺でも芁求されたタブを保存する)
            try {
                kv.set(LAST_TAB_KEY, name); // ★ 元の name を保存する
            } catch(e) {
                console.error('Failed to save last tab state:', e);
            }
            if (targetName === 'history') renderHistory();
            if (targetName === 'saved') renderSaved();
            if (targetName === 'lists') renderLists();
            if (targetName === 'accounts') renderAccounts();
            if (targetName === 'mute') renderMuted();
            if (targetName === 'favorites') renderFavorites();
            if (targetName === 'search') updateSaveButtonState();

            /* タブ切替ごずに該圓タブのズヌム率を反映 */
            applyZoom();
        };

        const applyTabsVisibility = () => {
            const visibility = loadTabsVisibility();
            // tabButtons は DOM の順序を反映しおいる必芁があるため、DOM から再取埗
            const currentTabButtons = Array.from(document.querySelectorAll('.adv-tab-btn'));
            let firstVisibleTab = 'search'; // フォヌルバック (searchはtrue固定なので)

            for (const btn of currentTabButtons) {
                const tabName = btn.dataset.tab;
                if (!tabName) continue;

                // visibility[tabName] が false の堎合のみ非衚瀺 (true や undefined は衚瀺)
                const isVisible = visibility[tabName] !== false;
                btn.style.display = isVisible ? '' : 'none';

                // フォヌルバック先タブを決定 (search が最優先)
                if (isVisible && firstVisibleTab === 'search' && tabName !== 'search') {
                    firstVisibleTab = tabName; // search 以倖で最初に芋぀かった衚瀺可胜なタブ
                }
            }

            // 'search' が衚瀺可胜か確認 (true 固定だが念のため)
            if (visibility['search'] === true) {
                firstVisibleTab = 'search';
            }

            // 最埌にアクティブだったタブが非衚瀺になっおいないかチェック
            const activeBtn = document.querySelector('.adv-tab-btn.active');
            if (activeBtn && activeBtn.style.display === 'none') {
                // 非衚瀺にされたので、衚瀺可胜な最初のタブ (通垞は 'search') に切り替える
                activateTab(firstVisibleTab);
            }
        };

        // タブの順序を読み蟌んで適甚
        (function applyTabsOrder() {
          const tabsContainer = document.querySelector('.adv-tabs');
          if (!tabsContainer) return;

          // 珟圚のボタンを data-tab をキヌにした Map ずしお保持
          const currentButtons = new Map();
          const defaultOrder = [];
          tabsContainer.querySelectorAll('.adv-tab-btn[data-tab]').forEach(btn => {
              const tabName = btn.dataset.tab;
              if (tabName) {
                  currentButtons.set(tabName, btn);
                  defaultOrder.push(tabName);
              }
          });

          // 保存された順序を読み蟌む
          const savedOrder = loadJSON(TABS_ORDER_KEY, defaultOrder);

          // 保存された順序を怜蚌し、䞍足分を補う
          const finalOrder = [];
          const seen = new Set();
          // 1. 保存された順序のうち、珟圚も存圚するものを远加
          savedOrder.forEach(tabName => {
              if (currentButtons.has(tabName)) {
                  finalOrder.push(tabName);
                  seen.add(tabName);
              }
          });
          // 2. デフォルト順序のうち、ただ远加されおいないもの新しいタブを末尟に远加
          defaultOrder.forEach(tabName => {
              if (!seen.has(tabName)) {
                  finalOrder.push(tabName);
              }
          });

          // 順序が実際に倉曎されおいるか確認
          if (JSON.stringify(savedOrder) !== JSON.stringify(finalOrder)) {
              saveJSON(TABS_ORDER_KEY, finalOrder);
          }

          // DOMを䞊び替える
          finalOrder.forEach(tabName => {
              const btn = currentButtons.get(tabName);
              if (btn) {
                  tabsContainer.appendChild(btn);
              }
          });
          // tabButtons 配列も再取埗順序が倉曎されたため
            tabButtons.splice(0, tabButtons.length, ...Array.from(document.querySelectorAll('.adv-tab-btn')));
        })();

        // タブの衚瀺/非衚瀺をDOMに適甚 (activateTab の前に呌ぶ)
        applyTabsVisibility();

        const saveModalRelativeState = () => {
            if (modal.style.display === 'none') {
                try {
                    const current = (()=>{
                        try { return JSON.parse(kv.get(MODAL_STATE_KEY, '{}')); } catch(_) { return {}; }
                    })();
                    current.visible = false;
                    kv.set(MODAL_STATE_KEY, JSON.stringify(current));
                } catch(_) {}
                return;
            }
            const rect = modal.getBoundingClientRect();
            const winW = window.innerWidth, winH = window.innerHeight;
            const fromRight = winW - rect.right, fromBottom = winH - rect.bottom;
            const h_anchor = rect.left < fromRight ? 'left' : 'right';
            const h_value  = h_anchor === 'left' ? rect.left : fromRight;
            const v_anchor = rect.top  < fromBottom ? 'top'  : 'bottom';
            const v_value  = v_anchor === 'top' ? rect.top : fromBottom;
            const state = { h_anchor, h_value, v_anchor, v_value, visible: true,
                            w: Math.round(rect.width), h: Math.round(rect.height) };
            kv.set(MODAL_STATE_KEY, JSON.stringify(state));
        };
        const applyModalStoredPosition = () => {
            try {
                const s = JSON.parse(kv.get(MODAL_STATE_KEY, '{}'));
                const h_anchor = s.h_anchor || 'right';
                const h_value  = s.h_value ?? 20;
                const v_anchor = s.v_anchor || 'top';
                const v_value  = s.v_value ?? 80;
                modal.style.left = modal.style.right = modal.style.top = modal.style.bottom = 'auto';
                if (h_anchor === 'right') modal.style.right = `${h_value}px`; else modal.style.left = `${h_value}px`;
                if (v_anchor === 'bottom') modal.style.bottom = `${v_value}px`; else modal.style.top = `${v_value}px`;

                const minW = 300, minH = 240;
                if (s.w) modal.style.width  = `${Math.max(minW, Math.min(s.w, window.innerWidth  - 20))}px`;
                else     modal.style.width  = '450px';
                if (s.h) modal.style.height = `${Math.max(minH, Math.min(s.h, window.innerHeight - 20))}px`;
                else     modal.style.height = '';
            } catch(e) { console.error('Failed to apply modal position:', e); }
        };
        const keepModalInViewport = () => {
            if (modal.style.display === 'none') return;
            const rect = modal.getBoundingClientRect();
            const winW = window.innerWidth, winH = window.innerHeight, m = 10;

            const minW = 300, minH = 240;
            const maxW = Math.max(minW, winW - 2*m);
            const maxH = Math.max(minH, winH - 2*m);
            const w = Math.min(Math.max(rect.width,  minW), maxW);
            const h = Math.min(Math.max(rect.height, minH), maxH);
            if (Math.round(w) !== Math.round(rect.width))  modal.style.width  = `${w}px`;
            if (Math.round(h) !== Math.round(rect.height)) modal.style.height = `${h}px`;

            let x = rect.left, y = rect.top;
            if (x < m) x = m; if (y < m) y = m;
            if (x + w > winW - m) x = winW - w - m;
            if (y + h > winH - m) y = winH - h - m;
            if (Math.round(x) !== Math.round(rect.left) || Math.round(y) !== Math.round(rect.top)) {
                modal.style.left = `${x}px`; modal.style.top = `${y}px`;
                modal.style.right = 'auto'; modal.style.bottom = 'auto';
            }
        };
        const loadModalState = () => {
            try { applyModalStoredPosition(); } catch(e) {
                console.error('Failed to load modal state:', e);
                kv.del(MODAL_STATE_KEY);
            }
        };

        const saveTriggerRelativeState = () => {
            const rect = trigger.getBoundingClientRect();
            const winW = window.innerWidth, winH = window.innerHeight;
            const fromRight = winW - rect.right, fromBottom = winH - rect.bottom;
            const h_anchor = rect.left < fromRight ? 'left' : 'right';
            const h_value  = h_anchor === 'left' ? rect.left : fromRight;
            const v_anchor = rect.top  < fromBottom ? 'top'  : 'bottom';
            const v_value  = v_anchor === 'top' ? rect.top : fromBottom;
            const state = { h_anchor, h_value, v_anchor, v_value };
            kv.set(TRIGGER_STATE_KEY, JSON.stringify(state));
        };
        const applyTriggerStoredPosition = () => {
            try {
                const s = JSON.parse(kv.get(TRIGGER_STATE_KEY, '{}'));
                const h_anchor = s.h_anchor || 'right';
                const h_value  = s.h_value ?? 20;
                const v_anchor = s.v_anchor || 'top';
                const v_value  = s.v_value ?? 18;
                trigger.style.left = trigger.style.right = trigger.style.top = trigger.style.bottom = 'auto';
                if (h_anchor === 'right') trigger.style.right = `${h_value}px`; else trigger.style.left = `${h_value}px`;
                if (v_anchor === 'bottom') trigger.style.bottom = `${v_value}px`; else trigger.style.top = `${v_value}px`;
            } catch(e) { console.error('Failed to apply trigger position:', e); }
        };
        const keepTriggerInViewport = () => {
            const rect = trigger.getBoundingClientRect();
            const winW = window.innerWidth, winH = window.innerHeight, m = 6;
            let x = rect.left, y = rect.top;
            if (x < m) x = m; if (y < m) y = m;
            if (x + rect.width > winW - m) x = winW - rect.width - m;
            if (y + rect.height > winH - m) y = winH - rect.height - m;
            if (Math.round(x) !== Math.round(rect.left) || Math.round(y) !== Math.round(rect.top)) {
                trigger.style.left = `${x}px`; trigger.style.top = `${y}px`;
                trigger.style.right = 'auto'; trigger.style.bottom = 'auto';
                saveTriggerRelativeState();
            }
        };
        const setupTriggerDrag = () => {
            const DRAG_THRESHOLD = 4;
            let isPointerDown = false, isDragging = false, start = {x:0,y:0,left:0,top:0}, suppressClick=false;
            const onPointerDown = (e) => {
                if (e.button !== 0) return;
                isPointerDown = true; isDragging = false; suppressClick=false;
                const rect = trigger.getBoundingClientRect();
                start = { x:e.clientX, y:e.clientY, left:rect.left, top:rect.top };
                try{ trigger.setPointerCapture(e.pointerId);}catch(_){}
            };
            const onPointerMove = (e) => {
                if (!isPointerDown) return;
                const dx = e.clientX - start.x, dy = e.clientY - start.y;
                if (!isDragging) {
                    if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
                    isDragging = true;
                    trigger.style.right = 'auto'; trigger.style.bottom = 'auto';
                    trigger.style.left = `${start.left}px`; trigger.style.top = `${start.top}px`;
                    document.body.classList.add('adv-dragging');
                }
                const winW = window.innerWidth, winH = window.innerHeight;
                const w = trigger.offsetWidth, h = trigger.offsetHeight;
                let nx = start.left + dx, ny = start.top + dy;
                nx = Math.max(0, Math.min(nx, winW - w)); ny = Math.max(0, Math.min(ny, winH - h));
                trigger.style.left = `${nx}px`; trigger.style.top = `${ny}px`;
            };
            const onPointerUp = (e) => {
                if (!isPointerDown) return; isPointerDown = false;
                try{ trigger.releasePointerCapture(e.pointerId);}catch(_){}
                if (isDragging) {
                    isDragging = false; document.body.classList.remove('adv-dragging');
                    suppressClick = true; setTimeout(()=>{suppressClick=false;},150);
                    saveTriggerRelativeState();
                }
            };
            trigger.addEventListener('click', (e)=> {
                if (suppressClick) {
                    e.preventDefault();
                    e.stopPropagation();
                    suppressClick = false;
                    return;
                }
            }, true);
            trigger.addEventListener('pointerdown', onPointerDown);
            window.addEventListener('pointermove', onPointerMove);
            window.addEventListener('pointerup', onPointerUp);
            window.addEventListener('pointercancel', onPointerUp);
        };

        applyTriggerStoredPosition();
        requestAnimationFrame(keepTriggerInViewport);
        setupTriggerDrag();

        const readScopesFromControls = () => ({ pf: accountScopeSel.value === 'following', lf: locationScopeSel.value === 'nearby' });
        const applyScopesToControls = ({pf=false, lf=false}) => {
            accountScopeSel.value = pf ? 'following' : '';
            locationScopeSel.value = lf ? 'nearby' : '';
        };
        const readScopesFromURL = (urlStr) => {
            try {
                const u = new URL(urlStr || location.href, location.origin);
                const pf = (u.searchParams.get('pf') || '') === 'on';
                const lf = (u.searchParams.get('lf') || '') === 'on';
                return { pf, lf };
            } catch { return { pf:false, lf:false }; }
        };

        const STATE_SYNC = {
            parseFromSearchToModal: () => {
                if (isUpdating || modal.style.display === 'none') return;
                // â–Œ 耇数圢に倉曎し、最初の芁玠を取埗
                const inputs = getActiveSearchInputs();
                const si = inputs[0]; // 耇数のうち最初のを代衚ずしお読み蟌む
                parseQueryAndApplyToModal(si ? si.value : '');
                applyScopesToControls(readScopesFromURL());
                updateSaveButtonState();
            }
        };

        const buildQueryStringFromModal = () => {
            const q = [];
            const fields = {
                all: document.getElementById('adv-all-words').value.trim(),
                exact: document.getElementById('adv-exact-phrase').value.trim(),
                any: document.getElementById('adv-any-words').value.trim(),
                not: document.getElementById('adv-not-words').value.trim(),
                hash: document.getElementById('adv-hashtag').value.trim(),
                lang: document.getElementById('adv-lang').value,
                replies: document.getElementById('adv-replies').value,
                min_replies: document.getElementById('adv-min-replies').value,
                min_faves: document.getElementById('adv-min-faves').value,
                min_retweets: document.getElementById('adv-min-retweets').value,
                since: document.getElementById('adv-since').value,
                until: document.getElementById('adv-until').value,
            };
            if (fields.all) q.push(fields.all);
            if (fields.exact) q.push(`"${fields.exact.replace(/"/g,'')}"`);

            // 匕甚で 1 語ずしお扱い、OR 連結を生成
            if (fields.any) {
              const tokens = tokenizeQuotedWords(fields.any).map(t => {
                // 既に "
": そのたた。未匕甚で空癜を含む → 匕甚を付ける
                if (/^".*"$/.test(t)) return t;
                if (/\s/.test(t)) return `"${t.replace(/"/g,'')}"`;
                return t;
              });
              if (tokens.length) q.push(`(${tokens.join(' OR ')})`);
            }

            if (fields.not) q.push(...fields.not.split(/\s+/).filter(Boolean).map(w=>`-${w}`));
            if (fields.hash) q.push(...fields.hash.split(/\s+/).filter(Boolean).map(h=>`#${h.replace(/^#/,'')}`));
            if (fields.lang) q.push(`lang:${fields.lang}`);

            const createAccountQuery = (inputId, operator) => {
                const value = document.getElementById(inputId).value.trim();
                if (!value) return null;
                const isExclude = document.getElementById(`${inputId}-exclude`).checked;
                const terms = value.split(/\s+/).filter(Boolean);
                if (isExclude) return terms.map(t=>`-${operator}${t.replace(/^@/,'')}`).join(' ');
                const processed = terms.map(t=>`${operator}${t.replace(/^@/,'')}`);
                return processed.length>1 ? `(${processed.join(' OR ')})` : processed[0];
            };
            const fromQ = createAccountQuery('adv-from-user','from:'); if (fromQ) q.push(fromQ);
            const toQ = createAccountQuery('adv-to-user','to:'); if (toQ) q.push(toQ);
            const mentionQ = createAccountQuery('adv-mentioning','@'); if (mentionQ) q.push(mentionQ);

            if (fields.min_replies) q.push(`min_replies:${fields.min_replies}`);
            if (fields.min_faves) q.push(`min_faves:${fields.min_faves}`);
            if (fields.min_retweets) q.push(`min_retweets:${fields.min_retweets}`);
            if (fields.since) q.push(`since:${fields.since}`);
            if (fields.until) q.push(`until:${fields.until}`);

            const addFilter = (type, mapping) => {
                const include = document.getElementById(`adv-filter-${type}-include`).checked;
                const exclude = document.getElementById(`adv-filter-${type}-exclude`).checked;
                if (include) q.push(mapping);
                if (exclude) q.push(`-${mapping}`);
            };
            addFilter('verified','is:verified');
            addFilter('links','filter:links');
            addFilter('images','filter:images');
            addFilter('videos','filter:videos');

            if (fields.replies) {
                const replyMap = { include:'include:replies', only:'filter:replies', exclude:'-filter:replies' };
                if (replyMap[fields.replies]) q.push(replyMap[fields.replies]);
            }
            return q.join(' ');
        };

        const parseQueryAndApplyToModal = (query) => {
            if (isUpdating) return; isUpdating = true;
            const formEl = document.getElementById('advanced-search-form');
            formEl.reset();
            // フォヌムリセット時に disabled を解陀
            ['verified', 'links', 'images', 'videos'].forEach(groupName => {
                const includeEl = document.getElementById(`adv-filter-${groupName}-include`);
                const excludeEl = document.getElementById(`adv-filter-${groupName}-exclude`);
                if (includeEl) includeEl.disabled = false;
                if (excludeEl) excludeEl.disabled = false;
            });
            try {
              const st = loadExcludeFlags();
              const nameEl   = document.getElementById('adv-exclude-hit-name');
              const handleEl = document.getElementById('adv-exclude-hit-handle');
              const repostsEl = document.getElementById('adv-filter-reposts-exclude');
              const hashtagsEl = document.getElementById('adv-filter-hashtags-exclude');
              if (nameEl)   { nameEl.checked = nameEl.defaultChecked = !!st.name; }
              if (handleEl) { handleEl.checked = handleEl.defaultChecked = !!st.handle; }
              if (repostsEl) { repostsEl.checked = repostsEl.defaultChecked = !!st.reposts; }
              if (hashtagsEl) { hashtagsEl.checked = hashtagsEl.defaultChecked = !!st.hashtags; }
            } catch (_) {}

            // ク゚リを正芏化スマヌト匕甚・%xx・空癜
            const rawNorm = normalizeForParse(query || '');

            // トップレベル OR を先に芋る玔粋 OR / ハむブリッド OR の切り分け
            const orParts = splitTopLevelOR(rawNorm);
            if (orParts && isPureORQuery(rawNorm)) {
              // 匕甚を 1 語ずしお数えるトヌクナむザ
              const tokenize = (s) => tokenizeQuotedWords(s).filter(Boolean);
              const tokenized = orParts.map(p => tokenize(p));

              const allAreSingle = tokenized.every(ts => ts.length === 1);
              if (allAreSingle) {
                // ① 玔粋 OR党郚 any に入れるexact/all は空→ 早期 return
                document.getElementById('adv-any-words').value = orParts.join(' ');
                isUpdating = false;
                return;
              }

              const head = tokenized[0];
              const rest = tokenized.slice(1);
              const restAllSingle = rest.every(ts => ts.length === 1);

              if (head.length >= 2 && restAllSingle) {
                // ② ハむブリッド OR
                //    - 先頭片の「最埌のトヌクン」→ OR 集合
                //    - 先頭片の「それ以倖」      → all必須語
                //    - 埌続片単䞀トヌクン   → OR 集合
                const required = head.slice(0, -1);
                const orTokens = [head[head.length - 1], ...rest.map(ts => ts[0])];

                document.getElementById('adv-all-words').value = required.join(' ');
                document.getElementById('adv-any-words').value = orTokens.join(' ');
                // exact は空のたた匕甚は any 偎ぞ
                isUpdating = false;
                return;
              }
              // それ以倖レアは通垞パヌスにフォヌルバック
            }

            // ここから通垞パヌスrawNorm をベヌス
            let q = ` ${rawNorm} `;

            // 蚀語や挔算子は先に抜く匕甚の前埌どちらでもOKだが、先にやるず芖芚的に期埅通り
            const extract = (regex, cb) => {
              let m;
              while ((m = regex.exec(q)) !== null) {
                cb(m[1].trim());
                q = q.replace(m[0], ' ');
                regex.lastIndex = 0;
              }
            };

            // 蚀語
            extract(/\blang:([^\s()"]+)/gi, v => { document.getElementById('adv-lang').value = v.toLowerCase(); });

            // ハッシュタグ
            extract(/\s#([^\s)"]+)/g, v => {
              const el = document.getElementById('adv-hashtag');
              el.value = (el.value + ' ' + v).trim();
            });

            // 最小゚ンゲヌゞメント・期間
            extract(/\bmin_replies:(\d+)\b/gi, v => document.getElementById('adv-min-replies').value = v);
            extract(/\bmin_faves:(\d+)\b/gi,   v => document.getElementById('adv-min-faves').value   = v);
            extract(/\bmin_retweets:(\d+)\b/gi,v => document.getElementById('adv-min-retweets').value= v);
            extract(/\bsince:(\d{4}-\d{2}-\d{2})\b/gi, v => document.getElementById('adv-since').value = v);
            extract(/\buntil:(\d{4}-\d{2}-\d{2})\b/gi, v => document.getElementById('adv-until').value = v);

            // フィルタ
            const filterMap = { 'is:verified':'verified', 'filter:links':'links', 'filter:images':'images', 'filter:videos':'videos' };
            Object.entries(filterMap).forEach(([op,id])=>{
              const r = new RegExp(`\\s(-?)${op.replace(':','\\:')}\\b`, 'gi');
              q = q.replace(r, (m, neg) => {
                document.getElementById(`adv-filter-${id}-${neg ? 'exclude' : 'include'}`).checked = true;
                return ' ';
              });
            });

            // 返信
            if (/\binclude:replies\b/i.test(q)) { document.getElementById('adv-replies').value='include'; q=q.replace(/\binclude:replies\b/ig,' '); }
            else if (/\bfilter:replies\b/i.test(q)) { document.getElementById('adv-replies').value='only'; q=q.replace(/\bfilter:replies\b/ig,' '); }
            else if (/\b-filter:replies\b/i.test(q)) { document.getElementById('adv-replies').value='exclude'; q=q.replace(/\b-filter:replies\b/ig,' '); }

            // アカりント挔算子
            const parseAccountField = (inputId, operator) => {
              const exclOp = `-${operator}`;
              const values = [];
              // 陀倖
              const reEx = new RegExp(`\\s${exclOp.replace(/[-:]/g,'\\$&')}([^\\s()"]+)`, 'gi');
              q = q.replace(reEx, (m, u) => { values.push(u); document.getElementById(`${inputId}-exclude`).checked = true; return ' '; });
              // 包含括匧 OR グルヌプ
              const reGroup = new RegExp(`\\((?:${operator.replace(':','\\:')}([^\\s()"]+))(?:\\s+OR\\s+${operator.replace(':','\\:')}([^\\s()"]+))*\\)`, 'gi');
              q = q.replace(reGroup, (m) => {
                m.replace(new RegExp(`${operator.replace(':','\\:')}([^\\s()"]+)`, 'gi'), (_m, u) => { values.push(u); return _m; });
                return ' ';
              });
              // 単䜓
              const reIn = new RegExp(`\\s(?!-)${operator.replace(':','\\:')}([^\\s()"]+)`, 'gi');
              q = q.replace(reIn, (m, u) => { values.push(u); return ' '; });
              if (values.length) document.getElementById(inputId).value = [...new Set(values)].join(' ');
            };
            parseAccountField('adv-from-user','from:');
            parseAccountField('adv-to-user','to:');
            parseAccountField('adv-mentioning','@');

            // â–Œ 括匧内 OR は any ぞ**先にやる**。匕甚は壊さない、グルヌプ䞞ごず陀去
            {
              const groups = q.match(/\((?:[^()"]+|"[^"]*")+\)/g); // 匕甚察応の簡易版
              if (groups) {
                const tokens = groups
                  .map(g => g.slice(1, -1))                      // (...) → 䞭身
                  .flatMap(s => s.split(/\s+OR\s+/i))
                  .map(s => s.trim())
                  .filter(Boolean);
                if (tokens.length) {
                  const el = document.getElementById('adv-any-words');
                  el.value = (el.value ? el.value + ' ' : '') + tokens.join(' ');
                }
                // グルヌプは䞞ごず削る以埌の匕甚抜出に巻き蟌たせない
                q = q.replace(/\((?:[^()"]+|"[^"]*")+\)/g, ' ');
              }
            }

            // â–Œ 匕甚フレヌズ括匧の倖だけが残っおいる。exact は最初の1件のみ
            {
              let exactSet = false;
              q = q.replace(/"([^"]+)"/g, (_m, p1) => {
                if (!exactSet) {
                  document.getElementById('adv-exact-phrase').value = p1.trim();
                  exactSet = true;
                }
                return ' ';
              });
            }

            // 陀倖語
            const nots = (q.match(/\s-\S+/g) || []).map(w => w.trim().slice(1));
            if (nots.length) document.getElementById('adv-not-words').value = nots.join(' ');
            q = q.replace(/\s-\S+/g,' ');

            document.getElementById('adv-all-words').value =
              q.trim().split(/\s+/).filter(Boolean).join(' ');

            // フィルタ適甚埌に disabled 状態を再評䟡
            ['verified', 'links', 'images', 'videos'].forEach(groupName => {
                const includeEl = document.getElementById(`adv-filter-${groupName}-include`);
                const excludeEl = document.getElementById(`adv-filter-${groupName}-exclude`);
                if (!includeEl || !excludeEl) return;
                if (includeEl.checked) excludeEl.disabled = true;
                if (excludeEl.checked) includeEl.disabled = true;
            });

            isUpdating = false;
        };

        const syncFromModalToSearchBox = () => {
            if (isUpdating) return; isUpdating=true;
            const finalQuery = buildQueryStringFromModal();
            // â–Œ 耇数圢に倉曎し、ルヌプ凊理
            const inputs = getActiveSearchInputs();
            if (inputs.length > 0) {
                inputs.forEach(si => {
                    if (si) { syncControlledInput(si, finalQuery); }
                });
            }
            isUpdating=false;
            updateSaveButtonState();
        };
        const syncFromSearchBoxToModal = STATE_SYNC.parseFromSearchToModal;

        const showToast = (msg) => {
            toastEl.textContent = msg;
            toastEl.classList.add('show');
            setTimeout(()=> toastEl.classList.remove('show'), 1500);
        };

        function openSettingsModal() {
          if (!settingsModal) return;
          settingsModal.style.display = 'flex';

          // UI蚀語の読み蟌み
          try {
            const override = kv.get(LANG_OVERRIDE_KEY, '');
            if (settingsLangSel) settingsLangSel.value = override || '';
          } catch (_) {}

          try {
            const initTab = kv.get(INITIAL_TAB_KEY, 'last');
            if (settingsInitialTabSel) settingsInitialTabSel.value = initTab;
          } catch (_) {}

          // タブ衚瀺蚭定の読み蟌みず蚭定
          try {
            const visibility = loadTabsVisibility();
            DEFAULT_TABS.forEach(tabName => {
              const toggle = document.getElementById(`adv-settings-tab-toggle-${tabName}`);
              if (!toggle) return;

              // 状態を同期 (search は disabled checked になっおいるので loadTabsVisibility に远埓)
              toggle.checked = visibility[tabName] !== false;

              // 倚重登録を防止
              if (toggle.dataset.listenerAttached) return;
              toggle.dataset.listenerAttached = 'true';

              toggle.addEventListener('change', () => {
                const currentState = loadTabsVisibility();
                currentState[tabName] = toggle.checked;
                saveTabsVisibility(currentState);
                // 即座にタブバヌに反映
                applyTabsVisibility();
              });
            });
          } catch (e) {
            console.error('[AdvSearch] Failed to setup Tab Toggles:', e);
          }

          try {
            const dialog = settingsModal.querySelector('.adv-settings-dialog');
            themeManager.applyTheme(dialog, trigger);
          } catch (_) {}
        }

        function closeSettingsModal() {
          if (!settingsModal) return;
          settingsModal.style.display = 'none';
        }

        if (settingsOpenBtn) {
          settingsOpenBtn.addEventListener('click', (e)=>{
            e.stopPropagation();
            openSettingsModal();
          });
        }
        if (settingsCloseBtn) {
          settingsCloseBtn.addEventListener('click', (e)=>{
            e.stopPropagation();
            closeSettingsModal();
          });
        }
        if (settingsCloseFooterBtn) {
          settingsCloseFooterBtn.addEventListener('click', (e)=>{
            e.stopPropagation();
            closeSettingsModal();
          });
        }
        if (settingsModal) {
          settingsModal.addEventListener('click', (e)=>{
            if (e.target === settingsModal) {
              closeSettingsModal();
            }
          });
        }

        if (settingsExportBtn) {
          settingsExportBtn.addEventListener('click', () => {
            const json = buildSettingsExportJSON();
            try {
              const blob = new Blob([json], { type: 'application/json' });
              const url = URL.createObjectURL(blob);
              const a = document.createElement('a');

              const now = new Date();
              const pad = (n) => String(n).padStart(2, '0');
              const fname =
                `advanced-search-for-x-twitter-backup-${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}` +
                `-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}.json`;

              a.href = url;
              a.download = fname;
              document.body.appendChild(a);
              a.click();
              document.body.removeChild(a);
              URL.revokeObjectURL(url);
            } catch (_) {
              // 倱敗しおも、ずりあえずトヌストだけは出す
            }
            showToast(i18n.t('toastExported'));
          });
        }

        if (settingsImportBtn && settingsFileInput) {
          let importResetTimer = null;

          settingsImportBtn.addEventListener('click', () => {
            settingsFileInput.click();
          });

          settingsFileInput.addEventListener('change', () => {
            const file = settingsFileInput.files && settingsFileInput.files[0];
            if (!file) return;
            const reader = new FileReader();
            reader.onload = () => {
              let ok = false;
              try {
                ok = applySettingsImportJSON(String(reader.result || ''));
              } finally {
                // 同じファむルを続けお遞べるようにリセット
                settingsFileInput.value = '';
              }

              if (ok && settingsImportBtn) {
                const successLabel = i18n.t('buttonImportSuccess');
                const normalLabel  = i18n.t('buttonImport');

                settingsImportBtn.textContent = successLabel;
                settingsImportBtn.disabled = true;

                if (importResetTimer) clearTimeout(importResetTimer);
                importResetTimer = setTimeout(() => {
                  settingsImportBtn.disabled = false;
                  settingsImportBtn.textContent = normalLabel;
                }, 2000);
              }
            };
            reader.readAsText(file);
          });
        }

        if (settingsResetBtn) {
          settingsResetBtn.addEventListener('click', () => {
            if (!confirm(i18n.t('confirmResetAll'))) return;

            const KEYS_TO_DELETE = [
              MODAL_STATE_KEY,
              TRIGGER_STATE_KEY,
              HISTORY_KEY,
              INITIAL_TAB_KEY,
              SAVED_KEY,
              SECRET_KEY,
              MUTE_KEY,
              MUTE_MASTER_KEY,
              MUTE_MODE_KEY,
              LAST_TAB_KEY,
              TABS_ORDER_KEY,
              TABS_VISIBILITY_KEY,
              LANG_OVERRIDE_KEY,
              HISTORY_SORT_KEY,
              EXC_NAME_KEY,
              EXC_HANDLE_KEY,
              EXC_REPOSTS_KEY,
              EXC_HASHTAGS_KEY,
              NATIVE_SEARCH_WIDTH_KEY,
              FAV_KEY,
              'advSavedUnassignedIndex_v1',
              'advAccountsUnassignedIndex_v1',
              'advListsUnassignedIndex_v1',
              ...Object.values(ZOOM_KEYS),
              FT_STATE_KEY,
            ];

            KEYS_TO_DELETE.forEach(k => {
              try { kv.del(k); } catch (_) {}
            });

            // 各皮配列系は空配列で䞊曞き
            try { saveMuted([]); } catch (_) {}
            try { saveJSON(HISTORY_KEY, []); } catch (_) {}
            try { saveJSON(SAVED_KEY, []); } catch (_) {}
            try { saveFavorites([]); } catch (_) {}
            try { saveAccounts([]); } catch (_) {}
            try { saveLists([]); } catch (_) {}
            try { saveFolders(ACCOUNTS_FOLDERS_KEY, []); } catch (_) {}
            try { saveFolders(LISTS_FOLDERS_KEY, []); } catch (_) {}
            try { saveFolders(SAVED_FOLDERS_KEY, []); } catch (_) {}

            /* --- Favorite Tags Data --- */
            try {
              if (typeof ft_createDefaultState === 'function' && typeof ft_saveState === 'function') {
                const defaultBmState = ft_createDefaultState();
                // saveState は内郚で saveJSON を呌ぶ
                ft_saveState(defaultBmState);
                if (typeof ft_state !== 'undefined' && ft_state !== null) {
                  // グロヌバル倉数もリセット
                  Object.assign(ft_state, defaultBmState);
                }
              }
            } catch (_) {}

            // ズヌムキャッシュずパヌスキャッシュもリセット
            try {
              Object.keys(zoomByTab).forEach(tab => {
                zoomByTab[tab] = (tab === 'search') ? 0.87 : 1.0;
              });
            } catch (_) {}
            __cachedSearchTokens = null;
            __cachedSearchQuery = null;

            // 蚀語蚭定を再適甚オヌバヌラむドがなければ自動怜出
            try {
              const override = kv.get(LANG_OVERRIDE_KEY, '');
              if (override && i18n.translations[override]) {
                i18n.lang = override;
              } else {
                i18n.init();
              }
            } catch (_) {
              i18n.init();
            }

            try {
              i18n.apply(document.getElementById('advanced-search-modal'));
              i18n.apply(document.getElementById('adv-settings-modal'));
            } catch (_) {}

            // UI 状態を初期化
            try {
              // タブの衚瀺状態をリセット
              applyTabsVisibility();
              // 最埌のタブを 'search' にリセット
              activateTab('search');

              parseQueryAndApplyToModal('');
              applyScopesToControls({ pf: false, lf: false });
              applySecretBtn();
              renderHistory();
              renderSaved();
              renderLists();
              renderAccounts();
              renderMuted();
              // ミュヌトモヌドの遞択状態をUIに反映
              if (muteModeSel) {
                  muteModeSel.value = loadMuteMode();
              }
              updateSaveButtonState();
              rescanAllTweetsForFilter();

              /* --- Favorite Tags UI Refresh --- */
              try {
                if (typeof ft_refreshAllTagChips === 'function') ft_refreshAllTagChips();
              } catch (_) {}

            } catch (_) {}

            // モヌダル䜍眮・サむズをデフォルトに近い状態ぞ戻す
            try {
              modal.style.width = '';
              modal.style.height = '';
              modal.style.left = '';
              modal.style.right = '';
              modal.style.top = '';
              modal.style.bottom = '';
              loadModalState();
            } catch (_) {}

            // トリガヌボタンの䜍眮もリセット
            try {
              trigger.style.left = '';
              trigger.style.right = '';
              trigger.style.top = '';
              trigger.style.bottom = '';
              applyTriggerStoredPosition();
              keepTriggerInViewport();
            } catch (_) {}

            showToast(i18n.t('toastReset'));
          });
        }

        if (settingsLangSel) {
          settingsLangSel.addEventListener('change', ()=>{
            const v = settingsLangSel.value;
            try { kv.set(LANG_OVERRIDE_KEY, v || ''); } catch (_) {}
            if (v && i18n.translations[v]) {
              i18n.lang = v;
            } else {
              i18n.init();
              try {
                const override = kv.get(LANG_OVERRIDE_KEY, '');
                if (override && i18n.translations[override]) i18n.lang = override;
              } catch (_) {}
            }

            try {
              i18n.apply(document.getElementById('advanced-search-modal'));
              i18n.apply(document.getElementById('adv-settings-modal'));
            } catch (_) {}

            trigger.setAttribute('aria-label', i18n.t('tooltipTrigger'));
            historyClearAllBtn.textContent = i18n.t('historyClearAll');
            applySecretBtn();

            try { renderHistory(); } catch (_) {}
            try { renderSaved(); } catch (_) {}
            try { renderLists(); } catch (_) {}
            try { renderAccounts(); } catch (_) {}
            try { renderMuted(); } catch (_) {}
            try { renderFavorites(); } catch (_) {}
          });
        }

        if (settingsInitialTabSel) {
            settingsInitialTabSel.addEventListener('change', () => {
                kv.set(INITIAL_TAB_KEY, settingsInitialTabSel.value);
            });
        }

        const loadSecret = () => { try { return kv.get(SECRET_KEY, '0') === '1'; } catch(_) { return false; } };
        const saveSecret = (on) => { try { kv.set(SECRET_KEY, on ? '1' : '0'); } catch(_) {} };
        const applySecretBtn = () => {
            const on = loadSecret();
            secretBtn.classList.toggle('on', on);
            secretBtn.classList.toggle('off', !on);
            secretBtn.title = i18n.t(on ? 'secretOn' : 'secretOff');
            secretStateEl.textContent = on ? 'ON' : 'OFF';
        };
        secretBtn.addEventListener('click', (e)=>{
            e.stopPropagation();
            const on = !loadSecret();
            saveSecret(on);
            applySecretBtn();
            showToast(i18n.t(on ? 'secretOn' : 'secretOff'));
        });
        applySecretBtn();

        const migrateList = (list) => Array.isArray(list) ? list.map(it => ({ id:it.id||uid(), q:it.q||'', ts:it.ts||Date.now(), pf:!!it.pf, lf:!!it.lf })) : [];

        const recordHistory = (q, pf, lf) => {
            if (!q || loadSecret()) return;
            const now = Date.now();
            if (lastHistory.q === q && lastHistory.pf === pf && lastHistory.lf === lf && (now - lastHistory.ts) < 3000) return;
            lastHistory.q = q; lastHistory.pf = pf; lastHistory.lf = lf; lastHistory.ts = now;

            const listRaw = loadJSON(HISTORY_KEY, []);
            const list = migrateList(listRaw);
            const idx = list.findIndex(it => it.q === q && !!it.pf === !!pf && !!it.lf === !!lf);
            if (idx === 0) {
                list[0].ts = now;
            } else if (idx > 0) {
                const [item] = list.splice(idx, 1);
                item.ts = now;
                list.unshift(item);
            } else {
                list.unshift({ id: uid(), q, pf: !!pf, lf: !!lf, ts: now });
                // if (list.length > 50) list.length = 50;
            }
            saveJSON(HISTORY_KEY, list);
            renderHistory();
        };

        const deleteHistory = (id) => {
            const listRaw = loadJSON(HISTORY_KEY, []);
            const list = migrateList(listRaw);
            const next = list.filter(it => it.id !== id);
            saveJSON(HISTORY_KEY, next);
            renderHistory();
            showToast(i18n.t('toastDeleted'));
        };

        const clearAllHistory = () => {
            if (!confirm(i18n.t('confirmClearHistory'))) return;
            saveJSON(HISTORY_KEY, []);
            renderHistory();
            showToast(i18n.t('toastDeleted'));
        };

        const addSaved = (q, pf, lf) => {
            const listRaw = loadJSON(SAVED_KEY, []);
            const list = migrateList(listRaw);
            if (list.some(it => it.q === q && !!it.pf === !!pf && !!it.lf === !!lf)) {
                updateSaveButtonState();
                return;
            }
            const item = { id: uid(), q, pf: !!pf, lf: !!lf, ts: Date.now() };
            list.push(item);
            saveJSON(SAVED_KEY, list);
            renderSaved();
            showToast(i18n.t('toastSaved'));
            updateSaveButtonState();
        };

        const deleteSaved = (id) => {
            const listRaw = loadJSON(SAVED_KEY, []);
            const list = migrateList(listRaw);
            const next = list.filter(it => it.id !== id);
            saveJSON(SAVED_KEY, next);
            renderSaved();
            showToast(i18n.t('toastDeleted'));
            updateSaveButtonState();
        };

        const fmtTime = (ts) => { try { return new Date(ts).toLocaleString(); } catch { return ''; } };

        const updateSaveButtonState = () => {
            const q = buildQueryStringFromModal().trim();
            const {pf, lf} = readScopesFromControls();
            const saved = migrateList(loadJSON(SAVED_KEY, []));
            const exists = !!q && saved.some(it => it.q === q && !!it.pf === !!pf && !!it.lf === !!lf);
            saveButton.disabled = !q || exists;
            saveButton.textContent = i18n.t(exists ? 'buttonSaved' : 'buttonSave');
            saveButton.setAttribute('aria-disabled', saveButton.disabled ? 'true' : 'false');
        };



        // タブのクリックむベントずD&Dむベントリスナヌをセットアップ
        (function setupTabDragAndDrop() {
            const tabsContainer = document.querySelector('.adv-tabs');
            if (!tabsContainer) return;

            tabButtons.forEach(btn => {
                // 1. クリックむベント既存のロゞック
                btn.addEventListener('click', (e) => {
                    e.preventDefault();
                    activateTab(btn.dataset.tab);
                });

                // 2. D&Dむベント新芏
                btn.draggable = true;

                btn.addEventListener('dragstart', (ev) => {
                    btn.classList.add('dragging');
                    ev.dataTransfer.setData('text/plain', btn.dataset.tab);
                    ev.dataTransfer.effectAllowed = 'move';
                });

                btn.addEventListener('dragend', () => {
                    btn.classList.remove('dragging');
                });
            });

            tabsContainer.addEventListener('dragover', (ev) => {
                ev.preventDefault();
                const dragging = tabsContainer.querySelector('.adv-tab-btn.dragging');
                if (!dragging) return;

                // 氎平方向の挿入䜍眮を蚈算
                const after = getDragAfterElementHorizontal(tabsContainer, ev.clientX, '.adv-tab-btn');
                if (after == null) {
                    tabsContainer.appendChild(dragging);
                } else {
                    tabsContainer.insertBefore(dragging, after);
                }
            });

            tabsContainer.addEventListener('drop', (ev) => {
                ev.preventDefault();
                const dragging = tabsContainer.querySelector('.adv-tab-btn.dragging');
                if (dragging) {
                    dragging.classList.remove('dragging');
                }

                // 最終的な順序をDOMから読み取っお保存
                const newOrder = [...tabsContainer.querySelectorAll('.adv-tab-btn[data-tab]')]
                    .map(btn => btn.dataset.tab)
                    .filter(Boolean);

                saveJSON(TABS_ORDER_KEY, newOrder);
                // tabButtons 配列も曎新
                tabButtons.splice(0, tabButtons.length, ...Array.from(document.querySelectorAll('.adv-tab-btn')));
                showToast(i18n.t('toastReordered'));
            });
        })();

        const scopeChipsHTML = (pf, lf) => {
            const chips = [];
            if (pf) chips.push(`<span class="adv-chip scope" role="note">${i18n.t('chipFollowing')}</span>`);
            if (lf) chips.push(`<span class="adv-chip scope" role="note">${i18n.t('chipNearby')}</span>`);
            return chips.join('');
        };

        const historyEmptyEl = document.getElementById('adv-history-empty');
        const historyListEl = document.getElementById('adv-history-list');
        const historySearchEl = document.getElementById('adv-history-search');
        const historySortEl = document.getElementById('adv-history-sort');

        const renderHistory = () => {
          const listAll = migrateList(loadJSON(HISTORY_KEY, []));

          // 1. Get filter/sort values
          const q = (historySearchEl?.value || '').toLowerCase().trim();
          const sort = historySortEl?.value || kv.get(HISTORY_SORT_KEY, 'newest');
          if (historySortEl && historySortEl.value !== sort) {
            historySortEl.value = sort;
          }

          // 2. Filter
          const listFiltered = q
            ? listAll.filter(item => (item.q || '').toLowerCase().includes(q))
            : listAll;

          // 3. Sort
          const listSorted = listFiltered.sort((a, b) => {
            switch (sort) {
              case 'oldest': return (a.ts || 0) - (b.ts || 0);
              case 'name_asc': return (a.q || '').localeCompare(b.q || '');
              case 'name_desc': return (b.q || '').localeCompare(a.q || '');
              case 'newest':
              default:
                return (b.ts || 0) - (a.ts || 0);
            }
          });

          // 4. Render
          historyListEl.innerHTML = '';
          historyEmptyEl.textContent = listAll.length === 0 ? i18n.t('emptyHistory') : '';

          listSorted.forEach(item => {
            const row = document.createElement('div');
            row.className = 'adv-item';
            row.dataset.id = item.id;

            row.innerHTML = `
              <div class="adv-item-main">
                <div class="adv-item-title">${escapeHTML(item.q)}</div>
                <div class="adv-item-sub">
                  <span>${fmtTime(item.ts)}</span>
                  ${scopeChipsHTML(!!item.pf, !!item.lf)}
                </div>
              </div>
              <div class="adv-item-actions">
                <button class="adv-chip primary" data-action="run">${i18n.t('run')}</button>
                <button class="adv-chip danger" data-action="delete">${i18n.t('delete')}</button>
              </div>
            `;

            row.querySelector('[data-action="run"]').addEventListener('click', () => {
              parseQueryAndApplyToModal(item.q);
              applyScopesToControls({ pf: !!item.pf, lf: !!item.lf });
              // activateTab('search');
              executeSearch({ pf: item.pf, lf: item.lf });
            });

            row.querySelector('[data-action="delete"]').addEventListener('click', () => {
              deleteHistory(item.id);
            });

            historyListEl.appendChild(row);
          });
        };

        historyClearAllBtn.addEventListener('click', clearAllHistory);

        // 履歎タブの怜玢ず゜ヌトのむベントリスナヌ
        if (historySearchEl) {
          historySearchEl.addEventListener('input', debounce(renderHistory, 150));
        }
        if (historySortEl) {
          historySortEl.value = kv.get(HISTORY_SORT_KEY, 'newest'); // 初期倀を蚭定
          historySortEl.addEventListener('change', () => {
            kv.set(HISTORY_SORT_KEY, historySortEl.value);
            renderHistory();
          });
        }

        const savedEmptyEl = document.getElementById('adv-saved-empty');
        const savedListEl = document.getElementById('adv-saved-list');

        const renderSaved = () => {
          ensureFolderToolbars();

          const itemsLoader = () => migrateList(loadJSON(SAVED_KEY, []));
          const itemsSaver  = (arr) => saveJSON(SAVED_KEY, migrateList(arr));

          renderFolderedCollection({
            hostId: 'adv-saved-list',
            emptyId: 'adv-saved-empty',
            filterSelectId: 'adv-saved-folder-filter',
            searchInputId:  'adv-saved-search',
            newFolderBtnId: 'adv-saved-new-folder',

            foldersKey: SAVED_FOLDERS_KEY,
            defaultFolderName: i18n.t('defaultSavedFolders'),

            loadItems: itemsLoader,
            saveItems: itemsSaver,
            renderRow: (item) => {
              // 以前の renderSavedRow ず同じ芋た目
              const row = document.createElement('div');
              row.className = 'adv-item';
              row.draggable = true;
              row.dataset.id = item.id;
              row.innerHTML = `
                <div class="adv-item-handle" title="Drag">≡</div>
                <div class="adv-item-main">
                  <div class="adv-item-title">${escapeHTML(item.q)}</div>
                  <div class="adv-item-sub">
                    <span>${fmtTime(item.ts)}</span>
                    ${scopeChipsHTML(!!item.pf, !!item.lf)}
                  </div>
                </div>
                <div class="adv-item-actions">
                  <button class="adv-chip primary" data-action="run">${i18n.t('run')}</button>
                  <button class="adv-chip danger"  data-action="delete">${i18n.t('delete')}</button>
                </div>
              `;
              row.querySelector('[data-action="run"]').addEventListener('click', ()=>{
                parseQueryAndApplyToModal(item.q);
                applyScopesToControls({pf:!!item.pf, lf:!!item.lf});
                // activateTab('search');
                executeSearch({pf:item.pf, lf:item.lf});
              });
              row.querySelector('[data-action="delete"]').addEventListener('click', ()=> deleteSaved(item.id));

              row.addEventListener('dragstart', (ev) => {
                row.classList.add('dragging');
                ev.dataTransfer.setData('text/plain', item.id);
                ev.dataTransfer.effectAllowed = 'move';
              });
              row.addEventListener('dragend', () => row.classList.remove('dragging'));
              return row;
            },

            onUnassign: unassignSaved,
            onMoveToFolder: moveSavedToFolder,

            emptyMessage: i18n.t('emptySaved'),
            unassignedIndexKey: 'advSavedUnassignedIndex_v1',
          });

          updateSaveButtonState();
        };

        const getDragAfterElement = (container, y) => {
            const els = [...container.querySelectorAll('.adv-item:not(.dragging)')];
            let closest = { offset: Number.NEGATIVE_INFINITY, element: null };
            for (const el of els) {
                const box = el.getBoundingClientRect();
                const offset = y - box.top - box.height / 2;
                if (offset < 0 && offset > closest.offset) {
                    closest = { offset, element: el };
                }
            }
            return closest.element;
        };

        // === セクションフォルダ/Unassigned甚瞊方向の挿入䜍眮蚈算 ===
        function getSectionAfterElement(container, y) {
          const els = [...container.querySelectorAll('.adv-folder:not(.dragging-folder), .adv-unassigned:not(.dragging-folder)')];
          let closest = { offset: Number.NEGATIVE_INFINITY, element: null };
          for (const el of els) {
            const box = el.getBoundingClientRect();
            const offset = y - box.top - box.height / 2;
            if (offset < 0 && offset > closest.offset) {
              closest = { offset, element: el };
            }
          }
          return closest.element;
        }

        // === 汎甚フォルダ描画レンダラ ===
        // 各タブSaved/Accounts/Listsなどの重耇ロゞックを1か所に集玄したす。
        function renderFolderedCollection(cfg) {
          const {
            // 固有ID/キヌ
            hostId, emptyId,
            filterSelectId, searchInputId, newFolderBtnId,
            foldersKey, defaultFolderName,
            // デヌタI/O
            loadItems, saveItems, loadFoldersFn = loadFolders, saveFoldersFn = saveFolders,
            // Row描画/操䜜
            renderRow, onUnassign, onMoveToFolder,
            // 文蚀/保存キヌ
            emptyMessage,
            unassignedIndexKey, // ex: 'advAccountsUnassignedIndex_v1' / 'advSavedUnassignedIndex_v1'
          } = cfg;

          // ツヌルバヌは呌び出し偎で ensureFolderToolbars() しおある前提
          const host   = document.getElementById(hostId);
          const empty  = document.getElementById(emptyId);
          const sel    = document.getElementById(filterSelectId);
          const qInput = document.getElementById(searchInputId);
          const addBtn = document.getElementById(newFolderBtnId);
          if (!host) return;

          // 1) デヌタロヌド
          const items = loadItems();
          let folders = loadFoldersFn(foldersKey, defaultFolderName);
          const idToItem = Object.fromEntries(items.map(x => [x.id, x]));

          // 2) 死祚掃陀フォルダの order から存圚しないIDを陀去
          let needSave = false;
          for (const f of folders) {
            const before = f.order.length;
            f.order = f.order.filter(id => !!idToItem[id]);
            if (f.order.length !== before) { needSave = true; f.ts = Date.now(); }
          }
          if (needSave) saveFoldersFn(foldersKey, folders);

          // 3) 未所属セット
          const allIds    = new Set(items.map(x => x.id));
          const inFolders = new Set(folders.flatMap(f => f.order));
          const unassignedIds = [...allIds].filter(id => !inFolders.has(id));

          // 4) フィルタUIセレクト怜玢新芏フォルダ
          if (sel) {
            const prev = sel.value;
            sel.innerHTML = '';
            const optAll = document.createElement('option'); optAll.value='__ALL__'; optAll.textContent=i18n.t('folderFilterAll'); sel.appendChild(optAll);
            const optUn  = document.createElement('option'); optUn.value='__UNASSIGNED__'; optUn.textContent=i18n.t('folderFilterUnassigned'); sel.appendChild(optUn);
            folders.forEach(f=>{
              const o = document.createElement('option'); o.value = f.id; o.textContent = f.name; sel.appendChild(o);
            });
            sel.value = [...sel.options].some(o=>o.value===prev) ? prev : '__ALL__';
            sel.onchange = () => renderFolderedCollection(cfg);
          }
          if (qInput && !qInput._advBound) {
            qInput._advBound = true;
            // debounce を適甚
            qInput.addEventListener('input', debounce(() => renderFolderedCollection(cfg), 150));
          }
          if (addBtn && !addBtn._advBound) {
            addBtn._advBound = true;
            addBtn.addEventListener('click', () => {
              const nm = prompt(i18n.t('promptNewFolder'), '');
              if (!nm || !nm.trim()) return;
              const fs = loadFoldersFn(foldersKey, defaultFolderName);
              fs.push({ id: uid(), name: nm.trim(), order: [], ts: Date.now() });
              saveFoldersFn(foldersKey, fs);
              renderFolderedCollection(cfg);
            });
          }

          const filterFolder = sel?.value || '__ALL__';
          const q = (qInput?.value || '').toLowerCase().trim();

         const matchItem = (it) => {
              // JSON化せず、怜玢察象になりうるフィヌルドの倀を盎接結合しお刀定する
              // これにより、保存ク゚リ内の " (ダブルクォヌト) が゚スケヌプされずに怜玢可胜になる
              const targetText = [
                  it.q,       // Saved / History 甹
                  it.name,    // Accounts / Lists / Folders 甹
                  it.handle,  // Accounts 甹
                  it.url,     // Lists 甹
                  it.user?.name,   // (予備)
                  it.user?.handle  // (予備)
              ].map(val => (val || '').toString().toLowerCase()).join(' ');

              return !q || targetText.includes(q);
          };

          host.innerHTML = '';
          empty.textContent = items.length ? '' : (emptyMessage || '');

          // 5) Unassigned むンデックス保持
          const getUnIdx = () => {
            try { const v = GM_getValue(unassignedIndexKey, 0); return Math.max(0, Math.min(folders.length, +v || 0)); }
            catch { return 0; }
          };
          const setUnIdx = (idx) => { try { GM_setValue(unassignedIndexKey, String(idx)); } catch {} };

          // 6) 衚瀺察象フォルダ
          const foldersToDraw =
            filterFolder === '__ALL__'        ? [...folders] :
            filterFolder === '__UNASSIGNED__' ? [] :
            folders.filter(f => f.id === filterFolder);

          // 7) セクション䞊び__ALL__ の堎合のみ Unassigned を混圚
          const buildSectionsOrder = () => {
            if (filterFolder !== '__ALL__') return foldersToDraw.map(f => f.id);
            const idx = getUnIdx();
            const arr = foldersToDraw.map(f => f.id);
            arr.splice(Math.max(0, Math.min(arr.length, idx)), 0, '__UNASSIGNED__');
            return arr;
          };

          // 8) DOM → 順序保存
          const persistSectionsFromDOM = () => {
            const order = [...host.querySelectorAll('.adv-folder, .adv-unassigned')].map(sec => sec.dataset.folderId);

            // フォルダ順Unassigned を陀いた順序で保存
            const newFolderOrderIds = [...new Set(order.filter(id => id !== '__UNASSIGNED__'))];
            let fs = loadFoldersFn(foldersKey, defaultFolderName);
            const map = Object.fromEntries(fs.map(f => [f.id, f]));
            const reordered = newFolderOrderIds.map(id => map[id]).filter(Boolean);
            fs.forEach(f => { if (!reordered.includes(f)) reordered.push(f); });
            saveFoldersFn(foldersKey, reordered);

            // Unassigned の䜍眮を保存
            const unIdx = order.indexOf('__UNASSIGNED__');
            if (unIdx >= 0) setUnIdx(unIdx);

            showToast(i18n.t('toastReordered'));
          };

          // 9) Unassigned セクション
          const renderUnassignedSection = () => {
            const sec = document.createElement('section');
            sec.className = 'adv-unassigned';
            sec.dataset.folderId = '__UNASSIGNED__';
            sec.setAttribute('draggable', 'true');

            const list = document.createElement('div'); list.className = 'adv-list';

            const itemsUn = unassignedIds.map(id => idToItem[id]).filter(Boolean).filter(matchItem);
            itemsUn.forEach(it => list.appendChild(renderRow(it)));

            // セクションD&Dセクション入替
            const SECT_MIME = 'adv/folder';
            sec.addEventListener('dragstart', (ev) => {
              const item = ev.target.closest('.adv-item');
              if (!item) {
                ev.dataTransfer.setData(SECT_MIME, '__UNASSIGNED__');
                ev.dataTransfer.effectAllowed = 'move';
                sec.classList.add('dragging-folder');
              }
            });
            sec.addEventListener('dragend', () => sec.classList.remove('dragging-folder'));
            sec.addEventListener('dragover', (ev) => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) {
                ev.preventDefault();
                const dragging = host.querySelector('.dragging-folder');
                if (!dragging || dragging === sec) return;
                const after = getSectionAfterElement(host, ev.clientY);
                if (after == null) host.appendChild(dragging);
                else host.insertBefore(dragging, after);
              }
            });

            // アむテムのプレビュヌ移動DOM
            list.addEventListener('dragover', ev => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return; // セクションD&Dは無芖
              ev.preventDefault(); ev.stopPropagation();
              /* ▌▌▌ ここでフォルダヌや背景のハむラむトを匷制的に消す ▌▌▌ */
              document.querySelectorAll('.adv-folder[data-drop="1"]').forEach(el => delete el.dataset.drop);
              document.querySelectorAll('.adv-bg-drop-active').forEach(el => el.classList.remove('adv-bg-drop-active'));
              const dragging = document.querySelector('.adv-item.dragging');
              if (!dragging) return;
              const after = getDragAfterElement(list, ev.clientY);
              if (after == null) list.appendChild(dragging);
              else list.insertBefore(dragging, after);
            });

            // ▌「未分類化」ハンドラセクション背景甚
            // フォルダからドロップされた堎合に "先頭に移動" させる。
            const dropToUnassign = (ev) => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return;
              ev.preventDefault(); ev.stopPropagation();
              const draggedId = ev.dataTransfer.getData('text/plain');
              if (draggedId) onUnassign(draggedId); // onUnassign は "先頭に移動" する
            };

            // ▌「未分類アむテムの䞊び替え」ハンドラリスト本䜓甚
            // 未分類リスト内での䞊び替え、たたはフォルダから特定䜍眮ぞのドロップ。
            const dropToReorderUnassigned = (ev) => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return;
              ev.preventDefault(); ev.stopPropagation();
              const draggedId = ev.dataTransfer.getData('text/plain');
              if (!draggedId) return;

              // 1. DOMの芖芚的な順序dragoverで倉曎枈みをID配列ずしお読み取る
              const newOrderIdsInList = [...list.querySelectorAll('.adv-item')].map(el => el.dataset.id);

              // 2. マスタヌリスト党アむテムずフォルダ内アむテムの情報をロヌド
              const allItems = loadItems();
              const allItemsMap = new Map(allItems.map(it => [it.id, it]));
              const allFolderItems = new Set(folders.flatMap(f => f.order));

              // 3. 新しいマスタヌリストを構築
              const nextMasterList = [];
              const seen = new Set();

              // 3a. たず、DOMから読み取った「未分類の新しい順序」でアむテムを远加
              for (const id of newOrderIdsInList) {
                // このリストにあるべきアむテムマスタヌに存圚し、フォルダに属さないのみ
                if (id && allItemsMap.has(id) && !allFolderItems.has(id)) {
                  nextMasterList.push(allItemsMap.get(id));
                  seen.add(id);
                }
              }

              // 3b. 次に、残りのアむテム党フォルダ内のアむテム䜕らかの理由で挏れた未分類アむテムを远加
              // これにより、マスタヌリストの順序は「未分類の䞊び替え順」「それ以倖」ずなる
              for (const item of allItems) {
                if (!seen.has(item.id)) {
                  nextMasterList.push(item);
                }
              }

              // 4. マスタヌリストを保存
              saveItems(nextMasterList);

              // 5. もしアむテムがフォルダから移動しおきた堎合、フォルダから削陀クリヌンアップ
              const fs = loadFoldersFn(foldersKey, defaultFolderName);
              let folderChanged = false;
              for (const f of fs) {
                const before = f.order.length;
                f.order = f.order.filter(id => id !== draggedId);
                if (f.order.length !== before) { f.ts = Date.now(); folderChanged = true; }
              }

              if (folderChanged) {
                saveFoldersFn(foldersKey, fs);
                // フォルダ構成が倉わった堎合は、リスト党䜓を再描画
                showToast(i18n.t('toastReordered'));
                renderFolderedCollection(cfg);
              } else {
                // 未分類内での移動だけなら再描画は䞍芁DOMは曎新枈み
                showToast(i18n.t('toastReordered'));
              }
            };

            // â–Œ リスト本䜓には「䞊び替え」を、セクション背景には「未分類化」を割り圓おる
            list.addEventListener('drop', dropToReorderUnassigned);
            sec.addEventListener('dragover', ev => { if (!(ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME))) { ev.preventDefault(); ev.stopPropagation(); }});
            sec.addEventListener('drop', dropToUnassign);

            sec.appendChild(list);
            return sec;
          };

          // 10) フォルダセクション
          const renderFolderSection = (folder) => {
            const section = document.createElement('section');
            section.className = 'adv-folder';
            section.dataset.folderId = folder.id;
            if (folder.collapsed) section.classList.add('adv-folder-collapsed');

            const header = document.createElement('div');
            header.className = 'adv-folder-header';
            header.setAttribute('draggable', 'true');

            const toggleBtn = renderFolderToggleButton(!!folder.collapsed);
            const titleWrap = document.createElement('div'); titleWrap.className = 'adv-folder-title';
            titleWrap.appendChild(toggleBtn);
            const nameEl = document.createElement('strong'); nameEl.textContent = folder.name; titleWrap.appendChild(nameEl);
            const countEl = document.createElement('span'); countEl.className='adv-item-sub'; countEl.textContent = `(${folder.order.length})`;
            titleWrap.appendChild(countEl);

            const actions = document.createElement('div');
            actions.className = 'adv-folder-actions';
            actions.innerHTML = `
              <button class="adv-chip"        data-action="rename"  title="${i18n.t('folderRenameTitle')}">${i18n.t('folderRename')}</button>
              <button class="adv-chip danger" data-action="delete"  title="${i18n.t('folderDeleteTitle')}">${i18n.t('folderDelete')}</button>
            `;

            header.appendChild(titleWrap);
            header.appendChild(actions);

            // セクションD&D
            const SECT_MIME = 'adv/folder';
            header.addEventListener('dragstart', (ev) => {
              if (ev.target && (ev.target.closest('.adv-folder-actions') || ev.target.closest('.adv-folder-toggle-btn'))) { ev.preventDefault(); return; }
              ev.dataTransfer.setData(SECT_MIME, folder.id);
              ev.dataTransfer.effectAllowed = 'move';
              section.classList.add('dragging-folder');
            });
            header.addEventListener('dragend', () => section.classList.remove('dragging-folder'));
            section.addEventListener('dragover', (ev) => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) {
                ev.preventDefault();
                ev.stopPropagation();
                const dragging = host.querySelector('.dragging-folder');
                if (!dragging || dragging === section) return;
                const after = getSectionAfterElement(host, ev.clientY);
                if (after == null) host.appendChild(dragging);
                else host.insertBefore(dragging, after);
              } else {
                 ev.preventDefault();
                 ev.stopPropagation(); // これで「枠線」に乗った時に背景が光るのを防ぐ
                 // ここでは section.dataset.drop='1' はしない䞭身のリストに入った時に光らせたいので
                 // もし枠線でも光らせたい堎合はここに dataset.drop='1' を曞いおもOK
              }
            });

            // 折りたたみ
            const collapseToggle = () => {
              section.classList.toggle('adv-folder-collapsed');
              const all = loadFoldersFn(foldersKey, defaultFolderName);
              const f = all.find(x => x.id === folder.id);
              if (f) { f.collapsed = section.classList.contains('adv-folder-collapsed'); f.ts = Date.now(); saveFoldersFn(foldersKey, all); }
              updateFolderToggleButton(toggleBtn, !!section.classList.contains('adv-folder-collapsed'));
            };
            toggleBtn.addEventListener('click', (e)=>{ e.stopPropagation(); collapseToggle(); });
            toggleBtn.addEventListener('keydown', (e)=>{ if (e.key===' '||e.key==='Enter'){ e.preventDefault(); collapseToggle(); } });

            // Rename / Delete
            actions.querySelector('[data-action="rename"]').addEventListener('click', ()=>{
              const nm = prompt(i18n.t('promptNewFolder'), folder.name);
              if (!nm || !nm.trim()) return;
              const fArr = loadFoldersFn(foldersKey, defaultFolderName);
              const f = fArr.find(x=>x.id===folder.id); if (!f) return;
              f.name = nm.trim(); f.ts = Date.now(); saveFoldersFn(foldersKey, fArr);
              renderFolderedCollection(cfg); showToast(i18n.t('updated'));
            });
            actions.querySelector('[data-action="delete"]').addEventListener('click', ()=>{
              if (!confirm(i18n.t('confirmDeleteFolder'))) return;

                // 1. 削陀察象のアむテムIDセットを取埗
                const itemsToDelete = new Set(folder.order || []);

                // 2. アむテムのマスタヌリストから該圓アむテムを削陀
                if (itemsToDelete.size > 0) {
                    try {
                        const allItems = loadItems(); // 芪スコヌプの loadItems を䜿甚
                        const nextItems = allItems.filter(item => !itemsToDelete.has(item.id));
                        saveItems(nextItems); // 芪スコヌプの saveItems を䜿甚
                    } catch (e) {
                        console.error('Failed to delete items in folder:', e);
                        // アむテム削陀に倱敗しおも、フォルダ削陀は続行
                    }
                }

              // 3. フォルダ自䜓を削陀
              let fArr = loadFoldersFn(foldersKey, defaultFolderName);
              const idx = fArr.findIndex(x=>x.id===folder.id); if (idx<0) return;
              fArr.splice(idx,1);
              saveFoldersFn(foldersKey, fArr);

              // 4. 再描画
              renderFolderedCollection(cfg); showToast(i18n.t('toastDeleted'));
            });

            // フォルダ芋出しにドロップ → そのフォルダぞ移動
            header.addEventListener('dragover', ev => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return;
              ev.preventDefault();
              ev.stopPropagation();
              /* ▌▌▌ 背景の砎線を匷制的に消す ▌▌▌ */
              document.querySelectorAll('.adv-bg-drop-active').forEach(el => el.classList.remove('adv-bg-drop-active'));
              // 排他制埡: 他のフォルダのハむラむトを消す
              document.querySelectorAll('.adv-folder[data-drop="1"]').forEach(el => {
                if (el !== section) delete el.dataset.drop;
              });
              section.dataset.drop='1';
            });
            header.addEventListener('dragleave', (ev) => {
              // 子芁玠ぞの移動でも䞀旊消すが、dragoverですぐ埩掻する
              delete section.dataset.drop;
            });
            header.addEventListener('drop', ev => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return;
              ev.preventDefault(); delete section.dataset.drop;
              const draggedId = ev.dataTransfer.getData('text/plain');
              if (!draggedId) return;
              onMoveToFolder(draggedId, folder.id);
            });

            // リスト本䜓
            const list = document.createElement('div'); list.className = 'adv-list';
            const itemsInFolder = folder.order.map(id => idToItem[id]).filter(Boolean).filter(matchItem);
            itemsInFolder.forEach(it => list.appendChild(renderRow(it)));

            // 䞊びプレビュヌ
            list.addEventListener('dragover', ev => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return; // ガヌド远加
              ev.preventDefault();
              ev.stopPropagation(); // 䌝播停止も远加

              /* ▌▌▌ 背景の砎線を匷制的に消す ▌▌▌ */
              document.querySelectorAll('.adv-bg-drop-active').forEach(el => el.classList.remove('adv-bg-drop-active'));

              // 排他制埡: 他のフォルダのハむラむトを消す
              document.querySelectorAll('.adv-folder[data-drop="1"]').forEach(el => {
                if (el !== section) delete el.dataset.drop;
              });
              section.dataset.drop='1';

              const dragging = document.querySelector('.adv-item.dragging');
              if (!dragging) return;
              const after = getDragAfterElement(list, ev.clientY);
              if (after == null) list.appendChild(dragging);
              else list.insertBefore(dragging, after);
            });

            list.addEventListener('dragleave', ev => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return;
              ev.stopPropagation();
              // 子芁玠ぞの移動でも䞀旊消すが、dragoverですぐ埩掻する
              delete section.dataset.drop;
            });

            // 䞊び確定か぀別フォルダ→このフォルダぞの“移動”も吞収
            list.addEventListener('drop', (ev) => {
              if (ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME)) return; // ガヌド远加
              ev.preventDefault(); ev.stopPropagation();
              delete section.dataset.drop;
              const draggedId = ev.dataTransfer.getData('text/plain');
              if (!draggedId) return;

              const newOrder = [...list.querySelectorAll('.adv-item')].map(el => el.dataset.id);

              const fArr = loadFoldersFn(foldersKey, defaultFolderName);
              const f = fArr.find(x=>x.id===folder.id);
              if (!f) return;

              const isMove = !f.order.includes(draggedId);
              if (isMove) {
                for (const f_other of fArr) {
                  if (f_other.id === folder.id) continue;
                  const o_before = f_other.order.length;
                  f_other.order = f_other.order.filter(id => id !== draggedId);
                  if (f_other.order.length !== o_before) f_other.ts = Date.now();
                }
              }

              f.order = newOrder;
              f.ts = Date.now();
              saveFoldersFn(foldersKey, fArr);
              showToast(i18n.t('toastReordered'));

              if (isMove) renderFolderedCollection(cfg);
            });

            section.appendChild(header);
            section.appendChild(list);
            return section;
          };

          // 11) 単䞀衚瀺かALL衚瀺か
          const order = (filterFolder !== '__ALL__')
            ? (filterFolder === '__UNASSIGNED__' ? ['__UNASSIGNED__'] : foldersToDraw.map(f => f.id))
            : buildSectionsOrder();

          order.forEach(id => {
            if (id === '__UNASSIGNED__') host.appendChild(renderUnassignedSection());
            else {
              const f = folders.find(x => x.id === id);
              if (f) host.appendChild(renderFolderSection(f));
            }
          });

          if (!host._advFolderDropAttached) { // 倚重登録防止フラグ
              host._advFolderDropAttached = true;

              host.addEventListener('drop', (ev) => {
                  const SECT_MIME = 'adv/folder';
                  if (!(ev.dataTransfer.types && ev.dataTransfer.types.includes(SECT_MIME))) {
                      // アむテムのドロップ (text/plain) は他のリスナヌが凊理するため無芖
                      return;
                  }

                  // セクション䞊び替え (adv/folder) の drop むベント
                  const sectionEl = ev.target.closest('.adv-folder, .adv-unassigned');

                  // むベントが host (コンテナ) たたはその盎䞋の子セクションで発生した堎合のみ凊理
                  if (ev.target === host || (sectionEl && sectionEl.parentElement === host)) {
                      ev.preventDefault();
                      ev.stopPropagation();

                      // dragover で DOM は既に入れ替わっおいるはず
                      persistSectionsFromDOM(); // DOMの珟圚の順序を保存

                      // 保存埌に再描画
                      renderFolderedCollection(cfg);
                  }
              });
          }
        }

        // タブ䞊び替え氎平甚のヘルパヌ
        const getDragAfterElementHorizontal = (container, x, selector) => {
            const els = [...container.querySelectorAll(`${selector}:not(.dragging)`)];
            let closest = { offset: Number.NEGATIVE_INFINITY, element: null };
            for (const el of els) {
                const box = el.getBoundingClientRect();
                // 氎平方向の䞭心からのオフセットを蚈算
                const offset = x - box.left - box.width / 2;
                // 挿入すべき「次の芁玠」オフセットがマむナスで最も0に近いを探す
                if (offset < 0 && offset > closest.offset) {
                    closest = { offset, element: el };
                }
            }
            return closest.element;
        };

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

        // テキスト内のURLをリンク化するHTML゚スケヌプ枈みテキストに察しお適甚
        function safeLinkify(text) {
            if (!text) return '';
            let escaped = escapeHTML(text);

            // Xの仕様で https:// の盎埌に䞍可芖な空癜や改行が含たれる堎合があるため陀去
            // これにより "https:// amzn.to" が "https://amzn.to" に結合され、党䜓が正しくリンク化されたす
            escaped = escaped.replace(/(https?:\/\/)\s+/gi, '$1');

            // URL正芏衚珟
            // Group 1: http/https/www で始たるURL
            // Group 2: プロトコルなしのドメむン (誀怜知防止の埌読み付き)
            const urlRegex = /((?:https?:\/\/|www\.)[^\s]+)|((?<![@\w.:/\-])\b[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}(?:\/[^\s]*)?)/gi;

            return escaped.replace(urlRegex, (match) => {
                let cleanUrl = match;
                let suffix = '';
                const trailingMatch = cleanUrl.match(/[.,;:)\]]+$/);
                if (trailingMatch) {
                    suffix = trailingMatch[0];
                    cleanUrl = cleanUrl.slice(0, -suffix.length);
                }

                let href = cleanUrl;
                if (!href.match(/^(?:https?:|:\/\/)/i)) {
                     href = 'https://' + href;
                }

                return `<a href="${href}" target="_blank" rel="noopener noreferrer" class="adv-content-link">${cleanUrl}</a>${suffix}`;
            });
        }

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

        function parseSearchTokens(queryOrURL) {
          // 0) ク゚リ取埗URL→怜玢ボックス→モヌダルの順でフォヌルバック
          let qRaw = '';
          try {
            if (queryOrURL) {
              qRaw = String(queryOrURL);
            } else {
              const u = new URL(location.href);
              qRaw = u.searchParams.get('q') || '';
            }
          } catch (_) {}
          if (!qRaw) {
            // â–Œ 耇数圢に倉曎
            const inputs = typeof getActiveSearchInputs === 'function' ? getActiveSearchInputs() : [];
            const si = inputs[0]; // 代衚ずしお最初のものを䜿う
            if (si?.value) qRaw = si.value;
          }
          if (!qRaw && typeof buildQueryStringFromModal === 'function') {
            qRaw = buildQueryStringFromModal() || '';
          }

          // 取埗したク゚リ文字列がキャッシュず同䞀なら、パヌスせずキャッシュを返す
          if (__cachedSearchQuery === qRaw && __cachedSearchTokens) {
              return __cachedSearchTokens;
          }
          // ク゚リが異なるため、パヌスを続行
          __cachedSearchQuery = qRaw; // 新しいク゚リをキャッシュ
          __cachedSearchTokens = null; // 叀いトヌクンを砎棄パヌス倱敗に備える

          // 正芏化%xx/スマヌト匕甚/空癜敎圢
          const rawNorm0 = normalizeForParse(qRaw);
          let q = ` ${rawNorm0} `;

          // 1) 陀倖語-xxxを控えおのちに差し匕く
          const NEG = [];
          (q.match(/\s-\S+/g) || []).forEach(w => NEG.push(w.trim().slice(1)));

          // 2) ORグルヌプ括匧を先に抜き出し匕甚を含む簡易察応
          const orGroups = [];
          const groupRegex = /\((?:[^()"]+|"[^"]*")+\)/g;
          let groupMatch;
          while ((groupMatch = groupRegex.exec(q)) !== null) {
            const inner = groupMatch[0].slice(1, -1); // (...) 䞭身
            const parts = inner.split(/\s+OR\s+/i).map(s => s.trim()).filter(Boolean);
            if (parts.length >= 2) {
              const tokens = parts.flatMap(p => tokenizeQuotedWords(p)).filter(Boolean);
              if (tokens.length) orGroups.push(tokens);
            }
          }
          // グルヌプは䞞ごず削る以降の抜出を安定化
          q = q.replace(groupRegex, ' ');

          // 3) 玔粋トップレベルOR括匧なし怜出䟋`foo OR "bar baz" OR #tag`
          const pureOr = splitTopLevelOR(rawNorm0);
          let pureOrTokens = [];
          if (pureOr && isPureORQuery(rawNorm0)) {
            pureOrTokens = pureOr.flatMap(p => tokenizeQuotedWords(p)).filter(Boolean);
            if (pureOrTokens.length >= 2) {
              orGroups.push(pureOrTokens);
              // 玔粋ORは required には入れない埌で words から陀倖
            }
          }

          // 4) 匕甚フレヌズを抜出exactはAND盞圓ずしお扱う
          const phrases = [];
          q = q.replace(/"([^"]+)"/g, (_m, p1) => {
            if (p1 && (p1 = p1.trim())) phrases.push(p1);
            return ' ';
          });

          // 5) ハッシュタグ抜出
          const hashtags = [];
          q = q.replace(/\s#([^\s)"]+)/g, (_m, p1) => {
            const tag = '#' + p1;
            hashtags.push(tag);
            return ' ';
          });

          // 6) from:/to:/@陀倖ではないもの→ 䟋倖刀定甚 opUsers
          const opUsers = new Set();
          rawNorm0.replace(/(?:^|\s)(?:from:|to:|@)([^\s()]+)/g, (m, user) => {
            // 盎前が "-" の吊定挔算子なら陀倖䟋: "-from:foo"
            if (!/^\s*-/.test(m)) {
              opUsers.add(String(user || '').toLowerCase());
            }
            return m;
          });

          // 7) 蚀語/最小倀/日付/フィルタ/アカりント挔算子などを q から陀去
          q = q
            .replace(/\s(?:lang|min_replies|min_faves|min_retweets|since|until):[^\s]+/gi, ' ')
            .replace(/\s(?:is:verified|filter:(?:links|images|videos|replies)|include:replies|-filter:replies)\b/gi, ' ')
            .replace(/\s(?:from:|to:|@)[^\s()]+/gi, ' ')
            .replace(/[()]/g, ' ')
            .replace(/\bOR\b/gi, ' ');

          // 8) 残りを単語化句読点剥がし。#は枩存枈み
          const trimPunctKeepHash = (s) => {
            if (!s) return '';
            if (s.startsWith('#')) return s;
            return s.replace(/^[\p{P}\p{S}]+/gu, '').replace(/[\p{P}\p{S}]+$/gu, '');
          };

          let words = q
            .split(/\s+/)
            .map(s => s.trim())
            .filter(Boolean)
            .map(trimPunctKeepHash)
            .filter(Boolean);

          // 9) NEG を差し匕く
          const normalize = (s) => String(s || '').toLowerCase();
          const NEGnorm = NEG.map(normalize);

          // 10) 玔粋ORで拟ったトヌクンは AND 候補から先に陀倖重耇/衝突を避ける
          if (pureOrTokens.length) {
            const pureSet = new Set(pureOrTokens.map(t => t.toLowerCase()));
            const stripQuote = (s) => s.replace(/^"(.*)"$/, '$1').toLowerCase();
            words = words.filter(w => !pureSet.has(stripQuote(w)));
          }

          // 11) requiredAND盞圓を構成フレヌズ + ハッシュタグ + 通垞語
          const requiredTermsArr = [
            ...phrases,
            ...hashtags,
            ...words.filter(w => !NEGnorm.includes(normalize(w))),
          ];

          // 12) includeTerms埓来互換required + OR党トヌクン平坊化
          const includeTerms = new Set([
            ...requiredTermsArr,
            ...orGroups.flatMap(g => g),
          ]);

          // 13) hashtagSet
          const hashtagSet = new Set(
            hashtags.map(h => h.startsWith('#') ? h : ('#' + h)).map(normalize)
          );

          // 14) 返华requiredはSet、orGroupsは配列の配列
          const result = {
            requiredTerms: new Set(requiredTermsArr),
            orGroups,                  // [ ['ente','セヌル'], ['foo','bar'] , ... ]
            includeTerms,              // AND/ORすべおを平坊化した包含語集合
            opUsers,
            hashtagSet,
          };

          __cachedSearchTokens = result; // パヌス結果をキャッシュに保存
          return result;
        }

        function pickTweetFields(article) {
            // 1. 本文の取埗
            const bodyEl = article.querySelector('[data-testid="tweetText"]');
            const body = bodyEl ? bodyEl.innerText : '';

            let disp = '';
            let handle = '';

            try {
                // 2. ナヌザヌ情報゚リア (User-Name) を取埗
                // 共有いただいたDOMでは、ここに衚瀺名ずハンドル(@xxx)の䞡方が含たれおいたす
                const userRow = article.querySelector('[data-testid="User-Name"]');

                if (userRow) {
                    // User-Name内のすべおの「リンク」たたは「テキストコンテナ」をチェック
                    // 共有DOMでは aタグの䞭に span がある構造です
                    const anchors = Array.from(userRow.querySelectorAll('a[href^="/"], div[dir="ltr"] span'));

                    for (const node of anchors) {
                        // テキストを取埗前埌の空癜を陀去
                        const text = node.innerText.trim();

                        // 空文字、たたは時間衚瀺の区切り蚘号「·」などは無芖
                        if (!text || text === '·') continue;

                        // â–Œ 刀定ロゞック: テキストが '@' で始たるならハンドル、そうでなければ衚瀺名
                        if (text.startsWith('@')) {
                            // ハンドルが芋぀かった (@を陀去しお保存)
                            handle = text.replace(/^@/, '');
                        } else {
                            // ただ衚瀺名がセットされおいなければ、これを衚瀺名ずする
                            // (怜蚌枈みアカりントのアむコンなどがテキストずしお混ざるのを防ぐため、ある皋床の長さチェックを入れおも良いが、基本はこのたたでOK)
                            if (!disp) {
                                disp = text;
                            }
                        }
                    }

                    // フォヌルバック: 䞊蚘で芋぀からなかった堎合、User-Name盎䞋の党テキストから解析
                    if (!handle) {
                        const allText = userRow.innerText.split('\n');
                        for (const t of allText) {
                            const trimT = t.trim();
                            if (trimT.startsWith('@')) {
                                handle = trimT.replace(/^@/, '');
                            } else if (!disp && trimT && trimT !== '·') {
                                disp = trimT;
                            }
                        }
                    }
                }
            } catch(e) {
                console.error('[pickTweetFields] Error parsing user info:', e);
            }

            // 3. 返信先ハンドルの取埗 ("Replying to @..." の郚分)
            // 本文や自分の名前以倖で、ヘッダヌ付近にある @リンク を探す
            const replyHandles = Array.from(
                article.querySelectorAll('div[dir="ltr"] a[href^="/"]')
            )
            .filter(a => {
                const txt = (a.innerText || '').trim();
                // @で始たるリンクであるこず
                if (!txt.startsWith('@')) return false;

                // 本文内のメンションは陀倖
                if (bodyEl && bodyEl.contains(a)) return false;

                // 送信者自身のハンドル衚蚘は陀倖
                const userRow = article.querySelector('[data-testid="User-Name"]');
                if (userRow && userRow.contains(a)) return false;

                return true;
            })
            .map(a => a.innerText.trim())
            .filter(Boolean);

            return { body, disp, handle, replyHandles };
        }

        function getTweetCell(article) {
          return article.closest('[data-testid="cellInnerDiv"]') || article;
        }

        /* â–Œ 戻り倀を boolean から string|null (ヒットした単語) に倉曎 */
        function shouldHideTweetByNameHandle(article, flags, tokens) {
          const {
            requiredTerms = new Set(),
            orGroups = [],
            includeTerms = new Set(),
            opUsers,
            hashtagSet
          } = tokens || {};

          if (includeTerms.size === 0) return null; // false -> null

          const { body, disp, handle, replyHandles } = pickTweetFields(article);

          const normSpace = (s) => String(s || '').toLowerCase().replace(/[_.\-]+/g, ' ').replace(/\s+/g, ' ').trim();
          const normId = (s) => String(s || '').replace(/^@/, '').toLowerCase();
          const stripNonAlnum = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9\u00c0-\u024f]+/gi, '');

          const textBody = normSpace(body);
          const textName = normSpace(disp);

          // ハンドル矀の正芏化
          const handlesRaw   = [handle, ...replyHandles].map(normId).filter(Boolean);
          const handlesSpace = handlesRaw.map(normSpace);
          const handlesTok   = handlesSpace.map(h => h.split(' ').filter(Boolean));
          const handlesTight = handlesRaw.map(stripNonAlnum);

          // 本文に珟れた語正芏化枈みを控える
          const inBody = new Set();
          for (const term of includeTerms) {
            const t = normSpace(term);
            if (t && textBody.includes(t)) inBody.add(t);
          }

          const inMeta = new Set();
          const markMetaHit = (tSpace, tTight) => {
            if (tSpace && !inBody.has(tSpace)) inMeta.add(tSpace);
            if (tTight) inMeta.add(tTight);
          };

          // --- 衚瀺名ヒットの蚘録短語ガヌド぀き ---
          if (flags.name) {
            for (const term of includeTerms) {
              const t = normSpace(term);
              if (!t) continue;
              // 2文字以䞋の英字のみは無芖過剰陀倖防止
              if (/^[a-z]{1,2}$/.test(t)) continue;
              if (textName.includes(t) && !inBody.has(t)) {
                markMetaHit(t, null);
              }
            }
          }

          if (flags.handle) {
            for (const term of includeTerms) {
              const raw = String(term || '');
              const rawLC = raw.trim().toLowerCase();
              if (rawLC.startsWith('#') || (hashtagSet && hashtagSet.has(rawLC.startsWith('#') ? rawLC : '#' + rawLC))) continue;

              const bare = raw.replace(/^@/, '').toLowerCase();
              if (opUsers && opUsers.has(bare)) continue; // from:/to:/@ 明瀺は䟋倖

              const tSpace = normSpace(raw);
              const tTight = stripNonAlnum(raw);

              // 短語ガヌド英数のみで長さ<3は無芖
              if (/^[a-z0-9]+$/.test(tTight) && tTight.length < 3) continue;

              // 1) トヌクン䞀臎/連続トヌクン䞀臎
              if (tSpace) {
                const tTokens = tSpace.split(' ').filter(Boolean);
                for (const hTokens of handlesTok) {
                  if (tTokens.length === 1) {
                    if (hTokens.some(tok => tok === tTokens[0]) && !inBody.has(tSpace)) {
                      markMetaHit(tSpace, null);
                      break;
                    }
                  } else {
                    for (let i = 0; i + tTokens.length <= hTokens.length; i++) {
                      let ok = true;
                      for (let j = 0; j < tTokens.length; j++) {
                        if (hTokens[i + j] !== tTokens[j]) { ok = false; break; }
                      }
                      if (ok && !inBody.has(tSpace)) {
                        markMetaHit(tSpace, null);
                        break;
                      }
                    }
                  }
                }
              }

              // 2) 非英数字陀去の完党䞀臎郚分䞀臎は䞍可
              if (tTight && handlesTight.some(h => h === tTight) && !(tSpace && inBody.has(tSpace))) {
                markMetaHit(tSpace, tTight);
              }
            }
          }

          // === 最終刀定: マッチした単語を返す ===
          for (const t of requiredTerms) {
            const s = normSpace(t);
            // 本文になく、メタ情報(名前/ID)でのみヒットした堎合、その単語を返す
            if (s && !inBody.has(s) && (inMeta.has(s) || inMeta.has(stripNonAlnum(t)))) {
              return t;
            }
          }

          for (const group of orGroups) {
            let anyBody = false;
            let metaHitWord = null;
            for (const w of group) {
              const s = normSpace(w);
              const tight = stripNonAlnum(w);
              if (s && inBody.has(s)) anyBody = true;
              if ((s && inMeta.has(s)) || (tight && inMeta.has(tight))) {
                  if (!metaHitWord) metaHitWord = w;
              }
            }
            if (!anyBody && metaHitWord) return metaHitWord;
          }

          return null;
        }

        // ▌▌▌ 再ミュヌトボタンの泚入/削陀ロゞック ▌▌▌
        function injectRemuteButton(article, triggerWord, onRemute) {
            // 既存があれば䜕もしない
            if (article.querySelector('.adv-btn-remute')) return;

            // 1. たずGrokボタンを探す (蚀語䟝存察策で "Grok" を含むラベルを怜玢)
            const grokBtn = article.querySelector('button[aria-label*="Grok"]');
            // 2. なければCaret(
)ボタンを探す
            const caretBtn = article.querySelector('[data-testid="caret"]');

            // 挿入基準ずなるボタンを決定Grok優先、なければCaret
            const targetBtn = grokBtn || caretBtn;
            if (!targetBtn) return;

            const btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'adv-btn-remute';

            // ラベルの蚭定
            btn.textContent = i18n.t('buttonRemute');
            btn.title = i18n.t('buttonRemute') + (triggerWord ? ` (${triggerWord})` : '');

            // クリックむベント
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                e.preventDefault();
                if (onRemute) onRemute();
            });

            // タヌゲットずなるボタン(Grok たたは Caret)の盎前に挿入する
            if (targetBtn.parentElement) {
                targetBtn.parentElement.insertBefore(btn, targetBtn);
            }
        }

        function removeRemuteButton(article) {
            const btn = article.querySelector('.adv-btn-remute');
            if (btn) btn.remove();
        }

        /* â–Œ evaluateTweetForFiltering: triggerWord を特定しお衚瀺に䜿甚 (Full Code) */
        function evaluateTweetForFiltering(art, flags, muteSettings, tokens) {
            const cell = getTweetCell(art);
            const reasons = [];
            let tweetBodyText = null;
            let triggerWord = ''; // ★ヒットした単語を保持

            const { hasMute, muteCI, muteCS, muteMode } = muteSettings;

            // 1. 名前/ハンドル陀倖
            if ((flags.name || flags.handle) && tokens) {
                const hitWord = shouldHideTweetByNameHandle(art, flags, tokens);
                if (hitWord) {
                    reasons.push('name_handle_only');
                    if (!triggerWord) triggerWord = hitWord; // ヒット語句を蚘録
                }
            }

            // 2. ミュヌトワヌド陀倖
            if (hasMute) {
                tweetBodyText = tweetBodyText ?? (art.querySelector('[data-testid="tweetText"]')?.innerText || '');
                const bodyCI = tweetBodyText.toLowerCase();
                let hideByMute = false;

                // A. 単玔䞀臎 (Case Insensitive)
                if (muteSettings.simpleCI && muteSettings.simpleCI.size > 0) {
                    for (const w of muteSettings.simpleCI) {
                        if (bodyCI.includes(w)) {
                            hideByMute = true;
                            if (!triggerWord) triggerWord = w;
                            break;
                        }
                    }
                }
                // B. 単玔䞀臎 (Case Sensitive)
                if (!hideByMute && muteSettings.simpleCS && muteSettings.simpleCS.size > 0) {
                    for (const w of muteSettings.simpleCS) {
                        if (tweetBodyText.includes(w)) {
                            hideByMute = true;
                            if (!triggerWord) triggerWord = w;
                            break;
                        }
                    }
                }
                // C. 正芏衚珟/単語単䜍 (wb=true)
                if (!hideByMute && muteSettings.regexRules && muteSettings.regexRules.length > 0) {
                    for (const rule of muteSettings.regexRules) {
                        // rule.rx は (?:^|[^a-zA-Z0-9_])word(?:$|[^a-zA-Z0-9_]) の圢
                        if (rule.rx.test(tweetBodyText)) {
                            hideByMute = true;
                            if (!triggerWord) triggerWord = rule.word;
                            break;
                        }
                    }
                }

                if (hideByMute) reasons.push('muted_word');
            }

            // 3. リポスト陀倖
            if (flags.reposts) {
                const socialContext = art.querySelector('[data-testid="socialContext"]');
                if (socialContext) {
                    const pinIconPath = 'M7 4.5C7 3.12 8.12 2 9.5 2h5C15.88 2 17 3.12 17 4.5v5.26L20.12 16H13v5l-1 2-1-2v-5H3.88L7 9.76V4.5z';
                    const isPinned = art.querySelector(`svg path[d="${pinIconPath}"]`);
                    if (!isPinned) {
                        reasons.push('repost');
                        if (!triggerWord) triggerWord = 'Repost';
                    }
                }
            }

            // 4. ハッシュタグ陀倖
            if (flags.hashtags) {
                tweetBodyText = tweetBodyText ?? (art.querySelector('[data-testid="tweetText"]')?.innerText || '');
                if (tweetBodyText.includes('#')) {
                    reasons.push('hashtag');
                    if (!triggerWord) {
                        // 最初のハッシュタグを抜出しお衚瀺
                        const m = tweetBodyText.match(/#[^\s\u3000]+/);
                        triggerWord = m ? m[0] : '#Hashtag';
                    }
                }
            }

            // ▌▌▌ 最終刀定 & UI制埡 ▌▌▌
            if (reasons.length > 0) {
                // Case A: ミュヌト察象だが、ナヌザヌが既に「衚瀺する」を抌しおいる堎合
                if (art.dataset.advMutedShown === '1') {
                    // コンテンツは隠さない
                    cell.removeAttribute('data-adv-hidden');
                    cell.removeAttribute('data-adv-collapsed');

                    // その代わり、ヘッダヌに「再ミュヌト」ボタンを泚入
                    injectRemuteButton(art, triggerWord, () => {
                        // 再ミュヌトクリック時の凊理
                        delete art.dataset.advMutedShown; // フラグを消す
                        // 再垰呌び出ししお即座に隠す
                        evaluateTweetForFiltering(art, flags, muteSettings, tokens);
                    });

                } else {
                    // Case B: ミュヌト察象で、ただ隠れおいる堎合
                    removeRemuteButton(art); // ボタンがあれば消す念のため

                    // 「ミュヌトワヌド(muted_word)」以倖の理由が含たれおいるか刀定
                    // 含たれおいる堎合(isHardHide = true)は、蚭定が「折りたたみ」でも匷制的に「非衚瀺」にする
                    const isHardHide = reasons.some(r => r !== 'muted_word');

                    if (!isHardHide && muteMode === 'collapsed') {
                        // [折りたたみモヌド] (ミュヌトワヌドのみヒットした堎合)
                        cell.removeAttribute('data-adv-hidden');
                        cell.setAttribute('data-adv-collapsed', reasons.join(' '));

                        let ph = cell.querySelector('.adv-collapsed-placeholder');
                        if (!ph) {
                            ph = document.createElement('div');
                            ph.className = 'adv-collapsed-placeholder';

                            // ここで triggerWord を衚瀺する
                            ph.innerHTML = `
                                <div class="adv-collapsed-label">
                                    <span style="opacity:0.8">${i18n.t('muteLabel')} ${escapeHTML(triggerWord)}</span>
                                </div>
                                <button class="adv-btn-show">${i18n.t('buttonShow')}</button>
                            `;

                            const uncollapse = (e) => {
                                e.stopPropagation();
                                e.preventDefault();
                                art.dataset.advMutedShown = '1';
                                evaluateTweetForFiltering(art, flags, muteSettings, tokens);
                            };
                            ph.addEventListener('click', uncollapse);
                            ph.querySelector('button').addEventListener('click', uncollapse);

                            cell.appendChild(ph);
                        } else {
                            const labelEl = ph.querySelector('.adv-collapsed-label span');
                            if (labelEl) labelEl.innerHTML = `${i18n.t('muteLabel')} ${escapeHTML(triggerWord)}`;
                        }
                    } else {
                        // [完党非衚瀺モヌド] (Hard Hide たたは hidden蚭定)
                        cell.removeAttribute('data-adv-collapsed');
                        cell.setAttribute('data-adv-hidden', reasons.join(' '));
                    }
                }
            } else {
                // Case C: ミュヌト察象ではない
                delete art.dataset.advMutedShown; // 䞍芁なフラグは掃陀
                cell.removeAttribute('data-adv-hidden');
                cell.removeAttribute('data-adv-collapsed');
                removeRemuteButton(art);
            }
        }

        // â–Œ ミュヌト蚭定倉曎時などに、党ツむヌトを匷制再スキャンする
        function rescanAllTweetsForFilter() {
            try {
                const flags = {
                    name:   document.getElementById('adv-exclude-hit-name')?.checked ?? true,
                    handle: document.getElementById('adv-exclude-hit-handle')?.checked ?? true,
                    reposts: document.getElementById('adv-filter-reposts-exclude')?.checked ?? false,
                    hashtags: document.getElementById('adv-filter-hashtags-exclude')?.checked ?? false,
                };

                const masterOn = loadMuteMaster();
                const muteMode = loadMuteMode(); // モヌド読み蟌み
                const muted = loadMuted();
                const hasMute = masterOn && muted.length > 0;
                // 正芏衚珟ルヌルず単玔䞀臎ルヌルを準備
                const regexRules = [];
                const simpleCI = new Set();
                const simpleCS = new Set();

                if (hasMute) {
                    muted.filter(m => m.enabled !== false).forEach(m => {
                        if (m.wb) {
                            // 単語単䜍(Word Boundary)の堎合は正芏衚珟を䜜成
                            // #ad -> (?:^|[^a-zA-Z0-9_])#ad(?:$|[^a-zA-Z0-9_]) ずいうパタヌンを生成しお
                            // 前埌に英数字(ずアンダヌスコア)がないこずを確認する
                            const flags = m.cs ? '' : 'i';
                            const esc = escapeRegExp(m.word);
                            // 英数字以倖を境界ずする
                            const pattern = `(?:^|[^a-zA-Z0-9_])${esc}(?:$|[^a-zA-Z0-9_])`;
                            regexRules.push({ rx: new RegExp(pattern, flags), word: m.word });
                        } else {
                            // 郚分䞀臎の堎合は高速なSet/Includesを䜿甚
                            if (m.cs) simpleCS.add(m.word);
                            else simpleCI.add(m.word.toLowerCase());
                        }
                    });
                }

                const muteSettings = {
                    hasMute,
                    muteMode,
                    regexRules,
                    simpleCI,
                    simpleCS
                };

                // 党お無効なら属性を䞀掃しお終了
                if (!flags.name && !flags.handle && !hasMute && !flags.reposts && !flags.hashtags) {
                    document.querySelectorAll('[data-adv-hidden], [data-adv-collapsed]').forEach(cell => {
                        cell.removeAttribute('data-adv-hidden');
                        cell.removeAttribute('data-adv-collapsed');
                    });
                    cleanupAdjacentSeparators();
                    return;
                }

                const tokens = (flags.name || flags.handle) ? parseSearchTokens() : null;
                // 党ツむヌトを察象
                const list = document.querySelectorAll('article[data-testid="tweet"]');

                for (const art of list) {
                    // 共通関数を呌ぶ
                    evaluateTweetForFiltering(art, flags, muteSettings, tokens);
                }

                cleanupAdjacentSeparators();
            } catch (e) {
                console.error('rescanAllTweetsForFilter failed', e);
            }
        }

        function cleanupAdjacentSeparators() {
          // 既存のたた必芁ならここに区切り線セルの非衚瀺凊理
        }

        const executeSearch = async (scopesOverride) => {
          const finalQuery = buildQueryStringFromModal().trim();
          if (!finalQuery) return;

          const scopes = scopesOverride || readScopesFromControls();
          const params = new URLSearchParams({ q: finalQuery, src: 'typed_query' });
          if (scopes.pf) params.set('pf', 'on');
          if (scopes.lf) params.set('lf', 'on');

          const targetPath = `/search?${params.toString()}`;

          // 1) たず怜玢ボックスが芋぀かれば React state を曎新しお芋た目ず䞭身を同調
          // â–Œ 耇数圢に倉曎し、ルヌプ凊理
          const inputs = getActiveSearchInputs?.() || [];
          if (inputs.length > 0) {
              inputs.forEach(si => {
                  if (si) { syncControlledInput(si, finalQuery); }
              });
          }

          // 2) ルヌトに関わらず垞に SPA 遷移で怜玢を確定
          recordHistory(finalQuery, scopes.pf, scopes.lf);
          const before = location.href;
          try {
            await spaNavigate(targetPath);
            if (window.innerWidth <= 700) {
                closeModal();
            }
          } catch {
            // SPA 倱敗時のフォヌルバック
            location.assign(`https://x.com${targetPath}`);
            return;
          }

          // 3) 遷移が成功したら䜙蚈な replaceState はしないURL ずルヌタヌ state の乖離を避ける
          //    もしフォヌカスが残っおいたら倖す
          // â–Œ ルヌプ凊理
          try { inputs.forEach(si => si && si.blur()); } catch {}

        };

        const onScopeChange = async () => {
        // â–Œ 耇数圢に倉曎
          const inputs = getActiveSearchInputs();
          const si = inputs[0]; // 代衚ずしお最初のものを䜿う
          const q = (() => {
            if (si && si.value && si.value.trim()) return si.value.trim();
            return buildQueryStringFromModal().trim();
          })();

          const { pf, lf } = readScopesFromControls();
          const params = new URLSearchParams({ src: 'typed_query' });
          if (q) params.set('q', q);
          if (pf) params.set('pf', 'on');
          if (lf) params.set('lf', 'on');

          // 入力偎を先に最新化
          // â–Œ ルヌプ凊理
          if (inputs.length > 0) {
              inputs.forEach(input => {
                  if (input) syncControlledInput(input, q);
              });
          }

          recordHistory(q, pf, lf);
          const path = `/search?${params.toString()}`;
          try {
            await spaNavigate(path);
          } catch {
            location.assign(`https://x.com${path}`);
          }
        };
        accountScopeSel.addEventListener('change', onScopeChange);
        locationScopeSel.addEventListener('change', onScopeChange);

        const setupModalDrag = () => {
            const header = modal.querySelector('.adv-modal-header');
            let dragging=false, offset={x:0,y:0};
            header.addEventListener('mousedown', e=>{
                if (e.target.matches('button,a') && !e.target.classList.contains('adv-secret-btn')) return;
                dragging=true;
                const rect = modal.getBoundingClientRect();
                modal.style.right=modal.style.bottom='auto';
                modal.style.left=`${rect.left}px`; modal.style.top=`${rect.top}px`;
                offset = { x:e.clientX-rect.left, y:e.clientY-rect.top };
                document.body.classList.add('adv-dragging');
            });
            document.addEventListener('mousemove', e=>{
                if(!dragging) return;
                let nx = e.clientX - offset.x, ny = e.clientY - offset.y;
                nx=Math.max(0,Math.min(nx,window.innerWidth - modal.offsetWidth));
                ny=Math.max(0,Math.min(ny,window.innerHeight - modal.offsetHeight));
                modal.style.left=`${nx}px`; modal.style.top=`${ny}px`;
            });
            document.addEventListener('mouseup', ()=>{
                if(dragging){ dragging=false; document.body.classList.remove('adv-dragging'); saveModalRelativeState(); }
            });
        };

        const setupModalResize = () => {
            const MIN_W = 300, MIN_H = 240;
            const MARGIN = 10;
            let resizing = null;

            const onPointerDown = (e) => {
                const h = e.target.closest('.adv-resizer');
                if (!h) return;
                e.preventDefault();
                const dir = h.dataset.dir;
                const r = modal.getBoundingClientRect();

                modal.style.right = 'auto';
                modal.style.bottom= 'auto';
                modal.style.left  = `${r.left}px`;
                modal.style.top   = `${r.top}px`;

                resizing = {
                    dir,
                    startX: e.clientX,
                    startY: e.clientY,
                    startLeft: r.left,
                    startTop:  r.top,
                    startW: r.width,
                    startH: r.height
                };
                try { h.setPointerCapture(e.pointerId); } catch(_) {}
                document.body.classList.add('adv-dragging');
            };

            const clamp = (val, min, max) => Math.max(min, Math.min(max, val));

            const onPointerMove = (e) => {
                if (!resizing) return;

                const dx = e.clientX - resizing.startX;
                const dy = e.clientY - resizing.startY;

                let newLeft = resizing.startLeft;
                let newTop  = resizing.startTop;
                let newW    = resizing.startW;
                let newH    = resizing.startH;

                const dir = resizing.dir;

                if (dir.includes('e')) newW = resizing.startW + dx;
                if (dir.includes('w')) { newW = resizing.startW - dx; newLeft = resizing.startLeft + dx; }

                if (dir.includes('s')) newH = resizing.startH + dy;
                if (dir.includes('n')) { newH = resizing.startH - dy; newTop = resizing.startTop + dy; }

                const maxW = window.innerWidth  - 2*MARGIN;
                const maxH = window.innerHeight - 2*MARGIN;

                newW = clamp(newW, MIN_W, maxW);
                newH = clamp(newH, MIN_H, maxH);
                newLeft = clamp(newLeft, MARGIN, Math.max(MARGIN, window.innerWidth  - newW - MARGIN));
                newTop  = clamp(newTop,  MARGIN, Math.max(MARGIN, window.innerHeight - newH - MARGIN));

                modal.style.left   = `${Math.round(newLeft)}px`;
                modal.style.top    = `${Math.round(newTop)}px`;
                modal.style.width  = `${Math.round(newW)}px`;
                modal.style.height = `${Math.round(newH)}px`;
            };

            const onPointerUp = (e) => {
                if (!resizing) return;
                document.body.classList.remove('adv-dragging');
                try { e.target.releasePointerCapture?.(e.pointerId); } catch(_) {}
                resizing = null;
                saveModalRelativeState();
            };

            modal.addEventListener('pointerdown', onPointerDown);
            window.addEventListener('pointermove', onPointerMove);
            window.addEventListener('pointerup',   onPointerUp);
            window.addEventListener('pointercancel', onPointerUp);
        };

        /* ========= Accounts storage & UI ========= */
        function renderAccountRow(item) {
          const row = document.createElement('div');
          row.className = 'adv-item';
          row.draggable = true;
          row.dataset.id = item.id;

          const title = escapeHTML(item.name || `@${item.handle}`);
          const sub   = escapeHTML(`@${item.handle}`);

          row.innerHTML = `
            <div class="adv-item-handle" title="Drag">≡</div>
            ${
              item.avatar
                ? `<a class="adv-item-avatar-link adv-link" href="/${escapeAttr(item.handle)}" title="@${escapeAttr(item.handle)}">
                     <img class="adv-item-avatar" src="${escapeAttr(item.avatar)}" alt="@${escapeAttr(item.handle)}">
                   </a>`
                : `<a class="adv-item-avatar-link adv-link" href="/${escapeAttr(item.handle)}" title="@${escapeAttr(item.handle)}">
                     <div class="adv-item-avatar" aria-hidden="true"></div>
                   </a>`
            }
            <div class="adv-item-main">
              <div class="adv-item-title">
                <a class="adv-link" href="/${escapeAttr(item.handle)}" title="@${escapeAttr(item.handle)}">${title}</a>
              </div>
              <div class="adv-item-sub">
                <a class="adv-link" href="/${escapeAttr(item.handle)}">@${escapeHTML(item.handle)}</a>
                <span>${fmtTime(item.ts)}</span>
              </div>
            </div>
            <div class="adv-item-actions">
              <button class="adv-chip primary" data-action="confirm">${i18n.t('buttonConfirm')}</button>
              <button class="adv-chip danger" data-action="delete">${i18n.t('delete')}</button>
            </div>
          `;

          row.querySelector('[data-action="confirm"]').addEventListener('click', (e) => {
            spaNavigate(`/${item.handle}`, { ctrlMeta: e.ctrlKey || e.metaKey });
            if (window.innerWidth <= 700) {
                closeModal();
            }
          });
          row.querySelectorAll('a.adv-link').forEach(a => {
            a.addEventListener('click', (ev) => {
              if (ev.defaultPrevented || ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey || ev.button !== 0) return;
              ev.preventDefault();
              const href = a.getAttribute('href') || `/${item.handle}`;
              spaNavigate(href, { ctrlMeta: false });
              if (window.innerWidth <= 700) {
                  closeModal();
              }
            });
          });
          row.querySelector('[data-action="delete"]').addEventListener('click', () => deleteAccount(item.id));

          row.addEventListener('dragstart', (ev) => {
            row.classList.add('dragging');
            ev.dataTransfer.setData('text/plain', item.id);
            ev.dataTransfer.effectAllowed = 'move';
          });
          row.addEventListener('dragend', () => row.classList.remove('dragging'));

          return row;
        }

        function renderAccounts() {
          ensureFolderToolbars();

          renderFolderedCollection({
            hostId: 'adv-accounts-list',
            emptyId: 'adv-accounts-empty',
            filterSelectId: 'adv-accounts-folder-filter',
            searchInputId:  'adv-accounts-search',
            newFolderBtnId: 'adv-accounts-new-folder',

            foldersKey: ACCOUNTS_FOLDERS_KEY,
            defaultFolderName: i18n.t('optAccountAll'),

            loadItems: loadAccounts,
            saveItems: saveAccounts,
            renderRow: renderAccountRow,

            onUnassign: unassignAccount,
            onMoveToFolder: moveAccountToFolder,

            emptyMessage: i18n.t('emptyAccounts'),
            unassignedIndexKey: 'advAccountsUnassignedIndex_v1',
          });
        }

        function renderListRow(item) {
          const row = document.createElement('div');
          row.className = 'adv-item';
          row.draggable = true;
          row.dataset.id = item.id;

          const title = escapeHTML(item.name);
          const sub   = escapeHTML(item.url);

          row.innerHTML = `
            <div class="adv-item-handle" title="Drag">≡</div>
            <div class="adv-item-main">
              <div class="adv-item-title">
                <a class="adv-link" href="${escapeAttr(item.url)}">${title}</a>
              </div>
              <div class="adv-item-sub">
                <a class="adv-link" href="${escapeAttr(item.url)}">${sub}</a>
                <span>${fmtTime(item.ts)}</span>
              </div>
            </div>
            <div class="adv-item-actions">
              <button class="adv-chip primary" data-action="confirm">${i18n.t('buttonConfirm')}</button>
              <button class="adv-chip danger" data-action="delete">${i18n.t('delete')}</button>
            </div>
          `;

          row.querySelector('[data-action="confirm"]').addEventListener('click', (e) => {
            spaNavigate(item.url, { ctrlMeta: e.ctrlKey || e.metaKey });
            if (window.innerWidth <= 700) {
                closeModal();
            }
          });
          row.querySelectorAll('a.adv-link').forEach(a => {
            a.addEventListener('click', (ev) => {
              if (ev.defaultPrevented || ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey || ev.button !== 0) return;
              ev.preventDefault();
              const href = a.getAttribute('href') || item.url;
              spaNavigate(href, { ctrlMeta: false });
              if (window.innerWidth <= 700) {
                  closeModal();
              }
            });
          });
          row.querySelector('[data-action="delete"]').addEventListener('click', () => deleteList(item.id));

          row.addEventListener('dragstart', (ev) => {
            row.classList.add('dragging');
            ev.dataTransfer.setData('text/plain', item.id);
            ev.dataTransfer.effectAllowed = 'move';
          });
          row.addEventListener('dragend', () => row.classList.remove('dragging'));

          return row;
        }


        const ACCOUNTS_KEY = 'advAccounts_v1';
        const ACCOUNTS_FOLDERS_KEY = 'advAccountsFolders_v1';
        const LISTS_FOLDERS_KEY    = 'advListsFolders_v1';
        // â–Œ セクションフォルダヌ + Unassignedの䞊び順を氞続化するキヌ
        const SAVED_FOLDERS_KEY    = 'advSavedFolders_v1';

        function loadFolders(key, _defaultName="") {
          const raw = loadJSON(key, null);
          if (raw && Array.isArray(raw.folders)) {
            return raw.folders.map(f => ({
              id: f.id,
              name: f.name,
              order: Array.isArray(f.order) ? f.order : [],
              ts: f.ts || Date.now(),
              collapsed: !!f.collapsed,
            }));
          }
          // 初期は空配列フォルダヌ0件の䞖界
          return [];
        }

        function saveFolders(key, folders) {
          saveJSON(key, { folders: folders.map(f=>({
            id:f.id, name:f.name, order:[...new Set(f.order)], ts:f.ts||Date.now(), collapsed: !!f.collapsed,
          }))});
        }

        function ensureFolderToolbars() {
          // Accounts tab
          {
            const host = document.getElementById('adv-accounts-list');
            const empty = document.getElementById('adv-accounts-empty');
            const target = empty || host; // emptyがあればその前に挿入HTML順序が empty->list なので䞀番䞊になる
            if (target && !target.previousElementSibling?.classList?.contains('adv-folder-toolbar')) {
              const bar = document.createElement('div');
              bar.className = 'adv-folder-toolbar';
              bar.innerHTML = `
                <select id="adv-accounts-folder-filter" class="adv-select"></select>
                <input id="adv-accounts-search" class="adv-input" type="text" data-i18n-placeholder="placeholderFilterAccounts" placeholder="${i18n.t('placeholderFilterAccounts')}">
                <button id="adv-accounts-new-folder" class="adv-chip" data-i18n="buttonAddFolder">${i18n.t('buttonAddFolder')}</button>
              `;
              target.parentElement.insertBefore(bar, target);
            }
          }
          // Lists tab
          {
            const host = document.getElementById('adv-lists-list');
            const empty = document.getElementById('adv-lists-empty');
            const target = empty || host;
            if (target && !target.previousElementSibling?.classList?.contains('adv-folder-toolbar')) {
              const bar = document.createElement('div');
              bar.className = 'adv-folder-toolbar';
              bar.innerHTML = `
                <select id="adv-lists-folder-filter" class="adv-select"></select>
                <input id="adv-lists-search" class="adv-input" type="text" data-i18n-placeholder="placeholderFilterLists" placeholder="${i18n.t('placeholderFilterLists')}">
                <button id="adv-lists-new-folder" class="adv-chip" data-i18n="buttonAddFolder">${i18n.t('buttonAddFolder')}</button>
              `;
              target.parentElement.insertBefore(bar, target);
            }
          }
          // Saved tab
          {
            const host = document.getElementById('adv-saved-list');
            const empty = document.getElementById('adv-saved-empty');
            const target = empty || host;
            if (target && !target.previousElementSibling?.classList?.contains('adv-folder-toolbar')) {
              const bar = document.createElement('div');
              bar.className = 'adv-folder-toolbar';
              bar.innerHTML = `
                <select id="adv-saved-folder-filter" class="adv-select"></select>
                <input id="adv-saved-search" class="adv-input" type="text" data-i18n-placeholder="placeholderSearchSaved" placeholder="${i18n.t('placeholderSearchSaved')}">
                <button id="adv-saved-new-folder" class="adv-chip" data-i18n="buttonAddFolder">${i18n.t('buttonAddFolder')}</button>
              `;
              target.parentElement.insertBefore(bar, target);
            }
          }
        }

        const migrateAccounts = (list) =>
          Array.isArray(list)
            ? list
                .map(it => ({
                  id: it.id || uid(),
                  handle: (it.handle || '').replace(/^@/, '').trim(),
                  name: (it.name || '').trim(),
                  avatar: it.avatar || '',
                  ts: it.ts || Date.now(),
                }))
                .filter(it => it.handle)
            : [];
        const loadAccounts = () => migrateAccounts(loadJSON(ACCOUNTS_KEY, []));
        const saveAccounts = (arr) => saveJSON(ACCOUNTS_KEY, migrateAccounts(arr));
        // 远加 or 曎新既存があれば name / avatar 差分のみ曎新
        const addAccount = ({ handle, name='', avatar='' }) => {
          const h = (handle || '').replace(/^@/, '').trim();
          if (!h) return 'empty';
          const list = loadAccounts();
          const ix = list.findIndex(x => x.handle.toLowerCase() === h.toLowerCase());
          if (ix >= 0) {
            let changed = false;
            if (name && name !== list[ix].name) { list[ix].name = name; changed = true; }
            if (avatar && avatar !== list[ix].avatar) { list[ix].avatar = avatar; changed = true; }
            if (changed) {
              list[ix].ts = Date.now();
              saveAccounts(list);
              renderAccounts();
              return 'updated';
            }
            return 'exists';
          }
          const id = uid();
          list.unshift({ id, handle: h, name, avatar, ts: Date.now() });
          saveAccounts(list);
          // フォルダヌぞは入れない未所属のたた
          try {
            const folders = loadFolders(ACCOUNTS_FOLDERS_KEY, i18n.t('optAccountAll'));
            // 念のため党フォルダヌから重耇を陀去だけしお保存未所属を保持
            folders.forEach(f => { f.order = f.order.filter(x => x !== id); });
            saveFolders(ACCOUNTS_FOLDERS_KEY, folders);
          } catch(_) {}
          renderAccounts();
          return 'ok';
        };
        // 既存アカりントがある堎合だけ name / avatar を曎新未登録なら䜕もしない
        const updateAccountIfExists = ({ handle, name='', avatar='' }) => {
          const h = (handle || '').replace(/^@/, '').trim();
          if (!h) return 'empty';
          const list = loadAccounts();
          const ix = list.findIndex(x => x.handle.toLowerCase() === h.toLowerCase());
          if (ix < 0) return 'not_found';
          let changed = false;
          if (name && name !== list[ix].name)   { list[ix].name   = name;   changed = true; }
          if (avatar && avatar !== list[ix].avatar) { list[ix].avatar = avatar; changed = true; }
          if (changed) {
            list[ix].ts = Date.now();
            saveAccounts(list);
            renderAccounts();
            return 'updated';
          }
          return 'unchanged';
        };
        const deleteAccount = (id) => {
            // â–Œ 削陀察象のハンドルを保持しおおく
            const accounts = loadAccounts();
            const deletedAccount = accounts.find(x => x.id === id);
            const deletedHandle = deletedAccount?.handle.toLowerCase();

            const next = accounts.filter(x => x.id !== id); // accounts倉数を䜿甚
            saveAccounts(next);
            renderAccounts();
            showToast(i18n.t('toastDeleted'));

            // â–Œ ペヌゞ䞊のボタンを匷制再描画
            // 珟圚のペヌゞハンドルを取埗
            const currentHandle = getProfileHandleFromURL()?.toLowerCase();
            // もし削陀したアカりントのペヌゞに今たさに居るなら、ボタンを匷制曎新
            if (deletedHandle && currentHandle === deletedHandle) {
                ensureProfileAddButton(true);
            }
        };

        const accountsListEl  = document.getElementById('adv-accounts-list');
        const advSavedListEl  = document.getElementById('adv-saved-list');

        function getProfileHandleFromURL(href = location.href) {
          try {
            const u = new URL(href, location.origin);
            const segs = u.pathname.split('/').filter(Boolean);
            if (segs.length === 0) return '';

            // 先頭セグメントを候補にする
            const first = segs[0];

            // 明らかな非プロフィヌルの予玄セグメントを陀倖
            const RESERVED = new Set([
              'home','explore','notifications','messages','i','settings',
              'compose','search','login','signup','tos','privacy','about'
            ]);
            if (RESERVED.has(first)) return '';

            // ナヌザヌ名パタヌン: プロフ盎䞋/配䞋タブ/with_replies, /media, /likes 等を蚱容
            if (/^[A-Za-z0-9_]{1,50}$/.test(first)) {
              return first; // /<handle> や /<handle>/with_replies /media /likes ... をすべおカバヌ
            }

            return '';
          } catch {
            // DOM フォヌルバック
            try {
              const a = document.querySelector('[data-testid="User-Name"] a[href^="/"], [data-testid="UserName"] a[href^="/"]');
              if (a) {
                const m = (a.getAttribute('href') || '').match(/^\/([A-Za-z0-9_]{1,50})/);
                if (m) return m[1];
              }
            } catch (_) {}
            return '';
          }
        }

        // 指定ハンドルのプロフィヌル領域だけをスコヌプにしお name / avatar を取埗
        function collectProfileMeta(handle) {
          let name = '';
          let avatar = '';
          try {
            const h = String(handle || '').replace(/^@/, '').trim();

            // 1) プロフィヌル領域衚瀺名
            //    ※ グロヌバルヘッダの自分の名前を拟わないように、最初に [data-testid="UserName"] を基準に限定
            const profileRoot =
              document.querySelector('[data-testid="UserName"]') ||
              document.querySelector('[data-testid="User-Name"]');

            if (profileRoot) {
              const texts = Array.from(profileRoot.querySelectorAll('span, div[dir="auto"]'))
                .map(el => (el.textContent || '').trim())
                .filter(Boolean);
              // 䟋: ["みみる@米囜株投資", "@mimiru_usstock", ...]
              name = texts.find(t => !t.startsWith('@')) || '';
            }

            // 2) アバタヌ領域をハンドルで限定
            //    DOM䟋: <div data-testid="UserAvatar-Container-mimiru_usstock"> ... </div>
            let avatarScope = null;
            if (h) {
              avatarScope = document.querySelector(`[data-testid="UserAvatar-Container-${CSS.escape(h)}"]`);
            }
            // フォヌルバックハンドル付き data-testid が無い叀い/差分レむアりト
            if (!avatarScope) {
              // プロフィヌルのヘッダ右偎の塊に限定
              avatarScope = profileRoot?.closest('[data-testid="UserProfileHeader_Items"]')?.parentElement
                         || profileRoot?.parentElement
                         || document;
            }

            // 2-1) たず <img> 優先
            const img = avatarScope.querySelector('img[src*="profile_images"]');
            if (img?.src) {
              avatar = img.src;
            } else {
              // 2-2) 背景画像 style="background-image:url(...)" から抜出
              //     提瀺DOMの:
              //     <div class="... r-1wyyakw ..." style="background-image:url('...')"></div>
              const bg = avatarScope.querySelector('[style*="background-image"]');
              if (bg) {
                const m = String(bg.getAttribute('style') || '').match(/background-image:\s*url\((["']?)(.*?)\1\)/i);
                if (m && m[2]) avatar = m[2];
              }
            }

            // バナヌ(header_photo) を誀怜出しないように、ヘッダバナヌ領域を陀倖
            // banner は /header_photo ぞのリンク配䞋; avatarScope 内に入らない蚭蚈だが保険
            if (avatar && /profile_banners\//.test(avatar)) {
              avatar = '';
            }

          } catch {}
          return { name, avatar };
        }

        let profileButtonObserver = null;
        let profileButtonInstalledFor = '';
        function ensureProfileAddButton(force = false) {
          const handle = getProfileHandleFromURL();
          if (!handle) return;
            // 同ハンドル内タブ遷移時でも、既存ボタンが消えおいたら再蚭眮できるようにする
          if (!force && profileButtonInstalledFor === handle && document.getElementById('adv-add-account-btn')) {
            return;
          }

          const moreBtn = document.querySelector('button[data-testid="userActions"]');
          if (!moreBtn) return;

          const parent = moreBtn.parentElement;
          if (!parent) return; // 芪コンテナがなければ挿入もできない

          // 状態远加枈みかを先に刀定
          const h_lower = handle.toLowerCase();
          const accounts = loadAccounts();
          const existingAccount = accounts.find(x => x.handle.toLowerCase() === h_lower);
          const isAdded = !!existingAccount;
          const accountId = existingAccount?.id || null;

          // 既存のボタンが残っおいれば、ハンドルに関わらず匷制的に削陀する
          const existingBtn = parent.querySelector('#adv-add-account-btn');
          if (existingBtn) {
              existingBtn.remove();
          }

          const btn = document.createElement('button');
          btn.id = 'adv-add-account-btn';
          btn.type = 'button';
          // 芋た目を完党同期class も style もコピヌ
          const syncVisual = (dst, src) => {
            dst.className = src.className;
            const st = src.getAttribute('style');
            if (st !== null) dst.setAttribute('style', st);
            // 念のため currentColor 継承
            dst.style.color ||= 'inherit';
          };
          syncVisual(btn, moreBtn);

          // 将来のテヌマ切替hover などで X が style/class を曞き換えたら远埓
          // 以前のObserverが残っおいれば砎棄し、リヌクを防ぐ
          if (profileButtonObserver) {
              profileButtonObserver.disconnect();
          }
          const visMo = new MutationObserver(() => syncVisual(btn, moreBtn));
          visMo.observe(moreBtn, { attributes: true, attributeFilter: ['class', 'style'] });
          // 新しいObserverを倉数に保持
          profileButtonObserver = visMo;
          // 状態に応じおラベルを倉曎
          const label = i18n.t(isAdded ? 'delete' : 'buttonAddAccount'); // 「削陀」キヌを流甚
          btn.setAttribute('aria-label', label);
          btn.title = label;
          // â–Œ 内偎の div / svg / span から「class ず inline style」を抜出
          const innerDiv   = moreBtn.querySelector('div[dir="ltr"]') || moreBtn.querySelector('div');
          const innerCls   = innerDiv?.getAttribute('class') || innerDiv?.classList?.value || '';
          const innerStyle = innerDiv?.getAttribute('style') || '';
          const svgEl      = innerDiv?.querySelector('svg') || moreBtn.querySelector('svg');
          const svgCls     = svgEl?.getAttribute('class') || svgEl?.classList?.value || '';
          const spanEl     = innerDiv?.querySelector('span') || moreBtn.querySelector('span');
          const spanCls    = spanEl?.getAttribute('class') || spanEl?.classList?.value || '';

          // 状態に応じおSVGパスを切り替え
          const ICON_PATH_ADD = 'M18 5h2v3h3v2h-3v3h-2V10h-3V8h3V5z';
          const ICON_PATH_CHECK = 'M23 8l-5 5-3-3 1.5-1.5L18 10l3.5-3.5L23 8z'; // 右䞊に配眮したチェック
          const iconPath = isAdded ? ICON_PATH_CHECK : ICON_PATH_ADD;

          btn.innerHTML = `
            <div dir="ltr" class="${innerCls}" style="${innerStyle}">
              <svg
                viewBox="0 0 24 24"
                aria-hidden="true"
                role="img"
                class="${svgCls}"
                fill="currentColor"
              >
                <circle cx="10" cy="7.5" r="3.5"></circle>
                <path d="M3.5 18.5C3.5 15.46 6.79 13 10 13s6.5 2.46 6.5 5.5V20H3.5v-1.5z"></path>
                <path d="${iconPath}"></path>
              </svg>
              <span class="${spanCls}"></span>
            </div>
          `;

          btn.addEventListener('click', () => {
            if (isAdded) {
              // 远加枈みの堎合削陀
              if (accountId) {
                deleteAccount(accountId); // deleteAccount は toast を内蔵しおいる
              }
            } else {
              // 未远加の堎合远加
              const { name, avatar } = collectProfileMeta(handle);
              const ret = addAccount({ handle, name, avatar });
              if (ret === 'ok') showToast(i18n.t('toastAccountAdded'));
              else if (ret === 'updated') showToast(i18n.t('updated'));
              else if (ret === 'exists') showToast(i18n.t('toastAccountExists'));
            }
            // 状態が倉わったので、ボタンを即座に再描画アむコンを切り替え
            ensureProfileAddButton(true); // force=true で再実行
          });
          // moreBtn.parentElement?.insertBefore(btn, moreBtn);
          parent.insertBefore(btn, moreBtn); // parent倉数を䜿甚
          profileButtonInstalledFor = handle;

          // プロフィヌルに来たタむミングで自動同期
          // 未登録は远加しない。既存時のみ差分曎新。
          try {
            const { name, avatar } = collectProfileMeta(handle);
            const status = updateAccountIfExists({ handle, name, avatar });
            if (status === 'updated') showToast(i18n.t('updated'));
            // 'not_found' / 'unchanged' は無通知でOK
          } catch {}

        }

        /* ========= Lists storage & UI ========= */
        const LISTS_KEY = 'advLists_v1';

        const migrateLists = (list) =>
          Array.isArray(list)
            ? list
                .map(it => ({
                  id: it.id || uid(),
                  name: (it.name || '').trim(),
                  url: (it.url || '').trim(),
                  ts: it.ts || Date.now(),
                }))
                .filter(it => it.name && it.url)
            : [];

        const loadLists  = () => migrateLists(loadJSON(LISTS_KEY, []));
        const saveLists  = (arr) => saveJSON(LISTS_KEY, migrateLists(arr));

        const addList = ({ name, url }) => {
          const nm = (name || '').trim();
          let u = (url || '').trim();
          if (!nm || !u) return 'empty';
          try {
            const parsed = new URL(u, location.origin);
            if (parsed.origin === location.origin) u = parsed.pathname + parsed.search + parsed.hash;
          } catch {}
          const list = loadLists();
          if (list.some(x => x.url === u)) return 'exists';
          const id = uid();
          list.unshift({ id, name: nm, url: u, ts: Date.now() });
          saveLists(list);
          // フォルダヌぞは入れない未所属のたた
          try {
            const folders = loadFolders(LISTS_FOLDERS_KEY, i18n.t('optLocationAll'));
            folders.forEach(f => { f.order = f.order.filter(x => x !== id); });
            saveFolders(LISTS_FOLDERS_KEY, folders);
          } catch(_) {}
          renderLists();
          return 'ok';
        };

        const deleteList = (id) => {
            // â–Œ 削陀察象のURLを保持しおおく
            const lists = loadLists();
            const deletedList = lists.find(x => x.id === id);
            const deletedUrl = deletedList?.url;

            const next = lists.filter(x => x.id !== id); // lists倉数を䜿甚
            saveLists(next);
            renderLists();
            showToast(i18n.t('toastDeleted'));

            // â–Œ ペヌゞ䞊のボタンを匷制再描画
            // 珟圚がリストペヌゞか、そのURLは䜕かを取埗
            if (isListPath()) {
                const { url: currentUrl } = getListMeta();
                // もし削陀したリストのペヌゞに今たさに居るなら、ボタンを匷制曎新
                if (deletedUrl && currentUrl === deletedUrl) {
                    ensureListAddButton(true);
                }
            }
        };

        const advListsListEl  = document.getElementById('adv-lists-list');

        // ===== FOLDER MIGRATION =====
        (function migrateAccountsToFolders(){
          // 既存フォルダヌがあっおも root 前提の自動䜜成/自動割圓はしない。
          // 叀いデヌタで item.folderId === 'root' の痕跡があれば“未所属”に正芏化。
          try {
            let items = loadAccounts();
            let changed = false;
            items = items.map(it => {
              if (it.folderId === 'root') { delete it.folderId; changed = true; }
              return it;
            });
            if (changed) saveAccounts(items);
          } catch(_) {}
        })();

        (function migrateListsToFolders(){
          // root 前提の自動䜜成/自動割圓は行わない。
          try {
            let items = loadLists();
            let changed = false;
            items = items.map(it => {
              if (it.folderId === 'root') { delete it.folderId; changed = true; }
              return it;
            });
            if (changed) saveLists(items);
          } catch(_) {}
        })();

        // UI toolbars
        ensureFolderToolbars();

        function renderLists() {
          ensureFolderToolbars();

          renderFolderedCollection({
            hostId: 'adv-lists-list',
            emptyId: 'adv-lists-empty',
            filterSelectId: 'adv-lists-folder-filter',
            searchInputId:  'adv-lists-search',
            newFolderBtnId: 'adv-lists-new-folder',

            foldersKey: LISTS_FOLDERS_KEY,
            defaultFolderName: i18n.t('optListsAll'),

            loadItems: loadLists,
            saveItems: saveLists,
            renderRow: renderListRow,

            onUnassign: unassignList,
            onMoveToFolder: moveListToFolder,

            emptyMessage: i18n.t('emptyLists'),
            unassignedIndexKey: 'advListsUnassignedIndex_v1',
          });
        }

        const isListPath = (pathname = location.pathname) => /^\/i\/lists\/\d+\/?$/.test(pathname);

        function getListMeta() {
          // 1) <title> から取り出し最優先
          let rawTitle = '';
          try { rawTitle = (document.title || '').trim(); } catch (_) {}

          // 末尟の " / X" たたは " / Twitter" を削る
          let baseTitle = rawTitle.replace(/\s*\/\s*(X|Twitter)\s*$/i, '').trim();

          let name = '';
          let m;

          // パタヌンA: "@owner/リスト名"
          m = baseTitle.match(/^\s*@([A-Za-z0-9_]{1,50})\/\s*(.+)\s*$/);
          if (m) {
            name = (m[2] || '').trim();
          }

          // パタヌンB: "リスト名 (@owner)"
          if (!name) {
            m = baseTitle.match(/^\s*(.+?)\s*\(@[A-Za-z0-9_]{1,50}\)\s*$/);
            if (m) {
              name = (m[1] || '').trim();
            }
          }

          // 䜙分な匕甚笊 “ ” " ' に察応
          if (name) {
            name = name.replace(/^[“"'](.+)[”"']$/, '$1').trim();
          }

          // 2) タむトルで取れない/怪しい時は芋出しから拟う@を含む/長文/ヘルプ文は陀倖
          if (!name) {
            try {
              const headingRoot =
                document.querySelector('[data-testid="ScrollSnap-ListHeader"]') ||
                document.querySelector('[data-testid="primaryColumn"]') ||
                document;

              const candidates = Array.from(
                headingRoot.querySelectorAll('h1[role="heading"], h2[role="heading"], h3[role="heading"]')
              )
                .flatMap(h => Array.from(h.querySelectorAll('span, div[dir="ltr"], div[dir="auto"]'))
                  .map(el => (el.textContent || '').trim()))
                .filter(Boolean)
                // 「@ 」はオヌナヌ衚蚘なので陀倖
                .filter(txt => !/^@/.test(txt))
                // 長文やヘルプ文キヌボヌドショヌトカット系を匟く
                .filter(txt => {
                  const t = txt.replace(/\s+/g, ' ');
                  if (t.length > 80) return false;
                  const NG = ['キヌボヌドショヌトカット', 'keyboard', 'help', 'ショヌトカット', 'press', '?'];
                  return !NG.some(ng => t.toLowerCase().includes(ng.toLowerCase()));
                });

              if (candidates.length) {
                // 䞀番短い候補装食の少ないタむトルの可胜性が高い
                name = candidates.sort((a, b) => a.length - b.length)[0].trim();
              }
            } catch (_) {}
          }

          // 3) 最終フォヌルバック
          if (!name) name = '';

          // URL は珟ペヌゞSPA察応でク゚リ/ハッシュも保持
          const url = location.pathname + location.search + location.hash;
          return { name, url };
        }

        let listButtonObserver = null;
        let listButtonInstalledAt = '';
        function ensureListAddButton(force = false) {
          if (!isListPath()) return;
          if (!force && listButtonInstalledAt === location.pathname) return;

          // 可芖状態にあるシェアボタンを厳密に特定する
          const shareBtns = Array.from(document.querySelectorAll('button[data-testid="share-button"]'));
          // offsetParent が null でない衚瀺されおいるボタンを探す
          // SP時は TopNavBar 内にあるこずが倚いため、それを優先しおも良いが、可芖チェックが最も汎甚的
          const shareBtn = shareBtns.find(btn => btn.offsetParent !== null);
          if (!shareBtn) return;

          const parent = shareBtn.parentElement;
          if (!parent) return;

          // â–Œ 状態刀定ロゞックを远加
          const { name: currentName, url: currentUrl } = getListMeta();
          // リスト名やURLが取埗できないリストペヌゞではない堎合はボタンを远加しない
          if (!currentName || !currentUrl) return;

          const lists = loadLists();
          const existingList = lists.find(x => x.url === currentUrl);
          const isAdded = !!existingList;
          const listId = existingList?.id || null;

          // 既存のボタンが残っおいれば、匷制的に削陀する
          const existingBtn = parent.querySelector('#adv-add-list-btn');
          if (existingBtn) {
              existingBtn.remove();
          }

          const btn = document.createElement('button');
          btn.id = 'adv-add-list-btn';
          btn.type = 'button';

          const syncVisual = (dst, src) => {
            dst.className = src.className;
            const st = src.getAttribute('style');
            if (st !== null) dst.setAttribute('style', st);
            dst.style.color ||= 'inherit';
          };
          syncVisual(btn, shareBtn);

          // 以前のObserverが残っおいれば砎棄し、リヌクを防ぐ
          if (listButtonObserver) {
              listButtonObserver.disconnect();
          }
          const visMo = new MutationObserver(() => syncVisual(btn, shareBtn));
          visMo.observe(shareBtn, { attributes: true, attributeFilter: ['class', 'style'] });
          // 新しいObserverを倉数に保持
          listButtonObserver = visMo;

          // â–Œ isAdded に応じおラベルを倉曎"削陀"キヌを流甚
          const label = i18n.t(isAdded ? 'delete' : 'buttonAddList');
          btn.setAttribute('aria-label', label);
          btn.title = label;

          const innerDiv   = shareBtn.querySelector('div[dir="ltr"]') || shareBtn.querySelector('div');
          const innerCls   = innerDiv?.getAttribute('class') || innerDiv?.classList?.value || '';
          const innerStyle = innerDiv?.getAttribute('style') || '';
          const svgEl      = innerDiv?.querySelector('svg') || shareBtn.querySelector('svg');
          const svgCls     = svgEl?.getAttribute('class') || svgEl?.classList?.value || '';
          const spanEl     = innerDiv?.querySelector('span') || shareBtn.querySelector('span');
          const spanCls    = spanEl?.getAttribute('class') || spanEl?.classList?.value || '';

          // â–Œ アむコンパスを定矩
          const ICON_PATH_ADD = 'M12 5c.55 0 1 .45 1 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H6a1 1 0 110-2h5V6c0-.55.45-1 1-1z';
          // アカりントボタンずは異なり、シンプルなチェックマヌクを䜿甚
          const ICON_PATH_CHECK = 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z';
          const iconPath = isAdded ? ICON_PATH_CHECK : ICON_PATH_ADD;

          // â–Œ iconPath を䜿甚するように innerHTML を倉曎
          btn.innerHTML = `
              <div dir="ltr" class="${innerCls}" style="${innerStyle}">
                  <svg viewBox="0 0 24 24" aria-hidden="true" class="${svgCls}" fill="currentColor">
                      <g><path d="${iconPath}"></path></g>
                  </svg>
                  <span class="${spanCls}"></span>
              </div>
          `;

          // â–Œ クリックむベントのロゞックをトグルに倉曎
          btn.addEventListener('click', () => {
              if (isAdded) {
                  // 既に登録枈みの堎合削陀
                  if (listId) {
                      deleteList(listId); // deleteList は内郚で toastDeleted を呌び出したす
                  }
              } else {
                  // 未登録の堎合远加
                  // (関数冒頭で取埗した currentName, currentUrl を䜿甚)
                  const ret = addList({ name: currentName, url: currentUrl });
                  if (ret === 'ok') showToast(i18n.t('toastListAdded'));
                  else if (ret === 'exists') showToast(i18n.t('toastListExists'));
              }

              // 状態が倉わったため、ボタンを匷制的に再描画アむコンを即時切替
              ensureListAddButton(true);
          });

          // 巊隣に蚭眮
          // shareBtn.parentElement?.insertBefore(btn, shareBtn);
          parent.insertBefore(btn, shareBtn); // parent倉数を䜿甚

          listButtonInstalledAt = location.pathname;
        }

        const reconcileUI = () => {
            const stored = (()=>{ try { return JSON.parse(kv.get(MODAL_STATE_KEY,'{}')); } catch{ return {}; } })();
            const desiredVisible = !!stored.visible;
            const blocked = isBlockedPath(location.pathname);

            // â–Œ 珟圚のパスが自動クロヌズ察象か刀定
            const autoClose = isAutoClosePath(location.pathname);

            if (blocked) {
                trigger.style.display = 'none';
            } else {
                trigger.style.display = '';
                applyTriggerStoredPosition();
                requestAnimationFrame(keepTriggerInViewport);
            }

            // â–Œ 自動クロヌズ察象の堎合、手動オヌプン(manualOverrideOpen)されおいなければ隠す
            // desiredVisible蚭定倀が true でも、autoClose ゚リアにいる間は無芖される
            // ゚リアから出れば autoClose が false になり、desiredVisible が再び有効になる埩掻
            const shouldShow = (!blocked) && ( (desiredVisible && !autoClose) || manualOverrideOpen );
            const wasShown = (modal.style.display === 'flex');
            modal.style.display = shouldShow ? 'flex' : 'none';
            if (shouldShow) {
                // 既に衚瀺されおいる堎合(wasShown=true)は、䜍眮の匷制適甚をスキップする
                if (!wasShown) {
                    applyModalStoredPosition();
                }

                // 画面倖にはみ出しおいないかのチェックだけは毎回行う䜍眮ズレ補正のため
                requestAnimationFrame(keepModalInViewport);

                if (!wasShown) {
                    syncFromSearchBoxToModal();
                    applyScopesToControls(readScopesFromURL());
                    updateSaveButtonState();
                }
            }
        };

        trigger.addEventListener('click', () => {
            if (trigger.style.display === 'none') return;
            const isVisibleNow = modal.style.display === 'flex';
            if (isVisibleNow) {
                manualOverrideOpen = false;
                modal.style.display = 'none';
                saveModalRelativeState();
            } else {
                manualOverrideOpen = true;
                modal.style.display = 'flex';
                syncFromSearchBoxToModal();
                applyScopesToControls(readScopesFromURL());
                applyModalStoredPosition();
                requestAnimationFrame(keepModalInViewport);
                applyZoom();
                saveModalRelativeState();
                updateSaveButtonState();
            }
        });

        const closeModal = () => {
            manualOverrideOpen = false;
            modal.style.display = 'none';
            saveModalRelativeState();
        };
        closeButton.addEventListener('click', closeModal);

        clearButton.addEventListener('click', () => {
            form.reset();
            // クリア時に disabled を解陀
            ['verified', 'links', 'images', 'videos'].forEach(groupName => {
                const includeEl = document.getElementById(`adv-filter-${groupName}-include`);
                const excludeEl = document.getElementById(`adv-filter-${groupName}-exclude`);
                if (includeEl) includeEl.disabled = false;
                if (excludeEl) excludeEl.disabled = false;
            });
            syncFromModalToSearchBox();
        });

        applyButton.addEventListener('click', () => {
            // 怜玢確定 → ルヌティング反映埅ち → スキャン
            Promise.resolve(executeSearch())
              .finally(() => setTimeout(() => processNewTweets(true), 800));
        });

        saveButton.addEventListener('click', () => {
            const q = buildQueryStringFromModal().trim();
            if (!q) return;
            const {pf, lf} = readScopesFromControls();
            addSaved(q, pf, lf);
            activateTab('saved');
        });

        form.addEventListener('input', syncFromModalToSearchBox);
        form.addEventListener('keydown', e => {
            if (e.key === 'Enter' && (e.target.matches('input[type="text"], input[type="number"]'))) {
                e.preventDefault();
                // 怜玢確定 → ルヌティング反映埅ち → スキャン
                Promise.resolve(executeSearch())
                  .finally(() => setTimeout(() => processNewTweets(true), 800));
            }
        });

        /* --- Date Shortcut Logic --- */
        const dateShortcutSel = document.getElementById('adv-date-shortcut');
        const sinceInput = document.getElementById('adv-since');
        const untilInput = document.getElementById('adv-until');

        if (dateShortcutSel && sinceInput && untilInput) {
            const toYMD = (date) => {
                const y = date.getFullYear();
                const m = String(date.getMonth() + 1).padStart(2, '0');
                const d = String(date.getDate()).padStart(2, '0');
                return `${y}-${m}-${d}`;
            };

            // â–Œ 日付からショヌトカットを逆算しお遞択状態を同期する関数
            const updateShortcutFromInputs = () => {
                // ナヌザヌがショヌトカットを操䜜䞭の堎合はルヌプ防止のため凊理しない
                if (document.activeElement === dateShortcutSel) return;

                const sVal = sinceInput.value;
                const uVal = untilInput.value;

                // 盞察日付ショヌトカットは「Untilが空」であるこずが前提
                if (uVal !== '' || sVal === '') {
                    if (dateShortcutSel.value !== '') dateShortcutSel.value = '';
                    return;
                }

                const now = new Date();
                const calcTargetDate = (fn) => {
                    const d = new Date(now);
                    fn(d);
                    return toYMD(d);
                };

                // 定矩ず日付の察応衚
                const targets = {
                    '1d': calcTargetDate(d => d.setDate(d.getDate() - 1)),
                    '1w': calcTargetDate(d => d.setDate(d.getDate() - 7)),
                    '1m': calcTargetDate(d => d.setMonth(d.getMonth() - 1)),
                    '3m': calcTargetDate(d => d.setMonth(d.getMonth() - 3)),
                    '6m': calcTargetDate(d => d.setMonth(d.getMonth() - 6)),
                    '1y': calcTargetDate(d => d.setFullYear(d.getFullYear() - 1)),
                    '2y': calcTargetDate(d => d.setFullYear(d.getFullYear() - 2)),
                    '3y': calcTargetDate(d => d.setFullYear(d.getFullYear() - 3)),
                    '5y': calcTargetDate(d => d.setFullYear(d.getFullYear() - 5)),
                };

                // 䞀臎するショヌトカットを探す
                const match = Object.entries(targets).find(([key, dateStr]) => dateStr === sVal);
                const nextVal = match ? match[0] : '';

                // 倀が倉わる堎合のみ曎新無駄な描画を抑制
                if (dateShortcutSel.value !== nextVal) {
                    dateShortcutSel.value = nextVal;
                }
            };

            // â–Œ 1. プログラムによる倀倉曎リロヌドやURL解析によるセットを怜知する仕掛け
            // input.value = '...' ずされた時にも updateShortcutFromInputs を走らせる
            const hookValueProperty = (input) => {
                const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
                Object.defineProperty(input, 'value', {
                    configurable: true,
                    enumerable: true,
                    get: function() {
                        return descriptor.get.call(this);
                    },
                    set: function(v) {
                        descriptor.set.call(this, v);
                        // 倀がセットされた盎埌に同期チェックを実行
                        updateShortcutFromInputs();
                    }
                });
            };
            hookValueProperty(sinceInput);
            hookValueProperty(untilInput);

            // â–Œ 2. ナヌザヌによる手動入力カレンダヌ操䜜やキヌ入力の怜知
            ['input', 'change'].forEach(evt => {
                sinceInput.addEventListener(evt, updateShortcutFromInputs);
                untilInput.addEventListener(evt, updateShortcutFromInputs);
            });

            // â–Œ 3. ショヌトカットプルダりン倉曎時の凊理日付をセット
            dateShortcutSel.addEventListener('change', () => {
                const val = dateShortcutSel.value;
                // 'clear'以倖で倀がない堎合は無芖
                if (!val && val !== 'clear') return;

                const now = new Date();
                let targetDate = new Date();

                if (val === 'clear') {
                    sinceInput.value = '';
                    untilInput.value = '';
                    dateShortcutSel.value = '';
                } else {
                    untilInput.value = ''; // 期間指定はUntil空
                    switch (val) {
                        case '1d': targetDate.setDate(now.getDate() - 1); break;
                        case '1w': targetDate.setDate(now.getDate() - 7); break;
                        case '1m': targetDate.setMonth(now.getMonth() - 1); break;
                        case '3m': targetDate.setMonth(now.getMonth() - 3); break;
                        case '6m': targetDate.setMonth(now.getMonth() - 6); break;
                        case '1y': targetDate.setFullYear(now.getFullYear() - 1); break;
                        case '2y': targetDate.setFullYear(now.getFullYear() - 2); break;
                        case '3y': targetDate.setFullYear(now.getFullYear() - 3); break;
                        case '5y': targetDate.setFullYear(now.getFullYear() - 5); break;
                    }
                    sinceInput.value = toYMD(targetDate);
                }

                // 怜玢ボックスぞの反映
                if (typeof syncFromModalToSearchBox === 'function') {
                    syncFromModalToSearchBox();
                }
            });
        }
        const muteEmptyEl = document.getElementById('adv-mute-empty');
        const muteListEl  = document.getElementById('adv-mute-list');
        const muteInputEl = document.getElementById('adv-mute-input');
        const muteFilterEl = document.getElementById('adv-mute-filter');
        const muteCsEl    = document.getElementById('adv-mute-cs');
        const muteWbEl    = document.getElementById('adv-mute-wb');
        const muteAddBtn  = document.getElementById('adv-mute-add');

        if (muteFilterEl) {
            muteFilterEl.addEventListener('input', () => renderMuted());
        }

        const renderMuted = () => {
          let list = loadMuted();
          // 怜玢ボックスに倀があればフィルタリング
          if (muteFilterEl) {
              const q = muteFilterEl.value.trim().toLowerCase();
              if (q) {
                  list = list.filter(item => item.word.toLowerCase().includes(q));
              }
          }
          muteListEl.innerHTML = '';
          muteEmptyEl.textContent = list.length ? '' : i18n.t('emptyMuted');
          list.forEach(item => {
            const row = document.createElement('div');
            row.className = 'adv-mute-item';
            if (!item.enabled) row.classList.add('disabled');
            row.innerHTML = `
              <div class="adv-mute-content-left">
                  <div class="adv-mute-word">${escapeHTML(item.word)}</div>
                  <div class="adv-mute-options-row">
                    <label class="adv-toggle">
                      <input type="checkbox" ${item.enabled ? 'checked' : ''} data-action="toggle-enabled">
                      <span data-i18n="labelEnabled">${i18n.t('labelEnabled')}</span>
                    </label>
                    <label class="adv-toggle">
                      <input type="checkbox" ${item.wb ? 'checked' : ''} data-action="toggle-wb">
                      <span data-i18n="labelWordBoundary">${i18n.t('labelWordBoundary')}</span>
                    </label>
                    <label class="adv-toggle">
                      <input type="checkbox" ${item.cs ? 'checked' : ''} data-action="toggle-cs">
                      <span data-i18n="labelCaseSensitive">${i18n.t('labelCaseSensitive')}</span>
                    </label>
                  </div>
              </div>
              <div class="adv-mute-actions-right">
                <button class="adv-chip danger" data-action="delete" style="padding:2px 8px; font-size:11px;">${i18n.t('delete')}</button>
              </div>
            `;
            row.querySelector('[data-action="toggle-enabled"]').addEventListener('change', () => toggleMutedEnabled(item.id));
            row.querySelector('[data-action="toggle-cs"]').addEventListener('change', () => toggleMutedCS(item.id));
            row.querySelector('[data-action="toggle-wb"]').addEventListener('change', () => toggleMutedWB(item.id));
            row.querySelector('[data-action="delete"]').addEventListener('click', () => deleteMuted(item.id));
            muteListEl.appendChild(row);
          });
        };

        function applyMuteVisualState() {
          const listEl = document.getElementById('adv-mute-list');
          if (!listEl) return;
          const masterOn = loadMuteMaster();

          // â–Œ 切替の瞬間だけトランゞション党停止
          listEl.classList.add('adv-no-anim');
          // 匷制リフロヌでスタむル確定
          void listEl.offsetHeight;
          listEl.classList.toggle('disabled', !masterOn);
          // 次フレヌムで解陀描画を跚がせるのがポむント
          requestAnimationFrame(() => {
            listEl.classList.remove('adv-no-anim');
          });
        }

        muteAddBtn.addEventListener('click', () => {
          addMuted(muteInputEl.value, !!muteCsEl.checked, !!(muteWbEl && muteWbEl.checked));
          muteInputEl.value = '';
          muteCsEl.checked = false;
          if(muteWbEl) muteWbEl.checked = false;
        });
        muteInputEl.addEventListener('keydown', (e) => {
          if (e.key === 'Enter') { e.preventDefault(); muteAddBtn.click(); }
        });

        const muteEnableAllEl = document.getElementById('adv-mute-enable-all');
        const muteModeSel = document.getElementById('adv-mute-mode');

        if (muteEnableAllEl && !muteEnableAllEl._advBound) {
          muteEnableAllEl._advBound = true;
          try { muteEnableAllEl.checked = loadMuteMaster(); } catch {}
          applyMuteVisualState();

          muteEnableAllEl.addEventListener('change', () => {
            saveMuteMaster(!!muteEnableAllEl.checked);
            applyMuteVisualState();
            rescanAllTweetsForFilter();
          });
        }

        // モヌド遞択の初期化ずむベント
        if (muteModeSel && !muteModeSel._advBound) {
            muteModeSel._advBound = true;
            try { muteModeSel.value = loadMuteMode(); } catch {}
            muteModeSel.addEventListener('change', () => {
                saveMuteMode(muteModeSel.value);
                rescanAllTweetsForFilter();
            });
        }

        const installNavigationHooks = (onRouteChange) => {
            let lastHref = location.href;
            const _debounce = (fn, wait=60) => { let t; return (...a)=>{ clearTimeout(t); t=setTimeout(()=>fn(...a), wait); }; };
            const fireIfChanged = _debounce(() => {
                const now = location.href;
                if (now !== lastHref) {
                    lastHref = now;
                    try {
                        const u = new URL(now, location.origin);
                        if (u.pathname.startsWith('/search')) {
                            const q = u.searchParams.get('q') || '';
                            const pf = (u.searchParams.get('pf') || '') === 'on';
                            const lf = (u.searchParams.get('lf') || '') === 'on';
                            if (q) recordHistory(decodeURIComponent(q), pf, lf);
                        } else if (u.pathname.startsWith('/hashtag/')) {
                            const hashtag = u.pathname.substring('/hashtag/'.length).split('/')[0];
                            if (hashtag) {
                                const q = `#${decodeURIComponent(hashtag)}`;
                                // ハッシュタグペヌゞは pf/lf スコヌプを持たない想定
                                recordHistory(q, false, false);
                            }
                        }
                    } catch(_) {}
                    onRouteChange();
                }
            }, 60);
            const wrapHistory = (m) => {
                const orig = history[m];
                history[m] = function(...args){
                    try {
                        const href = args && args[2];
                        if (href) {
                            const u = new URL(href, location.href);
                            if (u.origin === location.origin && isBlockedPath(u.pathname)) {
                                hideUIImmediately(
                                    document.getElementById('advanced-search-modal'),
                                    document.getElementById('advanced-search-trigger')
                                );
                            }
                        }
                    } catch(_) {}
                    const ret = orig.apply(this, args);
                    queueMicrotask(fireIfChanged);
                    return ret;
                };
            };
            wrapHistory('pushState'); wrapHistory('replaceState');
            window.addEventListener('popstate', fireIfChanged);
            document.addEventListener('click', (e) => {
                const a = e.target && e.target.closest ? e.target.closest('a[href]') : null;
                if (!a) return;
                try {
                    const u = new URL(a.href, location.href);
                    if (u.origin === location.origin) {
                        const sameTab = !(e.metaKey || e.ctrlKey || e.shiftKey || a.target === '_blank' || e.button === 1);
                        if (sameTab && isBlockedPath(u.pathname)) {
                            hideUIImmediately(
                                document.getElementById('advanced-search-modal'),
                                document.getElementById('advanced-search-trigger')
                            );
                        }
                        setTimeout(fireIfChanged, 0);
                    }
                } catch(_) {}
            }, true);

            return fireIfChanged;
        };

        // ツむヌトのDOMから保存甚デヌタを抜出
        function ft_extractTweetMeta(article, tweetId) {
            const text = article.querySelector('[data-testid="tweetText"]')?.innerText || '';
            const userRow = article.querySelector('[data-testid="User-Name"]');
            let name = '', handle = '', avatar = '';

            if (userRow) {
                name = userRow.querySelector('a span')?.innerText || '';
                const userLink = userRow.querySelector('a[href^="/"]');
                if (userLink) {
                    const href = userLink.getAttribute('href');
                    if (href) {
                        const parts = href.split('/');
                        if (parts.length >= 2) handle = parts[1];
                    }
                }
            }
            const img = article.querySelector('[data-testid="Tweet-User-Avatar"] img');
            if (img) avatar = img.src;

            // 投皿日時の取埗
            let postedAt = Date.now(); // フォヌルバックは珟圚時刻
            const timeEl = article.querySelector('time');
            if (timeEl && timeEl.getAttribute('datetime')) {
                postedAt = new Date(timeEl.getAttribute('datetime')).getTime();
            }

            // メディア抜出ヘルパヌ
            const extractMedia = (rootElement, excludeElement) => {
                const extracted = [];
                rootElement.querySelectorAll('div[data-testid="tweetPhoto"] img').forEach(m => {
                    if (excludeElement && excludeElement.contains(m)) return;
                    if (m.src) extracted.push({ type: 'image', url: m.src });
                });
                rootElement.querySelectorAll('video').forEach(v => {
                    if (excludeElement && excludeElement.contains(v)) return;
                    if (v.poster) extracted.push({ type: 'video', url: v.poster });
                });
                const unique = [];
                const seen = new Set();
                for (const m of extracted) {
                    if (!seen.has(m.url)) { seen.add(m.url); unique.push(m); }
                }
                return unique;
            };

            // 匕甚コンテナ特定
            let quoteContainer = null;
            const quoteCandidates = Array.from(article.querySelectorAll('div[role="link"]'));
            quoteContainer = quoteCandidates.find(el => {
                if (el.getAttribute('tabindex') !== '0') return false;
                const qUser = el.querySelector('[data-testid="User-Name"]');
                if (!qUser) return false;
                const hasText = el.querySelector('[data-testid="tweetText"]');
                const hasMedia = el.querySelector('[data-testid="tweetPhoto"]') || el.querySelector('video');
                return hasText || hasMedia;
            });

            const mainMedia = extractMedia(article, quoteContainer);

            let quote = null;
            if (quoteContainer) {
                const qText = quoteContainer.querySelector('[data-testid="tweetText"]')?.innerText || '';
                let qName = '', qHandle = '', qAvatar = '';
                const qUserRow = quoteContainer.querySelector('[data-testid="User-Name"]');
                if (qUserRow) {
                    qName = qUserRow.textContent.split('@')[0].trim();
                    const handleMatch = qUserRow.innerText.match(/@([a-zA-Z0-9_]+)/);
                    if (handleMatch) qHandle = handleMatch[1];
                }
                const qImg = quoteContainer.querySelector('img[src*="profile_images"]');
                if (qImg) qAvatar = qImg.src;

                let qTweetId = '';
                const photoLink = quoteContainer.querySelector('a[href*="/status/"][href*="/photo/"]');
                if (photoLink) {
                    const m = photoLink.getAttribute('href').match(/\/status\/(\d+)/);
                    if (m) qTweetId = m[1];
                }

                const qMedia = extractMedia(quoteContainer, null);

                quote = {
                    id: qTweetId,
                    text: qText,
                    user: { name: qName, handle: qHandle, avatar: qAvatar },
                    media: qMedia
                };
            }

            return {
                id: tweetId,
                text,
                user: { name, handle, avatar },
                media: mainMedia,
                quote,
                ts: Date.now(), // 保存操䜜をした日時゜ヌト甚などで䜿甚する堎合のため残す
                postedAt: postedAt // 実際の投皿日時
            };
        }

        // 特定のTweetIDを持぀蚘事のタグチップだけを即座に再評䟡・再描画する
        function refreshTagChipsForTweet(tweetId) {
            // data-ft-tweet-id 属性を持぀蚘事をピンポむントで取埗
            const articles = document.querySelectorAll(`article[data-ft-tweet-id="${tweetId}"]`);
            articles.forEach(article => {
                // 既存のロゞックを利甚しおチップの着脱を再刀定
                if (typeof ft_processTweetArticle === 'function') {
                    ft_processTweetArticle(article);
                }
            });
        }

        // 画面䞊のすべおのお気に入りボタンの状態を曎新する
        function updateAllFavoriteButtons() {
            document.querySelectorAll('.adv-fav-btn').forEach(btn => {
                const tid = btn.dataset.tweetId;
                if (tid) {
                    const active = isFavorited(tid);
                    btn.classList.toggle('active', active);
                }
            });
        }

        // ★マヌクボタンの泚入
        function injectFavoriteButton(article, tweetId) {
            const actionBar = article.querySelector('[role="group"]');
            if (!actionBar) return;

            // 1. シェアボタンを探す
            let shareBtn = actionBar.querySelector('[data-testid="share-button"]');
            if (!shareBtn) {
                const buttons = actionBar.querySelectorAll('button');
                for (const b of buttons) {
                    const label = b.getAttribute('aria-label') || '';
                    if (label.includes('共有') || label.includes('Share') || b.innerHTML.includes('M12 2.59l5.7 5.7')) {
                        shareBtn = b;
                        break;
                    }
                }
            }

            // シェアボタンが芋぀からない堎合はフォヌルバック末尟远加
            if (!shareBtn) {
                if (actionBar.querySelector('.adv-fav-btn')) return;
                const fallbackBtn = createFavButtonElement(article, tweetId, null);
                const wrapper = document.createElement('div');
                wrapper.style.cssText = 'display:flex;align-items:center;';
                wrapper.appendChild(fallbackBtn);
                actionBar.appendChild(wrapper);
                return;
            }

            // 2. シェアボタンの芪コンテナdisplay: inline-grid のや぀を探す
            let shareContainer = shareBtn.closest('div[style*="display: inline-grid"]') || shareBtn.parentNode?.parentNode;
            if (!shareContainer) shareContainer = shareBtn.parentNode;

            if (shareContainer.querySelector('.adv-fav-btn')) return;

            // 3. ボタン芁玠を䜜成
            const btn = createFavButtonElement(article, tweetId, shareBtn);

            // 4. 絶察配眮甚のスタむルを適甚
            shareContainer.style.position = 'relative';
            shareContainer.style.overflow = 'visible';

            // コンテナの巊偎に、星ボタンが入る分のスペヌス(箄36px)を匷制的に空ける
            // これにより、タむムラむン䞊で巊隣のブックマヌクボタンず重ならなくなりたす
            shareContainer.style.marginLeft = '36px';

            btn.style.position = 'absolute';
            btn.style.right = '100%';
            btn.style.top = '50%';
            btn.style.transform = 'translateY(-50%)';
            btn.style.marginRight = '2px'; // シェアボタンずの隙間

            // 5. 挿入
            shareContainer.appendChild(btn);
        }

        // ボタン生成ロゞックを分離共通化
        function createFavButtonElement(article, tweetId, sourceBtn) {
            const btn = document.createElement('button');
            // adv-native-style: CSSで固定サむズを解陀するためのクラス
            btn.className = (sourceBtn ? sourceBtn.className : '') + ' adv-fav-btn adv-native-style';
            btn.dataset.tweetId = tweetId;
            btn.type = 'button';
            btn.title = i18n.t('tabFavorites');

            // SVG (Star)
            btn.innerHTML = `
            <svg viewBox="0 0 24 24" aria-hidden="true">
              <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
            </svg>`;

            const updateState = () => {
                const active = isFavorited(tweetId);
                btn.classList.toggle('active', active);
            };
            updateState();

            btn.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                const meta = ft_extractTweetMeta(article, tweetId);
                toggleFavorite(meta);
                updateState();
                ft_processTweetArticle(article);
            });

            return btn;
        }

        // ============================================================
        //  High Performance Tweet Processor (O(1))
        // ============================================================

        function processSingleTweet(article) {
            // 重耇凊理ガヌド
            if (article.dataset.advProcessed) return;

            // 1. 共通: ツむヌトIDの確保
            const tweetId = article.dataset.ftTweetId || ft_extractTweetId(article);
            if (!tweetId) return;
            article.dataset.ftTweetId = tweetId;

            // 2. 蚭定ロヌド (Advanced Search甹) ...
            const flags = {
                name: document.getElementById('adv-exclude-hit-name')?.checked ?? true,
                handle: document.getElementById('adv-exclude-hit-handle')?.checked ?? true,
                reposts: document.getElementById('adv-filter-reposts-exclude')?.checked ?? false,
                hashtags: document.getElementById('adv-filter-hashtags-exclude')?.checked ?? false,
            };

            // 3. Advanced Search Filtering ...
            const masterOn = loadMuteMaster();
            const muteMode = loadMuteMode();
            const muted = loadMuted();
            const hasMute = masterOn && muted.length > 0;

            if (flags.name || flags.handle || hasMute || flags.reposts || flags.hashtags) {
                const regexRules = [];
                const simpleCI = new Set();
                const simpleCS = new Set();

                if (hasMute) {
                    muted.filter(m => m.enabled !== false).forEach(m => {
                        if (m.wb) {
                            // 単語単䜍: 正芏衚珟を生成
                            const flags = m.cs ? '' : 'i';
                            const esc = escapeRegExp(m.word);
                            const pattern = `(?:^|[^a-zA-Z0-9_])${esc}(?:$|[^a-zA-Z0-9_])`;
                            regexRules.push({ rx: new RegExp(pattern, flags), word: m.word });
                        } else {
                            // 通垞䞀臎: Setに振り分け
                            if (m.cs) simpleCS.add(m.word);
                            else simpleCI.add(m.word.toLowerCase());
                        }
                    });
                }

                const muteSettings = {
                    hasMute,
                    muteMode,
                    regexRules,
                    simpleCI,
                    simpleCS
                };
                const tokens = (flags.name || flags.handle) ? parseSearchTokens() : null;
                try {
                    evaluateTweetForFiltering(article, flags, muteSettings, tokens);
                } catch (e) { console.error('[AdvSearch] Filter error', e); }
            }

            // 4. Favorite Tags Processing (タグ衚瀺)
            if (typeof ft_processTweetArticle === 'function') {
                try {
                    ft_processTweetArticle(article);
                } catch (e) { console.error('[FT] Tag error', e); }
            }

            // 5.Inject Favorite Button
            injectFavoriteButton(article, tweetId);

            // 6. 凊理枈みフラグを立おる
            article.dataset.advProcessed = '1';
        }

        // 手動実行蚭定倉曎時などやペヌゞ遷移時甚
        // 普段のスクロヌル時は Observer が processSingleTweet を呌ぶので、これは走らない
        function processNewTweets(force = false) {
            // 匷制フラグがない堎合、入力䞭はスキップ
            if (!force && isTyping()) return;

            // 党ツむヌトを取埗しお凊理
            const articles = document.querySelectorAll('article[data-testid="tweet"]');
            for (const art of articles) {
                processSingleTweet(art);
            }

            // 区切り線のクリヌンアップなどはここで
            cleanupAdjacentSeparators();
        }

        // 統合スキャン関数 ここたで â–Œ
        const setupObservers = () => {
            // URL倉曎怜知甚のプレヌスホルダ
            let _fireIfChanged = () => {};

            const observer = new MutationObserver((mutations) => {
                let searchBoxChanged = false;

                for (const m of mutations) {
                    // 远加されたノヌドだけをルヌプする (Differential Update)
                    if (m.addedNodes.length > 0) {
                        for (const node of m.addedNodes) {
                            if (node.nodeType !== Node.ELEMENT_NODE) continue;

                            // A. 怜玢ボックスの怜知
                            if (!searchBoxChanged) {
                                if (node.matches?.('input[data-testid="SearchBox_Search_Input"]') ||
                                    node.querySelector?.('input[data-testid="SearchBox_Search_Input"]')) {
                                    searchBoxChanged = true;
                                }
                            }

                            // 怜玢フォヌムが远加されたらリサむザヌをセットアップ
                            if (node.matches?.('form[role="search"]') || node.querySelector?.('form[role="search"]')) {
                                // 少し遅延させおDOM安定埌に実行
                                setTimeout(setupNativeSearchResizer, 100);
                            }

                            // B. ツむヌト (article) が盎接远加された堎合
                            if (node.tagName === 'ARTICLE' && node.getAttribute('data-testid') === 'tweet') {
                                processSingleTweet(node);
                            }
                            // C. コンテナ (div/section等) が远加され、䞭にツむヌトが含たれる堎合
                            else if (node.firstElementChild) {
                                // cellInnerDiv もここに含たれる
                                const nestedTweets = node.querySelectorAll('article[data-testid="tweet"]');
                                if (nestedTweets.length > 0) {
                                    for (const tweet of nestedTweets) {
                                        processSingleTweet(tweet);
                                    }
                                }
                            }
                        }
                    }
                }

                // 怜玢ボックスが倉わっおいたらモヌダルず同期
                if (searchBoxChanged) {
                    syncFromSearchBoxToModal();
                }

                // プロフィヌル/リストのボタン蚭眮DOM倉化時は垞にチェックしおも軜量
                try {
                    ensureProfileAddButton(false);
                    ensureListAddButton(false);
                } catch (_) {}

                // URL倉曎チェック (Debounced)
                _fireIfChanged();
            });

            const appContainer = document.querySelector('div[data-testid="app-container"]');
            const observeTarget = appContainer || document.body;
            observer.observe(observeTarget, { childList: true, subtree: true });

            // installNavigationHooks はそのたた利甚
            _fireIfChanged = installNavigationHooks(() => {
                // Navigation Change Logic...
                if (profileButtonObserver) { profileButtonObserver.disconnect(); profileButtonObserver = null; }
                if (listButtonObserver) { listButtonObserver.disconnect(); listButtonObserver = null; }

                manualOverrideOpen = false;
                reconcileUI();
                syncFromSearchBoxToModal();
                applyScopesToControls(readScopesFromURL());
                updateSaveButtonState();

                // ペヌゞ遷移時は匷制的に党スキャン (Force)
                processNewTweets(true);
                setupNativeSearchResizer();
            });
        };
        window.addEventListener('resize', debounce(()=>{
            if (modal.style.display === 'flex') { applyModalStoredPosition(); requestAnimationFrame(keepModalInViewport); }
            if (trigger.style.display !== 'none') { applyTriggerStoredPosition(); requestAnimationFrame(keepTriggerInViewport); }
        }, 100));
        loadModalState();
        reconcileUI();
        setupModalDrag();
        setupModalResize();
        // 排他チェックボックスのロゞック
        const setupExclusiveChecks = () => {
            const groups = [
                'verified', 'links', 'images', 'videos'
            ];
            groups.forEach(groupName => {
                const includeEl = document.getElementById(`adv-filter-${groupName}-include`);
                const excludeEl = document.getElementById(`adv-filter-${groupName}-exclude`);
                if (!includeEl || !excludeEl) return;
                const handleChange = (eventSource, oppositeEl) => {
                    if (eventSource.checked) {
                        oppositeEl.disabled = true;
                    } else {
                        oppositeEl.disabled = false;
                    }
                };
                includeEl.addEventListener('change', () => handleChange(includeEl, excludeEl));
                excludeEl.addEventListener('change', () => handleChange(excludeEl, includeEl));
            });
        };
        setupExclusiveChecks();
        setupObservers();

        // むベント委任のためのルヌト芁玠を取埗
        const appContainer = document.querySelector('div[data-testid="app-container"]') || document.body;

        // 監芖察象セレクタを結合
        const allSearchSelectorsStr = searchInputSelectors.join(', ');

        // 1. 怜玢ボックスの入力 (むベント委任)
        appContainer.addEventListener('input', (e) => {
            if (!e.target || !e.target.matches(allSearchSelectorsStr)) return;
            const input = e.target;

            if (isUpdating || modal.style.display === 'none') return;

            const activeInputs = getActiveSearchInputs();
            if (activeInputs.includes(input)) {
                parseQueryAndApplyToModal(input.value);
                applyScopesToControls(readScopesFromURL());
                updateSaveButtonState();
            }
        });

        // 2. タむピングガヌド (むベント委任)
        const typingEvents = ['input', 'keydown', 'keyup', 'compositionstart', 'compositionupdate', 'compositionend'];
        typingEvents.forEach(evName => {
            appContainer.addEventListener(evName, (e) => {
                if (e.target && e.target.matches(allSearchSelectorsStr)) {
                    markTyping();
                }
            }, { passive: true, capture: true }); // capture: true でより確実に補足
        });

        // 怜玢入力䞭、アプリ党䜓を持ち䞊げおサゞェストを衚瀺し぀぀、サむドバヌのノむズを隠す
        const handleNativeSearchFocus = (e) => {
            const target = e.target;
            if (!target || target.nodeType !== 1) return;

            const isSearchInput = target.matches(allSearchSelectorsStr) ||
                                  target.getAttribute('data-testid') === 'SearchBox_Search_Input';
            if (!isSearchInput) return;

            const modalEl = document.getElementById('advanced-search-modal');
            const reactRoot = document.getElementById('react-root');

            if (!modalEl || !reactRoot) return;

            // モヌダルが衚瀺されおいるかチェック (非衚瀺なら䜕もしない)
            const isModalVisible = window.getComputedStyle(modalEl).display !== 'none';

            if (e.type === 'focusin') {
                // モヌダルが開いおいる時だけ発動
                if (isModalVisible) {
                    modalEl.classList.add('adv-z-lower');
                    reactRoot.classList.add('adv-app-lifted');

                    // モヌダルの䜍眮を確認し、巊メニュヌず被るなら巊メニュヌを隠すフラグを立おる
                    const modalRect = modalEl.getBoundingClientRect();
                    // 巊メニュヌの幅は最倧で275px皋床(PC版)
                    // モヌダルの巊端が 300px 未満なら「巊メニュヌの䞊に重なっおいる」ずみなす
                    if (modalRect.left < 300) {
                        reactRoot.classList.add('adv-overlap-left-menu');
                    } else {
                        reactRoot.classList.remove('adv-overlap-left-menu');
                    }
                }
            } else if (e.type === 'focusout') {
                // クリック猶予を持たせお元に戻す
                setTimeout(() => {
                    modalEl.classList.remove('adv-z-lower');
                    reactRoot.classList.remove('adv-app-lifted');
                    reactRoot.classList.remove('adv-overlap-left-menu'); //フラグ解陀
                }, 200);
            }
        };
        appContainer.addEventListener('focusin', handleNativeSearchFocus);
        appContainer.addEventListener('focusout', handleNativeSearchFocus);

        // 3. フォヌム送信 (むベント委任)
        appContainer.addEventListener('submit', (e) => {
            if (!e.target || !e.target.closest('form')) return;

            // SearchBox_Search_Input を含むフォヌムか刀定
            const input = e.target.querySelector('input[data-testid="SearchBox_Search_Input"]');
            if (input) {
                const val = (input.value || '').trim();
                const {pf, lf} = readScopesFromControls();
                if (val) recordHistory(val, pf, lf);
            }
        }, true); // キャプチャフェヌズで実行

        // ▌ Setup background drop zones ▌
        // このブロックは、最初の renderAccounts / renderLists / renderSaved を呌ぶ前に眮く
        setupBackgroundDrop(tabAccountsPanel, accountsListEl,  unassignAccount);
        setupBackgroundDrop(tabListsPanel,    advListsListEl,  unassignList);
        setupBackgroundDrop(tabSavedPanel,    advSavedListEl,  unassignSaved);

        // ft_init を最優先で実行し、stateをロヌドさせる
        if (typeof ft_init === 'function') {
            ft_init();
        }

        // 䞇が䞀ロヌド倱敗しおいた堎合に備え、デフォルトStateを泚入しお null萜ちを防ぐ
        if (typeof ft_state === 'undefined' || !ft_state) {
            ft_state = ft_createDefaultState();
        }

        setupFavoritesDelegation();
        renderFavorites(); // 初期描画 (これで ft_state がある状態で走る)
        renderHistory();
        renderSaved();
        renderAccounts();
        renderMuted();
        // スマホ察応甚タッチ操䜜をドラッグ操䜜ぞ倉換するリスナヌを登録
        enableMobileDragSupport();
        // 保存された最埌のタブを読み蟌んでアクティブにする
        const initTabSetting = kv.get(INITIAL_TAB_KEY, 'last'); // 蚭定を取埗 (デフォルトは 'last')
        let targetTab = 'search';

        if (initTabSetting === 'last') {
            // 'last' の堎合は前回開いおいたタブを䜿う
            targetTab = kv.get(LAST_TAB_KEY, 'search');
        } else {
            // それ以倖の堎合は指定されたタブを䜿う
            targetTab = initTabSetting;
        }

        // もし指定されたタブが蚭定で「非衚瀺」になっおいる堎合、activateTab 内郚のロゞックで
        // 自動的に 'search' 等の衚瀺可胜なタブにフォヌルバックされるため、ここでは単玔に枡すだけでOK
        activateTab(targetTab || 'search');
        (async () => {
            const input = await waitForElement(searchInputSelectors.join(','), 7000);

            // 怜玢窓が芋぀かったらリサむザヌ蚭眮
            setupNativeSearchResizer();

            if (input) {
                syncFromSearchBoxToModal();
                applyScopesToControls(readScopesFromURL());
                updateSaveButtonState();
                processNewTweets(true);

                // force=true で初回描画を匷制
                ensureProfileAddButton(true);
                ensureListAddButton(true);

                /* --- Favorite Tags Init Scan --- */
                try {
                   processNewTweets(true);
                } catch(e) { console.error('[FT] Init error', e); }
            }
        })();
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
};

// --- 環境刀定ブヌトロヌダヌ ---
// 1. UserScript環境: GM_info があり、か぀アダプタヌによる遅延実行埅ち(window.__X_ADV_SEARCH_MAIN__)ではない堎合
if (typeof GM_info !== 'undefined' && typeof window.__X_ADV_SEARCH_MAIN__ === 'undefined') {
    __X_ADV_SEARCH_MAIN_LOGIC__();
}
// 2. 拡匵機胜環境: adapter.js から呌ばれるのを埅぀ために window に公開
else {
    window.__X_ADV_SEARCH_MAIN__ = __X_ADV_SEARCH_MAIN_LOGIC__;
}