Action Menu on Selection

Contextual popup with quick search links. Supports custom links and language settings.

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.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

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 Action Menu on Selection
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Contextual popup with quick search links. Supports custom links and language settings.
// @author NoOne
// @license MIT
// @match *://*/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @run-at document-end
// ==/UserScript==

(function() {
    'use strict';

    const PLACEHOLDER_SYMBOL = '❯';
    const ICON_HEIGHT = '15px';
    const STORAGE_KEY = 'TSAB_CustomButtons';
    const TRANSLATE_LANG_KEY = 'TSAB_TranslateTargetLang';
    const DEFAULT_BUTTONS = [];
    const DEFAULT_TRANSLATE_LANG = 'en';

    const ICON_DEFAULT_FALLBACK = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLUxpY2Vuc2U6IENDIEF0dHJpYnV0aW9uLiBNYWRlIGJ5IHp3aWNvbjogaHR0cHM6Ly93d3cuendpY29uLmNvbS8tLT4KPHN2ZyBmaWxsPSIjZmZmIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJNMy41MTIxMTcxMiwxNSBMOC4xNzE5MDIyOSwxNSBDOC4wNTk0OTE5NywxNC4wNTIzNTA2IDgsMTMuMDQ0NDU1NCA4LDEyIEM4LDEwLjk1NTU0NDYgOC4wNTk0OTE5Nyw5Ljk0NzY0OTQyIDguMTcxOTAyMjksOSBMMy41MTIxMTcxMiw5IEMzLjE4MDQ2MjY2LDkuOTM4MzM2NzggMywxMC45NDgwOTM3IDMsMTIgQzMsMTMuMDUxOTA2MyAzLjE4MDQ2MjY2LDE0LjA2MTY2MzIgMy41MTIxMTcxMiwxNSBMMy41MTIxMTcxMiwxNSBaIE0zLjkzNTUxOTY1LDE2IEM1LjEyNTkwNDMzLDE4LjM5NTM0NDQgNy4zNTIwNzY3OCwyMC4xODUxMTc3IDEwLjAyODAwOTMsMjAuNzgzMjkyIEM5LjI0ODg5NDUxLDE5LjcyMjc3NTEgOC42NTIxNjEzNiwxOC4wMzcxMzYyIDguMzEzNzUwNjcsMTYgTDMuOTM1NTE5NjUsMTYgTDMuOTM1NTE5NjUsMTYgWiBNMjAuNDg3ODgyOSwxNSBDMjAuODE5NTM3MywxNC4wNjE2NjMyIDIxLDEzLjA1MTkwNjMgMjEsMTIgQzIxLDEwLjk0ODA5MzcgMjAuODE5NTM3Myw5LjkzODMzNjc4IDIwLjQ4Nzg4MjksOSBMMTUuODI4MDk3Nyw5IEMxNS45NDA1MDgsOS45NDc2NDk0MiAxNiwxMC45NTU1NDQ2IDE2LDEyIEMxNiwxMy4wNDQ0NTU0IDE1Ljk0MDUwOCwxNC4wNTIzNTA2IDE1LjgyODA5NzcsMTUgTDIwLjQ4Nzg4MjksMTUgTDIwLjQ4Nzg4MjksMTUgWiBNMjAuMDY0NDgwNCwxNiBMMTUuNjg2MjQ5MywxNiBDMTUuMzQ3ODM4NiwxOC4wMzcxMzYyIDE0Ljc1MTEwNTUsMTkuNzIyNzc1MSAxMy45NzE5OTA3LDIwLjc4MzI5MiBDMTYuNjQ3OTIzMiwyMC4xODUxMTc3IDE4Ljg3NDA5NTcsMTguMzk1MzQ0NCAyMC4wNjQ0ODA0LDE2IEwyMC4wNjQ0ODA0LDE2IFogTTkuMTg0NDAyNjksMTUgTDE0LjgxNTU5NzMsMTUgQzE0LjkzNDAxNzcsMTQuMDYyMzg4MiAxNSwxMy4wNTI4MjU2IDE1LDEyIEMxNSwxMC45NDcxNzQ0IDE0LjkzNDAxNzcsOS45Mzc2MTE4MyAxNC44MTU1OTczLDkgTDkuMTg0NDAyNjksOSBDOS4wNjU5ODIyOSw5LjkzNzYxMTgzIDksMTAuOTQ3MTc0NCA5LDEyIEM5LDEzLjA1MjgyNTYgOS4wNjU5ODIyOSwxNC4wNjIzODgyIDkuMTg0NDAyNjksMTUgTDkuMTg0NDAyNjksMTUgWiBNOS4zMzQ5ODIzLDE2IEM5Ljg1NzE3MDgyLDE4Ljk2NzgyOTUgMTAuOTE4MDcyOSwyMSAxMiwyMSBDMTMuMDgxOTI3MSwyMSAxNC4xNDI4MjkyLDE4Ljk2NzgyOTUgMTQuNjY1MDE3NywxNiBMOS4zMzQ5ODIzLDE2IEw5LjMzNDk4MjMsMTYgWiBNMy45MzU1MTk2NSw4IEw4LjMxMzc1MDY3LDggQzguNjUyMTYxMzYsNS45NjI4NjM4MyA5LjI0ODg5NDUxLDQuMjc3MjI0ODYgMTAuMDI4MDA5MywzLjIxNjcwODA0IEM3LjM1MjA3Njc4LDMuODE0ODgyMzQgNS4xMjU5MDQzMyw1LjYwNDY1NTU2IDMuOTM1NTE5NjUsOCBMMy45MzU1MTk2NSw4IFogTTIwLjA2NDQ4MDQsOCBDMTguODc0MDk1Nyw1LjYwNDY1NTU2IDE2LjY0NzkyMzIsMy44MTQ4ODIzNCAxMy45NzE5OTA3LDMuMjE2NzA4MDQgQzE0Ljc1MTEwNTUsNC4yNzcyMjQ4NiAxNS4zNDc4Mzg2LDUuOTYyODYzODMgMTUuNjg2MjQ5Myw4IEwyMC4wNjQ0ODA0LDggTDIwLjA2NDQ4MDQsOCBaIE05LjMzNDk4MjMsOCBMMTQuNjY1MDE3Nyw4IEMxNC4xNDI4MjkyLDUuMDMyMTcwNDggMTMuMDgxOTI3MSwzIDEyLDMgQzEwLjkxODA3MjksMyA5Ljg1NzE3MDgyLDUuMDMyMTcwNDggOS4zMzQ5ODIzLDggTDkuMzM0OTgyMyw4IFogTTEyLDIyIEM2LjQ3NzE1MjUsMjIgMiwxNy41MjI4NDc1IDIsMTIgQzIsNi40NzcxNTI1IDYuNDc3MTUyNSwyIDEyLDIgQzE3LjUyMjg0NzUsMiAyMiw2LjQ3NzE1MjUgMjIsMTIgQzIyLDE3LjUyMjg0NzUgMTcuNTIyODQ3NSwyMiAxMiwyMiBaIi8+Cjwvc3ZnPgo=';
    const ICON_BRAVE_FULL = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLUxpY2Vuc2U6IFBELiBNYWRlIGJ5IHB1cHB5bGludXg6IGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBweWxpbnV4LXdvb2YtQ0UvcHVwcHlfaWNvbl90aGVtZS0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4xIj4KICA8ZyB0cmFuc2Zvcm09InNjYWxlKDAuNTIxKSI+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojRjc2RjMxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxOyIgZD0ibSA2NiwxNCA2MCwwIDE0LDE2IDEwLC0yIDEwLDEwIDAsMTAgMTQsMjAgLTE4LDcwIGEgMjAgMjAgMCAwIDEgLTgsMTAgbCAtNDAsMzAgYSAyMCAyMCAwIDAgMSAtMjQsMCBsIC00MCwtMzAgYSAyMCAyMCAwIDAgMSAtOCwtMTAgbCAtMTgsLTcwIDE0LC0yMCAwLC0xMCAxMCwtMTAgMTAsMiB6Ii8+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojRkZGO3N0cm9rZTpub25lOyIgZD0ibSA1Niw0MiAxNCw0IGEgMjAgMjAgMCAwIDAgOCwwIGwgMTQsLTQgYSAyMCwyMCAwIDAgMSA4LDAgbCAxNCw0IGEgMjAgMjAgMCAwIDAgOCwwIGwgMTQsLTQgMjAsMjggYSAxMCAxMCAwIDAgMSAwLDggbCAtMjIsMjIgMyw4IGEgMjAgMTUgMCAwIDEgMCw4IGEgMjUgMjUgMCAwIDEgLTgsOCBhIDggOCAwIDAgMSAtNiwwIGEgNDAgNDAgMCAwIDEgLTIwLC0xNCBhIDQgNCAwIDAgMSAwLC00IGwgMTIsLTEyIGEgNCA0IDAgMCAwIDAsLTQgbCAtNCwtMTIgYSAxMCAxMCAwIDAgMSAyLC03IGEgNDAgNDAgMCAwIDEgMjQsLTEwIGEgNjAgNjAgMCAwIDAgLTMwLDYgbCA0LDI0IGEgNDAsNDAgMCAwIDEgLTMwLDAgbCA0LC0yNCBhIDYwIDYwIDAgMCAwIC0zMCwtNiBhIDQwIDQwIDAgMCAxIDI0LDEwIGEgMTAgMTAgMCAwIDEgMiw3IGwgLTQsMTIgYSA0IDQgMCAwIDAgMCw0IGwgMTIsMTIgYSA0IDQgMCAwIDEgMCw0IGEgNDAgNDAgMCAwIDEgLTIwLDE0IGEgOCA4IDAgMCAxIC02LDAgYSAyNSAyNSAwIDAgMSAtOCwtOCBhIDIwIDE1IDAgMCAxIDAsLTggbCAzLC04IC0yMiwtMjIgYSAxMCAxMCAwIDAgMSAwLC04IHoiLz4KICAgIDxwYXRoIHN0eWxlPSJmaWxsOiNGRkY7c3Ryb2tlOm5vbmU7IiBkPSJtIDkyLDEyMCBhIDEwIDEwIDAgMCAxIDgsMCBsIDIwLDEwIC0yNCwyMCAtMjQsLTIwIHoiLz4KICA8L2c+Cjwvc3ZnPgo=';
    const ICON_TRANSLATE_FULL = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApLS0+CjwhLS1MaWNlbnNlOiBDQzAuIE1hZGUgYnkgU1ZHIFJlcG86IGh0dHBzOi8vd3d3LnN2Z3JlcG8uY29tL3N2Zy8yMjMwNDQvdHJhbnNsYXRlLWxhbmd1YWdlLS0+CjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA1MTEuOTk5IDUxMS45OTkiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMS45OTkgNTExLjk5OTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgogIDxwYXRoIHN0eWxlPSJmaWxsOiNCOEM5RDk7IiBkPSJNNDYxLjkwOSwxMzMuNTYzSDMyMC43NzhjLTQuOTg2LDAtOS43MDYsMi4yMjYtMTIuODc4LDYuMDc3Yy0zLjE3MiwzLjg0LTQuNDUyLDguOTA0LTMuNTA2LDEzLjc5CglsMzcuMTA4LDE5MS42MDdIMTkwLjMzMWMtNS4wMDksMC05LjczOSwyLjIzNy0xMi45MjIsNi4xMTFjLTMuMTcyLDMuODYyLTQuNDMsOC45Ni0zLjQ1LDEzLjg1N2wyNi43MTMsMTMzLjU2MwoJYzEuNjI1LDguMTE0LDguNTE1LDEzLjExMSwxNS43NzIsMTMuNDIzaDI0NS40NjZjMjcuNjE0LDAsNTAuMDg2LTIyLjQ3Miw1MC4wODYtNTAuMDg2VjE4My42NDkKCUM1MTEuOTk1LDE1Ni4wMzUsNDg5LjUyMywxMzMuNTYzLDQ2MS45MDksMTMzLjU2M3oiLz4KICA8cGF0aCBzdHlsZT0iZmlsbDojRTZGM0ZGOyIgZD0iTTQ2MS45MDksMjgzLjgyMWgtNTAuMDg2di0xNi42OTVjMC05LjIyLTcuNDc1LTE2LjY5NS0xNi42OTUtMTYuNjk1CgljLTkuMjIsMC0xNi42OTUsNy40NzUtMTYuNjk1LDE2LjY5NXYxNi42OTVoLTUwLjA4NmMtOS4yMiwwLTE2LjY5NSw3LjQ3NS0xNi42OTUsMTYuNjk1czcuNDc1LDE2LjY5NSwxNi42OTUsMTYuNjk1aDE3Ljk4MgoJYzMuMTk1LDE5Ljg2MiwxMi4yNjEsMzQuOTE2LDI1LjU1Myw1MC4xNTFjLTcuMTM3LDYuOTU2LTE0LjAzMSwxMy42MDItMjEuOTUsMjEuNTIxYy02LjUyLDYuNTE5LTYuNTIsMTcuMDksMCwyMy42MTEKCWM2LjUxOSw2LjUyLDE3LjA5MSw2LjUyLDIzLjYxMSwwYzcuNzk0LTcuNzkzLDE0LjY3NC0xNC40MjUsMjEuNTg2LTIxLjE2M2M2LjkwMiw2LjcyOSwxMy43ODksMTMuMzY4LDIxLjU4NiwyMS4xNjMKCWM2LjUxOSw2LjUyLDE3LjA5LDYuNTIxLDIzLjYxMSwwYzYuNTItNi41Miw2LjUyLTE3LjA5MSwwLTIzLjYxMWMtNy45MTQtNy45MTQtMTQuODAyLTE0LjU1NS0yMS45NS0yMS41MjEKCWMxMy4yOTMtMTUuMjM0LDIyLjM1Ny0zMC4yODgsMjUuNTUzLTUwLjE1MWgxNy45ODJjOS4yMiwwLDE2LjY5NS03LjQ3NSwxNi42OTUtMTYuNjk1UzQ3MS4xMjksMjgzLjgyMSw0NjEuOTA5LDI4My44MjF6CgkgTTM5NS4xMjgsMzQzLjIyOWMtNy4zMjMtOC43MzYtMTIuMTUyLTE2Ljc1My0xNC42NTItMjYuMDE3aDI5LjMwM0M0MDcuMjc5LDMyNi40NzYsNDAyLjQ0OSwzMzQuNDk0LDM5NS4xMjgsMzQzLjIyOXoiLz4KICA8cGF0aCBzdHlsZT0iZmlsbDojMjg2MENDOyIgZD0iTTM3Ny4yODYsMzU1LjY1NmMtMi41MDQtNi40LTguNjgyLTEwLjYxOC0xNS41NDktMTAuNjE4SDE5MC4zMzFjLTUuMDA5LDAtOS43MzksMi4yMzctMTIuOTIyLDYuMTExCgljLTMuMTcyLDMuODYyLTQuNDMsOC45Ni0zLjQ1LDEzLjg1N2wyNi43MTMsMTMzLjU2M2MxLjYyNSw4LjExNCw4LjUxNSwxMy4xMTEsMTUuNzcyLDEzLjQyM2MwLjQ3OSwwLjAxMSwwLjk1NywwLjAxMSwxLjQzNiwwCgljMy43MDYtMC4xNjcsNy40MTMtMS41ODEsMTAuNDk2LTQuNDE5bDE0NC42OTMtMTMzLjU2M0MzNzguMTIxLDM2OS4zNDYsMzc5Ljc5LDM2Mi4wNTYsMzc3LjI4NiwzNTUuNjU2eiIvPgogIDxwYXRoIHN0eWxlPSJmaWxsOiMxNjdFRTY7IiBkPSJNMzYxLjczNywzNzguNDI4SDUwLjA5Yy0yNy42MTksMC01MC4wODYtMjIuNDY3LTUwLjA4Ni01MC4wODZWNTAuMDg2QzAuMDA0LDIyLjQ2OCwyMi40NzIsMCw1MC4wOSwwCgloMjQ0Ljg2NWM4LDAsMTQuODY5LDUuNjc0LDE2LjM5MSwxMy41MjFsNjYuNzgxLDM0NS4wMzdjMC45NDYsNC44OTItMC4zMzcsOS45NTYtMy41MSwxMy43OTQKCUMzNzEuNDQzLDM3Ni4yLDM2Ni43MjYsMzc4LjQyOCwzNjEuNzM3LDM3OC40Mjh6Ii8+CiAgPHBhdGggc3R5bGU9ImZpbGw6I0U2RjNGRjsiIGQ9Ik0xNjYuOTU4LDI1NS45OTZjLTM2LjgxNCwwLTY2Ljc4MS0yOS45NjctNjYuNzgxLTY2Ljc4MXMyOS45NjctNjYuNzgxLDY2Ljc4MS02Ni43ODEKCWM5LjAzMiwwLDE3LjgwNCwxLjc5MywyNi4wMjEsNS4yODJjOC40NzgsMy42MiwxMi40MjQsMTMuNDM0LDguODA0LDIxLjkxM2MtMy42Miw4LjQ0Ni0xMy40MDIsMTIuNDI0LTIxLjkxMyw4LjgwNAoJYy00LjA0NC0xLjcyOS04LjQxMy0yLjYwOS0xMi45MTMtMi42MDljLTE4LjQyNCwwLTMzLjM5MSwxNC45NjctMzMuMzkxLDMzLjM5MXMxNC45NjcsMzMuMzkxLDMzLjM5MSwzMy4zOTEKCWMxMi4zMjYsMCwyMy4xMTktNi43MTcsMjguOTIzLTE2LjY5NWgtMTIuMjI4Yy05LjIyOCwwLTE2LjY5NS03LjQ2Ny0xNi42OTUtMTYuNjk1YzAtOS4yMjgsNy40NjctMTYuNjk1LDE2LjY5NS0xNi42OTVoMzMuMzkxCgljOS4yMjgsMCwxNi42OTUsNy40NjcsMTYuNjk1LDE2LjY5NUMyMzMuNzM5LDIyNi4wMjgsMjAzLjc3MiwyNTUuOTk2LDE2Ni45NTgsMjU1Ljk5NnoiLz4KPC9zdmc+Cg==';
    const ICON_GOOGLE_FULL = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBMaWNlbnNlOiBMb2dvLiBNYWRlIGJ5IEhhc2hpQ29ycDogaHR0cHM6Ly9naXRodWIuY29tL2hhc2hpY29ycC9kZXNpZ24tc3lzdGVtIC0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDE2IDE2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiPjxwYXRoIGZpbGw9IiM0Mjg1RjQiIGQ9Ik0xNC45IDguMTYxYzAtLjQ3Ni0uMDM5LS45NTQtLjEyMS0xLjQyMmgtNi42NHYyLjY5NWgzLjgwMmEzLjI0IDMuMjQgMCAwMS0xLjQwNyAyLjEyN3YxLjc1aDIuMjY5YzEuMzMyLTEuMjIgMi4wOTctMy4wMiAyLjA5Ny01LjE1eiIvPjxwYXRoIGZpbGw9IiMzNEE4NTMiIGQ9Ik04LjE0IDE1YzEuODk4IDAgMy40OTktLjYyIDQuNjY1LTEuNjlsLTIuMjY4LTEuNzQ5Yy0uNjMxLjQyNy0xLjQ0Ni42NjktMi4zOTUuNjY5LTEuODM2IDAtMy4zOTMtMS4yMzItMy45NTItMi44ODhIMS44NXYxLjgwM0E3LjA0NCA3LjA0NCAwIDAwOC4xNCAxNXoiLz48cGF0aCBmaWxsPSIjRkJCQzA0IiBkPSJNNC4xODcgOS4zNDJhNC4xNyA0LjE3IDAgMDEwLTIuNjhWNC44NTlIMS44NDlhNi45NyA2Ljk3IDAgMDAwIDYuMjg2bDIuMzM4LTEuODAzeiIvPjxwYXRoIGZpbGw9IiNFQTQzMzUiIGQ9Ik04LjE0IDMuNzdhMy44MzcgMy44MzcgMCAwMTIuNyAxLjA1bDIuMDEtMS45OTlhNi43ODYgNi43ODYgMCAwMC00LjcxLTEuODIgNy4wNDIgNy4wNDIgMCAwMC02LjI5IDMuODU4TDQuMTg2IDYuNjZjLjU1Ni0xLjY1OCAyLjExNi0yLjg5IDMuOTUyLTIuODl6Ii8+PC9zdmc+';
    const ICON_YANDEX_FULL = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLUxpY2Vuc2U6IE1JVC4gTWFkZSBieSBLZW5hbiBHdW5kb2dhbjogaHR0cHM6Ly9naXRodWIuY29tL2tlbmFuZ3VuZG9nYW4vZm9udGlzdG8tLT4KPHN2ZyBmaWxsPSIjZmZmIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9Ii01LjUgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJtNS4yIDI0di03Ljc4NmwtNS4yLTEzLjk2NGgyLjYxNmwzLjgzNCAxMC43NjcgNC40MS0xMy4wMThoMi40MDVsLTUuNjU4IDE2LjMwM3Y3LjY5N3oiLz4KPC9zdmc+Cg==';
    const ICON_SITE_PLACEHOLDER = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLUxpY2Vuc2U6IENDIEF0dHJpYnV0aW9uLiBNYWRlIGJ5IHp3aWNvbjogaHR0cHM6Ly93d3cuendpY29uLmNvbS8tLT4KPHN2ZyBmaWxsPSIjZmZmIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJNMy41MTIxMTcxMiwxNSBMOC4xNzE5MDIyOSwxNSBDOC4wNTk0OTE5NywxNC4wNTIzNTA2IDgsMTMuMDQ0NDU1NCA4LDEyIEM4LDEwLjk1NTU0NDYgOC4wNTk0OTE5Nyw5Ljk0NzY0OTQyIDguMTcxOTAyMjksOSBMMy41MTIxMTcxMiw5IEMzLjE4MDQ2MjY2LDkuOTM4MzM2NzggMywxMC45NDgwOTM3IDMsMTIgQzMsMTMuMDUxOTA2MyAzLjE4MDQ2MjY2LDE0LjA2MTY2MzIgMy41MTIxMTcxMiwxNSBMMy41MTIxMTcxMiwxNSBaIE0zLjkzNTUxOTY1LDE2IEM1LjEyNTkwNDMzLDE4LjM5NTM0NDQgNy4zNTIwNzY3OCwyMC4xODUxMTc3IDEwLjAyODAwOTMsMjAuNzgzMjkyIEM5LjI0ODg5NDUxLDE5LjcyMjc3NTEgOC42NTIxNjEzNiwxOC4wMzcxMzYyIDguMzEzNzUwNjcsMTYgTDMuOTM1NTE5NjUsMTYgTDMuOTM1NTE5NjUsMTYgWiBNMjAuNDg3ODgyOSwxNSBDMjAuODE5NTM3MywxNC4wNjE2NjMyIDIxLDEzLjA1MTkwNjMgMjEsMTIgQzIxLDEwLjk0ODA5MzcgMjAuODE5NTM3Myw5LjkzODMzNjc4IDIwLjQ4Nzg4MjksOSBMMTUuODI4MDk3Nyw5IEMxNS45NDA1MDgsOS45NDc2NDk0MiAxNiwxMC45NTU1NDQ2IDE2LDEyIEMxNiwxMy4wNDQ0NTU0IDE1Ljk0MDUwOCwxNC4wNTIzNTA2IDE1LjgyODA5NzcsMTUgTDIwLjQ4Nzg4MjksMTUgTDIwLjQ4Nzg4MjksMTUgWiBNMjAuMDY0NDgwNCwxNiBMMTUuNjg2MjQ5MywxNiBDMTUuMzQ3ODM4NiwxOC4wMzcxMzYyIDE0Ljc1MTEwNTUsMTkuNzIyNzc1MSAxMy45NzE5OTA3LDIwLjc4MzI5MiBDMTYuNjQ3OTIzMiwyMC4xODUxMTc3IDE4Ljg3NDA5NTcsMTguMzk1MzQ0NCAyMC4wNjQ0ODA0LDE2IEwyMC4wNjQ0ODA0LDE2IFogTTkuMTg0NDAyNjksMTUgTDE0LjgxNTU5NzMsMTUgQzE0LjkzNDAxNzcsMTQuMDYyMzg4MiAxNSwxMy4wNTI4MjU2IDE1LDEyIEMxNSwxMC45NDcxNzQ0IDE0LjkzNDAxNzcsOS45Mzc2MTE4MyAxNC44MTU1OTczLDkgTDkuMTg0NDAyNjksOSBDOS4wNjU5ODIyOSw5LjkzNzYxMTgzIDksMTAuOTQ3MTc0NCA5LDEyIEM5LDEzLjA1MjgyNTYgOS4wNjU5ODIyOSwxNC4wNjIzODgyIDkuMTg0NDAyNjksMTUgTDkuMTg0NDAyNjksMTUgWiBNOS4zMzQ5ODIzLDE2IEM5Ljg1NzE3MDgyLDE4Ljk2NzgyOTUgMTAuOTE4MDcyOSwyMSAxMiwyMSBDMTMuMDgxOTI3MSwyMSAxNC4xNDI4MjkyLDE4Ljk2NzgyOTUgMTQuNjY1MDE3NywxNiBMOS4zMzQ5ODIzLDE2IEw5LjMzNDk4MjMsMTYgWiBNMy45MzU1MTk2NSw4IEw4LjMxMzc1MDY3LDggQzguNjUyMTYxMzYsNS45NjI4NjM4MyA5LjI0ODg5NDUxLDQuMjc3MjI0ODYgMTAuMDI4MDA5MywzLjIxNjcwODA0IEM3LjM1MjA3Njc4LDMuODE0ODgyMzQgNS4xMjU5MDQzMyw1LjYwNDY1NTU2IDMuOTM1NTE5NjUsOCBMMy45MzU1MTk2NSw4IFogTTIwLjA2NDQ4MDQsOCBDMTguODc0MDk1Nyw1LjYwNDY1NTU2IDE2LjY0NzkyMzIsMy44MTQ4ODIzNCAxMy45NzE5OTA3LDMuMjE2NzA4MDQgQzE0Ljc1MTEwNTUsNC4yNzcyMjQ4NiAxNS4zNDc4Mzg2LDUuOTYyODYzODMgMTUuNjg2MjQ5Myw4IEwyMC4wNjQ0ODA0LDggTDIwLjA2NDQ4MDQsOCBaIE05LjMzNDk4MjMsOCBMMTQuNjY1MDE3Nyw4IEMxNC4xNDI4MjkyLDUuMDMyMTcwNDggMTMuMDgxOTI3MSwzIDEyLDMgQzEwLjkxODA3MjksMyA5Ljg1NzE3MDgyLDUuMDMyMTcwNDggOS4zMzQ5ODIzLDggTDkuMzM0OTgyMyw4IFogTTEyLDIyIEM2LjQ3NzE1MjUsMjIgMiwxNy41MjI4NDc1IDIsMTIgQzIsNi40NzcxNTI1IDYuNDc3MTUyNSwyIDEyLDIgQzE3LjUyMjg0NzUsMiAyMiw2LjQ3NzE1MjUgMjIsMTIgQzIyLDE3LjUyMjg0NzUgMTcuNTIyODQ3NSwyMiAxMiwyMiBaIi8+Cjwvc3ZnPgo=';

    const TRANSLATION_LANGS = {
        'fr': 'French',
        'en': 'English',
        'es': 'Spanish',
        'de': 'German',
        'it': 'Italian',
        'ru': 'Russian',
        'pt': 'Portuguese',
        'zh-CN': 'Chinese (Simplified)',
        'zh-TW' : 'Chinese (Traditional)',
        'ja': 'Japanese'
    };

    GM_addStyle(`
        #selection-panel {
            position: absolute;
            display: none;
            z-index: 10000;
            background: transparent;
            padding: 5px;
            border-radius: 8px;
            pointer-events: none;
            user-select: none;
            transform: scale(1);
            transform-origin: center bottom;
            white-space: nowrap;
        }
        #selection-panel .action-icon {
            height: ${ICON_HEIGHT};
            width: auto;
            display: flex !important;
            flex-shrink: 0;
            object-fit: contain;
            margin: 2px;
        }
        #selection-panel .action-button {
            width: 74px;
            height: 34px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            transition: 0.3s ease;
            margin-right: 5px;
            pointer-events: auto;
            background: linear-gradient(to bottom right, #2e8eff 20%, rgba(46, 142, 255, 0) 40%);
            background-color: rgba(46, 142, 255, 0.2);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-weight: 600;
            text-align: center;
            padding: 0;
            overflow: hidden;
            box-sizing: border-box;
        }
        #selection-panel .action-button:hover, #selection-panel .action-button:focus {
            background-color: rgba(46, 142, 255, 0.7);
            box-shadow: 0 0 10px rgba(46, 142, 255, 0.5);
            outline: none;
        }
        #selection-panel .action-button-inner {
            width: 70px;
            height: 31px;
            border-radius: 6px;
            background-color: #1a1a1a;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            font-size: 11px;
            color: #fff;
            text-align: center;
            box-sizing: border-box;
            line-height: 1;
            padding: 0 !important;
        }
        #selection-panel #placeholder-button {
            width: 34px;
            height: 34px;
            display: flex;
            justify-content: flex-start;
            align-items: center;
            transition: width 0.3s ease, margin-right 0.3s ease, background-color 0.3s ease;
        }
        #selection-panel .placeholder-expanded {
            width: max-content !important;
            margin-right: 5px;
            pointer-events: auto;
            justify-content: flex-start;
        }
        #selection-panel #placeholder-button .action-button-inner {
            width: 30px;
            height: 31px;
            padding: 0;
            overflow: hidden;
            margin-left: 0.17em;
        }
        #selection-panel #placeholder-button.placeholder-expanded .action-button-inner {
            width: calc(100% - 4px);
            justify-content: flex-start;
            padding: 0;
            gap: 0;
            overflow: visible;
        }
        #selection-panel #placeholder-button-content {
            width: 34px !important;
            height: 25px !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            font-size: 11px !important;
            transform: rotateY(0deg);
            transition: transform 0.3s ease !important;
            user-select: none !important;
            line-height: 1 !important;
            white-space: nowrap !important;
            padding: 0 !important;
            margin: 0 !important;
            transform-origin: center !important;
            flex-shrink: 0 !important;
        }
        #selection-panel .rotated {
            transform: rotateY(180deg) !important;
        }
        #selection-panel #placeholder-actions {
            display: none;
            align-items: center;
            height: 100%;
            transition: opacity 0.1s ease 0.2s;
            flex-shrink: 0;
            gap: 2px;
            padding: 0 5px 0 2px;
        }
        #selection-panel .placeholder-expanded #placeholder-actions {
            display: flex;
        }
        #selection-panel .internal-action-button {
            background: none;
            border: none;
            cursor: pointer;
            color: #fff;
            padding: 0 !important;
            width: 25px;
            height: 25px;
            border-radius: 4px;
            transition: background-color 0.2s ease;
            flex-shrink: 0;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
        }
        #selection-panel .internal-action-button:hover {
            background-color: rgba(255, 255, 255, 0.1);
        }

        #tsab-options-modal {
            position: fixed;
            z-index: 10001;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 700px;
            max-width: 90%;
            height: 90%;
            max-height: 90vh;
            background-color: #161a20;
            border-radius: 8px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
            color: #fff;
            padding: 20px;
            display: none;
            flex-direction: column;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }
        #tsab-options-modal .modal-icon-preview {
            height: 25px;
            width: 25px;
            margin-right: 10px;
            flex-shrink: 0;
            object-fit: contain;
        }
        #tsab-options-modal #modal-content-container {
            flex-grow: 1;
            overflow-y: auto;
        }
        #tsab-options-modal #modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #444;
            padding-bottom: 10px;
            margin-top: 0;
        }
        #tsab-options-modal #modal-header h2 {
            margin: 0;
            padding: 0;
            border-bottom: none;
        }

        #tsab-options-modal #close-modal-cross {
            background-color: transparent !important;
            border: none;
            cursor: pointer;
            color: #ff4d4d;
            font-size: 20px;
            height: 40px;
            width: 40px;
            font-weight: 800;
            line-height: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            appearance: none;
            -webkit-appearance: none;
        }
        #tsab-options-modal #close-modal-cross:hover,
        #tsab-options-modal #close-modal-cross:focus,
        #tsab-options-modal #close-modal-cross:active {
            background-color: transparent !important;
            box-shadow: none !important;
            outline: none !important;
            color: #ff4d4d !important;
        }

        #tsab-options-modal input[type="text"],
        #tsab-options-modal button:not(.delete-btn):not(#add-edit-button):not(#close-modal-cross),
        #tsab-options-modal .modal-select {
            width: 97%;
            padding: 0px 10px 0px 10px;
            margin-bottom: 10px;
            border-radius: 8px !important;
            background-color: #2b2f34;
            color: #fff;
            box-sizing: border-box;
            border: 1px solid transparent;
            height: 3em !important;
        }

        #tsab-options-modal #add-edit-button {
            width: 97%;
            background-color: #2e8eff;
            border: none;
            font-weight: 700;
            height: 5vh;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 8px;
            color: #fff;
            appearance: none;
            -webkit-appearance: none;
        }
        #tsab-options-modal #add-edit-button:hover,
        #tsab-options-modal #add-edit-button:focus,
        #tsab-options-modal #add-edit-button:active {
            background-color: #007bff !important;
            box-shadow: none !important;
            outline: none !important;
            color: #fff !important;
        }

        #tsab-options-modal #tsab-custom-buttons-list {
            list-style: none;
            padding: 10px 20px 10px 0px;
            margin-bottom: 10px;
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 15px;
        }

        #tsab-options-modal input[type="text"]:focus,
        #tsab-options-modal .modal-select:focus {
            outline: none;
            border-color: #2e8eff;
            box-shadow: 0 0 5px rgba(46, 142, 255, 0.5);
        }
        #tsab-options-modal .custom-button-item {
            width: 100%;
            height: 100px;
            background: radial-gradient(150% 120% at 35% 100%, #B7B1FF 20%, rgba(255, 255, 255, 0) 70%), #ffffffc7;
            border-radius: 10px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            position: relative;
            cursor: grab;
            user-select: none;
            transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
            font-family: inherit;
        }
        #tsab-options-modal .custom-button-item:hover {
            transform: scale(0.97);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
        }
        #tsab-options-modal .custom-button-item.dragging {
            opacity: 0.7;
            transform: scale(1.02);
            border: 1px dashed #2e8eff;
        }
        #tsab-options-modal .card-header {
            padding: 10px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            color: #333;
            height: 60px;
            box-sizing: border-box;
        }
        #tsab-options-modal .card-icon-container {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            box-shadow: inset 0px 0px 6px 0px rgba(0, 0, 0, 0.45);
            flex-shrink: 0;
            margin-right: 10px;
            padding: 0 !important;
            overflow: hidden;
        }
        #tsab-options-modal .card-icon {
            width: 30px;
            height: 30px;
            object-fit: contain;
            display: block;
            margin: 0 auto;
            border-radius: 50%;
        }
        #tsab-options-modal .site-name {
            font-weight: 700;
            font-size: 14px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            flex-grow: 1;
            text-align: right;
            color: #1a1a1a;
        }
        #tsab-options-modal .card-body {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 7px 7px 10px;
            box-sizing: border-box;
            flex-grow: 1;
        }
        #tsab-options-modal .delete-btn {
            background-color: rgba(0, 0, 0, 0.06);
            border: none;
            color: rgba(87, 77, 51, 0.66);
            padding: 8px 12px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 12px;
            font-weight: 700;
            transition: background-color 0.2s ease, transform 0.1s;
            line-height: 1;
            height: 30px;
            align-self: flex-end;
            margin-left: 10px;
            appearance: none;
            -webkit-appearance: none;
        }
        #tsab-options-modal .delete-btn:hover,
        #tsab-options-modal .delete-btn:focus,
        #tsab-options-modal .delete-btn:active {
            background-color: rgba(255, 0, 0, 0.5) !important;
            box-shadow: none !important;
            outline: none !important;
        }
        #tsab-options-modal .edit-info {
            color: #555;
            font-size: 11px;
            font-weight: 600;
            align-self: flex-end;
            margin-bottom: 5px;
            flex-grow: 1;
            text-align: left;
            cursor: pointer;
            transition: color 0.2s;
        }
        #tsab-options-modal .edit-info:hover {
            color: #2e8eff;
        }
        #tsab-options-modal .move-handle {
            display: none;
        }
    `);

    let panel;
    let modal;
    let editingIndex = -1;
    let draggedItem = null;
    let isModalOpen = false;

    function createIconElement(url, isModalPreview = false) {
        const img = document.createElement('img');
        img.src = url;
        img.className = isModalPreview ? 'modal-icon-preview' : 'action-icon';
        if (url && url.startsWith('http') && !url.includes('data:')) {
             img.onerror = function() {
                 this.src = ICON_DEFAULT_FALLBACK;
                 this.className = isModalPreview ? 'modal-icon-preview' : 'action-icon';
                 this.onerror = null;
             };
        } else if (!url) {
            img.src = ICON_DEFAULT_FALLBACK;
        }
        return img;
    }

    function getQuotedText() {
        const text = window.getSelection().toString().trim();
        return text ? `"${text}"` : '';
    }

    function getRawText() {
        return window.getSelection().toString().trim();
    }

    function createButton(idSuffix, text, iconUrl, onClick) {
        const button = document.createElement('button');
        button.id = `action-button${idSuffix.replace(/\s/g, '-')}`;
        button.className = 'action-button';
        button.title = text;

        const inner = document.createElement('div');
        inner.className = 'action-button-inner';

        const iconElement = createIconElement(iconUrl);
        inner.appendChild(iconElement);

        const textNode = document.createElement('span');
        textNode.textContent = text;
        textNode.style.marginLeft = '2px';
        textNode.style.fontSize = '10px';
        inner.appendChild(textNode);

        button.appendChild(inner);

        const clickHandler = (e) => {
            e.preventDefault();
            e.stopPropagation();
            onClick();
        };

        button.addEventListener('click', clickHandler);
        button.addEventListener('mousedown', (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        return button;
    }

    function createInternalActionButton(idSuffix, iconUrl, onClick, title) {
        const button = document.createElement('button');
        button.id = `internal-action-button${idSuffix.replace(/\s/g, '-')}`;
        button.className = 'internal-action-button';
        button.title = title || idSuffix.trim();

        const iconElement = createIconElement(iconUrl);
        button.appendChild(iconElement);

        const clickHandler = (e) => {
            e.preventDefault();
            e.stopPropagation();
            onClick();
        };

        button.addEventListener('click', clickHandler);
        button.addEventListener('mousedown', (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        return button;
    }

    function initializePanel() {
        panel = document.createElement('div');
        panel.id = 'selection-panel';
        document.body.appendChild(panel);

        const placeholderButton = document.createElement('button');
        placeholderButton.id = 'placeholder-button';

        let isDraggingPanel = false;
        let dragOffsetX = 0;
        let dragOffsetY = 0;

        placeholderButton.addEventListener('mousedown', (e) => {
            if (e.target.id !== 'placeholder-button-content') return;

            isDraggingPanel = true;

            const rect = panel.getBoundingClientRect();
            dragOffsetX = e.clientX - rect.left;
            dragOffsetY = e.clientY - rect.top;

            e.preventDefault();
            e.stopPropagation();
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDraggingPanel) return;

            panel.style.left = `${e.clientX - dragOffsetX}px`;
            panel.style.top  = `${e.clientY - dragOffsetY}px`;
        });

        document.addEventListener('mouseup', () => {
            isDraggingPanel = false;
        });
        placeholderButton.className = 'action-button';

        const placeholderInner = document.createElement('div');
        placeholderInner.className = 'action-button-inner';

        const placeholderContent = document.createElement('span');
        placeholderContent.id = 'placeholder-button-content';
        placeholderContent.textContent = PLACEHOLDER_SYMBOL;

        const placeholderActions = document.createElement('div');
        placeholderActions.id = 'placeholder-actions';

        const googleButton = createInternalActionButton(' Google', ICON_GOOGLE_FULL, () => {
            const text = getQuotedText();
            if (text) {
                window.open(`https://www.google.com/search?q=${encodeURIComponent(text)}`, '_blank');
            }
        }, 'Google Search');

        const yandexButton = createInternalActionButton(' Yandex', ICON_YANDEX_FULL, () => {
            const text = getQuotedText();
            if (text) {
                window.open(`https://yandex.com/search/?text=${encodeURIComponent(text)}`, '_blank');
            }
        }, 'Yandex Search');

        placeholderActions.appendChild(googleButton);
        placeholderActions.appendChild(yandexButton);

        placeholderInner.appendChild(placeholderContent);
        placeholderInner.appendChild(placeholderActions);
        placeholderButton.appendChild(placeholderInner);

        placeholderButton.addEventListener('click', (e) => {
            e.preventDefault();
            placeholderButton.classList.toggle('placeholder-expanded');
            placeholderContent.classList.toggle('rotated');
        });

        placeholderButton.addEventListener('mousedown', (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        const braveButton = createButton(' brave', ' Brave', ICON_BRAVE_FULL, () => {
            const text = getQuotedText();
            if (text) {
                window.open(`https://search.brave.com/search?q=${encodeURIComponent(text)}`, '_blank');
            }
            hidePanel();
        });

        const translateButton = createButton(' translate', ' Translate', ICON_TRANSLATE_FULL, () => {
            const text = getRawText();
            const targetLang = getTranslateLanguage();

            if (text) {
                const encodedText = encodeURIComponent(text);
                const translateUrl = `https://translate.google.com/?sl=auto&tl=${targetLang}&text=${encodedText}&op=translate`;
                window.open(translateUrl, '_blank');
            }
            hidePanel();
        });

        panel.appendChild(braveButton);
        panel.appendChild(translateButton);
        panel.appendChild(placeholderButton);

        addCustomButtonsToPanel();
    }

    function getSelectionText() {
        const selection = window.getSelection();
        return selection.toString().trim();
    }

    function hidePanel() {
        if (!panel) return;
        panel.style.display = 'none';

        const placeholder = document.getElementById('placeholder-button');
        const content = document.getElementById('placeholder-button-content');
        if (placeholder && content && placeholder.classList.contains('placeholder-expanded')) {
            placeholder.classList.remove('placeholder-expanded');
            content.classList.remove('rotated');
        }
    }

    function showPanel(range) {
        if (!panel) return;

        const selectedText = getSelectionText();
        if (!selectedText) {
            hidePanel();
            return;
        }

        let rect;
        try {
            rect = range.getBoundingClientRect();
        } catch (e) {
            hidePanel();
            return;
        }

        const scrollX = window.scrollX || window.pageXOffset;
        const scrollY = window.scrollY || window.pageYOffset;

        panel.style.display = 'flex';
        panel.style.visibility = 'hidden';

        let x = rect.left + rect.width / 2;
        let y = rect.top;

        panel.style.left = `${x}px`;
        panel.style.top = `${y}px`;

        requestAnimationFrame(() => {
            const panelWidth = panel.offsetWidth;
            const panelHeight = panel.offsetHeight;

            let finalX = x + scrollX - (panelWidth / 2);
            let finalY = y + scrollY - 10 - panelHeight;

            finalX = Math.max(scrollX + 5, Math.min(finalX, scrollX + window.innerWidth - panelWidth - 5));
            finalY = Math.max(scrollY + 5, finalY);

            panel.style.left = `${finalX}px`;
            panel.style.top = `${finalY}px`;
            panel.style.pointerEvents = 'auto';
            panel.style.visibility = 'visible';
        });
    }

    document.addEventListener('mouseup', (event) => {
        if (isModalOpen) return;

        const selection = window.getSelection();
        const selectedText = selection.toString().trim();
        const modalElement = document.getElementById('tsab-options-modal');

        if (selectedText && !event.target.closest('#selection-panel') && !(modalElement && modalElement.contains(event.target))) {
            if (selection.rangeCount > 0) {
                const range = selection.getRangeAt(0);
                showPanel(range);
            }
        } else if (!event.target.closest('#selection-panel') && !(modalElement && modalElement.contains(event.target))) {
            hidePanel();
        }
    });

    document.addEventListener('scroll', hidePanel, true);
    window.addEventListener('resize', hidePanel);

    function getCustomButtons() {
        return GM_getValue(STORAGE_KEY, DEFAULT_BUTTONS);
    }

    function addCustomButtonsToPanel() {
        const placeholderActions = document.getElementById('placeholder-actions');
        if (!placeholderActions) return;

        placeholderActions.querySelectorAll('.custom-button').forEach(btn => btn.remove());

        const customButtons = getCustomButtons();

        customButtons.forEach((btnConfig, index) => {
            const customButton = createInternalActionButton(` custom-${index}`, btnConfig.iconUrl, () => {
                const text = getQuotedText();
                if (text) {
                    const url = btnConfig.url.replace(/text/g, encodeURIComponent(text));
                    window.open(url, '_blank');
                }
            }, btnConfig.name);
            customButton.classList.add('custom-button');
            placeholderActions.appendChild(customButton);
        });
    }

    function saveCustomButtons(buttons) {
        GM_setValue(STORAGE_KEY, buttons);
        addCustomButtonsToPanel();
        renderCustomButtonsList();
    }

    function saveTranslateLanguage(langCode) {
        GM_setValue(TRANSLATE_LANG_KEY, langCode);
    }

    function getTranslateLanguage() {
        return GM_getValue(TRANSLATE_LANG_KEY, DEFAULT_TRANSLATE_LANG);
    }

    function openOptionsModal() {
        const modalElement = document.getElementById('tsab-options-modal');
        if (modalElement) {
            modalElement.style.display = 'flex';
            isModalOpen = true;
            renderCustomButtonsList();
            document.getElementById('translate-target-lang').value = getTranslateLanguage();
            hidePanel();
        }
    }

    function closeOptionsModal() {
        const modalElement = document.getElementById('tsab-options-modal');
        if (modalElement) {
            modalElement.style.display = 'none';
            isModalOpen = false;
            resetForm();
        }
    }

    function resetForm() {
        document.getElementById('button-name').value = '';
        document.getElementById('button-url').value = '';
        document.getElementById('button-icon').value = '';
        document.getElementById('add-edit-button').textContent = 'Add Button';
        editingIndex = -1;
    }

    function editButton(index) {
        const buttons = getCustomButtons();
        const buttonConfig = buttons[index];

        document.getElementById('button-name').value = buttonConfig.name || '';
        document.getElementById('button-url').value = buttonConfig.url;
        document.getElementById('button-icon').value = buttonConfig.iconUrl || '';
        document.getElementById('add-edit-button').textContent = 'Save Changes';
        editingIndex = index;
    }

    function removeButton(index) {
        if (confirm('Are you sure you want to remove this button?')) {
            const buttons = getCustomButtons();
            buttons.splice(index, 1);
            saveCustomButtons(buttons);
            resetForm();
        }
    }

    function handleAddEditButton() {
        let name = document.getElementById('button-name').value.trim();
        const url = document.getElementById('button-url').value.trim();
        let iconUrl = document.getElementById('button-icon').value.trim();

        if (!url) {
            alert('The URL Template field is mandatory.');
            return;
        }

        if (!name) {
            name = 'Custom Button';
        }
        if (!iconUrl) {
            iconUrl = ICON_SITE_PLACEHOLDER;
        }

        let buttons = getCustomButtons();
        const newButton = { name, url, iconUrl };

        if (editingIndex !== -1) {
            buttons[editingIndex] = newButton;
        } else {
            buttons.push(newButton);
        }

        saveCustomButtons(buttons);
        resetForm();
    }

    function handleDragStart(e) {
        draggedItem = this;
        e.dataTransfer.effectAllowed = 'move';
        e.dataTransfer.setData('text/plain', this.dataset.index);
        setTimeout(() => this.classList.add('dragging'), 0);
    }

    function handleDragEnd() {
        this.classList.remove('dragging');
        draggedItem = null;
        document.querySelectorAll('.drag-over').forEach(el => el.classList.remove('drag-over'));
    }

    function handleDragOver(e) {
        e.preventDefault();
        if (draggedItem && draggedItem !== this && this.classList.contains('custom-button-item')) {
             e.dataTransfer.dropEffect = 'move';
        }
    }

    function handleDragEnter(e) {
        e.preventDefault();
        if (draggedItem && draggedItem !== this && this.classList.contains('custom-button-item')) {
            this.classList.add('drag-over');
        }
    }

    function handleDragLeave() {
        this.classList.remove('drag-over');
    }

    function handleDrop(e) {
        e.stopPropagation();
        this.classList.remove('drag-over');

        if (draggedItem && draggedItem !== this) {
            const list = document.getElementById('tsab-custom-buttons-list');
            const items = Array.from(list.children);
            const fromIndex = parseInt(draggedItem.dataset.index, 10);
            const toIndex = parseInt(this.dataset.index, 10);

            if (!isNaN(fromIndex) && !isNaN(toIndex)) {
                let buttons = getCustomButtons();
                const [movedItem] = buttons.splice(fromIndex, 1);
                buttons.splice(toIndex, 0, movedItem);
                saveCustomButtons(buttons);
            }
        }
    }

    function renderCustomButtonsList() {
        const list = document.getElementById('tsab-custom-buttons-list');
        if (!list) return;

        Array.from(list.children).forEach(child => {
            child.removeEventListener('dragstart', handleDragStart);
            child.removeEventListener('dragend', handleDragEnd);
            child.removeEventListener('dragover', handleDragOver);
            child.removeEventListener('dragenter', handleDragEnter);
            child.removeEventListener('dragleave', handleDragLeave);
            child.removeEventListener('drop', handleDrop);
            child.remove();
        });

        list.innerHTML = '';
        const buttons = getCustomButtons();

        buttons.forEach((btn, index) => {
            const listItem = document.createElement('li');
            listItem.className = 'custom-button-item';
            listItem.draggable = true;
            listItem.dataset.index = index;

            listItem.addEventListener('dragstart', handleDragStart);
            listItem.addEventListener('dragend', handleDragEnd);
            listItem.addEventListener('dragover', handleDragOver);
            listItem.addEventListener('dragenter', handleDragEnter);
            listItem.addEventListener('dragleave', handleDragLeave);
            listItem.addEventListener('drop', handleDrop);

            const cardHeader = document.createElement('div');
            cardHeader.className = 'card-header';

            const iconContainer = document.createElement('div');
            iconContainer.className = 'card-icon-container';

            const iconElement = createIconElement(btn.iconUrl, true);
            iconElement.className = 'card-icon';
            iconContainer.appendChild(iconElement);
            cardHeader.appendChild(iconContainer);

            const siteNameSpan = document.createElement('span');
            siteNameSpan.className = 'site-name';
            siteNameSpan.textContent = btn.name || 'No Name';
            cardHeader.appendChild(siteNameSpan);

            listItem.appendChild(cardHeader);

            const cardBody = document.createElement('div');
            cardBody.className = 'card-body';

            const editInfoSpan = document.createElement('span');
            editInfoSpan.className = 'edit-info';
            editInfoSpan.textContent = 'EDIT';
            editInfoSpan.addEventListener('click', (e) => {
                e.stopPropagation();
                editButton(index);
            });
            cardBody.appendChild(editInfoSpan);

            const deleteBtn = document.createElement('button');
            deleteBtn.className = 'delete-btn';
            deleteBtn.textContent = 'Delete';
            deleteBtn.title = 'Remove this custom button';
            deleteBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                removeButton(index);
            });
            cardBody.appendChild(deleteBtn);

            listItem.appendChild(cardBody);

            list.appendChild(listItem);
        });
    }

    function createLanguageOptions() {
        let optionsHtml = '';
        for (const code in TRANSLATION_LANGS) {
            optionsHtml += `<option value="${code}">${TRANSLATION_LANGS[code]}</option>`;
        }
        return optionsHtml;
    }

    function initializeModal() {
        modal = document.createElement('div');
        modal.id = 'tsab-options-modal';
        modal.innerHTML = `
            <div id="modal-header">
                <h2>Settings</h2>
                <button id="close-modal-cross" title="Close (ESC)">×</button>
            </div>
            <div id="modal-content-container">
                <label for="translate-target-lang">Default Translation Language:</label>
                <select id="translate-target-lang" class="modal-select">
                    ${createLanguageOptions()}
                </select>

                <h3>Add/Edit Custom Expanded Button</h3>
                <label for="button-name">Name</label>
                <input type="text" id="button-name" placeholder="e.g., DuckDuckGo">

                <label for="button-url">URL (Use 'text' as a placeholder):</label>
                <input type="text" id="button-url" placeholder="e.g., https://duckduckgo.com/?q=text">

                <label for="button-icon">Icon URL (HTTPS/BASE64):</label>
                <input type="text" id="button-icon" placeholder="e.g., https://brave.com/favicon.ico">

                <button id="add-edit-button">Add Button</button>

                <h3>Custom Buttons (Drag to Reorder)</h3>
                <ul id="tsab-custom-buttons-list"></ul>
            </div>
        `;
        document.body.appendChild(modal);

        document.getElementById('add-edit-button').addEventListener('click', handleAddEditButton);
        document.getElementById('close-modal-cross').addEventListener('click', closeOptionsModal);

        document.getElementById('translate-target-lang').addEventListener('change', (e) => {
            saveTranslateLanguage(e.target.value);
        });

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && isModalOpen) {
                closeOptionsModal();
            }
        });
    }

    initializePanel();
    initializeModal();
    GM_registerMenuCommand('Settings', openOptionsModal);

})();