KG_Chat_Application

Enhance the chat abilities

当前为 2025-05-27 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         KG_Chat_Application
// @namespace    klavogonki
// @version      5.1.6
// @description  Enhance the chat abilities
// @author       Patcher
// @match        *://klavogonki.ru/*
// @exclude      *://klavogonki.ru/g/?gmid=*
// @exclude      *://klavogonki.ru/chatlogs/*
// @exclude      *://klavogonki.ru/storage/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=klavogonki.ru
// @grant        GM_xmlhttpRequest
// ==/UserScript==

/*
 * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/animationKeyframes.scss":
/*!*************************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/animationKeyframes.scss ***!
  \*************************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.shake-effect {\n  animation: shake 500ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;\n}\n\n@keyframes shake {\n  0% {\n    transform: translateX(0);\n  }\n  10% {\n    transform: translateX(-4px);\n  }\n  20% {\n    transform: translateX(6px);\n  }\n  30% {\n    transform: translateX(-8px);\n  }\n  40% {\n    transform: translateX(8px);\n  }\n  50% {\n    transform: translateX(-6px);\n  }\n  60% {\n    transform: translateX(5px);\n  }\n  70% {\n    transform: translateX(-3px);\n  }\n  80% {\n    transform: translateX(2px);\n  }\n  90% {\n    transform: translateX(-1px);\n  }\n  100% {\n    transform: translateX(0);\n  }\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/animationKeyframes.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/chatUsernameColors.scss":
/*!*************************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/chatUsernameColors.scss ***!
  \*************************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.chat-username-color-picker {\n  opacity: 0;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  height: fit-content;\n  width: fit-content;\n  background-color: var(--background-color);\n  border: 1px solid var(--border-color);\n  padding: 1em;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  overflow: hidden;\n  z-index: 1100;\n}\n.chat-username-color-picker .username-colors {\n  max-width: 360px;\n  min-width: 220px;\n  min-height: 50px;\n  max-height: 70vh;\n  overflow-x: hidden;\n  overflow-y: auto;\n  scrollbar-width: none;\n}\n.chat-username-color-picker h2 {\n  font-size: 1.2em !important;\n  margin: 0 !important;\n  text-align: center !important;\n  color: var(--third-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.6em !important;\n}\n.chat-username-color-picker .saved-username-colors,\n.chat-username-color-picker .generated-username-colors {\n  margin-top: 1em;\n}\n.chat-username-color-picker .saved-username-colors h3,\n.chat-username-color-picker .generated-username-colors h3 {\n  font-size: 1em !important;\n  margin: 0.5em 0 !important;\n  text-align: center !important;\n  color: var(--first-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.3em !important;\n}\n.chat-username-color-picker .saved-username-colors h3 .counter,\n.chat-username-color-picker .generated-username-colors h3 .counter {\n  font-size: 0.8em !important;\n  color: var(--fourth-accent-color) !important;\n  margin-left: 0.5em !important;\n}\n.chat-username-color-picker .generated-username-colors .username-entry.disabled-entry {\n  pointer-events: none;\n  opacity: 0.2;\n}\n.chat-username-color-picker .username-entry {\n  display: flex;\n  align-items: center;\n  justify-content: right;\n  padding: 0.3em;\n  border-bottom: 1px dashed var(--border-color);\n}\n.chat-username-color-picker .username-entry:last-child {\n  border-bottom: none;\n}\n.chat-username-color-picker .username-entry .username {\n  flex: 1;\n  filter: var(--username-filter) !important;\n}\n.chat-username-color-picker .username-entry .color-box {\n  cursor: pointer !important;\n  border-radius: 0.2em !important;\n  margin-left: 1em;\n  padding: 0.6em;\n  font-size: 0.8em;\n  font-family: monospace;\n  filter: var(--username-filter) !important;\n}\n.chat-username-color-picker .username-entry input[type=color] {\n  display: none !important;\n}\n.chat-username-color-picker .entry-btn {\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 25px;\n  height: 25px;\n  border-radius: 0.2em !important;\n  margin-left: 8px;\n}\n.chat-username-color-picker .remove-all-btn {\n  background-color: color-mix(in srgb, var(--second-accent-color) 40%, var(--background-color) 60%) !important;\n}\n.chat-username-color-picker .remove-all-btn svg {\n  stroke: var(--second-accent-color) !important;\n}\n.chat-username-color-picker .remove-btn,\n.chat-username-color-picker .edit-btn {\n  filter: var(--username-filter) !important;\n}\n.chat-username-color-picker .add-btn,\n.chat-username-color-picker .import-btn,\n.chat-username-color-picker .export-btn {\n  background-color: color-mix(in srgb, var(--first-accent-color) 40%, var(--background-color) 60%) !important;\n}\n.chat-username-color-picker .load-btn {\n  background-color: color-mix(in srgb, var(--fourth-accent-color) 40%, var(--background-color) 60%) !important;\n}\n.chat-username-color-picker .add-btn svg,\n.chat-username-color-picker .import-btn svg,\n.chat-username-color-picker .export-btn svg {\n  stroke: var(--first-accent-color) !important;\n}\n.chat-username-color-picker .load-btn svg {\n  stroke: var(--fourth-accent-color) !important;\n}\n.chat-username-color-picker .confirmation {\n  display: flex;\n  align-items: center;\n  background-color: var(--background-color) !important;\n  position: absolute;\n  left: 0 !important;\n  top: 0 !important;\n  right: 0 !important;\n}\n.chat-username-color-picker .confirmation .input-field {\n  padding: 0.6em !important;\n  background-color: var(--highlight-color);\n  color: var(--main-text-color);\n  caret-color: var(--main-text-color);\n  width: 150% !important;\n  border: none !important;\n  outline: none !important;\n}\n.chat-username-color-picker .confirmation .field-btn {\n  width: 50%;\n  padding: 0.6em;\n  border: none !important;\n  outline: none !important;\n  cursor: pointer;\n  transition: filter 0.3s ease;\n}\n.chat-username-color-picker .confirmation .field-btn:hover {\n  filter: blur(1.2);\n}\n.chat-username-color-picker .confirmation .confirm-btn {\n  border-radius: 0 0.4em 0 0 !important;\n  background-color: var(--first-accent-color) !important;\n  color: color-mix(in srgb, var(--first-accent-color) 20%, var(--background-color) 80%) !important;\n}\n.chat-username-color-picker .confirmation .cancel-btn {\n  border-radius: 0.4em 0 0 0 !important;\n  background-color: var(--second-accent-color) !important;\n  color: color-mix(in srgb, var(--second-accent-color) 20%, var(--background-color) 80%) !important;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/chatUsernameColors.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/emojiPanel.scss":
/*!*****************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/emojiPanel.scss ***!
  \*****************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.emoji-panel {\n  opacity: 0;\n  transition: opacity 0.3s ease;\n  position: absolute !important;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  background: var(--background-color) !important;\n  border: 1px solid var(--border-color) !important;\n  border-radius: 0.4em !important;\n  width: 380px;\n  height: 580px;\n  display: flex;\n  flex-direction: column;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  z-index: 1010;\n}\n.emoji-panel .emoji-search-container {\n  padding: 1em !important;\n  border: none !important;\n}\n.emoji-panel .emoji-search-container .emoji-search {\n  width: 100%;\n  padding: 8px;\n  border-radius: 4px;\n  background: var(--highlight-color) !important;\n  border: none !important;\n  border-radius: 0.2em !important;\n  color: var(--main-text-color) !important;\n  caret-color: var(--main-text-color) !important;\n  font-size: 0.9em !important;\n}\n.emoji-panel .emoji-search-container .emoji-search:focus {\n  outline: none;\n}\n.emoji-panel .emoji-categories {\n  position: sticky !important;\n  top: 0 !important;\n  display: grid !important;\n  grid-template-columns: repeat(auto-fill, minmax(32px, 1fr)) !important;\n  padding: 8px !important;\n  border-bottom: 1px solid var(--border-color) !important;\n  gap: 8px !important;\n  justify-content: center !important;\n  align-items: center !important;\n  overflow-x: auto !important;\n  scrollbar-width: thin !important;\n}\n.emoji-panel .emoji-categories .emoji-category-btn {\n  font-family: \"Noto Color Emoji\" !important;\n  position: relative !important;\n  background: none !important;\n  border: none !important;\n  padding: 4px !important;\n  cursor: pointer !important;\n  font-size: 1.5em !important;\n  transition: background-color 0.2s;\n  width: 100% !important;\n  height: 100% !important;\n  display: flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  aspect-ratio: 1 !important;\n  border-bottom: 3px solid transparent !important;\n}\n.emoji-panel .emoji-categories .emoji-category-btn.active {\n  opacity: 1;\n  border-bottom: 3px solid var(--third-accent-color) !important;\n}\n.emoji-panel .emoji-categories .emoji-category-btn:hover {\n  background-color: #333;\n}\n.emoji-panel .emoji-categories::-webkit-scrollbar {\n  width: 6px;\n  height: 6px;\n}\n.emoji-panel .emoji-categories::-webkit-scrollbar-track {\n  background: #1e1e1e;\n}\n.emoji-panel .emoji-categories::-webkit-scrollbar-thumb {\n  background: #444;\n  border-radius: 3px;\n}\n.emoji-panel .emoji-categories::-webkit-scrollbar-thumb:hover {\n  background: #555;\n}\n.emoji-panel .emoji-container {\n  flex: 1;\n  overflow-y: auto;\n  overflow-x: hidden !important;\n  display: grid !important;\n  gap: 8px !important;\n  width: 100% !important;\n  max-width: 100% !important;\n  scrollbar-width: none !important;\n}\n.emoji-panel .emoji-container .emoji-category-section {\n  margin-bottom: 10px;\n}\n.emoji-panel .emoji-container .emoji-category-section .emoji-category-header {\n  padding: 8px !important;\n  color: var(--main-text-color) !important;\n  font-size: 0.9em !important;\n  position: sticky !important;\n  top: 0px !important;\n  background-color: var(--background-color) !important;\n  z-index: 1 !important;\n  border-bottom: 1px solid var(--border-color) !important;\n  width: 100% !important;\n  box-sizing: border-box !important;\n  margin: 0 !important;\n}\n.emoji-panel .emoji-container .emoji-category-section .emoji-list {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(32px, 1fr)) !important;\n  padding: 8px !important;\n  gap: 8px;\n  align-content: start;\n}\n.emoji-panel .emoji-container .emoji-category-section .emoji-list .emoji-btn {\n  font-family: \"Noto Color Emoji\" !important;\n  background: none;\n  border: none;\n  border-radius: 0.2em !important;\n  padding: 4px !important;\n  cursor: pointer;\n  font-size: 1.5em !important;\n  transition: background-color 0.2s;\n  width: 100% !important;\n  height: 100% !important;\n  display: flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  aspect-ratio: 1 !important;\n}\n.emoji-panel .emoji-container .emoji-category-section .emoji-list .emoji-btn:hover {\n  background-color: var(--highlight-color) !important;\n}\n.emoji-panel .emoji-container::-webkit-scrollbar {\n  width: 6px;\n  height: 6px;\n}\n.emoji-panel .emoji-container::-webkit-scrollbar-track {\n  background: #1e1e1e;\n}\n.emoji-panel .emoji-container::-webkit-scrollbar-thumb {\n  background: #444;\n  border-radius: 3px;\n}\n.emoji-panel .emoji-container::-webkit-scrollbar-thumb:hover {\n  background: #555;\n}\n.emoji-panel .emoji-footer {\n  border-top: 1px solid var(--border-color) !important;\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: center;\n  padding: 5px;\n}\n.emoji-panel .emoji-footer .emoji-info-panel {\n  height: 40px !important;\n  padding: 8px !important;\n  display: flex !important;\n  align-items: center !important;\n  gap: 8px !important;\n  color: var(--main-text-color) !important;\n  font-size: 0.9em !important;\n  background-color: var(--background-color) !important;\n}\n.emoji-panel .emoji-footer .emoji-info-panel .emoji-info-icon {\n  font-family: \"Noto Color Emoji\" !important;\n  font-size: 1.5em !important;\n}\n.emoji-panel .emoji-footer .emoji-info-panel .emoji-info-keywords {\n  color: #888 !important;\n  font-style: italic !important;\n}\n.emoji-panel .emoji-footer .emoji-language-select {\n  border-radius: 0.4em !important;\n  border: none !important;\n  padding: 5px 10px;\n  font-size: 14px;\n  background-color: var(--foreground-color) !important;\n  color: var(--main-text-color) !important;\n  cursor: pointer;\n  transition: border-color 0.3s ease;\n}\n.emoji-panel .emoji-footer .emoji-language-select:hover {\n  border-color: var(--border-color) !important;\n}\n.emoji-panel .emoji-footer .emoji-language-select option {\n  font-size: 14px;\n  background-color: var(--foreground-color) !important;\n  color: var(--main-text-color) !important;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/emojiPanel.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/eventsPanel.scss":
/*!******************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/eventsPanel.scss ***!
  \******************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.events-panel {\n  opacity: 0;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  height: fit-content;\n  width: fit-content;\n  background-color: var(--background-color);\n  border: 1px solid var(--border-color) !important;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  overflow: hidden;\n  z-index: 1100;\n}\n.events-panel h2 {\n  font-size: 1.2em !important;\n  margin: 0 !important;\n  text-align: center !important;\n  color: var(--third-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding: 0.5em !important;\n}\n.events-panel .events-list {\n  max-width: 90vw;\n  max-height: 70vh;\n  min-width: 300px;\n  overflow-y: auto;\n  overflow-x: hidden;\n  scrollbar-width: none;\n  display: flex;\n  flex-direction: column;\n  gap: 0.5em;\n  padding: 1em;\n}\n.events-panel .events-list .list-item {\n  display: flex;\n  font: 500 0.9em \"Montserrat\", sans-serif;\n  color: black;\n  border-radius: 0.2em !important;\n  padding: 0.5em;\n  gap: 0.5em;\n  cursor: pointer;\n}\n.events-panel .events-list .list-item .event-icon svg,\n.events-panel .events-list .list-item .timestamp {\n  filter: brightness(0.4);\n}\n.events-panel .events-list .list-item.new-event:not(.old-event) {\n  margin-top: 2em;\n}\n.events-panel .events-list .list-item.new-event:not(.old-event) + .list-item.new-event:not(.old-event) {\n  margin-top: 0;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/eventsPanel.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/helpPanel.scss":
/*!****************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/helpPanel.scss ***!
  \****************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.help-panel {\n  opacity: 0;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  height: fit-content;\n  width: fit-content;\n  background-color: var(--background-color) !important;\n  border: 1px solid var(--border-color) !important;\n  padding: 1em;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  color: var(--main-text-color) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  z-index: 1100;\n}\n.help-panel .help-content {\n  max-height: 70vh !important;\n  min-width: 350px !important;\n  max-width: 450px !important;\n  overflow-y: auto;\n  scrollbar-width: none;\n}\n.help-panel .help-header {\n  margin-top: 0;\n  font-size: 1.5em;\n  text-align: center;\n  color: var(--first-accent-color) !important;\n}\n.help-panel .help-section-header {\n  margin-top: 0 !important;\n  margin-bottom: 1.5em !important;\n  font-size: 1.5em !important;\n  text-align: center;\n  color: var(--third-accent-color) !important;\n}\n.help-panel .help-section-subheader {\n  margin: 0.8em 0 1.2em 1em;\n  font-size: 0.9em;\n  color: var(--first-accent-color) !important;\n  font-weight: normal;\n  text-align: left;\n}\n.help-panel .help-list {\n  list-style-type: none;\n  padding-left: 0;\n}\n.help-panel .help-list .help-list-item {\n  display: flex;\n  align-items: center;\n  flex-direction: row;\n  padding: 0.3em;\n  border-bottom: 1px dashed var(--border-color) !important;\n}\n.help-panel .help-list .help-list-item:last-child {\n  border-bottom: none;\n}\n.help-panel .help-list .help-list-item .help-hotkey {\n  white-space: nowrap !important;\n  width: fit-content;\n  display: flex;\n  color: var(--hotkey-label-text-color) !important;\n  font-family: monospace;\n  background-color: var(--hotkey-label-background-color) !important;\n  border: 1px solid var(--hotkey-label-border-color) !important;\n  border-left: 3px solid var(--hotkey-label-border-color) !important;\n  border-radius: 0 0.2em 0.2em 0 !important;\n  padding: 2px 4px;\n  margin-right: 1em;\n}\n\n@media (max-width: 768px) {\n  .help-panel .help-section-header {\n    margin-bottom: 1em !important;\n    font-size: 1em !important;\n  }\n  .help-panel .help-section-subheader {\n    margin: 0.5em 0 1em 1em !important;\n    font-size: 0.8em !important;\n  }\n  .help-panel .help-hotkey {\n    margin-right: 0 !important;\n    margin-bottom: 0.5em !important;\n  }\n  .help-panel .help-list-item {\n    font-size: 0.9em !important;\n    flex-direction: column !important;\n    align-items: flex-start !important;\n  }\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/helpPanel.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/ignoredUsers.scss":
/*!*******************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/ignoredUsers.scss ***!
  \*******************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.ignored-users-panel {\n  opacity: 0;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  height: fit-content;\n  width: fit-content;\n  background-color: var(--background-color);\n  border: 1px solid var(--border-color) !important;\n  padding: 1em;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  overflow: hidden;\n  z-index: 1100;\n}\n.ignored-users-panel .ignored-users-list {\n  max-width: 360px;\n  min-width: 220px;\n  max-height: 70vh;\n  overflow-y: auto;\n  overflow-x: hidden;\n  scrollbar-width: none;\n}\n.ignored-users-panel .ignored-users-list h3 {\n  font-size: 1em !important;\n  margin: 0.5em 0 !important;\n  text-align: center !important;\n  color: var(--first-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.3em !important;\n}\n.ignored-users-panel .ignored-users-list h3 .counter {\n  font-size: 0.8em !important;\n  color: var(--fourth-accent-color) !important;\n  margin-left: 0.5em !important;\n}\n.ignored-users-panel .ignored-users-input-container {\n  display: flex;\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n}\n.ignored-users-panel .ignored-users-input-container .ignored-users-input {\n  flex: 1;\n  padding: 0.6em;\n  border: none !important;\n  border-radius: 0.4em 0 0 0 !important;\n  background-color: var(--highlight-color);\n  color: var(--main-text-color);\n  caret-color: var(--main-text-color);\n  outline: none !important;\n}\n.ignored-users-panel .ignored-users-input-container .ignored-users-add-btn {\n  padding: 0.6em;\n  background-color: var(--first-accent-color) !important;\n  color: color-mix(in srgb, var(--first-accent-color) 20%, var(--background-color) 80%) !important;\n  border: none !important;\n  outline: none !important;\n  border-radius: 0 0.4em 0 0 !important;\n  cursor: pointer;\n  transition: filter 0.3s ease;\n}\n.ignored-users-panel .ignored-users-input-container .ignored-users-add-btn:hover {\n  filter: brightness(1.2);\n}\n.ignored-users-panel .ignored-users-list {\n  margin-top: 2em;\n}\n.ignored-users-panel .ignored-users-list h2 {\n  font-size: 1.2em !important;\n  margin: 0 !important;\n  text-align: center !important;\n  color: var(--third-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.6em !important;\n}\n.ignored-users-panel .ignored-user-entry {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 0.3em;\n  border-bottom: 1px dashed var(--border-color) !important;\n}\n.ignored-users-panel .ignored-user-entry .username {\n  flex: 1;\n  color: var(--second-accent-color) !important;\n}\n.ignored-users-panel .ignored-user-entry .remove-btn {\n  cursor: pointer;\n  padding: 0.6em;\n  background-color: var(--second-accent-color) !important;\n  border: none;\n  border-radius: 0.2em !important;\n  filter: brightness(1);\n  transition: filter 0.3s ease;\n}\n.ignored-users-panel .ignored-user-entry .remove-btn svg {\n  stroke: color-mix(in srgb, var(--second-accent-color) 20%, var(--background-color) 80%) !important;\n}\n.ignored-users-panel .ignored-user-entry .remove-btn:hover {\n  filter: brightness(1.2);\n}\n\n.field-error {\n  background-color: var(--second-accent-color) !important;\n  color: color-mix(in srgb, var(--first-accent-color) 20%, var(--background-color) 80%) !important;\n  caret-color: color-mix(in srgb, var(--first-accent-color) 20%, var(--background-color) 80%) !important;\n  transition: background-color 0.5s ease;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/ignoredUsers.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/style.scss":
/*!************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/style.scss ***!
  \************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n___CSS_LOADER_EXPORT___.push([module.id, \"@import url(https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap);\"]);\n___CSS_LOADER_EXPORT___.push([module.id, \"@import url(https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap);\"]);\n___CSS_LOADER_EXPORT___.push([module.id, \"@import url(https://fonts.googleapis.com/css2?family=Iansui&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap);\"]);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `#app-chat-container {\n  border-radius: 0.4em 0.4em 0 0 !important;\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  height: 300px;\n  background-color: var(--background-color) !important;\n  color: var(--main-text-color) !important;\n  border: 1px solid var(--border-color) !important;\n  display: flex;\n  font-family: sans-serif;\n  z-index: 999;\n  min-width: 320px !important;\n  box-sizing: border-box;\n  max-width: 100vw;\n  overflow: hidden;\n  transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);\n}\n#app-chat-container a {\n  color: var(--fourth-accent-color) !important;\n  transition: filter 0.15s !important;\n}\n#app-chat-container a:hover {\n  filter: brightness(0.8) !important;\n}\n#app-chat-container img {\n  text-align: unset !important;\n  position: unset !important;\n  padding: unset;\n  margin: unset;\n  display: unset;\n  max-width: unset;\n  height: fit-content;\n  width: fit-content;\n}\n#app-chat-container .break-content {\n  display: inline-flex !important;\n  flex-basis: 100% !important;\n  margin: 0 !important;\n  white-space: pre-wrap !important;\n  flex-wrap: wrap !important;\n}\n#app-chat-container.maximized {\n  position: fixed !important;\n  z-index: 1010 !important;\n  top: 0 !important;\n  left: 0 !important;\n  right: 0 !important;\n  bottom: 0 !important;\n  width: 100vw !important;\n  height: 100vh !important;\n  border-radius: 0 !important;\n  overflow: hidden !important;\n  background-color: var(--background-color) !important;\n  display: flex !important;\n  flex-direction: column !important;\n}\n#app-chat-container:not(.visible-chat):not(.hidden-chat):not(.maximized):not(.floating-chat) {\n  display: none;\n  opacity: 0;\n}\n#app-chat-container.visible-chat {\n  transform: translateY(0) !important;\n}\n#app-chat-container.hidden-chat {\n  opacity: 1;\n  transform: translateY(calc(100% - 25px)) !important;\n}\n#app-chat-container.floating-chat {\n  border-radius: 0.4em !important;\n}\n#app-chat-container .font-size-control {\n  display: flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  height: 25px !important;\n  padding: 0 10px !important;\n  gap: 5px !important;\n  z-index: 6 !important;\n}\n#app-chat-container .font-size-control .font-size-slider {\n  width: 80px !important;\n  height: 4px !important;\n  -webkit-appearance: none !important;\n  appearance: none !important;\n  background-color: color-mix(in srgb, var(--third-accent-color) 50%, var(--foreground-color) 50%) !important;\n  outline: none !important;\n  border-radius: 2px !important;\n  transition: opacity 0.2s !important;\n}\n#app-chat-container .font-size-control .font-size-slider::-webkit-slider-thumb {\n  -webkit-appearance: none !important;\n  appearance: none !important;\n  width: 10px !important;\n  height: 10px !important;\n  border-radius: 50% !important;\n  background: var(--third-accent-color) !important;\n  cursor: pointer !important;\n}\n#app-chat-container .font-size-control .font-size-slider::-moz-range-thumb {\n  width: 10px !important;\n  height: 10px !important;\n  border-radius: 50% !important;\n  background: var(--third-accent-color) !important;\n  cursor: pointer !important;\n  border: none !important;\n}\n#app-chat-container .resize-handle {\n  position: absolute !important;\n  background: transparent !important;\n  z-index: 1000 !important;\n}\n#app-chat-container .resize-handle.top {\n  top: -3px !important;\n  left: 0 !important;\n  right: 0 !important;\n  height: 6px !important;\n  cursor: ns-resize !important;\n}\n#app-chat-container .resize-handle.left {\n  left: -3px !important;\n  top: 0 !important;\n  bottom: 0 !important;\n  width: 6px !important;\n  cursor: ew-resize !important;\n}\n#app-chat-container .resize-handle.right {\n  right: -3px !important;\n  top: 0 !important;\n  bottom: 0 !important;\n  width: 6px !important;\n  cursor: ew-resize !important;\n}\n#app-chat-container .chat-wrapper {\n  display: grid;\n  height: 100% !important;\n  width: 100% !important;\n  grid-template-areas: \"header    header\" \"messages  userlist\";\n  grid-template-rows: auto 1fr !important;\n  grid-template-columns: 1fr auto;\n  min-width: 320px !important;\n  overflow: hidden !important;\n  background-color: var(--background-color) !important;\n}\n#app-chat-container .chat-content {\n  margin: 0 !important;\n  background-color: var(--background-color) !important;\n  display: flex !important;\n  grid-area: messages;\n  flex-direction: column !important;\n  overflow: hidden !important;\n}\n#app-chat-container .messages-panel {\n  flex: 1 !important;\n  overflow-y: auto !important;\n  overflow-x: hidden !important;\n  padding: 1em !important;\n  display: flex;\n  flex-direction: column !important;\n  gap: 0.2em !important;\n  scrollbar-width: thin !important;\n  scrollbar-color: var(--foreground-color) var(--background-color) !important;\n}\n#app-chat-container .messages-panel.keyboard-active {\n  transition: margin-bottom 0.3s ease !important;\n}\n#app-chat-container .messages-panel::-webkit-scrollbar {\n  width: 8px !important;\n}\n#app-chat-container .messages-panel::-webkit-scrollbar-thumb {\n  background-color: var(--foreground-color) !important;\n}\n#app-chat-container .messages-panel::-webkit-scrollbar-track {\n  background-color: var(--background-color) !important;\n}\n#app-chat-container .input-container {\n  display: flex !important;\n  width: 100%;\n  align-items: center !important;\n  padding: 1em !important;\n  gap: 0.5em !important;\n  border-top: 1px solid var(--border-color) !important;\n  background-color: var(--background-color) !important;\n}\n#app-chat-container #message-input {\n  outline: none !important;\n  flex: 1 !important;\n  background-color: var(--highlight-color) !important;\n  color: var(--main-text-color) !important;\n  padding: 0.5em !important;\n  border-radius: 0.2em !important;\n  min-width: 0 !important;\n  border: none !important;\n  position: relative;\n  font-family: inherit !important;\n  line-height: normal !important;\n  transition: font-size 0.2s ease !important;\n}\n#app-chat-container #message-input.private-mode {\n  background-color: var(--private-mode-background-color) !important;\n  color: color-mix(in srgb, var(--private-mode-color) 50%, #d2d2d2 50%) !important;\n  caret-color: var(--private-mode-color) !important;\n}\n#app-chat-container #message-input.private-mode::placeholder {\n  color: var(--private-mode-placeholder-color) !important;\n}\n#app-chat-container .length-field-popup {\n  position: absolute !important;\n  display: flex !important;\n  font-size: 12px !important;\n  font-weight: bold !important;\n  font-family: \"Montserrat\", Iansui, sans-serif !important;\n  bottom: 60px;\n  transition: left 100ms ease-out !important;\n  height: 20px !important;\n  align-items: center !important;\n  justify-content: center !important;\n  padding: 2px 4px;\n  opacity: 0;\n  border: none !important;\n  z-index: 101 !important;\n}\n#app-chat-container .user-list-container {\n  display: flex;\n  grid-area: userlist;\n  width: fit-content !important;\n  min-width: 180px !important;\n  max-width: fit-content !important;\n  overflow-y: auto !important;\n  overflow-x: hidden !important;\n  background-color: var(--background-color) !important;\n  color: var(--main-text-color) !important;\n  border-left: 1px solid var(--border-color) !important;\n  scrollbar-width: thin !important;\n  scrollbar-color: var(--foreground-color) var(--background-color) !important;\n}\n#app-chat-container .user-list-container #user-list {\n  padding: 1em !important;\n  user-select: none !important;\n}\n#app-chat-container .user-list-container #user-list .separation {\n  margin-bottom: 1.5em !important;\n}\n#app-chat-container .user-list-container::-webkit-scrollbar-thumb {\n  background-color: var(--foreground-color) !important;\n}\n#app-chat-container .user-list-container::-webkit-scrollbar-track {\n  background-color: var(--background-color) !important;\n}\n#app-chat-container .floating-userlist {\n  box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1) !important;\n}\n#app-chat-container .reveal-userlist-btn {\n  position: absolute !important;\n  top: 50% !important;\n  right: -1px !important;\n  transform: translateY(-50%) !important;\n  z-index: 1000 !important;\n  display: flex;\n  align-items: center !important;\n  justify-content: center !important;\n  padding: 0.4em !important;\n  background-color: var(--foreground-color) !important;\n  font-size: 18px !important;\n  font-family: \"Noto Color Emoji\", sans-serif !important;\n  font-weight: bold !important;\n  border: 1px solid var(--border-color) !important;\n  border-radius: 0.4em 0 0 0.4em !important;\n  cursor: pointer !important;\n  transition: background 0.2s ease, opacity 0.2s ease !important;\n}\n#app-chat-container .reveal-userlist-btn:hover {\n  background-color: var(--background-color) !important;\n}\n#app-chat-container .message {\n  padding: 0.2em 0.4em !important;\n  display: flex;\n  flex-direction: row;\n  border-radius: 0.2em !important;\n  width: 100%;\n  max-width: 100% !important;\n  word-break: break-word !important;\n}\n#app-chat-container .message .pending-emoji {\n  margin-left: 0.5em !important;\n}\n#app-chat-container .message .message-text {\n  display: inline-flex !important;\n  flex-wrap: wrap !important;\n}\n#app-chat-container .message .message-text .emoji-adjuster {\n  font-family: \"Noto Color Emoji\", sans-serif !important;\n  font-size: 1.25em !important;\n  display: inline-flex !important;\n}\n#app-chat-container .message .message-text .mention {\n  position: relative;\n  height: fit-content !important;\n  color: var(--mention-color) !important;\n  display: inline-flex !important;\n  font-family: Montserrat !important;\n  font-weight: 500 !important;\n  letter-spacing: 0.05em !important;\n  z-index: 1 !important;\n}\n#app-chat-container .message .message-text .mention::before {\n  content: \"\";\n  position: absolute !important;\n  top: -2px !important;\n  left: -6px !important;\n  right: -6px !important;\n  bottom: -2px !important;\n  background-color: color-mix(in srgb, var(--mention-color) 30%, var(--foreground-color) 70%) !important;\n  border: 1px solid color-mix(in srgb, var(--mention-color) 90%, var(--foreground-color) 10%) !important;\n  opacity: 0.4;\n  border-radius: 0.2em !important;\n  z-index: -1;\n}\n#app-chat-container .message .message-text .md-heading {\n  font-family: \"Montserrat\", sans-serif !important;\n  margin: 0 !important;\n  padding: 0 !important;\n  color: #bf9d70 !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h1 {\n  font-size: 1.8em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h2 {\n  font-size: 1.6em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h3 {\n  font-size: 1.4em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h4 {\n  font-size: 1.2em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h5 {\n  font-size: 1.1em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text .md-heading.md-h6 {\n  font-size: 1em !important;\n  font-weight: bold !important;\n}\n#app-chat-container .message .message-text code,\n#app-chat-container .message .message-text .md-code {\n  display: inline-flex !important;\n  font-size: 1em !important;\n  font-family: \"Consolas\", monospace !important;\n  background-color: #2a2a2a !important;\n  border: 1px solid #333 !important;\n  border-radius: 0.2em !important;\n  padding: 0.1em 0.2em !important;\n  color: #82b32a !important;\n  filter: none !important;\n  white-space: break-spaces !important;\n}\n#app-chat-container .message .message-text .md-bold {\n  font-weight: bold !important;\n  color: var(--main-text-color) !important;\n}\n#app-chat-container .message .message-text .md-italic {\n  font-style: italic !important;\n  color: var(--main-text-color) !important;\n}\n#app-chat-container .message .message-text .md-strikethrough {\n  text-decoration: line-through !important;\n  color: var(--main-text-color) !important;\n}\n#app-chat-container .message.banned {\n  background-color: var(--ban-message-background-color) !important;\n  border: 1px solid var(--ban-message-border-color) !important;\n  border-left: 3px solid var(--ban-message-color) !important;\n  width: fit-content !important;\n}\n#app-chat-container .message.banned .time {\n  color: color-mix(in srgb, var(--ban-message-time-color) 70%, var(--foreground-color) 30%) !important;\n}\n#app-chat-container .message.banned .username,\n#app-chat-container .message.banned .message-text {\n  color: var(--ban-message-color) !important;\n}\n#app-chat-container .message.system {\n  background-color: var(--system-message-background-color) !important;\n  border: 1px solid var(--system-message-border-color) !important;\n  border-left: 3px solid var(--system-message-color) !important;\n  width: fit-content !important;\n  align-items: center !important;\n}\n#app-chat-container .message.system .time {\n  margin-right: unset !important;\n  color: color-mix(in srgb, var(--system-message-time-color) 70%, var(--foreground-color) 30%) !important;\n}\n#app-chat-container .message.system .username {\n  display: none !important;\n}\n#app-chat-container .message.system .message-text {\n  color: var(--system-message-color) !important;\n}\n#app-chat-container .message.private {\n  width: fit-content !important;\n}\n#app-chat-container .message.private.sent {\n  background-color: var(--private-message-sent-background-color) !important;\n  border: 1px solid var(--private-message-sent-border-color) !important;\n  border-left: 3px solid var(--private-message-sent-color) !important;\n}\n#app-chat-container .message.private.sent .time {\n  color: color-mix(in srgb, var(--private-message-sent-time-color) 70%, var(--foreground-color) 30%) !important;\n}\n#app-chat-container .message.private.sent .username,\n#app-chat-container .message.private.sent .message-text {\n  color: var(--private-message-sent-color) !important;\n}\n#app-chat-container .message.private.received {\n  background-color: var(--private-message-received-background-color) !important;\n  border: 1px solid var(--private-message-received-border-color) !important;\n  border-left: 3px solid var(--private-message-received-color) !important;\n}\n#app-chat-container .message.private.received .time {\n  color: color-mix(in srgb, var(--private-message-received-time-color) 70%, var(--foreground-color) 30%) !important;\n}\n#app-chat-container .message.private.received .username,\n#app-chat-container .message.private.received .message-text {\n  color: var(--private-message-received-color) !important;\n}\n#app-chat-container .message-info {\n  margin-right: 1em !important;\n  white-space: nowrap !important;\n  height: fit-content !important;\n}\n#app-chat-container .message-info .time {\n  font-size: 0.9em !important;\n  margin-right: 1em !important;\n  color: color-mix(in srgb, var(--main-text-color) 50%, var(--foreground-color) 50%) !important;\n}\n#app-chat-container .message-info .username {\n  font-size: 1em !important;\n}\n#app-chat-container .username {\n  filter: var(--username-filter) !important;\n}\n#app-chat-container .username,\n#app-chat-container .time {\n  cursor: pointer !important;\n  transition: opacity 0.15s ease !important;\n}\n#app-chat-container .username:hover,\n#app-chat-container .time:hover {\n  opacity: 0.8 !important;\n}\n#app-chat-container .user-item {\n  display: flex !important;\n  align-items: center !important;\n  padding: 0.2em !important;\n  margin-bottom: 0.2em !important;\n  border-radius: 0.2em !important;\n  max-width: 100% !important;\n  text-overflow: ellipsis !important;\n}\n#app-chat-container .user-item .user-avatar {\n  display: flex !important;\n  justify-content: center !important;\n  align-items: center !important;\n  width: 24px !important;\n  height: 24px !important;\n  font-size: 18px !important;\n  border-radius: 0.1em !important;\n  margin-right: 1em !important;\n  text-align: center !important;\n  line-height: 24px !important;\n  flex-shrink: 0 !important;\n}\n#app-chat-container .user-item .user-avatar.image-avatar {\n  cursor: pointer !important;\n  transform-origin: left !important;\n  transition: transform 0.15s ease-out !important;\n}\n#app-chat-container .user-item .user-avatar.image-avatar:hover {\n  transform: scale(2) !important;\n}\n#app-chat-container .user-item .user-avatar.svg-avatar {\n  font-family: \"Noto Color Emoji\", sans-serif !important;\n}\n#app-chat-container .user-item .user-info {\n  flex: 1 !important;\n  min-width: 0 !important;\n  overflow: hidden !important;\n  text-overflow: ellipsis !important;\n  white-space: nowrap !important;\n}\n#app-chat-container .user-item .role,\n#app-chat-container .user-item .game-indicator {\n  cursor: pointer !important;\n  font-family: \"Noto Color Emoji\", sans-serif !important;\n}\n#app-chat-container .user-item .role .games-count,\n#app-chat-container .user-item .game-indicator .games-count {\n  font-family: \"Montserrat\", sans-serif !important;\n  color: var(--third-accent-color) !important;\n  opacity: 0.8 !important;\n}\n#app-chat-container .header-buttons {\n  display: flex;\n  flex-direction: row;\n  width: fit-content;\n  order: 1;\n}\n#app-chat-container .header-buttons .header-button {\n  width: 25px !important;\n  height: 25px !important;\n}\n#app-chat-container .button {\n  display: flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  cursor: pointer !important;\n  background-color: transparent !important;\n  border: none !important;\n  outline: none !important;\n  margin: 0 !important;\n  padding: 0 !important;\n  transition: all 0.15s ease-out;\n}\n#app-chat-container .button:hover {\n  filter: brightness(1.2) !important;\n}\n#app-chat-container .emoji-trigger,\n#app-chat-container .private-mode-exit,\n#app-chat-container .send-button {\n  font-family: \"Noto Color Emoji\", sans-serif !important;\n  height: 28px !important;\n  width: 28px !important;\n  font-size: 1.5em !important;\n}\n#app-chat-container .emoji-trigger #smile_color {\n  fill: var(--third-accent-color) !important;\n}\n#app-chat-container .send-button .send {\n  fill: var(--third-accent-color) !important;\n}\n#app-chat-container .chat-toggle-button {\n  right: 0 !important;\n}\n#app-chat-container .button .yes {\n  fill: var(--first-accent-color) !important;\n}\n#app-chat-container .button .no {\n  fill: var(--second-accent-color) !important;\n}\n#app-chat-container .chat-events-button,\n#app-chat-container .chat-blocked-button,\n#app-chat-container .chat-colors-button,\n#app-chat-container .chat-theme-button,\n#app-chat-container .chat-help-button,\n#app-chat-container .chat-maximize-button {\n  fill: var(--third-accent-color);\n}\n#app-chat-container .chat-events-button.new-events {\n  fill: var(--first-accent-color) !important;\n}\n#app-chat-container .chat-events-button.no-events {\n  fill: var(--second-accent-color) !important;\n}\n#app-chat-container .chat-drag-area {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  grid-area: header;\n  background-color: var(--drag-area-background-color) !important;\n  border-bottom: 1px solid var(--border-color) !important;\n  border-radius: 0.4em 0.4em 0 0 !important;\n  cursor: move !important;\n}\n#app-chat-container .chat-drag-area .chat-dynamic-alert {\n  white-space: nowrap;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  font: 500 10px \"Montserrat\", sans-serif;\n  opacity: 0;\n  color: black;\n  transform: translate(-50%, 0);\n  position: absolute;\n  top: 40px;\n  left: 50%;\n  padding: 0.5em;\n  border-radius: 0.2em !important;\n  z-index: 1120;\n  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5) !important;\n}\n#app-chat-container .image-container .processed-image {\n  margin-right: 0.5em !important;\n}\n#app-chat-container .image-container .clickable-thumbnail {\n  display: flex !important;\n  align-items: center;\n  opacity: 1;\n  transition: opacity 0.15s ease-in-out;\n  border: none !important;\n  max-width: 150px !important;\n  max-height: 150px !important;\n  cursor: pointer;\n  background-color: transparent;\n  margin: 0.5em 0.5em 0 0 !important;\n  overflow: hidden !important;\n  border-radius: 0.2em !important;\n  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5) !important;\n}\n#app-chat-container .image-container .clickable-thumbnail:hover {\n  opacity: 0.8;\n}\n#app-chat-container .image-container .clickable-thumbnail img {\n  max-height: 100% !important;\n  max-width: 100% !important;\n  background-color: transparent;\n  object-fit: contain;\n}\n#app-chat-container .video-wrapper {\n  display: flex;\n  flex-direction: column;\n}\n#app-chat-container .video-wrapper .processed-video {\n  margin-bottom: 0.2em !important;\n}\n#app-chat-container .video-wrapper .youtube-info {\n  display: flex !important;\n  flex-direction: column !important;\n  margin-bottom: 0.2em !important;\n  font-family: \"Montserrat\", sans-serif !important;\n  font-size: 0.9em !important;\n  color: var(--fourth-accent-color) !important;\n  font-weight: 500 !important;\n  white-space: break-spaces !important;\n}\n#app-chat-container .video-container,\n#app-chat-container .youtube-thumb {\n  border-radius: 0.4em !important;\n  display: flex;\n  border: none;\n  height: 200px !important;\n  width: 356px !important;\n  background-color: var(--background-color) !important;\n}\n#app-chat-container .youtube-thumb {\n  cursor: pointer !important;\n  object-fit: cover !important;\n}\n#app-chat-container .youtube-thumb:hover {\n  filter: brightness(0.8);\n  transition: filter 0.3s ease;\n}\n\n.dimming-element {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5019607843);\n  z-index: 1010 !important;\n  opacity: 0;\n  transition: opacity 0.3s ease;\n}\n\n.scaled-thumbnail {\n  top: 50%;\n  left: 50%;\n  transform-origin: center center;\n  transform: translate(-50%, -50%) scale(1);\n  position: fixed;\n  opacity: 0;\n  z-index: 1015 !important;\n  max-height: 90vh;\n  max-width: 90vw;\n  cursor: pointer;\n  border-radius: 0.6em !important;\n  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5) !important;\n}\n\n.ignore-options-popup {\n  position: absolute !important;\n  display: flex;\n  gap: 0.5em !important;\n  top: 0;\n  left: 0;\n  z-index: 1020 !important;\n}\n.ignore-options-popup .ignore-option-btn {\n  padding: 8px 16px;\n  transition: all 0.3s;\n  cursor: pointer;\n  filter: brightness(1);\n  border-radius: 0.2em !important;\n}\n.ignore-options-popup .ignore-option-btn:hover {\n  filter: brightness(1.5);\n}\n\n.action-buttons-container {\n  position: absolute !important;\n  display: flex;\n  gap: 0.5em !important;\n  top: 0;\n  left: 0;\n  z-index: 1020 !important;\n}\n.action-buttons-container .delete-btn,\n.action-buttons-container .ignore-btn {\n  padding: 8px 16px;\n  transition: all 0.3s;\n  cursor: pointer;\n  filter: brightness(1);\n  border-radius: 0.2em !important;\n}\n.action-buttons-container .delete-btn:hover,\n.action-buttons-container .ignore-btn:hover {\n  filter: brightness(1.5);\n}\n\n.message-mode .delete-btn,\n.username-mode .ignore-btn,\n.ignore-option-btn {\n  background-color: hsl(0, 50%, 20%);\n  color: hsl(0, 60%, 70%);\n  border: 1px solid hsl(0, 50%, 35%);\n}\n\n.username-mode .delete-btn {\n  background-color: hsl(145, 50%, 20%);\n  color: hsl(145, 60%, 70%);\n  border: 1px solid hsl(145, 50%, 35%);\n}\n\n.time-mode .delete-btn {\n  background-color: hsl(200, 50%, 20%);\n  color: hsl(200, 60%, 70%);\n  border: 1px solid hsl(200, 50%, 35%);\n}\n\n.toggle-button {\n  font: bold 0.9em \"Montserrat\", sans-serif;\n  position: absolute;\n  top: 0;\n  right: 2em;\n  padding: 8px 16px;\n  transition: filter 0.3s;\n  border-radius: 0 0 0.2em 0.2em !important;\n  border-top: none;\n  min-width: 4em;\n}\n.toggle-button.toggle-hidden {\n  background: linear-gradient(to top, hsl(0, 50%, 20%), hsl(0, 50%, 25%));\n  color: hsl(0, 60%, 70%);\n  border-left: 1px solid hsl(0, 50%, 35%);\n  border-right: 1px solid hsl(0, 50%, 35%);\n  border-bottom: 1px solid hsl(0, 50%, 35%);\n}\n.toggle-button.toggle-shown {\n  background: linear-gradient(to top, hsl(30, 50%, 20%), hsl(30, 50%, 25%));\n  color: hsl(30, 60%, 70%);\n  border-left: 1px solid hsl(30, 50%, 35%);\n  border-right: 1px solid hsl(30, 50%, 35%);\n  border-bottom: 1px solid hsl(30, 50%, 35%);\n}\n.toggle-button:hover {\n  filter: brightness(1.5);\n}\n.toggle-button-hidden {\n  background-color: hsl(0, 20%, 10%);\n  color: hsl(0, 50%, 50%);\n  border: 1px solid hsl(0, 50%, 50%);\n}\n.toggle-button-show {\n  background-color: hsl(90, 20%, 10%);\n  color: hsl(90, 50%, 50%);\n  border: 1px solid hsl(90, 50%, 50%);\n}\n.toggle-button-hide {\n  background-color: hsl(50, 20%, 10%);\n  color: hsl(50, 50%, 50%);\n  border: 1px solid hsl(50, 50%, 50%);\n}\n\n.selected-message {\n  background-clip: padding-box !important;\n}\n.selected-message.message-mode {\n  background-color: hsla(0, 50%, 50%, 0.2) !important;\n  box-shadow: inset 0px 0px 0px 1px hsla(0, 50%, 50%, 0.4) !important;\n}\n.selected-message.username-mode {\n  background-color: hsla(145, 50%, 30%, 0.2) !important;\n  box-shadow: inset 0px 0px 0px 1px hsla(145, 50%, 50%, 0.4) !important;\n}\n.selected-message.time-mode {\n  background-color: hsla(200, 50%, 30%, 0.2) !important;\n  box-shadow: inset 0px 0px 0px 1px hsla(200, 50%, 50%, 0.4) !important;\n}\n\n.shown-message {\n  background-color: hsla(30, 60%, 30%, 0.2) !important;\n  box-shadow: inset 0px 0px 0px 1px hsla(30, 60%, 50%, 0.4) !important;\n  background-clip: padding-box !important;\n}\n\n.hidden-message {\n  display: none !important;\n}\n\n.new-messages-separator {\n  display: flex;\n  align-items: center;\n  height: 1em !important;\n}\n.new-messages-separator .separator-line {\n  flex-grow: 1 !important;\n  border: none !important;\n  border-top: 1px solid rgba(255, 132, 0, 0.568627451) !important;\n  margin: 0 !important;\n}\n.new-messages-separator .separator-icon {\n  background-color: rgba(255, 132, 0, 0.2509803922) !important;\n  border-radius: 0.2em !important;\n  padding: 0.2em 0.4em !important;\n  font-family: \"Noto Color Emoji\" !important;\n  cursor: pointer !important;\n}\n\n.bounce-in {\n  animation: bounceIn 500ms forwards;\n}\n\n.bounce-out {\n  animation: bounceOut 500ms forwards;\n}\n\n@keyframes bounceIn {\n  0% {\n    transform: translateY(0);\n    opacity: 0;\n  }\n  50% {\n    transform: translateY(-10px);\n    opacity: 1;\n  }\n  100% {\n    transform: translateY(0);\n    opacity: 1;\n  }\n}\n@keyframes bounceOut {\n  0% {\n    transform: translateY(0);\n    opacity: 1;\n  }\n  50% {\n    transform: translateY(-10px);\n    opacity: 1;\n  }\n  100% {\n    transform: translateY(0);\n    opacity: 0;\n  }\n}\n@media (max-width: 780px) {\n  #app-chat-container .chat-wrapper {\n    width: 100% !important;\n    border-right: none !important;\n  }\n}\n@media screen and (max-width: 768px), (hover: none), (pointer: coarse) {\n  body {\n    background-color: #1e1e1e !important;\n  }\n  #app-chat-container {\n    height: 100% !important;\n    width: 100vw !important;\n    position: fixed !important;\n    top: 0 !important;\n    bottom: 0 !important;\n    left: 0 !important;\n    right: 0 !important;\n    min-width: 100vw !important;\n    border: none !important;\n    border-radius: 0 !important;\n    overflow: hidden !important;\n  }\n  #app-chat-container .chat-wrapper {\n    grid-template-rows: 30px 1fr !important;\n  }\n  #app-chat-container .font-size-control .font-size-slider {\n    width: 120px !important;\n  }\n  #app-chat-container .resize-handle,\n  #app-chat-container .chat-toggle-button,\n  #app-chat-container .chat-maximize-button {\n    display: none !important;\n  }\n  #app-chat-container .font-size-control {\n    height: 30px !important;\n  }\n  #app-chat-container .header-buttons {\n    gap: 4px !important;\n  }\n  #app-chat-container .header-buttons .header-button {\n    width: 30px !important;\n    height: 30px !important;\n  }\n  #app-chat-container .header-buttons .header-button svg {\n    width: 18px !important;\n    height: 18px !important;\n  }\n  .ignore-options-popup {\n    flex-direction: column !important;\n  }\n  .ownbanner-back,\n  .feedback,\n  #reformal_tab,\n  #footer,\n  .threecol233 .col1 {\n    display: none !important;\n  }\n  .profile-iframe-container {\n    width: calc(100vw - 1em) !important;\n    min-width: 360px !important;\n    top: 0 !important;\n    transform: translate(-50%, 1em) !important;\n  }\n}\n.profile-iframe-container {\n  opacity: 0;\n  border: none;\n  display: flex;\n  position: fixed;\n  z-index: 1010 !important;\n  width: 75vw;\n  min-width: 1000px;\n  height: 80vh;\n  top: 48.5vh;\n  left: 50vw;\n  transform: translate(-50%, -50%);\n  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08) !important;\n  border-radius: 0.6em !important;\n}\n\n.clear-btn {\n  position: absolute !important;\n  top: 0 !important;\n  border-radius: 0.4em 0 0.2em 0 !important;\n  left: 0 !important;\n  cursor: pointer;\n  height: 25px !important;\n  width: 25px !important;\n  border: none;\n  filter: brightness(1);\n  transition: filter 0.3s ease;\n  background-color: var(--third-accent-color) !important;\n}\n.clear-btn:hover {\n  filter: brightness(1.2) !important;\n}\n.clear-btn svg {\n  stroke: color-mix(in srgb, var(--third-accent-color) 20%, var(--background-color) 80%) !important;\n}\n\n.close-btn {\n  position: absolute !important;\n  top: 0 !important;\n  right: 0 !important;\n  border-radius: 0 0.4em 0 0.2em !important;\n  cursor: pointer;\n  height: 25px !important;\n  width: 25px !important;\n  border: none;\n  filter: brightness(1);\n  transition: filter 0.3s ease;\n  background-color: var(--second-accent-color) !important;\n}\n.close-btn:hover {\n  filter: brightness(1.2) !important;\n}\n.close-btn svg {\n  stroke: color-mix(in srgb, var(--second-accent-color) 20%, var(--background-color) 80%) !important;\n}\n\n.image-info-container {\n  position: fixed;\n  display: flex;\n  align-items: center;\n  top: 1em;\n  left: 1em;\n  background: var(--background-color);\n  color: var(--main-text-color);\n  gap: 0.5em;\n  padding: 0.5em 1em;\n  border-radius: 0.2em !important;\n  font-size: 0.9em;\n  font-family: \"Montserrat\", sans-serif;\n  z-index: 1020 !important;\n  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5) !important;\n}\n.image-info-container .image-info-username {\n  color: var(--fourth-accent-color);\n  font-weight: 500;\n}\n.image-info-container .image-info-time {\n  cursor: pointer;\n  opacity: 0.8;\n}\n\n.custom-tooltip-popup {\n  font-family: \"Montserrat\", \"Noto Color Emoji\", sans-serif !important;\n  position: fixed;\n  background: rgb(22, 22, 22);\n  color: rgb(222, 222, 222);\n  padding: 0.5em;\n  z-index: 1200;\n  font-size: 0.9em;\n  pointer-events: none;\n  white-space: nowrap;\n  opacity: 0;\n  transition: opacity 0.1s;\n  display: none;\n  flex-direction: column;\n  left: 0;\n  top: 0;\n  border: 1px solid rgb(60, 60, 60) !important;\n  border-radius: 4px !important;\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3) !important;\n}\n.custom-tooltip-popup .tooltip-item {\n  display: inline-flex;\n  align-items: center;\n}\n.custom-tooltip-popup .tooltip-action {\n  font-weight: bold !important;\n  color: var(--hotkey-label-text-color) !important;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/style.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/themesPanel.scss":
/*!******************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/themesPanel.scss ***!
  \******************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.themes-panel {\n  opacity: 0;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  height: fit-content;\n  max-height: 70vh !important;\n  max-width: 400px !important;\n  width: fit-content;\n  scrollbar-width: none;\n  background-color: var(--background-color);\n  border: 1px solid var(--border-color);\n  padding: 1em;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  overflow-y: auto;\n  overflow-x: hidden;\n  z-index: 1100;\n}\n.themes-panel h2 {\n  font-size: 1.2em !important;\n  margin: 0 !important;\n  text-align: center !important;\n  color: var(--third-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.6em !important;\n}\n.themes-panel h3 {\n  font-size: 1em !important;\n  margin: 0.5em 0 !important;\n  text-align: center !important;\n  color: var(--first-accent-color) !important;\n  border-bottom: 1px dashed var(--border-color) !important;\n  padding-bottom: 0.3em !important;\n}\n.themes-panel h3 .counter {\n  font-size: 0.8em !important;\n  color: var(--fourth-accent-color) !important;\n  margin-left: 0.5em !important;\n}\n.themes-panel .dark-themes,\n.themes-panel .light-themes {\n  margin-top: 1em;\n}\n.themes-panel .dark-themes .theme-button,\n.themes-panel .light-themes .theme-button {\n  display: flex;\n  width: 100%;\n  padding: 0.5em;\n  margin: 0.5em 0;\n  background-color: var(--highlight-color);\n  color: var(--main-text-color);\n  border: none !important;\n  border-radius: 0.2em !important;\n  text-align: left;\n  cursor: pointer;\n  transition: all 0.2s ease;\n}\n.themes-panel .dark-themes .theme-button:hover,\n.themes-panel .light-themes .theme-button:hover {\n  background-color: var(--third-accent-color);\n  color: var(--background-color);\n}\n.themes-panel .dark-themes .theme-button.active-theme,\n.themes-panel .light-themes .theme-button.active-theme {\n  background-color: var(--third-accent-color);\n  color: var(--background-color);\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/themesPanel.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/updateCheck.scss":
/*!******************************************************************************************************************!*\
  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/updateCheck.scss ***!
  \******************************************************************************************************************/
/***/ ((module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.update-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  z-index: 1200;\n}\n\n.update-popup {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  background: var(--background-color) !important;\n  padding: 1em;\n  border-radius: 0.4em !important;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n  color: var(--main-text-color) !important;\n  font-family: \"Gill Sans\", \"Gill Sans MT\", Calibri, \"Trebuchet MS\", sans-serif;\n  z-index: 1200;\n  max-width: 400px;\n  min-width: 300px;\n}\n.update-popup .update-header {\n  margin-top: 0 !important;\n  font-size: 1.5em !important;\n  text-align: center !important;\n  color: var(--first-accent-color) !important;\n}\n.update-popup .update-script {\n  margin: 1rem 0 !important;\n  text-align: center !important;\n  font-size: 1.2em !important;\n  color: #4285f4 !important;\n}\n.update-popup p {\n  margin: 0.5rem 0;\n  text-align: center;\n}\n.update-popup p .version {\n  font-weight: bold;\n  color: var(--first-accent-color) !important;\n}\n.update-popup .button-container {\n  display: flex;\n  justify-content: center;\n  margin-top: 15px;\n}\n.update-popup .button-container button {\n  padding: 5px 10px !important;\n  width: 100% !important;\n  border-radius: 0.2em !important;\n  cursor: pointer !important;\n  font-size: 1rem !important;\n  border: none !important;\n  transition: background-color 0.15s !important;\n}\n.update-popup .button-container button.update-later {\n  margin-right: 10px;\n  background: #f1f1f1;\n}\n.update-popup .button-container button.update-skip {\n  margin-right: 10px;\n  background: #ffcc00;\n  color: #333;\n}\n.update-popup .button-container button.update-now {\n  background: #4285f4;\n  color: white;\n}\n.update-popup .button-container button:hover {\n  opacity: 0.9;\n}`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/updateCheck.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js");

/***/ }),

/***/ "./node_modules/css-loader/dist/runtime/api.js":
/*!*****************************************************!*\
  !*** ./node_modules/css-loader/dist/runtime/api.js ***!
  \*****************************************************/
/***/ ((module) => {

eval("\r\n\r\n/*\r\n  MIT License http://www.opensource.org/licenses/mit-license.php\r\n  Author Tobias Koppers @sokra\r\n*/\r\nmodule.exports = function (cssWithMappingToString) {\r\n  var list = [];\r\n\r\n  // return the list of modules as css string\r\n  list.toString = function toString() {\r\n    return this.map(function (item) {\r\n      var content = \"\";\r\n      var needLayer = typeof item[5] !== \"undefined\";\r\n      if (item[4]) {\r\n        content += \"@supports (\".concat(item[4], \") {\");\r\n      }\r\n      if (item[2]) {\r\n        content += \"@media \".concat(item[2], \" {\");\r\n      }\r\n      if (needLayer) {\r\n        content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\r\n      }\r\n      content += cssWithMappingToString(item);\r\n      if (needLayer) {\r\n        content += \"}\";\r\n      }\r\n      if (item[2]) {\r\n        content += \"}\";\r\n      }\r\n      if (item[4]) {\r\n        content += \"}\";\r\n      }\r\n      return content;\r\n    }).join(\"\");\r\n  };\r\n\r\n  // import a list of modules into the list\r\n  list.i = function i(modules, media, dedupe, supports, layer) {\r\n    if (typeof modules === \"string\") {\r\n      modules = [[null, modules, undefined]];\r\n    }\r\n    var alreadyImportedModules = {};\r\n    if (dedupe) {\r\n      for (var k = 0; k < this.length; k++) {\r\n        var id = this[k][0];\r\n        if (id != null) {\r\n          alreadyImportedModules[id] = true;\r\n        }\r\n      }\r\n    }\r\n    for (var _k = 0; _k < modules.length; _k++) {\r\n      var item = [].concat(modules[_k]);\r\n      if (dedupe && alreadyImportedModules[item[0]]) {\r\n        continue;\r\n      }\r\n      if (typeof layer !== \"undefined\") {\r\n        if (typeof item[5] === \"undefined\") {\r\n          item[5] = layer;\r\n        } else {\r\n          item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\r\n          item[5] = layer;\r\n        }\r\n      }\r\n      if (media) {\r\n        if (!item[2]) {\r\n          item[2] = media;\r\n        } else {\r\n          item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\r\n          item[2] = media;\r\n        }\r\n      }\r\n      if (supports) {\r\n        if (!item[4]) {\r\n          item[4] = \"\".concat(supports);\r\n        } else {\r\n          item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\r\n          item[4] = supports;\r\n        }\r\n      }\r\n      list.push(item);\r\n    }\r\n  };\r\n  return list;\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/css-loader/dist/runtime/api.js?");

/***/ }),

/***/ "./node_modules/css-loader/dist/runtime/noSourceMaps.js":
/*!**************************************************************!*\
  !*** ./node_modules/css-loader/dist/runtime/noSourceMaps.js ***!
  \**************************************************************/
/***/ ((module) => {

eval("\r\n\r\nmodule.exports = function (i) {\r\n  return i[1];\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/css-loader/dist/runtime/noSourceMaps.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":
/*!****************************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***!
  \****************************************************************************/
/***/ ((module) => {

eval("\r\n\r\nvar stylesInDOM = [];\r\nfunction getIndexByIdentifier(identifier) {\r\n  var result = -1;\r\n  for (var i = 0; i < stylesInDOM.length; i++) {\r\n    if (stylesInDOM[i].identifier === identifier) {\r\n      result = i;\r\n      break;\r\n    }\r\n  }\r\n  return result;\r\n}\r\nfunction modulesToDom(list, options) {\r\n  var idCountMap = {};\r\n  var identifiers = [];\r\n  for (var i = 0; i < list.length; i++) {\r\n    var item = list[i];\r\n    var id = options.base ? item[0] + options.base : item[0];\r\n    var count = idCountMap[id] || 0;\r\n    var identifier = \"\".concat(id, \" \").concat(count);\r\n    idCountMap[id] = count + 1;\r\n    var indexByIdentifier = getIndexByIdentifier(identifier);\r\n    var obj = {\r\n      css: item[1],\r\n      media: item[2],\r\n      sourceMap: item[3],\r\n      supports: item[4],\r\n      layer: item[5]\r\n    };\r\n    if (indexByIdentifier !== -1) {\r\n      stylesInDOM[indexByIdentifier].references++;\r\n      stylesInDOM[indexByIdentifier].updater(obj);\r\n    } else {\r\n      var updater = addElementStyle(obj, options);\r\n      options.byIndex = i;\r\n      stylesInDOM.splice(i, 0, {\r\n        identifier: identifier,\r\n        updater: updater,\r\n        references: 1\r\n      });\r\n    }\r\n    identifiers.push(identifier);\r\n  }\r\n  return identifiers;\r\n}\r\nfunction addElementStyle(obj, options) {\r\n  var api = options.domAPI(options);\r\n  api.update(obj);\r\n  var updater = function updater(newObj) {\r\n    if (newObj) {\r\n      if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\r\n        return;\r\n      }\r\n      api.update(obj = newObj);\r\n    } else {\r\n      api.remove();\r\n    }\r\n  };\r\n  return updater;\r\n}\r\nmodule.exports = function (list, options) {\r\n  options = options || {};\r\n  list = list || [];\r\n  var lastIdentifiers = modulesToDom(list, options);\r\n  return function update(newList) {\r\n    newList = newList || [];\r\n    for (var i = 0; i < lastIdentifiers.length; i++) {\r\n      var identifier = lastIdentifiers[i];\r\n      var index = getIndexByIdentifier(identifier);\r\n      stylesInDOM[index].references--;\r\n    }\r\n    var newLastIdentifiers = modulesToDom(newList, options);\r\n    for (var _i = 0; _i < lastIdentifiers.length; _i++) {\r\n      var _identifier = lastIdentifiers[_i];\r\n      var _index = getIndexByIdentifier(_identifier);\r\n      if (stylesInDOM[_index].references === 0) {\r\n        stylesInDOM[_index].updater();\r\n        stylesInDOM.splice(_index, 1);\r\n      }\r\n    }\r\n    lastIdentifiers = newLastIdentifiers;\r\n  };\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js":
/*!********************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***!
  \********************************************************************/
/***/ ((module) => {

eval("\r\n\r\nvar memo = {};\r\n\r\n/* istanbul ignore next  */\r\nfunction getTarget(target) {\r\n  if (typeof memo[target] === \"undefined\") {\r\n    var styleTarget = document.querySelector(target);\r\n\r\n    // Special case to return head of iframe instead of iframe itself\r\n    if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\r\n      try {\r\n        // This will throw an exception if access to iframe is blocked\r\n        // due to cross-origin restrictions\r\n        styleTarget = styleTarget.contentDocument.head;\r\n      } catch (e) {\r\n        // istanbul ignore next\r\n        styleTarget = null;\r\n      }\r\n    }\r\n    memo[target] = styleTarget;\r\n  }\r\n  return memo[target];\r\n}\r\n\r\n/* istanbul ignore next  */\r\nfunction insertBySelector(insert, style) {\r\n  var target = getTarget(insert);\r\n  if (!target) {\r\n    throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\r\n  }\r\n  target.appendChild(style);\r\n}\r\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/insertBySelector.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js":
/*!**********************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***!
  \**********************************************************************/
/***/ ((module) => {

eval("\r\n\r\n/* istanbul ignore next  */\r\nfunction insertStyleElement(options) {\r\n  var element = document.createElement(\"style\");\r\n  options.setAttributes(element, options.attributes);\r\n  options.insert(element, options.options);\r\n  return element;\r\n}\r\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/insertStyleElement.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":
/*!**********************************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***!
  \**********************************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

eval("\r\n\r\n/* istanbul ignore next  */\r\nfunction setAttributesWithoutAttributes(styleElement) {\r\n  var nonce =  true ? __webpack_require__.nc : 0;\r\n  if (nonce) {\r\n    styleElement.setAttribute(\"nonce\", nonce);\r\n  }\r\n}\r\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js":
/*!***************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***!
  \***************************************************************/
/***/ ((module) => {

eval("\r\n\r\n/* istanbul ignore next  */\r\nfunction apply(styleElement, options, obj) {\r\n  var css = \"\";\r\n  if (obj.supports) {\r\n    css += \"@supports (\".concat(obj.supports, \") {\");\r\n  }\r\n  if (obj.media) {\r\n    css += \"@media \".concat(obj.media, \" {\");\r\n  }\r\n  var needLayer = typeof obj.layer !== \"undefined\";\r\n  if (needLayer) {\r\n    css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\r\n  }\r\n  css += obj.css;\r\n  if (needLayer) {\r\n    css += \"}\";\r\n  }\r\n  if (obj.media) {\r\n    css += \"}\";\r\n  }\r\n  if (obj.supports) {\r\n    css += \"}\";\r\n  }\r\n  var sourceMap = obj.sourceMap;\r\n  if (sourceMap && typeof btoa !== \"undefined\") {\r\n    css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\r\n  }\r\n\r\n  // For old IE\r\n  /* istanbul ignore if  */\r\n  options.styleTagTransform(css, styleElement, options.options);\r\n}\r\nfunction removeStyleElement(styleElement) {\r\n  // istanbul ignore if\r\n  if (styleElement.parentNode === null) {\r\n    return false;\r\n  }\r\n  styleElement.parentNode.removeChild(styleElement);\r\n}\r\n\r\n/* istanbul ignore next  */\r\nfunction domAPI(options) {\r\n  if (typeof document === \"undefined\") {\r\n    return {\r\n      update: function update() {},\r\n      remove: function remove() {}\r\n    };\r\n  }\r\n  var styleElement = options.insertStyleElement(options);\r\n  return {\r\n    update: function update(obj) {\r\n      apply(styleElement, options, obj);\r\n    },\r\n    remove: function remove() {\r\n      removeStyleElement(styleElement);\r\n    }\r\n  };\r\n}\r\nmodule.exports = domAPI;\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/styleDomAPI.js?");

/***/ }),

/***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js":
/*!*********************************************************************!*\
  !*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***!
  \*********************************************************************/
/***/ ((module) => {

eval("\r\n\r\n/* istanbul ignore next  */\r\nfunction styleTagTransform(css, styleElement) {\r\n  if (styleElement.styleSheet) {\r\n    styleElement.styleSheet.cssText = css;\r\n  } else {\r\n    while (styleElement.firstChild) {\r\n      styleElement.removeChild(styleElement.firstChild);\r\n    }\r\n    styleElement.appendChild(document.createTextNode(css));\r\n  }\r\n}\r\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack://tampermonkey-script/./node_modules/style-loader/dist/runtime/styleTagTransform.js?");

/***/ }),

/***/ "./src/auth.js":
/*!*********************!*\
  !*** ./src/auth.js ***!
  \*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   getAuthData: () => (/* binding */ getAuthData),\n/* harmony export */   klavoauth: () => (/* binding */ klavoauth),\n/* harmony export */   removeChatParams: () => (/* binding */ removeChatParams)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers/helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\nfunction removeChatParams() {\r\n  localStorage.removeItem('klavoauth');\r\n  localStorage.removeItem('chatUsernameColor');\r\n  setTimeout(() => {\r\n    window.location.href = 'https://klavogonki.ru/gamelist/';\r\n  }, 500);\r\n}\r\n\r\nconst klavoauth = {\r\n  get username() {\r\n    const data = localStorage.getItem('klavoauth');\r\n    return data ? JSON.parse(data).username : '';\r\n  },\r\n  get password() {\r\n    const data = localStorage.getItem('klavoauth');\r\n    return data ? JSON.parse(data).password : '';\r\n  }\r\n};\r\n\r\nfunction getAuthData() {\r\n  // Only proceed if on the gamelist page\r\n  if (!window.location.href.startsWith('https://klavogonki.ru/gamelist/')) return;\r\n\r\n  try {\r\n    // Find the script containing PageData\r\n    const script = Array.from(document.scripts).find(s => s.text.includes('PageData'));\r\n    if (!script) throw new Error('PageData script not found');\r\n\r\n    // Extract and parse the JSON-like data inside the script\r\n    const rawData = script.text.match(/\\.constant\\('PageData', ([\\s\\S]*?})\\)/)[1];\r\n    const parsedData = JSON.parse(\r\n      rawData\r\n        .replace(/(\\w+):/g, '\"$1\":') // Fix object keys\r\n        .replace(/'/g, '\"') // Fix string quotes\r\n    );\r\n\r\n    const username = `${parsedData.chatParams.user.id}#${parsedData.chatParams.user.login}`;\r\n    const password = parsedData.chatParams.pass;\r\n\r\n    // Redirect only if it hasn’t happened before\r\n    if (!localStorage.getItem('klavoauth')) {\r\n      // Always update klavoauth with the latest data\r\n      localStorage.setItem('klavoauth', JSON.stringify({ username, password }));\r\n      // Save separate key for chat color background value\r\n      localStorage.setItem('chatUsernameColor', parsedData.chatParams.user.background);\r\n      setTimeout(() => {\r\n        window.location.href = 'https://klavogonki.ru';\r\n      }, 500);\r\n    }\r\n  } catch (e) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Authentication error: ${e.message}`,\r\n      ru: `Ошибка аутентификации: ${e.message}`\r\n    }, 'error');\r\n    removeChatParams();\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/auth.js?");

/***/ }),

/***/ "./src/chat/chatEvents.js":
/*!********************************!*\
  !*** ./src/chat/chatEvents.js ***!
  \********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   setupDragHandlers: () => (/* binding */ setupDragHandlers),\n/* harmony export */   setupResizeHandlers: () => (/* binding */ setupResizeHandlers),\n/* harmony export */   setupWindowResizeHandler: () => (/* binding */ setupWindowResizeHandler)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/layoutBehavior.js */ \"./src/helpers/layoutBehavior.js\");\n/* harmony import */ var _chatState_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chatState.js */ \"./src/chat/chatState.js\");\n\r\n\r\n\r\n\r\n\r\n// ------------------------- Drag Handlers (Floating) -------------------------\r\nlet isDragging = false,\r\n    dragStartX,\r\n    dragStartY,\r\n    dragStartLeft,\r\n    dragStartTop;\r\n\r\nfunction setupDragHandlers() {\r\n  document.addEventListener('mousedown', (e) => {\r\n    const dragArea = e.target.closest('.chat-drag-area');\r\n    if (!dragArea) return;\r\n\r\n    const chat = document.getElementById('app-chat-container');\r\n    let chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.getChatState)();\r\n\r\n    isDragging = true;\r\n    dragStartX = e.clientX;\r\n    dragStartY = e.clientY;\r\n    dragStartLeft = chat.offsetLeft;\r\n    // Use the computed top if no inline style exists\r\n    dragStartTop = parseInt(chat.style.top) || chat.getBoundingClientRect().top;\r\n    \r\n    // If the chat isn’t already floating, convert it now\r\n    if (!chatState.floating) {\r\n      const newTop = window.innerHeight - chat.offsetHeight;\r\n      chat.style.top = newTop + 'px';\r\n      chat.style.bottom = '';\r\n      chatState.top = newTop;\r\n      chatState.floating = true;\r\n      chat.classList.add(\"floating-chat\");\r\n      (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.saveChatState)(chatState);\r\n    }\r\n\r\n    document.body.style.userSelect = 'none';\r\n  });\r\n\r\n  document.addEventListener('mousemove', (e) => {\r\n    if (!isDragging) return;\r\n\r\n    const chat = document.getElementById('app-chat-container');\r\n    const viewportWidth = window.innerWidth;\r\n    const viewportHeight = window.innerHeight;\r\n    const deltaX = e.clientX - dragStartX;\r\n    const deltaY = e.clientY - dragStartY;\r\n    const newLeft = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(dragStartLeft + deltaX, 0, viewportWidth - chat.offsetWidth);\r\n    // Ensure the chat does not go above the viewport (>= 0) or below viewport bottom\r\n    const newTop = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(dragStartTop + deltaY, 0, viewportHeight - chat.offsetHeight);\r\n    \r\n    chat.style.left = newLeft + 'px';\r\n    chat.style.top = newTop + 'px';\r\n    \r\n    let chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.getChatState)();\r\n    chatState.left = newLeft;\r\n    chatState.top = newTop;\r\n    chatState.floating = true;\r\n    (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.saveChatState)(chatState);\r\n  });\r\n\r\n  document.addEventListener('mouseup', () => {\r\n    if (!isDragging) return;\r\n    isDragging = false;\r\n\r\n    const chat = document.getElementById('app-chat-container');\r\n    const viewportWidth = window.innerWidth;\r\n    const viewportHeight = window.innerHeight;\r\n    const chatRect = chat.getBoundingClientRect();\r\n    const SNAP_THRESHOLD = 50;\r\n    \r\n    const outOfBounds = chatRect.left < 0 || chatRect.top < 0 ||\r\n                        chatRect.right > viewportWidth || chatRect.bottom > viewportHeight;\r\n    const nearBottom = (viewportHeight - chatRect.bottom) < SNAP_THRESHOLD;\r\n    \r\n    let chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.getChatState)();\r\n    if (outOfBounds || nearBottom) {\r\n      // Snap to bottom when out of bounds\r\n      chat.style.top = '';\r\n      chat.style.bottom = '0';\r\n      chatState.floating = false;\r\n      chat.classList.remove(\"floating-chat\");\r\n    } else {\r\n      chatState.floating = true;\r\n      chatState.top = chatRect.top;\r\n      chat.classList.add(\"floating-chat\");\r\n    }\r\n    \r\n    (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.saveChatState)(chatState);\r\n    document.body.style.userSelect = '';\r\n  });\r\n}\r\n\r\n// ------------------------- Resize Handlers -------------------------\r\nlet isResizing = false,\r\n    resizeType = null,\r\n    startX,\r\n    startY,\r\n    startWidth,\r\n    startHeight,\r\n    startLeft,\r\n    startTop,\r\n    offsetY = 0;  // used to keep the cursor's relative position on the edge\r\n\r\nfunction setupResizeHandlers() {\r\n  document.addEventListener('mousedown', (e) => {\r\n    const handle = e.target.closest('.resize-handle');\r\n    if (!handle) return;\r\n    isResizing = true;\r\n    resizeType = handle.classList[1]; // e.g., 'top', 'left', 'right'\r\n    const chat = document.getElementById('app-chat-container');\r\n    startX = e.clientX;\r\n    startY = e.clientY;\r\n    startWidth = chat.offsetWidth;\r\n    startHeight = chat.offsetHeight;\r\n    startLeft = chat.offsetLeft;\r\n    // Use inline style top if available, otherwise the computed top\r\n    startTop = parseInt(chat.style.top) || chat.getBoundingClientRect().top;\r\n    offsetY = e.clientY - startTop;  // capture the cursor offset relative to chat's top edge\r\n    document.body.style.userSelect = 'none';\r\n  });\r\n\r\n  document.addEventListener('mousemove', (e) => {\r\n    if (!isResizing) return;\r\n    const chat = document.getElementById('app-chat-container');\r\n    const viewportWidth = window.innerWidth;\r\n    const viewportHeight = window.innerHeight;\r\n    const computedStyle = getComputedStyle(document.documentElement);\r\n    const minWidth = parseInt(computedStyle.getPropertyValue('--min-chat-width')) || 250;\r\n    const minHeight = parseInt(computedStyle.getPropertyValue('--min-chat-height')) || 200;\r\n    let chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.getChatState)();\r\n\r\n    // Horizontal resizing (applies for left and right handles)\r\n    if (resizeType === 'left') {\r\n      const newWidth = Math.max(minWidth, startWidth - (e.clientX - startX));\r\n      const newLeft = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(startLeft + (e.clientX - startX), 0, viewportWidth - newWidth);\r\n      chat.style.width = newWidth + 'px';\r\n      chat.style.left = newLeft + 'px';\r\n      chatState.width = newWidth;\r\n      chatState.left = newLeft;\r\n    } else if (resizeType === 'right') {\r\n      const maxWidth = viewportWidth - chat.getBoundingClientRect().left;\r\n      const newWidth = Math.min(maxWidth, Math.max(minWidth, startWidth + (e.clientX - startX)));\r\n      chat.style.width = newWidth + 'px';\r\n      chatState.width = newWidth;\r\n    }\r\n\r\n    // Vertical resizing for the three handles will use the cursor’s Y position.\r\n    // Calculate the desired new top edge based on the original offset.\r\n    const newTopCandidate = e.clientY - offsetY;\r\n\r\n    // For the top handle, the chat’s top edge should follow the cursor.\r\n    if (resizeType === 'top') {\r\n      if (chatState.floating === false) {\r\n        // Docked: bottom remains anchored at viewport bottom.\r\n        // When docked, the computed startTop equals (viewportHeight - startHeight)\r\n        let newTop = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(newTopCandidate, 0, viewportHeight - minHeight);\r\n        let newHeight = viewportHeight - newTop; // bottom is fixed at viewport bottom\r\n        chat.style.top = newTop + 'px';\r\n        chat.style.height = newHeight + 'px';\r\n        chatState.top = newTop;\r\n        chatState.height = newHeight;\r\n      } else {\r\n        // Floating: simply follow the cursor for the top edge,\r\n        // ensuring we don’t shrink below minHeight.\r\n        let newTop = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(newTopCandidate, 0, startTop + startHeight - minHeight);\r\n        let newHeight = startHeight - (newTop - startTop);\r\n        // Also do not allow height to exceed viewport height\r\n        newHeight = Math.min(newHeight, viewportHeight);\r\n        chat.style.top = newTop + 'px';\r\n        chat.style.height = newHeight + 'px';\r\n        chatState.top = newTop;\r\n        chatState.height = newHeight;\r\n      }\r\n    }\r\n    \r\n    // For left/right handles, we also want vertical resizing.\r\n    if (resizeType === 'left' || resizeType === 'right') {\r\n      if (chatState.floating === false) {\r\n        // Docked: bottom is fixed\r\n        let newTop = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(newTopCandidate, 0, viewportHeight - minHeight);\r\n        let newHeight = viewportHeight - newTop;\r\n        chat.style.top = newTop + 'px';\r\n        chat.style.height = newHeight + 'px';\r\n        chatState.top = newTop;\r\n        chatState.height = newHeight;\r\n      } else {\r\n        // Floating: follow the cursor while keeping at least minHeight.\r\n        let newTop = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.clamp)(newTopCandidate, 0, startTop + startHeight - minHeight);\r\n        let newHeight = startHeight - (newTop - startTop);\r\n        newHeight = Math.min(newHeight, viewportHeight - newTop);\r\n        chat.style.top = newTop + 'px';\r\n        chat.style.height = newHeight + 'px';\r\n        chatState.top = newTop;\r\n        chatState.height = newHeight;\r\n      }\r\n    }\r\n\r\n    // Ensure height never exceeds the viewport height\r\n    if (chat.offsetHeight > viewportHeight) {\r\n      chat.style.height = viewportHeight + 'px';\r\n      if (chatState.floating === false) {\r\n        chat.style.top = '0px';  // if docked, force top to 0 so height = viewport height\r\n        chatState.top = 0;\r\n      }\r\n      chatState.height = viewportHeight;\r\n    }\r\n    \r\n    (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.saveChatState)(chatState);\r\n    (0,_helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_1__.handleLayoutBehavior)();\r\n  });\r\n\r\n  document.addEventListener('mouseup', () => {\r\n    isResizing = false;\r\n    document.body.style.userSelect = '';\r\n  });\r\n}\r\n\r\nfunction setupWindowResizeHandler() {\r\n  window.addEventListener('resize', () => {\r\n    (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.restoreChatState)();\r\n    (0,_helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_1__.handleLayoutBehavior)();\r\n  });\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/chat/chatEvents.js?");

/***/ }),

/***/ "./src/chat/chatFontSize.js":
/*!**********************************!*\
  !*** ./src/chat/chatFontSize.js ***!
  \**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   applyFontSize: () => (/* binding */ applyFontSize),\n/* harmony export */   createFontSizeControl: () => (/* binding */ createFontSizeControl),\n/* harmony export */   initFontSizeControls: () => (/* binding */ initFontSizeControls),\n/* harmony export */   restoreFontSize: () => (/* binding */ restoreFontSize),\n/* harmony export */   updateElementFontSizes: () => (/* binding */ updateElementFontSizes)\n/* harmony export */ });\n/* harmony import */ var _chatState_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chatState.js */ \"./src/chat/chatState.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\nfunction applyFontSize(multiplier) {\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  const messageInput = document.getElementById('message-input');\r\n  if (!chatContainer) return;\r\n\r\n  // Apply font size to the main container\r\n  chatContainer.style.fontSize = `${multiplier}em`;\r\n\r\n  // Apply base font size to message input without multiplier\r\n  // since it inherits the multiplier from the container\r\n  if (messageInput) {\r\n    messageInput.style.fontSize = '1em';\r\n  }\r\n\r\n  // Save the current multiplier in the chat state\r\n  const chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_0__.getChatState)();\r\n  (0,_chatState_js__WEBPACK_IMPORTED_MODULE_0__.saveChatState)({\r\n    ...chatState,\r\n    fontSizeMultiplier: multiplier\r\n  });\r\n}\r\n\r\nfunction restoreFontSize() {\r\n  const chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_0__.getChatState)();\r\n  applyFontSize(chatState.fontSizeMultiplier);\r\n}\r\n\r\nfunction createFontSizeControl() {\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  if (!chatContainer) return;\r\n\r\n  const chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_0__.getChatState)();\r\n\r\n  // Create font size control container\r\n  const fontSizeControl = document.createElement('div');\r\n  fontSizeControl.className = 'font-size-control';\r\n\r\n  // Create the slider\r\n  const fontSlider = document.createElement('input');\r\n  fontSlider.type = 'range';\r\n  fontSlider.min = '0.8';\r\n  fontSlider.max = '1.5';\r\n  fontSlider.step = '0.1';\r\n  fontSlider.value = chatState.fontSizeMultiplier;\r\n  fontSlider.className = 'font-size-slider';\r\n\r\n  // Prevent dragging the chat when interacting with the slider\r\n  fontSlider.addEventListener('mousedown', (e) => {\r\n    e.stopPropagation();\r\n  });\r\n\r\n  // Add custom tooltip to the slider (create only once)\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__.createCustomTooltip)(fontSlider, {\r\n    en: `Adjust chat font size. Current: ${fontSlider.value}x`,\r\n    ru: `Изменить размер шрифта чата. Текущий: ${fontSlider.value}x`\r\n  });\r\n\r\n  // Update font size on input change\r\n  fontSlider.addEventListener('input', (e) => {\r\n    const value = parseFloat(e.target.value);\r\n    applyFontSize(value);\r\n    // Update tooltip by calling createCustomTooltip again\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__.createCustomTooltip)(fontSlider, {\r\n      en: `Adjust chat font size. Current: ${value}x`,\r\n      ru: `Изменить размер шрифта чата. Текущий: ${value}x`\r\n    });\r\n  });\r\n\r\n  // Append the slider to the control container\r\n  fontSizeControl.appendChild(fontSlider);\r\n\r\n  // Add the control container to the chat drag area\r\n  const dragArea = document.querySelector('.chat-drag-area');\r\n  if (dragArea) {\r\n    dragArea.appendChild(fontSizeControl);\r\n  }\r\n}\r\n\r\n// Function to initialize font size controls\r\nfunction initFontSizeControls() {\r\n  createFontSizeControl();\r\n  restoreFontSize();\r\n\r\n  // Add event listener for when the chat container is resized or repositioned\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  if (chatContainer) {\r\n    const observer = new MutationObserver(() => {\r\n      // Make sure font size is preserved when chat state changes\r\n      const chatState = (0,_chatState_js__WEBPACK_IMPORTED_MODULE_0__.getChatState)();\r\n      applyFontSize(chatState.fontSizeMultiplier);\r\n    });\r\n\r\n    observer.observe(chatContainer, {\r\n      attributes: true,\r\n      attributeFilter: ['style', 'class']\r\n    });\r\n  }\r\n}\r\n\r\n// This function will apply the font size to all necessary elements\r\nfunction updateElementFontSizes(multiplier) {\r\n  const elements = {\r\n    messagePanel: document.getElementById('messages-panel'),\r\n    userList: document.getElementById('user-list'),\r\n    messageInput: document.getElementById('message-input')\r\n  };\r\n\r\n  // For any element that needs special handling beyond the container's em scaling\r\n  if (elements.messageInput) {\r\n    elements.messageInput.style.fontSize = `${multiplier}em`;\r\n  }\r\n\r\n  // Ensure time elements maintain their relative size (0.9em)\r\n  document.querySelectorAll('.time').forEach(el => {\r\n    el.style.fontSize = '0.9em';\r\n  });\r\n\r\n  // Ensure username elements maintain their size (1em)\r\n  document.querySelectorAll('.username').forEach(el => {\r\n    el.style.fontSize = '1em';\r\n  });\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/chat/chatFontSize.js?");

/***/ }),

/***/ "./src/chat/chatMessagesRemover.js":
/*!*****************************************!*\
  !*** ./src/chat/chatMessagesRemover.js ***!
  \*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ ChatMessagesRemover),\n/* harmony export */   pruneDeletedMessages: () => (/* binding */ pruneDeletedMessages)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n\r\nconst DELETED_MESSAGES_KEY = \"deletedChatAppMessages\";\r\nconst IGNORED_USERS_KEY = \"ignored\";\r\nconst TEMP_IGNORED_USERS_KEY = \"tempIgnored\";\r\n\r\nclass ChatMessagesRemover {\r\n  constructor() {\r\n    this.selected = new Set();\r\n    this.isDragging = false;\r\n    this.toggleBtn = null;\r\n    this.longPressTimer = null;\r\n    this.touchStartX = 0;\r\n    this.touchStartY = 0;\r\n    this.isMobile = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.checkIsMobile)();\r\n    this.init();\r\n  }\r\n\r\n  // Initialize the class by attaching events and rendering UI elements\r\n  init() {\r\n    this.attachEvents();\r\n    this.updateDeletedMessages();\r\n    this.renderToggle();\r\n    this.cleanupExpiredIgnores();\r\n  }\r\n\r\n  // Attach event listeners for desktop and mobile interactions\r\n  attachEvents() {\r\n    document.addEventListener(\"mousedown\", (e) => {\r\n      const msgEl = e.target.closest(\".messages-panel .message\");\r\n      if (!msgEl) return;\r\n\r\n      if (e.button === 2 && msgEl) {\r\n        this.handleSelection(e.target, msgEl, e.ctrlKey);\r\n      }\r\n    });\r\n\r\n    document.addEventListener(\"mouseup\", () => (this.isDragging = false));\r\n\r\n    document.addEventListener(\"mousemove\", (e) => {\r\n      if (!this.isDragging) return;\r\n\r\n      const msgEl = e.target.closest(\".messages-panel .message\");\r\n      if (msgEl) {\r\n        this.toggleSelect(msgEl, true, \"message-mode\");\r\n      }\r\n    });\r\n\r\n    document.addEventListener(\"contextmenu\", (e) => {\r\n      const msg = e.target.closest(\".messages-panel .message\");\r\n      if (msg) {\r\n        if (!(0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.isTextSelected)()) {\r\n          e.preventDefault();\r\n          this.showDeleteButton(e, msg);\r\n        }\r\n      }\r\n    });\r\n\r\n    if (this.isMobile) {\r\n      document.addEventListener(\"touchstart\", (e) => {\r\n        const msgEl = e.target.closest(\".messages-panel .message\");\r\n        if (!msgEl) return;\r\n\r\n        this.touchStartX = e.touches[0].clientX;\r\n        this.touchStartY = e.touches[0].clientY;\r\n\r\n        this.longPressTimer = setTimeout(() => {\r\n          this.handleSelection(e.target, msgEl, false);\r\n          this.showDeleteButton({\r\n            clientX: this.touchStartX,\r\n            clientY: this.touchStartY,\r\n            preventDefault: () => { }\r\n          }, msgEl);\r\n          if (navigator.vibrate) {\r\n            navigator.vibrate(50);\r\n          }\r\n        }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.longPressDuration);\r\n      });\r\n\r\n      document.addEventListener(\"touchmove\", (e) => {\r\n        if (this.isDragging) {\r\n          e.preventDefault(); // Prevent scrolling during multi-selection drag\r\n        }\r\n        const touchX = e.touches[0].clientX;\r\n        const touchY = e.touches[0].clientY;\r\n        const moveX = Math.abs(touchX - this.touchStartX);\r\n        const moveY = Math.abs(touchY - this.touchStartY);\r\n\r\n        if (moveX > 10 || moveY > 10) {\r\n          if (this.longPressTimer) {\r\n            clearTimeout(this.longPressTimer);\r\n            this.longPressTimer = null;\r\n          }\r\n        }\r\n      }, { passive: false });\r\n\r\n      document.addEventListener(\"touchend\", () => {\r\n        if (this.longPressTimer) {\r\n          clearTimeout(this.longPressTimer);\r\n          this.longPressTimer = null;\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  // Handle selection logic based on target type (time, username, or message)\r\n  handleSelection(target, msgEl, isCtrlKey) {\r\n    // Prevent selection if text is already selected in the message\r\n    if ((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.isTextSelected)()) return;\r\n\r\n    const timeEl = target.closest(\".time\");\r\n    const usernameEl = target.closest(\".username\");\r\n\r\n    if (timeEl) {\r\n      this.handleTimeSelection(msgEl, isCtrlKey);\r\n    } else if (usernameEl) {\r\n      this.handleUsernameSelection(usernameEl);\r\n    } else {\r\n      this.isDragging = true;\r\n      this.toggleSelect(msgEl, true, \"message-mode\");\r\n    }\r\n  }\r\n\r\n  // Select messages based on time criteria\r\n  handleTimeSelection(msgEl, isCtrlKey) {\r\n    const messages = Array.from(\r\n      document.querySelectorAll(\".messages-panel .message\")\r\n    );\r\n    const startIndex = messages.indexOf(msgEl);\r\n\r\n    if (startIndex === -1) return;\r\n\r\n    if (isCtrlKey) {\r\n      messages.slice(startIndex).forEach((m) => {\r\n        this.toggleSelect(m, true, \"time-mode\");\r\n        m.classList.add(\"time-mode\");\r\n      });\r\n    } else {\r\n      const usernameEl = msgEl.querySelector(\".username\");\r\n      if (!usernameEl) return;\r\n\r\n      const usernameText = usernameEl.textContent.trim();\r\n      messages.slice(startIndex).forEach((m) => {\r\n        const mUsernameEl = m.querySelector(\".username\");\r\n        if (\r\n          mUsernameEl &&\r\n          mUsernameEl.textContent.trim() === usernameText\r\n        ) {\r\n          this.toggleSelect(m, true, \"time-mode\");\r\n          m.classList.add(\"time-mode\");\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  // Select all messages from a specific user\r\n  handleUsernameSelection(usernameEl) {\r\n    const usernameText = usernameEl.textContent.trim();\r\n    document.querySelectorAll(\".messages-panel .message\").forEach((msg) => {\r\n      const msgUsernameEl = msg.querySelector(\".username\");\r\n      if (\r\n        msgUsernameEl &&\r\n        msgUsernameEl.textContent.trim() === usernameText\r\n      ) {\r\n        this.toggleSelect(msg, true, \"username-mode\");\r\n        msg.classList.add(\"username-mode\");\r\n      }\r\n    });\r\n  }\r\n\r\n  // Toggle selection state of a message element\r\n  toggleSelect(el, state, mode = \"message-mode\") {\r\n    if (!el) return;\r\n\r\n    el.classList.toggle(\"selected-message\", state);\r\n\r\n    if (!state) {\r\n      el.classList.remove(\"username-mode\", \"time-mode\", \"message-mode\");\r\n    } else if (mode === \"message-mode\") {\r\n      el.classList.add(\"message-mode\");\r\n    }\r\n\r\n    const id = getMessageId(el);\r\n    state ? this.selected.add(id) : this.selected.delete(id);\r\n  }\r\n\r\n  // Display delete and ignore buttons at the correct position\r\n  showDeleteButton(e, msg) {\r\n    // Prevent showing the delete button if text is already selected in the message\r\n    if ((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.isTextSelected)()) return;\r\n\r\n    const existingContainer = document.querySelector(\".action-buttons-container\");\r\n    if (existingContainer) existingContainer.remove();\r\n\r\n    const container = document.createElement(\"div\");\r\n    container.className = \"action-buttons-container\";\r\n\r\n    let modeClass = \"message-mode\";\r\n    if (msg.classList.contains(\"time-mode\")) {\r\n      modeClass = \"time-mode\";\r\n    } else if (msg.classList.contains(\"username-mode\")) {\r\n      modeClass = \"username-mode\";\r\n    }\r\n    container.classList.add(modeClass);\r\n\r\n    if (this.isMobile) {\r\n      container.classList.add(\"mobile-container\");\r\n    }\r\n\r\n    const deleteBtn = document.createElement(\"button\");\r\n    deleteBtn.className = \"delete-btn\";\r\n    deleteBtn.textContent = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.deleteButton[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage];\r\n    deleteBtn.onclick = () => this.deleteSelectedMessages(container);\r\n    container.appendChild(deleteBtn);\r\n\r\n    if (modeClass === \"username-mode\") {\r\n      const usernameEl = msg.querySelector(\".username\");\r\n      if (usernameEl) {\r\n        const username = usernameEl.textContent.trim();\r\n        if (username) {\r\n          const ignoreBtn = document.createElement(\"button\");\r\n          ignoreBtn.className = \"ignore-btn\";\r\n          ignoreBtn.textContent = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignoreButton[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage];\r\n          ignoreBtn.onclick = () => this.showIgnoreOptions(ignoreBtn, username);\r\n          container.appendChild(ignoreBtn);\r\n        }\r\n      }\r\n    }\r\n\r\n    container.addEventListener(\"touchstart\", (e) => {\r\n      e.stopPropagation();\r\n    });\r\n\r\n    // Temporarily append to body to measure dimensions\r\n    document.body.append(container);\r\n    const { offsetWidth: w, offsetHeight: h } = container;\r\n    container.remove();\r\n\r\n    // Calculate position ensuring the container stays within viewport bounds\r\n    const left = Math.max(0, Math.min(e.clientX - w / 2, window.innerWidth - w));\r\n    const top = Math.max(0, Math.min(e.clientY - h / 2, window.innerHeight - h));\r\n\r\n    Object.assign(container.style, {\r\n      position: \"fixed\",\r\n      top: `${top}px`,\r\n      left: `${left}px`,\r\n    });\r\n\r\n    if (this.isMobile) {\r\n      const handleOutsideTap = (event) => {\r\n        if (!container.contains(event.target)) {\r\n          this.clearSelection();\r\n          container.remove();\r\n          document.removeEventListener('touchstart', handleOutsideTap);\r\n        }\r\n      };\r\n      document.addEventListener('touchstart', handleOutsideTap);\r\n      container.outsideTapHandler = handleOutsideTap;\r\n    }\r\n\r\n    let timeoutId;\r\n    container.addEventListener(\"mouseenter\", () => {\r\n      if (timeoutId) clearTimeout(timeoutId);\r\n    });\r\n\r\n    container.addEventListener(\"mouseleave\", () => {\r\n      timeoutId = setTimeout(() => {\r\n        container.remove();\r\n        this.clearSelection();\r\n      }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.clearSelectionDelay);\r\n    });\r\n\r\n    document.body.append(container);\r\n  }\r\n\r\n  // Show popup with ignore duration options\r\n  showIgnoreOptions(ignoreBtn, username) {\r\n    const popup = document.createElement(\"div\");\r\n    popup.className = \"ignore-options-popup\";\r\n\r\n    // Custom minutes input button as the first option\r\n    const options = [\r\n      { custom: true },\r\n      { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignore1Hour[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage], duration: 60 * 60 * 1000 },\r\n      { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignore1Day[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage], duration: 24 * 60 * 60 * 1000 },\r\n      { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignoreForever[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage], duration: null }\r\n    ];\r\n\r\n    options.forEach(option => {\r\n      if (option.custom) {\r\n        const customBtn = document.createElement(\"button\");\r\n        customBtn.className = \"ignore-option-btn custom-ignore-minutes\";\r\n        customBtn.textContent = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignoreCustomMinutes[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage];\r\n        customBtn.onclick = () => {\r\n          let min;\r\n          while (true) {\r\n            min = prompt(_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.ignoreCustomPrompt[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage]);\r\n            if (min === null) return; // Cancelled\r\n            if (/^\\d+$/.test(min) && parseInt(min, 10) > 0) break;\r\n          }\r\n          const minutes = parseInt(min, 10);\r\n          this.ignoreUser(username, minutes * 60 * 1000);\r\n          popup.remove();\r\n          this.clearSelection();\r\n          const existingContainer = document.querySelector(\".action-buttons-container\");\r\n          if (existingContainer) existingContainer.remove();\r\n        };\r\n        popup.appendChild(customBtn);\r\n      } else {\r\n        const optionBtn = document.createElement(\"button\");\r\n        optionBtn.className = \"ignore-option-btn\";\r\n        optionBtn.textContent = option.text;\r\n        optionBtn.onclick = () => {\r\n          this.ignoreUser(username, option.duration);\r\n          popup.remove();\r\n          this.clearSelection();\r\n          const existingContainer = document.querySelector(\".action-buttons-container\");\r\n          if (existingContainer) existingContainer.remove();\r\n        };\r\n        popup.appendChild(optionBtn);\r\n      }\r\n    });\r\n\r\n    const rect = ignoreBtn.getBoundingClientRect();\r\n    const popupWidth = 100; // Approximate width\r\n    const left = Math.max(0, Math.min(rect.left, window.innerWidth - popupWidth));\r\n\r\n    popup.style.top = `${rect.bottom + 5}px`;\r\n    popup.style.left = `${left}px`;\r\n\r\n    document.body.appendChild(popup);\r\n\r\n    const handleOutsideClick = (event) => {\r\n      if (!popup.contains(event.target) && !ignoreBtn.contains(event.target)) {\r\n        popup.remove();\r\n        document.removeEventListener('click', handleOutsideClick);\r\n      }\r\n    };\r\n    document.addEventListener('click', handleOutsideClick);\r\n  }\r\n\r\n  // Ignore a user for a specified duration\r\n  ignoreUser(username, duration) {\r\n    if (duration === null) {\r\n      // Forever - add to permanent ignore list\r\n      const ignoredUsers = JSON.parse(localStorage.getItem(IGNORED_USERS_KEY) || \"[]\");\r\n      if (!ignoredUsers.includes(username)) {\r\n        ignoredUsers.push(username);\r\n        localStorage.setItem(IGNORED_USERS_KEY, JSON.stringify(ignoredUsers));\r\n      }\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n        en: `Added \"${username}\" to the ignore list`,\r\n        ru: `\"${username}\" добавлен(а) в список игнорируемых`\r\n      }, 'info');\r\n    } else {\r\n      // Temporary ignore - add to temp ignore list with expiry time\r\n      const tempIgnored = JSON.parse(localStorage.getItem(TEMP_IGNORED_USERS_KEY) || \"{}\");\r\n      const expiryTime = Date.now() + duration;\r\n      tempIgnored[username] = expiryTime;\r\n      localStorage.setItem(TEMP_IGNORED_USERS_KEY, JSON.stringify(tempIgnored));\r\n      const minutes = Math.round(duration / 60000);\r\n      function getMinuteWordRu(n) {\r\n        if (n % 10 === 1 && n % 100 !== 11) return 'минуту';\r\n        if ([2, 3, 4].includes(n % 10) && ![12, 13, 14].includes(n % 100)) return 'минуты';\r\n        return 'минут';\r\n      }\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n        en: `Added \"${username}\" to the ignore list for ${minutes} minutes`,\r\n        ru: `\"${username}\" добавлен(а) в список игнорируемых на ${minutes} ${getMinuteWordRu(minutes)}`\r\n      }, 'info');\r\n    }\r\n\r\n    if (window.messageManager && typeof window.messageManager.removeIgnoredMessages === 'function') {\r\n      window.messageManager.removeIgnoredMessages();\r\n    }\r\n  }\r\n\r\n  // Clean up expired temporary ignores\r\n  cleanupExpiredIgnores() {\r\n    const tempIgnoredData = JSON.parse(localStorage.getItem(TEMP_IGNORED_USERS_KEY) || \"{}\");\r\n    const now = Date.now();\r\n    let hasChanges = false;\r\n    let liberatedUsers = [];\r\n\r\n    Object.keys(tempIgnoredData).forEach(username => {\r\n      if (tempIgnoredData[username] <= now) {\r\n        delete tempIgnoredData[username];\r\n        hasChanges = true;\r\n        liberatedUsers.push(username);\r\n      }\r\n    });\r\n\r\n    if (hasChanges) {\r\n      localStorage.setItem(TEMP_IGNORED_USERS_KEY, JSON.stringify(tempIgnoredData));\r\n      liberatedUsers.forEach(username => {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n          en: `User \"${username}\" was removed from the ignore list`,\r\n          ru: `Пользователь \"${username}\" удалён из игнора`\r\n        }, 'info');\r\n      });\r\n    }\r\n  }\r\n\r\n  // Check if a user is currently ignored\r\n  isUserIgnored(username) {\r\n    const ignoredUsers = JSON.parse(localStorage.getItem(IGNORED_USERS_KEY) || \"[]\");\r\n    if (ignoredUsers.includes(username)) {\r\n      return true;\r\n    }\r\n\r\n    const tempIgnoredData = JSON.parse(localStorage.getItem(TEMP_IGNORED_USERS_KEY) || \"{}\");\r\n    if (tempIgnoredData[username] && tempIgnoredData[username] > Date.now()) {\r\n      return true;\r\n    }\r\n\r\n    return false;\r\n  }\r\n\r\n  // Delete selected messages and update UI\r\n  deleteSelectedMessages(container) {\r\n    document.querySelectorAll(\".selected-message\").forEach((msg) => {\r\n      if (!msg) return;\r\n\r\n      msg.classList.remove(\"selected-message\", \"username-mode\", \"time-mode\", \"message-mode\");\r\n      if (msg.classList.length === 0) msg.removeAttribute(\"class\");\r\n    });\r\n    this.storeDeleted([...this.selected]);\r\n    container.remove();\r\n    if (this.isMobile && container.outsideTapHandler) {\r\n      document.removeEventListener('touchstart', container.outsideTapHandler);\r\n    }\r\n    this.selected.clear();\r\n    this.updateDeletedMessages();\r\n    this.renderToggle();\r\n  }\r\n\r\n  // Clear all selected messages without deleting\r\n  clearSelection() {\r\n    document.querySelectorAll(\".selected-message\").forEach((msg) => {\r\n      if (!msg) return;\r\n\r\n      msg.classList.remove(\"selected-message\", \"username-mode\", \"time-mode\", \"message-mode\");\r\n      if (msg.classList.length === 0) {\r\n        msg.removeAttribute(\"class\");\r\n      }\r\n    });\r\n    this.selected.clear();\r\n  }\r\n\r\n  // Store deleted message IDs in localStorage\r\n  storeDeleted(ids) {\r\n    const stored = new Set(\r\n      JSON.parse(localStorage.getItem(DELETED_MESSAGES_KEY) || \"[]\")\r\n    );\r\n    ids.forEach((id) => stored.add(id));\r\n    localStorage.setItem(DELETED_MESSAGES_KEY, JSON.stringify([...stored]));\r\n  }\r\n\r\n  // Update visibility of messages based on deleted status\r\n  updateDeletedMessages() {\r\n    const stored = new Set(\r\n      JSON.parse(localStorage.getItem(DELETED_MESSAGES_KEY) || \"[]\")\r\n    );\r\n\r\n    const messages = document.querySelectorAll(\".messages-panel .message\");\r\n    if (messages.length === 0) return;\r\n\r\n    messages.forEach((msg) => {\r\n      if (!msg) return;\r\n\r\n      const id = getMessageId(msg);\r\n      msg.classList.remove(\"shown-message\");\r\n      msg.classList.toggle(\"hidden-message\", stored.has(id));\r\n    });\r\n\r\n    localStorage.setItem(DELETED_MESSAGES_KEY, JSON.stringify([...stored]));\r\n  }\r\n\r\n  // Render toggle button to show/hide deleted messages\r\n  renderToggle() {\r\n    const storedItems = JSON.parse(localStorage.getItem(DELETED_MESSAGES_KEY) || \"[]\");\r\n    const hasDeleted = storedItems.length > 0;\r\n\r\n    if (!hasDeleted) {\r\n      if (this.toggleBtn) {\r\n        this.toggleBtn.remove();\r\n        this.toggleBtn = null;\r\n      }\r\n      return;\r\n    }\r\n\r\n    const messagesPanel = document.querySelector(\".messages-panel\");\r\n    if (!messagesPanel) return;\r\n\r\n    if (!this.toggleBtn) {\r\n      this.toggleBtn = document.createElement(\"button\");\r\n      this.toggleBtn.className = \"toggle-button toggle-hidden\";\r\n      this.toggleBtn.textContent = \"Show\";\r\n\r\n      this.toggleBtn.onclick = (e) => {\r\n        if (e.ctrlKey) {\r\n          this.restoreAllMessages();\r\n          return;\r\n        }\r\n\r\n        const shouldShow = this.toggleBtn.textContent === \"Show\";\r\n        const storedIds = JSON.parse(\r\n          localStorage.getItem(DELETED_MESSAGES_KEY) || \"[]\"\r\n        );\r\n\r\n        document.querySelectorAll(\".messages-panel .message\").forEach((msg) => {\r\n          if (!msg) return;\r\n\r\n          const id = getMessageId(msg);\r\n          if (storedIds.includes(id)) {\r\n            msg.classList.toggle(\"hidden-message\", !shouldShow);\r\n            msg.classList.toggle(\"shown-message\", shouldShow);\r\n          }\r\n        });\r\n\r\n        if (shouldShow) {\r\n          this.toggleBtn.textContent = \"Hide\";\r\n          this.toggleBtn.classList.remove(\"toggle-hidden\");\r\n          this.toggleBtn.classList.add(\"toggle-shown\");\r\n        } else {\r\n          this.toggleBtn.textContent = \"Show\";\r\n          this.toggleBtn.classList.remove(\"toggle-shown\");\r\n          this.toggleBtn.classList.add(\"toggle-hidden\");\r\n        }\r\n      };\r\n\r\n      if (this.isMobile) {\r\n        let isLongPress = false;\r\n        let longPressTimer;\r\n\r\n        this.toggleBtn.addEventListener('touchstart', (e) => {\r\n          this.touchStartX = e.touches[0].clientX;\r\n          this.touchStartY = e.touches[0].clientY;\r\n          isLongPress = false;\r\n          longPressTimer = setTimeout(() => {\r\n            isLongPress = true;\r\n            this.restoreAllMessages();\r\n            if (navigator.vibrate) {\r\n              navigator.vibrate(50);\r\n            }\r\n          }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.longPressDuration);\r\n        });\r\n\r\n        this.toggleBtn.addEventListener('touchmove', (e) => {\r\n          const touchX = e.touches[0].clientX;\r\n          const touchY = e.touches[0].clientY;\r\n          const moveX = Math.abs(touchX - this.touchStartX);\r\n          const moveY = Math.abs(touchY - this.touchStartY);\r\n          if (moveX > 10 || moveY > 10) {\r\n            clearTimeout(longPressTimer);\r\n          }\r\n        });\r\n\r\n        this.toggleBtn.addEventListener('touchend', () => {\r\n          clearTimeout(longPressTimer);\r\n          if (isLongPress) {\r\n            this.toggleBtn.addEventListener('click', (e) => {\r\n              e.preventDefault();\r\n              e.stopPropagation();\r\n            }, { once: true });\r\n          }\r\n        });\r\n      }\r\n\r\n      messagesPanel.append(this.toggleBtn);\r\n    }\r\n  }\r\n\r\n  // Restore all deleted messages\r\n  restoreAllMessages() {\r\n    document.querySelectorAll(\".messages-panel .message\").forEach((msg) => {\r\n      if (!msg) return;\r\n\r\n      msg.classList.remove(\"hidden-message\", \"shown-message\");\r\n    });\r\n    localStorage.setItem(DELETED_MESSAGES_KEY, JSON.stringify([]));\r\n    this.selected.clear();\r\n    this.updateDeletedMessages();\r\n    this.renderToggle();\r\n  }\r\n}\r\n\r\n// Generate a unique ID for a message element\r\nfunction getMessageId(el) {\r\n  if (!el) return '';\r\n  if (el.dataset.messageId) return el.dataset.messageId;\r\n\r\n  let id = Array.from(el.childNodes)\r\n    .map((n) => {\r\n      if (!n) return '';\r\n      if (n.nodeType === Node.TEXT_NODE) return n.textContent.trim();\r\n      if (n.classList?.contains(\"username\")) return n.textContent.trim();\r\n      if (n.tagName === \"A\") return n.href;\r\n      if (n.tagName === \"IMG\") return n.title.trim();\r\n      if (n.tagName === \"IFRAME\") return n.src.trim();\r\n      return \"\";\r\n    })\r\n    .join(\"\");\r\n\r\n  if (!id) {\r\n    id = 'msg-' + Math.random().toString(36).substring(2, 7);\r\n  }\r\n  el.dataset.messageId = id;\r\n  return id;\r\n}\r\n\r\n// Prune deleted message IDs that no longer exist in the DOM\r\nfunction pruneDeletedMessages() {\r\n  const messages = document.querySelectorAll(\".messages-panel .message\");\r\n  if (messages.length === 0) return;\r\n\r\n  const currentIds = new Set(\r\n    Array.from(messages).map((msg) => getMessageId(msg))\r\n  );\r\n\r\n  const storedItems = JSON.parse(localStorage.getItem(DELETED_MESSAGES_KEY) || \"[]\");\r\n  const filteredItems = storedItems.filter((id) => currentIds.has(id));\r\n\r\n  localStorage.setItem(DELETED_MESSAGES_KEY, JSON.stringify(filteredItems));\r\n\r\n  // Remove the toggle button if no items remain\r\n  if (filteredItems.length === 0) {\r\n    const toggleBtn = document.querySelector(\".toggle-button\");\r\n    if (toggleBtn) {\r\n      toggleBtn.remove();\r\n    }\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/chat/chatMessagesRemover.js?");

/***/ }),

/***/ "./src/chat/chatState.js":
/*!*******************************!*\
  !*** ./src/chat/chatState.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   addChatToggleFeature: () => (/* binding */ addChatToggleFeature),\n/* harmony export */   getChatState: () => (/* binding */ getChatState),\n/* harmony export */   restoreChatState: () => (/* binding */ restoreChatState),\n/* harmony export */   saveChatState: () => (/* binding */ saveChatState),\n/* harmony export */   toggleChatMaximize: () => (/* binding */ toggleChatMaximize),\n/* harmony export */   toggleChatVisibility: () => (/* binding */ toggleChatVisibility)\n/* harmony export */ });\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/layoutBehavior.js */ \"./src/helpers/layoutBehavior.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction updateToggleButton(toggleButton, isVisible) {\r\n  toggleButton.innerHTML = isVisible ? _data_icons_js__WEBPACK_IMPORTED_MODULE_0__.closeSVG : _data_icons_js__WEBPACK_IMPORTED_MODULE_0__.openSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(toggleButton, {\r\n    en: `[Ctrl + Space] ${isVisible ? 'Hide chat' : 'Show chat'}`,\r\n    ru: `[Ctrl + Space] ${isVisible ? 'Скрыть чат' : 'Показать чат'}`\r\n  });\r\n}\r\n\r\nfunction updateMaximizeButton(maximizeButton, isMaximized) {\r\n  maximizeButton.innerHTML = isMaximized ? _data_icons_js__WEBPACK_IMPORTED_MODULE_0__.collapseSVG : _data_icons_js__WEBPACK_IMPORTED_MODULE_0__.expandSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(maximizeButton, {\r\n    en: `[Ctrl + Shift + Space] ${isMaximized ? 'Collapse chat' : 'Expand chat'}`,\r\n    ru: `[Ctrl + Shift + Space] ${isMaximized ? 'Свернуть чат' : 'Развернуть чат'}`\r\n  });\r\n}\r\n\r\nfunction restoreChatState() {\r\n  const chat = document.getElementById('app-chat-container');\r\n  const toggleButton = document.querySelector('.chat-toggle-button');\r\n  const maximizeButton = document.querySelector('.chat-maximize-button');\r\n  if (!chat || !toggleButton || !maximizeButton) return;\r\n\r\n  const state = getChatState();\r\n\r\n  // Handle maximized state\r\n  chat.classList.toggle('maximized', state.isMaximized);\r\n  updateMaximizeButton(maximizeButton, state.isMaximized);\r\n\r\n  // Handle visibility state\r\n  if (state.floating) {\r\n    chat.style.display = state.isVisible ? 'flex' : 'none';\r\n    chat.style.opacity = state.isVisible ? '1' : '0';\r\n    // Remove visibility classes for floating chat\r\n    chat.classList.remove('visible-chat', 'hidden-chat');\r\n  } else {\r\n    chat.classList.toggle('visible-chat', state.isVisible);\r\n    chat.classList.toggle('hidden-chat', !state.isVisible);\r\n  }\r\n\r\n  // Update toggle button\r\n  updateToggleButton(toggleButton, state.isVisible);\r\n\r\n  const viewportWidth = window.innerWidth;\r\n  const viewportHeight = window.innerHeight;\r\n  const computedStyle = getComputedStyle(document.documentElement);\r\n  const minWidth = parseInt(computedStyle.getPropertyValue('--min-chat-width')) || 250;\r\n  const minHeight = parseInt(computedStyle.getPropertyValue('--min-chat-height')) || 200;\r\n\r\n  chat.style.width = Math.min(viewportWidth, Math.max(minWidth, state.width)) + 'px';\r\n  chat.style.height = Math.min(viewportHeight, Math.max(minHeight, state.height)) + 'px';\r\n  chat.style.left = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.clamp)(state.left, 0, viewportWidth - chat.offsetWidth) + 'px';\r\n\r\n  if (state.floating) {\r\n    chat.style.top = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.clamp)(state.top, 0, viewportHeight - chat.offsetHeight) + 'px';\r\n    chat.style.bottom = '';\r\n    chat.classList.add(\"floating-chat\");\r\n  } else {\r\n    chat.style.bottom = '0';\r\n    chat.style.top = '';\r\n    chat.classList.remove(\"floating-chat\");\r\n  }\r\n\r\n  (0,_helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_2__.handleLayoutBehavior)();\r\n}\r\n\r\nfunction getChatState() {\r\n  const savedState = localStorage.getItem('chatState');\r\n  const defaultState = {\r\n    height: 300,\r\n    width: Math.min(window.innerWidth, 600),\r\n    left: 0,\r\n    floating: false,\r\n    top: window.innerHeight - 300,\r\n    isVisible: true,\r\n    fontSizeMultiplier: 1.0,\r\n    isMaximized: false\r\n  };\r\n\r\n  return savedState ? { ...defaultState, ...JSON.parse(savedState) } : defaultState;\r\n}\r\n\r\nfunction saveChatState(state) {\r\n  localStorage.setItem('chatState', JSON.stringify(state));\r\n}\r\n\r\nfunction toggleChatVisibility() {\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  const toggleButton = document.querySelector('.chat-toggle-button');\r\n  if (!chatContainer) return;\r\n\r\n  const chatState = getChatState();\r\n  const isFloating = chatState.floating || false;\r\n  const isVisible = !chatState.isVisible;\r\n\r\n  if (isFloating) {\r\n    chatContainer.style.opacity = isVisible ? '1' : '0';\r\n    setTimeout(() => {\r\n      chatContainer.style.display = isVisible ? 'flex' : 'none';\r\n      updateToggleButton(toggleButton, isVisible);\r\n      saveChatState({ ...chatState, isVisible });\r\n      if (isVisible) (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.focusTextInput)();\r\n    }, 300);\r\n  } else {\r\n    chatContainer.classList.toggle('visible-chat', isVisible);\r\n    chatContainer.classList.toggle('hidden-chat', !isVisible);\r\n    updateToggleButton(toggleButton, isVisible);\r\n    saveChatState({ ...chatState, isVisible });\r\n    if (isVisible) (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.focusTextInput)();\r\n  }\r\n}\r\n\r\nfunction addChatToggleFeature() {\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  const closeButton = document.getElementById('chat-close-btn');\r\n  const draggableHeader = document.getElementById('chat-header');\r\n  if (!chatContainer) return;\r\n\r\n  // Restore initial visibility from saved state\r\n  const chatState = JSON.parse(localStorage.getItem('chatState')) || {};\r\n  const isFloating = chatState.floating || false;\r\n  const isVisible = chatState.isVisible !== false;\r\n\r\n  if (isFloating) {\r\n    chatContainer.style.display = isVisible ? 'flex' : 'none';\r\n    chatContainer.style.opacity = isVisible ? '1' : '0';\r\n  } else {\r\n    chatContainer.classList.remove('visible-chat', 'hidden-chat');\r\n    chatContainer.classList.add(isVisible ? 'visible-chat' : 'hidden-chat');\r\n  }\r\n\r\n  // Keyboard shortcuts\r\n  document.addEventListener('keydown', (e) => {\r\n    if (e.ctrlKey && e.shiftKey && e.code === 'Space') {\r\n      e.preventDefault();\r\n      toggleChatMaximize();\r\n    } else if (e.ctrlKey && e.code === 'Space') {\r\n      e.preventDefault();\r\n      toggleChatVisibility();\r\n    }\r\n  });\r\n\r\n  if (closeButton) {\r\n    closeButton.addEventListener('click', toggleChatVisibility);\r\n  }\r\n\r\n  if (draggableHeader) {\r\n    draggableHeader.addEventListener('dblclick', toggleChatVisibility);\r\n  }\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction toggleChatMaximize() {\r\n  const chat = document.getElementById('app-chat-container');\r\n  const maximizeButton = document.querySelector('.chat-maximize-button');\r\n  if (!chat || !maximizeButton) return;\r\n\r\n  const state = getChatState();\r\n  const isMaximized = !state.isMaximized;\r\n\r\n  chat.classList.toggle('maximized', isMaximized);\r\n  updateMaximizeButton(maximizeButton, isMaximized);\r\n\r\n  saveChatState({ ...state, isMaximized });\r\n\r\n  requestAnimationFrame(() => {\r\n    (0,_helpers_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_2__.handleLayoutBehavior)();\r\n\r\n    const container = document.getElementById('messages-panel');\r\n    if (container) {\r\n      container.scrollTop = container.scrollHeight;\r\n    }\r\n\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.focusTextInput)();\r\n  });\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/chat/chatState.js?");

/***/ }),

/***/ "./src/chat/chatUI.js":
/*!****************************!*\
  !*** ./src/chat/chatUI.js ***!
  \****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   applyUITheme: () => (/* binding */ applyUITheme),\n/* harmony export */   createChatUI: () => (/* binding */ createChatUI)\n/* harmony export */ });\n/* harmony import */ var _helpers_lengthPopup_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/lengthPopup.js */ \"./src/helpers/lengthPopup.js\");\n/* harmony import */ var _helpers_mobileLayout_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/mobileLayout.js */ \"./src/helpers/mobileLayout.js\");\n/* harmony import */ var _chatState_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chatState.js */ \"./src/chat/chatState.js\");\n/* harmony import */ var _chatFontSize_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./chatFontSize.js */ \"./src/chat/chatFontSize.js\");\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n/* harmony import */ var _components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../components/helpPanel.js */ \"./src/components/helpPanel.js\");\n/* harmony import */ var _components_emojiPanel_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../components/emojiPanel.js */ \"./src/components/emojiPanel.js\");\n/* harmony import */ var _components_themesPanel_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../components/themesPanel.js */ \"./src/components/themesPanel.js\");\n/* harmony import */ var _components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../components/chatUsernameColorsPanel.js */ \"./src/components/chatUsernameColorsPanel.js\");\n/* harmony import */ var _components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../components/ignoredUsersPanel.js */ \"./src/components/ignoredUsersPanel.js\");\n/* harmony import */ var _components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../components/eventsPanel.js */ \"./src/components/eventsPanel.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Apply the UI theme to the chat\r\nfunction applyUITheme() {\r\n  let savedTheme = localStorage.getItem('selectedTheme');\r\n  if (!savedTheme) {\r\n    savedTheme = 'dark-soul'; // Default to dark theme if no theme is saved\r\n    localStorage.setItem('selectedTheme', savedTheme);\r\n  }\r\n  document.body.className = savedTheme; // Apply the theme to the body for global panels\r\n}\r\n\r\nfunction createChatUI() {\r\n  const chatContainer = document.createElement('div');\r\n  chatContainer.id = 'app-chat-container';\r\n\r\n  // Add resize handles\r\n  ['top', 'left', 'right'].forEach(type => {\r\n    const handle = document.createElement('div');\r\n    handle.className = `resize-handle ${type}`;\r\n    chatContainer.appendChild(handle);\r\n  });\r\n\r\n  // Chat wrapper for content and user list\r\n  const chatWrapper = document.createElement('div');\r\n  chatWrapper.className = 'chat-wrapper';\r\n\r\n  // Draggable top area\r\n  const dragArea = document.createElement('div');\r\n  dragArea.className = 'chat-drag-area';\r\n  dragArea.addEventListener('dblclick', _chatState_js__WEBPACK_IMPORTED_MODULE_2__.toggleChatVisibility);\r\n  chatWrapper.appendChild(dragArea);\r\n\r\n  // Left side: messages panel and input\r\n  const chatContent = document.createElement('div');\r\n  chatContent.className = 'chat-content';\r\n\r\n  const messagesPanel = document.createElement('div');\r\n  messagesPanel.id = 'messages-panel';\r\n  messagesPanel.className = 'messages-panel';\r\n\r\n  const inputContainer = document.createElement('div');\r\n  inputContainer.className = 'input-container';\r\n\r\n  // Create emoji button\r\n  const emojiButton = document.createElement('button');\r\n  emojiButton.className = 'emoji-trigger button';\r\n  emojiButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.smileSVG;\r\n  emojiButton.classList.add('emoji-button');\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(emojiButton, {\r\n    en: '[Ctrl + ;] Open emoji picker',\r\n    ru: '[Ctrl + ;] Открыть панель эмодзи'\r\n  });\r\n\r\n  // Setup emoji panel toggle functionality\r\n  let emojiPanelInstance = null;\r\n  emojiButton.addEventListener('click', (e) => {\r\n    e.stopPropagation();\r\n    if (!emojiPanelInstance || !document.querySelector('.emoji-panel')) {\r\n      emojiPanelInstance = new _components_emojiPanel_js__WEBPACK_IMPORTED_MODULE_6__.EmojiPanel({\r\n        container: messagesPanel,\r\n        position: 'bottom',\r\n        emojiButton: emojiButton,\r\n        onEmojiSelect: (emoji) => {\r\n          const messageInput = document.getElementById('message-input');\r\n          if (messageInput) {\r\n            const cursorPos = messageInput.selectionStart;\r\n            const textBefore = messageInput.value.substring(0, cursorPos);\r\n            const textAfter = messageInput.value.substring(messageInput.selectionEnd);\r\n            messageInput.value = textBefore + emoji + textAfter;\r\n            const newCursorPos = cursorPos + emoji.length;\r\n            messageInput.setSelectionRange(newCursorPos, newCursorPos);\r\n            messageInput.focus();\r\n          }\r\n        },\r\n        onDestroy: () => {\r\n          // Removed redundant tooltip reset; emojiPanel.js already handles this\r\n          emojiPanelInstance = null;\r\n        }\r\n      });\r\n      emojiPanelInstance.init();\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(emojiButton, {\r\n        en: '[Esc, qq] Close emoji picker',\r\n        ru: '[Esc, qq] Закрыть панель эмодзи'\r\n      });\r\n    } else {\r\n      emojiPanelInstance.destroy();\r\n    }\r\n  });\r\n\r\n  // Create message input\r\n  const messageInput = document.createElement('input');\r\n  messageInput.type = 'text';\r\n  messageInput.id = 'message-input';\r\n  messageInput.maxLength = 300;\r\n  messageInput.autocomplete = 'off';\r\n\r\n  // Create send button\r\n  const sendButton = document.createElement('button');\r\n  sendButton.id = 'send-button';\r\n  sendButton.className = 'button send-button';\r\n  sendButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.sendSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(sendButton, {\r\n    en: '[Enter] Send message',\r\n    ru: '[Enter] Отправить сообщение'\r\n  });\r\n\r\n  // Append elements in order\r\n  inputContainer.append(emojiButton, messageInput, sendButton);\r\n  chatContent.append(messagesPanel, inputContainer);\r\n\r\n  // Right side: user list\r\n  const userListContainer = document.createElement('div');\r\n  userListContainer.className = 'user-list-container';\r\n  const userList = document.createElement('div');\r\n  userList.id = 'user-list';\r\n  userListContainer.appendChild(userList);\r\n  chatWrapper.append(chatContent, userListContainer);\r\n  chatContainer.appendChild(chatWrapper);\r\n\r\n  // Header buttons\r\n  const headerButtons = document.createElement('div');\r\n  headerButtons.className = 'header-buttons';\r\n  dragArea.appendChild(headerButtons);\r\n\r\n  // Events panel button\r\n  const eventsButton = document.createElement('button');\r\n  eventsButton.className = 'button header-button chat-events-button';\r\n  eventsButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.eventsSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(eventsButton, {\r\n    en: '[/events] View events',\r\n    ru: '[/events] Просмотреть события'\r\n  });\r\n  eventsButton.addEventListener(\"click\", () => {\r\n    (0,_components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_10__.createEventsPanel)();\r\n  });\r\n\r\n  // Blocked users button\r\n  const blockedUsersButton = document.createElement('button');\r\n  blockedUsersButton.className = 'button header-button chat-blocked-button';\r\n  blockedUsersButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.blockedUsersSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(blockedUsersButton, {\r\n    en: '[/ignored] Block user',\r\n    ru: '[/ignored] Заблокировать пользователя'\r\n  });\r\n  blockedUsersButton.addEventListener(\"click\", () => {\r\n    (0,_components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_9__.openIgnoredUsersPanel)();\r\n  });\r\n\r\n  // User colors button\r\n  const userColorsButton = document.createElement('button');\r\n  userColorsButton.className = 'button header-button chat-colors-button';\r\n  userColorsButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.userColorsSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(userColorsButton, {\r\n    en: '[/colors] Set username color',\r\n    ru: '[/colors] Задать цвет пользователю'\r\n  });\r\n  userColorsButton.addEventListener(\"click\", () => {\r\n    (0,_components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_8__.openUsernameColors)();\r\n  });\r\n\r\n  // Theme button\r\n  const themeButton = document.createElement('button');\r\n  themeButton.className = 'button header-button chat-theme-button';\r\n  themeButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.magicWandSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(themeButton, {\r\n    en: '[/themes] Change theme',\r\n    ru: '[/themes] Сменить тему'\r\n  });\r\n  themeButton.addEventListener(\"click\", () => {\r\n    (0,_components_themesPanel_js__WEBPACK_IMPORTED_MODULE_7__.openThemesPanel)();\r\n  });\r\n\r\n  // Help button next to maximize button\r\n  const helpButton = document.createElement('button');\r\n  helpButton.className = 'button header-button chat-help-button';\r\n  helpButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_4__.helpSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(helpButton, {\r\n    en: '[/help] Show chat help',\r\n    ru: '[/help] Показать справку чата'\r\n  });\r\n\r\n  // Declare a variable to track the help panel instance.\r\n  let helpPanelInstance = null;\r\n\r\n  helpButton.addEventListener('click', (e) => {\r\n    e.stopPropagation();\r\n\r\n    // If a help panel exists, remove it and exit.\r\n    if (helpPanelInstance && document.querySelector('.help-panel')) {\r\n      helpPanelInstance.remove();\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(helpButton, {\r\n        en: '[/help] Show chat help',\r\n        ru: '[/help] Показать справку чата'\r\n      });\r\n      helpPanelInstance = null;\r\n      return;\r\n    }\r\n\r\n    // Otherwise, create a new help panel.\r\n    helpPanelInstance = new _components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__.HelpPanel({\r\n      helpButton: helpButton,\r\n      onDestroy: () => {\r\n        (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(helpButton, {\r\n          en: '[/help] Show chat help',\r\n          ru: '[/help] Показать справку чата'\r\n        });\r\n        helpPanelInstance = null;\r\n      }\r\n    });\r\n    helpPanelInstance.init();\r\n    helpPanelInstance.show();\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_11__.createCustomTooltip)(helpButton, {\r\n      en: '[/help] Hide chat help',\r\n      ru: '[/help] Скрыть справку чата'\r\n    });\r\n  });\r\n\r\n\r\n  // Maximize button\r\n  const maximizeButton = document.createElement('button');\r\n  maximizeButton.className = 'button header-button chat-maximize-button';\r\n  maximizeButton.addEventListener('click', _chatState_js__WEBPACK_IMPORTED_MODULE_2__.toggleChatMaximize);\r\n\r\n  // Toggle visibility button\r\n  const toggleButton = document.createElement('button');\r\n  toggleButton.className = 'button header-button chat-toggle-button';\r\n  toggleButton.addEventListener('click', _chatState_js__WEBPACK_IMPORTED_MODULE_2__.toggleChatVisibility);\r\n\r\n  headerButtons.append(\r\n    eventsButton,\r\n    blockedUsersButton,\r\n    userColorsButton,\r\n    themeButton,\r\n    helpButton,\r\n    maximizeButton,\r\n    toggleButton\r\n  );\r\n  document.body.appendChild(chatContainer);\r\n\r\n  // Apply the saved theme to the chat container\r\n  applyUITheme();\r\n\r\n  // Restore chat state and settings\r\n  (0,_chatState_js__WEBPACK_IMPORTED_MODULE_2__.restoreChatState)();\r\n  (0,_chatFontSize_js__WEBPACK_IMPORTED_MODULE_3__.createFontSizeControl)();\r\n  (0,_chatFontSize_js__WEBPACK_IMPORTED_MODULE_3__.restoreFontSize)();\r\n\r\n  // Initial setup after DOM is ready\r\n  requestAnimationFrame(() => {\r\n    if (messageInput) {\r\n      messageInput.value = ''; // Clear input field on load\r\n    }\r\n\r\n    // Pass the input element and messages panel into the helper functions.\r\n    (0,_helpers_lengthPopup_js__WEBPACK_IMPORTED_MODULE_0__.createLengthPopup)(messagesPanel);\r\n    (0,_helpers_lengthPopup_js__WEBPACK_IMPORTED_MODULE_0__.initChatLengthPopupEvents)(messageInput);\r\n    (0,_helpers_mobileLayout_js__WEBPACK_IMPORTED_MODULE_1__.handleMobileLayout)(chatContainer, chatContent, messagesPanel, dragArea, inputContainer);\r\n    (0,_components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_10__.updateEventsButtonState)();\r\n  });\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/chat/chatUI.js?");

/***/ }),

/***/ "./src/components/chatUsernameColorsPanel.js":
/*!***************************************************!*\
  !*** ./src/components/chatUsernameColorsPanel.js ***!
  \***************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   exportUsernameColors: () => (/* binding */ exportUsernameColors),\n/* harmony export */   importUsernameColors: () => (/* binding */ importUsernameColors),\n/* harmony export */   openUsernameColors: () => (/* binding */ openUsernameColors)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n// Centralized storage wrapper.\r\nconst storageKey = 'usernameColors';\r\nconst storageWrapper = {\r\n  get: (storage) => {\r\n    try {\r\n      const stored = storage.getItem(storageKey);\r\n      return stored ? JSON.parse(stored) : {};\r\n    } catch (e) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Error parsing ${storage === sessionStorage ? 'sessionStorage' : 'localStorage'} data: ${e.message}`,\r\n        ru: `Ошибка разбора данных ${storage === sessionStorage ? 'sessionStorage' : 'localStorage'}: ${e.message}`\r\n      }, 'error');\r\n      return {};\r\n    }\r\n  },\r\n  set: (storage, data) => {\r\n    try {\r\n      storage.setItem(storageKey, JSON.stringify(data));\r\n      return true;\r\n    } catch (e) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Error saving data to ${storage === sessionStorage ? 'sessionStorage' : 'localStorage'}: ${e.message}`,\r\n        ru: `Ошибка сохранения данных в ${storage === sessionStorage ? 'sessionStorage' : 'localStorage'}: ${e.message}`\r\n      }, 'error');\r\n      return false;\r\n    }\r\n  }\r\n};\r\n\r\nconst storageOps = {\r\n  getColors: () => storageWrapper.get(sessionStorage),\r\n  saveColor: (username, color) => {\r\n    const localColors = storageWrapper.get(localStorage);\r\n    localColors[username] = color;\r\n    return storageWrapper.set(localStorage, localColors);\r\n  },\r\n  removeColor: (username) => {\r\n    const localColors = storageWrapper.get(localStorage);\r\n    if (username in localColors) {\r\n      delete localColors[username];\r\n      return storageWrapper.set(localStorage, localColors);\r\n    }\r\n    return false;\r\n  },\r\n  isColorSaved: (username) => {\r\n    const localColors = storageWrapper.get(localStorage);\r\n    return username in localColors;\r\n  },\r\n  updateUsername: (oldUsername, newUsername, color) => {\r\n    const localColors = storageWrapper.get(localStorage);\r\n    if (oldUsername in localColors) {\r\n      delete localColors[oldUsername];\r\n      localColors[newUsername] = color;\r\n      return storageWrapper.set(localStorage, localColors);\r\n    }\r\n    return false;\r\n  }\r\n};\r\n\r\n// DOM element creation helper.\r\nfunction createElement(tag, className, attributes = {}) {\r\n  const element = document.createElement(tag);\r\n  if (className) element.className = className;\r\n  Object.entries(attributes).forEach(([key, value]) => {\r\n    if (key === 'text') {\r\n      element.textContent = value;\r\n    } else if (key === 'html') {\r\n      element.innerHTML = value;\r\n    } else {\r\n      element.setAttribute(key, value);\r\n    }\r\n  });\r\n  return element;\r\n};\r\n\r\n// Helper: append alpha to hex.\r\nfunction hexWithAlpha(hex, alpha) {\r\n  const alphaHex = Math.round(alpha * 255).toString(16).padStart(2, '0');\r\n  return hex.length === 7 ? hex + alphaHex : hex.slice(0, 7) + alphaHex;\r\n}\r\n\r\n// Update styling for label and color box.\r\nfunction updateStyles(label, colorBox, color) {\r\n  label.style.color = color;\r\n  Object.assign(colorBox.style, {\r\n    backgroundColor: hexWithAlpha(color, 0.4),\r\n    color\r\n  });\r\n  colorBox.textContent = color;\r\n};\r\n\r\n// Validate hex color (#FFFFFF format)\r\nconst isValidHex = (hex) => /^#[0-9A-Fa-f]{6}$/.test(hex);\r\n\r\n// The main exported function.\r\nfunction openUsernameColors() {\r\n  // Prevent duplicate container creation.\r\n  const existingContainer = document.querySelector('.chat-username-color-picker');\r\n  if (existingContainer) {\r\n    return existingContainer;\r\n  }\r\n\r\n  const sessionColors = storageOps.getColors();\r\n  let savedBlock = null;\r\n  let longPressTimer = null;\r\n  let currentEntry = null;\r\n\r\n  // Create container and username-colors container.\r\n  const container = createElement('div', 'chat-username-color-picker');\r\n  const usernameColors = createElement('div', 'username-colors');\r\n  container.appendChild(usernameColors);\r\n\r\n  // Create h2 (main header) and append to usernameColors.\r\n  const header = createElement('h2', null, { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.usernameColorsHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage] });\r\n  usernameColors.appendChild(header);\r\n\r\n  // Create close button\r\n  const closeButton = createElement('button', 'close-btn');\r\n  closeButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.removeSVG;\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(closeButton, {\r\n    en: 'Close panel',\r\n    ru: 'Закрыть панель'\r\n  });\r\n  closeButton.addEventListener('click', () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n  });\r\n  container.appendChild(closeButton);\r\n\r\n  // Create container and blocks.\r\n  const generatedBlock = createElement(\r\n    'div',\r\n    'generated-username-colors',\r\n    { html: `<h3>${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.generatedColorsHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage]} <span class=\"counter\">0</span></h3>` }\r\n  );\r\n\r\n  // Create saved colors block if needed.\r\n  function createSavedBlock() {\r\n    if (!savedBlock) {\r\n      savedBlock = createElement(\r\n        'div',\r\n        'saved-username-colors',\r\n        { html: `<h3>${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.savedColorsHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage]} <span class=\"counter\">0</span></h3>` }\r\n      );\r\n      const header = container.querySelector('h2');\r\n      header.nextSibling ? container.insertBefore(savedBlock, header.nextSibling) : usernameColors.appendChild(savedBlock);\r\n    }\r\n  };\r\n\r\n  // New helper to update header counters.\r\n  function updateCounters() {\r\n    if (generatedBlock) {\r\n      const count = generatedBlock.querySelectorAll('.username-entry').length;\r\n      const counterSpan = generatedBlock.querySelector('h3 .counter');\r\n      if (counterSpan) { counterSpan.textContent = count; }\r\n    }\r\n    if (savedBlock) {\r\n      const count = savedBlock.querySelectorAll('.username-entry').length;\r\n      const counterSpan = savedBlock.querySelector('h3 .counter');\r\n      if (counterSpan) { counterSpan.textContent = count; }\r\n    }\r\n  }\r\n\r\n  function updateGeneratedBlockStatus() {\r\n    generatedBlock.querySelectorAll('.username-entry').forEach(entry => {\r\n      const username = entry.querySelector('.username').textContent;\r\n      entry.classList.toggle('disabled-entry', storageOps.isColorSaved(username));\r\n    });\r\n    updateCounters();\r\n  };\r\n\r\n  // Create an entry element.\r\n  function createEntry(username, color, isSaved = false) {\r\n    const entry = createElement('div', 'username-entry');\r\n    const label = createElement('div', 'username', { text: username });\r\n    const colorBox = createElement('div', 'color-box');\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(colorBox, {\r\n      en: '[Click] Select new color [Hold (LMB)] Set hex color value',\r\n      ru: '[Клик] Выбрать новый цвет [Удерживание (ЛКМ)] Установить hex значение цвета'\r\n    });\r\n    updateStyles(label, colorBox, color);\r\n    const colorInput = createElement('input', null, { type: 'color', value: color });\r\n\r\n    // We keep a reference to the input element on the entry.\r\n    entry._colorInput = colorInput;\r\n    entry._username = username;\r\n    entry._color = color;\r\n\r\n    entry.append(label, colorBox, colorInput);\r\n\r\n    if (isSaved) {\r\n      // Create remove button on initialization.\r\n      const removeBtn = createOrUpdateRemoveButton(entry, username, color, () => {\r\n        entry.remove();\r\n        updateGeneratedBlockStatus();\r\n        if (savedBlock && !savedBlock.querySelector('.username-entry')) {\r\n          savedBlock.remove();\r\n          savedBlock = null;\r\n        }\r\n      });\r\n\r\n      // Create edit button for usernames in saved entries\r\n      const editBtn = createEditButton(entry, username, color);\r\n      entry.appendChild(editBtn);\r\n\r\n      // Save a reference for later update.\r\n      entry._removeBtn = removeBtn;\r\n      entry._editBtn = editBtn;\r\n    }\r\n\r\n    const debouncedUpdate = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.debounce)(() => {\r\n      const newColor = colorInput.value;\r\n      updateStyles(label, colorBox, newColor);\r\n      if (!isSaved) {\r\n        sessionColors[username] = newColor;\r\n        storageWrapper.set(sessionStorage, sessionColors);\r\n        storageOps.saveColor(username, newColor);\r\n        createSavedBlock();\r\n        renderSavedBlock();\r\n        updateGeneratedBlockStatus();\r\n      } else {\r\n        storageOps.saveColor(username, newColor);\r\n        entry._color = newColor;\r\n\r\n        // Update or recreate the buttons\r\n        if (!entry._removeBtn || !entry.contains(entry._removeBtn)) {\r\n          entry._removeBtn = createOrUpdateRemoveButton(entry, username, newColor, () => {\r\n            entry.remove();\r\n            updateGeneratedBlockStatus();\r\n            if (savedBlock && !savedBlock.querySelector('.username-entry')) {\r\n              savedBlock.remove();\r\n              savedBlock = null;\r\n            }\r\n          });\r\n        } else {\r\n          Object.assign(entry._removeBtn.style, {\r\n            backgroundColor: hexWithAlpha(newColor, 0.4),\r\n            color: newColor\r\n          });\r\n        }\r\n\r\n        if (!entry._editBtn || !entry.contains(entry._editBtn)) {\r\n          entry._editBtn = createEditButton(entry, username, newColor);\r\n        } else {\r\n          Object.assign(entry._editBtn.style, {\r\n            backgroundColor: hexWithAlpha(newColor, 0.4),\r\n            color: newColor\r\n          });\r\n        }\r\n      }\r\n    }, 1000);\r\n\r\n    colorInput.addEventListener('input', debouncedUpdate);\r\n    return entry;\r\n  };\r\n\r\n  // Create edit button for username entries\r\n  function createEditButton(entry, _username, color) {\r\n    const editBtn = createElement('div', 'entry-btn edit-btn');\r\n    editBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.editSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(editBtn, {\r\n      en: 'Edit username',\r\n      ru: 'Редактировать имя пользователя'\r\n    });\r\n    Object.assign(editBtn.style, {\r\n      backgroundColor: hexWithAlpha(color, 0.4),\r\n      color\r\n    });\r\n\r\n    editBtn.addEventListener('click', (e) => {\r\n      e.stopPropagation();\r\n      showConfirmation(entry, 'username');\r\n    });\r\n\r\n    entry.appendChild(editBtn);\r\n    return editBtn;\r\n  };\r\n\r\n  // Render saved colors block.\r\n  function renderSavedBlock() {\r\n    if (!savedBlock) return;\r\n    const localColors = storageWrapper.get(localStorage);\r\n    savedBlock.innerHTML = `<h3>${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.savedColorsHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage]} <span class=\"counter\">0</span></h3>`;\r\n    // prepend add button as first entry\r\n    savedBlock.appendChild(createFirstEntryButtons());\r\n    Object.entries(localColors).forEach(([username, color]) => {\r\n      const entry = createEntry(username, color, true);\r\n      savedBlock.appendChild(entry);\r\n    });\r\n    if (!savedBlock.querySelector('.username-entry')) {\r\n      savedBlock.remove();\r\n      savedBlock = null;\r\n    }\r\n    updateCounters();\r\n  }\r\n\r\n  // Render generated colors.\r\n  Object.entries(sessionColors).forEach(([username, color]) => {\r\n    const entry = createEntry(username, color);\r\n    generatedBlock.appendChild(entry);\r\n  });\r\n  updateCounters();\r\n  createSavedBlock();\r\n  renderSavedBlock();\r\n  updateGeneratedBlockStatus();\r\n\r\n  usernameColors.appendChild(generatedBlock);\r\n  document.body.appendChild(container);\r\n\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'show', 1);\r\n\r\n  const handleEscapeKey = (e) => {\r\n    if (e.key === 'Escape') {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('keydown', handleEscapeKey);\r\n    }\r\n  };\r\n\r\n  document.addEventListener('keydown', handleEscapeKey);\r\n\r\n  // Hide container on outside click.\r\n  const handleOutsideClick = (e) => {\r\n    if (!container.contains(e.target)) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('click', handleOutsideClick, true);\r\n      document.removeEventListener('keydown', handleEscapeKey); // Remove ESC key listener\r\n    }\r\n  };\r\n  document.addEventListener('click', handleOutsideClick, true);\r\n\r\n  // Delegate click events on the container.\r\n  container.addEventListener('click', (e) => {\r\n    // Handle remove button clicks.\r\n    const removeBtn = e.target.closest('.remove-btn');\r\n    if (removeBtn) {\r\n      const entry = removeBtn.closest('.username-entry');\r\n      if (!entry) return;\r\n      const username = entry.querySelector('.username').textContent;\r\n      storageOps.removeColor(username);\r\n      entry.remove();\r\n      updateGeneratedBlockStatus();\r\n      if (savedBlock && !savedBlock.querySelector('.username-entry')) {\r\n        savedBlock.remove();\r\n        savedBlock = null;\r\n      }\r\n      return;\r\n    }\r\n\r\n    // Handle color box click.\r\n    const colorBox = e.target.closest('.color-box');\r\n    if (colorBox) {\r\n      const entry = colorBox.closest('.username-entry');\r\n      if (!entry || entry.classList.contains('disabled-entry') || entry._confirmation) return;\r\n\r\n      // Always open native color picker on click\r\n      if (entry._colorInput) {\r\n        entry._colorInput.click();\r\n      }\r\n    }\r\n  });\r\n\r\n  // Delegate pointer events for long press on color boxes.\r\n  container.addEventListener('pointerdown', (e) => {\r\n    const colorBox = e.target.closest('.color-box');\r\n    if (!colorBox) return;\r\n    const entry = colorBox.closest('.username-entry');\r\n    if (!entry || entry.classList.contains('disabled-entry')) return;\r\n    // Start long press timer.\r\n    longPressTimer = setTimeout(() => {\r\n      entry._isLongPress = true;\r\n      showConfirmation(entry, 'color');\r\n    }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.longPressDuration);\r\n    // Save the current entry for pointerup/leave events.\r\n    currentEntry = entry;\r\n  });\r\n\r\n  container.addEventListener('pointerup', clearLongPress);\r\n  container.addEventListener('pointerleave', clearLongPress);\r\n  container.addEventListener('pointercancel', clearLongPress);\r\n\r\n  function clearLongPress() {\r\n    clearTimeout(longPressTimer);\r\n    if (currentEntry) {\r\n      currentEntry._isLongPress = false;\r\n      currentEntry = null;\r\n    }\r\n  }\r\n\r\n  // Highlight field on error or no value\r\n  function highlightFieldOnError(field) {\r\n    field.classList.add('field-error');\r\n    setTimeout(() => field.classList.remove('field-error'), 500);\r\n  }\r\n\r\n  // Builds the first-entry control buttons.\r\n  function createFirstEntryButtons() {\r\n    const entry = createElement('div', 'username-entry');\r\n\r\n    const removeAllBtn = createElement('div', 'entry-btn remove-all-btn');\r\n    removeAllBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.removeSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(removeAllBtn, {\r\n      en: 'Remove all saved colors',\r\n      ru: 'Удалить все сохранённые цвета'\r\n    });\r\n    removeAllBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n\r\n      showConfirmation({ _confirmation: false }, 'removeAll', () => {\r\n        localStorage.removeItem(storageKey);\r\n        const picker = document.querySelector('.chat-username-color-picker');\r\n        if (picker) {\r\n          picker.remove();\r\n          openUsernameColors();\r\n        }\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: 'All saved username colors have been removed',\r\n          ru: 'Все сохранённые цвета имён пользователей удалены'\r\n        }, 'info');\r\n      });\r\n    });\r\n\r\n    // LOAD button (new)\r\n    const loadBtn = createElement('div', 'entry-btn load-btn');\r\n    loadBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.loadSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(loadBtn, {\r\n      en: 'Load colors from GitHub',\r\n      ru: 'Загрузить цвета из GitHub'\r\n    });\r\n    loadBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      loadUsernameColors(_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.loadUsernameColorsUrl);\r\n    });\r\n\r\n    // IMPORT button\r\n    const importBtn = createElement('div', 'entry-btn import-btn');\r\n    importBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.importSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(importBtn, {\r\n      en: 'Import colors',\r\n      ru: 'Импортировать цвета'\r\n    });\r\n    importBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      importUsernameColors();\r\n    });\r\n\r\n    // EXPORT button\r\n    const exportBtn = createElement('div', 'entry-btn export-btn');\r\n    exportBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.exportSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(exportBtn, {\r\n      en: 'Export colors',\r\n      ru: 'Экспортировать цвета'\r\n    });\r\n    exportBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      exportUsernameColors();\r\n    });\r\n\r\n    // ADD button\r\n    const addBtn = createElement('div', 'entry-btn add-btn');\r\n    addBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.addSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(addBtn, {\r\n      en: 'Add username',\r\n      ru: 'Добавить имя пользователя'\r\n    });\r\n    addBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      showConfirmation({ _confirmation: false, _add: true }, 'username');\r\n    });\r\n\r\n    entry.append(removeAllBtn, loadBtn, importBtn, exportBtn, addBtn);\r\n    return entry;\r\n  }\r\n\r\n  // Unified confirm dialog for color-edit, username-edit, or remove-only flows.\r\n  function showConfirmation(entry, mode = 'color', callback = null) {\r\n    const parent = document.querySelector('.chat-username-color-picker');\r\n\r\n    // First, check if there's any existing confirmation dialog anywhere\r\n    const existingConfirmation = parent.querySelector('.confirmation');\r\n    if (existingConfirmation) {\r\n      existingConfirmation.remove();\r\n    }\r\n\r\n    // Mark the entry as having a confirmation dialog\r\n    entry._confirmation = true;\r\n\r\n    // Create the new confirmation dialog\r\n    const container = createElement('div', 'confirmation');\r\n    const cancelBtn = createElement('button', 'field-btn cancel-btn', { text: 'Cancel' });\r\n    const confirmBtn = createElement('button', 'field-btn confirm-btn', { text: 'Confirm' });\r\n\r\n    // Only create an input field for color or username modes\r\n    let inputField = null;\r\n    if (mode === 'color' || mode === 'username') {\r\n      inputField = createElement('input', 'input-field', {\r\n        type: 'search',\r\n        placeholder: mode === 'color'\r\n          ? `H: ${entry._username}`\r\n          : `U: ${entry._username || 'username'}`\r\n      });\r\n      container.append(cancelBtn, inputField, confirmBtn);\r\n    } else {\r\n      // Remove-only flow\r\n      container.append(cancelBtn, confirmBtn);\r\n    }\r\n\r\n    // Append the container to the parent\r\n    parent.appendChild(container);\r\n\r\n    if (inputField) {\r\n      inputField.focus();\r\n      inputField.addEventListener('keydown', e => {\r\n        if (e.key === 'Enter') {\r\n          e.stopPropagation();\r\n          confirmBtn.click();\r\n        }\r\n      });\r\n    }\r\n\r\n    // Cleanup helper function\r\n    function closeDialog() {\r\n      container.remove();\r\n      entry._confirmation = false;\r\n    }\r\n\r\n    confirmBtn.addEventListener('click', async e => {\r\n      e.stopPropagation();\r\n\r\n      if (mode === 'color') {\r\n        const val = inputField.value.trim();\r\n        if (!val) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: 'The field cannot be empty',\r\n            ru: 'Поле не может быть пустым'\r\n          }, 'warning');\r\n          highlightFieldOnError(inputField);\r\n          return;\r\n        }\r\n        if (!isValidHex(val)) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: `Invalid hex \"${val}\"`,\r\n            ru: `Некорректный hex \"${val}\"`\r\n          }, 'error');\r\n          highlightFieldOnError(inputField);\r\n          return;\r\n        }\r\n        entry._colorInput.value = val.toLowerCase();\r\n        entry._colorInput.dispatchEvent(new Event('input', { bubbles: true }));\r\n\r\n      } else if (mode === 'username') {\r\n        const val = inputField.value.trim();\r\n        if (!val) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: 'The field cannot be empty',\r\n            ru: 'Поле не может быть пустым'\r\n          }, 'warning');\r\n          highlightFieldOnError(inputField);\r\n          return;\r\n        }\r\n\r\n        // First verify user exists\r\n        const userId = await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.getExactUserIdByName)(val);\r\n        if (!userId) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: `Could not find user \"${val}\"`,\r\n            ru: `Не удалось найти пользователя \"${val}\"`\r\n          }, 'error');\r\n          highlightFieldOnError(inputField);\r\n          return;\r\n        }\r\n\r\n        // If this was the \"add\" button dummy\r\n        if (entry._add) {\r\n          const username = val;\r\n          const defaultColor = '#cdcdcd';\r\n          storageOps.saveColor(username, defaultColor);\r\n          createSavedBlock();\r\n          renderSavedBlock();\r\n          updateGeneratedBlockStatus();\r\n          closeDialog();\r\n          return;\r\n        }\r\n\r\n        // Otherwise it's the edit-existing flow\r\n        if (val !== entry._username) {\r\n          storageOps.updateUsername(entry._username, val, entry._color);\r\n          entry.querySelector('.username').textContent = val;\r\n          entry._username = val;\r\n          updateGeneratedBlockStatus();\r\n        }\r\n\r\n      } else if (mode === 'remove') {\r\n        storageOps.removeColor(entry._username);\r\n        if (entry instanceof Element) entry.remove();\r\n        updateGeneratedBlockStatus();\r\n      } else if (mode === 'removeAll') {\r\n        if (typeof callback === 'function') {\r\n          callback();\r\n        }\r\n      }\r\n\r\n      closeDialog();\r\n    });\r\n\r\n    cancelBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      closeDialog();\r\n    });\r\n\r\n    // Stop propagation of click events to prevent bubbling\r\n    container.addEventListener('click', e => e.stopPropagation());\r\n  }\r\n\r\n  // Helper to create or update the remove button for an entry.\r\n  function createOrUpdateRemoveButton(entry, username, color, updateCb) {\r\n    // remove any old button\r\n    let removeBtn = entry.querySelector('.remove-btn');\r\n    if (removeBtn) entry.removeChild(removeBtn);\r\n\r\n    // build new one\r\n    removeBtn = createElement('div', 'entry-btn remove-btn');\r\n    removeBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_2__.removeSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_3__.createCustomTooltip)(removeBtn, {\r\n      en: 'Remove entry',\r\n      ru: 'Удалить запись'\r\n    });\r\n    Object.assign(removeBtn.style, {\r\n      backgroundColor: hexWithAlpha(color, 0.4),\r\n      color\r\n    });\r\n\r\n    removeBtn.addEventListener('click', e => {\r\n      e.stopPropagation();\r\n      // guard re-entry\r\n      if (entry._confirmation) return;\r\n      // launch confirm-only dialog; on confirm → actually remove\r\n      showConfirmation(entry, 'remove', () => {\r\n        storageOps.removeColor(username);\r\n        entry.remove();\r\n        if (typeof updateCb === 'function') updateCb();\r\n      });\r\n    });\r\n\r\n    entry.appendChild(removeBtn);\r\n    return removeBtn;\r\n  };\r\n\r\n  return container;\r\n};\r\n\r\n// Helper to export username colors to a JSON file.\r\nfunction exportUsernameColors() {\r\n  const usernameColors = localStorage.getItem('usernameColors');\r\n  if (!usernameColors) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: 'No username colors found to export',\r\n      ru: 'Нет цветов имён пользователей для экспорта'\r\n    }, 'warning');\r\n    return;\r\n  }\r\n  // Parse and stringify with indentation\r\n  const formattedJson = JSON.stringify(JSON.parse(usernameColors), null, 2);\r\n  const blob = new Blob([formattedJson], { type: 'application/json' });\r\n  const url = URL.createObjectURL(blob);\r\n  const a = document.createElement('a');\r\n  a.href = url;\r\n  a.download = 'usernameColors.json';\r\n  a.click();\r\n  URL.revokeObjectURL(url);\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n    en: 'Username colors exported as JSON file',\r\n    ru: 'Цвета имён пользователей экспортированы в JSON-файл'\r\n  }, 'success');\r\n}\r\n\r\n// Helper to import username colors from a JSON file.\r\nfunction importUsernameColors() {\r\n  const input = document.createElement('input');\r\n  input.type = 'file';\r\n  input.accept = 'application/json';\r\n  input.style.display = 'none';\r\n  document.body.appendChild(input);\r\n  input.addEventListener('change', (event) => {\r\n    const file = event.target.files[0];\r\n    if (!file) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: 'No file selected',\r\n        ru: 'Файл не выбран'\r\n      }, 'warning');\r\n      return;\r\n    }\r\n    const reader = new FileReader();\r\n    reader.onload = (e) => {\r\n      try {\r\n        const jsonData = JSON.parse(e.target.result);\r\n        localStorage.setItem('usernameColors', JSON.stringify(jsonData));\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: 'Username colors imported successfully',\r\n          ru: 'Цвета имён пользователей успешно импортированы'\r\n        }, 'info');\r\n      } catch (err) {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: 'Invalid JSON file',\r\n          ru: 'Некорректный JSON-файл'\r\n        }, 'error');\r\n      }\r\n    };\r\n    reader.readAsText(file);\r\n  });\r\n  input.click();\r\n  document.body.removeChild(input);\r\n}\r\n\r\n// Helper to load username colors from a URL\r\nfunction loadUsernameColors(url) {\r\n  fetch(url)\r\n    .then(response => {\r\n      if (!response.ok) {\r\n        throw new Error(`Failed to load: ${response.statusText}`);\r\n      }\r\n      return response.json();\r\n    })\r\n    .then(jsonData => {\r\n      localStorage.setItem('usernameColors', JSON.stringify(jsonData));\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: 'Username colors loaded successfully',\r\n        ru: 'Цвета имён пользователей успешно загружены'\r\n      }, 'success');\r\n\r\n      // Refresh the UI if color picker is currently open\r\n      const picker = document.querySelector('.chat-username-color-picker');\r\n      if (picker) {\r\n        // Remove existing picker and create a new one to reflect the changes\r\n        picker.remove();\r\n        openUsernameColors();\r\n      }\r\n    })\r\n    .catch(error => {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Error loading colors: ${error.message}`, 'error');\r\n    });\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/chatUsernameColorsPanel.js?");

/***/ }),

/***/ "./src/components/emojiPanel.js":
/*!**************************************!*\
  !*** ./src/components/emojiPanel.js ***!
  \**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   EmojiPanel: () => (/* binding */ EmojiPanel)\n/* harmony export */ });\n/* harmony import */ var _data_emojiData_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/emojiData.js */ \"./src/data/emojiData.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n// Create a single global shortcut handler\r\nconst setupGlobalEmojiShortcut = (() => {\r\n  let isSetup = false;\r\n\r\n  return function () {\r\n    if (!isSetup) {\r\n      document.addEventListener('keydown', (e) => {\r\n        if (e.ctrlKey && e.code === 'Semicolon') {\r\n          e.preventDefault();\r\n          if (!document.querySelector('.emoji-panel')) {\r\n            // Initialize or show the emoji panel with a callback to insert emoji\r\n            new EmojiPanel({\r\n              onEmojiSelect: (emoji) => {\r\n                const input = document.getElementById('message-input');\r\n                if (input) {\r\n                  input.value += emoji;\r\n                  // Optionally, dispatch an input event if your application needs it\r\n                  input.dispatchEvent(new Event('input', { bubbles: true }));\r\n                  input.focus(); // Add this line to restore focus\r\n                }\r\n              }\r\n            }).show();\r\n          }\r\n        }\r\n      });\r\n      isSetup = true;\r\n    }\r\n  };\r\n})();\r\n\r\n// Call this function immediately to set up the shortcut\r\nsetupGlobalEmojiShortcut();\r\n\r\n\r\nclass EmojiPanel {\r\n  static instance = null;\r\n\r\n  constructor(options = {}) {\r\n    if (EmojiPanel.instance) {\r\n      return EmojiPanel.instance;\r\n    }\r\n    EmojiPanel.instance = this;\r\n    this.options = {\r\n      onEmojiSelect: options.onEmojiSelect || (() => { }),\r\n      container: options.container || document.getElementById('messages-panel') || document.body,\r\n      position: options.position || 'bottom',\r\n      onDestroy: options.onDestroy,\r\n      emojiButton: options.emojiButton,\r\n    };\r\n\r\n    // DOM elements\r\n    this.container = null;\r\n    this.searchInput = null;\r\n    this.emojiContainer = null;\r\n    this.categoryNav = null;\r\n    this.infoPanel = null;\r\n    this.infoIcon = null;\r\n    this.infoKeywords = null;\r\n    this.languageSelect = null;\r\n\r\n    // Category definitions with icons\r\n    this.categories = {\r\n      recent: { icon: '🕒' },\r\n      smileys: { icon: '😊' },\r\n      nature: { icon: '🦊' },\r\n      food: { icon: '🍔' },\r\n      activities: { icon: '⚽' },\r\n      travel: { icon: '✈️' },\r\n      objects: { icon: '💡' },\r\n      symbols: { icon: '💕' },\r\n      flags: { icon: '🎌' }\r\n    };\r\n\r\n    // Localized category names\r\n    this.categoryLabels = {\r\n      en: {\r\n        recent: 'Recently Used',\r\n        smileys: 'Smileys & People',\r\n        nature: 'Animals & Nature',\r\n        food: 'Food & Drink',\r\n        activities: 'Activities',\r\n        travel: 'Travel & Places',\r\n        objects: 'Objects',\r\n        symbols: 'Symbols',\r\n        flags: 'Flags'\r\n      },\r\n      ru: {\r\n        recent: 'Недавно использованные',\r\n        smileys: 'Смайлы и люди',\r\n        nature: 'Животные и природа',\r\n        food: 'Еда и напитки',\r\n        activities: 'Активности',\r\n        travel: 'Путешествия и места',\r\n        objects: 'Объекты',\r\n        symbols: 'Символы',\r\n        flags: 'Флаги'\r\n      }\r\n    };\r\n\r\n    // UI Labels for static text elements\r\n    this.uiLabels = {\r\n      en: {\r\n        searchResults: 'Search Results'\r\n      },\r\n      ru: {\r\n        searchResults: 'Результаты поиска'\r\n      }\r\n    };\r\n\r\n    // Emoji data and keywords\r\n    this.emojiData = _data_emojiData_js__WEBPACK_IMPORTED_MODULE_0__.emojiData;\r\n    this.emojiKeywords = _data_emojiData_js__WEBPACK_IMPORTED_MODULE_0__.emojiKeywords;\r\n\r\n    // Recently used emojis (loaded from localStorage)\r\n    this.recentEmojis = this.loadRecentEmojis();\r\n\r\n    // Infinite scroll settings\r\n    this.batchSize = 50;\r\n    this.loadedIndices = {};\r\n    this.categorySections = {};\r\n\r\n    // Retrieve current language from localStorage (default to 'en')\r\n    this.currentLanguage = localStorage.getItem('emojiPanelLanguage') || 'en';\r\n  }\r\n\r\n  /** Initialize the emoji panel */\r\n  init() {\r\n    this.createPanel();\r\n    this.bindEvents();\r\n    this.loadAllEmojis();\r\n    return this;\r\n  }\r\n\r\n  /** Create the HTML structure of the emoji panel */\r\n  createPanel() {\r\n    if (document.querySelector('.emoji-panel')) {\r\n      return;\r\n    }\r\n    this.container = document.createElement('div');\r\n    this.container.className = 'emoji-panel';\r\n\r\n    // Search container\r\n    const searchContainer = document.createElement('div');\r\n    searchContainer.className = 'emoji-search-container';\r\n    this.searchInput = document.createElement('input');\r\n    this.searchInput.type = 'search';\r\n    this.searchInput.className = 'emoji-search';\r\n    searchContainer.appendChild(this.searchInput);\r\n\r\n    // Category navigation\r\n    this.categoryNav = document.createElement('div');\r\n    this.categoryNav.className = 'emoji-categories';\r\n    Object.entries(this.categories).forEach(([key, category]) => {\r\n      const categoryBtn = document.createElement('button');\r\n      categoryBtn.className = 'emoji-category-btn';\r\n      categoryBtn.dataset.category = key;\r\n      categoryBtn.innerHTML = category.icon;\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(categoryBtn, this.getLocalizedCategoryName(key));\r\n      this.categoryNav.appendChild(categoryBtn);\r\n    });\r\n\r\n    // Emoji grid container\r\n    this.emojiContainer = document.createElement('div');\r\n    this.emojiContainer.className = 'emoji-container';\r\n\r\n    // Info panel\r\n    this.infoPanel = document.createElement('div');\r\n    this.infoPanel.className = 'emoji-info-panel';\r\n    this.infoIcon = document.createElement('span');\r\n    this.infoIcon.className = 'emoji-info-icon';\r\n    this.infoKeywords = document.createElement('span');\r\n    this.infoKeywords.className = 'emoji-info-keywords';\r\n    this.infoPanel.appendChild(this.infoIcon);\r\n    this.infoPanel.appendChild(this.infoKeywords);\r\n\r\n    // Language selector\r\n    this.languageSelect = document.createElement('select');\r\n    this.languageSelect.className = 'emoji-language-select';\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(this.languageSelect, {\r\n      en: 'Select interface language',\r\n      ru: 'Выберите язык интерфейса'\r\n    });\r\n    this.languageSelect.innerHTML = `\r\n      <option value=\"en\">EN</option>\r\n      <option value=\"ru\">RU</option>\r\n    `;\r\n    this.languageSelect.value = this.currentLanguage;\r\n\r\n    // Footer to hold info panel and language selector\r\n    const footer = document.createElement('div');\r\n    footer.className = 'emoji-footer';\r\n    footer.appendChild(this.infoPanel);\r\n    footer.appendChild(this.languageSelect);\r\n\r\n    // Assemble the panel\r\n    this.container.appendChild(searchContainer);\r\n    this.container.appendChild(this.categoryNav);\r\n    this.container.appendChild(this.emojiContainer);\r\n    this.container.appendChild(footer);\r\n    this.options.container.appendChild(this.container);\r\n    // Fade in the panel\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.container, 'show', '1');\r\n\r\n    // Perform mobile check and focus only when the panel is created\r\n    if (!(0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.checkIsMobile)()) {\r\n      this.searchInput.focus();\r\n    }\r\n  }\r\n\r\n  /** Load initial batch of emojis for all categories */\r\n  loadAllEmojis() {\r\n    if (!this.emojiContainer) return; // Exit early if container is missing\r\n    this.emojiContainer.innerHTML = '';\r\n    this.loadedIndices = {};\r\n    this.categorySections = {};\r\n    Object.keys(this.categories).forEach(category => {\r\n      const section = document.createElement('div');\r\n      section.className = 'emoji-category-section';\r\n      section.id = `emoji-section-${category}`;\r\n      const header = document.createElement('div');\r\n      header.className = 'emoji-category-header';\r\n      header.textContent = this.getLocalizedCategoryName(category);\r\n      section.appendChild(header);\r\n      const emojiList = document.createElement('div');\r\n      emojiList.className = 'emoji-list';\r\n      section.appendChild(emojiList);\r\n      this.emojiContainer.appendChild(section);\r\n      this.loadedIndices[category] = 0;\r\n      this.categorySections[category] = { section, emojiList, header };\r\n      this.loadMoreEmojisForCategory(category);\r\n    });\r\n  }\r\n\r\n  /** Load more emojis for a specific category */\r\n  loadMoreEmojisForCategory(category) {\r\n    const data = category === 'recent' ? this.recentEmojis : (this.emojiData[category] || []);\r\n    const start = this.loadedIndices[category];\r\n    const batch = data.slice(start, start + this.batchSize);\r\n    if (!batch.length) return;\r\n    const container = this.categorySections[category].emojiList;\r\n    batch.forEach(emoji => {\r\n      const button = document.createElement('button');\r\n      button.className = 'emoji-btn';\r\n      button.textContent = emoji;\r\n      button.addEventListener('mouseenter', () => this.updateInfoPanel(emoji));\r\n      button.addEventListener('mouseleave', () => this.clearInfoPanel());\r\n      button.addEventListener('click', (e) => {\r\n        e.stopPropagation();\r\n        if (e.shiftKey && category === 'recent') {\r\n          e.preventDefault();\r\n          this.removeFromRecent(emoji);\r\n        } else {\r\n          this.addToRecent(emoji);\r\n          this.options.onEmojiSelect(emoji);\r\n          if (!e.ctrlKey) {\r\n            this.destroy();\r\n          } else {\r\n            this.searchInput.focus();\r\n          }\r\n        }\r\n      });\r\n      container.appendChild(button);\r\n    });\r\n    this.loadedIndices[category] += batch.length;\r\n  }\r\n\r\n  /** Search for emojis based on a search term */\r\n  searchEmojis(searchTerm) {\r\n    if (!this.emojiContainer) return; // Exit early if container is missing\r\n    this.emojiContainer.innerHTML = '';\r\n    const section = document.createElement('div');\r\n    section.className = 'emoji-category-section';\r\n    const header = document.createElement('div');\r\n    header.className = 'emoji-category-header';\r\n    header.textContent = this.uiLabels[this.currentLanguage].searchResults;\r\n    section.appendChild(header);\r\n    const emojiList = document.createElement('div');\r\n    emojiList.className = 'emoji-list';\r\n    section.appendChild(emojiList);\r\n    const results = [];\r\n    Object.keys(this.emojiData).forEach(category => {\r\n      const emojis = this.emojiData[category] || [];\r\n      emojis.forEach(emoji => {\r\n        const keywordsObj = this.emojiKeywords[emoji] || {};\r\n        const allKeywords = Object.values(keywordsObj).flat();\r\n        if (\r\n          emoji.includes(searchTerm) ||\r\n          allKeywords.some(keyword => keyword.toLowerCase().includes(searchTerm))\r\n        ) {\r\n          results.push(emoji);\r\n        }\r\n      });\r\n    });\r\n    results.forEach(emoji => {\r\n      const button = document.createElement('button');\r\n      button.className = 'emoji-btn';\r\n      button.textContent = emoji;\r\n      button.addEventListener('mouseenter', () => this.updateInfoPanel(emoji));\r\n      button.addEventListener('mouseleave', () => this.clearInfoPanel());\r\n      button.addEventListener('click', (e) => {\r\n        e.stopPropagation();\r\n        this.addToRecent(emoji);\r\n        this.options.onEmojiSelect(emoji);\r\n        if (!e.ctrlKey) {\r\n          this.destroy();\r\n        } else {\r\n          this.searchInput.focus();\r\n        }\r\n      });\r\n      emojiList.appendChild(button);\r\n    });\r\n    this.emojiContainer.appendChild(section);\r\n  }\r\n\r\n  /** Bind event listeners for the emoji panel */\r\n  bindEvents() {\r\n    // Close panel on clicking outside\r\n    this._documentClickHandler = (e) => {\r\n      if (!this.container.contains(e.target)) {\r\n        this.destroy();\r\n      }\r\n    };\r\n    document.addEventListener('click', this._documentClickHandler);\r\n\r\n    // Close panel on Escape key\r\n    this._emojiKeydownHandler = (e) => {\r\n      if (e.key === 'Escape') {\r\n        this.destroy();\r\n      }\r\n    };\r\n    document.addEventListener('keydown', this._emojiKeydownHandler);\r\n\r\n    // Handle 'q' key for closing panel\r\n    this._qKeydownHandler = (e) => {\r\n      if (e.code === 'KeyQ') {\r\n        if (document.activeElement === this.searchInput) {\r\n          const now = Date.now();\r\n          if (this._lastQPressTime && (now - this._lastQPressTime < 500)) {\r\n            e.preventDefault();\r\n            this.destroy();\r\n            this._lastQPressTime = 0;\r\n          } else {\r\n            this._lastQPressTime = now;\r\n          }\r\n        } else {\r\n          e.preventDefault();\r\n          this.destroy();\r\n        }\r\n      }\r\n    };\r\n    document.addEventListener('keydown', this._qKeydownHandler);\r\n\r\n    // Update view on search input change\r\n    this.searchInput.addEventListener('input', (e) => {\r\n      const searchTerm = e.target.value.trim().toLowerCase();\r\n      if (searchTerm) {\r\n        this.searchEmojis(searchTerm);\r\n        this.emojiContainer.classList.add('search-active');\r\n      } else {\r\n        this.loadAllEmojis();\r\n        this.emojiContainer.classList.remove('search-active');\r\n      }\r\n    });\r\n\r\n    // Handle Enter key in search input\r\n    this.searchInput.addEventListener('keydown', (e) => {\r\n      if (e.key === 'Enter') {\r\n        e.preventDefault();\r\n\r\n        // Ensure both elements exist before proceeding\r\n        if (!this.searchInput || !this.emojiContainer) return;\r\n\r\n        if (this.emojiContainer.classList.contains('search-active')) {\r\n          const firstEmojiBtn = this.emojiContainer?.querySelector('.emoji-btn');\r\n\r\n          if (firstEmojiBtn) {\r\n            const clickEvent = new MouseEvent('click', {\r\n              bubbles: true,\r\n              cancelable: true,\r\n              ctrlKey: e.ctrlKey\r\n            });\r\n            firstEmojiBtn.dispatchEvent(clickEvent);\r\n\r\n            // Ensure emojiContainer still exists before modifying it\r\n            if (this.emojiContainer) {\r\n              this.emojiContainer.classList.remove('search-active');\r\n              this.loadAllEmojis(); // Only if emojiContainer is still valid\r\n            }\r\n\r\n            // Ensure the search input exists before modifying it\r\n            if (this.searchInput) {\r\n              this.searchInput.value = '';\r\n            }\r\n\r\n            if (!e.ctrlKey) {\r\n              this.destroy();\r\n            } else if (this.searchInput) {\r\n              this.searchInput.focus();\r\n            }\r\n          }\r\n        }\r\n      }\r\n    });\r\n\r\n    // Category navigation clicks\r\n    this.categoryNav.addEventListener('click', (e) => {\r\n      const btn = e.target.closest('.emoji-category-btn');\r\n      if (btn) {\r\n        const category = btn.dataset.category;\r\n        const section = document.getElementById(`emoji-section-${category}`);\r\n        if (section && this.emojiContainer) {\r\n          // Add smooth scrolling behavior\r\n          this.emojiContainer.style.scrollBehavior = 'smooth';\r\n\r\n          // Instead of using scrollIntoView, manually set the scrollTop\r\n          // of the emoji container to the offsetTop of the section\r\n          this.emojiContainer.scrollTop = section.offsetTop - this.emojiContainer.offsetTop;\r\n\r\n          // Prevent default behavior to avoid any parent scrolling\r\n          e.preventDefault();\r\n          e.stopPropagation();\r\n        }\r\n      }\r\n    });\r\n\r\n    // Infinite scroll handler\r\n    this.emojiContainer.addEventListener('scroll', () => this.handleScroll());\r\n\r\n    // Language change handler\r\n    this.languageSelect.addEventListener('change', (e) => {\r\n      this.currentLanguage = e.target.value;\r\n      localStorage.setItem('emojiPanelLanguage', this.currentLanguage);\r\n      const currentEmoji = this.infoIcon.textContent;\r\n      if (currentEmoji) {\r\n        this.updateInfoPanel(currentEmoji);\r\n      }\r\n      this.updateCategoryLabels();\r\n      if (this.searchInput.value.trim()) {\r\n        this.searchEmojis(this.searchInput.value.trim().toLowerCase());\r\n      }\r\n    });\r\n\r\n    // Prevent closing when clicking inside panel\r\n    this.container.addEventListener('click', (e) => {\r\n      e.stopPropagation();\r\n    });\r\n  }\r\n\r\n  /** Handle scroll events for infinite scrolling and category highlighting */\r\n  handleScroll() {\r\n    Object.keys(this.categorySections).forEach(category => {\r\n      const { section } = this.categorySections[category];\r\n      const sectionRect = section.getBoundingClientRect();\r\n      const containerRect = this.emojiContainer.getBoundingClientRect();\r\n      if (sectionRect.bottom < containerRect.bottom + 100) {\r\n        this.loadMoreEmojisForCategory(category);\r\n      }\r\n    });\r\n    let activeCategory = null;\r\n    let minDistance = Infinity;\r\n    Object.keys(this.categorySections).forEach(category => {\r\n      const headerRect = this.categorySections[category].header.getBoundingClientRect();\r\n      const containerRect = this.emojiContainer.getBoundingClientRect();\r\n      const distance = Math.abs(headerRect.top - containerRect.top);\r\n      if (headerRect.top <= containerRect.top + 10 && distance < minDistance) {\r\n        minDistance = distance;\r\n        activeCategory = category;\r\n      }\r\n    });\r\n    if (activeCategory) {\r\n      this.highlightCategory(activeCategory);\r\n    }\r\n  }\r\n\r\n  /** Update category labels based on current language */\r\n  updateCategoryLabels() {\r\n    Object.keys(this.categories).forEach(category => {\r\n      const localizedName = this.getLocalizedCategoryName(category);\r\n      const btn = this.categoryNav.querySelector(`[data-category=\"${category}\"]`);\r\n      if (btn) (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(btn, localizedName);\r\n      if (this.categorySections[category] && this.categorySections[category].header) {\r\n        this.categorySections[category].header.textContent = localizedName;\r\n      }\r\n    });\r\n  }\r\n\r\n  /** Update the info panel with emoji and keywords */\r\n  updateInfoPanel(emoji) {\r\n    // Check if the info panel elements exist before trying to update them\r\n    if (!this.infoIcon || !this.infoKeywords) return;\r\n\r\n    this.infoIcon.textContent = emoji;\r\n    const keywordsObj = this.emojiKeywords[emoji] || {};\r\n    const keywords = keywordsObj[this.currentLanguage] || [];\r\n    this.infoKeywords.textContent = keywords.join(', ');\r\n  }\r\n\r\n  /** Clear the info panel */\r\n  clearInfoPanel() {\r\n    // Check if the info panel elements exist before trying to clear them\r\n    if (!this.infoIcon || !this.infoKeywords) return;\r\n\r\n    this.infoIcon.textContent = '';\r\n    this.infoKeywords.textContent = '';\r\n  }\r\n\r\n  /** Add an emoji to the recent list and refresh the recent section */\r\n  addToRecent(emoji) {\r\n    this.recentEmojis = [\r\n      emoji,\r\n      ...this.recentEmojis.filter(e => e !== emoji)\r\n    ].slice(0, 25);\r\n    this.saveRecentEmojis();\r\n    if (this.categorySections['recent']) {\r\n      const recentList = this.categorySections['recent'].emojiList;\r\n      recentList.innerHTML = '';\r\n      this.loadedIndices['recent'] = 0;\r\n      this.loadMoreEmojisForCategory('recent');\r\n    }\r\n  }\r\n\r\n  /** Remove an emoji from the recent list and refresh the recent section */\r\n  removeFromRecent(emoji) {\r\n    this.recentEmojis = this.recentEmojis.filter(e => e !== emoji);\r\n    this.saveRecentEmojis();\r\n    if (this.categorySections['recent']) {\r\n      const recentList = this.categorySections['recent'].emojiList;\r\n      recentList.innerHTML = '';\r\n      this.loadedIndices['recent'] = 0;\r\n      this.loadMoreEmojisForCategory('recent');\r\n    }\r\n  }\r\n\r\n  /** Load recent emojis from localStorage */\r\n  loadRecentEmojis() {\r\n    try {\r\n      return JSON.parse(localStorage.getItem('recentEmojis')) || [];\r\n    } catch {\r\n      return [];\r\n    }\r\n  }\r\n\r\n  /** Save recent emojis to localStorage */\r\n  saveRecentEmojis() {\r\n    try {\r\n      localStorage.setItem('recentEmojis', JSON.stringify(this.recentEmojis));\r\n    } catch (e) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n        en: 'Failed to save recent emojis:',\r\n        ru: 'Не удалось сохранить последние эмодзи:'\r\n      }, e.message);\r\n    }\r\n  }\r\n\r\n  /** Highlight the active category in the navigation */\r\n  highlightCategory(categoryId) {\r\n    const buttons = this.categoryNav.querySelectorAll('.emoji-category-btn');\r\n    buttons.forEach(btn => {\r\n      btn.classList.toggle('active', btn.dataset.category === categoryId);\r\n    });\r\n  }\r\n\r\n  /** Show the emoji panel */\r\n  show() {\r\n    this.createPanel();\r\n    this.bindEvents();\r\n    this.loadAllEmojis();\r\n  }\r\n\r\n  /** Completely remove the emoji panel from DOM and clean up */\r\n  destroy() {\r\n    document.removeEventListener('keydown', this._emojiKeydownHandler);\r\n    document.removeEventListener('keydown', this._qKeydownHandler);\r\n    document.removeEventListener('click', this._documentClickHandler);\r\n    if (this.container) {\r\n      // Fade out the panel; the helper will remove it after transition.\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.container, 'hide', '0');\r\n    }\r\n    this.container = null;\r\n    this.searchInput = null;\r\n    this.emojiContainer = null;\r\n    this.categoryNav = null;\r\n    this.infoPanel = null;\r\n    this.infoIcon = null;\r\n    this.infoKeywords = null;\r\n    this.languageSelect = null;\r\n    EmojiPanel.instance = null;\r\n    if (this.options.emojiButton) {\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(this.options.emojiButton, {\r\n        en: '[Ctrl + ;] Open emoji picker',\r\n        ru: '[Ctrl + ;] Открыть панель эмодзи'\r\n      });\r\n    }\r\n    if (typeof this.options.onDestroy === 'function') {\r\n      this.options.onDestroy();\r\n    }\r\n  }\r\n\r\n  /** Toggle the visibility of the emoji panel */\r\n  toggle() {\r\n    if (document.querySelector('.emoji-panel')) {\r\n      this.destroy();\r\n    } else {\r\n      this.show();\r\n    }\r\n  }\r\n\r\n  /** Get the localized name for a category */\r\n  getLocalizedCategoryName(categoryKey) {\r\n    return this.categoryLabels[this.currentLanguage][categoryKey] || categoryKey;\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/emojiPanel.js?");

/***/ }),

/***/ "./src/components/eventsPanel.js":
/*!***************************************!*\
  !*** ./src/components/eventsPanel.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   EventsPanel: () => (/* binding */ EventsPanel),\n/* harmony export */   createEventsPanel: () => (/* binding */ createEventsPanel),\n/* harmony export */   getSavedEvents: () => (/* binding */ getSavedEvents),\n/* harmony export */   saveEvent: () => (/* binding */ saveEvent),\n/* harmony export */   updateEventsButtonState: () => (/* binding */ updateEventsButtonState)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_animations_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/animations.js */ \"./src/data/animations.js\");\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\nconst EVENTS_STORAGE_KEY = 'chatEvents';\r\nconst LAST_VIEWED_KEY = 'lastViewedEventTime';\r\n\r\n// Events cache refresh system (like avatar refresh)\r\nfunction loadEventsCache() {\r\n  try {\r\n    const cacheData = localStorage.getItem(EVENTS_STORAGE_KEY);\r\n    if (cacheData) {\r\n      const cache = JSON.parse(cacheData);\r\n      if (cache.date === new Date().toDateString()) {\r\n        return cache.events || [];\r\n      } else {\r\n        // Set localSorage to empty array if the date doesn't match\r\n        localStorage.setItem(EVENTS_STORAGE_KEY, JSON.stringify({\r\n          date: new Date().toDateString(),\r\n          events: []\r\n        }));\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n          en: \"Events cache expired, creating fresh cache.\",\r\n          ru: \"Кэш событий устарел, создается новый.\"\r\n        }, 'info');\r\n      }\r\n    }\r\n  } catch (error) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n      en: \"Error loading events cache, creating fresh cache.\",\r\n      ru: \"Ошибка загрузки кэша событий, создается новый.\"\r\n    }, 'error');\r\n  }\r\n  return [];\r\n}\r\n\r\nfunction saveEventsCache(events) {\r\n  try {\r\n    localStorage.setItem(EVENTS_STORAGE_KEY, JSON.stringify({\r\n      date: new Date().toDateString(),\r\n      events: events\r\n    }));\r\n  } catch (error) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n      en: \"Error saving events cache.\",\r\n      ru: \"Ошибка сохранения кэша событий.\"\r\n    }, 'error');\r\n  }\r\n}\r\n\r\n// Retrieve events from localStorage for the current day\r\nfunction getSavedEvents() {\r\n  return loadEventsCache();\r\n}\r\n\r\n// Handle events notification state - always call this to keep button updated\r\nfunction updateEventsButtonState() {\r\n  const eventsButton = document.querySelector('.chat-events-button');\r\n  if (eventsButton) {\r\n    const events = getSavedEvents();\r\n    const lastViewed = localStorage.getItem(LAST_VIEWED_KEY) || '0';\r\n    const hasNewEvents = events.some(event =>\r\n      new Date(event.date).getTime() > parseInt(lastViewed)\r\n    );\r\n\r\n    // Update highlight based on new events\r\n    eventsButton.classList.toggle('new-events', hasNewEvents);\r\n\r\n    // Add no-events class if there are no events\r\n    eventsButton.classList.toggle('no-events', !events || events.length === 0);\r\n  }\r\n}\r\n\r\n// Save an event to localStorage\r\nfunction saveEvent(event) {\r\n  const events = loadEventsCache();\r\n  events.push({ ...event, date: new Date().toISOString() });\r\n  saveEventsCache(events);\r\n  updateEventsButtonState();\r\n}\r\n\r\n// Format timestamp\r\nfunction formatTimestamp(dateString) {\r\n  const date = new Date(dateString);\r\n  return date.toLocaleTimeString('en-US', {\r\n    hour12: false,\r\n    hour: '2-digit',\r\n    minute: '2-digit',\r\n    second: '2-digit'\r\n  });\r\n}\r\n\r\nclass EventsPanel {\r\n  static instance = null;\r\n\r\n  constructor() {\r\n    if (EventsPanel.instance) {\r\n      // If there's an existing instance but it's not in the DOM, recreate it\r\n      if (!EventsPanel.instance.panel.parentNode) {\r\n        EventsPanel.instance = null;\r\n      } else {\r\n        return EventsPanel.instance;\r\n      }\r\n    }\r\n\r\n    EventsPanel.instance = this;\r\n\r\n    this.panel = document.createElement('div');\r\n    this.panel.className = 'events-panel';\r\n\r\n    this.eventsList = document.createElement('div');\r\n    this.eventsList.className = 'events-list';\r\n\r\n    this.init();\r\n    this.show();\r\n  }\r\n\r\n  init() {\r\n    const header = document.createElement('h2');\r\n    header.textContent = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.uiStrings.eventsHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage];\r\n    this.panel.appendChild(header);\r\n    this.panel.appendChild(this.eventsList);\r\n\r\n    // Create clear button\r\n    const clearButton = document.createElement('button');\r\n    clearButton.className = 'clear-btn';\r\n    clearButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.clearSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__.createCustomTooltip)(clearButton, {\r\n      en: 'Clear all events',\r\n      ru: 'Очистить все события'\r\n    });\r\n    clearButton.addEventListener('click', () => {\r\n      const events = getSavedEvents();\r\n      if (events.length === 0) return; // Do nothing if no events exist\r\n\r\n      localStorage.removeItem(EVENTS_STORAGE_KEY);\r\n      updateEventsButtonState();\r\n      this.hide(); // Close the panel\r\n    });\r\n    this.panel.appendChild(clearButton);\r\n\r\n    // Create close button\r\n    const closeButton = document.createElement('button');\r\n    closeButton.className = 'close-btn';\r\n    closeButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.removeSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__.createCustomTooltip)(closeButton, {\r\n      en: 'Close panel',\r\n      ru: 'Закрыть панель'\r\n    });\r\n    closeButton.addEventListener('click', () => {\r\n      this.hide();\r\n    });\r\n    this.panel.appendChild(closeButton);\r\n\r\n    // Load saved events for the current day\r\n    const events = getSavedEvents();\r\n    const lastViewed = localStorage.getItem(LAST_VIEWED_KEY) || '0';\r\n\r\n    if (events && events.length > 0) {\r\n      events.forEach(event => {\r\n        const isNew = new Date(event.date).getTime() > parseInt(lastViewed);\r\n        this.renderEvent(event, isNew);\r\n      });\r\n    }\r\n\r\n    // Scroll to bottom after rendering events\r\n    this.scrollToBottom();\r\n\r\n    // Setup event handlers\r\n    this.setupEventListeners();\r\n  }\r\n\r\n  renderEvent(event, isNew = false) {\r\n    const listItem = document.createElement('div');\r\n    listItem.className = `list-item ${isNew ? 'new-event' : 'old-event'}`;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__.createCustomTooltip)(listItem, {\r\n      en: 'Click to copy message',\r\n      ru: 'Нажмите, чтобы скопировать сообщение'\r\n    });\r\n\r\n    const iconWrapper = document.createElement('span');\r\n    iconWrapper.className = \"event-icon icon-wrapper\";\r\n    let iconSVG;\r\n    switch (event.type) {\r\n      case 'warning':\r\n        iconSVG = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.warningSVG;\r\n        break;\r\n      case 'error':\r\n        iconSVG = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.errorSVG;\r\n        break;\r\n      case 'success':\r\n        iconSVG = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.successSVG;\r\n        break;\r\n      case 'info':\r\n      default:\r\n        iconSVG = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.infoSVG;\r\n        break;\r\n    }\r\n\r\n    // Apply stroke color from eventsColorMap\r\n    const typeColor = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap[event.type] || _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap.info;\r\n    iconWrapper.innerHTML = iconSVG.replace('stroke=\"currentColor\"', `stroke=\"${typeColor}\"`);\r\n\r\n    const timestamp = document.createElement('span');\r\n    timestamp.className = 'timestamp';\r\n    timestamp.textContent = formatTimestamp(event.date);\r\n    timestamp.style.color = typeColor;\r\n\r\n    const message = document.createElement('span');\r\n    message.className = 'message';\r\n    message.textContent = event.message;\r\n\r\n    listItem.style.backgroundColor = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap[event.type] || _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap.info;\r\n    listItem.append(iconWrapper, timestamp, message);\r\n    this.eventsList.appendChild(listItem);\r\n  }\r\n\r\n  setupEventListeners() {\r\n    // Handle ESC key\r\n    this.handleEscape = (event) => {\r\n      if (event.key === 'Escape') {\r\n        this.hide();\r\n      }\r\n    };\r\n\r\n    // Handle click outside\r\n    this.handleClickOutside = (event) => {\r\n      if (!this.panel.contains(event.target)) {\r\n        this.hide();\r\n      }\r\n    };\r\n\r\n    // Delegate click events on list-item elements\r\n    this.eventsList.addEventListener('click', (event) => {\r\n      const listItem = event.target.closest('.list-item');\r\n      if (listItem) {\r\n        const messageElement = listItem.querySelector('.message');\r\n        if (messageElement) {\r\n          navigator.clipboard.writeText(messageElement.textContent).then(() => {\r\n            (0,_data_animations_js__WEBPACK_IMPORTED_MODULE_2__.addShakeEffect)(listItem);\r\n          }).catch((error) => {\r\n            (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n              en: `Failed to copy event message: ${error.message}`,\r\n              ru: `Не удалось скопировать сообщение события: ${error.message}`\r\n            }, 'error');\r\n          });\r\n        }\r\n      }\r\n    });\r\n\r\n    document.addEventListener('keydown', this.handleEscape);\r\n    document.addEventListener('click', this.handleClickOutside, true);\r\n  }\r\n\r\n  // Helper method to scroll to bottom\r\n  scrollToBottom() {\r\n    requestAnimationFrame(() => {\r\n      this.eventsList.scrollTop = this.eventsList.scrollHeight;\r\n    });\r\n  }\r\n\r\n  show() {\r\n    const events = getSavedEvents();\r\n    if (!events || events.length === 0) return; // Do nothing if no events exist\r\n\r\n    document.body.appendChild(this.panel);\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.panel, 'show', 1);\r\n\r\n    localStorage.setItem(LAST_VIEWED_KEY, new Date().getTime().toString());\r\n    updateEventsButtonState();\r\n    this.scrollToBottom();\r\n  }\r\n\r\n  hide() {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.panel, 'hide', 0);\r\n    document.removeEventListener('keydown', this.handleEscape);\r\n    document.removeEventListener('click', this.handleClickOutside, true);\r\n\r\n    setTimeout(() => {\r\n      if (this.panel.parentNode) {\r\n        this.panel.parentNode.removeChild(this.panel);\r\n      }\r\n    }, 300);\r\n  }\r\n\r\n  addEvent(message, type = 'info') {\r\n    const newEvent = { message, type, date: new Date().toISOString() };\r\n    this.renderEvent(newEvent, true);\r\n    saveEvent(newEvent);\r\n    this.scrollToBottom();\r\n  }\r\n}\r\n\r\nfunction createEventsPanel() {\r\n  return new EventsPanel();\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/eventsPanel.js?");

/***/ }),

/***/ "./src/components/helpPanel.js":
/*!*************************************!*\
  !*** ./src/components/helpPanel.js ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   HelpPanel: () => (/* binding */ HelpPanel)\n/* harmony export */ });\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\nclass HelpPanel {\r\n  constructor(options = {}) {\r\n    this.container = null;\r\n    this.options = {\r\n      container: options.container || document.body,\r\n      helpButton: options.helpButton,\r\n      onDestroy: options.onDestroy\r\n    };\r\n    // Set the class instance to this\r\n    HelpPanel.instance = this;\r\n  }\r\n\r\n  init() {\r\n    this.createPanel();\r\n    this.bindEvents();\r\n    return this;\r\n  }\r\n\r\n  createPanel() {\r\n    this.container = document.createElement('div');\r\n    this.container.className = 'help-panel';\r\n    this.content = document.createElement('div');\r\n    this.content.className = 'help-content';\r\n    this.updatePanelContent();\r\n    this.container.appendChild(this.content);\r\n\r\n    // Create close button\r\n    const closeButton = document.createElement('button');\r\n    closeButton.className = 'close-btn';\r\n    closeButton.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_0__.removeSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(closeButton, {\r\n      en: 'Close panel',\r\n      ru: 'Закрыть панель'\r\n    });\r\n    closeButton.addEventListener('click', () => {\r\n      this.remove();\r\n    });\r\n    this.container.appendChild(closeButton);\r\n\r\n    document.body.appendChild(this.container);\r\n    // Fade in the panel\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.container, 'show', '1');\r\n  }\r\n\r\n  updatePanelContent() {\r\n    const lang = localStorage.getItem('emojiPanelLanguage') || 'en';\r\n    const helpTranslations = {\r\n      en: {\r\n        heading: \"Chat Commands & Hotkeys\",\r\n        sections: [\r\n          {\r\n            title: \"Chat Commands\",\r\n            items: [\r\n              { key: \"/help\", desc: \"Show this help panel\" },\r\n              { key: \"/me message\", desc: \"Send an action message\" },\r\n              { key: \"/pm username\", desc: \"Activate private chat mode with the specified user\" },\r\n              { key: \"/exit\", desc: \"Exit private chat mode\" },\r\n              { key: \"/reset\", desc: \"Reset the chat data\" },\r\n              { key: \"/colors\", desc: \"Show the username color panel\" },\r\n              { key: \"/import colors\", desc: \"Import user colors from a json file\" },\r\n              { key: \"/export colors\", desc: \"Export user colors to a json file\" },\r\n              { key: \"/ignored\", desc: \"Show the ignored users panel\" },\r\n              { key: \"/themes\", desc: \"Show the themes panel\" },\r\n              { key: \"/events\", desc: \"Show the events panel\" },\r\n              { key: \"/list normal\", desc: \"User list: Normal mode (sorted by role, not by race count)\" },\r\n              { key: \"/list race\", desc: \"User list: Users in a race at the top (sorted by race count)\" },\r\n              { key: \"/list chat\", desc: \"User list: General chat users at the top, others (sorted by race count)\" }\r\n            ]\r\n          },\r\n          {\r\n            title: \"Chat Hotkeys\",\r\n            items: [\r\n              { key: \"Ctrl + Space\", desc: \"Hide/Show the chat\" },\r\n              { key: \"Shift + Ctrl + Space\", desc: \"Expand/Collapse the chat\" },\r\n              { key: \"Ctrl + Click\", desc: \"Activate private chat mode with the clicked user\" },\r\n              { key: \"Hold (LMB)\", desc: \"Activate private chat mode with the clicked user (Userlist)\" },\r\n              { key: \"Double Click (LMB)\", desc: \"Replace selected users with one in the input field (Messages)\" },\r\n              { key: \"Shift + Click\", desc: \"Open the user profile by nickname in the message\" },\r\n              { key: \"List + Double Click (LMB)\", desc: \"Toggle between user list modes (Normal/Race/Chat)\" }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Emoji Panel Actions & Hotkeys\",\r\n            subSections: [\r\n              {\r\n                title: \"Emoji Panel Actions\",\r\n                items: [\r\n                  { key: \"Click an emoji\", desc: \"Insert the emoji\" },\r\n                  { key: \"Click outside panel\", desc: \"Closes the panel (emoji or help)\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Emoji Panel Hotkeys\",\r\n                items: [\r\n                  { key: \"Ctrl + ;\", desc: \"Open the Emoji Panel\" },\r\n                  { key: \"Enter\", desc: \"Insert the emoji\" },\r\n                  { key: \"Ctrl + Enter\", desc: \"Insert the emoji keeping the panel open\" },\r\n                  { key: \"Ctrl + Click\", desc: \"Insert the emoji keeping the panel open\" },\r\n                  { key: \"Shift + Click\", desc: \"Remove emoji from recent list (in recent category)\" },\r\n                  { key: \"q\", desc: \"Hide the Emoji Panel (single press when search is not focused)\" },\r\n                  { key: \"qq\", desc: \"Hide the Emoji Panel (double press 'q' when search is focused)\" },\r\n                  { key: \"Esc\", desc: \"Close the panel (emoji or help)\" }\r\n                ]\r\n              }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Image Manipulations\",\r\n            subSections: [\r\n              {\r\n                title: \"Open/Close\",\r\n                items: [\r\n                  { key: \"(LMB) Click\", desc: \"Open the image\" },\r\n                  { key: \"Ctrl + (RMB)\", desc: \"Close the image and copy the link\" },\r\n                  { key: \"Space or ESC\", desc: \"Close the image\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Movement and Scaling\",\r\n                items: [\r\n                  { key: \"Hold (MMB)\", desc: \"Drag the expanded image\" },\r\n                  { key: \"Scroll (MMB)\", desc: \"Zoom in/out the image\" },\r\n                  { key: \"Ctrl + (MMB)\", desc: \"Scale the image. Move the cursor up or down.\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Navigation\",\r\n                items: [\r\n                  { key: \"Arrow keys (< >)\", desc: \"Switch between images\" },\r\n                  { key: \"(LMB), (RMB)\", desc: \"Switch between images\" }\r\n                ]\r\n              }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Markdown Formatting\",\r\n            items: [\r\n              { key: \"# Heading\", desc: \"Headings: use # for h1, ## for h2, up to ###### for h6\" },\r\n              { key: \"`code`\", desc: \"Inline code\" },\r\n              { key: \"**text**\", desc: \"Bold text\" },\r\n              { key: \"__text__\", desc: \"Italic text\" },\r\n              { key: \"~~text~~\", desc: \"Strikethrough text\" }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Delete / Show / Restore Messages\",\r\n            subSections: [\r\n              {\r\n                title: \"Deletion\",\r\n                items: [\r\n                  { key: \"(RMB) + Message\", desc: \"Delete message\" },\r\n                  { key: \"(RMB) + Nickname\", desc: \"Delete user's messages\" },\r\n                  { key: \"(RMB) + Time\", desc: \"Delete his messages from the selected time\" },\r\n                  { key: \"Ctrl + (RMB) + Time\", desc: \"Delete all messages from the selected time\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Show / Restore\",\r\n                items: [\r\n                  { key: \"(LMB) + Toggle\", desc: \"Show/Hide messages\" },\r\n                  { key: \"Ctrl + (LMB) + Toggle\", desc: \"Restore hidden messages\" }\r\n                ]\r\n              }\r\n            ]\r\n          }\r\n\r\n        ]\r\n      },\r\n\r\n      ru: {\r\n        heading: \"Команды чата и горячие клавиши\",\r\n        sections: [\r\n          {\r\n            title: \"Команды чата\",\r\n            items: [\r\n              { key: \"/help\", desc: \"Показать панель помощи\" },\r\n              { key: \"/me сообщение\", desc: \"Отправить сообщение действия\" },\r\n              { key: \"/pm username\", desc: \"Активировать приватный чат для указанного пользователя\" },\r\n              { key: \"/exit\", desc: \"Выйти из приватного чата\" },\r\n              { key: \"/reset\", desc: \"Сбросить данные чата\" },\r\n              { key: \"/colors\", desc: \"Показать панель цветов имен пользователей\" },\r\n              { key: \"/import colors\", desc: \"Импортировать цвета пользователей из json файла\" },\r\n              { key: \"/export colors\", desc: \"Экспортировать цвета пользователей в json файл\" },\r\n              { key: \"/ignored\", desc: \"Показать панель игнорируемых пользователей\" },\r\n              { key: \"/themes\", desc: \"Показать панель тем\" },\r\n              { key: \"/events\", desc: \"Показать панель событий\" },\r\n              { key: \"/list normal\", desc: \"Список пользователей: Обычный режим (сортировка по роли, без сортировки по колличеству заездов)\" },\r\n              { key: \"/list race\", desc: \"Список пользователей: Пользователи в игре сверху (сортировка по колличеству заездов)\" },\r\n              { key: \"/list chat\", desc: \"Список пользователей: Пользователи общего чата сверху, остальные (сортированные по колличеству заездов)\" }\r\n            ]\r\n          },\r\n          {\r\n            title: \"Горячие клавиши чата\",\r\n            items: [\r\n              { key: \"Ctrl + Space\", desc: \"Скрыть/Показать чат\" },\r\n              { key: \"Shift + Ctrl + Space\", desc: \"Развернуть/Свернуть чат\" },\r\n              { key: \"Ctrl + Click\", desc: \"Активировать приватный чат для выбранного пользователя\" },\r\n              { key: \"Удерживание (ЛКМ)\", desc: \"Активировать приватный чат для выбранного пользователя (Пользователи)\" },\r\n              { key: \"Двойной клик (ЛКМ)\", desc: \"Замена выбранных пользователей одним в поле ввода (Сообщения)\" },\r\n              { key: \"Shift + Click\", desc: \"Открыть профиль пользователя по никнейму в сообщении\" },\r\n              { key: \"List + Двойной клик (ЛКМ)\", desc: \"Переключение между режимами списка пользователей (Обычный/Заезд/Чат)\" }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Действия и горячие клавиши панели эмодзи\",\r\n            subSections: [\r\n              {\r\n                title: \"Действия панели эмодзи\",\r\n                items: [\r\n                  { key: \"Click an emoji\", desc: \"Вставить эмодзи\" },\r\n                  { key: \"Click outside panel\", desc: \"Закрыть панель (эмодзи или помощь)\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Горячие клавиши панели эмодзи\",\r\n                items: [\r\n                  { key: \"Ctrl + ;\", desc: \"Открыть панель эмодзи\" },\r\n                  { key: \"Enter\", desc: \"Вставить эмодзи\" },\r\n                  { key: \"Ctrl + Enter\", desc: \"Вставить эмодзи, оставив панель открытой\" },\r\n                  { key: \"Ctrl + Click\", desc: \"Вставить эмодзи, оставив панель открытой\" },\r\n                  { key: \"Shift + Click\", desc: \"Удалить эмодзи из списка \\\"Недавно использованные\\\"\" },\r\n                  { key: \"q\", desc: \"Скрыть панель эмодзи (одиночный нажим, когда поиск не в фокусе)\" },\r\n                  { key: \"qq\", desc: \"Скрыть панель эмодзи (дважды нажмите 'q', когда поиск в фокусе)\" },\r\n                  { key: \"Esc\", desc: \"Закрыть (эмодзи или помощь)\" }\r\n                ]\r\n              }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Манипуляции с изображением\",\r\n            subSections: [\r\n              {\r\n                title: \"Открытие/Закрытие\",\r\n                items: [\r\n                  { key: \"(ЛКМ) Клик\", desc: \"Открыть изображение\" },\r\n                  { key: \"Ctrl + (ПКМ)\", desc: \"Закрыть изображение и скопировать ссылку\" },\r\n                  { key: \"Space или ESC\", desc: \"Закрыть изображение\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Перемещение и масштабирование\",\r\n                items: [\r\n                  { key: \"Зажатая (СКМ)\", desc: \"Перемещайте развернутое изображение\" },\r\n                  { key: \"Прокрутка (СКМ)\", desc: \"Увеличивайте/уменьшайте изображение\" },\r\n                  { key: \"Ctrl + (СКМ)\", desc: \"Масштабируйте изображение. Курсор вверх или вниз.\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Навигация\",\r\n                items: [\r\n                  { key: \"Стрелки (< >)\", desc: \"Переключение между изображениями\" },\r\n                  { key: \"(ЛКМ), (ПКМ)\", desc: \"Переключение между изображениями\" }\r\n                ]\r\n              }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Форматирование Markdown\",\r\n            items: [\r\n              { key: \"# Заголовок\", desc: \"Заголовки: используйте # для h1, ## для h2, до ###### для h6\" },\r\n              { key: \"`код`\", desc: \"Встроенный код\" },\r\n              { key: \"**текст**\", desc: \"Жирный текст\" },\r\n              { key: \"__текст__\", desc: \"Курсивный текст\" },\r\n              { key: \"~~текст~~\", desc: \"Зачёркнутый текст\" }\r\n            ]\r\n          },\r\n\r\n          {\r\n            heading: \"Удаление / Показ / Восстановление сообщений\",\r\n            subSections: [\r\n              {\r\n                title: \"Удаление\",\r\n                items: [\r\n                  { key: \"(ПКМ) + Сообщение\", desc: \"Удалить сообщение\" },\r\n                  { key: \"(ПКМ) + Никнейм\", desc: \"Удалить сообщения пользователя\" },\r\n                  { key: \"(ПКМ) + Время\", desc: \"Удалить его сообщения с выбранного времени\" },\r\n                  { key: \"Ctrl + (ПКМ) + Время\", desc: \"Удалить все сообщения с выбранного времени\" }\r\n                ]\r\n              },\r\n              {\r\n                title: \"Показ / Восстановление\",\r\n                items: [\r\n                  { key: \"(ЛКМ) + Toggle\", desc: \"Показать/Скрыть сообщения\" },\r\n                  { key: \"Ctrl + (ЛКМ) + Toggle\", desc: \"Восстановить скрытые сообщения\" },\r\n                ]\r\n              }\r\n            ]\r\n          }\r\n\r\n        ]\r\n      }\r\n    };\r\n    const t = helpTranslations[lang];\r\n    let html = `<h5 class=\"help-section-header\">${t.heading}</h5>`;\r\n    t.sections.forEach(section => {\r\n      if (section.title) {\r\n        html += `<h6 class=\"help-section-subheader\">${section.title}</h6>`;\r\n      } else if (section.heading) {\r\n        html += `<h5 class=\"help-section-header\">${section.heading}</h5>`;\r\n      }\r\n      if (section.items) {\r\n        html += `<ul class=\"help-list\">`;\r\n        section.items.forEach(item => {\r\n          html += `<li class=\"help-list-item\"><strong class=\"help-hotkey\">${item.key}</strong> ${item.desc}</li>`;\r\n        });\r\n        html += `</ul>`;\r\n      }\r\n      if (section.subSections) {\r\n        section.subSections.forEach(sub => {\r\n          html += `<h6 class=\"help-section-subheader\">${sub.title}</h6>`;\r\n          html += `<ul class=\"help-list\">`;\r\n          sub.items.forEach(item => {\r\n            html += `<li class=\"help-list-item\"><strong class=\"help-hotkey\">${item.key}</strong> ${item.desc}</li>`;\r\n          });\r\n          html += `</ul>`;\r\n        });\r\n      }\r\n    });\r\n    this.content.innerHTML = html;\r\n  }\r\n\r\n  bindEvents() {\r\n    this._clickOutsideHandler = (e) => {\r\n      if (this.options.helpButton &&\r\n        (e.target === this.options.helpButton || this.options.helpButton.contains(e.target))) {\r\n        return;\r\n      }\r\n      if (this.container && !this.container.contains(e.target)) {\r\n        this.remove();\r\n      }\r\n    };\r\n    document.addEventListener('click', this._clickOutsideHandler, true);\r\n\r\n    this._escHandler = (e) => {\r\n      if (e.key === 'Escape') {\r\n        this.remove();\r\n      }\r\n    };\r\n    document.addEventListener('keydown', this._escHandler, true);\r\n\r\n    this._stopPropagationHandler = (e) => {\r\n      e.stopPropagation();\r\n    };\r\n    this.container.addEventListener('click', this._stopPropagationHandler);\r\n  }\r\n\r\n  remove() {\r\n    if (this._clickOutsideHandler) {\r\n      document.removeEventListener('click', this._clickOutsideHandler, true);\r\n      this._clickOutsideHandler = null;\r\n    }\r\n    if (this._escHandler) {\r\n      document.removeEventListener('keydown', this._escHandler, true);\r\n      this._escHandler = null;\r\n    }\r\n    if (this.container) {\r\n      this.container.removeEventListener('click', this._stopPropagationHandler);\r\n      this._stopPropagationHandler = null;\r\n    }\r\n    if (this.container) {\r\n      // Fade out the panel; the helper will remove the element after transition.\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.container, 'hide', '0');\r\n      this.container = null;\r\n    }\r\n    if (typeof this.options.onDestroy === 'function') {\r\n      this.options.onDestroy();\r\n    }\r\n    HelpPanel.instance = null;\r\n  }\r\n\r\n  show() {\r\n    if (!this.container) {\r\n      this.init();\r\n    } else {\r\n      this.updatePanelContent();\r\n    }\r\n    if (!document.body.contains(this.container)) {\r\n      document.body.appendChild(this.container);\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.adjustVisibility)(this.container, 'show', '1');\r\n    }\r\n  }\r\n\r\n  toggle() {\r\n    if (this.container && document.body.contains(this.container)) {\r\n      this.remove();\r\n    } else {\r\n      this.show();\r\n    }\r\n  }\r\n}\r\n\r\n// Static instance tracker\r\nHelpPanel.instance = null;\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/helpPanel.js?");

/***/ }),

/***/ "./src/components/ignoredUsersPanel.js":
/*!*********************************************!*\
  !*** ./src/components/ignoredUsersPanel.js ***!
  \*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   getAllIgnoredUsers: () => (/* binding */ getAllIgnoredUsers),\n/* harmony export */   openIgnoredUsersPanel: () => (/* binding */ openIgnoredUsersPanel),\n/* harmony export */   storageWrapper: () => (/* binding */ storageWrapper)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n/* harmony import */ var _data_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../data/icons.js */ \"./src/data/icons.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n// Storage keys for ignored users\r\nconst IGNORED_USERS_KEY = 'ignored';\r\nconst TEMP_IGNORED_USERS_KEY = 'tempIgnored';\r\n\r\n// Centralized storage wrapper for ignored users.\r\nconst storageWrapper = {\r\n  get: (key, fallback) => {\r\n    try {\r\n      const stored = localStorage.getItem(key);\r\n      return stored ? JSON.parse(stored) : fallback;\r\n    } catch (e) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Error parsing ignored users data: ${e.message}`,\r\n        ru: `Ошибка разбора данных игнорируемых пользователей: ${e.message}`\r\n      }, 'error');\r\n      return fallback;\r\n    }\r\n  },\r\n  set: (key, data) => {\r\n    try {\r\n      localStorage.setItem(key, JSON.stringify(data));\r\n      return true;\r\n    } catch (e) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Error saving ignored users data: ${e.message}`,\r\n        ru: `Ошибка сохранения данных игнорируемых пользователей: ${e.message}`\r\n      }, 'error');\r\n      return false;\r\n    }\r\n  }\r\n};\r\n\r\n// DOM element creation helper.\r\nconst createElement = (tag, className, attributes = {}) => {\r\n  const element = document.createElement(tag);\r\n  if (className) element.className = className;\r\n  Object.entries(attributes).forEach(([key, value]) => {\r\n    if (key === 'text') {\r\n      element.textContent = value;\r\n    } else {\r\n      element.setAttribute(key, value);\r\n    }\r\n  });\r\n  return element;\r\n};\r\n\r\n// Helper to get all ignored users (permanent and non-expired temporary)\r\nfunction getAllIgnoredUsers() {\r\n  const forever = storageWrapper.get(IGNORED_USERS_KEY, []);\r\n  const temp = storageWrapper.get(TEMP_IGNORED_USERS_KEY, {});\r\n  const now = Date.now();\r\n  const temporary = Object.entries(temp)\r\n    .filter(([_, expiry]) => expiry > now)\r\n    .map(([username]) => username);\r\n  return { forever, temporary };\r\n}\r\n\r\n// The main exported function.\r\nconst openIgnoredUsersPanel = () => {\r\n  // Prevent duplicate container creation.\r\n  const existingContainer = document.querySelector('.ignored-users-panel');\r\n  if (existingContainer) {\r\n    return existingContainer;\r\n  }\r\n\r\n  // Use the helper to get both lists\r\n  const { forever, temporary } = getAllIgnoredUsers();\r\n\r\n  // Retrieve tempIgnored ONCE for this panel render\r\n  const tempIgnoredMap = storageWrapper.get(TEMP_IGNORED_USERS_KEY, {});\r\n\r\n  // Create container and ignored-users container.\r\n  const container = createElement('div', 'ignored-users-panel');\r\n  const userList = createElement('div', 'ignored-users-list');\r\n  container.appendChild(userList);\r\n\r\n  // Create h2 (main header) and append to userList.\r\n  const header = createElement('h2', null, { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.ignoredUsersHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage] });\r\n  userList.appendChild(header);\r\n\r\n  // Helper to create a section (forever or temporary)\r\n  function createIgnoredSection({\r\n    type,\r\n    users,\r\n    userList,\r\n    uiStrings,\r\n    defaultLanguage,\r\n    createEntry,\r\n    tempIgnoredMap // Pass tempIgnoredMap for temporary users\r\n  }) {\r\n    if (!users.length) return null;\r\n    const header = document.createElement('h3');\r\n    header.className = 'ignored-users-subheader';\r\n    header.innerHTML = `${uiStrings[type === 'forever' ? 'ignoredUsersSubheaderForever' : 'ignoredUsersSubheaderTemporary'][defaultLanguage]} <span class=\"counter\">${users.length}</span>`;\r\n    const sectionClass = type === 'forever' ? 'ignored-users-forever-section' : 'ignored-users-temporary-section';\r\n    const section = createElement('div', sectionClass);\r\n    userList.append(header, section);\r\n    users.forEach(username => {\r\n      const entry = createEntry(username, type, tempIgnoredMap);\r\n      section.appendChild(entry);\r\n    });\r\n    return section;\r\n  }\r\n\r\n  // Forever section\r\n  createIgnoredSection({\r\n    type: 'forever',\r\n    users: forever,\r\n    userList,\r\n    uiStrings: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings,\r\n    defaultLanguage: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage,\r\n    createEntry\r\n  });\r\n\r\n  // Temporary section (fetch tempIgnored map once)\r\n  createIgnoredSection({\r\n    type: 'temporary',\r\n    users: temporary,\r\n    userList,\r\n    uiStrings: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings,\r\n    defaultLanguage: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage,\r\n    createEntry,\r\n    tempIgnoredMap\r\n  });\r\n\r\n  // Add input field and button for adding new ignored users\r\n  const inputContainer = createElement('div', 'ignored-users-input-container');\r\n  const inputField = createElement('input', 'ignored-users-input', { type: 'search', placeholder: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.ignoredUsersPlaceholder[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage] });\r\n  const addButton = createElement('button', 'ignored-users-add-btn', { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings.ignoredBlockButton[_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage] });\r\n  (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(addButton, {\r\n    en: 'Add to ignored',\r\n    ru: 'Добавить в игнорируемые'\r\n  });\r\n\r\n  const handleAddIgnoredUser = async () => {\r\n    const username = inputField.value.trim();\r\n    if (!username) return;\r\n\r\n    // Check if already ignored\r\n    if (forever.includes(username) || temporary.includes(username)) return;\r\n\r\n    const userId = await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.getExactUserIdByName)(username);\r\n    if (!userId) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Could not find user \"${username}\"`,\r\n        ru: `Не удалось найти пользователя \"${username}\"`\r\n      }, 'error');\r\n      inputField.value = '';\r\n      inputField.classList.add('field-error');\r\n      setTimeout(() => inputField.classList.remove('field-error'), 500);\r\n      return;\r\n    }\r\n\r\n    // Always add as permanent ban (forever)\r\n    forever.push(username);\r\n    storageWrapper.set(IGNORED_USERS_KEY, forever);\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Added \"${username}\" to the ignore list`,\r\n      ru: `\"${username}\" добавлен(а) в список игнорируемых`\r\n    }, 'info');\r\n    inputField.value = '';\r\n    if (window.messageManager && typeof window.messageManager.removeIgnoredMessages === 'function') {\r\n      window.messageManager.removeIgnoredMessages();\r\n    }\r\n\r\n    // If foreverSection doesn't exist yet, create it now\r\n    let foreverSection = document.querySelector('.ignored-users-forever-section');\r\n    if (!foreverSection) {\r\n      foreverSection = createIgnoredSection({\r\n        type: 'forever',\r\n        users: [username],\r\n        userList,\r\n        uiStrings: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.uiStrings,\r\n        defaultLanguage: _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage,\r\n        createEntry\r\n      });\r\n    } else {\r\n      foreverSection.appendChild(createEntry(username, 'forever'));\r\n    }\r\n  };\r\n\r\n  addButton.addEventListener('click', handleAddIgnoredUser);\r\n  inputField.addEventListener('keypress', (event) => {\r\n    if (event.key === 'Enter') {\r\n      handleAddIgnoredUser();\r\n    }\r\n  });\r\n\r\n  inputContainer.append(inputField, addButton);\r\n  container.insertBefore(inputContainer, userList);\r\n\r\n  // Create an entry element.\r\n  function createEntry(username, type = 'forever', tempIgnoredMap = null) {\r\n    const entry = createElement('div', 'ignored-user-entry');\r\n    const label = createElement('div', 'username', { text: username });\r\n    // Use tempIgnoredMap passed in for temporary users\r\n    if (type === 'temporary') {\r\n      label.classList.add('temporary-banned');\r\n      // Tooltip for temporary ignored users\r\n      const expiry = tempIgnoredMap ? tempIgnoredMap[username] : null;\r\n      if (expiry) {\r\n        const now = Date.now();\r\n        const msLeft = expiry - now;\r\n        // Try to infer duration (1h, 1d, etc) by checking common values\r\n        let durationMs = null;\r\n        if (msLeft > 0) {\r\n          // Try to guess duration: check if close to 1h or 1d\r\n          const diff1h = Math.abs((expiry - msLeft) - (expiry - 60 * 60 * 1000));\r\n          const diff1d = Math.abs((expiry - msLeft) - (expiry - 24 * 60 * 60 * 1000));\r\n          if (diff1h < 60000) durationMs = 60 * 60 * 1000;\r\n          else if (diff1d < 60000) durationMs = 24 * 60 * 60 * 1000;\r\n        }\r\n        // Fallback: use expiry - msLeft as addedAt\r\n        const addedAt = durationMs ? (expiry - durationMs) : (expiry - msLeft);\r\n        // Format remaining time\r\n        const totalSeconds = Math.max(0, Math.floor(msLeft / 1000));\r\n        const hours = Math.floor(totalSeconds / 3600);\r\n        const minutes = Math.floor((totalSeconds % 3600) / 60);\r\n        const seconds = totalSeconds % 60;\r\n        // Tooltip text\r\n        const addedDate = new Date(addedAt);\r\n        // Compact 24-hour format: YYYY-MM-DD HH:mm:ss\r\n        const pad = n => n.toString().padStart(2, '0');\r\n        const addedStr = `${addedDate.getFullYear()}-${pad(addedDate.getMonth() + 1)}-${pad(addedDate.getDate())} ${pad(addedDate.getHours())}:${pad(addedDate.getMinutes())}:${pad(addedDate.getSeconds())}`;\r\n        // Localized labels in brackets\r\n        const addedLabel = _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage === 'ru' ? '[Добавлен]' : '[Added]';\r\n        const timeLeftLabel = _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.defaultLanguage === 'ru' ? '[Осталось]' : '[Time left]';\r\n        const tooltipText =\r\n          `${addedLabel}: ${addedStr}\\n` +\r\n          `${timeLeftLabel}: ${hours}h ${minutes}m ${seconds}s`;\r\n        (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(label, { en: tooltipText, ru: tooltipText });\r\n      }\r\n    } else {\r\n      label.classList.add('forever-banned');\r\n    }\r\n    const removeBtn = createElement('button', 'remove-btn');\r\n    removeBtn.innerHTML = _data_icons_js__WEBPACK_IMPORTED_MODULE_3__.removeSVG;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_2__.createCustomTooltip)(removeBtn, {\r\n      en: 'Remove from ignored',\r\n      ru: 'Удалить из игнорируемых'\r\n    });\r\n\r\n    // Helper to remove entry and, if last, remove section (and header if present)\r\n    function removeSectionIfEmpty(entry) {\r\n      const section = entry.parentElement;\r\n      entry.remove();\r\n      if (section && section.children.length === 0) {\r\n        // Remove the section and its previous sibling (header) if present\r\n        const header = section.previousElementSibling;\r\n        section.remove();\r\n        if (header) header.remove();\r\n      }\r\n    }\r\n\r\n    removeBtn.addEventListener('click', () => {\r\n      if (type === 'temporary') {\r\n        // Remove from temp ignored\r\n        // Use tempIgnoredMap already defined above\r\n        delete tempIgnoredMap[username];\r\n        storageWrapper.set(TEMP_IGNORED_USERS_KEY, tempIgnoredMap);\r\n        removeSectionIfEmpty(entry);\r\n      } else {\r\n        // Remove from permanent ignored\r\n        const forever = storageWrapper.get(IGNORED_USERS_KEY, []);\r\n        const updatedUsers = forever.filter(user => user !== username);\r\n        storageWrapper.set(IGNORED_USERS_KEY, updatedUsers);\r\n        removeSectionIfEmpty(entry);\r\n      }\r\n    });\r\n\r\n    entry.append(label, removeBtn);\r\n    return entry;\r\n  }\r\n\r\n  document.body.appendChild(container);\r\n\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'show', 1);\r\n\r\n  const handleEscapeKey = (e) => {\r\n    if (e.key === 'Escape') {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('keydown', handleEscapeKey);\r\n    }\r\n  };\r\n\r\n  document.addEventListener('keydown', handleEscapeKey);\r\n\r\n  // Hide container on outside click.\r\n  const handleOutsideClick = (e) => {\r\n    if (!container.contains(e.target)) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('click', handleOutsideClick, true);\r\n      document.removeEventListener('keydown', handleEscapeKey); // Remove ESC key listener\r\n    }\r\n  };\r\n  document.addEventListener('click', handleOutsideClick, true);\r\n\r\n  return container;\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/ignoredUsersPanel.js?");

/***/ }),

/***/ "./src/components/themesPanel.js":
/*!***************************************!*\
  !*** ./src/components/themesPanel.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   openThemesPanel: () => (/* binding */ openThemesPanel)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_themes_lightThemes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../data/themes/lightThemes.js */ \"./src/data/themes/lightThemes.js\");\n/* harmony import */ var _data_themes_darkThemes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/themes/darkThemes.js */ \"./src/data/themes/darkThemes.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n// DOM element creation helper.\r\nconst createElement = (tag, className, attributes = {}) => {\r\n  const element = document.createElement(tag);\r\n  if (className) element.className = className;\r\n  Object.entries(attributes).forEach(([key, value]) => {\r\n    if (key === 'text') {\r\n      element.textContent = value;\r\n    } else if (key === 'html') {\r\n      element.innerHTML = value;\r\n    } else {\r\n      element.setAttribute(key, value);\r\n    }\r\n  });\r\n  return element;\r\n};\r\n\r\n// Function to get theme variables\r\nfunction getThemes(theme) {\r\n  const variables = {};\r\n  // Check if the theme exists in lightThemes or darkThemes\r\n  const themeSource = _data_themes_lightThemes_js__WEBPACK_IMPORTED_MODULE_1__.lightThemes['--background-color'][theme]\r\n    ? _data_themes_lightThemes_js__WEBPACK_IMPORTED_MODULE_1__.lightThemes\r\n    : _data_themes_darkThemes_js__WEBPACK_IMPORTED_MODULE_2__.darkThemes;\r\n\r\n  for (const [key, value] of Object.entries(themeSource)) {\r\n    if (value[theme]) {\r\n      variables[key] = value[theme];\r\n    }\r\n  }\r\n  return variables;\r\n}\r\n\r\n// Function to apply theme styles dynamically\r\nfunction applyThemeStyles(themeClassName) {\r\n  const root = document.documentElement;\r\n  const variables = getThemes(themeClassName);\r\n\r\n  if (variables) {\r\n    Object.entries(variables).forEach(([key, value]) => {\r\n      root.style.setProperty(key, value);\r\n    });\r\n  }\r\n}\r\n\r\n// Apply the default theme on page load\r\nconst defaultTheme = localStorage.getItem('selectedTheme') || 'dark-soul';\r\napplyThemeStyles(defaultTheme);\r\n\r\n// The main exported function.\r\nconst openThemesPanel = () => {\r\n  // Prevent duplicate container creation.\r\n  const existingContainer = document.querySelector('.themes-panel');\r\n  if (existingContainer) {\r\n    return existingContainer;\r\n  }\r\n\r\n  // Create container with main header (replace static HTML header)\r\n  const container = createElement('div', 'themes-panel');\r\n  const header = createElement('h2', null, { text: _data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.uiStrings.themesPanelHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.defaultLanguage] });\r\n  container.appendChild(header);\r\n\r\n  // Create blocks for both theme types\r\n  const darkThemesBlock = createElement('div', 'dark-themes');\r\n  const lightThemesBlock = createElement('div', 'light-themes');\r\n\r\n  // Add headers with counters using localized strings\r\n  darkThemesBlock.innerHTML = `<h3>${_data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.uiStrings.themesDarkHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.defaultLanguage]} <span class=\"counter\">${Object.keys(_data_themes_darkThemes_js__WEBPACK_IMPORTED_MODULE_2__.darkThemes['--background-color']).length}</span></h3>`;\r\n  lightThemesBlock.innerHTML = `<h3>${_data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.uiStrings.themesLightHeader[_data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.defaultLanguage]} <span class=\"counter\">${Object.keys(_data_themes_lightThemes_js__WEBPACK_IMPORTED_MODULE_1__.lightThemes['--background-color']).length}</span></h3>`;\r\n\r\n  // Store original theme for preview restoration\r\n  let originalTheme = localStorage.getItem('selectedTheme') || 'dark-soul';\r\n\r\n  // Function to preview theme with debounce\r\n  const previewTheme = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.debounce)(theme => applyThemeStyles(theme), _data_definitions_js__WEBPACK_IMPORTED_MODULE_3__.settings.themePreviewDelay);\r\n\r\n  // Function to create theme buttons\r\n  const createThemeButton = (themeName, themeKey) => {\r\n    const button = createElement('button', 'theme-button', {\r\n      text: themeName.replace(/-/g, ' ').replace(/\\b\\w/g, char => char.toUpperCase())\r\n    });\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_4__.createCustomTooltip)(button, {\r\n      en: `[Hover] Preview theme ${button.textContent} [Click] Apply theme`,\r\n      ru: `[Наведение] Предпросмотр темы ${button.textContent} [Клик] Применить тему`\r\n    });\r\n    button.dataset.theme = themeKey;\r\n\r\n    // Mouse enter for preview\r\n    button.addEventListener('mouseenter', () => {\r\n      previewTheme(themeKey);\r\n    });\r\n\r\n    // Apply theme permanently on click\r\n    button.addEventListener('click', () => {\r\n      originalTheme = themeKey;\r\n      localStorage.setItem('selectedTheme', themeKey);\r\n      highlightActiveTheme();\r\n      applyThemeStyles(themeKey);\r\n    });\r\n\r\n    return button;\r\n  };\r\n\r\n  // Add dark themes\r\n  Object.keys(_data_themes_darkThemes_js__WEBPACK_IMPORTED_MODULE_2__.darkThemes['--background-color']).forEach(themeKey => {\r\n    darkThemesBlock.appendChild(createThemeButton(themeKey, themeKey));\r\n  });\r\n\r\n  // Add light themes\r\n  Object.keys(_data_themes_lightThemes_js__WEBPACK_IMPORTED_MODULE_1__.lightThemes['--background-color']).forEach(themeKey => {\r\n    lightThemesBlock.appendChild(createThemeButton(themeKey, themeKey));\r\n  });\r\n\r\n  // Highlight the active theme button and scroll it into view\r\n  const highlightActiveTheme = () => {\r\n    const currentTheme = localStorage.getItem('selectedTheme') || 'dark-soul';\r\n    originalTheme = currentTheme; // Update the original theme reference\r\n    let activeButton = null;\r\n\r\n    container.querySelectorAll('.theme-button').forEach(button => {\r\n      const isActive = button.dataset.theme === currentTheme;\r\n      button.classList.toggle('active-theme', isActive);\r\n      if (isActive) {\r\n        activeButton = button;\r\n      }\r\n    });\r\n\r\n    // Scroll the active button into view with smooth behavior\r\n    if (activeButton) {\r\n      setTimeout(() => {\r\n        activeButton.scrollIntoView({\r\n          behavior: 'smooth',\r\n          block: 'center'\r\n        });\r\n      }, 100); // Small delay to ensure panel is visible first\r\n    }\r\n  };\r\n\r\n  // Add event to revert theme when mouse leaves the panel\r\n  container.addEventListener('mouseleave', () => {\r\n    // Cancel any pending preview\r\n    previewTheme.cancel();\r\n    // Restore original theme if not activated\r\n    applyThemeStyles(originalTheme);\r\n  });\r\n\r\n  // Append blocks to container (dark themes first)\r\n  container.appendChild(darkThemesBlock);\r\n  container.appendChild(lightThemesBlock);\r\n\r\n  document.body.appendChild(container);\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'show', 1);\r\n\r\n  // Call highlightActiveTheme after the panel is visible\r\n  highlightActiveTheme();\r\n\r\n  const handleEscapeKey = (e) => {\r\n    if (e.key === 'Escape') {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('keydown', handleEscapeKey);\r\n      document.removeEventListener('click', handleOutsideClick, true);\r\n    }\r\n  };\r\n  document.addEventListener('keydown', handleEscapeKey);\r\n\r\n  // Hide container on outside click\r\n  const handleOutsideClick = (e) => {\r\n    if (!container.contains(e.target)) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(container, 'hide', 0);\r\n      document.removeEventListener('click', handleOutsideClick, true);\r\n      document.removeEventListener('keydown', handleEscapeKey);\r\n    }\r\n  };\r\n  document.addEventListener('click', handleOutsideClick, true);\r\n\r\n  return container;\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/themesPanel.js?");

/***/ }),

/***/ "./src/components/updateCheck.js":
/*!***************************************!*\
  !*** ./src/components/updateCheck.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   checkForUpdates: () => (/* binding */ checkForUpdates)\n/* harmony export */ });\nfunction checkForUpdates() {\r\n  const initialVersion = \"0.0.0\"; // Version used only for first run\r\n  const localVersionKey = \"KG_Chat_App_Version\";\r\n  const metaUrl = 'https://update.greasyfork.org/scripts/529368/KG_Chat_Application.meta.js';\r\n  const fullMetaUrl = metaUrl + '?rand=' + Date.now();\r\n  // Fallback download URL (user script URL) renamed to downloadUrl\r\n  const downloadUrl = 'https://update.greasyfork.org/scripts/529368/KG_Chat_Application.user.js';\r\n\r\n  // Initialize localStorage version to initialVersion if not set yet\r\n  if (!localStorage.getItem(localVersionKey)) {\r\n    localStorage.setItem(localVersionKey, initialVersion);\r\n  }\r\n\r\n  // Get the stored version (which is now guaranteed to exist)\r\n  const storedVersion = localStorage.getItem(localVersionKey);\r\n\r\n  fetch(fullMetaUrl)\r\n    .then(response => response.text())\r\n    .then(text => {\r\n      // Updated regex: allow an optional \"v\" or \"V\" prefix and trim extra spaces\r\n      const versionMatch = text.match(/@version\\s+v?([\\d.]+)/i);\r\n\r\n      if (!versionMatch) {\r\n        throw new Error(\"Version not found in meta file\");\r\n      }\r\n\r\n      // Trim to remove any accidental whitespace\r\n      const latestVersion = versionMatch[1].trim();\r\n\r\n      // Always use the fallback downloadUrl (named downloadUrl above)\r\n      // Compare the remote version with the stored version\r\n      if (compareVersions(latestVersion, storedVersion) > 0) {\r\n        showUpdatePopup(latestVersion, storedVersion, downloadUrl, () => {\r\n          localStorage.setItem(localVersionKey, latestVersion);\r\n        });\r\n      }\r\n    })\r\n    .catch(error => console.error('Update check failed:', error));\r\n}\r\n\r\nfunction showUpdatePopup(newVersion, currentVersion, downloadUrl, onUpdateComplete) {\r\n  // Create overlay and popup elements and assign classes for styling\r\n  const overlay = document.createElement('div');\r\n  overlay.className = 'update-overlay';\r\n\r\n  const popup = document.createElement('div');\r\n  popup.className = 'update-popup';\r\n\r\n  popup.innerHTML = `\r\n      <h2 class=\"update-header\">Update Available</h2>\r\n      <h2 class=\"update-script\">KG_Chat_Application</h2>\r\n      <p>A new version <span class=\"version\">${newVersion}</span> is available.</p>\r\n      <p>You are currently using version <span class=\"version\">${currentVersion}</span>.</p>\r\n      <div class=\"button-container\">\r\n        <button id=\"update-later\" class=\"update-later\">Later</button>\r\n        <button id=\"update-skip\" class=\"update-skip\">Skip</button>\r\n        <button id=\"update-now\" class=\"update-now\">Update Now</button>\r\n      </div>\r\n  `;\r\n\r\n  document.body.append(overlay, popup);\r\n\r\n  // \"Later\" button: simply dismiss the popup without updating stored version\r\n  document.getElementById('update-later').addEventListener('click', () => {\r\n    overlay.remove();\r\n    popup.remove();\r\n  });\r\n\r\n  // \"Skip\" button: dismiss the popup and update stored version so the user won't be prompted again for this version\r\n  document.getElementById('update-skip').addEventListener('click', () => {\r\n    if (onUpdateComplete) onUpdateComplete();\r\n    overlay.remove();\r\n    popup.remove();\r\n  });\r\n\r\n  // \"Update Now\" button: open a new tab with the download URL without updating the stored version\r\n  document.getElementById('update-now').addEventListener('click', () => {\r\n    if (onUpdateComplete) onUpdateComplete();\r\n    window.open(downloadUrl, '_blank');\r\n    overlay.remove();\r\n    popup.remove();\r\n  });\r\n}\r\n\r\n// Version compare helper function that supports versions with different lengths (e.g., 1.0 vs 1.0.1)\r\nfunction compareVersions(v1, v2) {\r\n  const parts1 = v1.split('.').map(Number);\r\n  const parts2 = v2.split('.').map(Number);\r\n  const maxLen = Math.max(parts1.length, parts2.length);\r\n  for (let i = 0; i < maxLen; i++) {\r\n    const num1 = parts1[i] || 0;\r\n    const num2 = parts2[i] || 0;\r\n    if (num1 > num2) return 1;\r\n    if (num1 < num2) return -1;\r\n  }\r\n  return 0;\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/components/updateCheck.js?");

/***/ }),

/***/ "./src/converters/imageConverter/imageConverter.js":
/*!*********************************************************!*\
  !*** ./src/converters/imageConverter/imageConverter.js ***!
  \*********************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   convertImageLinksToImage: () => (/* binding */ convertImageLinksToImage),\n/* harmony export */   getThumbnailLinks: () => (/* binding */ getThumbnailLinks),\n/* harmony export */   refreshThumbnailLinks: () => (/* binding */ refreshThumbnailLinks)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n/* harmony import */ var _imageViewer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./imageViewer.js */ \"./src/converters/imageConverter/imageViewer.js\");\n\r\n\r\n\r\n\r\n// Image constants\r\nconst imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];\r\nconst emojis = { image: '📷', domain: '🖥️', untrusted: '💀️️' };\r\n\r\n// Thumbnail links array to be exported\r\nlet thumbnailLinks = [];\r\n\r\nconst getExtension = (url) => {\r\n  try {\r\n    return (url.match(/\\.([^?#.]+)(?:[?#]|$)/i)?.[1]?.toLowerCase() || '');\r\n  } catch (error) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Error extracting image extension: ${error.message}`, 'error');\r\n    return '';\r\n  }\r\n};\r\n\r\nconst isAllowedImageExtension = (url) => {\r\n  const extension = getExtension(url);\r\n  return { allowed: imageExtensions.includes(extension), extension };\r\n};\r\n\r\n// Function to refresh the thumbnail links array\r\nconst refreshThumbnailLinks = () => {\r\n  const container = document.getElementById('messages-panel');\r\n  if (!container) return;\r\n\r\n  thumbnailLinks = [];\r\n  container.querySelectorAll(\".clickable-thumbnail\").forEach((thumbnail, index) => {\r\n    const img = thumbnail.querySelector(\"img\");\r\n    if (img && thumbnail.dataset.sourceLink) {\r\n      thumbnailLinks.push({ link: thumbnail.dataset.sourceLink, imgSrc: img.src, index });\r\n    }\r\n  });\r\n\r\n  return thumbnailLinks;\r\n};\r\n\r\n// Get the current thumbnail links\r\nconst getThumbnailLinks = () => thumbnailLinks;\r\n\r\nfunction createThumbnail(link, isUntrusted) {\r\n  // Ensure the link is wrapped in an image-container.\r\n  let container = link.parentElement;\r\n  if (!container.classList.contains('image-container')) {\r\n    container = document.createElement('div');\r\n    container.classList.add('image-container');\r\n    // Insert the container before the link and then move the link into it.\r\n    link.parentNode.insertBefore(container, link);\r\n    container.appendChild(link);\r\n  }\r\n\r\n  // Create the thumbnail element.\r\n  const thumbnail = document.createElement(\"div\");\r\n  thumbnail.classList.add(\"clickable-thumbnail\");\r\n  thumbnail.dataset.sourceLink = link.href;\r\n\r\n  const img = document.createElement(\"img\");\r\n  img.src = link.href;\r\n\r\n  img.onload = () => {\r\n    thumbnail.appendChild(img);\r\n    // Append the thumbnail to the container instead of next to the link.\r\n    container.appendChild(thumbnail);\r\n  };\r\n\r\n  img.onerror = () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Failed to load image: ${link.href}`, 'error');\r\n    link.classList.add(\"skipped\");\r\n  };\r\n\r\n  if (isUntrusted) {\r\n    if (!link.querySelector(\".clickable-thumbnail\")) {\r\n      link.addEventListener(\"click\", () => {\r\n        if (!link.querySelector(\".clickable-thumbnail\")) {\r\n          thumbnail.appendChild(img);\r\n          container.appendChild(thumbnail);\r\n        }\r\n      });\r\n    }\r\n  } else {\r\n    thumbnail.appendChild(img);\r\n    container.appendChild(thumbnail);\r\n  }\r\n\r\n  thumbnail.addEventListener(\"click\", (e) => {\r\n    e.stopPropagation();\r\n    const updatedLinks = refreshThumbnailLinks();\r\n    const clickedIndex = updatedLinks.findIndex(\r\n      (item) => item.link === link.href || item.imgSrc === img.src\r\n    );\r\n\r\n    const expandedImage = (0,_imageViewer_js__WEBPACK_IMPORTED_MODULE_2__.createExpandedView)(\r\n      img.src,\r\n      clickedIndex >= 0 ? clickedIndex : 0\r\n    );\r\n\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(expandedImage, \"show\", \"1\");\r\n    const dimmingElement = document.querySelector('.dimming-element');\r\n    if (dimmingElement) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(dimmingElement, \"show\", \"1\");\r\n    }\r\n  });\r\n}\r\n\r\nfunction handleUntrustedLink(link, extension, domain) {\r\n  link.classList.add(\"skipped\");\r\n  link.textContent = `${emojis.image} ${extension.toUpperCase()} ${emojis.domain} ${domain} ${emojis.untrusted} Untrusted`;\r\n  link.addEventListener(\"click\", (e) => {\r\n    if (!link.classList.contains(\"processed-image\")) {\r\n      e.preventDefault();\r\n      link.classList.remove(\"skipped\");\r\n      link.classList.add(\"processed-image\");\r\n      createThumbnail(link, true);\r\n    }\r\n  });\r\n}\r\n\r\nfunction handleTrustedLink(link, extension, domain) {\r\n  link.textContent = `${emojis.image} ${extension.toUpperCase()} ${emojis.domain} ${domain}`;\r\n  link.classList.add(\"processed-image\");\r\n  createThumbnail(link, false);\r\n}\r\n\r\nfunction convertImageLinksToImage() {\r\n  const container = document.getElementById('messages-panel');\r\n  if (!container) return;\r\n\r\n  const links = container.querySelectorAll(\"a:not(.skipped):not(.processed-image)\");\r\n  if (!links.length) return;\r\n\r\n  links.forEach((link) => {\r\n    if (!link.href || !link.href.startsWith(\"http\")) return;\r\n    const { allowed, extension } = isAllowedImageExtension(link.href);\r\n    if (!allowed) return;\r\n\r\n    link.classList.add(\"media\");\r\n    const { isTrusted, domain } = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.isTrustedDomain)(link.href);\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__.createCustomTooltip)(link, (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.isEncodedURL)(link.href) ? (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.decodeURL)(link.href) : link.href);\r\n\r\n    isTrusted\r\n      ? handleTrustedLink(link, extension, domain)\r\n      : handleUntrustedLink(link, extension, domain);\r\n  });\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/converters/imageConverter/imageConverter.js?");

/***/ }),

/***/ "./src/converters/imageConverter/imageViewer.js":
/*!******************************************************!*\
  !*** ./src/converters/imageConverter/imageViewer.js ***!
  \******************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   createExpandedView: () => (/* binding */ createExpandedView)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _imageConverter_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./imageConverter.js */ \"./src/converters/imageConverter/imageConverter.js\");\n\r\n\r\n\r\n// Image viewer state variables\r\nlet currentIndex = 0;\r\nlet isChangingImage = false;\r\nlet expandedImage = null;\r\nlet bigImageEvents = {}; // Object to store event handlers\r\nlet imageInfoContainer = null; // Container for image info\r\n\r\n// Constants for image viewer\r\nconst zoomLimits = { min: 0.2, max: 10, factor: 0.1 };\r\nconst navigationDelay = 50;\r\n\r\nfunction addBigImageEventListeners() {\r\n  Object.entries(bigImageEvents).forEach(([event, handler]) => {\r\n    document.addEventListener(event, handler);\r\n  });\r\n}\r\n\r\nfunction removeBigImageEventListeners() {\r\n  Object.entries(bigImageEvents).forEach(([event, handler]) => {\r\n    document.removeEventListener(event, handler);\r\n  });\r\n}\r\n\r\nfunction getImageInfo(index) {\r\n  const thumbnails = document.querySelectorAll('.clickable-thumbnail');\r\n  const thumbnail = Array.from(thumbnails)[index];\r\n  if (!thumbnail) return null;\r\n\r\n  // Find the message container that contains this thumbnail\r\n  let messageContainer = thumbnail.closest('.message');\r\n  if (!messageContainer) return null;\r\n\r\n  // Get the message info elements\r\n  const messageInfo = messageContainer.querySelector('.message-info');\r\n  if (!messageInfo) return null;\r\n\r\n  const time = messageInfo.querySelector('.time')?.textContent || '';\r\n  const username = messageInfo.querySelector('.username')?.textContent || '';\r\n\r\n  return { time, username };\r\n}\r\n\r\nfunction createImageInfo() {\r\n  const container = document.createElement('div');\r\n  container.className = 'image-info-container';\r\n  return container;\r\n}\r\n\r\nfunction updateImageInfo(index) {\r\n  if (!imageInfoContainer) return;\r\n  const info = getImageInfo(index);\r\n  if (!info) return;\r\n\r\n  imageInfoContainer.innerHTML = `\r\n    <div class=\"image-info-time\">${info.time}</div>\r\n    <div class=\"image-info-username\">${info.username}</div>\r\n  `;\r\n\r\n  // Add click event to time element\r\n  const timeEl = imageInfoContainer.querySelector('.image-info-time');\r\n  if (timeEl) {\r\n    timeEl.addEventListener('click', (e) => {\r\n      e.stopPropagation();\r\n      const localTime = timeEl.textContent.trim();\r\n      const moscowTime = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.calibrateToMoscowTime)(localTime);\r\n      const today = new Intl.DateTimeFormat('en-CA').format(new Date());\r\n      const url = `https://klavogonki.ru/chatlogs/${today}.html#${moscowTime}`;\r\n      window.open(url, '_blank');\r\n    });\r\n  }\r\n}\r\n\r\nfunction removeImageInfo() {\r\n  if (imageInfoContainer && imageInfoContainer.parentNode) {\r\n    imageInfoContainer.parentNode.removeChild(imageInfoContainer);\r\n    imageInfoContainer = null;\r\n  }\r\n}\r\n\r\n// Close the expanded view\r\nconst closeExpandedView = (img) => {\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(img, 'hide', '0');\r\n  const dimmingElement = document.querySelector('.dimming-element');\r\n  if (!document.querySelector('.popup-panel') && dimmingElement) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(dimmingElement, 'hide', '0');\r\n  }\r\n  removeBigImageEventListeners();\r\n  removeImageInfo();\r\n};\r\n\r\n// Navigate between images\r\nconst navigateImages = (direction) => {\r\n  const thumbnailLinks = (0,_imageConverter_js__WEBPACK_IMPORTED_MODULE_1__.getThumbnailLinks)();\r\n  const newIndex = currentIndex + direction;\r\n\r\n  if (newIndex >= 0 && newIndex < thumbnailLinks.length && !isChangingImage) {\r\n    isChangingImage = true;\r\n    if (expandedImage) expandedImage.src = thumbnailLinks[newIndex].imgSrc;\r\n    setTimeout(() => {\r\n      isChangingImage = false;\r\n      currentIndex = newIndex;\r\n      updateImageInfo(currentIndex); // Ensure info updates on navigation\r\n    }, navigationDelay);\r\n  }\r\n};\r\n\r\n// Create the expanded view of an image\r\nconst createExpandedView = (src, clickedThumbnailIndex) => {\r\n  // Create and add expanded image to DOM\r\n  const imageElement = document.createElement('img');\r\n  imageElement.src = src;\r\n  imageElement.classList.add('scaled-thumbnail');\r\n\r\n  document.body.appendChild(imageElement);\r\n  expandedImage = imageElement;\r\n\r\n  currentIndex = clickedThumbnailIndex;\r\n\r\n  // Create and add info container\r\n  imageInfoContainer = createImageInfo();\r\n  document.body.appendChild(imageInfoContainer);\r\n  updateImageInfo(currentIndex);\r\n\r\n  // Zoom and movement variables\r\n  let zoomScale = 1;\r\n  let isMMBPressed = false;\r\n  let lastMouseX = 0,\r\n    lastMouseY = 0;\r\n  let translateX = 0,\r\n    translateY = 0;\r\n  const movementSpeed = 5;\r\n\r\n  // Get or create the dimming element\r\n  let dimmingElement = document.querySelector('.dimming-element');\r\n  if (!dimmingElement) {\r\n    dimmingElement = document.createElement('div');\r\n    dimmingElement.classList.add('dimming-element');\r\n    document.body.appendChild(dimmingElement);\r\n  }\r\n\r\n  // Add mobile touch support\r\n  if ((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.checkIsMobile)()) {\r\n    setupMobileTouchHandlers(imageElement, zoomScale, translateX, translateY);\r\n  }\r\n\r\n  // Define event listeners for the expanded image (desktop)\r\n  bigImageEvents.click = (event) => {\r\n    if (!imageElement.contains(event.target)) {\r\n      imageElement.remove();\r\n      removeBigImageEventListeners();\r\n    }\r\n  };\r\n\r\n  bigImageEvents.keydown = (event) => {\r\n    if (event.code === 'Escape' || event.code === 'Space') {\r\n      event.preventDefault();\r\n      closeExpandedView(imageElement);\r\n    } else if (event.code === 'ArrowLeft') {\r\n      navigateImages(-1);\r\n    } else if (event.code === 'ArrowRight') {\r\n      navigateImages(1);\r\n    }\r\n  };\r\n\r\n  bigImageEvents.wheel = (event) => {\r\n    event.preventDefault();\r\n    const rect = imageElement.getBoundingClientRect();\r\n    const mouseX = (event.clientX - rect.left) - rect.width / 2;\r\n    const mouseY = (event.clientY - rect.top) - rect.height / 2;\r\n    const direction = event.deltaY < 0 ? 1 : -1;\r\n    const oldScale = zoomScale;\r\n    let newScale = zoomScale + direction * zoomLimits.factor * zoomScale;\r\n    newScale = Math.max(zoomLimits.min, Math.min(newScale, zoomLimits.max));\r\n\r\n    ({ translateX, translateY } = zoomAtPoint({\r\n      imageElement,\r\n      anchorX: mouseX,\r\n      anchorY: mouseY,\r\n      oldScale,\r\n      newScale,\r\n      translateX,\r\n      translateY\r\n    }));\r\n\r\n    zoomScale = newScale;\r\n  };\r\n\r\n  bigImageEvents.mousemove = (event) => {\r\n    if (isMMBPressed) {\r\n      if (event.ctrlKey) {\r\n        const rect = imageElement.getBoundingClientRect();\r\n        const mouseX = (event.clientX - rect.left) - rect.width / 2;\r\n        const mouseY = (event.clientY - rect.top) - rect.height / 2;\r\n        const deltaY = event.clientY - lastMouseY;\r\n        const zoomDirection = deltaY < 0 ? 1 : -1;\r\n        const zoomAmount = Math.abs(deltaY) * zoomLimits.factor * 0.05;\r\n        const oldScale = zoomScale;\r\n        let newScale = zoomScale + zoomDirection * zoomAmount * zoomScale;\r\n        newScale = Math.max(zoomLimits.min, Math.min(newScale, zoomLimits.max));\r\n\r\n        ({ translateX, translateY } = zoomAtPoint({\r\n          imageElement,\r\n          anchorX: mouseX,\r\n          anchorY: mouseY,\r\n          oldScale,\r\n          newScale,\r\n          translateX,\r\n          translateY\r\n        }));\r\n\r\n        zoomScale = newScale;\r\n      } else {\r\n        const deltaX = (event.clientX - lastMouseX) / zoomScale * movementSpeed;\r\n        const deltaY = (event.clientY - lastMouseY) / zoomScale * movementSpeed;\r\n        translateX += deltaX;\r\n        translateY += deltaY;\r\n        imageElement.style.transform = `translate(-50%, -50%) translate(${translateX}px, ${translateY}px) scale(${zoomScale})`;\r\n      }\r\n      lastMouseX = event.clientX;\r\n      lastMouseY = event.clientY;\r\n    }\r\n  };\r\n\r\n  bigImageEvents.mousedown = (event) => {\r\n    const { button, clientX, clientY, target, ctrlKey } = event;\r\n    if ((button === 0 || button === 2) && target !== imageElement) return;\r\n    if (button === 0) {\r\n      navigateImages(-1);\r\n    } else if (button === 2) {\r\n      event.preventDefault();\r\n      if (ctrlKey) {\r\n        navigator.clipboard.writeText(target.src).catch(console.error);\r\n        closeExpandedView(imageElement);\r\n      } else {\r\n        navigateImages(1);\r\n      }\r\n    } else if (button === 1) {\r\n      isMMBPressed = true;\r\n      lastMouseX = clientX;\r\n      lastMouseY = clientY;\r\n      event.preventDefault();\r\n    }\r\n  };\r\n\r\n  bigImageEvents.mouseup = (event) => {\r\n    if (event.button === 1) {\r\n      isMMBPressed = false;\r\n    }\r\n  };\r\n\r\n  bigImageEvents.contextmenu = (event) => event.preventDefault();\r\n\r\n  // Add the event listeners\r\n  addBigImageEventListeners();\r\n\r\n  // Show the dimming element\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(dimmingElement, \"show\", \"1\");\r\n\r\n  // When clicking the dimming background, hide the image and the dimming element\r\n  dimmingElement.addEventListener('click', () => {\r\n    closeExpandedView(imageElement);\r\n  });\r\n\r\n  return imageElement;\r\n};\r\n\r\nfunction zoomAtPoint({\r\n  imageElement,\r\n  anchorX,\r\n  anchorY,\r\n  oldScale,\r\n  newScale,\r\n  translateX,\r\n  translateY\r\n}) {\r\n  // anchorX, anchorY are relative to image center (in px, not scaled)\r\n  const deltaScale = newScale - oldScale;\r\n  translateX -= (anchorX / oldScale) * deltaScale;\r\n  translateY -= (anchorY / oldScale) * deltaScale;\r\n  imageElement.style.transform = `translate(-50%, -50%) translate(${translateX}px, ${translateY}px) scale(${newScale})`;\r\n  return { translateX, translateY };\r\n}\r\n\r\n// Setup mobile touch handlers\r\nfunction setupMobileTouchHandlers(imageElement, zoomScale, translateX, translateY) {\r\n  // Variables to track touch state\r\n  let prevTouches = 0;\r\n  let prevDistance = 0;\r\n  let prevTouchX = 0;\r\n  let prevTouchY = 0;\r\n  let prevPinchCenter = { x: 0, y: 0 };\r\n\r\n  const handleTouchStart = (event) => {\r\n    event.preventDefault();\r\n    if (event.touches.length === 2) {\r\n      // Store initial pinch center\r\n      const touch1 = event.touches[0];\r\n      const touch2 = event.touches[1];\r\n      prevPinchCenter.x = (touch1.clientX + touch2.clientX) / 2;\r\n      prevPinchCenter.y = (touch1.clientY + touch2.clientY) / 2;\r\n    }\r\n  };\r\n\r\n  const handleTouchMove = (event) => {\r\n    event.preventDefault(); // Prevent scrolling\r\n\r\n    const currentTouches = event.touches.length;\r\n\r\n    if (currentTouches === 2) {\r\n      // Pinch zoom with two fingers\r\n      const touch1 = event.touches[0];\r\n      const touch2 = event.touches[1];\r\n      const centerX = (touch1.clientX + touch2.clientX) / 2;\r\n      const centerY = (touch1.clientY + touch2.clientY) / 2;\r\n      const currentDistance = Math.hypot(\r\n        touch1.clientX - touch2.clientX,\r\n        touch1.clientY - touch2.clientY\r\n      );\r\n      if (prevTouches === 2) {\r\n        const rect = imageElement.getBoundingClientRect();\r\n        const pinchX = (centerX - rect.left) - rect.width / 2;\r\n        const pinchY = (centerY - rect.top) - rect.height / 2;\r\n        const oldScale = zoomScale;\r\n        const zoomFactor = currentDistance / prevDistance;\r\n        let newScale = zoomScale * zoomFactor;\r\n        newScale = Math.max(zoomLimits.min, Math.min(newScale, zoomLimits.max));\r\n\r\n        ({ translateX, translateY } = zoomAtPoint({\r\n          imageElement,\r\n          anchorX: pinchX,\r\n          anchorY: pinchY,\r\n          oldScale,\r\n          newScale,\r\n          translateX,\r\n          translateY\r\n        }));\r\n\r\n        zoomScale = newScale;\r\n      }\r\n      prevDistance = currentDistance;\r\n      prevPinchCenter.x = centerX;\r\n      prevPinchCenter.y = centerY;\r\n    } else if (currentTouches === 1) {\r\n      // Pan with one finger\r\n      const touch = event.touches[0];\r\n      const currentX = touch.clientX;\r\n      const currentY = touch.clientY;\r\n\r\n      if (prevTouches === 1) {\r\n        // Apply pan only if previous event also had 1 touch\r\n        const deltaX = currentX - prevTouchX;\r\n        const deltaY = currentY - prevTouchY;\r\n        translateX += deltaX;\r\n        translateY += deltaY;\r\n        imageElement.style.transform = `translate(-50%, -50%) translate(${translateX}px, ${translateY}px) scale(${zoomScale})`;\r\n      }\r\n      prevTouchX = currentX;\r\n      prevTouchY = currentY;\r\n    }\r\n\r\n    prevTouches = currentTouches; // Update previous touch count\r\n  };\r\n\r\n  const handleTouchEnd = (event) => {\r\n    if (event.touches.length === 0) {\r\n      prevTouches = 0; // Reset when all fingers are lifted\r\n    }\r\n  };\r\n\r\n  // Add touch event listeners with passive: false to allow preventDefault\r\n  imageElement.addEventListener('touchstart', handleTouchStart, { passive: false });\r\n  imageElement.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n  imageElement.addEventListener('touchend', handleTouchEnd);\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/converters/imageConverter/imageViewer.js?");

/***/ }),

/***/ "./src/converters/videoConverter.js":
/*!******************************************!*\
  !*** ./src/converters/videoConverter.js ***!
  \******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   convertVideoLinksToPlayer: () => (/* binding */ convertVideoLinksToPlayer)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n// Constants\r\nconst emojis = {\r\n  channel: '📺',\r\n  title: '📹',\r\n  type: '🎬️',\r\n  domain: '🖥️',\r\n  untrusted: '💀️️'\r\n};\r\nconst allowedVideoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi'];\r\n\r\n// Utility Functions\r\n\r\n/** Checks if a URL has an allowed video extension */\r\nconst isAllowedVideoExtension = url => {\r\n  const ext = url.match(/\\.([^?#.]+)(?:[?#]|$)/i)?.[1]?.toLowerCase() || '';\r\n  return { allowed: allowedVideoExtensions.includes(ext), extension: ext };\r\n};\r\n\r\n// Global Variables\r\nlet sharedYouTubePlayer = null; // Shared YouTube player instance\r\nlet activeYouTubePlaceholder = null; // Tracks the currently active YouTube preview\r\n\r\n/** Returns or creates a shared YouTube iframe player */\r\nfunction getSharedYouTubePlayer() {\r\n  if (!sharedYouTubePlayer) {\r\n    sharedYouTubePlayer = document.createElement('iframe');\r\n    sharedYouTubePlayer.classList.add(\"video-container\");\r\n    sharedYouTubePlayer.allowFullscreen = true;\r\n  }\r\n  return sharedYouTubePlayer;\r\n}\r\n\r\n/** Fetches YouTube metadata using the oEmbed endpoint */\r\nasync function fetchYouTubeMetadata(videoId) {\r\n  const oembedUrl = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoId}&format=json`;\r\n  try {\r\n    const response = await fetch(oembedUrl);\r\n    const data = await response.json();\r\n    const title = data.title || 'Title not found';\r\n    const channel = data.author_name || 'Channel not found';\r\n    return { title, channel };\r\n  } catch (error) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(\"Error fetching YouTube metadata.\", 'error');\r\n    return { title: 'Error', channel: 'Error' };\r\n  }\r\n}\r\n\r\n/** Renders a YouTube preview with metadata and thumbnail */\r\nasync function renderYouTubePreview(infoContainer, placeholder, videoId, videoType) {\r\n  infoContainer.hidden = true;\r\n  placeholder.hidden = true;\r\n\r\n  const metadata = await fetchYouTubeMetadata(videoId);\r\n\r\n  const channel = document.createElement('span');\r\n  channel.classList.add(\"channel-name\");\r\n  channel.textContent = `${emojis.channel} ${metadata.channel}`;\r\n\r\n  const title = document.createElement('span');\r\n  title.classList.add(\"video-title\");\r\n  title.textContent = `${emojis.title} ${metadata.title}`;\r\n\r\n  const thumb = new Image();\r\n  thumb.src = `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;\r\n  thumb.alt = videoType;\r\n  thumb.classList.add(\"youtube-thumb\");\r\n\r\n  thumb.addEventListener('load', () => {\r\n    infoContainer.replaceChildren(channel, title);\r\n    placeholder.replaceChildren(thumb);\r\n    infoContainer.hidden = false;\r\n    placeholder.hidden = false;\r\n  });\r\n\r\n  thumb.addEventListener('error', () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Error loading Youtube thumbnail image for ${videoId}.`, 'error');\r\n  });\r\n}\r\n\r\n/** Extracts video information from a URL */\r\nfunction getVideoInfo(url) {\r\n  const youtubeMatch = url.match(/(?:shorts\\/|live\\/|watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/i);\r\n  if (youtubeMatch) {\r\n    const videoId = youtubeMatch[1];\r\n    const videoType = url.includes('shorts/') ? 'Shorts' :\r\n      url.includes('live/') ? 'Live' :\r\n        url.includes('watch?v=') ? 'Watch' :\r\n          url.includes('youtu.be/') ? 'Share' : 'YouTube';\r\n    return { youtubeMatch: true, videoId, videoType };\r\n  }\r\n\r\n  const extension = url.split('.').pop().toLowerCase();\r\n  if (allowedVideoExtensions.includes(extension)) {\r\n    return { youtubeMatch: false, videoType: `Video (${extension.toUpperCase()})` };\r\n  }\r\n  return false;\r\n}\r\n\r\n/** Main function to convert video links to players or previews */\r\nfunction convertVideoLinksToPlayer() {\r\n  const container = document.getElementById('messages-panel');\r\n  if (!container) return;\r\n\r\n  const links = container.querySelectorAll(\"a:not(.skipped):not(.processed-video)\");\r\n  if (!links.length) return;\r\n\r\n  links.forEach(link => {\r\n    const url = link.href;\r\n    if (!url) return;\r\n\r\n    const videoInfo = getVideoInfo(url);\r\n    if (!videoInfo) return;\r\n\r\n    link.classList.add(\"media\");\r\n    const { isTrusted, domain } = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.isTrustedDomain)(url);\r\n\r\n    if (!isTrusted) {\r\n      link.classList.add(\"skipped\");\r\n      link.textContent = `${emojis.type} ${videoInfo.videoType} ${emojis.domain} ${domain} ${emojis.untrusted} Untrusted`;\r\n      link.addEventListener(\"click\", e => {\r\n        if (!link.classList.contains(\"processed-video\")) {\r\n          e.preventDefault();\r\n          link.classList.remove(\"skipped\");\r\n          processVideoLink(link, url, domain, videoInfo);\r\n        }\r\n      });\r\n      return;\r\n    }\r\n\r\n    processVideoLink(link, url, domain, videoInfo);\r\n  });\r\n\r\n  /** Processes a single video link */\r\n  async function processVideoLink(link, url, domain, videoInfo) {\r\n    const { youtubeMatch, videoType, videoId } = videoInfo;\r\n    const videoCheck = isAllowedVideoExtension(url);\r\n    if (!youtubeMatch && !videoCheck.allowed) return;\r\n\r\n    link.classList.add(\"processed-video\");\r\n\r\n    const wrapper = document.createElement('div');\r\n    wrapper.classList.add(\"video-wrapper\");\r\n\r\n    link.textContent = `${emojis.type} ${videoType} ${emojis.domain} ${domain}`;\r\n    (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_1__.createCustomTooltip)(link, (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.isEncodedURL)(url) ? (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.decodeURL)(url) : url);\r\n    link.style.display = 'inline-flex';\r\n\r\n    if (youtubeMatch) {\r\n      const infoContainer = document.createElement('div');\r\n      infoContainer.classList.add(\"youtube-info\");\r\n\r\n      const placeholder = document.createElement('div');\r\n      placeholder.classList.add(\"youtube-placeholder\");\r\n      placeholder.dataset.videoId = videoId;\r\n      placeholder.dataset.videoType = videoType;\r\n\r\n      link.parentNode.insertBefore(wrapper, link);\r\n      wrapper.append(link, infoContainer, placeholder);\r\n\r\n      await renderYouTubePreview(infoContainer, placeholder, videoId, videoType);\r\n\r\n      placeholder.addEventListener(\"click\", () => {\r\n        if (activeYouTubePlaceholder && activeYouTubePlaceholder !== placeholder) {\r\n          const prevVideoId = activeYouTubePlaceholder.dataset.videoId;\r\n          const prevVideoType = activeYouTubePlaceholder.dataset.videoType;\r\n          renderYouTubePreview(\r\n            activeYouTubePlaceholder.previousElementSibling,\r\n            activeYouTubePlaceholder,\r\n            prevVideoId,\r\n            prevVideoType\r\n          );\r\n        }\r\n        activeYouTubePlaceholder = placeholder;\r\n\r\n        const player = getSharedYouTubePlayer();\r\n        player.hidden = true;\r\n        player.src = `https://www.youtube.com/embed/${videoId}?autoplay=1`;\r\n        placeholder.replaceChildren(player);\r\n        player.addEventListener('load', () => {\r\n          player.hidden = false;\r\n        });\r\n      });\r\n    } else {\r\n      const embed = document.createElement('video');\r\n      embed.classList.add(\"video-container\");\r\n      embed.src = url;\r\n      embed.controls = true;\r\n      embed.hidden = true;\r\n\r\n      embed.addEventListener('loadeddata', () => {\r\n        embed.hidden = false;\r\n      });\r\n\r\n      embed.addEventListener('error', () => {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Error loading video source: ${url}`, 'error');\r\n        wrapper.replaceChildren(link);\r\n      });\r\n\r\n      link.parentNode.insertBefore(wrapper, link);\r\n      wrapper.append(link, embed);\r\n    }\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/converters/videoConverter.js?");

/***/ }),

/***/ "./src/data/animations.js":
/*!********************************!*\
  !*** ./src/data/animations.js ***!
  \********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   addJumpEffect: () => (/* binding */ addJumpEffect),\n/* harmony export */   addShakeEffect: () => (/* binding */ addShakeEffect)\n/* harmony export */ });\nfunction addJumpEffect(element, initialTranslateX = 0, initialTranslateY = 0) {\r\n  // Define keyframes with specified percentages, scale effect, and calc for Y translation\r\n  const keyframes = [\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}%)) scale(1)` }, // 0%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% - 60%)) scale(1.1)` }, // 20%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% + 15%)) scale(1)` }, // 40%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% - 20%)) scale(1.05)` }, // 60%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% + 8%)) scale(1)` }, // 75%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% - 10%)) scale(1.05)` }, // 85%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}% + 4%)) scale(1)` }, // 92%\r\n    { transform: `translate(${initialTranslateX}%, calc(${initialTranslateY}%)) scale(1)` } // 100%\r\n  ];\r\n\r\n  // Animation options\r\n  const options = {\r\n    duration: 500, // Total animation duration in ms (adjust as needed)\r\n    easing: 'ease', // Smooth easing between keyframes\r\n    iterations: 1 // Play once\r\n  };\r\n\r\n  // Start the animation\r\n  const animation = element.animate(keyframes, options);\r\n\r\n  // Optional: Return a promise that resolves when animation completes\r\n  return animation.finished;\r\n}\r\n\r\n// Helper function to add shake effect\r\nfunction addShakeEffect(element) {\r\n  element.classList.add('shake-effect');\r\n  setTimeout(() => {\r\n    element.classList.remove('shake-effect');\r\n  }, 500);\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/animations.js?");

/***/ }),

/***/ "./src/data/definitions.js":
/*!*********************************!*\
  !*** ./src/data/definitions.js ***!
  \*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   BASE_URL: () => (/* binding */ BASE_URL),\n/* harmony export */   FALLBACK_COLOR: () => (/* binding */ FALLBACK_COLOR),\n/* harmony export */   GAME_URL: () => (/* binding */ GAME_URL),\n/* harmony export */   XMPP_BIND_URL: () => (/* binding */ XMPP_BIND_URL),\n/* harmony export */   connectionMessages: () => (/* binding */ connectionMessages),\n/* harmony export */   defaultLanguage: () => (/* binding */ defaultLanguage),\n/* harmony export */   emojiFaces: () => (/* binding */ emojiFaces),\n/* harmony export */   eventsColorMap: () => (/* binding */ eventsColorMap),\n/* harmony export */   loadUsernameColorsUrl: () => (/* binding */ loadUsernameColorsUrl),\n/* harmony export */   settings: () => (/* binding */ settings),\n/* harmony export */   trustedDomains: () => (/* binding */ trustedDomains),\n/* harmony export */   uiStrings: () => (/* binding */ uiStrings)\n/* harmony export */ });\n/* harmony import */ var _styles_style_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../styles/style.scss */ \"./src/styles/style.scss\");\n/* harmony import */ var _styles_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../styles/emojiPanel.scss */ \"./src/styles/emojiPanel.scss\");\n/* harmony import */ var _styles_helpPanel_scss__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../styles/helpPanel.scss */ \"./src/styles/helpPanel.scss\");\n/* harmony import */ var _styles_updateCheck_scss__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../styles/updateCheck.scss */ \"./src/styles/updateCheck.scss\");\n/* harmony import */ var _styles_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../styles/chatUsernameColors.scss */ \"./src/styles/chatUsernameColors.scss\");\n/* harmony import */ var _styles_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../styles/ignoredUsers.scss */ \"./src/styles/ignoredUsers.scss\");\n/* harmony import */ var _styles_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../styles/animationKeyframes.scss */ \"./src/styles/animationKeyframes.scss\");\n/* harmony import */ var _styles_themesPanel_scss__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../styles/themesPanel.scss */ \"./src/styles/themesPanel.scss\");\n/* harmony import */ var _styles_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../styles/eventsPanel.scss */ \"./src/styles/eventsPanel.scss\");\n // main styles\r\n // emoji panel styles\r\n // help panel styles\r\n // update panel styles\r\n // chat username colors styles\r\n // ignored users styles\r\n // animation keyframes styles\r\n // themes panel styles\r\n // events panel styles\r\n\r\n// URL constants\r\nconst BASE_URL = 'https://klavogonki.ru';\r\nconst GAME_URL = `${BASE_URL}/g/?gmid=`;\r\nconst XMPP_BIND_URL = `${BASE_URL}/xmpp-httpbind/`;\r\n\r\nconst settings = {\r\n  connectionDelay: 100,\r\n  reconnectionDelay: 3000,\r\n  pendingUserDelay: 500,\r\n  longPressDuration: 300,\r\n  clearSelectionDelay: 500,\r\n  revealUserListDelay: 150,\r\n  themePreviewDelay: 150,\r\n  showAlertDuration: 2000,\r\n  pingInterval: 10000,\r\n  deduplicationDelay: 2000,\r\n  tooltipShowDelay: 400,\r\n  tooltipVisibleTime: 100,\r\n};\r\n\r\nconst connectionMessages = {\r\n  chat: {\r\n    en: {\r\n      online: 'Chat connection established.',\r\n      offline: 'Chat connection lost.'\r\n    },\r\n    ru: {\r\n      online: 'Соединение с чатом установлено.',\r\n      offline: 'Соединение с чатом потеряно.'\r\n    }\r\n  },\r\n  network: {\r\n    en: {\r\n      online: 'Network connection restored.',\r\n      offline: 'Network connection lost.'\r\n    },\r\n    ru: {\r\n      online: 'Сетевое соединение восстановлено.',\r\n      offline: 'Сетевое соединение потеряно.'\r\n    }\r\n  }\r\n};\r\n\r\nconst emojiFaces = [\r\n  // People Emojis (Facial expressions)\r\n  '😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆',\r\n  '😉', '😊', '😋', '😎', '😏', '😐', '😑', '😒',\r\n  '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚',\r\n  '😜', '😝', '😛', '🤑', '🤗', '🤔', '🤐', '🤨',\r\n  '😣', '😥', '😮', '🤯', '😳', '😱', '😨', '😰',\r\n  '😢', '🤪', '😵', '😲', '🤤', '😷', '🤒', '🤕',\r\n  '🤢', '🤧', '😇', '🥳', '🥺', '😬', '😴', '😌',\r\n  '🤥', '🥴', '🥵', '🥶', '🤧', '🤭', '🤫', '😠',\r\n  '😡', '😳', '😞', '😟', '😕',\r\n\r\n  // Cat Emojis (Expressive faces of cats)\r\n  '🐱', '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾',\r\n\r\n  // Other Animal Emojis (Various animals' faces)\r\n  '🐶', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼',\r\n  '🐨', '🐯', '🦁', '🐮', '🐷', '🐸', '🐵',\r\n  '🙈', '🙉', '🙊', '🐔', '🦄'\r\n];\r\n\r\n// List of trusted domains\r\nconst trustedDomains = [\r\n  'klavogonki.ru',\r\n  'youtube.com', // youtube main\r\n  'youtu.be', // youtube share\r\n  'imgur.com',\r\n  'pikabu.ru',\r\n  'userapi.com', // vk.com\r\n  'ibb.co', // imgbb.com\r\n  'yaplakal.com',\r\n  'freepik.com',\r\n  'fastpic.org'\r\n];\r\n\r\n// Define a single fallback username color for consistency\r\nconst FALLBACK_COLOR = \"#1e1e1e\";\r\n\r\nconst loadUsernameColorsUrl = \"https://raw.githubusercontent.com/VimiummuimiV/KG_Chat_Application/refs/heads/main/src/data/usernameColors.json\";\r\n\r\n// Define a color map for the chat alerts\r\nconst eventsColorMap = {\r\n  info: '#2196F3',\r\n  warning: '#FF9800',\r\n  error: '#F44336',\r\n  success: '#4CAF50'\r\n};\r\n\r\nconst defaultLanguage = localStorage.getItem('emojiPanelLanguage') || 'en';\r\n\r\n// UI strings for headers and placeholders only\r\nconst uiStrings = {\r\n  // Events panel\r\n  eventsHeader: { en: \"Events\", ru: \"События\" },\r\n  // Ignored users panel\r\n  ignoredUsersHeader: { en: \"Ignored\", ru: \"Игнорируемые\" },\r\n  ignoredUsersSubheaderForever: { en: \"Forever\", ru: \"Навсегда\" },\r\n  ignoredUsersSubheaderTemporary: { en: \"Temporary\", ru: \"Временно\" },\r\n  ignoredUsersPlaceholder: { en: \"Enter username\", ru: \"Введите никнейм\" },\r\n  ignoredBlockButton: { en: \"Block\", ru: \"Бан\" },\r\n  // Username colors panel\r\n  usernameColorsHeader: { en: \"Username Colors\", ru: \"Пользовательские цвета\" },\r\n  generatedColorsHeader: { en: \"Generated Colors\", ru: \"Сгенерированные цвета\" },\r\n  savedColorsHeader: { en: \"Saved Colors\", ru: \"Сохранённые цвета\" },\r\n  // Themes panel\r\n  themesPanelHeader: { en: \"Themes\", ru: \"Темы\" },\r\n  themesLightHeader: { en: \"Light Themes\", ru: \"Светлые темы\" },\r\n  themesDarkHeader: { en: \"Dark Themes\", ru: \"Тёмные темы\" },\r\n  // Message remover buttons\r\n  deleteButton: { en: \"Delete\", ru: \"Удалить\" },\r\n  ignoreButton: { en: \"Ignore\", ru: \"Игнорировать\" },\r\n  ignore1Hour: { en: \"1 Hour\", ru: \"1 час\" },\r\n  ignore1Day: { en: \"1 Day\", ru: \"1 день\" },\r\n  ignoreForever: { en: \"Forever\", ru: \"Навсегда\" },\r\n  ignoreCustomMinutes: { en: \"Minutes\", ru: \"Минуты\" },\r\n  ignoreCustomPrompt: { en: \"Enter minutes to ignore:\", ru: \"Введите количество минут для игнора:\" },\r\n};\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/definitions.js?");

/***/ }),

/***/ "./src/data/emojiData.js":
/*!*******************************!*\
  !*** ./src/data/emojiData.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   emojiData: () => (/* binding */ emojiData),\n/* harmony export */   emojiKeywords: () => (/* binding */ emojiKeywords)\n/* harmony export */ });\nconst emojiData = {\r\n  smileys: [\r\n    // Face smiling\r\n    '😀', '😃', '😄', '😆', '😁', '😅', '😂', '🤣', '🥲', '☺️', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😙', '😚', '😗', '😘',\r\n    '😋', '🥸', '😵‍💫',\r\n    // Face affection\r\n    '😛', '😝', '😜', '🤪', '😎', '🤓', '🧐', '🤨', '🤩', '🥳', '😏', '😒', '😞', '😔', '😟', '😕', '🙁', '☹️', '😣', '😖', '😫',\r\n    // Face tongue\r\n    '😩', '🥺', '😢', '😭', '😤', '😠', '😡', '🤬', '🤯', '😳', '🥵', '🥶', '😱', '😨', '😰', '😥', '😓', '🤗', '🤔', '🤭', '🤫',\r\n    // Face negative\r\n    '🤥', '😶', '😐', '😑', '😬', '🙄', '😯', '😦', '😧', '😮', '😲', '🥱', '😴', '🤤', '😪', '😵', '🤐', '🥴', '🤢', '🤮', '🤧',\r\n    // Face costume\r\n    '😷', '🤒', '🤕', '🤑', '🤠', '😈', '👿', '👹', '👺', '🤡', '💩', '👻', '💀', '☠️', '👽', '👾', '🤖', '🎃',\r\n    // Cat faces\r\n    '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾',\r\n    // Hand gestures\r\n    '👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎',\r\n    // Hand symbols\r\n    '✊', '👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏',\r\n    // Body parts\r\n    '✍️', '💅', '🤳', '💪', '🦾', '🦿', '🦵', '🦶', '👂', '🦻', '👃', '🧠', '🫀', '🫁', '🦷', '🦴', '👀', '👁️', '👅', '👄',\r\n    // Person\r\n    '👶', '🧒', '👦', '👧', '🧑', '👱', '👨', '🧔', '👩', '🧓', '👴', '👵', '🙍', '🙎', '🙅', '🙆', '💁', '🙋', '🧏', '🙇', '🤦', '🤷',\r\n    // Professional\r\n    '👮', '🕵️', '💂', '🥷', '👷', '🤴', '👸', '👳', '👲', '🧕', '🤵', '👰', '🤰', '🤱', '👼', '🎅', '🤶', '🦸', '🦹', '🧙', '🧚', '🧛', '🧜'\r\n  ],\r\n\r\n  nature: [\r\n    // Mammals\r\n    '🐵', '🐒', '🦍', '🦧', '🐶', '🐕', '🦮', '🐕‍🦺', '🐩', '🐺', '🦊', '🦝', '🐱', '🐈', '🐈‍⬛', '🦁', '🐯', '🐅', '🐆', '🐴', '🐎',\r\n    '🦄', '🦓', '🦌', '🦬', '🐮', '🐂', '🐃', '🐄', '🐷', '🐖', '🐗', '🐽', '🐏', '🐑', '🐐', '🐪', '🐫', '🦙', '🦒', '🐘', '🦏',\r\n    '🦛', '🐭', '🐁', '🐀', '🐹', '🐰', '🐇', '🦫', '🦘', '🦡', '🐿️', '🦔', '🦦', '🦥', '🐼', '🦨', '🦘', '🦡',\r\n    // Birds\r\n    '🦃', '🐔', '🐓', '🐣', '🐤', '🐥', '🐦', '🐧', '🕊️', '🦅', '🦆', '🦢', '🦉', '🦤', '🪶', '🦩', '🦚', '🦜',\r\n    // Reptiles/Amphibians\r\n    '🐸', '🐊', '🐢', '🦎', '🐍', '🐲', '🐉', '🦕', '🦖',\r\n    // Marine\r\n    '🐳', '🐋', '🐬', '🦭', '🐟', '🐠', '🐡', '🦈', '🐙', '🐚', '🪸',\r\n    // Insects\r\n    '🐌', '🦋', '🐛', '🐜', '🐝', '🪲', '🐞', '🦗', '🪳', '🕷️', '🕸️', '🦂', '🦟', '🪰', '🪱',\r\n    // Plants\r\n    '🌸', '💮', '🏵️', '🌹', '🥀', '🌺', '🌻', '🌼', '🌷', '🌱', '🪴', '🌲', '🌳', '🌴', '🌵', '🌾', '🌿', '☘️', '🍀', '🍁', '🍂', '🍃'\r\n  ],\r\n\r\n  food: [\r\n    // Fruits\r\n    '🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍈', '🍒', '🍑', '🥭', '🍍', '🥥', '🥝',\r\n    // Vegetables\r\n    '🍅', '🍆', '🥑', '🥦', '🥬', '🥒', '🌶️', '🫑', '🥕', '🧄', '🧅', '🥔', '🍠', '🥐', '🥯', '🍞', '🥖', '🥨',\r\n    // Prepared\r\n    '🧀', '🥚', '🍳', '🥓', '🥩', '🍗', '🍖', '🦴', '🌭', '🍔', '🍟', '🍕', '🫓', '🥪', '🥙', '🧆', '🌮', '🌯', '🫔', '🥗',\r\n    // Asian\r\n    '🥘', '🫕', '🥫', '🍝', '🍜', '🍲', '🍛', '🍣', '🍱', '🥟', '🦪', '🍤', '🍙', '🍚', '🍘', '🍥', '🥠', '🥮',\r\n    // Sweets\r\n    '🍢', '🍡', '🍧', '🍨', '🍦', '🥧', '🧁', '🍰', '🎂', '🍮', '🍭', '🍬', '🍫', '🍿', '🍩', '🍪',\r\n    // Drink\r\n    '🫖', '☕', '🍵', '🧃', '🥤', '🧋', '🍶', '🍺', '🍻', '🥂', '🍷', '🥃', '🍸', '🍹', '🧉', '🍾'\r\n  ],\r\n\r\n  activities: [\r\n    // Sports\r\n    '⚽', '🏀', '🏈', '⚾', '🥎', '🎾', '🏐', '🏉', '🥏', '🎱', '🪀', '🏓', '🏸', '🏒', '🏑', '🥍', '🏏', '⛳', '🪁', '🎣',\r\n    '🤿', '🎽', '🛹', '🛼', '🛷', '⛸️', '🥌', '⛷️', '🏂', '🪂', '🏋️', '🤼', '🤸', '⛹️', '🤾', '🏌️', '🏇', '🧘', '🏄', '🏊',\r\n    // Activities\r\n    '🤽', '🚣', '🧗', '🚴', '🚵', '🎪', '🎭', '🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁', '🎷', '🎺', '🎸', '🎻', '🎲', '🎯',\r\n    '🎳', '🎮', '🎰', '🧩', '🎪', '🎫', '🎟️'\r\n  ],\r\n\r\n  travel: [\r\n    // Land transport\r\n    '🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🛻', '🚚', '🚛', '🚜', '🛵', '🏍️', '🛺', '🚲', '🛴',\r\n    // Air transport\r\n    '✈️', '🛩️', '🛫', '🛬', '🚁', '🚀', '🛸',\r\n    // Water transport\r\n    '🛶', '⛵', '🚤', '🛥️', '🛳️', '⛴️', '🚢',\r\n    // Places\r\n    '🏰', '🏯', '🏟️', '🏖️', '🏝️', '🏜️', '🌋', '⛰️', '🏔️', '🗻', '🏕️', '🏭', '🏢', '🏬', '🏣', '🏤', '🏥', '🏦', '🏨',\r\n    '🏪', '🏫', '🏩', '💒', '⛪', '🕌', '🕍', '🛕', '⛩️', '🏛️'\r\n  ],\r\n\r\n  objects: [\r\n    // Tools\r\n    '📱', '💻', '⌨️', '🖥️', '🖨️', '🖱️', '🖲️', '🕹️', '🗜️', '💽', '💾', '💿', '📀', '📼', '📷', '📸', '📹', '🎥',\r\n    // Office\r\n    '📞', '☎️', '📟', '📠', '📺', '📻', '🎙️', '🎚️', '🎛️', '📡', '🔋', '🔌', '💡', '🔦', '🕯️',\r\n    // Household\r\n    '🧯', '🛢️', '💸', '💵', '💴', '💶', '💷', '🪙', '💰', '💳', '💎', '⚖️', '🪜', '🧰', '🔧', '🔨', '⚒️', '🛠️', '⛏️',\r\n    // Writing\r\n    '✏️', '🖊️', '🖋️', '✒️', '🖌️', '🖍️', '📝', '📚', '📖', '🔖', '📑', '🗒️', '📄', '📰', '🗞️', '📁', '📂', '🗂️',\r\n    // Clocks (additional clock emojis)\r\n    '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕰️', '⏰', '⏱️', '⏲️', '⌚'\r\n  ],\r\n\r\n  symbols: [\r\n    // Hearts\r\n    '❤️', '🧡', '💛', '💚', '💙', '💜', '🤎', '🖤', '🤍', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟',\r\n    // Religion\r\n    '☮️', '✝️', '☪️', '🕉️', '☸️', '✡️', '🔯', '🕎', '☯️', '☦️', '🛐', '⛎',\r\n    // Warning\r\n    '⚠️', '🚸', '⛔', '🚫', '☢️', '☣️',\r\n    // Math\r\n    '➕', '➖', '➗', '✖️', '♾️', '💲', '💱',\r\n    // Arrows\r\n    '⬆️', '↗️', '➡️', '↘️', '⬇️', '↙️', '⬅️', '↖️', '↕️', '↔️', '↩️', '↪️', '⤴️', '⤵️', '🔃', '🔄',\r\n    // Other\r\n    '🔆', '📶', '🎦', '🔅', '♻️', '✅', '❌', '❎', '➰', '➿', '〽️', '✳️', '✴️', '❇️', '©️', '®️', '™️'\r\n  ],\r\n\r\n  flags: [\r\n    // Special flags\r\n    '🏁', '🚩', '🎌', '🏴', '🏳️', '🏳️‍🌈', '🏳️‍⚧️', '🏴‍☠️',\r\n    // Country flags (sample)\r\n    '🇺🇸', '🇬🇧', '🇯🇵', '🇰🇷', '🇩🇪', '🇨🇳', '🇧🇷', '🇮🇳', '🇫🇷', '🇪🇸', '🇮🇹', '🇷🇺', '🇨🇦', '🇦🇺', '🇳🇿',\r\n    // More popular country flags\r\n    '🇲🇽', '🇦🇷', '🇵🇰', '🇪🇬', '🇸🇪', '🇳🇴', '🇳🇱', '🇨🇭', '🇹🇷', '🇮🇩', '🇸🇬', '🇮🇱', '🇵🇹', '🇵🇱', '🇹🇭'\r\n  ]\r\n};\r\n\r\nconst emojiKeywords = {\r\n  //------------------------- Smileys & Emotion -------------------------\r\n  // Face smiling\r\n  '😀': {\r\n    en: ['grinning', 'face', 'smile', 'happy', 'joy'],\r\n    ru: ['улыбающийся', 'лицо', 'улыбка', 'счастливый', 'радость']\r\n  },\r\n  '😃': {\r\n    en: ['smiley', 'face', 'happy', 'joy', 'laugh'],\r\n    ru: ['улыбчивый', 'лицо', 'счастливый', 'радость', 'смех']\r\n  },\r\n  '😄': {\r\n    en: ['laughing', 'face', 'happy', 'joy', 'grin'],\r\n    ru: ['смеющийся', 'лицо', 'счастливый', 'радость', 'ухмылка']\r\n  },\r\n  '😆': {\r\n    en: ['grinning face', 'laugh'],\r\n    ru: ['улыбка', 'смех']\r\n  },\r\n  '😁': {\r\n    en: ['beaming', 'face', 'grin', 'smile', 'happy'],\r\n    ru: ['сияющий', 'лицо', 'улыбка', 'счастье', 'радость']\r\n  },\r\n  '😅': {\r\n    en: ['sweat', 'nervous', 'face', 'laugh', 'relief'],\r\n    ru: ['пот', 'нервный', 'лицо', 'смех', 'облегчение']\r\n  },\r\n  '😂': {\r\n    en: ['tears', 'joy', 'face', 'laugh', 'happy'],\r\n    ru: ['слёзы', 'радость', 'лицо', 'смех', 'счастье']\r\n  },\r\n  '🤣': {\r\n    en: ['rolling', 'floor', 'laugh', 'funny', 'amused'],\r\n    ru: ['катающийся', 'пол', 'смех', 'смешной', 'развлечённый']\r\n  },\r\n  '🥲': {\r\n    en: ['smiling', 'tear', 'bittersweet', 'nostalgic', 'happy'],\r\n    ru: ['улыбающийся', 'слеза', 'горько-сладкий', 'ностальгический', 'счастливый']\r\n  },\r\n  '☺️': {\r\n    en: ['smile', 'blush', 'content', 'peaceful'],\r\n    ru: ['улыбка', 'румянец', 'довольный', 'спокойный']\r\n  },\r\n  '😊': {\r\n    en: ['smiling', 'happy', 'blushing', 'content'],\r\n    ru: ['улыбающийся', 'счастливый', 'румянец', 'довольный']\r\n  },\r\n  '😇': {\r\n    en: ['angel', 'halo', 'innocent', 'saint', 'pure'],\r\n    ru: ['ангел', 'ореол', 'невинный', 'святой', 'чистый']\r\n  },\r\n  '🙂': {\r\n    en: ['slight', 'smile', 'face', 'mild'],\r\n    ru: ['слегка', 'улыбка', 'лицо', 'умеренный']\r\n  },\r\n  '🙃': {\r\n    en: ['upside-down', 'silly', 'quirky', 'funny'],\r\n    ru: ['перевернутый', 'глупый', 'странный', 'смешной']\r\n  },\r\n  '😉': {\r\n    en: ['wink', 'flirt', 'playful', 'smile'],\r\n    ru: ['подмигивание', 'флирт', 'игривый', 'улыбка']\r\n  },\r\n  '😌': {\r\n    en: ['relieved', 'calm', 'content', 'satisfied'],\r\n    ru: ['облегчённый', 'спокойный', 'довольный', 'удовлетворённый']\r\n  },\r\n  '😍': {\r\n    en: ['heart', 'love', 'smiling', 'eyes', 'adore'],\r\n    ru: ['сердце', 'любовь', 'улыбающийся', 'глаза', 'обожать']\r\n  },\r\n  '🥰': {\r\n    en: ['love', 'hearts', 'affection', 'adoration', 'cuddle'],\r\n    ru: ['любовь', 'сердца', 'нежность', 'обожание', 'обниматься']\r\n  },\r\n  '😙': {\r\n    en: ['kiss', 'love', 'affection', 'flirt'],\r\n    ru: ['поцелуй', 'любовь', 'нежность', 'флирт']\r\n  },\r\n  '😗': {\r\n    en: ['kiss', 'face', 'smile', 'affection'],\r\n    ru: ['поцелуй', 'лицо', 'улыбка', 'нежность']\r\n  },\r\n  '😚': {\r\n    en: ['kiss', 'closed eyes', 'affection', 'love'],\r\n    ru: ['поцелуй', 'закрытые глаза', 'нежность', 'любовь']\r\n  },\r\n  '😘': {\r\n    en: ['kiss', 'love', 'affection', 'flirt'],\r\n    ru: ['поцелуй', 'любовь', 'нежность', 'флирт']\r\n  },\r\n  '😋': {\r\n    en: ['yum', 'delicious', 'tasty', 'savor', 'lick'],\r\n    ru: ['ням', 'вкусно', 'аппетитно', 'наслаждаться', 'лизать']\r\n  },\r\n  '🥸': {\r\n    en: ['disguise', 'glasses', 'funny', 'sneaky', 'face'],\r\n    ru: ['маскировка', 'очки', 'смешной', 'хитрый', 'лицо']\r\n  },\r\n  '😵‍💫': {\r\n    en: ['dizzy', 'spiral eyes', 'confused', 'hypnotized', 'disoriented'],\r\n    ru: ['головокружение', 'спиральные глаза', 'запутанный', 'загипнотизированный', 'дезориентированный']\r\n  },\r\n\r\n  // Face affection\r\n  '😛': {\r\n    en: ['tongue', 'playful', 'cheeky', 'silly'],\r\n    ru: ['язык', 'игривый', 'нахальный', 'глупый']\r\n  },\r\n  '😝': {\r\n    en: ['tongue', 'silly', 'wacky', 'fun'],\r\n    ru: ['язык', 'глупый', 'безумный', 'весёлый']\r\n  },\r\n  '😜': {\r\n    en: ['tongue', 'wink', 'playful', 'fun'],\r\n    ru: ['язык', 'подмигивание', 'игривый', 'весёлый']\r\n  },\r\n  '🤪': {\r\n    en: ['crazy', 'wacky', 'zany', 'quirky'],\r\n    ru: ['сумасшедший', 'безумный', 'чудаковатый', 'странный']\r\n  },\r\n  '😎': {\r\n    en: ['cool', 'sunglasses', 'confident', 'chill'],\r\n    ru: ['крутой', 'очки', 'уверенный', 'расслабленный']\r\n  },\r\n  '🤓': {\r\n    en: ['nerd', 'geek', 'glasses', 'studious'],\r\n    ru: ['ботан', 'задрот', 'очки', 'учёный']\r\n  },\r\n  '🧐': {\r\n    en: ['monocle', 'investigative', 'curious', 'thoughtful'],\r\n    ru: ['одноглазый', 'расследовательский', 'любопытный', 'задумчивый']\r\n  },\r\n  '🤨': {\r\n    en: ['skeptical', 'doubtful', 'uncertain', 'raised eyebrow'],\r\n    ru: ['скептический', 'сомневающийся', 'неуверенный', 'поднятая бровь']\r\n  },\r\n  '🤩': {\r\n    en: ['starstruck', 'amazed', 'excited', 'admire'],\r\n    ru: ['восхищённый', 'поражённый', 'взволнованный', 'обожать']\r\n  },\r\n  '🥳': {\r\n    en: ['party', 'celebrate', 'birthday', 'festive'],\r\n    ru: ['вечеринка', 'праздновать', 'день рождения', 'праздничный']\r\n  },\r\n  '😏': {\r\n    en: ['smirk', 'sly', 'mischievous', 'confident'],\r\n    ru: ['ухмылка', 'хитрый', 'озорной', 'уверенный']\r\n  },\r\n  '😒': {\r\n    en: ['unamused', 'displeased', 'bored', 'sigh'],\r\n    ru: ['неудовлетворённый', 'недовольный', 'скучный', 'вздох']\r\n  },\r\n  '😞': {\r\n    en: ['disappointed', 'sad', 'down', 'somber'],\r\n    ru: ['разочарованный', 'грустный', 'унылый', 'мрачный']\r\n  },\r\n  '😔': {\r\n    en: ['pensive', 'sad', 'reflective', 'mournful'],\r\n    ru: ['задумчивый', 'грустный', 'рефлексивный', 'скорбный']\r\n  },\r\n  '😟': {\r\n    en: ['worried', 'concerned', 'anxious', 'upset'],\r\n    ru: ['обеспокоенный', 'тревожный', 'беспокойный', 'расстроенный']\r\n  },\r\n  '😕': {\r\n    en: ['confused', 'perplexed', 'uncertain', 'baffled'],\r\n    ru: ['смущённый', 'озадаченный', 'неуверенный', 'в замешательстве']\r\n  },\r\n  '🙁': {\r\n    en: ['frowning', 'sad', 'disappointed', 'downcast'],\r\n    ru: ['хмурый', 'грустный', 'разочарованный', 'угнетённый']\r\n  },\r\n  '☹️': {\r\n    en: ['frowning', 'sad', 'unhappy', 'mournful'],\r\n    ru: ['хмурый', 'грустный', 'несчастный', 'скорбный']\r\n  },\r\n  '😣': {\r\n    en: ['strained', 'persevering', 'tired', 'discomfort'],\r\n    ru: ['напряжённый', 'терпеливый', 'уставший', 'дискомфорт']\r\n  },\r\n  '😖': {\r\n    en: ['confounded', 'annoyed', 'distressed', 'exasperated'],\r\n    ru: ['озадаченный', 'раздражённый', 'огорчённый', 'изнурённый']\r\n  },\r\n  '😫': {\r\n    en: ['tired', 'exhausted', 'weary', 'worn out'],\r\n    ru: ['усталый', 'измученный', 'изнурённый', 'измотанный']\r\n  },\r\n\r\n  // Face tongue\r\n  '😩': {\r\n    en: ['weary', 'tired', 'exhausted', 'overwhelmed'],\r\n    ru: ['изнурённый', 'уставший', 'измученный', 'перегруженный']\r\n  },\r\n  '🥺': {\r\n    en: ['pleading', 'begging', 'cute', 'vulnerable'],\r\n    ru: ['умоляющий', 'просьба', 'милый', 'уязвимый']\r\n  },\r\n  '😢': {\r\n    en: ['cry', 'sad', 'tear', 'sorrow'],\r\n    ru: ['плакать', 'грустный', 'слеза', 'печаль']\r\n  },\r\n  '😭': {\r\n    en: ['crying', 'tearful', 'sad', 'heartbroken'],\r\n    ru: ['плачущий', 'со слезами', 'грустный', 'с разбитым сердцем']\r\n  },\r\n  '😤': {\r\n    en: ['triumphant', 'exasperated', 'proud', 'angry'],\r\n    ru: ['триумфальный', 'раздражённый', 'гордый', 'сердитый']\r\n  },\r\n  '😠': {\r\n    en: ['angry', 'mad', 'annoyed', 'irate'],\r\n    ru: ['сердитый', 'злой', 'раздражённый', 'яростный']\r\n  },\r\n  '😡': {\r\n    en: ['pouting', 'mad', 'furious', 'irate'],\r\n    ru: ['надувшийся', 'злой', 'яростный', 'взбешённый']\r\n  },\r\n  '🤬': {\r\n    en: ['cursing', 'swearing', 'angry', 'foul language'],\r\n    ru: ['ругательства', 'мат', 'сердитый', 'неприличный']\r\n  },\r\n  '🤯': {\r\n    en: ['mind blown', 'shocked', 'amazed', 'stunned'],\r\n    ru: ['взрыв мозга', 'шокированный', 'поражённый', 'ошеломлённый']\r\n  },\r\n  '😳': {\r\n    en: ['flushed', 'embarrassed', 'shocked', 'awkward'],\r\n    ru: ['покрасневший', 'смущённый', 'шокированный', 'неловкий']\r\n  },\r\n  '🥵': {\r\n    en: ['hot', 'overheated', 'sweaty', 'exhausted'],\r\n    ru: ['горячий', 'перегретый', 'потный', 'изнурённый']\r\n  },\r\n  '🥶': {\r\n    en: ['cold', 'freezing', 'chilly', 'frozen'],\r\n    ru: ['холодный', 'замерзающий', 'прохладный', 'замороженный']\r\n  },\r\n  '😱': {\r\n    en: ['screaming', 'horror', 'shock', 'fear'],\r\n    ru: ['кричащий', 'ужас', 'шок', 'страх']\r\n  },\r\n  '😨': {\r\n    en: ['fearful', 'scared', 'anxious', 'nervous'],\r\n    ru: ['боязливый', 'испуганный', 'тревожный', 'нервный']\r\n  },\r\n  '😰': {\r\n    en: ['anxious', 'nervous', 'sweating', 'scared'],\r\n    ru: ['тревожный', 'нервный', 'потеющий', 'испуганный']\r\n  },\r\n  '😥': {\r\n    en: ['disappointed', 'sad', 'pensive', 'teary'],\r\n    ru: ['разочарованный', 'грустный', 'задумчивый', 'со слезами']\r\n  },\r\n  '😓': {\r\n    en: ['cold sweat', 'nervous', 'anxious', 'tired'],\r\n    ru: ['холодный пот', 'нервный', 'тревожный', 'усталый']\r\n  },\r\n  '🤗': {\r\n    en: ['hug', 'embrace', 'caring', 'love'],\r\n    ru: ['объятие', 'принимать', 'заботливый', 'любовь']\r\n  },\r\n  '🤔': {\r\n    en: ['thinking', 'pondering', 'curious', 'confused'],\r\n    ru: ['думающий', 'размышляющий', 'любопытный', 'смущённый']\r\n  },\r\n  '🤭': {\r\n    en: ['guilty', 'shy', 'embarrassed', 'oops'],\r\n    ru: ['виноватый', 'застенчивый', 'смущённый', 'упс']\r\n  },\r\n  '🤫': {\r\n    en: ['quiet', 'secret', 'hush', 'shh'],\r\n    ru: ['тихий', 'секрет', 'тишина', 'ш-ш']\r\n  },\r\n\r\n  // Face negative\r\n  '🤥': {\r\n    en: ['lying', 'fib', 'deceitful', 'dishonest'],\r\n    ru: ['врущий', 'ложь', 'обманчивый', 'нечестный']\r\n  },\r\n  '😶': {\r\n    en: ['speechless', 'mute', 'quiet', 'blank'],\r\n    ru: ['безмолвный', 'немой', 'тихий', 'пустой']\r\n  },\r\n  '😐': {\r\n    en: ['neutral', 'expressionless', 'indifferent', 'flat'],\r\n    ru: ['нейтральный', 'без выражения', 'безразличный', 'плоский']\r\n  },\r\n  '😑': {\r\n    en: ['deadpan', 'expressionless', 'blank', 'unemotional'],\r\n    ru: ['без эмоций', 'без выражения', 'пустой', 'неэмоциональный']\r\n  },\r\n  '😬': {\r\n    en: ['grimace', 'awkward', 'nervous', 'tense'],\r\n    ru: ['гримаса', 'неловко', 'нервный', 'напряжённый']\r\n  },\r\n  '🙄': {\r\n    en: ['eye roll', 'sarcastic', 'disdain', 'bored'],\r\n    ru: ['закатывание глаз', 'саркастичный', 'пренебрежительный', 'скучный']\r\n  },\r\n  '😯': {\r\n    en: ['hushed', 'surprised', 'shocked', 'amazed'],\r\n    ru: ['тихий', 'удивлённый', 'шокированный', 'поражённый']\r\n  },\r\n  '😦': {\r\n    en: ['frowning', 'dismayed', 'shocked', 'surprised'],\r\n    ru: ['хмурый', 'огорчённый', 'шокированный', 'удивлённый']\r\n  },\r\n  '😧': {\r\n    en: ['astonished', 'stunned', 'surprised', 'speechless'],\r\n    ru: ['изумлённый', 'ошеломлённый', 'удивлённый', 'безмолвный']\r\n  },\r\n  '😮': {\r\n    en: ['open mouth', 'surprised', 'shocked', 'amazed'],\r\n    ru: ['открытый рот', 'удивлённый', 'шокированный', 'поражённый']\r\n  },\r\n  '😲': {\r\n    en: ['astonished', 'stunned', 'shocked', 'in awe'],\r\n    ru: ['изумлённый', 'ошеломлённый', 'шокированный', 'в благоговении']\r\n  },\r\n  '🥱': {\r\n    en: ['yawning', 'sleepy', 'tired', 'bored'],\r\n    ru: ['зевота', 'сонный', 'усталый', 'скучный']\r\n  },\r\n  '😴': {\r\n    en: ['sleeping', 'tired', 'napping', 'dozing'],\r\n    ru: ['спящий', 'усталый', 'дремлющий', 'засыпающий']\r\n  },\r\n  '🤤': {\r\n    en: ['drooling', 'desire', 'craving', 'hungry'],\r\n    ru: ['слюнявый', 'желание', 'тяга', 'голодный']\r\n  },\r\n  '😪': {\r\n    en: ['sleepy', 'drowsy', 'tired', 'nodding'],\r\n    ru: ['сонный', 'вялый', 'усталый', 'кивающий']\r\n  },\r\n  '😵': {\r\n    en: ['dizzy', 'knocked out', 'stunned', 'confused'],\r\n    ru: ['головокружительный', 'вырубленный', 'ошеломлённый', 'сбитый с толку']\r\n  },\r\n  '🤐': {\r\n    en: ['zipper-mouth', 'secretive', 'quiet', 'mute'],\r\n    ru: ['закрытый рот', 'секретный', 'тихий', 'немой']\r\n  },\r\n  '🥴': {\r\n    en: ['woozy', 'tipsy', 'dizzy', 'unsteady'],\r\n    ru: ['ошеломлённый', 'подошедший', 'головокружительный', 'неустойчивый']\r\n  },\r\n  '🤢': {\r\n    en: ['nauseated', 'sick', 'disgusted', 'vomit'],\r\n    ru: ['тошнотворный', 'больной', 'отвратительный', 'рвота']\r\n  },\r\n  '🤮': {\r\n    en: ['vomiting', 'nauseous', 'sick', 'disgust'],\r\n    ru: ['рвота', 'тошнотворный', 'больной', 'отвратительный']\r\n  },\r\n  '🤧': {\r\n    en: ['sneezing', 'ill', 'sick', 'allergy'],\r\n    ru: ['чихание', 'болен', 'больной', 'аллергия']\r\n  },\r\n\r\n  // Face costume\r\n  '😷': {\r\n    en: ['mask', 'sick', 'ill', 'health'],\r\n    ru: ['маска', 'больной', 'нездоровый', 'здоровье']\r\n  },\r\n  '🤒': {\r\n    en: ['fever', 'sick', 'ill', 'unwell'],\r\n    ru: ['лихорадка', 'больной', 'нездоровый', 'неважно']\r\n  },\r\n  '🤕': {\r\n    en: ['injured', 'hurt', 'bandaged', 'pain'],\r\n    ru: ['раненый', 'повреждённый', 'забинтованный', 'боль']\r\n  },\r\n  '🤑': {\r\n    en: ['money', 'rich', 'greedy', 'cash'],\r\n    ru: ['деньги', 'богатый', 'жадный', 'наличные']\r\n  },\r\n  '🤠': {\r\n    en: ['cowboy', 'hat', 'western', 'fun'],\r\n    ru: ['ковбой', 'шляпа', 'вестерн', 'веселье']\r\n  },\r\n  '😈': {\r\n    en: ['devil', 'mischievous', 'naughty', 'sinister'],\r\n    ru: ['дьявол', 'озорной', 'непослушный', 'зловещий']\r\n  },\r\n  '👿': {\r\n    en: ['angry', 'devil', 'evil', 'fiendish'],\r\n    ru: ['сердитый', 'дьявол', 'злой', 'зловещий']\r\n  },\r\n  '👹': {\r\n    en: ['ogre', 'demon', 'monster', 'scary'],\r\n    ru: ['огр', 'демон', 'монстр', 'страшный']\r\n  },\r\n  '👺': {\r\n    en: ['goblin', 'troll', 'spooky', 'creepy'],\r\n    ru: ['гоблин', 'тролль', 'жуткий', 'страшный']\r\n  },\r\n  '🤡': {\r\n    en: ['clown', 'silly', 'funny', 'circus'],\r\n    ru: ['клоун', 'глупый', 'смешной', 'цирк']\r\n  },\r\n  '💩': {\r\n    en: ['poop', 'crap', 'feces', 'funny'],\r\n    ru: ['какашка', 'дерьмо', 'фекалии', 'смешной']\r\n  },\r\n  '👻': {\r\n    en: ['ghost', 'spirit', 'haunted', 'scary'],\r\n    ru: ['призрак', 'дух', 'обитающий', 'страшный']\r\n  },\r\n  '💀': {\r\n    en: ['skull', 'death', 'creepy', 'spooky'],\r\n    ru: ['череп', 'смерть', 'жуткий', 'страшный']\r\n  },\r\n  '☠️': {\r\n    en: ['skull', 'danger', 'death', 'poison'],\r\n    ru: ['череп', 'опасность', 'смерть', 'яд']\r\n  },\r\n  '👽': {\r\n    en: ['alien', 'extraterrestrial', 'space', 'ufo'],\r\n    ru: ['инопланетянин', 'внеземной', 'космос', 'НЛО']\r\n  },\r\n  '👾': {\r\n    en: ['alien', 'monster', 'video game', 'retro'],\r\n    ru: ['инопланетянин', 'монстр', 'видеоигра', 'ретро']\r\n  },\r\n  '🤖': {\r\n    en: ['robot', 'machine', 'tech', 'android'],\r\n    ru: ['робот', 'машина', 'технология', 'андроид']\r\n  },\r\n  '🎃': {\r\n    en: ['pumpkin', 'halloween', 'spooky', 'festive'],\r\n    ru: ['тыква', 'Хэллоуин', 'жуткий', 'праздничный']\r\n  },\r\n\r\n  // Cat faces\r\n  '😺': {\r\n    en: ['smiling', 'cat', 'happy', 'playful'],\r\n    ru: ['улыбающийся', 'кот', 'счастливый', 'игривый']\r\n  },\r\n  '😸': {\r\n    en: ['grinning', 'cat', 'joyful', 'cheerful'],\r\n    ru: ['широко улыбающийся', 'кот', 'радостный', 'весёлый']\r\n  },\r\n  '😹': {\r\n    en: ['tearful', 'joy', 'cat', 'laughing'],\r\n    ru: ['со слезами', 'радость', 'кот', 'смеющийся']\r\n  },\r\n  '😻': {\r\n    en: ['heart', 'cat', 'love', 'adorable'],\r\n    ru: ['сердце', 'кот', 'любовь', 'милый']\r\n  },\r\n  '😼': {\r\n    en: ['smirking', 'cat', 'mischievous', 'sly'],\r\n    ru: ['ухмыляющийся', 'кот', 'озорной', 'хитрый']\r\n  },\r\n  '😽': {\r\n    en: ['kissing', 'cat', 'affection', 'cute'],\r\n    ru: ['целующий', 'кот', 'нежность', 'милый']\r\n  },\r\n  '🙀': {\r\n    en: ['surprised', 'cat', 'scared', 'shocked'],\r\n    ru: ['испуганный', 'кот', 'испуганный', 'шокированный']\r\n  },\r\n  '😿': {\r\n    en: ['crying', 'cat', 'sad', 'tearful'],\r\n    ru: ['плачущий', 'кот', 'грустный', 'со слезами']\r\n  },\r\n  '😾': {\r\n    en: ['angry', 'cat', 'annoyed', 'displeased'],\r\n    ru: ['сердитый', 'кот', 'раздражённый', 'недовольный']\r\n  },\r\n\r\n  //------------------------- People & Body -------------------------\r\n  // Hand gestures\r\n  '👋': {\r\n    en: ['wave', 'hello', 'goodbye', 'greeting'],\r\n    ru: ['махание', 'привет', 'прощание', 'приветствие']\r\n  },\r\n  '🤚': {\r\n    en: ['raised hand', 'stop', 'palm'],\r\n    ru: ['поднятая рука', 'стой', 'ладонь']\r\n  },\r\n  '🖐️': {\r\n    en: ['hand', 'high five', 'greeting'],\r\n    ru: ['рука', 'дай пять', 'приветствие']\r\n  },\r\n  '✋': {\r\n    en: ['stop', 'palm', 'high five'],\r\n    ru: ['стой', 'ладонь', 'дай пять']\r\n  },\r\n  '🖖': {\r\n    en: ['vulcan salute', 'live long', 'sci-fi'],\r\n    ru: ['салют Вулканцев', 'живи долго', 'научная фантастика']\r\n  },\r\n  '👌': {\r\n    en: ['okay', 'perfect', 'good'],\r\n    ru: ['ок', 'идеально', 'хорошо']\r\n  },\r\n  '🤌': {\r\n    en: ['pinched', 'precise', 'delicious'],\r\n    ru: ['сжатый', 'точный', 'вкусный']\r\n  },\r\n  '🤏': {\r\n    en: ['small', 'tiny', 'minuscule'],\r\n    ru: ['маленький', 'крошечный', 'микроскопический']\r\n  },\r\n  '✌️': {\r\n    en: ['peace', 'victory', 'v sign'],\r\n    ru: ['мир', 'победа', 'знак победы']\r\n  },\r\n  '🤞': {\r\n    en: ['fingers crossed', 'hope', 'luck'],\r\n    ru: ['скрещенные пальцы', 'надежда', 'удача']\r\n  },\r\n  '🤟': {\r\n    en: ['I love you', 'rock on', 'sign language'],\r\n    ru: ['я тебя люблю', 'рок он', 'язык жестов']\r\n  },\r\n  '🤘': {\r\n    en: ['rock', 'metal', 'horns'],\r\n    ru: ['рок', 'металл', 'рога']\r\n  },\r\n  '🤙': {\r\n    en: ['call me', 'hang loose', 'shaka'],\r\n    ru: ['позвони мне', 'расслабься', 'шак']\r\n  },\r\n  '👈': {\r\n    en: ['point left', 'direction', 'arrow'],\r\n    ru: ['указание влево', 'направление', 'стрелка']\r\n  },\r\n  '👉': {\r\n    en: ['point right', 'direction', 'arrow'],\r\n    ru: ['указание вправо', 'направление', 'стрелка']\r\n  },\r\n  '👆': {\r\n    en: ['point up', 'direction', 'up'],\r\n    ru: ['указание вверх', 'направление', 'вверх']\r\n  },\r\n  '🖕': {\r\n    en: ['middle finger', 'offensive', 'rude'],\r\n    ru: ['средний палец', 'оскорбительный', 'грубый']\r\n  },\r\n  '👇': {\r\n    en: ['point down', 'direction', 'down'],\r\n    ru: ['указание вниз', 'направление', 'вниз']\r\n  },\r\n  '☝️': {\r\n    en: ['point up', 'number one', 'important'],\r\n    ru: ['указание вверх', 'номер один', 'важный']\r\n  },\r\n  '👍': {\r\n    en: ['thumbs up', 'good', 'approve'],\r\n    ru: ['палец вверх', 'хорошо', 'одобрить']\r\n  },\r\n  '👎': {\r\n    en: ['thumbs down', 'bad', 'disapprove'],\r\n    ru: ['палец вниз', 'плохо', 'не одобрять']\r\n  },\r\n\r\n  // Hand symbols\r\n  '✊': {\r\n    en: ['fist', 'power', 'solidarity'],\r\n    ru: ['кулак', 'сила', 'солидарность']\r\n  },\r\n  '👊': {\r\n    en: ['punch', 'fist bump', 'hit'],\r\n    ru: ['удар', 'кулачок', 'ударить']\r\n  },\r\n  '🤛': {\r\n    en: ['left fist', 'punch', 'strike'],\r\n    ru: ['левая рука', 'удар', 'нанести удар']\r\n  },\r\n  '🤜': {\r\n    en: ['right fist', 'punch', 'strike'],\r\n    ru: ['правая рука', 'удар', 'нанести удар']\r\n  },\r\n  '👏': {\r\n    en: ['clap', 'applause', 'bravo'],\r\n    ru: ['хлопки', 'аплодисменты', 'браво']\r\n  },\r\n  '🙌': {\r\n    en: ['celebrate', 'praise', 'hooray'],\r\n    ru: ['торжествовать', 'хвалить', 'ура']\r\n  },\r\n  '👐': {\r\n    en: ['open hands', 'embrace', 'welcome'],\r\n    ru: ['раскрытые руки', 'объятие', 'добро пожаловать']\r\n  },\r\n  '🤲': {\r\n    en: ['palms', 'offering', 'receive'],\r\n    ru: ['ладони', 'предложение', 'получать']\r\n  },\r\n  '🤝': {\r\n    en: ['handshake', 'agreement', 'cooperation'],\r\n    ru: ['рукопожатие', 'соглашение', 'сотрудничество']\r\n  },\r\n  '🙏': {\r\n    en: ['pray', 'thanks', 'please'],\r\n    ru: ['молиться', 'спасибо', 'пожалуйста']\r\n  },\r\n\r\n  // Body parts\r\n  '✍️': {\r\n    en: ['writing', 'pen', 'signature'],\r\n    ru: ['письмо', 'ручка', 'подпись']\r\n  },\r\n  '💅': {\r\n    en: ['nail polish', 'beauty', 'manicure'],\r\n    ru: ['лак для ногтей', 'красота', 'маникюр']\r\n  },\r\n  '🤳': {\r\n    en: ['selfie', 'photo', 'camera'],\r\n    ru: ['селфи', 'фото', 'камера']\r\n  },\r\n  '💪': {\r\n    en: ['flex', 'strong', 'muscle'],\r\n    ru: ['сгибать', 'сильный', 'мышцы']\r\n  },\r\n  '🦾': {\r\n    en: ['mechanical arm', 'robotic', 'cyborg'],\r\n    ru: ['механическая рука', 'роботизированный', 'киборг']\r\n  },\r\n  '🦿': {\r\n    en: ['mechanical leg', 'prosthetic', 'robotic'],\r\n    ru: ['механическая нога', 'протез', 'роботизированный']\r\n  },\r\n  '🦵': {\r\n    en: ['leg', 'limb', 'lower body'],\r\n    ru: ['нога', 'конечность', 'нижняя часть тела']\r\n  },\r\n  '🦶': {\r\n    en: ['foot', 'toes', 'step'],\r\n    ru: ['нога', 'пальцы ноги', 'шаг']\r\n  },\r\n  '👂': {\r\n    en: ['ear', 'listening', 'sound'],\r\n    ru: ['ухо', 'слушание', 'звук']\r\n  },\r\n  '🦻': {\r\n    en: ['hearing aid', 'listening', 'assistive'],\r\n    ru: ['слуховой аппарат', 'слушание', 'помощь']\r\n  },\r\n  '👃': {\r\n    en: ['nose', 'smell', 'scent'],\r\n    ru: ['нос', 'запах', 'аромат']\r\n  },\r\n  '🧠': {\r\n    en: ['brain', 'intelligence', 'mind'],\r\n    ru: ['мозг', 'интеллект', 'ум']\r\n  },\r\n  '🫀': {\r\n    en: ['heart (organ)', 'anatomy', 'biology'],\r\n    ru: ['сердце (орган)', 'анатомия', 'биология']\r\n  },\r\n  '🫁': {\r\n    en: ['lungs', 'breath', 'organ'],\r\n    ru: ['легкие', 'дыхание', 'орган']\r\n  },\r\n  '🦷': {\r\n    en: ['tooth', 'dental', 'smile'],\r\n    ru: ['зуб', 'стоматология', 'улыбка']\r\n  },\r\n  '🦴': {\r\n    en: ['bone', 'skeleton', 'hard'],\r\n    ru: ['кость', 'скелет', 'твердый']\r\n  },\r\n  '👀': {\r\n    en: ['eyes', 'look', 'see'],\r\n    ru: ['глаза', 'смотреть', 'видеть']\r\n  },\r\n  '👁️': {\r\n    en: ['eye', 'vision', 'watch'],\r\n    ru: ['глаз', 'зрение', 'наблюдать']\r\n  },\r\n  '👅': {\r\n    en: ['tongue', 'taste', 'lick'],\r\n    ru: ['язык', 'вкус', 'лизать']\r\n  },\r\n  '👄': {\r\n    en: ['lips', 'kiss', 'mouth'],\r\n    ru: ['губы', 'поцелуй', 'рот']\r\n  },\r\n\r\n  // Person\r\n  '👶': {\r\n    en: ['baby', 'infant', 'cute'],\r\n    ru: ['младенец', 'ребенок', 'милый']\r\n  },\r\n  '🧒': {\r\n    en: ['child', 'kid', 'youth'],\r\n    ru: ['ребенок', 'малыш', 'юный']\r\n  },\r\n  '👦': {\r\n    en: ['boy', 'child', 'kid'],\r\n    ru: ['мальчик', 'ребенок', 'малыш']\r\n  },\r\n  '👧': {\r\n    en: ['girl', 'child', 'kid'],\r\n    ru: ['девочка', 'ребенок', 'малышка']\r\n  },\r\n  '🧑': {\r\n    en: ['person', 'human', 'individual'],\r\n    ru: ['человек', 'личность', 'индивид']\r\n  },\r\n  '👱': {\r\n    en: ['blonde', 'person', 'light hair'],\r\n    ru: ['блондин', 'человек', 'светлые волосы']\r\n  },\r\n  '👨': {\r\n    en: ['man', 'male', 'guy'],\r\n    ru: ['мужчина', 'мужской', 'парень']\r\n  },\r\n  '🧔': {\r\n    en: ['bearded', 'man', 'facial hair'],\r\n    ru: ['бородатый', 'мужчина', 'борода']\r\n  },\r\n  '👩': {\r\n    en: ['woman', 'female', 'lady'],\r\n    ru: ['женщина', 'женский', 'дама']\r\n  },\r\n  '🧓': {\r\n    en: ['elderly', 'senior', 'aged'],\r\n    ru: ['пожилой', 'старший', 'в преклонном возрасте']\r\n  },\r\n  '👴': {\r\n    en: ['old man', 'elderly', 'senior'],\r\n    ru: ['старик', 'пожилой', 'старший']\r\n  },\r\n  '👵': {\r\n    en: ['old woman', 'elderly', 'senior'],\r\n    ru: ['старуха', 'пожилая', 'старшая']\r\n  },\r\n  '🙍': {\r\n    en: ['frowning', 'sad', 'displeased'],\r\n    ru: ['хмурый', 'грустный', 'недовольный']\r\n  },\r\n  '🙎': {\r\n    en: ['pouting', 'angry', 'displeased'],\r\n    ru: ['надувшийся', 'сердитый', 'недовольный']\r\n  },\r\n  '🙅': {\r\n    en: ['no', 'prohibited', 'refusal'],\r\n    ru: ['нет', 'запрещено', 'отказ']\r\n  },\r\n  '🙆': {\r\n    en: ['ok', 'acceptable', 'okay'],\r\n    ru: ['ок', 'приемлемо', 'хорошо']\r\n  },\r\n  '💁': {\r\n    en: ['information', 'help', 'assistance'],\r\n    ru: ['информация', 'помощь', 'поддержка']\r\n  },\r\n  '🙋': {\r\n    en: ['raising hand', 'question', 'volunteer'],\r\n    ru: ['поднимающая руку', 'вопрос', 'доброволец']\r\n  },\r\n  '🧏': {\r\n    en: ['deaf', 'listening', 'silent'],\r\n    ru: ['глухой', 'слушающий', 'безмолвный']\r\n  },\r\n  '🙇': {\r\n    en: ['bowing', 'apologetic', 'respect'],\r\n    ru: ['наклон', 'извиняющийся', 'уважение']\r\n  },\r\n  '🤦': {\r\n    en: ['facepalm', 'disbelief', 'oops'],\r\n    ru: ['лицо ладонь', 'недоверие', 'упс']\r\n  },\r\n  '🤷': {\r\n    en: ['shrug', 'uncertain', 'indifferent'],\r\n    ru: ['пожимание плечами', 'неуверенный', 'безразличный']\r\n  },\r\n\r\n  // Professional\r\n  '👮': {\r\n    en: ['police', 'officer', 'law'],\r\n    ru: ['полицейский', 'офицер', 'закон']\r\n  },\r\n  '🕵️': {\r\n    en: ['detective', 'spy', 'investigate'],\r\n    ru: ['детектив', 'шпион', 'расследование']\r\n  },\r\n  '💂': {\r\n    en: ['guard', 'soldier', 'military'],\r\n    ru: ['страж', 'солдат', 'военный']\r\n  },\r\n  '🥷': {\r\n    en: ['ninja', 'stealth', 'assassin'],\r\n    ru: ['ниндзя', 'скрытность', 'ассассин']\r\n  },\r\n  '👷': {\r\n    en: ['construction', 'worker', 'helmet'],\r\n    ru: ['строитель', 'рабочий', 'шлем']\r\n  },\r\n  '🤴': {\r\n    en: ['prince', 'royalty', 'king'],\r\n    ru: ['принц', 'королевская семья', 'король']\r\n  },\r\n  '👸': {\r\n    en: ['princess', 'royalty', 'queen'],\r\n    ru: ['принцесса', 'королевская семья', 'королева']\r\n  },\r\n  '👳': {\r\n    en: ['turban', 'cultural', 'tradition'],\r\n    ru: ['тюрбан', 'культура', 'традиция']\r\n  },\r\n  '👲': {\r\n    en: ['man with cap', 'cultural', 'traditional'],\r\n    ru: ['мужчина в кепке', 'культура', 'традиционный']\r\n  },\r\n  '🧕': {\r\n    en: ['woman with headscarf', 'cultural', 'modest'],\r\n    ru: ['женщина в платке', 'культурная', 'скромная']\r\n  },\r\n  '🤵': {\r\n    en: ['tuxedo', 'groom', 'formal'],\r\n    ru: ['смокинг', 'жених', 'официальный']\r\n  },\r\n  '👰': {\r\n    en: ['bride', 'wedding', 'formal'],\r\n    ru: ['невеста', 'свадьба', 'официальный']\r\n  },\r\n  '🤰': {\r\n    en: ['pregnant', 'expecting', 'mother'],\r\n    ru: ['беременная', 'ожидающая', 'мать']\r\n  },\r\n  '🤱': {\r\n    en: ['nursing', 'mother', 'baby'],\r\n    ru: ['кормящая', 'мать', 'ребенок']\r\n  },\r\n  '👼': {\r\n    en: ['angel', 'cherub', 'divine'],\r\n    ru: ['ангел', 'херувим', 'божественный']\r\n  },\r\n  '🎅': {\r\n    en: ['santa', 'christmas', 'jolly'],\r\n    ru: ['Санта', 'Рождество', 'радостный']\r\n  },\r\n  '🤶': {\r\n    en: ['mrs claus', 'christmas', 'holiday'],\r\n    ru: ['миссис Клаус', 'Рождество', 'праздник']\r\n  },\r\n  '🦸': {\r\n    en: ['superhero', 'power', 'hero'],\r\n    ru: ['супергерой', 'сила', 'герой']\r\n  },\r\n  '🦹': {\r\n    en: ['villain', 'bad', 'criminal'],\r\n    ru: ['злодей', 'плохой', 'преступник']\r\n  },\r\n  '🧙': {\r\n    en: ['wizard', 'magic', 'sorcery'],\r\n    ru: ['волшебник', 'магия', 'колдовство']\r\n  },\r\n  '🧚': {\r\n    en: ['fairy', 'magic', 'mystical'],\r\n    ru: ['фея', 'магия', 'мистический']\r\n  },\r\n  '🧛': {\r\n    en: ['vampire', 'dracula', 'undead'],\r\n    ru: ['вампир', 'Дракула', 'нежить']\r\n  },\r\n  '🧜': {\r\n    en: ['mermaid', 'mythical', 'ocean'],\r\n    ru: ['русалка', 'мифическая', 'океан']\r\n  },\r\n\r\n  //------------------------- Animals & Nature -------------------------\r\n  // Mammals\r\n  '🐵': {\r\n    en: ['monkey', 'ape', 'funny', 'mammal'],\r\n    ru: ['обезьяна', 'примат', 'смешной', 'млекопитающее']\r\n  },\r\n  '🐒': {\r\n    en: ['monkey', 'primate', 'curious'],\r\n    ru: ['обезьяна', 'примат', 'любопытный']\r\n  },\r\n  '🦍': {\r\n    en: ['gorilla', 'ape', 'strong', 'wild'],\r\n    ru: ['горилла', 'обезьяна', 'сильный', 'дикий']\r\n  },\r\n  '🦧': {\r\n    en: ['orangutan', 'ape', 'wild', 'mammal'],\r\n    ru: ['орангутан', 'обезьяна', 'дикий', 'млекопитающее']\r\n  },\r\n  '🐶': {\r\n    en: ['dog', 'puppy', 'pet', 'mammal'],\r\n    ru: ['собака', 'щенок', 'домашний питомец', 'млекопитающее']\r\n  },\r\n  '🐕': {\r\n    en: ['dog', 'canine', 'pet'],\r\n    ru: ['собака', 'псовой', 'домашний питомец']\r\n  },\r\n  '🦮': {\r\n    en: ['guide dog', 'service', 'assistance'],\r\n    ru: ['собака-поводырь', 'служебная', 'помощь']\r\n  },\r\n  '🐕‍🦺': {\r\n    en: ['service dog', 'working', 'assistance'],\r\n    ru: ['служебная собака', 'рабочая', 'помощь']\r\n  },\r\n  '🐩': {\r\n    en: ['poodle', 'dog', 'pet', 'fancy'],\r\n    ru: ['пудель', 'собака', 'домашний питомец', 'элегантный']\r\n  },\r\n  '🐺': {\r\n    en: ['wolf', 'wild', 'howl'],\r\n    ru: ['волк', 'дикий', 'воет']\r\n  },\r\n  '🦊': {\r\n    en: ['fox', 'cunning', 'wild'],\r\n    ru: ['лиса', 'хитрая', 'дикая']\r\n  },\r\n  '🦝': {\r\n    en: ['raccoon', 'mischievous', 'wild'],\r\n    ru: ['енот', 'озорной', 'дикий']\r\n  },\r\n  '🐱': {\r\n    en: ['cat', 'pet', 'feline'],\r\n    ru: ['кот', 'домашний питомец', 'кошачий']\r\n  },\r\n  '🐈': {\r\n    en: ['cat', 'feline', 'pet'],\r\n    ru: ['кот', 'кошачий', 'домашний питомец']\r\n  },\r\n  '🐈‍⬛': {\r\n    en: ['black cat', 'mysterious', 'feline'],\r\n    ru: ['чёрный кот', 'загадочный', 'кошачий']\r\n  },\r\n  '🦁': {\r\n    en: ['lion', 'king', 'wild', 'courage'],\r\n    ru: ['лев', 'король', 'дикий', 'отвага']\r\n  },\r\n  '🐯': {\r\n    en: ['tiger', 'wild', 'stripes', 'fierce'],\r\n    ru: ['тигр', 'дикий', 'полосатый', 'свирепый']\r\n  },\r\n  '🐅': {\r\n    en: ['tiger', 'stripes', 'wild'],\r\n    ru: ['тигр', 'полосатый', 'дикий']\r\n  },\r\n  '🐆': {\r\n    en: ['leopard', 'spots', 'wild', 'fast'],\r\n    ru: ['леопард', 'пятна', 'дикий', 'быстрый']\r\n  },\r\n  '🐴': {\r\n    en: ['horse', 'ride', 'equine'],\r\n    ru: ['лошадь', 'езда', 'конный']\r\n  },\r\n  '🐎': {\r\n    en: ['horse', 'racing', 'equine'],\r\n    ru: ['лошадь', 'гонки', 'конный']\r\n  },\r\n  '🦄': {\r\n    en: ['unicorn', 'magical', 'fantasy'],\r\n    ru: ['единорог', 'волшебный', 'фэнтези']\r\n  },\r\n  '🦓': {\r\n    en: ['zebra', 'stripes', 'wild'],\r\n    ru: ['зебра', 'полосатая', 'дикая']\r\n  },\r\n  '🦌': {\r\n    en: ['deer', 'antlers', 'forest'],\r\n    ru: ['олень', 'рога', 'лес']\r\n  },\r\n  '🦬': {\r\n    en: ['bison', 'buffalo', 'wild'],\r\n    ru: ['бизон', 'буйвол', 'дикий']\r\n  },\r\n  '🐮': {\r\n    en: ['cow', 'farm', 'bovine'],\r\n    ru: ['корова', 'ферма', 'коровий']\r\n  },\r\n  '🐂': {\r\n    en: ['ox', 'bull', 'bovine'],\r\n    ru: ['вол', 'бык', 'коровий']\r\n  },\r\n  '🐃': {\r\n    en: ['water buffalo', 'bovine', 'farm'],\r\n    ru: ['водный буйвол', 'коровий', 'ферма']\r\n  },\r\n  '🐄': {\r\n    en: ['cow', 'bovine', 'farm'],\r\n    ru: ['корова', 'коровий', 'ферма']\r\n  },\r\n  '🐷': {\r\n    en: ['pig', 'farm', 'oink'],\r\n    ru: ['свинья', 'ферма', 'хрюк']\r\n  },\r\n  '🐖': {\r\n    en: ['pig', 'swine', 'farm'],\r\n    ru: ['свинья', 'свинное животное', 'ферма']\r\n  },\r\n  '🐗': {\r\n    en: ['boar', 'wild', 'pig'],\r\n    ru: ['кабан', 'дикий', 'свинья']\r\n  },\r\n  '🐽': {\r\n    en: ['pig nose', 'snout'],\r\n    ru: ['свинной нос', 'хоботок']\r\n  },\r\n  '🐏': {\r\n    en: ['ram', 'sheep', 'male'],\r\n    ru: ['баран', 'овца', 'самец']\r\n  },\r\n  '🐑': {\r\n    en: ['sheep', 'wool', 'farm'],\r\n    ru: ['овца', 'шерсть', 'ферма']\r\n  },\r\n  '🐐': {\r\n    en: ['goat', 'farm', 'bleat'],\r\n    ru: ['коза', 'ферма', 'блеет']\r\n  },\r\n  '🐪': {\r\n    en: ['camel', 'desert', 'hump'],\r\n    ru: ['верблюд', 'пустыня', 'горб']\r\n  },\r\n  '🐫': {\r\n    en: ['camel', 'two-hump', 'desert'],\r\n    ru: ['двугорбый верблюд', 'двугорбый', 'пустыня']\r\n  },\r\n  '🦙': {\r\n    en: ['llama', 'alpaca', 'cute'],\r\n    ru: ['лама', 'альпака', 'милый']\r\n  },\r\n  '🦒': {\r\n    en: ['giraffe', 'tall', 'spots'],\r\n    ru: ['жираф', 'высокий', 'пятна']\r\n  },\r\n  '🐘': {\r\n    en: ['elephant', 'trunk', 'large'],\r\n    ru: ['слон', 'хобот', 'большой']\r\n  },\r\n  '🦏': {\r\n    en: ['rhinoceros', 'horn', 'tough'],\r\n    ru: ['носорог', 'рог', 'жесткий']\r\n  },\r\n  '🦛': {\r\n    en: ['hippopotamus', 'water', 'large'],\r\n    ru: ['бегемот', 'вода', 'большой']\r\n  },\r\n\r\n  // Birds\r\n  '🦃': {\r\n    en: ['turkey', 'bird', 'thanksgiving'],\r\n    ru: ['индейка', 'птица', 'День благодарения']\r\n  },\r\n  '🐔': {\r\n    en: ['chicken', 'rooster', 'hen'],\r\n    ru: ['курица', 'петух', 'курица (самка)']\r\n  },\r\n  '🐓': {\r\n    en: ['rooster', 'chicken', 'bird'],\r\n    ru: ['петух', 'курица', 'птица']\r\n  },\r\n  '🐣': {\r\n    en: ['hatching chick', 'baby', 'bird'],\r\n    ru: ['вылупляющийся цыплёнок', 'малыш', 'птица']\r\n  },\r\n  '🐤': {\r\n    en: ['chick', 'small', 'bird'],\r\n    ru: ['цыплёнок', 'маленький', 'птица']\r\n  },\r\n  '🐥': {\r\n    en: ['baby chicken', 'cute', 'bird'],\r\n    ru: ['цыплёнок', 'милый', 'птица']\r\n  },\r\n  '🐦': {\r\n    en: ['bird', 'tweet', 'wing'],\r\n    ru: ['птица', 'чирик', 'крыло']\r\n  },\r\n  '🐧': {\r\n    en: ['penguin', 'cold', 'bird'],\r\n    ru: ['пингвин', 'холодный', 'птица']\r\n  },\r\n  '🕊️': {\r\n    en: ['dove', 'peace', 'bird'],\r\n    ru: ['голубь', 'мир', 'птица']\r\n  },\r\n  '🦅': {\r\n    en: ['eagle', 'wild', 'bird'],\r\n    ru: ['орёл', 'дикий', 'птица']\r\n  },\r\n  '🦆': {\r\n    en: ['duck', 'water', 'bird'],\r\n    ru: ['утка', 'вода', 'птица']\r\n  },\r\n  '🦢': {\r\n    en: ['swan', 'graceful', 'bird'],\r\n    ru: ['лебедь', 'грациозный', 'птица']\r\n  },\r\n  '🦉': {\r\n    en: ['owl', 'wise', 'night', 'bird'],\r\n    ru: ['сова', 'мудрая', 'ночная', 'птица']\r\n  },\r\n  '🦤': {\r\n    en: ['dodo', 'extinct', 'bird'],\r\n    ru: ['додо', 'вымершая', 'птица']\r\n  },\r\n  '🪶': {\r\n    en: ['feather', 'light', 'bird'],\r\n    ru: ['перо', 'лёгкое', 'птица']\r\n  },\r\n  '🦩': {\r\n    en: ['flamingo', 'pink', 'bird'],\r\n    ru: ['фламинго', 'розовый', 'птица']\r\n  },\r\n  '🦚': {\r\n    en: ['peacock', 'colorful', 'bird'],\r\n    ru: ['павлин', 'яркий', 'птица']\r\n  },\r\n  '🦜': {\r\n    en: ['parrot', 'talkative', 'colorful'],\r\n    ru: ['попугай', 'болтливый', 'яркий']\r\n  },\r\n\r\n  // Reptiles/Amphibians\r\n  '🐸': {\r\n    en: ['frog', 'amphibian', 'green'],\r\n    ru: ['лягушка', 'амфибия', 'зелёная']\r\n  },\r\n  '🐊': {\r\n    en: ['crocodile', 'reptile', 'danger'],\r\n    ru: ['крокодил', 'рептилия', 'опасность']\r\n  },\r\n  '🐢': {\r\n    en: ['turtle', 'slow', 'reptile'],\r\n    ru: ['черепаха', 'медленная', 'рептилия']\r\n  },\r\n  '🦎': {\r\n    en: ['lizard', 'reptile', 'scaly'],\r\n    ru: ['ящерица', 'рептилия', 'чешуйчатая']\r\n  },\r\n  '🐍': {\r\n    en: ['snake', 'reptile', 'slither'],\r\n    ru: ['змея', 'рептилия', 'ползать']\r\n  },\r\n  '🐲': {\r\n    en: ['dragon face', 'mythical', 'dragon'],\r\n    ru: ['лицо дракона', 'мифический', 'дракон']\r\n  },\r\n  '🐉': {\r\n    en: ['dragon', 'mythical', 'fire'],\r\n    ru: ['дракон', 'мифический', 'огонь']\r\n  },\r\n  '🦕': {\r\n    en: ['dinosaur', 'sauropod', 'prehistoric'],\r\n    ru: ['динозавр', 'зауропод', 'доисторический']\r\n  },\r\n  '🦖': {\r\n    en: ['dinosaur', 'T-Rex', 'prehistoric'],\r\n    ru: ['динозавр', 'Ти-Рекс', 'доисторический']\r\n  },\r\n\r\n  // Marine\r\n  '🐳': {\r\n    en: ['whale', 'ocean', 'large'],\r\n    ru: ['кит', 'океан', 'большой']\r\n  },\r\n  '🐋': {\r\n    en: ['whale', 'ocean', 'big'],\r\n    ru: ['кит', 'океан', 'огромный']\r\n  },\r\n  '🐬': {\r\n    en: ['dolphin', 'ocean', 'friendly'],\r\n    ru: ['дельфин', 'океан', 'дружелюбный']\r\n  },\r\n  '🦭': {\r\n    en: ['seal', 'marine', 'cute'],\r\n    ru: ['тюлень', 'морской', 'милый']\r\n  },\r\n  '🐟': {\r\n    en: ['fish', 'ocean', 'swim'],\r\n    ru: ['рыба', 'океан', 'плавать']\r\n  },\r\n  '🐠': {\r\n    en: ['tropical fish', 'ocean', 'colorful'],\r\n    ru: ['тропическая рыба', 'океан', 'яркая']\r\n  },\r\n  '🐡': {\r\n    en: ['blowfish', 'puffer', 'ocean'],\r\n    ru: ['рыба-иглобрюх', 'фугу', 'океан']\r\n  },\r\n  '🦈': {\r\n    en: ['shark', 'ocean', 'dangerous'],\r\n    ru: ['акула', 'океан', 'опасная']\r\n  },\r\n  '🐙': {\r\n    en: ['octopus', 'marine', 'tentacles'],\r\n    ru: ['осьминог', 'морской', 'щупальца']\r\n  },\r\n  '🐚': {\r\n    en: ['shell', 'beach', 'ocean'],\r\n    ru: ['ракушка', 'пляж', 'океан']\r\n  },\r\n  '🪸': {\r\n    en: ['coral', 'reef', 'ocean'],\r\n    ru: ['коралл', 'риф', 'океан']\r\n  },\r\n\r\n  // Insects\r\n  '🐌': {\r\n    en: ['snail', 'slow', 'mollusk'],\r\n    ru: ['улитка', 'медленная', 'моллюск']\r\n  },\r\n  '🦋': {\r\n    en: ['butterfly', 'insect', 'colorful'],\r\n    ru: ['бабочка', 'насекомое', 'яркая']\r\n  },\r\n  '🐛': {\r\n    en: ['caterpillar', 'insect', 'larva'],\r\n    ru: ['гусеница', 'насекомое', 'личинка']\r\n  },\r\n  '🐜': {\r\n    en: ['ant', 'small', 'insect'],\r\n    ru: ['муравей', 'маленький', 'насекомое']\r\n  },\r\n  '🐝': {\r\n    en: ['bee', 'insect', 'honey'],\r\n    ru: ['пчела', 'насекомое', 'мёд']\r\n  },\r\n  '🪲': {\r\n    en: ['beetle', 'insect', 'bug'],\r\n    ru: ['жук', 'насекомое', 'баг']\r\n  },\r\n  '🐞': {\r\n    en: ['ladybug', 'insect', 'lucky'],\r\n    ru: ['божья коровка', 'насекомое', 'счастливая']\r\n  },\r\n  '🦗': {\r\n    en: ['cricket', 'insect', 'chirp'],\r\n    ru: ['сверчок', 'насекомое', 'щебет']\r\n  },\r\n  '🪳': {\r\n    en: ['cockroach', 'insect', 'pest'],\r\n    ru: ['таракан', 'насекомое', 'вредитель']\r\n  },\r\n  '🕷️': {\r\n    en: ['spider', 'arachnid', 'insect'],\r\n    ru: ['паук', 'паукообразное', 'насекомое']\r\n  },\r\n  '🕸️': {\r\n    en: ['web', 'spider', 'trap'],\r\n    ru: ['паутина', 'паук', 'ловушка']\r\n  },\r\n  '🦂': {\r\n    en: ['scorpion', 'insect', 'venom'],\r\n    ru: ['скорпион', 'насекомое', 'яд']\r\n  },\r\n  '🦟': {\r\n    en: ['mosquito', 'insect', 'bite'],\r\n    ru: ['комар', 'насекомое', 'укус']\r\n  },\r\n  '🪰': {\r\n    en: ['fly', 'insect', 'buzz'],\r\n    ru: ['муха', 'насекомое', 'жужжание']\r\n  },\r\n  '🪱': {\r\n    en: ['worm', 'earth', 'invertebrate'],\r\n    ru: ['червь', 'земля', 'беспозвоночное']\r\n  },\r\n\r\n  // Plants\r\n  '🌸': {\r\n    en: ['cherry blossom', 'flower', 'spring'],\r\n    ru: ['сакура', 'цветок', 'весна']\r\n  },\r\n  '💮': {\r\n    en: ['white flower', 'flower', 'symbol'],\r\n    ru: ['белый цветок', 'цветок', 'символ']\r\n  },\r\n  '🏵️': {\r\n    en: ['rosette', 'flower', 'decorative'],\r\n    ru: ['розетка', 'цветок', 'декоративный']\r\n  },\r\n  '🌹': {\r\n    en: ['rose', 'flower', 'love', 'romance'],\r\n    ru: ['роза', 'цветок', 'любовь', 'романтика']\r\n  },\r\n  '🥀': {\r\n    en: ['wilted flower', 'sad', 'decay'],\r\n    ru: ['увядший цветок', 'грусть', 'разложение']\r\n  },\r\n  '🌺': {\r\n    en: ['hibiscus', 'flower', 'tropical'],\r\n    ru: ['гибискус', 'цветок', 'тропический']\r\n  },\r\n  '🌻': {\r\n    en: ['sunflower', 'flower', 'summer'],\r\n    ru: ['подсолнух', 'цветок', 'лето']\r\n  },\r\n  '🌼': {\r\n    en: ['blossom', 'flower', 'spring'],\r\n    ru: ['цветение', 'цветок', 'весна']\r\n  },\r\n  '🌷': {\r\n    en: ['tulip', 'flower', 'spring'],\r\n    ru: ['тюльпан', 'цветок', 'весна']\r\n  },\r\n  '🌱': {\r\n    en: ['seedling', 'plant', 'growth'],\r\n    ru: ['сеянец', 'растение', 'рост']\r\n  },\r\n  '🪴': {\r\n    en: ['potted plant', 'indoor', 'green'],\r\n    ru: ['растение в горшке', 'в помещении', 'зелёное']\r\n  },\r\n  '🌲': {\r\n    en: ['evergreen', 'tree', 'forest'],\r\n    ru: ['вечнозелёное', 'дерево', 'лес']\r\n  },\r\n  '🌳': {\r\n    en: ['tree', 'nature', 'shade'],\r\n    ru: ['дерево', 'природа', 'тень']\r\n  },\r\n  '🌴': {\r\n    en: ['palm tree', 'tropical', 'beach'],\r\n    ru: ['пальма', 'тропический', 'пляж']\r\n  },\r\n  '🌵': {\r\n    en: ['cactus', 'desert', 'succulent'],\r\n    ru: ['кактус', 'пустыня', 'суккулент']\r\n  },\r\n  '🌾': {\r\n    en: ['sheaf', 'grain', 'farm'],\r\n    ru: ['сноп', 'зерно', 'ферма']\r\n  },\r\n  '🌿': {\r\n    en: ['herb', 'plant', 'leaf'],\r\n    ru: ['трава', 'растение', 'лист']\r\n  },\r\n  '☘️': {\r\n    en: ['shamrock', 'luck', 'clover'],\r\n    ru: ['клевер', 'удача', 'трилистник']\r\n  },\r\n  '🍀': {\r\n    en: ['four-leaf clover', 'luck', 'green'],\r\n    ru: ['клевер с четырьмя листьями', 'удача', 'зелёный']\r\n  },\r\n  '🍁': {\r\n    en: ['maple leaf', 'autumn', 'fall'],\r\n    ru: ['кленовый лист', 'осень', 'осенний']\r\n  },\r\n  '🍂': {\r\n    en: ['fallen leaf', 'autumn', 'nature'],\r\n    ru: ['опавший лист', 'осень', 'природа']\r\n  },\r\n  '🍃': {\r\n    en: ['leaf', 'wind', 'nature'],\r\n    ru: ['лист', 'ветер', 'природа']\r\n  },\r\n\r\n  //------------------------- Food & Drink -------------------------\r\n  // Fruits\r\n  '🍎': {\r\n    en: ['apple', 'red', 'fruit', 'healthy'],\r\n    ru: ['яблоко', 'красное', 'фрукт', 'полезное']\r\n  },\r\n  '🍐': {\r\n    en: ['pear', 'fruit', 'green', 'juicy'],\r\n    ru: ['груша', 'фрукт', 'зелёная', 'сочная']\r\n  },\r\n  '🍊': {\r\n    en: ['orange', 'fruit', 'citrus', 'vitamin C'],\r\n    ru: ['апельсин', 'фрукт', 'цитрус', 'витамин C']\r\n  },\r\n  '🍋': {\r\n    en: ['lemon', 'citrus', 'sour', 'yellow'],\r\n    ru: ['лимон', 'цитрус', 'кислый', 'жёлтый']\r\n  },\r\n  '🍌': {\r\n    en: ['banana', 'fruit', 'yellow', 'tropical'],\r\n    ru: ['банан', 'фрукт', 'жёлтый', 'тропический']\r\n  },\r\n  '🍉': {\r\n    en: ['watermelon', 'fruit', 'summer', 'refreshing'],\r\n    ru: ['арбуз', 'фрукт', 'лето', 'освежающий']\r\n  },\r\n  '🍇': {\r\n    en: ['grapes', 'fruit', 'purple', 'vine'],\r\n    ru: ['виноград', 'фрукт', 'фиолетовый', 'виноградная лоза']\r\n  },\r\n  '🍓': {\r\n    en: ['strawberry', 'fruit', 'red', 'sweet'],\r\n    ru: ['клубника', 'фрукт', 'красная', 'сладкая']\r\n  },\r\n  '🫐': {\r\n    en: ['blueberry', 'fruit', 'blue', 'healthy'],\r\n    ru: ['черника', 'фрукт', 'синяя', 'полезная']\r\n  },\r\n  '🍈': {\r\n    en: ['melon', 'fruit', 'sweet', 'green'],\r\n    ru: ['дыня', 'фрукт', 'сладкая', 'зелёная']\r\n  },\r\n  '🍒': {\r\n    en: ['cherry', 'fruit', 'red', 'sweet'],\r\n    ru: ['вишня', 'фрукт', 'красная', 'сладкая']\r\n  },\r\n  '🍑': {\r\n    en: ['peach', 'fruit', 'fuzzy', 'sweet'],\r\n    ru: ['персик', 'фрукт', 'шероховатый', 'сладкий']\r\n  },\r\n  '🥭': {\r\n    en: ['mango', 'fruit', 'tropical', 'yellow'],\r\n    ru: ['манго', 'фрукт', 'тропический', 'жёлтый']\r\n  },\r\n  '🍍': {\r\n    en: ['pineapple', 'fruit', 'tropical', 'spiky'],\r\n    ru: ['ананас', 'фрукт', 'тропический', 'колючий']\r\n  },\r\n  '🥥': {\r\n    en: ['coconut', 'tropical', 'fruit', 'white'],\r\n    ru: ['кокос', 'тропический', 'фрукт', 'белый']\r\n  },\r\n  '🥝': {\r\n    en: ['kiwi', 'fruit', 'green', 'tart'],\r\n    ru: ['киви', 'фрукт', 'зелёный', 'кисловатый']\r\n  },\r\n\r\n  // Vegetables\r\n  '🍅': {\r\n    en: ['tomato', 'vegetable', 'red', 'juicy'],\r\n    ru: ['помидор', 'овощ', 'красный', 'сочный']\r\n  },\r\n  '🍆': {\r\n    en: ['eggplant', 'vegetable', 'purple', 'aubergine'],\r\n    ru: ['баклажан', 'овощ', 'фиолетовый', 'баклажан']\r\n  },\r\n  '🥑': {\r\n    en: ['avocado', 'vegetable', 'green', 'healthy'],\r\n    ru: ['авокадо', 'овощ', 'зелёный', 'полезный']\r\n  },\r\n  '🥦': {\r\n    en: ['broccoli', 'vegetable', 'green', 'healthy'],\r\n    ru: ['брокколи', 'овощ', 'зелёный', 'полезный']\r\n  },\r\n  '🥬': {\r\n    en: ['leafy greens', 'vegetable', 'lettuce', 'healthy'],\r\n    ru: ['листья салата', 'овощ', 'салат', 'полезный']\r\n  },\r\n  '🥒': {\r\n    en: ['cucumber', 'vegetable', 'green', 'fresh'],\r\n    ru: ['огурец', 'овощ', 'зелёный', 'свежий']\r\n  },\r\n  '🌶️': {\r\n    en: ['chili pepper', 'spicy', 'red', 'hot'],\r\n    ru: ['чили', 'острый', 'красный', 'горячий']\r\n  },\r\n  '🫑': {\r\n    en: ['bell pepper', 'vegetable', 'colorful', 'sweet'],\r\n    ru: ['болгарский перец', 'овощ', 'разноцветный', 'сладкий']\r\n  },\r\n  '🥕': {\r\n    en: ['carrot', 'vegetable', 'orange', 'crunchy'],\r\n    ru: ['морковь', 'овощ', 'оранжевая', 'хрустящая']\r\n  },\r\n  '🧄': {\r\n    en: ['garlic', 'vegetable', 'aromatic', 'flavorful'],\r\n    ru: ['чеснок', 'овощ', 'ароматный', 'вкусный']\r\n  },\r\n  '🧅': {\r\n    en: ['onion', 'vegetable', 'strong', 'flavor'],\r\n    ru: ['лук', 'овощ', 'сильный', 'вкус']\r\n  },\r\n  '🥔': {\r\n    en: ['potato', 'vegetable', 'starchy', 'brown'],\r\n    ru: ['картофель', 'овощ', 'крахмалистый', 'коричневый']\r\n  },\r\n  '🍠': {\r\n    en: ['sweet potato', 'vegetable', 'orange', 'starchy'],\r\n    ru: ['батат', 'овощ', 'оранжевый', 'крахмалистый']\r\n  },\r\n\r\n  // Breads & Baked Goods\r\n  '🥐': {\r\n    en: ['croissant', 'bread', 'pastry', 'flaky'],\r\n    ru: ['круассан', 'хлеб', 'выпечка', 'слоёный']\r\n  },\r\n  '🥯': {\r\n    en: ['bagel', 'bread', 'round', 'chewy'],\r\n    ru: ['бейгл', 'хлеб', 'круглый', 'жевательный']\r\n  },\r\n  '🍞': {\r\n    en: ['bread', 'baked', 'loaf', 'toast'],\r\n    ru: ['хлеб', 'выпеченный', 'буханка', 'тост']\r\n  },\r\n  '🥖': {\r\n    en: ['baguette', 'bread', 'French', 'long'],\r\n    ru: ['багет', 'хлеб', 'французский', 'длинный']\r\n  },\r\n  '🥨': {\r\n    en: ['pretzel', 'snack', 'salted', 'twisted'],\r\n    ru: ['претцель', 'закуска', 'солёный', 'скрученный']\r\n  },\r\n\r\n  // Prepared Foods\r\n  '🧀': {\r\n    en: ['cheese', 'dairy', 'yellow', 'savory'],\r\n    ru: ['сыр', 'молочный продукт', 'жёлтый', 'пикантный']\r\n  },\r\n  '🥚': {\r\n    en: ['egg', 'protein', 'breakfast'],\r\n    ru: ['яйцо', 'белок', 'завтрак']\r\n  },\r\n  '🍳': {\r\n    en: ['fried egg', 'breakfast', 'cooked'],\r\n    ru: ['жареное яйцо', 'завтрак', 'приготовленное']\r\n  },\r\n  '🥓': {\r\n    en: ['bacon', 'meat', 'crispy', 'breakfast'],\r\n    ru: ['бекон', 'мясо', 'хрустящий', 'завтрак']\r\n  },\r\n  '🥩': {\r\n    en: ['steak', 'meat', 'protein', 'beef'],\r\n    ru: ['стейк', 'мясо', 'белок', 'говядина']\r\n  },\r\n  '🍗': {\r\n    en: ['chicken leg', 'meat', 'drumstick', 'grilled'],\r\n    ru: ['куриная ножка', 'мясо', 'барабанная палочка', 'гриль']\r\n  },\r\n  '🍖': {\r\n    en: ['meat on bone', 'barbecue', 'protein'],\r\n    ru: ['мясо на кости', 'барбекю', 'белок']\r\n  },\r\n  '🦴': {\r\n    en: ['bone', 'meat', 'dog', 'skeleton'],\r\n    ru: ['кость', 'мясо', 'собака', 'скелет']\r\n  },\r\n  '🌭': {\r\n    en: ['hot dog', 'fast food', 'sausage'],\r\n    ru: ['хот-дог', 'фастфуд', 'колбаска']\r\n  },\r\n  '🍔': {\r\n    en: ['burger', 'fast food', 'beef', 'cheese'],\r\n    ru: ['бургер', 'фастфуд', 'говядина', 'сыр']\r\n  },\r\n  '🍟': {\r\n    en: ['french fries', 'fast food', 'crispy', 'potato'],\r\n    ru: ['картофель фри', 'фастфуд', 'хрустящий', 'картофель']\r\n  },\r\n  '🍕': {\r\n    en: ['pizza', 'cheese', 'fast food', 'Italian'],\r\n    ru: ['пицца', 'сыр', 'фастфуд', 'итальянская']\r\n  },\r\n  '🫓': {\r\n    en: ['flatbread', 'bread', 'soft'],\r\n    ru: ['лепёшка', 'хлеб', 'мягкая']\r\n  },\r\n  '🥪': {\r\n    en: ['sandwich', 'bread', 'meal'],\r\n    ru: ['бутерброд', 'хлеб', 'приём пищи']\r\n  },\r\n  '🥙': {\r\n    en: ['pita', 'bread', 'stuffed', 'Greek'],\r\n    ru: ['пита', 'хлеб', 'фаршированная', 'греческая']\r\n  },\r\n  '🧆': {\r\n    en: ['falafel', 'vegetarian', 'fried'],\r\n    ru: ['фалафель', 'вегетарианский', 'жареный']\r\n  },\r\n  '🌮': {\r\n    en: ['taco', 'Mexican', 'spicy'],\r\n    ru: ['тако', 'мексиканская', 'острая']\r\n  },\r\n  '🌯': {\r\n    en: ['burrito', 'Mexican', 'stuffed'],\r\n    ru: ['буррито', 'мексиканская', 'фаршированная']\r\n  },\r\n  '🫔': {\r\n    en: ['tamale', 'Mexican', 'corn'],\r\n    ru: ['тамале', 'мексиканская', 'кукурузная']\r\n  },\r\n  '🥗': {\r\n    en: ['salad', 'healthy', 'vegetable'],\r\n    ru: ['салат', 'здоровый', 'овощной']\r\n  },\r\n\r\n  // Asian Foods\r\n  '🥘': {\r\n    en: ['paella', 'stew', 'seafood'],\r\n    ru: ['паэлья', 'тушёное блюдо', 'морепродукты']\r\n  },\r\n  '🫕': {\r\n    en: ['fondue', 'melted', 'cheese'],\r\n    ru: ['фондю', 'расплавленный', 'сыр']\r\n  },\r\n  '🥫': {\r\n    en: ['canned food', 'storage', 'preserved'],\r\n    ru: ['консервы', 'хранение', 'сохранённое']\r\n  },\r\n  '🍝': {\r\n    en: ['spaghetti', 'pasta', 'Italian'],\r\n    ru: ['спагетти', 'паста', 'итальянская']\r\n  },\r\n  '🍜': {\r\n    en: ['ramen', 'noodles', 'Asian'],\r\n    ru: ['рамен', 'лапша', 'азиатская']\r\n  },\r\n  '🍲': {\r\n    en: ['hotpot', 'stew', 'broth'],\r\n    ru: ['хотпот', 'тушёное блюдо', 'бульон']\r\n  },\r\n  '🍛': {\r\n    en: ['curry', 'spicy', 'rice'],\r\n    ru: ['карри', 'острая', 'рис']\r\n  },\r\n  '🍣': {\r\n    en: ['sushi', 'Japanese', 'fish'],\r\n    ru: ['суши', 'японская', 'рыба']\r\n  },\r\n  '🍱': {\r\n    en: ['bento box', 'Japanese', 'meal'],\r\n    ru: ['бенто', 'японская', 'еда']\r\n  },\r\n  '🥟': {\r\n    en: ['dumpling', 'Asian', 'stuffed'],\r\n    ru: ['пельмени', 'азиатские', 'фаршированные']\r\n  },\r\n  '🦪': {\r\n    en: ['oyster', 'seafood', 'shellfish'],\r\n    ru: ['устрица', 'морепродукт', 'раковина']\r\n  },\r\n  '🍤': {\r\n    en: ['shrimp tempura', 'fried', 'seafood'],\r\n    ru: ['креветка темпура', 'жареная', 'морепродукт']\r\n  },\r\n  '🍙': {\r\n    en: ['rice ball', 'Japanese', 'onigiri'],\r\n    ru: ['рисовый шар', 'японская', 'онигири']\r\n  },\r\n  '🍚': {\r\n    en: ['cooked rice', 'staple', 'Asian'],\r\n    ru: ['варёный рис', 'основа', 'азиатская']\r\n  },\r\n  '🍘': {\r\n    en: ['rice cracker', 'snack', 'Japanese'],\r\n    ru: ['рисовый крекер', 'закуска', 'японская']\r\n  },\r\n  '🍥': {\r\n    en: ['fish cake', 'Japanese', 'swirl'],\r\n    ru: ['рыбный пирожок', 'японская', 'спираль']\r\n  },\r\n  '🥠': {\r\n    en: ['fortune cookie', 'Chinese', 'paper'],\r\n    ru: ['печенье с предсказанием', 'китайское', 'бумажное']\r\n  },\r\n  '🥮': {\r\n    en: ['mooncake', 'Chinese', 'festival'],\r\n    ru: ['лунное печенье', 'китайское', 'фестиваль']\r\n  },\r\n\r\n  // Sweets & Desserts\r\n  '🍢': {\r\n    en: ['skewered snack', 'street food'],\r\n    ru: ['шампур', 'уличная еда']\r\n  },\r\n  '🍡': {\r\n    en: ['dango', 'Japanese', 'mochi'],\r\n    ru: ['данго', 'японское', 'мочи']\r\n  },\r\n  '🍧': {\r\n    en: ['shaved ice', 'dessert', 'cold'],\r\n    ru: ['измельчённый лёд', 'десерт', 'холодный']\r\n  },\r\n  '🍨': {\r\n    en: ['ice cream', 'cold', 'sweet'],\r\n    ru: ['мороженое', 'холодное', 'сладкое']\r\n  },\r\n  '🍦': {\r\n    en: ['soft serve', 'dessert', 'cold'],\r\n    ru: ['мягкое мороженое', 'десерт', 'холодное']\r\n  },\r\n  '🥧': {\r\n    en: ['pie', 'dessert', 'baked'],\r\n    ru: ['пирог', 'десерт', 'выпеченный']\r\n  },\r\n  '🧁': {\r\n    en: ['cupcake', 'sweet', 'frosting'],\r\n    ru: ['капкейк', 'сладкий', 'с глазурью']\r\n  },\r\n  '🍰': {\r\n    en: ['cake', 'dessert', 'slice'],\r\n    ru: ['торт', 'десерт', 'кусок']\r\n  },\r\n  '🎂': {\r\n    en: ['birthday cake', 'celebration', 'sweet'],\r\n    ru: ['торт ко дню рождения', 'празднование', 'сладкий']\r\n  },\r\n  '🍮': {\r\n    en: ['flan', 'custard', 'dessert'],\r\n    ru: ['флан', 'кастард', 'десерт']\r\n  },\r\n  '🍭': {\r\n    en: ['lollipop', 'candy', 'sweet'],\r\n    ru: ['леденец', 'конфета', 'сладкий']\r\n  },\r\n  '🍬': {\r\n    en: ['candy', 'sweet', 'sugar'],\r\n    ru: ['конфета', 'сладость', 'сахар']\r\n  },\r\n  '🍫': {\r\n    en: ['chocolate', 'sweet', 'cocoa'],\r\n    ru: ['шоколад', 'сладкий', 'какао']\r\n  },\r\n  '🍿': {\r\n    en: ['popcorn', 'snack', 'buttery'],\r\n    ru: ['попкорн', 'закуска', 'масляный']\r\n  },\r\n  '🍩': {\r\n    en: ['doughnut', 'sweet', 'fried'],\r\n    ru: ['пончик', 'сладкий', 'жареный']\r\n  },\r\n  '🍪': {\r\n    en: ['cookie', 'sweet', 'baked'],\r\n    ru: ['печенье', 'сладкое', 'выпеченное']\r\n  },\r\n\r\n  // Drinks\r\n  '🫖': {\r\n    en: ['teapot', 'tea', 'hot'],\r\n    ru: ['чайник', 'чай', 'горячий']\r\n  },\r\n  '☕': {\r\n    en: ['coffee', 'hot drink', 'caffeine'],\r\n    ru: ['кофе', 'горячий напиток', 'кофеин']\r\n  },\r\n  '🍵': {\r\n    en: ['green tea', 'hot', 'Japanese'],\r\n    ru: ['зелёный чай', 'горячий', 'японский']\r\n  },\r\n  '🧃': {\r\n    en: ['juice', 'drink', 'fruit'],\r\n    ru: ['сок', 'напиток', 'фруктовый']\r\n  },\r\n  '🥤': {\r\n    en: ['soft drink', 'straw', 'fast food'],\r\n    ru: ['безалкогольный напиток', 'с трубочкой', 'фастфуд']\r\n  },\r\n  '🧋': {\r\n    en: ['bubble tea', 'milk tea', 'boba'],\r\n    ru: ['бабл-ти', 'молочный чай', 'боба']\r\n  },\r\n  '🍶': {\r\n    en: ['sake', 'Japanese', 'rice wine'],\r\n    ru: ['саке', 'японский', 'рисовое вино']\r\n  },\r\n  '🍺': {\r\n    en: ['beer', 'drink', 'alcohol'],\r\n    ru: ['пиво', 'напиток', 'алкоголь']\r\n  },\r\n  '🍻': {\r\n    en: ['cheers', 'beer', 'drinking'],\r\n    ru: ['ура', 'пиво', 'выпивка']\r\n  },\r\n  '🥂': {\r\n    en: ['champagne', 'celebration', 'toast'],\r\n    ru: ['шампанское', 'празднование', 'тост']\r\n  },\r\n  '🍷': {\r\n    en: ['wine', 'drink', 'red'],\r\n    ru: ['вино', 'напиток', 'красное']\r\n  },\r\n  '🥃': {\r\n    en: ['whiskey', 'liquor', 'alcohol'],\r\n    ru: ['виски', 'ликёр', 'алкоголь']\r\n  },\r\n  '🍸': {\r\n    en: ['cocktail', 'martini', 'drink'],\r\n    ru: ['коктейль', 'мартини', 'напиток']\r\n  },\r\n  '🍹': {\r\n    en: ['tropical drink', 'cocktail', 'summer'],\r\n    ru: ['тропический напиток', 'коктейль', 'лето']\r\n  },\r\n  '🧉': {\r\n    en: ['mate', 'South American', 'tea'],\r\n    ru: ['мате', 'южноамериканский', 'чай']\r\n  },\r\n  '🍾': {\r\n    en: ['champagne bottle', 'celebration', 'party'],\r\n    ru: ['бутылка шампанского', 'празднование', 'вечеринка']\r\n  },\r\n\r\n  //------------------------- Activities & Objects -------------------------\r\n  // Sports\r\n  '⚽': {\r\n    en: ['soccer', 'football', 'sports', 'ball'],\r\n    ru: ['футбол', 'футбол', 'спорт', 'мяч']\r\n  },\r\n  '🏀': {\r\n    en: ['basketball', 'sports', 'hoop', 'dunk'],\r\n    ru: ['баскетбол', 'спорт', 'кольцо', 'данк']\r\n  },\r\n  '🏈': {\r\n    en: ['American football', 'sports', 'rugby'],\r\n    ru: ['американский футбол', 'спорт', 'регби']\r\n  },\r\n  '⚾': {\r\n    en: ['baseball', 'sports', 'bat'],\r\n    ru: ['бейсбол', 'спорт', 'бита']\r\n  },\r\n  '🥎': {\r\n    en: ['softball', 'sports', 'ball'],\r\n    ru: ['софтбол', 'спорт', 'мяч']\r\n  },\r\n  '🎾': {\r\n    en: ['tennis', 'sports', 'racket'],\r\n    ru: ['теннис', 'спорт', 'ракетка']\r\n  },\r\n  '🏐': {\r\n    en: ['volleyball', 'sports', 'beach'],\r\n    ru: ['волейбол', 'спорт', 'пляж']\r\n  },\r\n  '🏉': {\r\n    en: ['rugby', 'sports', 'oval ball'],\r\n    ru: ['регби', 'спорт', 'овальный мяч']\r\n  },\r\n  '🥏': {\r\n    en: ['frisbee', 'throw', 'flying disc'],\r\n    ru: ['фрисби', 'бросок', 'летающий диск']\r\n  },\r\n  '🎱': {\r\n    en: ['billiards', '8 ball', 'pool'],\r\n    ru: ['бильярд', 'восьмёрка', 'пул']\r\n  },\r\n  '🪀': {\r\n    en: ['yo-yo', 'toy', 'string'],\r\n    ru: ['йо-йо', 'игрушка', 'верёвка']\r\n  },\r\n  '🏓': {\r\n    en: ['ping pong', 'table tennis', 'sports'],\r\n    ru: ['пинг-понг', 'настольный теннис', 'спорт']\r\n  },\r\n  '🏸': {\r\n    en: ['badminton', 'racket', 'sports'],\r\n    ru: ['бадминтон', 'ракетка', 'спорт']\r\n  },\r\n  '🏒': {\r\n    en: ['hockey', 'ice hockey', 'sports'],\r\n    ru: ['хоккей', 'хоккей на льду', 'спорт']\r\n  },\r\n  '🏑': {\r\n    en: ['field hockey', 'sports', 'stick'],\r\n    ru: ['хоккей на траве', 'спорт', 'клюшка']\r\n  },\r\n  '🥍': {\r\n    en: ['lacrosse', 'sports', 'net'],\r\n    ru: ['лакросс', 'спорт', 'сеть']\r\n  },\r\n  '🏏': {\r\n    en: ['cricket', 'bat', 'sports'],\r\n    ru: ['крикет', 'бита', 'спорт']\r\n  },\r\n  '⛳': {\r\n    en: ['golf', 'sports', 'hole in one'],\r\n    ru: ['гольф', 'спорт', 'луночка']\r\n  },\r\n  '🪁': {\r\n    en: ['kite', 'flying', 'wind'],\r\n    ru: ['змей', 'летать', 'ветер']\r\n  },\r\n  '🎣': {\r\n    en: ['fishing', 'hook', 'water'],\r\n    ru: ['рыбалка', 'крючок', 'вода']\r\n  },\r\n  '🤿': {\r\n    en: ['diving', 'underwater', 'snorkel'],\r\n    ru: ['дайвинг', 'под водой', 'снорклинг']\r\n  },\r\n  '🎽': {\r\n    en: ['running', 'jersey', 'athlete'],\r\n    ru: ['бег', 'майка', 'спортсмен']\r\n  },\r\n  '🛹': {\r\n    en: ['skateboard', 'sports', 'extreme'],\r\n    ru: ['скейтборд', 'спорт', 'экстрим']\r\n  },\r\n  '🛼': {\r\n    en: ['roller skate', 'sports', 'wheels'],\r\n    ru: ['роликовые коньки', 'спорт', 'колёса']\r\n  },\r\n  '🛷': {\r\n    en: ['sled', 'winter', 'snow'],\r\n    ru: ['санки', 'зима', 'снег']\r\n  },\r\n  '⛸️': {\r\n    en: ['ice skate', 'winter', 'sports'],\r\n    ru: ['коньки', 'зима', 'спорт']\r\n  },\r\n  '🥌': {\r\n    en: ['curling', 'winter', 'stone'],\r\n    ru: ['керлинг', 'зима', 'камень']\r\n  },\r\n  '⛷️': {\r\n    en: ['skiing', 'winter', 'snow'],\r\n    ru: ['лыжи', 'зима', 'снег']\r\n  },\r\n  '🏂': {\r\n    en: ['snowboarding', 'sports', 'snow'],\r\n    ru: ['сноуборд', 'спорт', 'снег']\r\n  },\r\n  '🪂': {\r\n    en: ['parachute', 'skydiving', 'air'],\r\n    ru: ['парашют', 'скайдайвинг', 'воздух']\r\n  },\r\n  '🏋️': {\r\n    en: ['weightlifting', 'gym', 'strong'],\r\n    ru: ['тяжёлая атлетика', 'спортзал', 'сильный']\r\n  },\r\n  '🤼': {\r\n    en: ['wrestling', 'fight', 'grapple'],\r\n    ru: ['борьба', 'драка', 'схватка']\r\n  },\r\n  '🤸': {\r\n    en: ['gymnastics', 'acrobatics', 'flip'],\r\n    ru: ['гимнастика', 'акробатика', 'сальто']\r\n  },\r\n  '⛹️': {\r\n    en: ['basketball', 'dribbling', 'sports'],\r\n    ru: ['баскетбол', 'дриблинг', 'спорт']\r\n  },\r\n  '🤾': {\r\n    en: ['handball', 'sports', 'throw'],\r\n    ru: ['гандбол', 'спорт', 'бросок']\r\n  },\r\n  '🏌️': {\r\n    en: ['golf', 'swing', 'sports'],\r\n    ru: ['гольф', 'мах', 'спорт']\r\n  },\r\n  '🏇': {\r\n    en: ['horse racing', 'sports', 'jockey'],\r\n    ru: ['конные скачки', 'спорт', 'жокей']\r\n  },\r\n  '🧘': {\r\n    en: ['meditation', 'yoga', 'zen'],\r\n    ru: ['медитация', 'йога', 'дзен']\r\n  },\r\n  '🏄': {\r\n    en: ['surfing', 'wave', 'water'],\r\n    ru: ['серфинг', 'волна', 'вода']\r\n  },\r\n  '🏊': {\r\n    en: ['swimming', 'water', 'pool'],\r\n    ru: ['плавание', 'вода', 'бассейн']\r\n  },\r\n\r\n  // Activities (cultural/entertainment)\r\n  '🤽': {\r\n    en: ['water polo', 'sports', 'swimming'],\r\n    ru: ['водное поло', 'спорт', 'плавание']\r\n  },\r\n  '🚣': {\r\n    en: ['rowing', 'boat', 'water'],\r\n    ru: ['гребля', 'лодка', 'вода']\r\n  },\r\n  '🧗': {\r\n    en: ['rock climbing', 'sports', 'mountain'],\r\n    ru: ['скалолазание', 'спорт', 'гора']\r\n  },\r\n  '🚴': {\r\n    en: ['cycling', 'bike', 'sports'],\r\n    ru: ['велоспорт', 'велосипед', 'спорт']\r\n  },\r\n  '🚵': {\r\n    en: ['mountain biking', 'sports', 'outdoor'],\r\n    ru: ['маунтинбайк', 'спорт', 'на свежем воздухе']\r\n  },\r\n  '🎪': {\r\n    en: ['circus', 'tent', 'performance'],\r\n    ru: ['цирк', 'палатка', 'выступление']\r\n  },\r\n  '🎭': {\r\n    en: ['theater', 'drama', 'acting'],\r\n    ru: ['театр', 'драма', 'актерство']\r\n  },\r\n  '🎨': {\r\n    en: ['painting', 'art', 'colors'],\r\n    ru: ['живопись', 'искусство', 'цвета']\r\n  },\r\n  '🎬': {\r\n    en: ['film', 'clapperboard', 'movie'],\r\n    ru: ['фильм', 'хлопушка', 'кино']\r\n  },\r\n  '🎤': {\r\n    en: ['microphone', 'singing', 'music'],\r\n    ru: ['микрофон', 'пение', 'музыка']\r\n  },\r\n  '🎧': {\r\n    en: ['headphones', 'music', 'listening'],\r\n    ru: ['наушники', 'музыка', 'прослушивание']\r\n  },\r\n  '🎼': {\r\n    en: ['music', 'sheet', 'notes'],\r\n    ru: ['музыка', 'ноты', 'сценарий']\r\n  },\r\n  '🎹': {\r\n    en: ['piano', 'keyboard', 'music'],\r\n    ru: ['пианино', 'клавиатура', 'музыка']\r\n  },\r\n  '🥁': {\r\n    en: ['drums', 'music', 'percussion'],\r\n    ru: ['барабаны', 'музыка', 'ударные']\r\n  },\r\n  '🎷': {\r\n    en: ['saxophone', 'jazz', 'music'],\r\n    ru: ['саксофон', 'джаз', 'музыка']\r\n  },\r\n  '🎺': {\r\n    en: ['trumpet', 'brass', 'music'],\r\n    ru: ['труба', 'латунь', 'музыка']\r\n  },\r\n  '🎸': {\r\n    en: ['guitar', 'music', 'rock'],\r\n    ru: ['гитара', 'музыка', 'рок']\r\n  },\r\n  '🎻': {\r\n    en: ['violin', 'music', 'strings'],\r\n    ru: ['скрипка', 'музыка', 'струны']\r\n  },\r\n  '🎲': {\r\n    en: ['dice', 'game', 'board game'],\r\n    ru: ['кубики', 'игра', 'настольная игра']\r\n  },\r\n  '🎯': {\r\n    en: ['dart', 'target', 'game'],\r\n    ru: ['дротик', 'цель', 'игра']\r\n  },\r\n  '🎳': {\r\n    en: ['bowling', 'sports', 'pins'],\r\n    ru: ['боулинг', 'спорт', 'кегли']\r\n  },\r\n  '🎮': {\r\n    en: ['video game', 'console', 'gaming'],\r\n    ru: ['видеоигра', 'консоль', 'игры']\r\n  },\r\n  '🎰': {\r\n    en: ['slot machine', 'casino', 'gambling'],\r\n    ru: ['игровой автомат', 'казино', 'азартные игры']\r\n  },\r\n  '🧩': {\r\n    en: ['puzzle', 'pieces', 'brain teaser'],\r\n    ru: ['головоломка', 'кусочки', 'разминка для мозга']\r\n  },\r\n  '🎫': {\r\n    en: ['ticket', 'event', 'entry'],\r\n    ru: ['билет', 'событие', 'вход']\r\n  },\r\n  '🎟️': {\r\n    en: ['admission', 'ticket', 'event'],\r\n    ru: ['входной билет', 'билет', 'событие']\r\n  },\r\n\r\n  //------------------------- Travel & Places -------------------------\r\n  // Land Transport\r\n  '🚗': {\r\n    en: ['car', 'automobile', 'vehicle', 'transport'],\r\n    ru: ['автомобиль', 'машина', 'транспортное средство', 'транспорт']\r\n  },\r\n  '🚕': {\r\n    en: ['taxi', 'cab', 'transport', 'vehicle'],\r\n    ru: ['такси', 'маршрутка', 'транспорт', 'транспортное средство']\r\n  },\r\n  '🚙': {\r\n    en: ['suv', 'vehicle', 'transport'],\r\n    ru: ['внедорожник', 'транспортное средство', 'транспорт']\r\n  },\r\n  '🚌': {\r\n    en: ['bus', 'public transport', 'commute'],\r\n    ru: ['автобус', 'общественный транспорт', 'коммьют']\r\n  },\r\n  '🚎': {\r\n    en: ['trolleybus', 'public transport', 'electric'],\r\n    ru: ['троллейбус', 'общественный транспорт', 'электрический']\r\n  },\r\n  '🏎️': {\r\n    en: ['race car', 'sports car', 'fast', 'speed'],\r\n    ru: ['гоночный автомобиль', 'спортивный автомобиль', 'быстрый', 'скорость']\r\n  },\r\n  '🚓': {\r\n    en: ['police car', 'law enforcement', 'vehicle'],\r\n    ru: ['полицейская машина', 'правоохранительные органы', 'транспортное средство']\r\n  },\r\n  '🚑': {\r\n    en: ['ambulance', 'emergency', 'hospital'],\r\n    ru: ['скорая помощь', 'чрезвычайная ситуация', 'больница']\r\n  },\r\n  '🚒': {\r\n    en: ['fire truck', 'firefighter', 'emergency'],\r\n    ru: ['пожарная машина', 'пожарный', 'чрезвычайная ситуация']\r\n  },\r\n  '🚐': {\r\n    en: ['van', 'minibus', 'transport'],\r\n    ru: ['фургон', 'маршрутка', 'транспорт']\r\n  },\r\n  '🛻': {\r\n    en: ['pickup truck', 'off-road', 'vehicle'],\r\n    ru: ['пикап', 'для бездорожья', 'транспортное средство']\r\n  },\r\n  '🚚': {\r\n    en: ['delivery truck', 'freight', 'cargo'],\r\n    ru: ['грузовик', 'доставка', 'груз']\r\n  },\r\n  '🚛': {\r\n    en: ['truck', 'semi-trailer', 'transport'],\r\n    ru: ['грузовик', 'самосвал', 'транспорт']\r\n  },\r\n  '🚜': {\r\n    en: ['tractor', 'farming', 'agriculture'],\r\n    ru: ['трактор', 'сельское хозяйство', 'агрономия']\r\n  },\r\n  '🛵': {\r\n    en: ['scooter', 'motorbike', 'moped'],\r\n    ru: ['скутер', 'мотоцикл', 'мопед']\r\n  },\r\n  '🏍️': {\r\n    en: ['motorcycle', 'bike', 'racing'],\r\n    ru: ['мотоцикл', 'байк', 'гоночный']\r\n  },\r\n  '🛺': {\r\n    en: ['rickshaw', 'auto rickshaw', 'transport'],\r\n    ru: ['рикша', 'авто-рикша', 'транспорт']\r\n  },\r\n  '🚲': {\r\n    en: ['bicycle', 'bike', 'pedal', 'cycling'],\r\n    ru: ['велосипед', 'байк', 'педаль', 'велоспорт']\r\n  },\r\n  '🛴': {\r\n    en: ['kick scooter', 'scooter', 'ride'],\r\n    ru: ['самокат', 'скутер', 'поездка']\r\n  },\r\n\r\n  // Air Transport\r\n  '✈️': {\r\n    en: ['airplane', 'flight', 'travel', 'sky'],\r\n    ru: ['самолёт', 'рейс', 'путешествие', 'небо']\r\n  },\r\n  '🛩️': {\r\n    en: ['small airplane', 'aviation', 'sky'],\r\n    ru: ['малый самолёт', 'авиация', 'небо']\r\n  },\r\n  '🛫': {\r\n    en: ['departure', 'takeoff', 'airport'],\r\n    ru: ['вылет', 'взлёт', 'аэропорт']\r\n  },\r\n  '🛬': {\r\n    en: ['landing', 'arrival', 'airport'],\r\n    ru: ['посадка', 'прибытие', 'аэропорт']\r\n  },\r\n  '🚁': {\r\n    en: ['helicopter', 'aviation', 'air'],\r\n    ru: ['вертолёт', 'авиация', 'воздух']\r\n  },\r\n  '🚀': {\r\n    en: ['rocket', 'space', 'launch', 'NASA'],\r\n    ru: ['ракета', 'космос', 'запуск', 'НАСА']\r\n  },\r\n  '🛸': {\r\n    en: ['UFO', 'alien', 'spaceship', 'extraterrestrial'],\r\n    ru: ['НЛО', 'инопланетянин', 'космический корабль', 'внеземной']\r\n  },\r\n\r\n  // Water Transport\r\n  '🛶': {\r\n    en: ['canoe', 'boat', 'paddle', 'water'],\r\n    ru: ['каноэ', 'лодка', 'весло', 'вода']\r\n  },\r\n  '⛵': {\r\n    en: ['sailboat', 'yacht', 'sea'],\r\n    ru: ['парусник', 'яхта', 'море']\r\n  },\r\n  '🚤': {\r\n    en: ['motorboat', 'speedboat', 'ocean'],\r\n    ru: ['моторная лодка', 'скоростной катер', 'океан']\r\n  },\r\n  '🛥️': {\r\n    en: ['yacht', 'luxury', 'boat'],\r\n    ru: ['яхта', 'роскошь', 'лодка']\r\n  },\r\n  '🛳️': {\r\n    en: ['cruise ship', 'ocean', 'voyage'],\r\n    ru: ['круизный лайнер', 'океан', 'путешествие']\r\n  },\r\n  '⛴️': {\r\n    en: ['ferry', 'boat', 'transport'],\r\n    ru: ['паром', 'лодка', 'транспорт']\r\n  },\r\n  '🚢': {\r\n    en: ['ship', 'ocean', 'voyage'],\r\n    ru: ['корабль', 'океан', 'путешествие']\r\n  },\r\n\r\n  // Places\r\n  '🏰': {\r\n    en: ['castle', 'fortress', 'history'],\r\n    ru: ['замок', 'крепость', 'история']\r\n  },\r\n  '🏯': {\r\n    en: ['Japanese castle', 'Asia', 'samurai'],\r\n    ru: ['японский замок', 'Азия', 'самурай']\r\n  },\r\n  '🏟️': {\r\n    en: ['stadium', 'sports', 'arena'],\r\n    ru: ['стадион', 'спорт', 'арена']\r\n  },\r\n  '🏖️': {\r\n    en: ['beach', 'sun', 'vacation'],\r\n    ru: ['пляж', 'солнце', 'отпуск']\r\n  },\r\n  '🏝️': {\r\n    en: ['island', 'tropical', 'vacation'],\r\n    ru: ['остров', 'тропический', 'отпуск']\r\n  },\r\n  '🏜️': {\r\n    en: ['desert', 'sand', 'dry'],\r\n    ru: ['пустыня', 'песок', 'сухой']\r\n  },\r\n  '🌋': {\r\n    en: ['volcano', 'eruption', 'lava'],\r\n    ru: ['вулкан', 'извержение', 'лава']\r\n  },\r\n  '⛰️': {\r\n    en: ['mountain', 'hiking', 'nature'],\r\n    ru: ['гора', 'поход', 'природа']\r\n  },\r\n  '🏔️': {\r\n    en: ['snowy mountain', 'climbing', 'cold'],\r\n    ru: ['снежная гора', 'скалолазание', 'холод']\r\n  },\r\n  '🗻': {\r\n    en: ['Mount Fuji', 'Japan', 'scenic'],\r\n    ru: ['гора Фудзи', 'Япония', 'живописный']\r\n  },\r\n  '🏕️': {\r\n    en: ['camping', 'tent', 'outdoors'],\r\n    ru: ['кемпинг', 'палатка', 'на природе']\r\n  },\r\n  '🏭': {\r\n    en: ['factory', 'industry', 'building'],\r\n    ru: ['фабрика', 'индустрия', 'здание']\r\n  },\r\n  '🏢': {\r\n    en: ['office building', 'corporate', 'city'],\r\n    ru: ['офисное здание', 'корпоративный', 'город']\r\n  },\r\n  '🏬': {\r\n    en: ['shopping mall', 'retail', 'stores'],\r\n    ru: ['торговый центр', 'розничная торговля', 'магазины']\r\n  },\r\n  '🏣': {\r\n    en: ['post office', 'mail', 'building'],\r\n    ru: ['почтовое отделение', 'почта', 'здание']\r\n  },\r\n  '🏤': {\r\n    en: ['post office', 'mail', 'postal service'],\r\n    ru: ['почтовое отделение', 'почта', 'почтовая служба']\r\n  },\r\n  '🏥': {\r\n    en: ['hospital', 'healthcare', 'emergency'],\r\n    ru: ['больница', 'здравоохранение', 'чрезвычайная ситуация']\r\n  },\r\n  '🏦': {\r\n    en: ['bank', 'money', 'finance'],\r\n    ru: ['банк', 'деньги', 'финансы']\r\n  },\r\n  '🏨': {\r\n    en: ['hotel', 'accommodation', 'stay'],\r\n    ru: ['отель', 'размещение', 'проживание']\r\n  },\r\n  '🏪': {\r\n    en: ['convenience store', 'shopping', '24/7'],\r\n    ru: ['магазин', 'шоппинг', 'круглосуточно']\r\n  },\r\n  '🏫': {\r\n    en: ['school', 'education', 'learning'],\r\n    ru: ['школа', 'образование', 'обучение']\r\n  },\r\n  '🏩': {\r\n    en: ['love hotel', 'romantic', 'Japan'],\r\n    ru: ['любовный отель', 'романтический', 'Япония']\r\n  },\r\n  '💒': {\r\n    en: ['wedding', 'church', 'marriage'],\r\n    ru: ['свадьба', 'церковь', 'брак']\r\n  },\r\n  '⛪': {\r\n    en: ['church', 'Christianity', 'religion'],\r\n    ru: ['церковь', 'христианство', 'религия']\r\n  },\r\n  '🕌': {\r\n    en: ['mosque', 'Islam', 'prayer'],\r\n    ru: ['мечеть', 'ислам', 'молитва']\r\n  },\r\n  '🕍': {\r\n    en: ['synagogue', 'Judaism', 'religion'],\r\n    ru: ['синагога', 'иудаизм', 'религия']\r\n  },\r\n  '🛕': {\r\n    en: ['hindu temple', 'spiritual', 'India'],\r\n    ru: ['индуистский храм', 'духовный', 'Индия']\r\n  },\r\n  '⛩️': {\r\n    en: ['shrine', 'torii', 'Japan'],\r\n    ru: ['святилище', 'тории', 'Япония']\r\n  },\r\n  '🏛️': {\r\n    en: ['government building', 'politics', 'history'],\r\n    ru: ['правительственное здание', 'политика', 'история']\r\n  },\r\n\r\n  //------------------------- Objects & Symbols -------------------------\r\n  // Tools & Technology\r\n  '📱': {\r\n    en: ['smartphone', 'mobile', 'phone'],\r\n    ru: ['смартфон', 'мобильный', 'телефон']\r\n  },\r\n  '💻': {\r\n    en: ['laptop', 'computer', 'technology'],\r\n    ru: ['ноутбук', 'компьютер', 'технология']\r\n  },\r\n  '⌨️': {\r\n    en: ['keyboard', 'typing', 'computer'],\r\n    ru: ['клавиатура', 'набор текста', 'компьютер']\r\n  },\r\n  '🖥️': {\r\n    en: ['desktop', 'monitor', 'screen'],\r\n    ru: ['настольный компьютер', 'монитор', 'экран']\r\n  },\r\n  '🖨️': {\r\n    en: ['printer', 'print', 'office'],\r\n    ru: ['принтер', 'печать', 'офис']\r\n  },\r\n  '🖱️': {\r\n    en: ['mouse', 'computer', 'click'],\r\n    ru: ['мышь', 'компьютер', 'клик']\r\n  },\r\n  '🖲️': {\r\n    en: ['trackball', 'navigation', 'input'],\r\n    ru: ['трекбол', 'навигация', 'ввод']\r\n  },\r\n  '🕹️': {\r\n    en: ['joystick', 'gaming', 'console'],\r\n    ru: ['джойстик', 'игры', 'консоль']\r\n  },\r\n  '🗜️': {\r\n    en: ['clamp', 'tool', 'hardware'],\r\n    ru: ['зажим', 'инструмент', 'аппаратное обеспечение']\r\n  },\r\n  '💽': {\r\n    en: ['mini disc', 'storage', 'media'],\r\n    ru: ['мини-диск', 'хранение', 'медиа']\r\n  },\r\n  '💾': {\r\n    en: ['floppy disk', 'save', 'data'],\r\n    ru: ['флоппи-диск', 'сохранить', 'данные']\r\n  },\r\n  '💿': {\r\n    en: ['CD', 'compact disc', 'music'],\r\n    ru: ['CD', 'компакт-диск', 'музыка']\r\n  },\r\n  '📀': {\r\n    en: ['DVD', 'video', 'disc'],\r\n    ru: ['DVD', 'видео', 'диск']\r\n  },\r\n  '📼': {\r\n    en: ['VHS', 'video cassette', 'retro'],\r\n    ru: ['VHS', 'видеокассета', 'ретро']\r\n  },\r\n  '📷': {\r\n    en: ['camera', 'photo', 'photography'],\r\n    ru: ['камера', 'фото', 'фотография']\r\n  },\r\n  '📸': {\r\n    en: ['camera flash', 'photography', 'snapshot'],\r\n    ru: ['вспышка камеры', 'фотография', 'снимок']\r\n  },\r\n  '📹': {\r\n    en: ['video camera', 'recording', 'film'],\r\n    ru: ['видеокамера', 'запись', 'фильм']\r\n  },\r\n  '🎥': {\r\n    en: ['movie camera', 'film', 'cinema'],\r\n    ru: ['кино-камера', 'фильм', 'кино']\r\n  },\r\n\r\n  // Office & Communication\r\n  '📞': {\r\n    en: ['telephone', 'call', 'communication'],\r\n    ru: ['телефон', 'звонок', 'коммуникация']\r\n  },\r\n  '☎️': {\r\n    en: ['phone', 'landline', 'call'],\r\n    ru: ['телефон', 'стационарный', 'звонок']\r\n  },\r\n  '📟': {\r\n    en: ['pager', 'message', 'communication'],\r\n    ru: ['пейджер', 'сообщение', 'коммуникация']\r\n  },\r\n  '📠': {\r\n    en: ['fax machine', 'office', 'document'],\r\n    ru: ['факс', 'офис', 'документ']\r\n  },\r\n  '📺': {\r\n    en: ['TV', 'television', 'screen'],\r\n    ru: ['телевизор', 'теле', 'экран']\r\n  },\r\n  '📻': {\r\n    en: ['radio', 'broadcast', 'audio'],\r\n    ru: ['радио', 'трансляция', 'аудио']\r\n  },\r\n  '🎙️': {\r\n    en: ['microphone', 'recording', 'podcast'],\r\n    ru: ['микрофон', 'запись', 'подкаст']\r\n  },\r\n  '🎚️': {\r\n    en: ['control knob', 'audio', 'volume'],\r\n    ru: ['ручка управления', 'аудио', 'громкость']\r\n  },\r\n  '🎛️': {\r\n    en: ['sliders', 'equalizer', 'settings'],\r\n    ru: ['ползунки', 'эквалайзер', 'настройки']\r\n  },\r\n  '📡': {\r\n    en: ['satellite dish', 'broadcast', 'signal'],\r\n    ru: ['спутниковая антенна', 'трансляция', 'сигнал']\r\n  },\r\n  '🔋': {\r\n    en: ['battery', 'power', 'energy'],\r\n    ru: ['батарея', 'мощность', 'энергия']\r\n  },\r\n  '🔌': {\r\n    en: ['plug', 'electricity', 'charging'],\r\n    ru: ['штекер', 'электричество', 'зарядка']\r\n  },\r\n  '💡': {\r\n    en: ['light bulb', 'idea', 'illumination'],\r\n    ru: ['лампочка', 'идея', 'освещение']\r\n  },\r\n  '🔦': {\r\n    en: ['flashlight', 'torch', 'light'],\r\n    ru: ['фонарик', 'фонарь', 'свет']\r\n  },\r\n  '🕯️': {\r\n    en: ['candle', 'light', 'fire'],\r\n    ru: ['свеча', 'свет', 'огонь']\r\n  },\r\n\r\n  // Household & Money\r\n  '🧯': {\r\n    en: ['fire extinguisher', 'safety', 'fire'],\r\n    ru: ['огнетушитель', 'безопасность', 'огонь']\r\n  },\r\n  '🛢️': {\r\n    en: ['barrel', 'oil', 'fuel'],\r\n    ru: ['бочка', 'масло', 'топливо']\r\n  },\r\n  '💸': {\r\n    en: ['money with wings', 'cash', 'spending'],\r\n    ru: ['деньги с крыльями', 'наличные', 'расходы']\r\n  },\r\n  '💵': {\r\n    en: ['dollar bills', 'money', 'USD'],\r\n    ru: ['долларовые банкноты', 'деньги', 'USD']\r\n  },\r\n  '💴': {\r\n    en: ['yen', 'money', 'Japan'],\r\n    ru: ['иена', 'деньги', 'Япония']\r\n  },\r\n  '💶': {\r\n    en: ['euro', 'money', 'currency'],\r\n    ru: ['евро', 'деньги', 'валюта']\r\n  },\r\n  '💷': {\r\n    en: ['pound', 'money', 'UK'],\r\n    ru: ['фунт', 'деньги', 'Великобритания']\r\n  },\r\n  '🪙': {\r\n    en: ['coin', 'currency', 'money'],\r\n    ru: ['монета', 'валюта', 'деньги']\r\n  },\r\n  '💰': {\r\n    en: ['money bag', 'wealth', 'rich'],\r\n    ru: ['мешок с деньгами', 'богатство', 'богатый']\r\n  },\r\n  '💳': {\r\n    en: ['credit card', 'banking', 'payment'],\r\n    ru: ['кредитная карта', 'банковское дело', 'оплата']\r\n  },\r\n  '💎': {\r\n    en: ['gem', 'diamond', 'valuable'],\r\n    ru: ['драгоценный камень', 'бриллиант', 'ценный']\r\n  },\r\n  '⚖️': {\r\n    en: ['balance scale', 'justice', 'law'],\r\n    ru: ['весы', 'справедливость', 'закон']\r\n  },\r\n  '🪜': {\r\n    en: ['ladder', 'climb', 'height'],\r\n    ru: ['лестница', 'лазить', 'высота']\r\n  },\r\n  '🧰': {\r\n    en: ['toolbox', 'tools', 'repair'],\r\n    ru: ['ящик с инструментами', 'инструменты', 'ремонт']\r\n  },\r\n  '🔧': {\r\n    en: ['wrench', 'repair', 'tools'],\r\n    ru: ['гаечный ключ', 'ремонт', 'инструменты']\r\n  },\r\n  '🔨': {\r\n    en: ['hammer', 'build', 'fix'],\r\n    ru: ['молоток', 'строить', 'чинить']\r\n  },\r\n  '⚒️': {\r\n    en: ['hammer and pick', 'construction', 'work'],\r\n    ru: ['молот и кирка', 'строительство', 'работа']\r\n  },\r\n  '🛠️': {\r\n    en: ['tools', 'fix', 'maintenance'],\r\n    ru: ['инструменты', 'чинить', 'обслуживание']\r\n  },\r\n  '⛏️': {\r\n    en: ['pickaxe', 'mining', 'digging'],\r\n    ru: ['кирка', 'горное дело', 'копать']\r\n  },\r\n\r\n  // Writing & Reading\r\n  '✏️': {\r\n    en: ['pencil', 'writing', 'notes'],\r\n    ru: ['карандаш', 'написание', 'заметки']\r\n  },\r\n  '🖊️': {\r\n    en: ['pen', 'writing', 'signature'],\r\n    ru: ['ручка', 'написание', 'подпись']\r\n  },\r\n  '🖋️': {\r\n    en: ['fountain pen', 'calligraphy', 'writing'],\r\n    ru: ['перьевая ручка', 'каллиграфия', 'написание']\r\n  },\r\n  '✒️': {\r\n    en: ['nib', 'ink', 'writing'],\r\n    ru: ['остриё', 'чернила', 'написание']\r\n  },\r\n  '🖌️': {\r\n    en: ['paintbrush', 'art', 'painting'],\r\n    ru: ['кисть', 'искусство', 'живопись']\r\n  },\r\n  '🖍️': {\r\n    en: ['crayon', 'drawing', 'color'],\r\n    ru: ['мелки', 'рисование', 'цвет']\r\n  },\r\n  '📝': {\r\n    en: ['memo', 'notes', 'document'],\r\n    ru: ['заметка', 'записи', 'документ']\r\n  },\r\n  '📚': {\r\n    en: ['books', 'reading', 'library'],\r\n    ru: ['книги', 'чтение', 'библиотека']\r\n  },\r\n  '📖': {\r\n    en: ['open book', 'reading', 'story'],\r\n    ru: ['открытая книга', 'чтение', 'история']\r\n  },\r\n  '🔖': {\r\n    en: ['bookmark', 'reading', 'save'],\r\n    ru: ['закладка', 'чтение', 'сохранить']\r\n  },\r\n  '📑': {\r\n    en: ['bookmark tabs', 'pages', 'notes'],\r\n    ru: ['закладки', 'страницы', 'заметки']\r\n  },\r\n  '🗒️': {\r\n    en: ['spiral notepad', 'notes', 'journal'],\r\n    ru: ['спиральный блокнот', 'записи', 'журнал']\r\n  },\r\n  '📄': {\r\n    en: ['document', 'paper', 'page'],\r\n    ru: ['документ', 'бумага', 'страница']\r\n  },\r\n  '📰': {\r\n    en: ['newspaper', 'news', 'journalism'],\r\n    ru: ['газета', 'новости', 'журналистика']\r\n  },\r\n  '🗞️': {\r\n    en: ['rolled newspaper', 'press', 'print'],\r\n    ru: ['свернутая газета', 'пресса', 'печатное издание']\r\n  },\r\n  '📁': {\r\n    en: ['file folder', 'documents', 'storage'],\r\n    ru: ['папка', 'документы', 'хранение']\r\n  },\r\n  '📂': {\r\n    en: ['open folder', 'organization', 'files'],\r\n    ru: ['открытая папка', 'организация', 'файлы']\r\n  },\r\n  '🗂️': {\r\n    en: ['card index', 'catalog', 'records'],\r\n    ru: ['карточный индекс', 'каталог', 'записи']\r\n  },\r\n  '🕐': {\r\n    en: ['1 o\\'clock', 'clock face', 'time'],\r\n    ru: ['час', 'циферблат', 'время']\r\n  },\r\n  '🕑': {\r\n    en: ['2 o\\'clock', 'clock face', 'time'],\r\n    ru: ['два часа', 'циферблат', 'время']\r\n  },\r\n  '🕒': {\r\n    en: ['3 o\\'clock', 'clock face', 'time'],\r\n    ru: ['три часа', 'циферблат', 'время']\r\n  },\r\n  '🕓': {\r\n    en: ['4 o\\'clock', 'clock face', 'time'],\r\n    ru: ['четыре часа', 'циферблат', 'время']\r\n  },\r\n  '🕔': {\r\n    en: ['5 o\\'clock', 'clock face', 'time'],\r\n    ru: ['пять часов', 'циферблат', 'время']\r\n  },\r\n  '🕕': {\r\n    en: ['6 o\\'clock', 'clock face', 'time'],\r\n    ru: ['шесть часов', 'циферблат', 'время']\r\n  },\r\n  '🕖': {\r\n    en: ['7 o\\'clock', 'clock face', 'time'],\r\n    ru: ['семь часов', 'циферблат', 'время']\r\n  },\r\n  '🕗': {\r\n    en: ['8 o\\'clock', 'clock face', 'time'],\r\n    ru: ['восемь часов', 'циферблат', 'время']\r\n  },\r\n  '🕘': {\r\n    en: ['9 o\\'clock', 'clock face', 'time'],\r\n    ru: ['девять часов', 'циферблат', 'время']\r\n  },\r\n  '🕙': {\r\n    en: ['10 o\\'clock', 'clock face', 'time'],\r\n    ru: ['десять часов', 'циферблат', 'время']\r\n  },\r\n  '🕚': {\r\n    en: ['11 o\\'clock', 'clock face', 'time'],\r\n    ru: ['одиннадцать часов', 'циферблат', 'время']\r\n  },\r\n  '🕛': {\r\n    en: ['12 o\\'clock', 'clock face', 'time'],\r\n    ru: ['двенадцать часов', 'циферблат', 'время']\r\n  },\r\n  '🕰️': {\r\n    en: ['mantel clock', 'clock', 'time'],\r\n    ru: ['настенные часы', 'часы', 'время']\r\n  },\r\n  '⏰': {\r\n    en: ['alarm clock', 'wake up', 'time'],\r\n    ru: ['будильник', 'пробуждение', 'время']\r\n  },\r\n  '⏱️': {\r\n    en: ['stopwatch', 'timer', 'time'],\r\n    ru: ['секундомер', 'таймер', 'время']\r\n  },\r\n  '⏲️': {\r\n    en: ['kitchen timer', 'timer', 'time'],\r\n    ru: ['кухонный таймер', 'таймер', 'время']\r\n  },\r\n  '⌚': {\r\n    en: ['watch', 'smartwatch', 'time'],\r\n    ru: ['часы', 'умные часы', 'время']\r\n  },\r\n\r\n  //------------------------- Symbols & Signs -------------------------\r\n  // Hearts\r\n  '❤️': {\r\n    en: ['heart', 'love', 'affection'],\r\n    ru: ['сердце', 'любовь', 'нежность']\r\n  },\r\n  '🧡': {\r\n    en: ['orange heart', 'warmth', 'care'],\r\n    ru: ['оранжевое сердце', 'теплота', 'забота']\r\n  },\r\n  '💛': {\r\n    en: ['yellow heart', 'friendship', 'happiness'],\r\n    ru: ['жёлтое сердце', 'дружба', 'счастье']\r\n  },\r\n  '💚': {\r\n    en: ['green heart', 'envy', 'nature', 'eco'],\r\n    ru: ['зелёное сердце', 'зависть', 'природа', 'эко']\r\n  },\r\n  '💙': {\r\n    en: ['blue heart', 'loyalty', 'trust'],\r\n    ru: ['синее сердце', 'верность', 'доверие']\r\n  },\r\n  '💜': {\r\n    en: ['purple heart', 'compassion', 'admiration'],\r\n    ru: ['фиолетовое сердце', 'сострадание', 'восхищение']\r\n  },\r\n  '🤎': {\r\n    en: ['brown heart', 'earth', 'stability'],\r\n    ru: ['коричневое сердце', 'земля', 'устойчивость']\r\n  },\r\n  '🖤': {\r\n    en: ['black heart', 'mourning', 'dark'],\r\n    ru: ['чёрное сердце', 'скорбь', 'тёмный']\r\n  },\r\n  '🤍': {\r\n    en: ['white heart', 'pure', 'peace'],\r\n    ru: ['белое сердце', 'чистый', 'мир']\r\n  },\r\n  '💔': {\r\n    en: ['broken heart', 'sad', 'heartbreak'],\r\n    ru: ['разбитое сердце', 'грусть', 'сердечная боль']\r\n  },\r\n  '❣️': {\r\n    en: ['heart exclamation', 'love', 'emotion'],\r\n    ru: ['сердечный восклицательный знак', 'любовь', 'эмоция']\r\n  },\r\n  '💕': {\r\n    en: ['two hearts', 'romance', 'affection'],\r\n    ru: ['два сердца', 'романтика', 'нежность']\r\n  },\r\n  '💞': {\r\n    en: ['revolving hearts', 'love', 'relationship'],\r\n    ru: ['вращающиеся сердца', 'любовь', 'отношения']\r\n  },\r\n  '💓': {\r\n    en: ['beating heart', 'emotion', 'passion'],\r\n    ru: ['бьющееся сердце', 'эмоция', 'страсть']\r\n  },\r\n  '💗': {\r\n    en: ['growing heart', 'love', 'expanding'],\r\n    ru: ['растущее сердце', 'любовь', 'расширяющееся']\r\n  },\r\n  '💖': {\r\n    en: ['sparkling heart', 'admiration', 'shine'],\r\n    ru: ['блестящее сердце', 'восхищение', 'сияние']\r\n  },\r\n  '💘': {\r\n    en: ['heart with arrow', 'love', 'romance'],\r\n    ru: ['сердце со стрелой', 'любовь', 'романтика']\r\n  },\r\n  '💝': {\r\n    en: ['heart with ribbon', 'gift', 'affection'],\r\n    ru: ['сердце с лентой', 'подарок', 'нежность']\r\n  },\r\n  '💟': {\r\n    en: ['heart decoration', 'symbol', 'love'],\r\n    ru: ['украшение сердца', 'символ', 'любовь']\r\n  },\r\n\r\n  // Religion\r\n  '☮️': {\r\n    en: ['peace', 'pacifism', 'symbol'],\r\n    ru: ['мир', 'пацифизм', 'символ']\r\n  },\r\n  '✝️': {\r\n    en: ['cross', 'christianity', 'religion'],\r\n    ru: ['крест', 'христианство', 'религия']\r\n  },\r\n  '☪️': {\r\n    en: ['star and crescent', 'islam', 'faith'],\r\n    ru: ['звезда и полумесяц', 'ислам', 'вера']\r\n  },\r\n  '🕉️': {\r\n    en: ['om', 'hinduism', 'spiritual'],\r\n    ru: ['ом', 'индуизм', 'духовный']\r\n  },\r\n  '☸️': {\r\n    en: ['dharma wheel', 'buddhism', 'karma'],\r\n    ru: ['колесо дхармы', 'буддизм', 'карма']\r\n  },\r\n  '✡️': {\r\n    en: ['star of david', 'judaism', 'faith'],\r\n    ru: ['звезда Давида', 'иудаизм', 'вера']\r\n  },\r\n  '🔯': {\r\n    en: ['hexagram', 'mystic', 'spiritual'],\r\n    ru: ['шестиконечная звезда', 'мистический', 'духовный']\r\n  },\r\n  '🕎': {\r\n    en: ['menorah', 'hanukkah', 'jewish'],\r\n    ru: ['менора', 'Ханука', 'еврейский']\r\n  },\r\n  '☯️': {\r\n    en: ['yin yang', 'balance', 'harmony'],\r\n    ru: ['инь-ян', 'баланс', 'гармония']\r\n  },\r\n  '☦️': {\r\n    en: ['orthodox cross', 'christianity', 'faith'],\r\n    ru: ['православный крест', 'христианство', 'вера']\r\n  },\r\n  '🛐': {\r\n    en: ['place of worship', 'religion', 'faith'],\r\n    ru: ['место поклонения', 'религия', 'вера']\r\n  },\r\n  '⛎': {\r\n    en: ['ophiuchus', 'zodiac', 'astrology'],\r\n    ru: ['змееносец', 'зодиак', 'астрология']\r\n  },\r\n\r\n  // Warning & Restrictions\r\n  '⚠️': {\r\n    en: ['warning', 'caution', 'alert'],\r\n    ru: ['предупреждение', 'осторожность', 'тревога']\r\n  },\r\n  '🚸': {\r\n    en: ['children crossing', 'school', 'pedestrian'],\r\n    ru: ['дети на переходе', 'школа', 'пешеход']\r\n  },\r\n  '⛔': {\r\n    en: ['no entry', 'prohibited', 'restricted'],\r\n    ru: ['вход запрещён', 'запрещено', 'ограничено']\r\n  },\r\n  '🚫': {\r\n    en: ['prohibited', 'no', 'forbidden'],\r\n    ru: ['запрещено', 'нет', 'запрещено']\r\n  },\r\n  '☢️': {\r\n    en: ['radioactive', 'hazard', 'danger'],\r\n    ru: ['радиоактивный', 'опасность', 'угроза']\r\n  },\r\n  '☣️': {\r\n    en: ['biohazard', 'toxic', 'warning'],\r\n    ru: ['биологическая опасность', 'ядовитый', 'предупреждение']\r\n  },\r\n\r\n  // Math Symbols\r\n  '➕': {\r\n    en: ['plus', 'addition', 'math'],\r\n    ru: ['плюс', 'сложение', 'математика']\r\n  },\r\n  '➖': {\r\n    en: ['minus', 'subtraction', 'math'],\r\n    ru: ['минус', 'вычитание', 'математика']\r\n  },\r\n  '➗': {\r\n    en: ['division', 'divide', 'math'],\r\n    ru: ['деление', 'делить', 'математика']\r\n  },\r\n  '✖️': {\r\n    en: ['multiplication', 'times', 'math'],\r\n    ru: ['умножение', 'раз', 'математика']\r\n  },\r\n  '♾️': {\r\n    en: ['infinity', 'limitless', 'math'],\r\n    ru: ['бесконечность', 'безграничный', 'математика']\r\n  },\r\n  '💲': {\r\n    en: ['dollar', 'money', 'currency'],\r\n    ru: ['доллар', 'деньги', 'валюта']\r\n  },\r\n  '💱': {\r\n    en: ['currency exchange', 'finance', 'money'],\r\n    ru: ['обмен валюты', 'финансы', 'деньги']\r\n  },\r\n\r\n  // Arrows\r\n  '⬆️': {\r\n    en: ['up arrow', 'increase', 'direction'],\r\n    ru: ['стрелка вверх', 'увеличение', 'направление']\r\n  },\r\n  '↗️': {\r\n    en: ['up-right arrow', 'growth', 'move'],\r\n    ru: ['стрелка вверх-вправо', 'рост', 'движение']\r\n  },\r\n  '➡️': {\r\n    en: ['right arrow', 'next', 'forward'],\r\n    ru: ['стрелка вправо', 'далее', 'вперёд']\r\n  },\r\n  '↘️': {\r\n    en: ['down-right arrow', 'decrease', 'move'],\r\n    ru: ['стрелка вниз-вправо', 'уменьшение', 'движение']\r\n  },\r\n  '⬇️': {\r\n    en: ['down arrow', 'lower', 'decline'],\r\n    ru: ['стрелка вниз', 'понижение', 'снижение']\r\n  },\r\n  '↙️': {\r\n    en: ['down-left arrow', 'falling', 'move'],\r\n    ru: ['стрелка вниз-влево', 'падение', 'движение']\r\n  },\r\n  '⬅️': {\r\n    en: ['left arrow', 'back', 'previous'],\r\n    ru: ['стрелка влево', 'назад', 'предыдущий']\r\n  },\r\n  '↖️': {\r\n    en: ['up-left arrow', 'direction', 'move'],\r\n    ru: ['стрелка вверх-влево', 'направление', 'движение']\r\n  },\r\n  '↕️': {\r\n    en: ['vertical arrows', 'up down', 'change'],\r\n    ru: ['вертикальные стрелки', 'вверх вниз', 'изменение']\r\n  },\r\n  '↔️': {\r\n    en: ['horizontal arrows', 'left right', 'switch'],\r\n    ru: ['горизонтальные стрелки', 'влево вправо', 'переключение']\r\n  },\r\n  '↩️': {\r\n    en: ['back arrow', 'undo', 'return'],\r\n    ru: ['стрелка назад', 'отмена', 'возврат']\r\n  },\r\n  '↪️': {\r\n    en: ['right curved arrow', 'redirect', 'turn'],\r\n    ru: ['изогнутая стрелка вправо', 'перенаправление', 'поворот']\r\n  },\r\n  '⤴️': {\r\n    en: ['up-right arrow', 'diagonal', 'move'],\r\n    ru: ['диагональная стрелка вверх-вправо', 'диагональ', 'движение']\r\n  },\r\n  '⤵️': {\r\n    en: ['down-right arrow', 'diagonal', 'move'],\r\n    ru: ['диагональная стрелка вниз-вправо', 'диагональ', 'движение']\r\n  },\r\n  '🔃': {\r\n    en: ['repeat', 'cycle', 'refresh'],\r\n    ru: ['повтор', 'цикл', 'обновление']\r\n  },\r\n  '🔄': {\r\n    en: ['counterclockwise arrows', 'reload', 'sync'],\r\n    ru: ['стрелки против часовой стрелки', 'перезагрузка', 'синхронизация']\r\n  },\r\n\r\n  // Miscellaneous Symbols\r\n  '🔆': {\r\n    en: ['bright', 'high brightness', 'sun'],\r\n    ru: ['яркий', 'высокая яркость', 'солнце']\r\n  },\r\n  '📶': {\r\n    en: ['signal', 'network', 'connection'],\r\n    ru: ['сигнал', 'сеть', 'соединение']\r\n  },\r\n  '🎦': {\r\n    en: ['cinema', 'movies', 'entertainment'],\r\n    ru: ['кино', 'фильмы', 'развлечения']\r\n  },\r\n  '🔅': {\r\n    en: ['dim', 'low brightness', 'light'],\r\n    ru: ['тусклый', 'низкая яркость', 'свет']\r\n  },\r\n  '♻️': {\r\n    en: ['recycle', 'eco', 'sustainability'],\r\n    ru: ['переработка', 'эко', 'устойчивость']\r\n  },\r\n  '✅': {\r\n    en: ['check mark', 'yes', 'approved'],\r\n    ru: ['галочка', 'да', 'одобрено']\r\n  },\r\n  '❌': {\r\n    en: ['cross mark', 'no', 'wrong'],\r\n    ru: ['крестик', 'нет', 'неправильно']\r\n  },\r\n  '❎': {\r\n    en: ['negative cross', 'decline', 'cancel'],\r\n    ru: ['отрицательный крест', 'отказ', 'отмена']\r\n  },\r\n  '➰': {\r\n    en: ['curly loop', 'infinity', 'twist'],\r\n    ru: ['извилистая петля', 'бесконечность', 'скрутка']\r\n  },\r\n  '➿': {\r\n    en: ['double curly loop', 'loop', 'repeat'],\r\n    ru: ['двойная извилистая петля', 'петля', 'повтор']\r\n  },\r\n  '〽️': {\r\n    en: ['part alternation', 'music', 'symbol'],\r\n    ru: ['знак чередования', 'музыка', 'символ']\r\n  },\r\n  '✳️': {\r\n    en: ['eight-spoked asterisk', 'star', 'highlight'],\r\n    ru: ['восьмиконечная астериска', 'звезда', 'акцент']\r\n  },\r\n  '✴️': {\r\n    en: ['eight-pointed star', 'shine', 'special'],\r\n    ru: ['восьмиконечная звезда', 'сияние', 'особый']\r\n  },\r\n  '❇️': {\r\n    en: ['sparkle', 'highlight', 'shine'],\r\n    ru: ['сверкание', 'акцент', 'сияние']\r\n  },\r\n  '©️': {\r\n    en: ['copyright', 'legal', 'rights'],\r\n    ru: ['авторское право', 'юридический', 'права']\r\n  },\r\n  '®️': {\r\n    en: ['registered', 'trademark', 'brand'],\r\n    ru: ['зарегистрировано', 'торговая марка', 'бренд']\r\n  },\r\n  '™️': {\r\n    en: ['trademark', 'brand', 'symbol'],\r\n    ru: ['торговая марка', 'бренд', 'символ']\r\n  },\r\n\r\n  //------------------------- Flags -------------------------\r\n  // Special Flags\r\n  '🏁': {\r\n    en: ['checkered flag', 'finish line', 'racing'],\r\n    ru: ['шашечный флаг', 'финишная черта', 'гонки']\r\n  },\r\n  '🚩': {\r\n    en: ['triangular flag', 'mark', 'warning'],\r\n    ru: ['треугольный флаг', 'метка', 'предупреждение']\r\n  },\r\n  '🎌': {\r\n    en: ['crossed flags', 'celebration', 'Japan'],\r\n    ru: ['перекрещённые флаги', 'празднование', 'Япония']\r\n  },\r\n  '🏴': {\r\n    en: ['black flag', 'protest', 'symbol'],\r\n    ru: ['чёрный флаг', 'протест', 'символ']\r\n  },\r\n  '🏳️': {\r\n    en: ['white flag', 'surrender', 'peace'],\r\n    ru: ['белый флаг', 'капитуляция', 'мир']\r\n  },\r\n  '🏳️‍🌈': {\r\n    en: ['rainbow flag', 'LGBTQ+', 'pride'],\r\n    ru: ['радужный флаг', 'ЛГБТК+', 'гордость']\r\n  },\r\n  '🏳️‍⚧️': {\r\n    en: ['transgender flag', 'trans', 'pride'],\r\n    ru: ['трансгендерный флаг', 'транс', 'гордость']\r\n  },\r\n  '🏴‍☠️': {\r\n    en: ['pirate flag', 'skull', 'danger'],\r\n    ru: ['пиратский флаг', 'череп', 'опасность']\r\n  },\r\n\r\n  // Country Flags (Sample)\r\n  '🇺🇸': {\r\n    en: ['United States', 'USA', 'America'],\r\n    ru: ['Соединённые Штаты', 'США', 'Америка']\r\n  },\r\n  '🇬🇧': {\r\n    en: ['United Kingdom', 'UK', 'Britain'],\r\n    ru: ['Соединённое Королевство', 'Великобритания', 'Британия']\r\n  },\r\n  '🇯🇵': {\r\n    en: ['Japan', 'Japanese', 'Asia'],\r\n    ru: ['Япония', 'японский', 'Азия']\r\n  },\r\n  '🇰🇷': {\r\n    en: ['South Korea', 'Korea', 'Asian'],\r\n    ru: ['Южная Корея', 'Корея', 'азиатский']\r\n  },\r\n  '🇩🇪': {\r\n    en: ['Germany', 'Deutschland', 'Europe'],\r\n    ru: ['Германия', 'Германия', 'Европа']\r\n  },\r\n  '🇨🇳': {\r\n    en: ['China', 'Chinese', 'Asia'],\r\n    ru: ['Китай', 'китайский', 'Азия']\r\n  },\r\n  '🇧🇷': {\r\n    en: ['Brazil', 'Brasil', 'South America'],\r\n    ru: ['Бразилия', 'Бразилия', 'Южная Америка']\r\n  },\r\n  '🇮🇳': {\r\n    en: ['India', 'Indian', 'Asia'],\r\n    ru: ['Индия', 'индийский', 'Азия']\r\n  },\r\n  '🇫🇷': {\r\n    en: ['France', 'French', 'Europe'],\r\n    ru: ['Франция', 'французский', 'Европа']\r\n  },\r\n  '🇪🇸': {\r\n    en: ['Spain', 'Spanish', 'Europe'],\r\n    ru: ['Испания', 'испанский', 'Европа']\r\n  },\r\n  '🇮🇹': {\r\n    en: ['Italy', 'Italian', 'Europe'],\r\n    ru: ['Италия', 'итальянский', 'Европа']\r\n  },\r\n  '🇷🇺': {\r\n    en: ['Russia', 'Russian', 'Europe'],\r\n    ru: ['Россия', 'русский', 'Европа']\r\n  },\r\n  '🇨🇦': {\r\n    en: ['Canada', 'Canadian', 'North America'],\r\n    ru: ['Канада', 'канадский', 'Северная Америка']\r\n  },\r\n  '🇦🇺': {\r\n    en: ['Australia', 'Aussie', 'Oceania'],\r\n    ru: ['Австралия', 'австралиец', 'Океания']\r\n  },\r\n  '🇳🇿': {\r\n    en: ['New Zealand', 'Kiwi', 'Oceania'],\r\n    ru: ['Новая Зеландия', 'киви', 'Океания']\r\n  },\r\n  // Additional Country Flags (Extended)\r\n  '🇲🇽': {\r\n    en: ['Mexico', 'Mexican', 'Latin America'],\r\n    ru: ['Мексика', 'мексиканский', 'Латинская Америка']\r\n  },\r\n  '🇦🇷': {\r\n    en: ['Argentina', 'Argentinian', 'South America'],\r\n    ru: ['Аргентина', 'аргентинский', 'Южная Америка']\r\n  },\r\n  '🇵🇰': {\r\n    en: ['Pakistan', 'Pakistani', 'Asia'],\r\n    ru: ['Пакистан', 'пакистанский', 'Азия']\r\n  },\r\n  '🇪🇬': {\r\n    en: ['Egypt', 'Egyptian', 'Africa'],\r\n    ru: ['Египет', 'египетский', 'Африка']\r\n  },\r\n  '🇸🇪': {\r\n    en: ['Sweden', 'Swedish', 'Europe'],\r\n    ru: ['Швеция', 'шведский', 'Европа']\r\n  },\r\n  '🇳🇴': {\r\n    en: ['Norway', 'Norwegian', 'Europe'],\r\n    ru: ['Норвегия', 'норвежский', 'Европа']\r\n  },\r\n  '🇳🇱': {\r\n    en: ['Netherlands', 'Dutch', 'Europe'],\r\n    ru: ['Нидерланды', 'голландский', 'Европа']\r\n  },\r\n  '🇨🇭': {\r\n    en: ['Switzerland', 'Swiss', 'Europe'],\r\n    ru: ['Швейцария', 'швейцарский', 'Европа']\r\n  },\r\n  '🇹🇷': {\r\n    en: ['Turkey', 'Turkish', 'Eurasia'],\r\n    ru: ['Турция', 'турецкий', 'Евразия']\r\n  },\r\n  '🇮🇩': {\r\n    en: ['Indonesia', 'Indonesian', 'Asia'],\r\n    ru: ['Индонезия', 'индонезийский', 'Азия']\r\n  },\r\n  '🇸🇬': {\r\n    en: ['Singapore', 'Singaporean', 'Asia'],\r\n    ru: ['Сингапур', 'сингапурский', 'Азия']\r\n  },\r\n  '🇮🇱': {\r\n    en: ['Israel', 'Israeli', 'Middle East'],\r\n    ru: ['Израиль', 'израильский', 'Ближний Восток']\r\n  },\r\n  '🇵🇹': {\r\n    en: ['Portugal', 'Portuguese', 'Europe'],\r\n    ru: ['Португалия', 'португальский', 'Европа']\r\n  },\r\n  '🇵🇱': {\r\n    en: ['Poland', 'Polish', 'Europe'],\r\n    ru: ['Польша', 'польский', 'Европа']\r\n  },\r\n  '🇹🇭': {\r\n    en: ['Thailand', 'Thai', 'Asia'],\r\n    ru: ['Таиланд', 'тайский', 'Азия']\r\n  }\r\n};\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/emojiData.js?");

/***/ }),

/***/ "./src/data/icons.js":
/*!***************************!*\
  !*** ./src/data/icons.js ***!
  \***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   addSVG: () => (/* binding */ addSVG),\n/* harmony export */   blockedUsersSVG: () => (/* binding */ blockedUsersSVG),\n/* harmony export */   clearSVG: () => (/* binding */ clearSVG),\n/* harmony export */   closeSVG: () => (/* binding */ closeSVG),\n/* harmony export */   collapseSVG: () => (/* binding */ collapseSVG),\n/* harmony export */   editSVG: () => (/* binding */ editSVG),\n/* harmony export */   errorSVG: () => (/* binding */ errorSVG),\n/* harmony export */   eventsSVG: () => (/* binding */ eventsSVG),\n/* harmony export */   expandSVG: () => (/* binding */ expandSVG),\n/* harmony export */   exportSVG: () => (/* binding */ exportSVG),\n/* harmony export */   helpSVG: () => (/* binding */ helpSVG),\n/* harmony export */   importSVG: () => (/* binding */ importSVG),\n/* harmony export */   infoSVG: () => (/* binding */ infoSVG),\n/* harmony export */   loadSVG: () => (/* binding */ loadSVG),\n/* harmony export */   magicWandSVG: () => (/* binding */ magicWandSVG),\n/* harmony export */   openSVG: () => (/* binding */ openSVG),\n/* harmony export */   removeSVG: () => (/* binding */ removeSVG),\n/* harmony export */   sendSVG: () => (/* binding */ sendSVG),\n/* harmony export */   smileSVG: () => (/* binding */ smileSVG),\n/* harmony export */   successSVG: () => (/* binding */ successSVG),\n/* harmony export */   userColorsSVG: () => (/* binding */ userColorsSVG),\n/* harmony export */   warningSVG: () => (/* binding */ warningSVG)\n/* harmony export */ });\nconst svgUrl = \"http://www.w3.org/2000/svg\";\r\nconst iconSize = 24;\r\n\r\nconst sendSVG = `\r\n  <svg class=\"send\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize}\" \r\n  height=\"${iconSize}\" \r\n  viewBox=\"-10 -10 270 270\">\r\n    <path d=\"M22.32 98.04l-19.04 -87.15c-0.75,-3.46 0.48,-6.84 3.29,-9 2.81,-2.17 6.39,-2.49 9.55,-0.87l225.95 116.02c3.07,1.57 4.87,4.52 4.87,7.96 0,3.44 -1.8,6.39 -4.87,7.96l-225.95 116.02c-3.16,1.62 -6.74,1.3 -9.55,-0.87 -2.81,-2.16 -4.04,-5.54 -3.29,-9l19.04 -87.15c0.79,-3.62 3.53,-6.26 7.18,-6.91l102.6 -18.19c0.91,-0.16 1.56,-0.94 1.56,-1.86 0,-0.92 -0.65,-1.7 -1.56,-1.86l-102.6 -18.19c-3.65,-0.65 -6.39,-3.29 -7.18,-6.91z\"/>\r\n  </svg>`;\r\n\r\nconst closeSVG = `\r\n  <svg class=\"no\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\" \r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n      <path d=\"M46.62 0l156.76 0c25.64,0 46.62,20.98 46.62,46.62l0 156.75c0,25.65 -20.98,46.63 -46.62,46.63l-156.76 0c-25.64,0 -46.62,-20.98 -46.62,-46.63l0 -156.75c0,-25.64 20.98,-46.62 46.62,-46.62zm45.71 70.24l32.67 32.67 32.67 -32.67c2.73,-2.73 7.18,-2.73 9.91,0l12.18 12.18c2.73,2.73 2.73,7.18 0,9.91l-32.67 32.67 32.67 32.66c2.73,2.74 2.73,7.19 0,9.92l-12.18 12.18c-2.73,2.73 -7.18,2.73 -9.91,0l-32.67 -32.67 -32.67 32.67c-2.73,2.73 -7.18,2.73 -9.91,0l-12.18 -12.18c-2.73,-2.73 -2.73,-7.18 0,-9.92l32.67 -32.66 -32.67 -32.67c-2.73,-2.73 -2.73,-7.18 0,-9.91l12.18 -12.18c2.73,-2.73 7.18,-2.73 9.91,0z\"/>\r\n  </svg>`;\r\n\r\nconst openSVG = `\r\n  <svg class=\"yes\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\" \r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n      <path d=\"M46.62 0l156.76 0c25.64,0 46.62,20.98 46.62,46.62l0 156.75c0,25.65 -20.98,46.63 -46.62,46.63l-156.76 0c-25.64,0 -46.62,-20.98 -46.62,-46.63l0 -156.75c0,-25.64 20.98,-46.62 46.62,-46.62zm15.5 135.79l57.92 -57.93c2.73,-2.73 7.19,-2.72 9.92,0.01l57.92 57.92c2.73,2.73 2.73,7.18 0,9.91l-12.18 12.18c-2.73,2.73 -7.18,2.73 -9.92,0l-35.82 -35.83c-2.73,-2.73 -7.19,-2.73 -9.92,0l-35.82 35.83c-2.74,2.73 -7.19,2.73 -9.92,0l-12.18 -12.18c-2.73,-2.73 -2.73,-7.18 0,-9.91z\"/>\r\n  </svg>`;\r\n\r\nconst collapseSVG = `\r\n  <svg class=\"yes\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.62 0l156.76 0c25.64,0 46.62,20.98 46.62,46.62l0 156.75c0,25.65 -20.98,46.63 -46.62,46.63l-156.76 0c-25.64,0 -46.62,-20.98 -46.62,-46.63l0 -156.75c0,-25.64 20.98,-46.62 46.62,-46.62zm109.99 181.69l-75.07 0c-7.3,0 -13.23,-5.92 -13.23,-13.22l0 -75.08c0,-2.35 1.92,-4.28 4.28,-4.28l17.9 0c2.35,0 4.27,1.93 4.27,4.28l0 32.81c0,1.77 1.01,3.28 2.64,3.96 1.63,0.67 3.42,0.33 4.66,-0.93l59.68 -59.68c1.67,-1.65 4.38,-1.65 6.05,0l12.66 12.66c1.66,1.67 1.66,4.38 0,6.05l-59.68 59.68c-1.26,1.24 -1.6,3.03 -0.93,4.66 0.68,1.63 2.19,2.64 3.96,2.64l32.81 0c2.35,0 4.28,1.92 4.28,4.28l0 17.9c0,2.36 -1.93,4.28 -4.28,4.28z\"/>\r\n  </svg>`;\r\n\r\nconst expandSVG = `\r\n  <svg class=\"no\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.62 0l156.76 0c25.64,0 46.62,20.98 46.62,46.62l0 156.75c0,25.65 -20.98,46.63 -46.62,46.63l-156.76 0c-25.64,0 -46.62,-20.98 -46.62,-46.63l0 -156.75c0,-25.64 20.98,-46.62 46.62,-46.62zm46.77 68.31l75.07 0c7.3,0 13.23,5.92 13.23,13.22l0 75.08c0,2.35 -1.92,4.28 -4.28,4.28l-17.9 0c-2.35,0 -4.27,-1.93 -4.27,-4.28l0 -32.81c0,-1.77 -1.01,-3.28 -2.64,-3.96 -1.63,-0.67 -3.42,-0.33 -4.66,0.93l-59.68 59.68c-1.67,1.65 -4.38,1.65 -6.05,0l-12.66 -12.66c-1.66,-1.67 -1.66,-4.38 0,-6.05l59.68 -59.68c1.26,-1.24 1.6,-3.03 0.93,-4.66 -0.68,-1.63 -2.19,-2.64 -3.96,-2.64l-32.81 0c-2.35,0 -4.28,-1.92 -4.28,-4.27l0 -17.9c0,-2.36 1.93,-4.28 4.28,-4.28z\"/>\r\n  </svg>`;\r\n\r\nconst helpSVG = `\r\n  <svg class=\"help\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.59 0l156.82 0c25.65,0 46.59,20.94 46.59,46.59l0 156.82c0,25.65 -20.94,46.59 -46.59,46.59l-156.82 0c-25.65,0 -46.59,-20.94 -46.59,-46.59l0 -156.82c0,-25.65 20.94,-46.59 46.59,-46.59zm130.96 87.85c0,6.57 -1.03,12.72 -3.08,18.06 -2.05,5.34 -4.93,9.85 -8.42,13.75 -3.69,3.9 -8,7.39 -13.13,10.47 -4.11,2.46 -8.83,4.93 -13.96,6.98 -1.64,0.82 -2.87,2.46 -2.87,4.51l0 15.19c0,2.67 -2.06,4.72 -4.73,4.72l-25.04 0c-2.66,0 -4.92,-2.05 -4.92,-4.72l0 -25.65c0,-2.26 1.44,-3.9 3.49,-4.52 2.87,-1.02 5.95,-2.05 9.23,-3.28 4.52,-1.85 8.62,-3.9 12.11,-6.57 3.9,-2.67 6.78,-5.75 9.24,-9.24 2.46,-3.49 3.49,-7.59 3.49,-12.31 0,-6.78 -2.05,-11.7 -6.36,-14.78 -4.31,-2.88 -10.06,-4.52 -17.65,-4.52 -5.75,0 -11.7,1.24 -18.07,3.7 -5.33,2.05 -9.85,4.31 -13.13,6.36 -1.03,0.62 -2.26,0.62 -3.29,0 -1.02,-0.62 -1.64,-1.64 -1.64,-2.87l0 -23.2c0,-2.05 1.23,-3.9 3.08,-4.51 4.1,-1.44 9.44,-3.08 15.8,-4.52 8.42,-2.05 17.24,-3.07 26.89,-3.07 8.42,0 16.01,1.02 22.58,3.07 6.36,2.06 12.11,4.72 16.62,8.42 4.52,3.49 7.8,7.8 10.27,12.72 2.26,4.73 3.49,10.06 3.49,15.81l0 0zm-46.19 114.12l-25.04 0c-2.67,0 -4.92,-2.05 -4.92,-4.72l0 -17.24c0,-2.67 2.25,-4.72 4.92,-4.72l25.04 0c2.67,0 4.72,2.05 4.72,4.72l0 17.24c0,2.67 -2.05,4.72 -4.72,4.72z\"/>\r\n  </svg>`;\r\n\r\nconst magicWandSVG = `\r\n  <svg class=\"theme\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\" \r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.59 0l156.82 0c25.65,0 46.59,20.94 46.59,46.59l0 156.82c0,25.65 -20.94,46.59 -46.59,46.59l-156.82 0c-25.65,0 -46.59,-20.94 -46.59,-46.59l0 -156.82c0,-25.65 20.94,-46.59 46.59,-46.59zm5.64 173.13l65.47 -60.21c4.39,-4.03 11.2,-3.74 15.41,0.47l3.42 3.42c4.21,4.21 4.5,11.02 0.47,15.41l-60.22 65.47c-2.17,2.37 -4.86,3.69 -8.08 3.79 -3.21,0.1 -6.02,-1.01 -8.29,-3.29l-8.68 -8.68c-2.28,-2.28 -3.39,-5.08 -3.29,-8.3 0.1,-3.21 1.42,-5.9 3.79,-8.08zm142.53 -113.72l-4.72 22.03 11.64 21.05c0.62,1.11 0.63,2.35 0.05,3.47 -0.59,1.13 -1.62,1.82 -2.87,1.95l-22.41 2.32 -16.43 17.58c-0.86,0.93 -2.03,1.32 -3.28,1.11 -1.25,-0.21 -2.23,-0.97 -2.74,-2.12l-9.13 -20.59 -21.8 -10.19c-1.15,-0.54 -1.89,-1.53 -2.07,-2.78 -0.19,-1.26 0.23,-2.42 1.17,-3.27l16.76 -15.05 2.96 -23.87c0.16,-1.26 0.87,-2.27 2.01,-2.83 1.13,-0.57 2.37,-0.53 3.47,0.11l19.48 11.29 23.63 -4.57c1.24,-0.24 2.42,0.13 3.31,1.03 0.89,0.91 1.23,2.09 0.97,3.33z\"/>\r\n  </svg>`;\r\n\r\nconst userColorsSVG = `\r\n  <svg class=\"colors\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.59 0l156.82 0c25.65,0 46.59,20.94 46.59,46.59l0 156.82c0,25.65 -20.94,46.59 -46.59,46.59l-156.82 0c-25.65,0 -46.59,-20.94 -46.59,-46.59l0 -156.82c0,-25.65 20.94,-46.59 46.59,-46.59zm78.41 47.82c9.23,0 17.59,3.75 23.65,9.8 6.05,6.05 9.79,14.41 9.79,23.64 0,9.23 -3.74,17.6 -9.79,23.65 -6.06,6.05 -14.42,9.79 -23.65,9.79 -9.23,0 -17.59,-3.74 -23.64,-9.79 -6.06,-6.05 -9.8,-14.42 -9.8,-23.65 0,-9.23 3.74,-17.59 9.8,-23.64 6.05,-6.05 14.41,-9.8 23.64,-9.8zm-73.59 146.17c1.72,-38.79 33.75,-70.35 73.59,-70.35 39.84,0 71.87,31.56 73.59,70.35 0.17,4.09 -3.07,7.49 -7.16,7.49l-14.83 0c-3.81,0 -6.94,-2.98 -7.16,-6.77 -1.34,-23.41 -20.72,-41.9 -44.44,-41.9 -23.51,0 -43.09,18.27 -44.44,41.9 -0.21,3.79 -3.35,6.77 -7.15,6.77l-14.84 0c-4.09,0 -7.33,-3.4 -7.16,-7.49z\"/>\r\n</svg>`;\r\n\r\nconst blockedUsersSVG = `\r\n  <svg class=\"blocked\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.59 0l156.82 0c25.65,0 46.59,20.94 46.59,46.59l0 156.82c0,25.65 -20.94,46.59 -46.59,46.59l-156.82 0c-25.65,0 -46.59,-20.94 -46.59,-46.59l0 -156.82c0,-25.65 20.94,-46.59 46.59,-46.59zm78.41 45.74c43.78,0 79.26,35.49 79.26,79.26 0,43.78 -35.48,79.26 -79.26,79.26 -43.77,0 -79.26,-35.49 -79.26,-79.26 0,-43.77 35.49,-79.26 79.26,-79.26zm-28.51 33.08l74.7 74.69c13.19,-21.32 9.98,-49.1 -7.81,-66.88 -17.79,-17.79 -45.56,-21.01 -66.89,-7.81zm57.02 92.37l-74.69 -74.7c-13.19,21.32 -9.98,49.1 7.8,66.88 17.81,17.78 45.54,21.02 66.89,7.82z\"/>\r\n</svg>`;\r\n\r\nconst smileSVG = `\r\n  <svg class=\"smile\" xmlns=\"${svgUrl}\"\r\n  width=\"${iconSize}\"\r\n  height=\"${iconSize}\"\r\n  viewBox=\"-10 -10 270 270\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <defs>\r\n      <linearGradient id=\"id0\" gradientUnits=\"objectBoundingBox\" x1=\"50.0025%\" y1=\"0%\" x2=\"50.0025%\" y2=\"100%\">\r\n        <stop offset=\"0\" style=\"stop-opacity:0.8; stop-color:white\"/>\r\n        <stop offset=\"1\" style=\"stop-opacity:0; stop-color:#FEFEFE\"/>\r\n      </linearGradient>\r\n      <radialGradient id=\"id1\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(6.12322E-17 0.999998 -0.999998 6.12322E-17 250 0)\" cx=\"125\" cy=\"125\" r=\"165.74\" fx=\"125\" fy=\"125\">\r\n        <stop offset=\"0\" style=\"stop-opacity:0; stop-color:black\"/>\r\n        <stop offset=\"0.8\" style=\"stop-opacity:0; stop-color:black\"/>\r\n        <stop offset=\"1\" style=\"stop-opacity:0.2; stop-color:black\"/>\r\n      </radialGradient>\r\n      <radialGradient id=\"id2\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(6.12322E-17 0.999998 -0.999998 6.12322E-17 250 0)\" cx=\"125\" cy=\"125\" r=\"165.74\" fx=\"125\" fy=\"125\">\r\n        <stop offset=\"0\" style=\"stop-opacity:0.4; stop-color:#FEFEFE\"/>\r\n        <stop offset=\"0.701961\" style=\"stop-opacity:0.254902; stop-color:#FEFEFE\"/>\r\n        <stop offset=\"1\" style=\"stop-opacity:0; stop-color:white\"/>\r\n      </radialGradient>\r\n    </defs>\r\n\r\n    <g id=\"smile_svg\">\r\n      <path\r\n        id=\"smile_background\"\r\n        fill=\"#261717\"\r\n        transform=\"translate(125 125) scale(0.9) translate(-125 -125)\"\r\n        d=\"M125 0c69.04,0 125,55.96 125,125 0,69.04 -55.96,125 -125,125 -69.04,0 -125,-55.96 -125,-125 0,-69.04 55.96,-125 125,-125z\"/>\r\n\r\n      <path\r\n        id=\"smile_color\"\r\n        d=\"M81.5 78.58c9.51,0 17.23,8.98 17.23,20.05 0,11.08 -7.72,20.05 -17.23,20.05 -9.51,0 -17.22,-8.97 -17.22,-20.05 0,-11.07 7.71,-20.05 17.22,-20.05\r\n           zm87 0c-9.51,0 -17.23,8.98 -17.23,20.05 0,11.08 7.72,20.05 17.23,20.05 9.51,0 17.22,-8.97 17.22,-20.05 0,-11.07 -7.71,-20.05 -17.22,-20.05\r\n           zm-43.5 171.42c69.04,0 125,-55.96 125,-125 0,-69.04 -55.96,-125 -125,-125 -69.04,0 -125,55.96 -125,125 0,69.04 55.96,125 125,125\r\n           zm-48.25 -90.43c7.62,5.06 24.35,14.68 48.25,14.68 23.9,0 40.63,-9.62 48.25,-14.68 1.98,-1.32 4.64,-0.88 6.09,1 1.45,1.89 1.2,4.56 -0.58,6.14\r\n           -8.12,7.24 -26.48,20.11 -53.76,20.11 -27.28,0 -45.64,-12.87 -53.76,-20.11 -1.78,-1.58 -2.03,-4.25 -0.58,-6.14 1.45,-1.88 4.11,-2.32 6.09,-1z\"/>\r\n\r\n      <path\r\n        id=\"smile_around_shadow\"\r\n        fill=\"url(#id1)\"\r\n        d=\"M81.5 78.58c9.51,0 17.23,8.98 17.23,20.05 0,11.08 -7.72,20.05 -17.23,20.05 -9.51,0 -17.22,-8.97 -17.22,-20.05 0,-11.07 7.71,-20.05 17.22,-20.05\r\n           zm87 0c-9.51,0 -17.23,8.98 -17.23,20.05 0,11.08 7.72,20.05 17.23,20.05 9.51,0 17.22,-8.97 17.22,-20.05 0,-11.07 -7.71,-20.05 -17.22,-20.05\r\n           zm-43.5 171.42c69.04,0 125,-55.96 125,-125 0,-69.04 -55.96,-125 -125,-125 -69.04,0 -125,55.96 -125,125 0,69.04 55.96,125 125,125\r\n           zm-48.25 -90.43c7.62,5.06 24.35,14.68 48.25,14.68 23.9,0 40.63,-9.62 48.25,-14.68 1.98,-1.32 4.64,-0.88 6.09,1 1.45,1.89 1.2,4.56 -0.58,6.14\r\n           -8.12,7.24 -26.48,20.11 -53.76,20.11 -27.28,0 -45.64,-12.87 -53.76,-20.11 -1.78,-1.58 -2.03,-4.25 -0.58,-6.14 1.45,-1.88 4.11,-2.32 6.09,-1z\"/>\r\n\r\n      <path\r\n        id=\"smile_front_light\"\r\n        fill=\"url(#id2)\"\r\n        d=\"M81.5 78.58c9.51,0 17.23,8.98 17.23,20.05 0,11.08 -7.72,20.05 -17.23,20.05 -9.51,0 -17.22,-8.97 -17.22,-20.05 0,-11.07 7.71,-20.05 17.22,-20.05\r\n           zm87 0c-9.51,0 -17.23,8.98 -17.23,20.05 0,11.08 7.72,20.05 17.23,20.05 9.51,0 17.22,-8.97 17.22,-20.05 0,-11.07 -7.71,-20.05 -17.22,-20.05\r\n           zm-43.5 171.42c69.04,0 125,-55.96 125,-125 0,-69.04 -55.96,-125 -125,-125 -69.04,0 -125,55.96 -125,125 0,69.04 55.96,125 125,125\r\n           zm-48.25 -90.43c7.62,5.06 24.35,14.68 48.25,14.68 23.9,0 40.63,-9.62 48.25,-14.68 1.98,-1.32 4.64,-0.88 6.09,1 1.45,1.89 1.2,4.56 -0.58,6.14\r\n           -8.12,7.24 -26.48,20.11 -53.76,20.11 -27.28,0 -45.64,-12.87 -53.76,-20.11 -1.78,-1.58 -2.03,-4.25 -0.58,-6.14 1.45,-1.88 4.11,-2.32 6.09,-1z\"/>\r\n\r\n      <path\r\n        id=\"smile_left_eye_highlight\"\r\n        fill=\"url(#id0)\"\r\n        d=\"M79.25 82.88c-4.34,0 -7.87,4.1 -7.87,9.16 0,5.06 3.53,9.16 7.87,9.16 4.35,0 7.88,-4.1 7.88,-9.16 0,-5.06 -3.53,-9.16 -7.88,-9.16z\"/>\r\n\r\n      <path\r\n        id=\"smile_right_eye_highlight\"\r\n        fill=\"url(#id0)\"\r\n        d=\"M166.25 82.88c-4.35,0 -7.87,4.1 -7.87,9.16 0,5.06 3.52,9.16 7.87,9.16 4.35,0 7.87,-4.1 7.87,-9.16 0,-5.06 -3.52,-9.16 -7.87,-9.16z\"/>\r\n    </g>\r\n  </svg>`;\r\n\r\nconst addSVG = `\r\n  <svg class=\"add-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\r\n    <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\r\n  </svg>`;\r\n\r\nconst editSVG = `\r\n  <svg class=\"edit-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"></path>\r\n    <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"></path>\r\n  </svg>`;\r\n\r\nconst removeSVG = `\r\n  <svg class=\"remove-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n    <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n  </svg>`;\r\n\r\nconst importSVG = `\r\n  <svg class=\"export-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\r\n    <polyline points=\"7 10 12 15 17 10\"></polyline>\r\n    <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line>\r\n  </svg>`;\r\n\r\nconst exportSVG = `\r\n  <svg class=\"import-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\r\n    <polyline points=\"17 8 12 3 7 8\"></polyline>\r\n    <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"></line>\r\n  </svg>`;\r\n\r\nconst loadSVG = `\r\n  <svg class=\"load-icon\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 2}\" \r\n  height=\"${iconSize / 2}\" \r\n  viewBox=\"0 0 24 24\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"6\"></line>\r\n    <line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"22\"></line>\r\n    <line x1=\"4.93\" y1=\"4.93\" x2=\"7.76\" y2=\"7.76\"></line>\r\n    <line x1=\"16.24\" y1=\"16.24\" x2=\"19.07\" y2=\"19.07\"></line>\r\n    <line x1=\"2\" y1=\"12\" x2=\"6\" y2=\"12\"></line>\r\n    <line x1=\"18\" y1=\"12\" x2=\"22\" y2=\"12\"></line>\r\n    <line x1=\"4.93\" y1=\"19.07\" x2=\"7.76\" y2=\"16.24\"></line>\r\n    <line x1=\"16.24\" y1=\"7.76\" x2=\"19.07\" y2=\"4.93\"></line>\r\n  </svg>`;\r\n\r\nconst eventsSVG = `\r\n  <svg class=\"activity\" xmlns=\"${svgUrl}\" \r\n  width=\"${iconSize / 1.6}\" \r\n  height=\"${iconSize / 1.6}\" \r\n  viewBox=\"0 0 250 250\"\r\n  style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\">\r\n    <path d=\"M46.59 0l156.82 0c25.65,0 46.59,20.94 46.59,46.59l0 156.82c0,25.65 -20.94,46.59 -46.59,46.59l-156.82 0c-25.65,0 -46.59,-20.94 -46.59,-46.59l0 -156.82c0,-25.65 20.94,-46.59 46.59,-46.59zm152.82 112.66c6.82,0 12.34,5.53 12.34,12.34 0,6.82 -5.52,12.34 -12.34,12.34l-20.92 0 -19.5 58.49c-2.13,6.44 -9.08,9.94 -15.52,7.81 -3.84,-1.27 -6.63,-4.25 -7.81,-7.81l-32.98 -98.95 -10.66 31.98c-1.71,5.16 -6.51,8.48 -11.67,8.48l-29.76 0c-6.82,0 -12.34,-5.52 -12.34,-12.34 0,-6.81 5.52,-12.34 12.34,-12.34l20.92 0 19.5 -58.49c1.18,-3.56 3.97,-6.54 7.81,-7.81 6.44,-2.13 13.39,1.37 15.52,7.81l32.98 98.95 10.3 -30.88c1.25,-5.48 6.16,-9.58 12.03,-9.58l29.76 0z\"/>\r\n  </svg>`;\r\n\r\n// Log messages icons\r\nconst infoSVG = `\r\n  <svg class=\"event-info\" xmlns=\"${svgUrl}\" \r\n  viewBox=\"0 0 24 24\" \r\n  width=\"14\"\r\n  height=\"14\"\r\n  fill=\"none\" \r\n  stroke=\"currentColor\" \r\n  stroke-width=\"2\" \r\n  stroke-linecap=\"round\" \r\n  stroke-linejoin=\"round\">\r\n    <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\r\n    <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line>\r\n    <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line>\r\n  </svg>`;\r\n\r\nconst warningSVG = `\r\n  <svg class=\"event-warning\" xmlns=\"${svgUrl}\" \r\n  viewBox=\"0 0 24 24\" \r\n  width=\"14\"\r\n  height=\"14\"\r\n  fill=\"none\" \r\n  stroke=\"currentColor\" \r\n  stroke-width=\"2\" \r\n  stroke-linecap=\"round\" \r\n  stroke-linejoin=\"round\">\r\n    <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path>\r\n    <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line>\r\n    <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\r\n  </svg>`;\r\n\r\nconst errorSVG = `\r\n  <svg class=\"event-error\" xmlns=\"${svgUrl}\" \r\n  viewBox=\"0 0 24 24\" \r\n  width=\"14\"\r\n  height=\"14\"\r\n  fill=\"none\" \r\n  stroke=\"currentColor\" \r\n  stroke-width=\"2\" \r\n  stroke-linecap=\"round\" \r\n  stroke-linejoin=\"round\">\r\n    <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\r\n    <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"></line>\r\n    <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"></line>\r\n  </svg>`;\r\n\r\nconst successSVG = `\r\n  <svg class=\"event-success\" xmlns=\"${svgUrl}\" \r\n  viewBox=\"0 0 24 24\" \r\n  width=\"14\"\r\n  height=\"14\"\r\n  fill=\"none\" \r\n  stroke=\"currentColor\" \r\n  stroke-width=\"2\" \r\n  stroke-linecap=\"round\" \r\n  stroke-linejoin=\"round\">\r\n    <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n  </svg>`;\r\n\r\nconst clearSVG = `\r\n  <svg class=\"event-clear\" xmlns=\"${svgUrl}\"\r\n  viewBox=\"0 0 24 24\"\r\n  width=\"${iconSize / 2}\"\r\n  height=\"${iconSize / 2}\"\r\n  fill=\"none\"\r\n  stroke=\"currentColor\"\r\n  stroke-width=\"2\"\r\n  stroke-linecap=\"round\"\r\n  stroke-linejoin=\"round\">\r\n    <polyline points=\"3 6 5 6 21 6\"></polyline>\r\n    <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\r\n  </svg>`;\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/icons.js?");

/***/ }),

/***/ "./src/data/themes/darkThemes.js":
/*!***************************************!*\
  !*** ./src/data/themes/darkThemes.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   darkThemes: () => (/* binding */ darkThemes),\n/* harmony export */   sharedColors: () => (/* binding */ sharedColors)\n/* harmony export */ });\n// Shared button colors for dark themes\r\nconst sharedColors = {\r\n  background: {\r\n    'photoshop-black': '#323232',\r\n    'photoshop-dark': '#454545',\r\n    'gruvbox-hard-dark': '#1d2021',\r\n    'gruvbox-medium-dark': '#282828',\r\n    'gruvbox-soft-dark': '#32302f',\r\n    'one-dark': '#282c34',\r\n    'one-dark-pro': '#282c34',\r\n    'dracula-dark': '#292a35',\r\n    'palenight-dark': '#292d3f',\r\n    'one-monokai-dark': '#282c34',\r\n    'one-monokai-darker': '#1e1e1e',\r\n    'polykai-dark': '#141818',\r\n    'material-dark': '#121212',\r\n    'turbo-dark': '#000000',\r\n    'github-dark': '#222830',\r\n    'solarized-dark': '#052b35',\r\n    'nord-polar-night': '#2e3440',\r\n    'nord-snow-storm': '#202325',\r\n    'monokai-pro-dark': '#181b1c',\r\n    'ayu-dark': '#0a0e14',\r\n    'ayu-mirage': '#1f2430',\r\n    'telegram-dark': '#17212b',\r\n    'dark-soul': '#1e1e1e',\r\n    'matrix-dark': '#191a19'\r\n  },\r\n  foreground: {\r\n    'photoshop-black': '#323232',\r\n    'photoshop-dark': '#454545',\r\n    'gruvbox-hard-dark': '#282828',\r\n    'gruvbox-medium-dark': '#3c3836',\r\n    'gruvbox-soft-dark': '#3c3836',\r\n    'one-dark': '#21252b',\r\n    'one-dark-pro': '#21252b',\r\n    'dracula-dark': '#454759',\r\n    'palenight-dark': '#31364b',\r\n    'one-monokai-dark': '#21252b',\r\n    'one-monokai-darker': '#222222',\r\n    'polykai-dark': '#1e2424',\r\n    'material-dark': '#1e1e1e',\r\n    'turbo-dark': '#1a1a1a',\r\n    'github-dark': '#161b23',\r\n    'solarized-dark': '#0e3641',\r\n    'nord-polar-night': '#3b4252',\r\n    'nord-snow-storm': '#292d2e',\r\n    'monokai-pro-dark': '#232829',\r\n    'ayu-dark': '#191c25',\r\n    'ayu-mirage': '#292f3d',\r\n    'telegram-dark': '#1f2936',\r\n    'dark-soul': '#2a2a2a',\r\n    'matrix-dark': '#13221b'\r\n  },\r\n  highlight: {\r\n    'photoshop-black': '#292929',\r\n    'photoshop-dark': '#383838',\r\n    'gruvbox-hard-dark': '#282828',\r\n    'gruvbox-medium-dark': '#3c3836',\r\n    'gruvbox-soft-dark': '#3c3836',\r\n    'one-dark': '#21252b',\r\n    'one-dark-pro': '#21252b',\r\n    'dracula-dark': '#44475a',\r\n    'palenight-dark': '#31364b',\r\n    'one-monokai-dark': '#21252b',\r\n    'one-monokai-darker': '#222222',\r\n    'polykai-dark': '#1e2424',\r\n    'material-dark': '#1e1e1e',\r\n    'turbo-dark': '#0f0f0f',\r\n    'github-dark': '#2c3644',\r\n    'solarized-dark': '#0e3641',\r\n    'nord-polar-night': '#3b4252',\r\n    'nord-snow-storm': '#292d2e',\r\n    'monokai-pro-dark': '#232829',\r\n    'ayu-dark': '#191c25',\r\n    'ayu-mirage': '#292f3d',\r\n    'telegram-dark': '#1f2936',\r\n    'dark-soul': '#2a2a2a',\r\n    'matrix-dark': '#1c221c'\r\n  },\r\n\r\n  // Accent colors\r\n  firstAccent: {\r\n    'photoshop-black': '#32c649',\r\n    'photoshop-dark': '#4be83e',\r\n    'gruvbox-hard-dark': '#b8bb26',\r\n    'gruvbox-medium-dark': '#b8bb26',\r\n    'gruvbox-soft-dark': '#b8bb26',\r\n    'one-dark': '#98c379',\r\n    'one-dark-pro': '#97c27e',\r\n    'dracula-dark': '#59f880',\r\n    'palenight-dark': '#c2e791',\r\n    'one-monokai-dark': '#a6e22e',\r\n    'one-monokai-darker': '#34c848',\r\n    'polykai-dark': '#a0ff20',\r\n    'material-dark': '#30d9c5',\r\n    'turbo-dark': '#1c9740',\r\n    'github-dark': '#56c882',\r\n    'solarized-dark': '#84981c',\r\n    'nord-polar-night': '#a3be8c',\r\n    'nord-snow-storm': '#a3be8c',\r\n    'monokai-pro-dark': '#a9db7b',\r\n    'ayu-dark': '#32C647',\r\n    'ayu-mirage': '#32C647',\r\n    'telegram-dark': '#85d610',\r\n    'dark-soul': '#82b32a',\r\n    'matrix-dark': '#659a4b'\r\n  },\r\n  secondAccent: {\r\n    'photoshop-black': '#ff5f52',\r\n    'photoshop-dark': '#ff5d73',\r\n    'gruvbox-hard-dark': '#fb4934',\r\n    'gruvbox-medium-dark': '#fb4934',\r\n    'gruvbox-soft-dark': '#fb4934',\r\n    'one-dark': '#e06c75',\r\n    'one-dark-pro': '#de6d79',\r\n    'dracula-dark': '#e65e60',\r\n    'palenight-dark': '#fa5d77',\r\n    'one-monokai-dark': '#f9397e',\r\n    'one-monokai-darker': '#fa655e',\r\n    'polykai-dark': '#ff0060',\r\n    'material-dark': '#d9306f',\r\n    'turbo-dark': '#db3d3d',\r\n    'github-dark': '#c85666',\r\n    'solarized-dark': '#d83938',\r\n    'nord-polar-night': '#cc8087',\r\n    'nord-snow-storm': '#cc8087',\r\n    'monokai-pro-dark': '#fb6287',\r\n    'ayu-dark': '#fa625d',\r\n    'ayu-mirage': '#fa625d',\r\n    'telegram-dark': '#f1417b',\r\n    'dark-soul': '#d8775a',\r\n    'matrix-dark': '#bc7676'\r\n  },\r\n  thirdAccent: {\r\n    'photoshop-black': '#72acf3',\r\n    'photoshop-dark': '#8abaf5',\r\n    'gruvbox-hard-dark': '#fabd2f',\r\n    'gruvbox-medium-dark': '#fabd2f',\r\n    'gruvbox-soft-dark': '#fabd2f',\r\n    'one-dark': '#c67bdb',\r\n    'one-dark-pro': '#c67bdb',\r\n    'dracula-dark': '#92e8fb',\r\n    'palenight-dark': '#c792ea',\r\n    'one-monokai-dark': '#66d9ef',\r\n    'one-monokai-darker': '#8cbeec',\r\n    'polykai-dark': '#40c4ff',\r\n    'material-dark': '#bd89f9',\r\n    'turbo-dark': '#b9a222',\r\n    'github-dark': '#d2d7e0',\r\n    'solarized-dark': '#3a8bcf',\r\n    'nord-polar-night': '#b6d8e2',\r\n    'nord-snow-storm': '#88c0d0',\r\n    'monokai-pro-dark': '#f89769',\r\n    'ayu-dark': '#ddae51',\r\n    'ayu-mirage': '#ffcc66',\r\n    'telegram-dark': '#4082bc',\r\n    'dark-soul': '#d07e36',\r\n    'matrix-dark': '#b5b344'\r\n  },\r\n  fourthAccent: {\r\n    'photoshop-black': '#2797ff',\r\n    'photoshop-dark': '#45a6ff',\r\n    'gruvbox-hard-dark': '#83a598',\r\n    'gruvbox-medium-dark': '#83a598',\r\n    'gruvbox-soft-dark': '#83a598',\r\n    'one-dark': '#98c379',\r\n    'one-dark-pro': '#6dafed',\r\n    'dracula-dark': '#92e8fb',\r\n    'palenight-dark': '#89ddff',\r\n    'one-monokai-dark': '#66d9ef',\r\n    'one-monokai-darker': '#8cbeec',\r\n    'polykai-dark': '#ff9020',\r\n    'material-dark': '#4b9ff1',\r\n    'turbo-dark': '#20a4cc',\r\n    'github-dark': '#4b8cd8',\r\n    'solarized-dark': '#2aa198',\r\n    'nord-polar-night': '#c4a47c',\r\n    'nord-snow-storm': '#c4a47c',\r\n    'monokai-pro-dark': '#7ddae5',\r\n    'ayu-dark': '#36c692',\r\n    'ayu-mirage': '#36c692',\r\n    'telegram-dark': '#5eb3f3',\r\n    'dark-soul': '#58c195',\r\n    'matrix-dark': '#48c89e'\r\n  }\r\n};\r\n\r\nconst darkThemes = {\r\n  // Background colors\r\n  '--background-color': sharedColors.background,\r\n  '--foreground-color': sharedColors.foreground,\r\n  '--highlight-color': sharedColors.highlight,\r\n\r\n  // Main text colors\r\n  '--main-text-color': {\r\n    'photoshop-black': '#cccccc',\r\n    'photoshop-dark': '#d4d4d4',\r\n    'gruvbox-hard-dark': '#ebdbb2',\r\n    'gruvbox-medium-dark': '#ebdbb2',\r\n    'gruvbox-soft-dark': '#ebdbb2',\r\n    'one-dark': '#abb2bf',\r\n    'one-dark-pro': '#abb2bf',\r\n    'dracula-dark': '#f8f8f2',\r\n    'palenight-dark': '#bdc6d5',\r\n    'one-monokai-dark': '#b2bbbb',\r\n    'one-monokai-darker': '#aaaaaa',\r\n    'polykai-dark': '#cecece',\r\n    'material-dark': '#c6c6c6',\r\n    'turbo-dark': '#959595',\r\n    'github-dark': '#d1d7e0',\r\n    'solarized-dark': '#849496',\r\n    'nord-polar-night': '#b5bcca',\r\n    'nord-snow-storm': '#adb4b8',\r\n    'monokai-pro-dark': '#9c988d',\r\n    'ayu-dark': '#a3afc2',\r\n    'ayu-mirage': '#b1b9cd',\r\n    'telegram-dark': '#c8c8c8',\r\n    'dark-soul': '#cdb398',\r\n    'matrix-dark': '#7bc66b'\r\n  },\r\n\r\n  // Drag area colors\r\n  '--drag-area-background-color': {\r\n    'photoshop-black': '#323232',\r\n    'photoshop-dark': '#454545',\r\n    'gruvbox-hard-dark': '#1d2021',\r\n    'gruvbox-medium-dark': '#282828',\r\n    'gruvbox-soft-dark': '#32302f',\r\n    'one-dark': '#21252b',\r\n    'one-dark-pro': '#21252b',\r\n    'dracula-dark': '#44475a',\r\n    'palenight-dark': '#31364b',\r\n    'one-monokai-dark': '#21252b',\r\n    'one-monokai-darker': '#1e1e1e',\r\n    'polykai-dark': '#1e2424',\r\n    'material-dark': '#000000',\r\n    'turbo-dark': '#000000',\r\n    'github-dark': '#161b23',\r\n    'solarized-dark': '#0e3641',\r\n    'nord-polar-night': '#3b4252',\r\n    'nord-snow-storm': '#292d2e',\r\n    'monokai-pro-dark': '#232829',\r\n    'ayu-dark': '#0a0e14',\r\n    'ayu-mirage': '#292f3d',\r\n    'telegram-dark': '#1f2936',\r\n    'dark-soul': '#171717',\r\n    'matrix-dark': '#191a19'\r\n  },\r\n\r\n  // Border colors\r\n  '--border-color': {\r\n    'photoshop-black': '#262626',\r\n    'photoshop-dark': '#383838',\r\n    'gruvbox-hard-dark': '#32302f',\r\n    'gruvbox-medium-dark': '#3c3836',\r\n    'gruvbox-soft-dark': '#504945',\r\n    'one-dark': '#181a1f',\r\n    'one-dark-pro': '#404349',\r\n    'dracula-dark': '#434456',\r\n    'palenight-dark': '#444267',\r\n    'one-monokai-dark': '#35383f',\r\n    'one-monokai-darker': '#2d2d2d',\r\n    'polykai-dark': '#242424',\r\n    'material-dark': '#222222',\r\n    'turbo-dark': '#0d0d0d',\r\n    'github-dark': '#3d444d',\r\n    'solarized-dark': '#0e3641',\r\n    'nord-polar-night': '#3b4252',\r\n    'nord-snow-storm': '#292d2e',\r\n    'monokai-pro-dark': '#262a2c',\r\n    'ayu-dark': '#202734',\r\n    'ayu-mirage': '#2e3547',\r\n    'telegram-dark': '#101921',\r\n    'dark-soul': '#333333',\r\n    'matrix-dark': '#122c16'\r\n  },\r\n\r\n  // Username filter (brightness) per dark theme\r\n  '--username-filter': {\r\n    'photoshop-black': 'brightness(1)',\r\n    'photoshop-dark': 'brightness(1.3)',\r\n    'gruvbox-hard-dark': 'brightness(1)',\r\n    'gruvbox-medium-dark': 'brightness(1)',\r\n    'gruvbox-soft-dark': 'brightness(1)',\r\n    'one-dark': 'brightness(1)',\r\n    'one-dark-pro': 'brightness(1)',\r\n    'dracula-dark': 'brightness(1)',\r\n    'palenight-dark': 'brightness(1)',\r\n    'one-monokai-dark': 'brightness(1)',\r\n    'one-monokai-darker': 'brightness(1)',\r\n    'polykai-dark': 'brightness(0.9)',\r\n    'material-dark': 'brightness(0.8)',\r\n    'turbo-dark': 'brightness(0.8)',\r\n    'github-dark': 'brightness(1)',\r\n    'solarized-dark': 'brightness(0.9)',\r\n    'nord-polar-night': 'brightness(1)',\r\n    'nord-snow-storm': 'brightness(1)',\r\n    'monokai-pro-dark': 'brightness(1)',\r\n    'ayu-dark': 'brightness(0.8)',\r\n    'ayu-mirage': 'brightness(1)',\r\n    'telegram-dark': 'brightness(1)',\r\n    'dark-soul': 'brightness(1)',\r\n    'matrix-dark': 'brightness(1)'\r\n  },\r\n\r\n   '--mention-color': {\r\n    'photoshop-black': '#b8d3f9',\r\n    'photoshop-dark': '#b8d3f9',\r\n    'gruvbox-hard-dark': '#fbc251',\r\n    'gruvbox-medium-dark': '#fbc251',\r\n    'gruvbox-soft-dark': '#fbc251',\r\n    'one-dark': '#c67bdb',\r\n    'one-dark-pro': '#dbadeb',\r\n    'dracula-dark': '#92e8fb',\r\n    'palenight-dark': '#d9bef4',\r\n    'one-monokai-dark': '#8ce1f2',\r\n    'one-monokai-darker': '#a8ccf0',\r\n    'polykai-dark': '#40c4ff',\r\n    'material-dark': '#c5a1f7',\r\n    'turbo-dark': '#b9a222',\r\n    'github-dark': '#79cfec',\r\n    'solarized-dark': '#85b3e0',\r\n    'nord-polar-night': '#b6d8e2',\r\n    'nord-snow-storm': '#a3c9dc',\r\n    'monokai-pro-dark': '#f89769',\r\n    'ayu-dark': '#ddae51',\r\n    'ayu-mirage': '#ffcc66',\r\n    'telegram-dark': '#9fbfdf',\r\n    'dark-soul': '#e6bf99',\r\n    'matrix-dark': '#cece7e'\r\n  },\r\n\r\n  // Accent colors\r\n  '--first-accent-color': sharedColors.firstAccent,\r\n  '--second-accent-color': sharedColors.secondAccent,\r\n  '--third-accent-color': sharedColors.thirdAccent,\r\n  '--fourth-accent-color': sharedColors.fourthAccent,\r\n\r\n  // Hotkey colors\r\n  '--hotkey-label-text-color': sharedColors.fourthAccent,\r\n  '--hotkey-label-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '1a'])\r\n  ),\r\n  '--hotkey-label-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '66'])\r\n  ),\r\n\r\n  // Private mode input colors\r\n  '--private-mode-color': sharedColors.secondAccent,\r\n  '--private-mode-placeholder-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + 'cc'])\r\n  ),\r\n  '--private-mode-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '40'])\r\n  ),\r\n\r\n  // Private message sent colors\r\n  '--private-message-sent-color': sharedColors.firstAccent,\r\n  '--private-message-sent-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.firstAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--private-message-sent-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.firstAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--private-message-sent-time-color': sharedColors.firstAccent,\r\n\r\n  // Private message received colors\r\n  '--private-message-received-color': sharedColors.secondAccent,\r\n  '--private-message-received-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--private-message-received-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--private-message-received-time-color': sharedColors.secondAccent,\r\n\r\n  // System message colors\r\n  '--system-message-color': sharedColors.thirdAccent,\r\n  '--system-message-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.thirdAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--system-message-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.thirdAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--system-message-time-color': sharedColors.thirdAccent,\r\n\r\n  // Ban message colors\r\n  '--ban-message-color': sharedColors.fourthAccent,\r\n  '--ban-message-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--ban-message-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--ban-message-time-color': sharedColors.fourthAccent\r\n};\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/themes/darkThemes.js?");

/***/ }),

/***/ "./src/data/themes/lightThemes.js":
/*!****************************************!*\
  !*** ./src/data/themes/lightThemes.js ***!
  \****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   lightThemes: () => (/* binding */ lightThemes),\n/* harmony export */   sharedColors: () => (/* binding */ sharedColors)\n/* harmony export */ });\n// Shared button colors for light themes\r\nconst sharedColors = {\r\n  background: {\r\n    'photoshop-light': '#f0f0f0',\r\n    'photoshop-gray': '#b8b8b8',\r\n    'gruvbox-hard-light': '#f9f5d7',\r\n    'gruvbox-medium-light': '#fbf1c7',\r\n    'gruvbox-soft-light': '#eddbb2',\r\n    'dracula-light': '#ffffff',\r\n    'material-light': '#fafafa',\r\n    'github-light': '#ffffff',\r\n    'solarized-light': '#fdf6e3',\r\n    'one-light': '#fafafa',\r\n    'nord-light': '#e5e9f0',\r\n    'monokai-pro-light': '#f8f8f2',\r\n    'ayu-light': '#fcfcfc',\r\n    'paper-light': '#eeeeee',\r\n    'dollar-light': '#e4e4d5',\r\n    'ysgrifennwr': '#f9f8f4'\r\n  },\r\n  foreground: {\r\n    'photoshop-light': '#f0f0f0',\r\n    'photoshop-gray': '#a3a3a3',\r\n    'gruvbox-hard-light': '#ebdbb2',\r\n    'gruvbox-medium-light': '#d5c4a1',\r\n    'gruvbox-soft-light': '#d5c4a1',\r\n    'dracula-light': '#e9e9f4',\r\n    'material-light': '#d9d9d9',\r\n    'github-light': '#f6f8fa',\r\n    'solarized-light': '#eee8d5',\r\n    'one-light': '#f0f0f0',\r\n    'nord-light': '#eceff4',\r\n    'monokai-pro-light': '#e8e5de',\r\n    'ayu-light': '#e6eaed',\r\n    'paper-light': '#cccccc',\r\n    'dollar-light': '#d0d1bd',\r\n    'ysgrifennwr': '#edece8'\r\n  },\r\n  highlight: {\r\n    'photoshop-light': '#dbdbdb',\r\n    'photoshop-gray': '#a3a3a3',\r\n    'gruvbox-hard-light': '#ebdbb2',\r\n    'gruvbox-medium-light': '#e0d2ac',\r\n    'gruvbox-soft-light': '#d5c4a1',\r\n    'dracula-light': '#e9e9f4',\r\n    'material-light': '#e6e6e6',\r\n    'github-light': '#ebf0f4',\r\n    'solarized-light': '#eee8d5',\r\n    'one-light': '#eaeaea',\r\n    'nord-light': '#d2d9e5',\r\n    'monokai-pro-light': '#e8e5de',\r\n    'ayu-light': '#e6eaed',\r\n    'paper-light': '#d9d9d9',\r\n    'dollar-light': '#d0d1bd',\r\n    'ysgrifennwr': '#edece8'\r\n  },\r\n\r\n  // Accent colors\r\n  firstAccent: {\r\n    'photoshop-light': '#30ac44',\r\n    'photoshop-gray': '#1b6427',\r\n    'gruvbox-hard-light': '#838216',\r\n    'gruvbox-medium-light': '#838216',\r\n    'gruvbox-soft-light': '#6d6c12',\r\n    'dracula-light': '#05ae30',\r\n    'material-light': '#43a047',\r\n    'github-light': '#2ea44f',\r\n    'solarized-light': '#859900',\r\n    'one-light': '#50a14f',\r\n    'nord-light': '#7da35c',\r\n    'monokai-pro-light': '#80b319',\r\n    'ayu-light': '#25c097',\r\n    'paper-light': '#12a036',\r\n    'dollar-light': '#12a036',\r\n    'ysgrifennwr': '#8f9550'\r\n  },\r\n  secondAccent: {\r\n    'photoshop-light': '#d23e32',\r\n    'photoshop-gray': '#922920',\r\n    'gruvbox-hard-light': '#cc241d',\r\n    'gruvbox-medium-light': '#cc241d',\r\n    'gruvbox-soft-light': '#b32019',\r\n    'dracula-light': '#f33f33',\r\n    'material-light': '#e53935',\r\n    'github-light': '#d73a49',\r\n    'solarized-light': '#dc322f',\r\n    'one-light': '#e45649',\r\n    'nord-light': '#bf616a',\r\n    'monokai-pro-light': '#f8075e',\r\n    'ayu-light': '#cf4b4d',\r\n    'paper-light': '#d2181a',\r\n    'dollar-light': '#d2181a',\r\n    'ysgrifennwr': '#e05281'\r\n  },\r\n  thirdAccent: {\r\n    'photoshop-light': '#1473e6',\r\n    'photoshop-gray': '#0c468d',\r\n    'gruvbox-hard-light': '#b57614',\r\n    'gruvbox-medium-light': '#b57614',\r\n    'gruvbox-soft-light': '#a16912',\r\n    'dracula-light': '#6272a4',\r\n    'material-light': '#3c96ef',\r\n    'github-light': '#0969da',\r\n    'solarized-light': '#268bd2',\r\n    'one-light': '#0184bc',\r\n    'nord-light': '#5e81ac',\r\n    'monokai-pro-light': '#139eb9',\r\n    'ayu-light': '#32a7e9',\r\n    'paper-light': '#1285a0',\r\n    'dollar-light': '#8a9a6b',\r\n    'ysgrifennwr': '#c38647'\r\n  },\r\n  fourthAccent: {\r\n    'photoshop-light': '#1a66e1',\r\n    'photoshop-gray': '#0075ff',\r\n    'gruvbox-hard-light': '#076678',\r\n    'gruvbox-medium-light': '#076678',\r\n    'gruvbox-soft-light': '#076678',\r\n    'dracula-light': '#8d602d',\r\n    'material-light': '#234f5d',\r\n    'github-light': '#2f4c77',\r\n    'solarized-light': '#2aa198',\r\n    'one-light': '#50a14f',\r\n    'nord-light': '#bf616a',\r\n    'monokai-pro-light': '#709d16',\r\n    'ayu-light': '#fa8834',\r\n    'paper-light': '#2e5d9a',\r\n    'dollar-light': '#5f6a48',\r\n    'ysgrifennwr': '#67c6d0'\r\n  }\r\n};\r\n\r\nconst lightThemes = {\r\n  // Background colors\r\n  '--background-color': sharedColors.background,\r\n  '--foreground-color': sharedColors.foreground,\r\n  '--highlight-color': sharedColors.highlight,\r\n\r\n  // Main text colors\r\n  '--main-text-color': {\r\n    'photoshop-light': '#6c6c6c',\r\n    'photoshop-gray': '#535353',\r\n    'gruvbox-hard-light': '#282828',\r\n    'gruvbox-medium-light': '#282828',\r\n    'gruvbox-soft-light': '#282828',\r\n    'dracula-light': '#665e92',\r\n    'material-light': '#212121',\r\n    'github-light': '#2c3136',\r\n    'solarized-light': '#657b83',\r\n    'one-light': '#383a42',\r\n    'nord-light': '#2e3440',\r\n    'monokai-pro-light': '#272822',\r\n    'ayu-light': '#5c6167',\r\n    'paper-light': '#444444',\r\n    'dollar-light': '#555a56',\r\n    'ysgrifennwr': '#424348'\r\n  },\r\n\r\n  // Drag area colors\r\n  '--drag-area-background-color': {\r\n    'photoshop-light': '#f0f0f0',\r\n    'photoshop-gray': '#b8b8b8',\r\n    'gruvbox-hard-light': '#f9f5d7',\r\n    'gruvbox-medium-light': '#fbf1c7',\r\n    'gruvbox-soft-light': '#eddbb2',\r\n    'dracula-light': '#e9e9f4',\r\n    'material-light': '#eeeeee',\r\n    'github-light': '#f6f8fa',\r\n    'solarized-light': '#eee8d5',\r\n    'one-light': '#eaeaea',\r\n    'nord-light': '#eceff4',\r\n    'monokai-pro-light': '#f5f4f1',\r\n    'ayu-light': '#f8f9fa',\r\n    'paper-light': '#eeeeee',\r\n    'dollar-light': '#e4e4d5',\r\n    'ysgrifennwr': '#edece8'\r\n  },\r\n\r\n  // Border colors\r\n  '--border-color': {\r\n    'photoshop-light': '#d1d1d1',\r\n    'photoshop-gray': '#9c9c9c',\r\n    'gruvbox-hard-light': '#ebdbb2',\r\n    'gruvbox-medium-light': '#ebdbb2',\r\n    'gruvbox-soft-light': '#d5c4a1',\r\n    'dracula-light': '#d6d6e7',\r\n    'material-light': '#e0e0e0',\r\n    'github-light': '#e1e4e8',\r\n    'solarized-light': '#eee8d5',\r\n    'one-light': '#e5e5e6',\r\n    'nord-light': '#d8dee9',\r\n    'monokai-pro-light': '#e0e0e0',\r\n    'ayu-light': '#eaecef',\r\n    'paper-light': '#d9d9d9',\r\n    'dollar-light': '#d0d1bd',\r\n    'ysgrifennwr': '#edece8'\r\n  },\r\n\r\n  // Username filter (brightness) per light theme\r\n  '--username-filter': {\r\n    'photoshop-light': 'brightness(0.7)',\r\n    'photoshop-gray': 'brightness(0.55)',\r\n    'gruvbox-hard-light': 'brightness(0.7)',\r\n    'gruvbox-medium-light': 'brightness(0.6)',\r\n    'gruvbox-soft-light': 'brightness(0.65)',\r\n    'dracula-light': 'brightness(0.8)',\r\n    'material-light': 'brightness(0.8)',\r\n    'github-light': 'brightness(0.8)',\r\n    'solarized-light': 'brightness(0.7)',\r\n    'one-light': 'brightness(0.8)',\r\n    'nord-light': 'brightness(0.7)',\r\n    'monokai-pro-light': 'brightness(0.8)',\r\n    'ayu-light': 'brightness(0.8)',\r\n    'paper-light': 'brightness(0.7)',\r\n    'dollar-light': 'brightness(0.6)',\r\n    'ysgrifennwr': 'brightness(0.8)'\r\n  },\r\n\r\n  '--mention-color': {\r\n    'photoshop-light': '#1473e6',\r\n    'photoshop-gray': '#0c468d',\r\n    'gruvbox-hard-light': '#b57614',\r\n    'gruvbox-medium-light': '#a16912',\r\n    'gruvbox-soft-light': '#734b0d',\r\n    'dracula-light': '#6272a4',\r\n    'material-light': '#1380ec',\r\n    'github-light': '#0969da',\r\n    'solarized-light': '#2466a8',\r\n    'one-light': '#0184bc',\r\n    'nord-light': '#3e5974',\r\n    'monokai-pro-light': '#0f758a',\r\n    'ayu-light': '#1481b8',\r\n    'paper-light': '#1285a0',\r\n    'dollar-light': '#5f6b47',\r\n    'ysgrifennwr': '#c38647'\r\n  },\r\n\r\n  // Accent colors\r\n  '--third-accent-color': sharedColors.thirdAccent,\r\n  '--first-accent-color': sharedColors.firstAccent,\r\n  '--second-accent-color': sharedColors.secondAccent,\r\n  '--fourth-accent-color': sharedColors.fourthAccent,\r\n\r\n  // Hotkey colors\r\n  '--hotkey-label-text-color': sharedColors.fourthAccent,\r\n  '--hotkey-label-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '1a'])\r\n  ),\r\n  '--hotkey-label-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '66'])\r\n  ),\r\n\r\n  // Private mode input colors\r\n  '--private-mode-color': sharedColors.secondAccent,\r\n  '--private-mode-placeholder-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + 'cc'])\r\n  ),\r\n  '--private-mode-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '40'])\r\n  ),\r\n\r\n  // Private message sent colors\r\n  '--private-message-sent-color': sharedColors.firstAccent,\r\n  '--private-message-sent-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.firstAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--private-message-sent-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.firstAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--private-message-sent-time-color': sharedColors.firstAccent,\r\n\r\n  // Private message received colors\r\n  '--private-message-received-color': sharedColors.secondAccent,\r\n  '--private-message-received-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--private-message-received-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.secondAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--private-message-received-time-color': sharedColors.secondAccent,\r\n\r\n  // System message colors\r\n  '--system-message-color': sharedColors.thirdAccent,\r\n  '--system-message-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.thirdAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--system-message-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.thirdAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--system-message-time-color': sharedColors.thirdAccent,\r\n\r\n  // Ban message colors\r\n  '--ban-message-color': sharedColors.fourthAccent,\r\n  '--ban-message-background-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '20'])\r\n  ),\r\n  '--ban-message-border-color': Object.fromEntries(\r\n    Object.entries(sharedColors.fourthAccent).map(([theme, color]) => [theme, color + '30'])\r\n  ),\r\n  '--ban-message-time-color': sharedColors.fourthAccent\r\n};\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/data/themes/lightThemes.js?");

/***/ }),

/***/ "./src/helpers/chatHeaderAlert.js":
/*!****************************************!*\
  !*** ./src/helpers/chatHeaderAlert.js ***!
  \****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   showChatAlert: () => (/* binding */ showChatAlert)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/eventsPanel.js */ \"./src/components/eventsPanel.js\");\n\r\n\r\n\r\nlet alertSet = new Set();\r\nlet isAlertShowing = false;\r\n\r\nfunction showChatAlert(message, options = {}) {\r\n  const type = options.type || 'info';\r\n  const key = `${message}|${type}`;\r\n  if (alertSet.has(key)) return; // Prevent duplicate\r\n  alertSet.add(key);\r\n  if (!isAlertShowing) {\r\n    processQueue();\r\n  }\r\n}\r\n\r\nfunction processQueue() {\r\n  if (isAlertShowing || alertSet.size === 0) return;\r\n  isAlertShowing = true;\r\n  // Get the first key from the set\r\n  const key = alertSet.values().next().value;\r\n  const [message, type = 'info'] = key.split('|');\r\n  showSingleAlert(message, { type }, key);\r\n}\r\n\r\nfunction showSingleAlert(message, options = {}, key) {\r\n  const dragArea = document.querySelector('.chat-drag-area');\r\n  if (!dragArea) {\r\n    alertSet.delete(key);\r\n    isAlertShowing = false;\r\n    processQueue();\r\n    return;\r\n  }\r\n\r\n  const existingAlert = dragArea.querySelector('.chat-dynamic-alert');\r\n  if (existingAlert && existingAlert.parentNode === dragArea) {\r\n    dragArea.removeChild(existingAlert);\r\n  }\r\n\r\n  const defaultOptions = { type: 'info', duration: _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.showAlertDuration };\r\n  const alertSettings = { ...defaultOptions, ...options };\r\n\r\n  const alertElement = document.createElement('div');\r\n  alertElement.className = 'chat-dynamic-alert';\r\n  alertElement.innerHTML = message;\r\n  alertElement.style.cssText = `\r\n    background-color: ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap[alertSettings.type] || _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.eventsColorMap.info};\r\n  `;\r\n\r\n  dragArea.appendChild(alertElement);\r\n\r\n  // Save the alert message to events storage\r\n  if (message) {\r\n    (0,_components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_1__.saveEvent)({ message, type: alertSettings.type });\r\n  }\r\n\r\n  function animateAlert() {\r\n    requestAnimationFrame(() => {\r\n      alertElement.style.transition = 'opacity 0.3s ease-in-out';\r\n      alertElement.style.opacity = '1';\r\n\r\n      setTimeout(() => {\r\n        alertElement.style.transition = 'transform 0.05s ease-in-out';\r\n        const shakeSequence = [\r\n          { x: 5, delay: 0 },\r\n          { x: -7, delay: 50 },\r\n          { x: 9, delay: 100 },\r\n          { x: -6, delay: 150 },\r\n          { x: 4, delay: 200 },\r\n          { x: -3, delay: 250 },\r\n          { x: 0, delay: 300 }\r\n        ];\r\n\r\n        shakeSequence.forEach((move) => {\r\n          setTimeout(() => {\r\n            alertElement.style.transform = `translate(calc(-50% + ${move.x}px), 0)`;\r\n          }, move.delay);\r\n        });\r\n      }, 300);\r\n\r\n      setTimeout(() => {\r\n        alertElement.style.transition = 'opacity 0.3s ease-in-out';\r\n        alertElement.style.opacity = '0';\r\n\r\n        setTimeout(() => {\r\n          if (alertElement && alertElement.parentNode === dragArea) {\r\n            dragArea.removeChild(alertElement);\r\n          }\r\n          alertSet.delete(key);\r\n          isAlertShowing = false;\r\n          processQueue();\r\n        }, 300);\r\n      }, alertSettings.duration);\r\n    });\r\n  }\r\n\r\n  animateAlert();\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/chatHeaderAlert.js?");

/***/ }),

/***/ "./src/helpers/chatUsernameColors.js":
/*!*******************************************!*\
  !*** ./src/helpers/chatUsernameColors.js ***!
  \*******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   optimizeColor: () => (/* binding */ optimizeColor),\n/* harmony export */   usernameColors: () => (/* binding */ usernameColors)\n/* harmony export */ });\nconst colorUtils = {\r\n  // Convert HSL (with h in [0,360] and s,l in percentage numbers) to hex\r\n  hslToHex(h, s, l) {\r\n    s /= 100;\r\n    l /= 100;\r\n    const c = (1 - Math.abs(2 * l - 1)) * s;\r\n    const x = c * (1 - Math.abs((h / 60) % 2 - 1));\r\n    const m = l - c / 2;\r\n    let r, g, b;\r\n    if (h < 60) {\r\n      r = c; g = x; b = 0;\r\n    } else if (h < 120) {\r\n      r = x; g = c; b = 0;\r\n    } else if (h < 180) {\r\n      r = 0; g = c; b = x;\r\n    } else if (h < 240) {\r\n      r = 0; g = x; b = c;\r\n    } else if (h < 300) {\r\n      r = x; g = 0; b = c;\r\n    } else {\r\n      r = c; g = 0; b = x;\r\n    }\r\n    r = Math.round((r + m) * 255);\r\n    g = Math.round((g + m) * 255);\r\n    b = Math.round((b + m) * 255);\r\n    return '#' + ((1 << 24) + (r << 16) + (g << 8) + b)\r\n      .toString(16).slice(1);\r\n  },\r\n\r\n  // Convert hex to HSL object {h, s, l}\r\n  hexToHSL(hex) {\r\n    hex = hex.replace(/^#/, '');\r\n    if (hex.length === 3) {\r\n      hex = hex.split('').map(c => c + c).join('');\r\n    }\r\n    const r = parseInt(hex.substring(0, 2), 16) / 255;\r\n    const g = parseInt(hex.substring(2, 4), 16) / 255;\r\n    const b = parseInt(hex.substring(4, 6), 16) / 255;\r\n    const max = Math.max(r, g, b);\r\n    const min = Math.min(r, g, b);\r\n    let h = 0;\r\n    let s = 0;\r\n    const l = (max + min) / 2;\r\n\r\n    if (max !== min) {\r\n      const d = max - min;\r\n      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\r\n\r\n      if (max === r) {\r\n        h = ((g - b) / d + (g < b ? 6 : 0)) * 60;\r\n      } else if (max === g) {\r\n        h = ((b - r) / d + 2) * 60;\r\n      } else {\r\n        h = ((r - g) / d + 4) * 60;\r\n      }\r\n    }\r\n\r\n    return { h: Math.round(h), s: s * 100, l: l * 100 };\r\n  },\r\n\r\n  // Extract just the hue from a hex color\r\n  hexToHue(hex) {\r\n    return this.hexToHSL(hex).h;\r\n  },\r\n\r\n  // Calculate relative luminance from hex for accessibility calculations\r\n  getLuminance(hex) {\r\n    hex = hex.replace(\"#\", \"\");\r\n    const r = parseInt(hex.slice(0, 2), 16) / 255;\r\n    const g = parseInt(hex.slice(2, 4), 16) / 255;\r\n    const b = parseInt(hex.slice(4, 6), 16) / 255;\r\n    const convert = c => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\r\n    return 0.2126 * convert(r) + 0.7152 * convert(g) + 0.0722 * convert(b);\r\n  },\r\n\r\n  // Calculate contrast ratio between two colors\r\n  contrastRatio(fg, bg) {\r\n    const L1 = this.getLuminance(fg);\r\n    const L2 = this.getLuminance(bg);\r\n    return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);\r\n  }\r\n};\r\n\r\n// Color generator factory function (not exported)\r\nfunction colorGenerator(config) {\r\n  // Use sessionStorage as required\r\n  const storageKey = config.storageKey || 'usernameColors';\r\n  let colorMap;\r\n  try {\r\n    const stored = sessionStorage.getItem(storageKey);\r\n    colorMap = stored ? JSON.parse(stored) : {};\r\n  } catch (e) {\r\n    colorMap = {};\r\n  }\r\n\r\n  // Allow the entire hue circle by default.\r\n  const hueRanges = config.hueRanges || [{ min: 0, max: 360 }];\r\n\r\n  // Calculate total available hue space\r\n  const totalHueSpace = hueRanges.reduce((sum, range) =>\r\n    sum + (range.max - range.min), 0);\r\n\r\n  const hasFixedSaturation = Boolean(config.saturation);\r\n  const hasFixedLightness = Boolean(config.lightness);\r\n  const minSat = config.minSaturation || 40;\r\n  const maxSat = config.maxSaturation || 90;\r\n  const minLight = config.minLightness || 55;\r\n  const maxLight = config.maxLightness || 80;\r\n  const satRange = maxSat - minSat;\r\n  const lightRange = maxLight - minLight;\r\n\r\n  // Cache existing color values and used hues for quick comparison\r\n  const existingColorValues = new Set(Object.values(colorMap));\r\n  const usedHues = new Set();\r\n\r\n  // Extract used hues from stored hex values by converting back to hue\r\n  Object.values(colorMap).forEach(colorStr => {\r\n    try {\r\n      usedHues.add(colorUtils.hexToHue(colorStr));\r\n    } catch (e) {\r\n      // Ignore parsing errors\r\n    }\r\n  });\r\n\r\n  // Helper to generate a random hue from the allowed ranges\r\n  function generateRandomHue() {\r\n    // Generate a random value within the total available hue space\r\n    let randomValue = Math.floor(Math.random() * totalHueSpace);\r\n\r\n    // Map this random value to the correct range\r\n    for (let range of hueRanges) {\r\n      const rangeSize = range.max - range.min;\r\n      if (randomValue < rangeSize) {\r\n        // Map the value to the range\r\n        return range.min + randomValue;\r\n      }\r\n      // Move to the next range\r\n      randomValue -= rangeSize;\r\n    }\r\n\r\n    // Fallback (should never happen if ranges are configured correctly)\r\n    return hueRanges[0].min;\r\n  }\r\n\r\n  return {\r\n    getColor(username) {\r\n      // If username is falsy, return a default color (converted to hex)\r\n      if (!username) {\r\n        const satVal = hasFixedSaturation ? parseInt(config.saturation, 10) : 50;\r\n        let lightVal = hasFixedLightness ? parseInt(config.lightness, 10) : 50;\r\n        // Ensure default follows the rule if hue is 0 (which is not in 210–280, so no check needed)\r\n        return colorUtils.hslToHex(0, satVal, lightVal);\r\n      }\r\n\r\n      // Get the username from localStorage if exist to prevent color generation\r\n      const key = username.trim();\r\n\r\n      // First, check localStorage\r\n      let localColors = {};\r\n      try {\r\n        const storedLocal = localStorage.getItem(storageKey);\r\n        localColors = storedLocal ? JSON.parse(storedLocal) : {};\r\n      } catch (e) {\r\n        // Ignore parsing errors\r\n      }\r\n      if (localColors[key]) {\r\n        return localColors[key];\r\n      }\r\n\r\n      // Next, check sessionStorage cache from colorMap\r\n      if (colorMap[key]) {\r\n        return colorMap[key];\r\n      }\r\n\r\n      let color = null;\r\n      let attempts = 0;\r\n\r\n      // Try to find a unique color (max 10 attempts)\r\n      while (!color && attempts < 10) {\r\n        // Generate a hue from the allowed ranges\r\n        let hue;\r\n        if (usedHues.size >= totalHueSpace) {\r\n          // If all possible hues are used, pick a random one from allowed ranges\r\n          hue = generateRandomHue();\r\n        } else {\r\n          // Try to find an unused hue within allowed ranges\r\n          do {\r\n            hue = generateRandomHue();\r\n          } while (usedHues.has(hue) && usedHues.size < totalHueSpace);\r\n        }\r\n\r\n        // Generate saturation as a number\r\n        const satVal = hasFixedSaturation ? parseInt(config.saturation, 10) :\r\n          Math.floor(Math.random() * satRange) + minSat;\r\n\r\n        // Generate lightness with a special rule:\r\n        // For hues between 210 and 280, the lightness must be at least 65.\r\n        let lightVal;\r\n        if (hasFixedLightness) {\r\n          lightVal = parseInt(config.lightness, 10);\r\n          if (hue >= 210 && hue < 280 && lightVal < 65) {\r\n            lightVal = 65;\r\n          }\r\n        } else {\r\n          let effectiveMinLight = minLight;\r\n          if (hue >= 210 && hue < 280) {\r\n            effectiveMinLight = Math.max(minLight, 65);\r\n          }\r\n          const effectiveLightRange = maxLight - effectiveMinLight;\r\n          lightVal = Math.floor(Math.random() * effectiveLightRange) + effectiveMinLight;\r\n        }\r\n\r\n        const newColor = colorUtils.hslToHex(hue, satVal, lightVal);\r\n\r\n        // Check if this color is unique\r\n        if (!existingColorValues.has(newColor)) {\r\n          color = newColor;\r\n          usedHues.add(hue);\r\n          break;\r\n        }\r\n        attempts++;\r\n      }\r\n\r\n      // Fallback if unique color not found in allotted attempts\r\n      if (!color) {\r\n        const hue = generateRandomHue();\r\n        const satVal = hasFixedSaturation ? parseInt(config.saturation, 10) :\r\n          Math.floor(Math.random() * satRange) + minSat;\r\n        let lightVal;\r\n        if (hasFixedLightness) {\r\n          lightVal = parseInt(config.lightness, 10);\r\n          if (hue >= 210 && hue < 280 && lightVal < 65) {\r\n            lightVal = 65;\r\n          }\r\n        } else {\r\n          let effectiveMinLight = minLight;\r\n          if (hue >= 210 && hue < 280) {\r\n            effectiveMinLight = Math.max(minLight, 65);\r\n          }\r\n          const effectiveLightRange = maxLight - effectiveMinLight;\r\n          lightVal = Math.floor(Math.random() * effectiveLightRange) + effectiveMinLight;\r\n        }\r\n        color = colorUtils.hslToHex(hue, satVal, lightVal);\r\n      }\r\n\r\n      // Save the new color\r\n      colorMap[key] = color;\r\n      existingColorValues.add(color);\r\n\r\n      // Batch update to sessionStorage with throttling\r\n      this.saveColors();\r\n\r\n      return color;\r\n    },\r\n\r\n    // Use a debounced save to reduce writes to sessionStorage\r\n    saveTimeout: null,\r\n    saveColors() {\r\n      if (this.saveTimeout) clearTimeout(this.saveTimeout);\r\n      this.saveTimeout = setTimeout(() => {\r\n        try {\r\n          sessionStorage.setItem(storageKey, JSON.stringify(colorMap));\r\n        } catch (e) {\r\n          // Handle potential storage errors silently\r\n        }\r\n      }, 500);\r\n    }\r\n  };\r\n}\r\n\r\n// Darken the color until it meets 4.5:1 contrast on white (exported)\r\nconst optimizeColor = hex => {\r\n  console.info(\"Optimizing color for contrast:\", hex);\r\n  let { h, s, l } = colorUtils.hexToHSL(hex);\r\n  let newHex = hex;\r\n  while (colorUtils.contrastRatio(newHex, \"#FFFFFF\") < 4.5 && l > 0) {\r\n    newHex = colorUtils.hslToHex(h, s, --l);\r\n  }\r\n  return newHex;\r\n};\r\n\r\n// Pre-configured color generators (exported)\r\nconst usernameColors = colorGenerator({\r\n  storageKey: 'usernameColors',\r\n  minSaturation: 35,\r\n  maxSaturation: 75,\r\n  minLightness: 65,\r\n  maxLightness: 80\r\n});\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/chatUsernameColors.js?");

/***/ }),

/***/ "./src/helpers/commands.js":
/*!*********************************!*\
  !*** ./src/helpers/commands.js ***!
  \*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   setupCommandEvents: () => (/* binding */ setupCommandEvents)\n/* harmony export */ });\n/* harmony import */ var _components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/chatUsernameColorsPanel.js */ \"./src/components/chatUsernameColorsPanel.js\");\n/* harmony import */ var _components_themesPanel_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/themesPanel.js */ \"./src/components/themesPanel.js\");\n/* harmony import */ var _components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/eventsPanel.js */ \"./src/components/eventsPanel.js\");\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _auth_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../auth.js */ \"./src/auth.js\");\n/* harmony import */ var _components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../components/helpPanel.js */ \"./src/components/helpPanel.js\");\n/* harmony import */ var _components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../components/ignoredUsersPanel.js */ \"./src/components/ignoredUsersPanel.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Define available commands with their handlers\r\nconst chatCommands = [\r\n  {\r\n    name: 'reset',\r\n    pattern: /^\\/reset\\s*$/,\r\n    handler: () => {\r\n      (0,_auth_js__WEBPACK_IMPORTED_MODULE_4__.removeChatParams)();\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.removeChatTraces)();\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.logMessage)({\r\n        en: 'Chat settings have been reset. Reloading...',\r\n        ru: 'Настройки чата сброшены. Перезагрузка...'\r\n      }, 'info');\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'colors',\r\n    pattern: /^\\/colors\\s*$/,\r\n    handler: () => {\r\n      (0,_components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_0__.openUsernameColors)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'export colors',\r\n    pattern: /^\\/export\\s+colors\\s*$/,\r\n    handler: () => {\r\n      (0,_components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_0__.exportUsernameColors)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'import colors',\r\n    pattern: /^\\/import\\s+colors\\s*$/,\r\n    handler: () => {\r\n      (0,_components_chatUsernameColorsPanel_js__WEBPACK_IMPORTED_MODULE_0__.importUsernameColors)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'themes',\r\n    pattern: /^\\/themes\\s*$/,\r\n    handler: () => {\r\n      (0,_components_themesPanel_js__WEBPACK_IMPORTED_MODULE_1__.openThemesPanel)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'help',\r\n    pattern: /^\\/help\\s*$/,\r\n    handler: () => {\r\n      if (!_components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__.HelpPanel.instance) {\r\n        const hp = new _components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__.HelpPanel({ onDestroy: () => { } });\r\n        hp.init();\r\n        hp.show();\r\n      } else {\r\n        _components_helpPanel_js__WEBPACK_IMPORTED_MODULE_5__.HelpPanel.instance.remove();\r\n      }\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'ignored',\r\n    pattern: /^\\/ignored\\s*$/,\r\n    handler: () => {\r\n      (0,_components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_6__.openIgnoredUsersPanel)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'events',\r\n    pattern: /^\\/events\\s*$/,\r\n    handler: () => {\r\n      (0,_components_eventsPanel_js__WEBPACK_IMPORTED_MODULE_2__.createEventsPanel)();\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'list normal',\r\n    pattern: /^\\/list\\s+normal\\s*$/,\r\n    handler: () => {\r\n      localStorage.setItem('userlistMode', 'normal');\r\n      updateUserListUI(); \r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.logMessage)({\r\n        en: 'User list mode set to normal',\r\n        ru: 'Список пользователей: обычный режим'\r\n      }, 'info');\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'list race',\r\n    pattern: /^\\/list\\s+race\\s*$/,\r\n    handler: () => {\r\n      localStorage.setItem('userlistMode', 'race');\r\n      updateUserListUI();\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.logMessage)({\r\n        en: 'User list mode set to race',\r\n        ru: 'Список пользователей: заезды сверху'\r\n      }, 'info');\r\n      return true;\r\n    }\r\n  },\r\n  {\r\n    name: 'list chat',\r\n    pattern: /^\\/list\\s+chat\\s*$/,\r\n    handler: () => {\r\n      localStorage.setItem('userlistMode', 'chat');\r\n      updateUserListUI();\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.logMessage)({\r\n        en: 'User list mode set to general chat',\r\n        ru: 'Список пользователей: общий чат сверху'\r\n      }, 'info');\r\n      return true;\r\n    }\r\n  }\r\n];\r\n\r\n// Setup event handlers for commands\r\nfunction setupCommandEvents(inputElement) {\r\n  if (!inputElement) return;\r\n\r\n  // Add input event handler for all commands\r\n  inputElement.addEventListener('input', () => {\r\n    handleCommands(inputElement);\r\n  });\r\n}\r\n\r\n// Handle any command entered in the input field\r\nfunction handleCommands(inputElement) {\r\n  if (!inputElement) return false;\r\n  const input = inputElement.value;\r\n\r\n  // Check each command to see if it matches\r\n  for (const command of chatCommands) {\r\n    if (command.pattern.test(input)) {\r\n      // Execute the command's handler\r\n      const result = command.handler();\r\n\r\n      // Clear the input field if command was successfully handled\r\n      if (result) {\r\n        inputElement.value = '';\r\n      }\r\n\r\n      return result;\r\n    }\r\n  }\r\n\r\n  return false; // Return false if no command matched\r\n}\r\n\r\nfunction updateUserListUI() {\r\n  const userManager = window.userManager;\r\n  if (userManager) {\r\n    userManager.updateUI();\r\n  } else {\r\n    console.warn('UserManager is not initialized');\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/commands.js?");

/***/ }),

/***/ "./src/helpers/helpers.js":
/*!********************************!*\
  !*** ./src/helpers/helpers.js ***!
  \********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   addViewportMeta: () => (/* binding */ addViewportMeta),\n/* harmony export */   adjustVisibility: () => (/* binding */ adjustVisibility),\n/* harmony export */   base64Encode: () => (/* binding */ base64Encode),\n/* harmony export */   calibrateToMoscowTime: () => (/* binding */ calibrateToMoscowTime),\n/* harmony export */   checkImageExists: () => (/* binding */ checkImageExists),\n/* harmony export */   checkIsMobile: () => (/* binding */ checkIsMobile),\n/* harmony export */   clamp: () => (/* binding */ clamp),\n/* harmony export */   compactXML: () => (/* binding */ compactXML),\n/* harmony export */   debounce: () => (/* binding */ debounce),\n/* harmony export */   decodeEncodedURL: () => (/* binding */ decodeEncodedURL),\n/* harmony export */   decodeURL: () => (/* binding */ decodeURL),\n/* harmony export */   extractUserId: () => (/* binding */ extractUserId),\n/* harmony export */   extractUsername: () => (/* binding */ extractUsername),\n/* harmony export */   fetchJSON: () => (/* binding */ fetchJSON),\n/* harmony export */   focusTextInput: () => (/* binding */ focusTextInput),\n/* harmony export */   getExactUserIdByName: () => (/* binding */ getExactUserIdByName),\n/* harmony export */   getRandomEmojiAvatar: () => (/* binding */ getRandomEmojiAvatar),\n/* harmony export */   isEncodedURL: () => (/* binding */ isEncodedURL),\n/* harmony export */   isTextSelected: () => (/* binding */ isTextSelected),\n/* harmony export */   isTrustedDomain: () => (/* binding */ isTrustedDomain),\n/* harmony export */   logMessage: () => (/* binding */ logMessage),\n/* harmony export */   observeMessagesPanel: () => (/* binding */ observeMessagesPanel),\n/* harmony export */   parseUsername: () => (/* binding */ parseUsername),\n/* harmony export */   removeChatTraces: () => (/* binding */ removeChatTraces),\n/* harmony export */   scrollToBottom: () => (/* binding */ scrollToBottom),\n/* harmony export */   sleep: () => (/* binding */ sleep)\n/* harmony export */ });\n/* harmony import */ var _converters_imageConverter_imageConverter_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../converters/imageConverter/imageConverter.js */ \"./src/converters/imageConverter/imageConverter.js\");\n/* harmony import */ var _converters_videoConverter_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../converters/videoConverter.js */ \"./src/converters/videoConverter.js\");\n/* harmony import */ var _layoutBehavior_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./layoutBehavior.js */ \"./src/helpers/layoutBehavior.js\");\n/* harmony import */ var _helpers_chatHeaderAlert_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers/chatHeaderAlert.js */ \"./src/helpers/chatHeaderAlert.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// ==================================================================================================\r\n\r\nlet lastEmojiAvatar = null;\r\nfunction getRandomEmojiAvatar() {\r\n  let newEmoji;\r\n  do {\r\n    newEmoji = _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.emojiFaces[Math.floor(Math.random() * _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.emojiFaces.length)];\r\n  } while (newEmoji === lastEmojiAvatar);\r\n  lastEmojiAvatar = newEmoji;\r\n  return newEmoji;\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction observeMessagesPanel() {\r\n  const messagesPanel = document.getElementById('messages-panel');\r\n  if (!messagesPanel) return;\r\n\r\n  const observer = new MutationObserver(() => {\r\n    (0,_layoutBehavior_js__WEBPACK_IMPORTED_MODULE_2__.handleLayoutBehavior)();\r\n    (0,_converters_videoConverter_js__WEBPACK_IMPORTED_MODULE_1__.convertVideoLinksToPlayer)();\r\n    (0,_converters_imageConverter_imageConverter_js__WEBPACK_IMPORTED_MODULE_0__.convertImageLinksToImage)();\r\n    scrollToBottom(350);\r\n  });\r\n\r\n  observer.observe(messagesPanel, { childList: true, subtree: true });\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction clamp(value, min, max) {\r\n  return Math.min(Math.max(value, min), max);\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction parseUsername(username) {\r\n  if (typeof username !== 'string') return username;\r\n  return username.replace(/^\\d+#/, '');\r\n}\r\n\r\n// Extract userId from JID, handling formats like \"123456#Username\"\r\nfunction extractUserId(jid) {\r\n  if (!jid) return null;\r\n  const parts = jid.split('/');\r\n  if (parts.length < 2) return null;\r\n\r\n  const secondPart = parts[1];\r\n  return secondPart.split('#')[0]; // Get everything before the # character\r\n}\r\n\r\n// Extract username from the full JID or login string\r\nfunction extractUsername(login) {\r\n  if (!login) return \"Unknown\";\r\n\r\n  // If login contains #, get everything after it\r\n  if (login.includes('#')) {\r\n    return login.split('#')[1];\r\n  }\r\n\r\n  // Replace the parseUsername call with direct implementation\r\n  return login.replace(/^\\d+#/, '');\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction adjustVisibility(element, action, opacity) {\r\n  if (!element) return;\r\n  void element.offsetHeight; // Force reflow\r\n  element.style.transition = 'opacity 0.3s ease';\r\n  element.style.opacity = action === 'show' ? opacity : '0';\r\n  if (action === 'hide') {\r\n    element.addEventListener('transitionend', () => {\r\n      if (element.style.opacity === '0' && element.parentNode) {\r\n        element.parentNode.removeChild(element);\r\n      }\r\n    }, { once: true });\r\n  }\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nconst isTrustedDomain = url => {\r\n  try {\r\n    const { hostname } = new URL(url);\r\n    const domain = hostname.toLowerCase().split('.').slice(-2).join('.');\r\n    return { isTrusted: _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.trustedDomains.includes(domain), domain };\r\n  } catch (err) {\r\n    logMessage({\r\n      en: `Error in isTrustedDomain: ${err.message}`,\r\n      ru: `Ошибка в isTrustedDomain: ${err.message}`\r\n    }, 'error');\r\n    return { isTrusted: false, domain: url };\r\n  }\r\n};\r\n\r\n// ==================================================================================================\r\n\r\nfunction isEncodedURL(url) {\r\n  const urlPattern = /^https?:\\/\\//;\r\n  const encodedPattern = /%[0-9A-Fa-f]{2}/;\r\n  return urlPattern.test(url) && encodedPattern.test(url);\r\n}\r\n\r\nfunction decodeURL(url) {\r\n  const [base] = url.split('#');\r\n  return decodeURIComponent(base).replace(/ /g, '_');\r\n}\r\n\r\nfunction decodeEncodedURL(text) {\r\n  return text.replace(/\\b(https?:\\/\\/[^\\s]+)/gi, match =>\r\n    isEncodedURL(match) ? decodeURL(match) : match\r\n  );\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction scrollToBottom(scrollThreshold) {\r\n  const container = document.getElementById('messages-panel');\r\n  if (!container) return;\r\n\r\n  const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;\r\n  if (distanceFromBottom <= scrollThreshold) {\r\n    container.scrollTop = container.scrollHeight;\r\n  }\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction focusTextInput() {\r\n  const chatContainer = document.getElementById('app-chat-container');\r\n  const element = document.getElementById('message-input');\r\n  if (element && chatContainer && chatContainer.style.display !== 'none') {\r\n    element.focus();\r\n    return true;\r\n  }\r\n  return false;\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n// Helper to fetch JSON and validate response\r\nasync function fetchJSON(url) {\r\n  const response = await fetch(url);\r\n  if (!response.ok) throw new Error(`Failed to fetch ${url}`);\r\n  return response.json();\r\n}\r\n\r\n// Helper function to get Exact user ID by username via the search API\r\nasync function getExactUserIdByName(userName) {\r\n  // Define the search API URL\r\n  const searchApiUrl = `https://klavogonki.ru/api/profile/search-users?query=${encodeURIComponent(userName)}`;\r\n\r\n  try {\r\n    // Get search results from the API\r\n    const searchResults = await fetchJSON(searchApiUrl);\r\n\r\n    // Ensure search results exist and contain data\r\n    if (!searchResults.all?.length) {\r\n      throw new Error(`User ${userName} not found.`);\r\n    }\r\n\r\n    // Return the ID of the user with the exact matching login\r\n    const user = searchResults.all.find(user => user.login === userName);\r\n    if (!user) {\r\n      throw new Error(`Exact match for user ${userName} not found.`);\r\n    }\r\n\r\n    return user.id;\r\n  } catch (error) {\r\n    console.error(`Error fetching user ID for ${userName}: ${error.message}`);\r\n    return null;\r\n  }\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction sleep(ms) {\r\n  return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction base64Encode(str) {\r\n  const encoder = new TextEncoder();\r\n  const data = encoder.encode(str);\r\n  return btoa(String.fromCharCode(...data));\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n// Helper function to check if an image exists\r\nfunction checkImageExists(url) {\r\n  return new Promise((resolve) => {\r\n    const img = new Image();\r\n    img.onload = () => resolve(true);\r\n    img.onerror = () => resolve(false);\r\n    img.src = url;\r\n  });\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction addViewportMeta() {\r\n  if (!document.querySelector('meta[name=\"viewport\"]')) {\r\n    const viewportMeta = document.createElement('meta');\r\n    viewportMeta.name = 'viewport';\r\n    viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';\r\n    document.head.appendChild(viewportMeta);\r\n    console.log('Viewport meta tag added dynamically');\r\n  }\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n/**\r\n * Converts a given local time to Moscow time (UTC+3) based on the system's timezone.\r\n *\r\n * How it works:\r\n * 1. Gets the system's local timezone offset in minutes (positive if behind UTC).\r\n * 2. Converts the local offset to total minutes from UTC.\r\n * 3. Defines Moscow's fixed offset as UTC+3 (180 minutes).\r\n * 4. Calculates the difference between Moscow's offset and the local offset.\r\n * 5. Parses the input time and converts it into total minutes since midnight.\r\n * 6. Adjusts the time by the calculated difference.\r\n * 7. Ensures the result stays within the 24-hour format (wrap-around handling).\r\n * 8. Converts the result back to HH:MM:SS format and returns it.\r\n *\r\n * @param {string} time - The local time in \"HH:MM:SS\" format.\r\n * @returns {string} - The converted time in Moscow time (HH:MM:SS).\r\n */\r\nfunction calibrateToMoscowTime(time) {\r\n  // Get local timezone offset in minutes (positive if local is behind UTC)\r\n  const localOffsetMinutes = new Date().getTimezoneOffset();\r\n\r\n  // Convert local offset to total minutes from UTC (local time = UTC + localTotalOffset)\r\n  const localTotalOffset = -localOffsetMinutes;\r\n\r\n  // Moscow is UTC+3 (180 minutes)\r\n  const moscowOffset = 3 * 60; // 180 minutes\r\n\r\n  // Calculate the adjustment needed: Moscow offset - local offset\r\n  const diffMinutes = moscowOffset - localTotalOffset;\r\n\r\n  // Parse input time\r\n  const [hours, minutes, seconds] = time.split(':').map(Number);\r\n\r\n  // Convert input time to total minutes since 00:00\r\n  const totalInputMinutes = hours * 60 + minutes;\r\n\r\n  // Adjust by diff and wrap within a single day (1440 minutes)\r\n  let adjustedMinutes = totalInputMinutes + diffMinutes;\r\n  adjustedMinutes = ((adjustedMinutes % 1440) + 1440) % 1440; // Ensure positive\r\n\r\n  // Convert back to hours and minutes\r\n  const adjustedHours = Math.floor(adjustedMinutes / 60);\r\n  const adjustedMins = adjustedMinutes % 60;\r\n\r\n  // Format the result with original seconds\r\n  return `${adjustedHours.toString().padStart(2, '0')}:` +\r\n    `${adjustedMins.toString().padStart(2, '0')}:` +\r\n    `${seconds.toString().padStart(2, '0')}`;\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n// Removes newlines and excess whitespace from XML strings to create a compact single-line format while preserving content.\r\nfunction compactXML(xmlString) {\r\n  // Remove all newlines and trim excess whitespace to single spaces\r\n  return xmlString\r\n    .replace(/\\n/g, '')      // Remove all newlines\r\n    .replace(/\\s+/g, ' ')    // Replace multiple spaces/tabs with a single space\r\n    .replace(/>\\s+</g, '><') // Remove spaces between tags\r\n    .trim();                 // Remove leading/trailing whitespace\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction checkIsMobile() {\r\n  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||\r\n    ('ontouchstart' in window);\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n// Debounce helper with cancel support\r\nfunction debounce(func, wait) {\r\n  let timeout = null;\r\n\r\n  function debounced(...args) {\r\n    clearTimeout(timeout);\r\n    timeout = setTimeout(() => func.apply(this, args), wait);\r\n  }\r\n\r\n  debounced.cancel = () => {\r\n    clearTimeout(timeout);\r\n    timeout = null;\r\n  };\r\n\r\n  return debounced;\r\n}\r\n\r\n// ===================================================================================================\r\n\r\nfunction removeChatTraces() {\r\n  localStorage.removeItem('userAvatarCache');\r\n  localStorage.removeItem('chatState');\r\n  localStorage.removeItem('chatEvents');\r\n}\r\n\r\n// ==================================================================================================\r\n\r\nfunction isTextSelected() {\r\n  return window.getSelection().toString().length > 0;\r\n}\r\n\r\n// ==================================================================================================\r\n\r\n// Function to log messages with different types and show alerts\r\n// Accepts: message (string or {en,ru}), type, showAlert, lang\r\nfunction logMessage(message, type = 'info', showAlert = true, lang = null) {\r\n  const styles = {\r\n    info: `color: ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.eventsColorMap.info}`,\r\n    warning: `color: ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.eventsColorMap.warning}`,\r\n    error: `color: ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.eventsColorMap.error}`,\r\n    success: `color: ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.eventsColorMap.success}`\r\n  };\r\n  const style = styles[type] || styles.info;\r\n\r\n  // Language detection: use param, else imported default, else 'en'\r\n  lang = lang || _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.defaultLanguage || 'en';\r\n\r\n  // If message is an object with en/ru, pick the right one for alert, always use en/raw for console\r\n  let alertMsg = message;\r\n  if (typeof message === 'object' && message !== null && (message.en || message.ru)) {\r\n    alertMsg = message[lang] || message.en || message.ru;\r\n    message = message.en || message.ru || '';\r\n  }\r\n\r\n  // Console logging with appropriate method and color (always EN/RAW)\r\n  switch (type) {\r\n    case 'error':\r\n      console.error(`%c${message}`, style);\r\n      break;\r\n    case 'warning':\r\n      console.warn(`%c${message}`, style);\r\n      break;\r\n    case 'success':\r\n      console.log(`%c${message}`, style);\r\n      break;\r\n    case 'info':\r\n    default:\r\n      console.info(`%c${message}`, style);\r\n      break;\r\n  }\r\n\r\n  if (showAlert) {\r\n    (0,_helpers_chatHeaderAlert_js__WEBPACK_IMPORTED_MODULE_3__.showChatAlert)(alertMsg, { type, duration: _data_definitions_js__WEBPACK_IMPORTED_MODULE_4__.settings.showAlertDuration });\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/helpers.js?");

/***/ }),

/***/ "./src/helpers/iframeProfileLoader.js":
/*!********************************************!*\
  !*** ./src/helpers/iframeProfileLoader.js ***!
  \********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   loadProfileIntoIframe: () => (/* binding */ loadProfileIntoIframe)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n// Define a variable to track the last focused textarea in the iframe\r\nlet lastFocusedIframeTextarea = null;\r\n\r\n// Creates and manages an iframe modal for profile content\r\nconst loadProfileIntoIframe = (url) => {\r\n  let profileIframe = document.querySelector('.profile-iframe-container');\r\n\r\n  if (!profileIframe) {\r\n    profileIframe = document.createElement('iframe');\r\n    profileIframe.classList.add('profile-iframe-container');\r\n    document.body.appendChild(profileIframe);\r\n  }\r\n\r\n  profileIframe.src = url;\r\n  (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(profileIframe, 'show', 1);\r\n\r\n  const removeIframe = () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.adjustVisibility)(profileIframe, 'hide', 0);\r\n    document.removeEventListener('keydown', handleEvents);\r\n    document.removeEventListener('mousedown', handleEvents);\r\n  };\r\n\r\n  // Update the handleEvents function to include only the 'username' class\r\n  const handleEvents = (event) => {\r\n    if (event.type === 'keydown' && event.code === 'Space') {\r\n      if (lastFocusedIframeTextarea) {\r\n        event.stopPropagation();\r\n        return;\r\n      }\r\n      event.preventDefault();\r\n      removeIframe();\r\n    }\r\n\r\n    if (event.type === 'mousedown') {\r\n      const isClickOnUsername = event.target.classList.contains('username');\r\n      if (!profileIframe.contains(event.target) && !isClickOnUsername) {\r\n        removeIframe();\r\n      }\r\n    }\r\n  };\r\n\r\n  document.addEventListener('keydown', handleEvents);\r\n  document.addEventListener('mousedown', handleEvents);\r\n\r\n  profileIframe.onload = () => {\r\n    try {\r\n      const iframeWindow = profileIframe.contentWindow;\r\n      const iframeDoc = iframeWindow.document;\r\n\r\n      iframeDoc.addEventListener('focusin', (e) => {\r\n        if (e.target.tagName === 'TEXTAREA') {\r\n          lastFocusedIframeTextarea = e.target;\r\n        }\r\n      });\r\n\r\n      iframeDoc.addEventListener('focusout', () => {\r\n        setTimeout(() => {\r\n          if (!iframeDoc.activeElement || iframeDoc.activeElement.tagName !== 'TEXTAREA') {\r\n            lastFocusedIframeTextarea = null;\r\n          }\r\n        }, 0);\r\n      });\r\n\r\n      iframeWindow.addEventListener('keydown', handleEvents);\r\n      iframeWindow.addEventListener('dblclick', removeIframe);\r\n\r\n      new MutationObserver((mutations, observer) => {\r\n        if (mutations.some(m => [...m.removedNodes].some(n =>\r\n          n.nodeType === 1 && (n.classList.contains('dimming-background') || n.classList.contains('cached-users-panel'))\r\n        ))) {\r\n          removeIframe();\r\n          observer.disconnect();\r\n        }\r\n      }).observe(document.body, { childList: true, subtree: true });\r\n\r\n    } catch (error) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: \"Unable to access iframe contents. This may be due to cross-origin restrictions.\",\r\n        ru: \"Невозможно получить доступ к содержимому iframe. Возможно, это связано с ограничениями кросс-домена.\"\r\n      }, 'error');\r\n    }\r\n  };\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/iframeProfileLoader.js?");

/***/ }),

/***/ "./src/helpers/layoutBehavior.js":
/*!***************************************!*\
  !*** ./src/helpers/layoutBehavior.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   handleLayoutBehavior: () => (/* binding */ handleLayoutBehavior)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n\r\nfunction handleLayoutBehavior() {\r\n  const chatContainer = document.querySelector('#app-chat-container');\r\n  const wrapper = chatContainer.querySelector('.chat-wrapper');\r\n  const isNarrow = wrapper.offsetWidth <= 780;\r\n  const isVeryNarrow = wrapper.offsetWidth <= 380;\r\n  const userList = chatContainer.querySelector('.user-list-container');\r\n  const isMobile = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.checkIsMobile)();\r\n\r\n  // Handle user list visibility and styling\r\n  if (userList) {\r\n    const systemMessages = chatContainer.querySelectorAll('.message.system');\r\n    const isCollapsed = isNarrow || isMobile;\r\n\r\n    if (isCollapsed) {\r\n      // Set mobile/narrow styles\r\n      Object.assign(userList.style, {\r\n        position: 'absolute',\r\n        height: '100%',\r\n        top: '0',\r\n        right: '0',\r\n        transition: `transform ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.revealUserListDelay}ms ease-in-out, opacity ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.revealUserListDelay}ms ease-in-out`,\r\n        zIndex: '1001'\r\n      });\r\n\r\n      // Add floating-userlist class when collapsed\r\n      userList.classList.add('floating-userlist');\r\n\r\n      systemMessages.forEach(msg => msg.style.setProperty('align-items', 'start', 'important'));\r\n\r\n      // Create or update toggle button\r\n      let revealButton = chatContainer.querySelector('.reveal-userlist-btn');\r\n      const isOpen = userList.classList.contains('shown-userlist');\r\n\r\n      if (!revealButton) {\r\n        revealButton = document.createElement('button');\r\n        revealButton.className = 'reveal-userlist-btn';\r\n        revealButton.textContent = '📋';\r\n        chatContainer.appendChild(revealButton);\r\n\r\n        // Handle outside clicks\r\n        const outsideClick = evt => {\r\n          if (!userList.contains(evt.target) && evt.target !== revealButton) {\r\n            toggleUserList(userList, false);\r\n            setTimeout(() => document.removeEventListener('click', outsideClick, true), _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.revealUserListDelay);\r\n          }\r\n        };\r\n\r\n        // Toggle on button click\r\n        revealButton.addEventListener('click', ev => {\r\n          ev.stopPropagation();\r\n          const isVisible = userList.classList.contains('shown-userlist');\r\n          const nowOpen = toggleUserList(userList, !isVisible);\r\n          nowOpen ? document.addEventListener('click', outsideClick, true)\r\n            : document.removeEventListener('click', outsideClick, true);\r\n        });\r\n      }\r\n\r\n      // Set initial state if not already configured\r\n      if (!isOpen) {\r\n        userList.style.transform = 'translateX(100%)';\r\n        userList.style.opacity = '0';\r\n        userList.style.display = 'none';\r\n      }\r\n    } else {\r\n      // Reset to desktop styles\r\n      Object.assign(userList.style, {\r\n        position: '', height: '', top: '', right: '', transform: '',\r\n        opacity: '', display: '', transition: '', zIndex: ''\r\n      });\r\n      userList.classList.remove('shown-userlist');\r\n\r\n      // Remove floating-userlist class when not collapsed\r\n      userList.classList.remove('floating-userlist');\r\n\r\n      systemMessages.forEach(msg => msg.style.removeProperty('align-items'));\r\n\r\n      const existingButton = chatContainer.querySelector('.reveal-userlist-btn');\r\n      existingButton?.remove();\r\n    }\r\n  }\r\n\r\n  // Adjust message layout\r\n  chatContainer.querySelectorAll('.message').forEach(msg => {\r\n    const txt = msg.querySelector('.message-text');\r\n    if (txt) {\r\n      msg.style.flexDirection = isNarrow ? 'column' : 'row';\r\n      msg.style.marginBottom = isNarrow ? '0.8em' : '0';\r\n      txt.style.marginTop = isNarrow ? '0.2em' : '0';\r\n    }\r\n  });\r\n\r\n  // Scale media for small screens or narrow chat\r\n  chatContainer.querySelectorAll('.video-container, .youtube-thumb')\r\n    .forEach(el => el.style.maxWidth = isVeryNarrow ? '100%' : '');\r\n}\r\n\r\n// Helper to toggle user list visibility\r\nfunction toggleUserList(list, makeVisible) {\r\n  // Only proceed if state is changing\r\n  if (list.classList.contains('shown-userlist') !== makeVisible) {\r\n    list.classList.toggle('shown-userlist', makeVisible);\r\n\r\n    if (makeVisible) {\r\n      list.style.display = 'flex';\r\n      void list.offsetWidth; // Force reflow\r\n      list.style.transform = 'translateX(0)';\r\n      list.style.opacity = '1';\r\n    } else {\r\n      list.style.transform = 'translateX(100%)';\r\n      list.style.opacity = '0';\r\n      setTimeout(() => {\r\n        if (!list.classList.contains('shown-userlist')) {\r\n          list.style.display = 'none';\r\n        }\r\n      }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.revealUserListDelay);\r\n    }\r\n  }\r\n  return makeVisible;\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/layoutBehavior.js?");

/***/ }),

/***/ "./src/helpers/lengthPopup.js":
/*!************************************!*\
  !*** ./src/helpers/lengthPopup.js ***!
  \************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   createLengthPopup: () => (/* binding */ createLengthPopup),\n/* harmony export */   initChatLengthPopupEvents: () => (/* binding */ initChatLengthPopupEvents)\n/* harmony export */ });\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n// Instead of getting the elements immediately, we declare module-level variables.\r\nlet chatField = null;\r\nlet messagesContainer = null;\r\nlet lengthPopup = null;\r\n\r\n/**\r\n * Create and append the length popup.\r\n * @param {HTMLElement} container - The container (messagesPanel) to which the popup should be appended.\r\n */\r\nfunction createLengthPopup(container) {\r\n  messagesContainer = container;\r\n  lengthPopup = document.createElement('div');\r\n  lengthPopup.className = 'length-field-popup';\r\n  messagesContainer.appendChild(lengthPopup);\r\n}\r\n\r\n// Create a canvas for text measurement.\r\nconst textMeasurementCanvas = document.createElement('canvas');\r\nconst textMeasurementContext = textMeasurementCanvas.getContext('2d');\r\n\r\nlet isPopupVisible = false;\r\nlet previousLength = 0;\r\nlet hidePopupTimeout;\r\n\r\nfunction updateLengthPopupColor(length) {\r\n  if (!lengthPopup) {\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Length popup: Popup element is not defined.\",\r\n      ru: \"Длинномер сообщения: Элемент всплывающего окна не определён.\"\r\n    }, 'error');\r\n    return;\r\n  }\r\n\r\n  let h, s = 100, l = 50;\r\n\r\n  if (length === 0) {\r\n    h = 200; s = 20; l = 50;\r\n  } else if (length <= 90) {\r\n    h = 120;\r\n  } else if (length <= 100) {\r\n    h = 120 - ((length - 90) / 10) * 60;\r\n  } else if (length <= 190) {\r\n    h = 60;\r\n  } else if (length <= 200) {\r\n    h = 60 - ((length - 190) / 10) * 20;\r\n  } else if (length <= 250) {\r\n    h = 40;\r\n  } else if (length <= 300) {\r\n    h = 40 - ((length - 250) / 50) * 40;\r\n  } else {\r\n    h = 0;\r\n  }\r\n\r\n  const textColor = `hsl(${h}, ${s}%, ${l}%)`;\r\n  const backgroundColor = `hsl(${h}, ${s}%, ${Math.max(l - (length > 250 ? 35 : 30), 8)}%)`;\r\n  const borderColor = `hsla(${h}, ${s}%, ${l}%, 0.1)`;\r\n\r\n  lengthPopup.style.setProperty('color', textColor, 'important');\r\n  lengthPopup.style.setProperty('background-color', backgroundColor, 'important');\r\n  lengthPopup.style.setProperty('border', `1px solid ${borderColor}`, 'important');\r\n  lengthPopup.style.setProperty('border-radius', '0.4em', 'important');\r\n}\r\n\r\nfunction updatePopupMetrics(text) {\r\n  if (!chatField) {\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Length popup: Chat field is not defined for updating metrics.\",\r\n      ru: \"Длинномер сообщения: Поле чата не определено для обновления метрик.\"\r\n    }, 'error');\r\n    return;\r\n  }\r\n  // Get current font from input field.\r\n  const computedStyle = getComputedStyle(chatField);\r\n  textMeasurementContext.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;\r\n  // Measure text.\r\n  const textWidth = textMeasurementContext.measureText(text).width;\r\n  // Calculate position.\r\n  const newLeft = chatField.offsetLeft + textWidth + 5;\r\n  const maxLeft = chatField.offsetLeft + chatField.offsetWidth - lengthPopup.offsetWidth;\r\n  lengthPopup.style.left = `${Math.min(newLeft, maxLeft)}px`;\r\n}\r\n\r\nconst arrowRightBold = \"➡\"; // Heavy right arrow\r\nconst arrowLeftBold = \"⬅\"; // Heavy left arrow\r\n\r\nfunction updateLengthPopup(length) {\r\n  let displayText =\r\n    length > previousLength ? `${length} ${arrowRightBold}` :\r\n      length < previousLength ? `${arrowLeftBold} ${length}` :\r\n        `${length}`;\r\n\r\n  lengthPopup.textContent = displayText;\r\n  updateLengthPopupColor(length);\r\n  previousLength = length;\r\n}\r\n\r\nfunction togglePopup(show) {\r\n  if (isPopupVisible === show) return;\r\n  lengthPopup.classList.toggle('bounce-in', show);\r\n  lengthPopup.classList.toggle('bounce-out', !show);\r\n  isPopupVisible = show;\r\n  if (!show) setTimeout(() => lengthPopup.classList.remove('bounce-out'), 500);\r\n}\r\n\r\nfunction resetPopup() {\r\n  updateLengthPopup(0);\r\n  Object.assign(lengthPopup.style, { left: '0px', color: 'hsl(200, 20%, 50%)' });\r\n}\r\n\r\nfunction handleInputEvent() {\r\n  clearTimeout(hidePopupTimeout);\r\n  updateLengthPopup(chatField.value.length);\r\n  updatePopupMetrics(chatField.value);\r\n  togglePopup(true);\r\n  hidePopupTimeout = setTimeout(() => togglePopup(false), 1000);\r\n}\r\n\r\nfunction handleKeydownEvent(e) {\r\n  if (e.key !== 'Enter') return;\r\n  resetPopup();\r\n  togglePopup(true);\r\n  hidePopupTimeout = setTimeout(() => togglePopup(false), 1000);\r\n}\r\n\r\n/**\r\n * Initializes chat length popup events.\r\n * @param {HTMLElement} field - The chat input field.\r\n */\r\nfunction initChatLengthPopupEvents(field) {\r\n  chatField = field;\r\n  if (!chatField) {\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Length popup: Chat field is null during initialization.\",\r\n      ru: \"Длинномер сообщения: Поле чата равно null при инициализации.\"\r\n    }, 'error');\r\n    return;\r\n  }\r\n  if (!lengthPopup) {\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Length popup: Popup element is not created, skipping event listeners.\",\r\n      ru: \"Длинномер сообщения: Всплывающее окно не создано, обработчики событий не добавлены.\"\r\n    }, 'warning');\r\n    return;\r\n  }\r\n  // Only attach event listeners if the popup was created.\r\n  chatField.addEventListener('input', handleInputEvent);\r\n  chatField.addEventListener('keydown', handleKeydownEvent);\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/lengthPopup.js?");

/***/ }),

/***/ "./src/helpers/mentionWatcher.js":
/*!***************************************!*\
  !*** ./src/helpers/mentionWatcher.js ***!
  \***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   banned: () => (/* binding */ banned),\n/* harmony export */   highlightMentionWords: () => (/* binding */ highlightMentionWords),\n/* harmony export */   notification: () => (/* binding */ notification),\n/* harmony export */   playAudio: () => (/* binding */ playAudio)\n/* harmony export */ });\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\nconst notification = 'https://github.com/VimiummuimiV/KG_Chat_Application/raw/refs/heads/main/src/sounds/notification-pluck-on.mp3';\r\nconst banned = 'https://github.com/VimiummuimiV/KG_Chat_Application/raw/refs/heads/main/src/sounds/mario-game-over.mp3';\r\n\r\nfunction playAudio(url) {\r\n  const audio = new Audio(url);\r\n  audio.volume = 1;\r\n  audio.play();\r\n}\r\n\r\nfunction highlightMentionWords() {\r\n  const container = document.getElementById('messages-panel');\r\n  if (!container) return;\r\n\r\n  // Get username from auth data\r\n  const authData = localStorage.getItem('klavoauth');\r\n  let username = '';\r\n  try {\r\n    if (authData) {\r\n      const parsedAuth = JSON.parse(authData);\r\n      if (parsedAuth && parsedAuth.username) {\r\n        username = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.extractUsername)(parsedAuth.username);\r\n      }\r\n    }\r\n  } catch (e) {\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Mention watcher: Error parsing auth data: ${e.message}`,\r\n      ru: `Ошибка парсинга данных авторизации в отслеживателе упоминаний: ${e.message}`\r\n    }, 'error');\r\n  }\r\n\r\n  // Don't proceed if no username to check\r\n  if (!username) return;\r\n\r\n  const highlightTerms = [username];\r\n  const globalProcessed = new WeakSet();\r\n\r\n  const messages = container.querySelectorAll(\r\n    '.message:not(.system):not(.private) ' +\r\n    '.message-text:not(.processed-for-mention)'\r\n  );\r\n  messages.forEach((message) => {\r\n    const walker = document.createTreeWalker(\r\n      message,\r\n      NodeFilter.SHOW_TEXT,\r\n      {\r\n        acceptNode: (node) => {\r\n          if (globalProcessed.has(node)) return NodeFilter.FILTER_SKIP;\r\n          const parent = node.parentElement;\r\n          if (parent.closest('.mention, .time, .username')) {\r\n            return NodeFilter.FILTER_SKIP;\r\n          }\r\n          return NodeFilter.FILTER_ACCEPT;\r\n        }\r\n      }\r\n    );\r\n\r\n    const nodes = [];\r\n    let currentNode;\r\n    while ((currentNode = walker.nextNode())) nodes.push(currentNode);\r\n\r\n    if (nodes.length > 0) {\r\n      nodes.forEach((node) => {\r\n        if (!globalProcessed.has(node)) {\r\n          processNode(node, highlightTerms);\r\n          globalProcessed.add(node);\r\n        }\r\n      });\r\n\r\n      message.classList.add('processed-for-mention');\r\n    }\r\n  });\r\n\r\n  function processNode(node, keywords) {\r\n    const regex = /(@?[\\wа-яА-ЯёЁ'-]+)|[\\s]+|[^@\\s\\wа-яА-ЯёЁ'-]+/gu;\r\n    const tokens = node.textContent.match(regex) || [];\r\n    const fragment = document.createDocumentFragment();\r\n\r\n    tokens.forEach(token => {\r\n      const isMatch = keywords.some(keyword =>\r\n        keyword.localeCompare(token, undefined, { sensitivity: 'accent' }) === 0\r\n      );\r\n\r\n      if (isMatch) {\r\n        const mentionSpan = document.createElement('span');\r\n        mentionSpan.className = 'mention';\r\n        mentionSpan.textContent = token;\r\n        fragment.appendChild(mentionSpan);\r\n      } else {\r\n        fragment.appendChild(document.createTextNode(token));\r\n      }\r\n    });\r\n\r\n    node.parentNode.replaceChild(fragment, node);\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/mentionWatcher.js?");

/***/ }),

/***/ "./src/helpers/messagesSeparator.js":
/*!******************************************!*\
  !*** ./src/helpers/messagesSeparator.js ***!
  \******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   createNewMessagesSeparator: () => (/* binding */ createNewMessagesSeparator),\n/* harmony export */   removeNewMessagesSeparator: () => (/* binding */ removeNewMessagesSeparator)\n/* harmony export */ });\n/* harmony import */ var _tooltip_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n/**\r\n * Creates an HR-like separator with an emoji icon.\r\n * @returns {HTMLElement} The separator element.\r\n */\r\nfunction createNewMessagesSeparator() {\r\n  const separator = document.createElement('div');\r\n  separator.className = 'new-messages-separator';\r\n\r\n  const hr = document.createElement('hr');\r\n  hr.className = 'separator-line';\r\n\r\n  // Use an emoji icon (feel free to change it)\r\n  const iconContainer = document.createElement('div');\r\n  iconContainer.className = 'separator-icon';\r\n  iconContainer.textContent = '🔥';\r\n  (0,_tooltip_js__WEBPACK_IMPORTED_MODULE_0__.createCustomTooltip)(iconContainer, {\r\n    en: 'New messages [Click] to remove',\r\n    ru: 'Новые сообщения [Клик] для удаления'\r\n  });\r\n\r\n  // Add click handler to remove separator\r\n  iconContainer.addEventListener('click', () => {\r\n    separator.remove();\r\n  });\r\n\r\n  separator.appendChild(hr);\r\n  separator.appendChild(iconContainer);\r\n\r\n  return separator;\r\n}\r\n\r\n/**\r\n * Removes the separator if it exists from the provided container.\r\n * @param {HTMLElement} panel - The container element to check for the separator.\r\n */\r\nfunction removeNewMessagesSeparator(panel) {\r\n  const separator = panel.querySelector('.new-messages-separator');\r\n  if (separator) {\r\n    separator.remove();\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/messagesSeparator.js?");

/***/ }),

/***/ "./src/helpers/mobileLayout.js":
/*!*************************************!*\
  !*** ./src/helpers/mobileLayout.js ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   handleMobileLayout: () => (/* binding */ handleMobileLayout)\n/* harmony export */ });\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n// Add this function to handle mobile/touch devices\r\nfunction handleMobileLayout(chatContainer, chatContent, messagesPanel, dragArea, inputContainer) {\r\n  const isMobile = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.checkIsMobile)();\r\n  if (isMobile) {\r\n\r\n    // Add styles for mobile view\r\n    const globalMobileStyles = document.createElement('style');\r\n    globalMobileStyles.classList.add('global-mobile-styles');\r\n    globalMobileStyles.textContent = `\r\n      html, body {\r\n        overflow: hidden !important;\r\n        height: 0 !important;\r\n      }\r\n\r\n      #app-chat-container .emoji-panel {\r\n        transform: translate(-50%, 0%) !important;\r\n        height: 60vh !important;\r\n        top: 1em !important;\r\n        left: 50% !important;\r\n        right: unset !important;\r\n      }\r\n      .help-panel,\r\n      .ignored-users-panel,\r\n      .chat-username-color-picker {\r\n        top: 80px !important;\r\n        transform: translate(-50%, 0%) !important;\r\n      }\r\n      \r\n      .events-panel {\r\n        left: 5% !important;\r\n        transform: none !important;\r\n        top: 80px !important;\r\n        width: 90% !important;\r\n      }\r\n\r\n      #app-chat-container .user-list-container {\r\n        top: 50px !important;\r\n        height: fit-content !important;\r\n        max-height: 70vh !important;\r\n        border-top: 1px solid var(--border-color) !important;\r\n        border-bottom: 1px solid var(--border-color) !important;\r\n        border-radius: 0.5em 0 0 0.5em !important;\r\n      }\r\n\r\n      #app-chat-container .toggle-button {\r\n        border: none !important;\r\n        top: 0 !important;\r\n        right: 0 !important;\r\n        border-radius: 0.2em !important;\r\n        margin: 1em !important;\r\n        box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1) !important;\r\n      }\r\n    `;\r\n    document.head.appendChild(globalMobileStyles);\r\n\r\n    // Use Visual Viewport API for keyboard detection and correct positioning\r\n    if (window.visualViewport) {\r\n      window.visualViewport.addEventListener('resize', () => {\r\n        // Calculate the bottom offset taking into account the viewport offset when scrolling\r\n        const bottomOffset = window.innerHeight - window.visualViewport.height - window.visualViewport.offsetTop;\r\n        // Update the chat container height to fit the available space when keyboard is open\r\n        chatContainer.style.setProperty('height', `calc(100% - ${bottomOffset}px)`, 'important');\r\n\r\n        // Get the current height of the chat container\r\n        const hideElements = chatContainer.getBoundingClientRect().height < 100;\r\n\r\n        // Hide or show elements based on the chat container height\r\n        messagesPanel.style.display = hideElements ? 'none' : '';\r\n        chatContent.style.margin = hideElements ? '0' : '';\r\n        chatContent.style.marginTop = hideElements ? '0' : '';\r\n        inputContainer.style.position = hideElements ? 'absolute' : '';\r\n        inputContainer.style.bottom = hideElements ? '0' : '';\r\n        dragArea.style.display = hideElements ? 'none' : '';\r\n        const revealBtn = document.querySelector('.reveal-userlist-btn');\r\n        if (revealBtn) revealBtn.style.display = hideElements ? 'none' : '';\r\n\r\n        // Forse to scroll the messages panel to the bottom when keyboard is opened or closed\r\n        messagesPanel.scrollTop = messagesPanel.scrollHeight;\r\n      });\r\n    }\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/mobileLayout.js?");

/***/ }),

/***/ "./src/helpers/parser.js":
/*!*******************************!*\
  !*** ./src/helpers/parser.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   parseMarkdown: () => (/* binding */ parseMarkdown),\n/* harmony export */   parseMessageText: () => (/* binding */ parseMessageText)\n/* harmony export */ });\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\nconst parseMessageText = text => {\r\n  // First, apply markdown transformations\r\n  text = parseMarkdown(text);\r\n\r\n  let i = 0, urls = [];\r\n  // Extract URLs and replace them with placeholders\r\n  text = text.replace(/(\\b(https?|ftp):\\/\\/[-A-Z0-9+&@#\\/%?=~|!:,.;()_]*[-A-Z0-9+&@#\\/%=~|()_])/ig, m => {\r\n    urls.push(m);\r\n    return `___URL${i++}___`;\r\n  });\r\n\r\n  // Replace smilies and adjust emoji presentation\r\n  text = text\r\n    .replace(/:(\\w+):/g, (_, e) => `<img src=\"https://klavogonki.ru/img/smilies/${e}.gif\" alt=\"${e}\" />`)\r\n    .replace(/(\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F)/gu, '<span class=\"emoji-adjuster\">$&</span>');\r\n\r\n  // Replace placeholders with anchor tags after markdown processing\r\n  urls.forEach((url, idx) => {\r\n    if ((0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.isEncodedURL)(url)) {\r\n      const decodedURL = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.decodeURL)(url);\r\n      text = text.replace(\r\n        `___URL${idx}___`,\r\n        `<a class=\"processed-link decoded-link\" href=\"${url}\" target=\"_blank\">${decodedURL}</a>`\r\n      );\r\n    } else {\r\n      text = text.replace(\r\n        `___URL${idx}___`,\r\n        `<a class=\"processed-link\" href=\"${url}\" target=\"_blank\">${url}</a>`\r\n      );\r\n    }\r\n  });\r\n\r\n  // Define the regex to match anchor tags\r\n  const anchorRegex = /<a [^>]+>.*?<\\/a>/gi;\r\n\r\n  // Split the text into parts, separating anchors from plain text\r\n  const textParts = text.split(anchorRegex);\r\n\r\n  // Extract all anchor tags into an array\r\n  const anchors = text.match(anchorRegex) || [];\r\n\r\n  let finalMessage = '';\r\n\r\n  // Iterate over text parts and interleave with anchors\r\n  textParts.forEach((part, index) => {\r\n    // Wrap non-empty text parts in <p> with both classes\r\n    if (part.trim()) {\r\n      finalMessage += `<p class=\"message-piece break-content\">${part}</p>`;\r\n    }\r\n    // Append the anchor if it exists at this index\r\n    if (index < anchors.length) {\r\n      finalMessage += anchors[index];\r\n    }\r\n  });\r\n\r\n  return finalMessage;\r\n}\r\n\r\n// Basic markdown support function with additional CSS classes\r\nconst parseMarkdown = text => {\r\n  // Convert markdown headings to HTML headings with extra class names\r\n  text = text.replace(/^######\\s+(.*)$/gim, '<h6 class=\"md-heading md-h6\">$1</h6>');\r\n  text = text.replace(/^#####\\s+(.*)$/gim, '<h5 class=\"md-heading md-h5\">$1</h5>');\r\n  text = text.replace(/^####\\s+(.*)$/gim, '<h4 class=\"md-heading md-h4\">$1</h4>');\r\n  text = text.replace(/^###\\s+(.*)$/gim, '<h3 class=\"md-heading md-h3\">$1</h3>');\r\n  text = text.replace(/^##\\s+(.*)$/gim, '<h2 class=\"md-heading md-h2\">$1</h2>');\r\n  text = text.replace(/^#\\s+(.*)$/gim, '<h1 class=\"md-heading md-h1\">$1</h1>');\r\n\r\n  // Convert inline code enclosed in backticks\r\n  text = text.replace(/`([^`]+)`/g, '<code class=\"md-code\">$1</code>');\r\n\r\n  // Convert bold text (using ** only)\r\n  text = text.replace(/\\*\\*(.+?)\\*\\*/g, '<strong class=\"md-bold\">$1</strong>');\r\n\r\n  // Convert italic text (using __ only)\r\n  text = text.replace(/__(.+?)__/g, '<em class=\"md-italic\">$1</em>');\r\n\r\n  // Convert markdown strikethrough using ~~text~~\r\n  text = text.replace(/~~(.+?)~~/g, '<del class=\"md-strikethrough\">$1</del>');\r\n\r\n  return text;\r\n};\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/parser.js?");

/***/ }),

/***/ "./src/helpers/privateMessagesHandler.js":
/*!***********************************************!*\
  !*** ./src/helpers/privateMessagesHandler.js ***!
  \***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   handlePrivateMessageInput: () => (/* binding */ handlePrivateMessageInput),\n/* harmony export */   privateMessageState: () => (/* binding */ privateMessageState),\n/* harmony export */   setupPrivateMessageEvents: () => (/* binding */ setupPrivateMessageEvents)\n/* harmony export */ });\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _tooltip_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n// State management for private messaging\r\nconst privateMessageState = {\r\n  isPrivateMode: false,\r\n  targetUsername: null,\r\n  targetId: null,\r\n  fullJid: null,\r\n\r\n  async setPrivateTarget(username) {\r\n    if (!username) {\r\n      this.exitPrivateMode();\r\n      return false;\r\n    }\r\n\r\n    try {\r\n      const userId = await (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.getExactUserIdByName)(username);\r\n      if (!userId) return false;\r\n\r\n      this.isPrivateMode = true;\r\n      this.targetUsername = username;\r\n      this.targetId = userId;\r\n      this.fullJid = `${userId}#${username}@jabber.klavogonki.ru/web`;\r\n\r\n      return true;\r\n    } catch (error) {\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Error setting private target: ${error.message}`,\r\n        ru: `Ошибка установки приватной цели: ${error.message}`\r\n      }, 'error');\r\n      return false;\r\n    }\r\n  },\r\n\r\n  exitPrivateMode() {\r\n    this.isPrivateMode = false;\r\n    this.targetUsername = null;\r\n    this.targetId = null;\r\n    this.fullJid = null;\r\n  }\r\n};\r\n\r\n// Global reference for ESC key handler\r\nlet escKeyHandler = null;\r\n\r\n// Function to handle ESC key press\r\nfunction handleEscKeyPress(event) {\r\n  if (event.key === 'Escape' && privateMessageState.isPrivateMode) {\r\n    exitPrivateMode();\r\n  }\r\n}\r\n\r\n// Toggle private message mode based on input value\r\nasync function handlePrivateMessageInput(inputElement) {\r\n  if (!inputElement) return;\r\n  const input = inputElement.value;\r\n  // Updated regex to include hyphens and other common username special characters\r\n  const privateModeRegex = /^\\/pm\\s+([\\wа-яА-ЯёЁ\\-\\.\\_\\+]+)\\s/;\r\n  const exitPrivateModeRegex = /^\\/exit\\s*$/;\r\n  const match = input.match(privateModeRegex);\r\n  if (match) {\r\n    const username = match[1];\r\n    const success = await privateMessageState.setPrivateTarget(username);\r\n    if (success) {\r\n      enterPrivateMode(username);\r\n      inputElement.value = input.replace(privateModeRegex, ''); // Remove the /pm username part\r\n    } else {\r\n      (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n        en: `Could not find user \"${username}\"`,\r\n        ru: `Не удалось найти пользователя \"${username}\"`\r\n      }, 'error');\r\n      exitPrivateMode();\r\n    }\r\n  } else if (exitPrivateModeRegex.test(input)) {\r\n    exitPrivateMode();\r\n    inputElement.value = ''; // Clear the input\r\n  }\r\n}\r\n\r\nfunction enterPrivateMode(username) {\r\n  const messageInput = document.getElementById('message-input');\r\n  if (privateMessageState.isPrivateMode && privateMessageState.targetUsername !== username) {\r\n    exitPrivateMode();\r\n  }\r\n\r\n  if (!messageInput.classList.contains('private-mode') || privateMessageState.targetUsername !== username) {\r\n    messageInput.classList.add('private-mode');\r\n    messageInput.placeholder = `PM to ➡ ${username}`;\r\n\r\n    // Create or update exit button\r\n    let exitButton = document.querySelector('.private-mode-exit');\r\n    if (!exitButton) {\r\n      exitButton = document.createElement('span');\r\n      exitButton.className = 'button private-mode-exit';\r\n\r\n      // Add click event to exit private mode\r\n      exitButton.addEventListener('click', () => {\r\n        exitPrivateMode();\r\n        messageInput.focus();\r\n      });\r\n\r\n      // Add the exit button to the UI near the input\r\n      const inputContainer = messageInput.parentElement;\r\n      inputContainer.insertBefore(exitButton, messageInput.nextSibling);\r\n    }\r\n\r\n    // Set default closed lock emoji and custom tooltip\r\n    exitButton.innerHTML = \"🔒\";\r\n    (0,_tooltip_js__WEBPACK_IMPORTED_MODULE_1__.createCustomTooltip)(exitButton, {\r\n      en: \"Exit private mode\",\r\n      ru: \"Выйти из приватного режима\"\r\n    });\r\n\r\n    // Change emoji on hover: open lock on mouseenter, closed lock on mouseleave\r\n    exitButton.addEventListener('mouseenter', () => {\r\n      exitButton.innerHTML = \"🔓\";\r\n    });\r\n\r\n    exitButton.addEventListener('mouseleave', () => {\r\n      exitButton.innerHTML = \"🔒\";\r\n    });\r\n\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Entered private chat with ${username}`,\r\n      ru: `Вошли в приватный чат с ${username}`\r\n    }, 'warning');\r\n    privateMessageState.isPrivateMode = true;\r\n    privateMessageState.targetUsername = username;\r\n\r\n    // Add ESC key event listener when entering private mode\r\n    if (!escKeyHandler) {\r\n      escKeyHandler = handleEscKeyPress;\r\n      document.addEventListener('keydown', escKeyHandler);\r\n    }\r\n  } else if (privateMessageState.targetUsername === username) {\r\n    messageInput.placeholder = `️PM to ➡ ${username}`;\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Entered private chat with ${username}`,\r\n      ru: `Вошли в приватный чат с ${username}`\r\n    }, 'warning');\r\n  }\r\n}\r\n\r\nfunction exitPrivateMode() {\r\n  const messageInput = document.getElementById('message-input');\r\n  if (messageInput.classList.contains('private-mode')) {\r\n    messageInput.classList.remove('private-mode');\r\n    messageInput.placeholder = ''; // Reset placeholder\r\n\r\n    // Remove the exit button\r\n    const exitButton = document.querySelector('.private-mode-exit');\r\n    if (exitButton) exitButton.remove();\r\n\r\n    const username = privateMessageState.targetUsername; // Get username before clearing state\r\n    \r\n    // Use the global messageManager reference to remove private messages\r\n    if (window.messageManager && typeof window.messageManager.removePrivateMessages === 'function') {\r\n      window.messageManager.removePrivateMessages();\r\n    }\r\n    \r\n    privateMessageState.exitPrivateMode(); // Only call once\r\n    (0,_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: `Exited private chat with ${username}`,\r\n      ru: `Вышли из приватного чата с ${username}`\r\n    }, 'success');\r\n\r\n    // Remove ESC key event listener when exiting private mode\r\n    if (escKeyHandler) {\r\n      document.removeEventListener('keydown', escKeyHandler);\r\n      escKeyHandler = null;\r\n    }\r\n  }\r\n}\r\n\r\n// Handle ESC key to exit private mode\r\nfunction setupPrivateMessageEvents(inputElement) {\r\n  if (!inputElement) return;\r\n\r\n  // Check for private message mode on input changes\r\n  inputElement.addEventListener('input', () => {\r\n    handlePrivateMessageInput(inputElement);\r\n  });\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/privateMessagesHandler.js?");

/***/ }),

/***/ "./src/helpers/tooltip.js":
/*!********************************!*\
  !*** ./src/helpers/tooltip.js ***!
  \********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   createCustomTooltip: () => (/* binding */ createCustomTooltip)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n\r\nlet tooltipEl = null, tooltipHideTimer = null, tooltipShowTimer = null;\r\nlet tooltipIsVisible = false, tooltipCurrentTarget = null;\r\n\r\nconst positionTooltip = (clientX, clientY) => {\r\n  if (!tooltipEl) return;\r\n  let leftPos = clientX + 10;\r\n  const tooltipWidth = tooltipEl.offsetWidth;\r\n  const tooltipHeight = tooltipEl.offsetHeight;\r\n  const screenWidth = window.innerWidth;\r\n  const screenHeight = window.innerHeight;\r\n\r\n  // Adjust position if overflowing horizontally\r\n  leftPos = Math.min(Math.max(leftPos, 10), screenWidth - tooltipWidth - 10);\r\n\r\n  // Use separate margins for top and bottom\r\n  const topMargin = 18, bottomMargin = 0;\r\n  let topPos = clientY + topMargin;\r\n\r\n  // If tooltip would overflow at the bottom, try above the cursor\r\n  if (topPos + tooltipHeight > screenHeight - bottomMargin) {\r\n    const above = clientY - tooltipHeight - topMargin;\r\n    if (above >= topMargin) {\r\n      topPos = above;\r\n    } else {\r\n      // Clamp to bottom margin if above is not possible\r\n      topPos = screenHeight - tooltipHeight - bottomMargin;\r\n    }\r\n  }\r\n\r\n  // Clamp to always respect top margin\r\n  topPos = Math.max(topMargin, topPos);\r\n\r\n  tooltipEl.style.left = `${leftPos}px`;\r\n  tooltipEl.style.top = `${topPos}px`;\r\n};\r\n\r\nconst tooltipTrackMouse = e => tooltipEl && positionTooltip(e.clientX, e.clientY);\r\n\r\nconst hideTooltipElement = () => {\r\n  tooltipIsVisible = false;\r\n  tooltipCurrentTarget = null;\r\n  clearTimeout(tooltipShowTimer);\r\n  clearTimeout(tooltipHideTimer);\r\n\r\n  tooltipHideTimer = setTimeout(() => {\r\n    if (!tooltipEl) return;\r\n    tooltipEl.style.opacity = '0';\r\n\r\n    setTimeout(() => {\r\n      if (!tooltipIsVisible && tooltipEl) {\r\n        tooltipEl.style.display = 'none';\r\n        document.removeEventListener('mousemove', tooltipTrackMouse);\r\n        tooltipEl.textContent = '';\r\n      }\r\n    }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.tooltipVisibleTime / 2);\r\n  }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.tooltipVisibleTime);\r\n};\r\n\r\nnew MutationObserver(() => {\r\n  if (tooltipCurrentTarget && !document.contains(tooltipCurrentTarget)) hideTooltipElement();\r\n}).observe(document, { childList: true, subtree: true });\r\n\r\n// Highlight [Action]Message pairs in the tooltip content\r\nfunction highlightTooltipActions(str) {\r\n  // Match [Action]Message pairs\r\n  const regex = /\\[([^\\]]+)\\]([^\\[]*)/g;\r\n  let result = '';\r\n  let lastEnd = 0;\r\n  let match;\r\n  while ((match = regex.exec(str)) !== null) {\r\n    // Add any text before the first match (shouldn't happen in normal usage)\r\n    if (match.index > lastEnd) result += str.slice(lastEnd, match.index);\r\n    result += `\r\n    <div class=\"tooltip-item\">\r\n      <span class=\"tooltip-action\">${match[1]}</span>&nbsp;\r\n      <span class=\"tooltip-message\">${match[2].trim()}</span>\r\n    </div>`;\r\n    lastEnd = regex.lastIndex;\r\n  }\r\n  // Add any trailing text after the last match\r\n  if (lastEnd < str.length) result += str.slice(lastEnd);\r\n  return result;\r\n}\r\n\r\nfunction createCustomTooltip(element, tooltipContent, lang = null) {\r\n  if ((0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.checkIsMobile)()) return; // Prevent tooltips on mobile\r\n  if (tooltipContent == null) return; // Skip if content is null/undefined\r\n\r\n  // Determine language: use param, else imported default, else 'en'\r\n  lang = lang || _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.defaultLanguage || 'en';\r\n\r\n  // If tooltipContent is an object with language keys, pick the right one\r\n  let content = tooltipContent;\r\n  if (typeof tooltipContent === 'object' && (tooltipContent.en || tooltipContent.ru)) {\r\n    content = tooltipContent[lang] || tooltipContent.en || tooltipContent.ru;\r\n  }\r\n\r\n  // Highlight [action] words\r\n  content = highlightTooltipActions(content);\r\n\r\n  // Always update the tooltip content stored on the element.\r\n  element._tooltipContent = content;\r\n\r\n  // If tooltip event listeners haven't been attached, attach them once.\r\n  if (!element._tooltipInitialized) {\r\n    element._tooltipInitialized = true;\r\n\r\n    // Initialize tooltip element if it doesn't exist yet.\r\n    tooltipEl ||= (() => {\r\n      const tooltipDiv = document.createElement('div');\r\n      tooltipDiv.classList.add(\"custom-tooltip-popup\");\r\n      // Optionally, set positioning styles here:\r\n      tooltipDiv.style.position = 'absolute';\r\n      tooltipDiv.style.display = 'none';\r\n      tooltipDiv.style.opacity = '0';\r\n      document.body.appendChild(tooltipDiv);\r\n      return tooltipDiv;\r\n    })();\r\n\r\n    element.addEventListener('mouseenter', e => {\r\n      tooltipIsVisible = true;\r\n      tooltipCurrentTarget = element;\r\n      clearTimeout(tooltipHideTimer);\r\n      clearTimeout(tooltipShowTimer);\r\n\r\n      // Use the latest stored tooltip content\r\n      tooltipEl.innerHTML = element._tooltipContent;\r\n      tooltipEl.style.display = 'flex';\r\n      tooltipEl.style.opacity = '0';\r\n\r\n      // Force layout recalculation to ensure transition works\r\n      tooltipEl.offsetHeight;\r\n      positionTooltip(e.clientX, e.clientY);\r\n      document.addEventListener('mousemove', tooltipTrackMouse);\r\n\r\n      tooltipShowTimer = setTimeout(() => {\r\n        tooltipEl.style.opacity = '1';\r\n      }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.tooltipShowDelay);\r\n    });\r\n\r\n    element.addEventListener('mouseleave', e => {\r\n      hideTooltipElement();\r\n      document.removeEventListener('mousemove', tooltipTrackMouse);\r\n    });\r\n  }\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/helpers/tooltip.js?");

/***/ }),

/***/ "./src/main.js":
/*!*********************!*\
  !*** ./src/main.js ***!
  \*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _xmpp_xmppConnection_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./xmpp/xmppConnection.js */ \"./src/xmpp/xmppConnection.js\");\n/* harmony import */ var _managers_userManager_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./managers/userManager.js */ \"./src/managers/userManager.js\");\n/* harmony import */ var _managers_messageManager_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./managers/messageManager.js */ \"./src/managers/messageManager.js\");\n/* harmony import */ var _chat_chatUI_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./chat/chatUI.js */ \"./src/chat/chatUI.js\");\n/* harmony import */ var _auth_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./auth.js */ \"./src/auth.js\");\n/* harmony import */ var _components_updateCheck_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/updateCheck.js */ \"./src/components/updateCheck.js\");\n/* harmony import */ var _helpers_commands_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./helpers/commands.js */ \"./src/helpers/commands.js\");\n/* harmony import */ var _chat_chatMessagesRemover_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./chat/chatMessagesRemover.js */ \"./src/chat/chatMessagesRemover.js\");\n/* harmony import */ var _chat_chatEvents_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./chat/chatEvents.js */ \"./src/chat/chatEvents.js\");\n/* harmony import */ var _xmpp_xmppClient_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./xmpp/xmppClient.js */ \"./src/xmpp/xmppClient.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _src_chat_chatState_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../src/chat/chatState.js */ \"./src/chat/chatState.js\");\n/* harmony import */ var _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./helpers/privateMessagesHandler.js */ \"./src/helpers/privateMessagesHandler.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Function to detect if running in an iframe\r\nfunction isInIframe() {\r\n  try {\r\n    return window !== window.top;\r\n  } catch (e) {\r\n    // If there's an error when trying to access window.top, \r\n    // it's likely due to cross-origin restrictions, which means we're in an iframe\r\n    return true;\r\n  }\r\n}\r\n\r\n// ------------------------- Auth Check ---------------------------\r\nfunction checkAuth() {\r\n  // First check if running in iframe\r\n  if (isInIframe()) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.logMessage)(\"Application cannot run in an iframe\", 'error');\r\n    return false;\r\n  }\r\n\r\n  const params = new URLSearchParams(window.location.search);\r\n  if (window.location.pathname === '/g/' && params.has('gmid')) {\r\n    return false;\r\n  }\r\n  if (window.location.href.includes('/gamelist/')) {\r\n    (0,_auth_js__WEBPACK_IMPORTED_MODULE_4__.getAuthData)();\r\n    return false;\r\n  }\r\n  const authData = localStorage.getItem('klavoauth');\r\n  if (!authData || !_auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.username || !_auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.password) {\r\n    localStorage.removeItem('klavoauth');\r\n    window.location.href = 'https://klavogonki.ru/gamelist/';\r\n    return false;\r\n  }\r\n  return true;\r\n}\r\n\r\n// ------------------------- Main App ---------------------------\r\nasync function initializeApp() {\r\n  try {\r\n    // Add viewport meta tag\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.addViewportMeta)();\r\n\r\n    if (!checkAuth()) return;\r\n\r\n    // Initialize UI and features\r\n    (0,_chat_chatUI_js__WEBPACK_IMPORTED_MODULE_3__.createChatUI)();\r\n    (0,_src_chat_chatState_js__WEBPACK_IMPORTED_MODULE_11__.addChatToggleFeature)();\r\n    (0,_chat_chatEvents_js__WEBPACK_IMPORTED_MODULE_8__.setupDragHandlers)();\r\n    (0,_chat_chatEvents_js__WEBPACK_IMPORTED_MODULE_8__.setupResizeHandlers)();\r\n    (0,_chat_chatEvents_js__WEBPACK_IMPORTED_MODULE_8__.setupWindowResizeHandler)();\r\n\r\n    // Set up the messages panel observer\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.observeMessagesPanel)();\r\n\r\n    // Initialize managers and XMPP connection\r\n    const userManager = new _managers_userManager_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]('user-list');\r\n    window.userManager = userManager; // Make userManager globally accessible\r\n    const messageManager = new _managers_messageManager_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"]('messages-panel', (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.parseUsername)(_auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.username));\r\n    window.messageManager = messageManager; // Make messageManager globally accessible\r\n    const xmppConnection = new _xmpp_xmppConnection_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\r\n      username: _auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.username,\r\n      password: _auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.password\r\n    });\r\n\r\n    const xmppClient = (0,_xmpp_xmppClient_js__WEBPACK_IMPORTED_MODULE_9__.createXMPPClient)(\r\n      xmppConnection,\r\n      userManager,\r\n      messageManager,\r\n      _auth_js__WEBPACK_IMPORTED_MODULE_4__.klavoauth.username\r\n    );\r\n\r\n    const input = document.getElementById('message-input');\r\n\r\n    const sendMessage = () => {\r\n      const text = input.value.trim();\r\n      if (!text) return;\r\n      xmppClient.sendMessage(text);\r\n      input.value = '';\r\n      input.focus();\r\n    };\r\n\r\n    // Set up event listeners\r\n    document.getElementById('send-button').addEventListener('click', sendMessage);\r\n    input.addEventListener('keypress', e => e.key === 'Enter' && sendMessage());\r\n    input.addEventListener('paste', e => requestAnimationFrame(() => input.value = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.decodeEncodedURL)(input.value)));\r\n\r\n    // Set up private messaging events\r\n    (0,_helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_12__.setupPrivateMessageEvents)(input);\r\n    // Set up reset command event\r\n    (0,_helpers_commands_js__WEBPACK_IMPORTED_MODULE_6__.setupCommandEvents)(input);\r\n\r\n    // Connect to XMPP and join the room\r\n    await xmppClient.connect();\r\n    window.xmppClient = xmppClient; // For debugging\r\n\r\n  } catch (error) {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_10__.logMessage)(`App initialization error: ${error.message}`, 'error');\r\n    (0,_auth_js__WEBPACK_IMPORTED_MODULE_4__.removeChatParams)();\r\n  }\r\n}\r\n\r\n// Start the app and perform initial operations\r\ninitializeApp().then(() => {\r\n  (0,_chat_chatMessagesRemover_js__WEBPACK_IMPORTED_MODULE_7__.pruneDeletedMessages)(); // Remove unexisting deleted messages IDs from localStorage\r\n  (0,_components_updateCheck_js__WEBPACK_IMPORTED_MODULE_5__.checkForUpdates)(); // Check for updates on page load\r\n});\n\n//# sourceURL=webpack://tampermonkey-script/./src/main.js?");

/***/ }),

/***/ "./src/managers/messageManager.js":
/*!****************************************!*\
  !*** ./src/managers/messageManager.js ***!
  \****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ MessageManager)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _helpers_messagesSeparator_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/messagesSeparator.js */ \"./src/helpers/messagesSeparator.js\");\n/* harmony import */ var _helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/mentionWatcher.js */ \"./src/helpers/mentionWatcher.js\");\n/* harmony import */ var _chat_chatMessagesRemover_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../chat/chatMessagesRemover.js */ \"./src/chat/chatMessagesRemover.js\");\n/* harmony import */ var _helpers_parser_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../helpers/parser.js */ \"./src/helpers/parser.js\");\n/* harmony import */ var _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../helpers/chatUsernameColors.js */ \"./src/helpers/chatUsernameColors.js\");\n/* harmony import */ var _components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../components/ignoredUsersPanel.js */ \"./src/components/ignoredUsersPanel.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_iframeProfileLoader_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../helpers/iframeProfileLoader.js */ \"./src/helpers/iframeProfileLoader.js\");\n/* harmony import */ var _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../helpers/privateMessagesHandler.js */ \"./src/helpers/privateMessagesHandler.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nclass MessageManager {\r\n  constructor(panelId = 'messages-panel', currentUsername = '') {\r\n    this.panel = document.getElementById(panelId);\r\n    this.messageMap = new Map();\r\n    // renderedMessageIds will be maintained in sync with the DOM\r\n    this.renderedMessageIds = new Set();\r\n    this.currentUsername = currentUsername;\r\n    this.maxMessages = 30;\r\n    this.defaultMessagesCount = 20;\r\n    this.initialLoadComplete = false;\r\n    this.chatRemover = new _chat_chatMessagesRemover_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"]();\r\n    this.messageInput = document.getElementById('message-input');\r\n    this.shouldCreateSeparator = true;\r\n    this._delegatedClickAttached = false;\r\n\r\n    // Listen for tab visibility changes\r\n    document.addEventListener(\"visibilitychange\", () => {\r\n      if (document.hidden) {\r\n        (0,_helpers_messagesSeparator_js__WEBPACK_IMPORTED_MODULE_1__.removeNewMessagesSeparator)(this.panel);\r\n        this.shouldCreateSeparator = true;\r\n      }\r\n    });\r\n\r\n    // Remove separator when user focuses on message input\r\n    if (this.messageInput) {\r\n      this.messageInput.addEventListener('focus', () => {\r\n        (0,_helpers_messagesSeparator_js__WEBPACK_IMPORTED_MODULE_1__.removeNewMessagesSeparator)(this.panel);\r\n        this.shouldCreateSeparator = true;\r\n      });\r\n    }\r\n  }\r\n\r\n  // Updated unique ID generator to include the timestamp\r\n  generateUniqueId(type, timestamp, username, text) {\r\n    const time = timestamp || new Date().toLocaleTimeString('en-GB', { hour12: false });\r\n    if (type === 'private') {\r\n      const now = Date.now(); // milliseconds since epoch\r\n      return `private-${now}`;\r\n    }\r\n    return `${time}-[${username}]-${text}`;\r\n  }\r\n\r\n  addMessage(messageObj) {\r\n    this.messageMap.set(messageObj.id, messageObj);\r\n    this.trimMessages();\r\n    return true;\r\n  }\r\n\r\n  trimMessages() {\r\n    while (this.messageMap.size > this.maxMessages) {\r\n      const oldestKey = this.messageMap.keys().next().value;\r\n      this.messageMap.delete(oldestKey);\r\n      this.renderedMessageIds.delete(oldestKey);\r\n    }\r\n  }\r\n\r\n  processMessages(xmlResponse) {\r\n    if (typeof xmlResponse !== 'string' || !xmlResponse) return;\r\n    // Use centralized helper for ignored users\r\n    const { forever, temporary } = (0,_components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_6__.getAllIgnoredUsers)();\r\n    const ignoredUsers = [...forever, ...temporary];\r\n\r\n    const doc = new DOMParser().parseFromString(xmlResponse, \"text/xml\");\r\n    const messageElements = doc.getElementsByTagName(\"message\");\r\n    let newMessagesAdded = false;\r\n\r\n    Array.from(messageElements).forEach(msg => {\r\n      const bodyNode = msg.getElementsByTagName(\"body\")[0];\r\n      if (!bodyNode || !bodyNode.textContent) return;\r\n      const text = bodyNode.textContent.trim();\r\n      if (text === \"This room is not anonymous\") return;\r\n\r\n      // Skip messages addressed to ignored users, e.g. \"Mark, how are you?\"\r\n      const addressMatch = /^([^,\\s]+),/.exec(text);\r\n      if (addressMatch && ignoredUsers.includes(addressMatch[1])) {\r\n        return;\r\n      }\r\n\r\n      const fromAttr = msg.getAttribute(\"from\");\r\n      const from = fromAttr\r\n        ? fromAttr.split('#')[1]?.split('@')[0] || \"unknown\"\r\n        : \"unknown\";\r\n      const cleanFrom = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.parseUsername)(from);\r\n\r\n      // Skip messages from ignored users\r\n      if (ignoredUsers.includes(cleanFrom)) return;\r\n\r\n      const toAttr = msg.getAttribute(\"to\");\r\n      const typeAttr = msg.getAttribute(\"type\");\r\n      const isPrivate = typeAttr === 'chat';\r\n      let recipient = null;\r\n      if (isPrivate && toAttr) {\r\n        recipient = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.parseUsername)(toAttr.split('#')[1]?.split('@')[0] || toAttr);\r\n      }\r\n\r\n      // Extract timestamp from delay element\r\n      let timestamp = null;\r\n      const delayEl = msg.getElementsByTagName(\"delay\")[0];\r\n      if (delayEl && delayEl.getAttribute(\"stamp\")) {\r\n        const stampStr = delayEl.getAttribute(\"stamp\");\r\n        try {\r\n          const stampDate = new Date(stampStr);\r\n          // Always use the server timestamp here.\r\n          timestamp = stampDate.toLocaleTimeString('en-GB', { hour12: false });\r\n        } catch (e) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Message manager: Error parsing timestamp: ${e.message}`, 'error');\r\n        }\r\n      }\r\n\r\n      if (!timestamp) {\r\n        // Only fall back to local time if there's no server timestamp at all.\r\n        timestamp = new Date().toLocaleTimeString('en-GB', { hour12: false });\r\n      }\r\n\r\n      // Prevent loading my own messages if already loaded\r\n      if (cleanFrom === this.currentUsername && this.initialLoadComplete) return;\r\n\r\n      const isDuplicate = Array.from(this.messageMap.values()).some(existingMsg =>\r\n        existingMsg.from === cleanFrom &&\r\n        existingMsg.text === text\r\n      );\r\n\r\n      if (!isDuplicate) {\r\n        const uniqueId = this.generateUniqueId(\r\n          isPrivate ? 'private' : 'public',\r\n          timestamp, // server timestamp\r\n          cleanFrom,\r\n          text\r\n        );\r\n\r\n        const messageObj = {\r\n          id: uniqueId,\r\n          from: cleanFrom,\r\n          text,\r\n          isPrivate,\r\n          recipient,\r\n          pending: false,\r\n          timestamp\r\n        };\r\n\r\n        if (this.addMessage(messageObj)) {\r\n          newMessagesAdded = true;\r\n        }\r\n      }\r\n    });\r\n\r\n    if (newMessagesAdded) {\r\n      this.updatePanel();\r\n    }\r\n  }\r\n\r\n  addSentMessage(text, options = {}) {\r\n    const isPrivate = options.isPrivate || false;\r\n    const currentTime = new Date().toLocaleTimeString('en-GB', { hour12: false });\r\n    const uniqueId = this.generateUniqueId(\r\n      isPrivate ? 'private' : 'public',\r\n      currentTime, // local timestamp\r\n      this.currentUsername,\r\n      text\r\n    );\r\n\r\n    const messageObj = {\r\n      id: uniqueId,\r\n      from: this.currentUsername,\r\n      text,\r\n      isPrivate,\r\n      recipient: options.recipient || null,\r\n      pending: options.pending || false,\r\n      timestamp: currentTime\r\n    };\r\n\r\n    if (this.addMessage(messageObj)) {\r\n      this.updatePanel();\r\n    }\r\n\r\n    return uniqueId;\r\n  }\r\n\r\n  updatePendingStatus(messageId, pendingStatus) {\r\n    const msg = this.messageMap.get(messageId);\r\n    if (msg) {\r\n      msg.pending = pendingStatus;\r\n      this.updatePanel();\r\n    }\r\n  }\r\n\r\n  updatePanel() {\r\n    if (!this.panel) return;\r\n    // Compute the set of IDs already rendered in the DOM.\r\n    const domRenderedIds = new Set(\r\n      Array.from(this.panel.querySelectorAll('.message')).map(el => el.getAttribute('data-message-id'))\r\n    );\r\n    // Synchronize the in‑memory set with the DOM.\r\n    this.renderedMessageIds = domRenderedIds;\r\n\r\n    // Create a single fragment for new messages.\r\n    const fragment = document.createDocumentFragment();\r\n    let mentionDetected = false;\r\n\r\n    // Iterate over our messages from the messageMap.\r\n    this.messageMap.forEach((msg, id) => {\r\n      if (!this.renderedMessageIds.has(id)) {\r\n        const formattedTime = msg.timestamp || new Date().toLocaleTimeString('en-GB', { hour12: false });\r\n        const normalizedUsername = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.parseUsername)(msg.from);\r\n        const usernameColor = _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_5__.usernameColors.getColor(normalizedUsername);\r\n        const messageEl = document.createElement('div');\r\n        messageEl.className = 'message';\r\n        messageEl.setAttribute('data-message-id', id);\r\n\r\n        // Add classname 'banned' for Клавобот\r\n        if (msg.from === 'Клавобот') {\r\n          messageEl.classList.add('banned');\r\n          if (this.initialLoadComplete) {\r\n            (0,_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.playAudio)(_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.banned);\r\n          }\r\n        }\r\n\r\n        // Play notification sound for new private messages when the tab is inactive\r\n        if (msg.isPrivate && msg.from !== this.currentUsername && document.hidden) {\r\n          (0,_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.playAudio)(_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.notification);\r\n        }\r\n\r\n        if (msg.isPrivate) {\r\n          messageEl.classList.add('private');\r\n          messageEl.classList.add(msg.from === this.currentUsername ? 'sent' : 'received');\r\n          if (msg.recipient) {\r\n            messageEl.setAttribute('data-recipient', msg.recipient);\r\n          }\r\n        }\r\n\r\n        if (msg.text.startsWith('/me ')) {\r\n          messageEl.classList.add('system');\r\n          msg.text = `${msg.from} ${msg.text.substring(msg.text.indexOf(' ') + 1)}`;\r\n        }\r\n\r\n        if (msg.isSystem) {\r\n          messageEl.classList.add('system');\r\n        }\r\n\r\n        // Build message info.\r\n        const messageInfoEl = document.createElement('div');\r\n        messageInfoEl.className = 'message-info';\r\n        let usernameDisplay = msg.from;\r\n        if (msg.isPrivate) {\r\n          usernameDisplay = msg.from === this.currentUsername && msg.recipient\r\n            ? `→ ${msg.recipient}`\r\n            : `${msg.from} →`;\r\n        }\r\n        messageInfoEl.innerHTML = `\r\n          <span class=\"time\">${formattedTime}</span>\r\n          <span class=\"username\" style=\"color: ${usernameColor}\">${usernameDisplay}</span>\r\n        `;\r\n\r\n        // Build message text.\r\n        const messageTextEl = document.createElement('div');\r\n        messageTextEl.className = 'message-text';\r\n        messageTextEl.innerHTML = (0,_helpers_parser_js__WEBPACK_IMPORTED_MODULE_4__.parseMessageText)(msg.text);\r\n\r\n        messageEl.appendChild(messageInfoEl);\r\n        messageEl.appendChild(messageTextEl);\r\n\r\n        if (msg.pending) {\r\n          const pendingIconEl = document.createElement('span');\r\n          pendingIconEl.className = 'pending-emoji';\r\n          pendingIconEl.textContent = '⏱️';\r\n          messageEl.appendChild(pendingIconEl); // Append after messageTextEl\r\n        }\r\n\r\n        fragment.appendChild(messageEl);\r\n\r\n        // Mark this message as rendered.\r\n        this.renderedMessageIds.add(id);\r\n\r\n        if (this.currentUsername && msg.text.includes(this.currentUsername)) {\r\n          mentionDetected = true;\r\n        }\r\n      }\r\n    });\r\n\r\n    // If the tab is inactive and new messages have arrived, insert the separator.\r\n    if (document.hidden && this.initialLoadComplete && fragment.childNodes.length > 0 && this.shouldCreateSeparator) {\r\n      const separator = (0,_helpers_messagesSeparator_js__WEBPACK_IMPORTED_MODULE_1__.createNewMessagesSeparator)();\r\n      fragment.insertBefore(separator, fragment.firstChild); // Insert at the beginning of the fragment\r\n      this.shouldCreateSeparator = false;\r\n    }\r\n\r\n    // Append all new messages in one DOM operation.\r\n    this.panel.appendChild(fragment);\r\n    this.addDelegatedClickListeners();\r\n    (0,_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.highlightMentionWords)([this.currentUsername]);\r\n\r\n    if (this.initialLoadComplete && mentionDetected) {\r\n      (0,_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.playAudio)(_helpers_mentionWatcher_js__WEBPACK_IMPORTED_MODULE_2__.notification);\r\n    }\r\n\r\n    requestAnimationFrame(() => {\r\n      // Scroll to the bottom when all messages are loaded.\r\n      if (!this.initialLoadComplete && this.messageMap.size >= this.defaultMessagesCount) {\r\n        // Scroll to the bottom only once when the initial load is complete.\r\n        this.panel.scrollTop = this.panel.scrollHeight;\r\n        this.initialLoadComplete = true;\r\n      }\r\n    });\r\n\r\n    if (this.chatRemover) {\r\n      this.chatRemover.updateDeletedMessages();\r\n      this.chatRemover.renderToggle();\r\n    }\r\n  }\r\n\r\n  addDelegatedClickListeners() {\r\n    if (!this.panel._delegatedClickAttached) {\r\n      // Track click count and timing for double-click detection\r\n      let lastClickTime = 0;\r\n      let lastClickUsername = '';\r\n\r\n      this.panel.addEventListener(\"click\", async (event) => {\r\n        const usernameEl = event.target.closest('.username');\r\n        if (usernameEl && this.panel.contains(usernameEl)) {\r\n          const usernameText = usernameEl.textContent.trim();\r\n          let selectedUsername = usernameText;\r\n\r\n          if (selectedUsername.includes('→')) {\r\n            if (selectedUsername.startsWith('→')) {\r\n              selectedUsername = selectedUsername.replace('→', '').trim();\r\n            } else {\r\n              selectedUsername = selectedUsername.split('→')[0].trim();\r\n            }\r\n          }\r\n\r\n          // Handle Shift+Click to navigate to user profile\r\n          if (event.shiftKey) {\r\n            // Prevent text selection\r\n            window.getSelection().removeAllRanges();\r\n\r\n            // Get the stored username IDs object from sessionStorage\r\n            let usernameIds = {};\r\n            const storedIds = sessionStorage.getItem('usernameIds');\r\n            if (storedIds) {\r\n              try {\r\n                usernameIds = JSON.parse(storedIds);\r\n              } catch (e) {\r\n                (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)(`Message manager: Error parsing stored username IDs: ${e.message}`, 'error');\r\n                usernameIds = {};\r\n              }\r\n            }\r\n\r\n            // Check if the username already has a stored ID\r\n            let userId = usernameIds[selectedUsername];\r\n\r\n            if (!userId) {\r\n              // If not cached, fetch the user ID and store it\r\n              userId = await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.getExactUserIdByName)(selectedUsername);\r\n              if (userId) {\r\n                // Update the object and save it back to sessionStorage\r\n                usernameIds[selectedUsername] = userId;\r\n                sessionStorage.setItem('usernameIds', JSON.stringify(usernameIds));\r\n              }\r\n            }\r\n\r\n            if (userId) {\r\n              const profileUrl = `https://klavogonki.ru/u/#/${userId}/`;\r\n              (0,_helpers_iframeProfileLoader_js__WEBPACK_IMPORTED_MODULE_8__.loadProfileIntoIframe)(profileUrl);\r\n            }\r\n            return;\r\n          }\r\n\r\n          // Original Ctrl+Click behavior for private messaging\r\n          if (event.ctrlKey) {\r\n            this.messageInput.value = `/pm ${selectedUsername} `;\r\n            (0,_helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_9__.handlePrivateMessageInput)(this.messageInput);\r\n          } else {\r\n            // Detect double-click\r\n            const now = Date.now();\r\n            const isDoubleClick = (now - lastClickTime < 300) && (lastClickUsername === selectedUsername);\r\n\r\n            if (isDoubleClick) {\r\n              // Double-click: Replace entire input with username\r\n              this.messageInput.value = `${selectedUsername}, `;\r\n            } else {\r\n              // Single-click: Append username\r\n              const appendUsername = `${selectedUsername}, `;\r\n              if (!this.messageInput.value.includes(appendUsername)) {\r\n                this.messageInput.value += appendUsername;\r\n              }\r\n            }\r\n\r\n            // Update tracking variables\r\n            lastClickTime = now;\r\n            lastClickUsername = selectedUsername;\r\n          }\r\n          this.messageInput.focus();\r\n        }\r\n\r\n        // Original time element click behavior\r\n        const timeEl = event.target.closest('.time');\r\n        if (timeEl && this.panel.contains(timeEl)) {\r\n          const localTime = timeEl.textContent.trim();\r\n          const moscowTime = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.calibrateToMoscowTime)(localTime);\r\n          const today = new Intl.DateTimeFormat('en-CA').format(new Date());\r\n          const url = `https://klavogonki.ru/chatlogs/${today}.html#${moscowTime}`;\r\n          window.open(url, '_blank');\r\n        }\r\n      });\r\n      this.panel._delegatedClickAttached = true;\r\n    }\r\n  }\r\n\r\n  getChatHistory() {\r\n    return Array.from(this.messageMap.values());\r\n  }\r\n\r\n  refreshMessages(connectionStatus = false, connectionType = 'chat') {\r\n    const messageId = 'connection-status';\r\n    // Get language from localStorage, default to 'en'\r\n    const lang = localStorage.getItem('emojiPanelLanguage') === 'ru' ? 'ru' : 'en';\r\n    const messageText = _data_definitions_js__WEBPACK_IMPORTED_MODULE_7__.connectionMessages[connectionType][lang][connectionStatus ? 'online' : 'offline'];\r\n\r\n    // Remove the specific system connection message from our map and from our in‑memory rendered IDs.\r\n    this.messageMap.delete(messageId);\r\n    this.renderedMessageIds.delete(messageId);\r\n\r\n    // Create and add the new system message.\r\n    const systemMessage = {\r\n      id: messageId,\r\n      from: \"System\",\r\n      text: messageText,\r\n      isPrivate: false,\r\n      recipient: null,\r\n      isSystem: true,\r\n      pending: false,\r\n      timestamp: new Date().toLocaleTimeString('en-GB', { hour12: false })\r\n    };\r\n\r\n    this.messageMap.set(messageId, systemMessage);\r\n    this.updateConnectionStatusInUI(systemMessage);\r\n  }\r\n\r\n  updateConnectionStatusInUI(systemMessage) {\r\n    // Remove all pending icons.\r\n    this.panel.querySelectorAll('.pending-emoji').forEach(el => el.remove());\r\n\r\n    // Remove the existing system message element (if any).\r\n    const systemMessageElement = this.panel.querySelector(`[data-message-id=\"${systemMessage.id}\"]`);\r\n    if (systemMessageElement) {\r\n      systemMessageElement.remove();\r\n    }\r\n\r\n    // Re-render messages (using the updated DOM as the source of rendered IDs).\r\n    this.updatePanel();\r\n  }\r\n\r\n  removePrivateMessages() {\r\n    // Remove private messages from messageMap and renderedMessageIds\r\n    for (const [id, message] of this.messageMap.entries()) {\r\n      if (message.isPrivate) {\r\n        this.messageMap.delete(id);\r\n        this.renderedMessageIds.delete(id);\r\n      }\r\n    }\r\n\r\n    // Remove private message elements from DOM\r\n    const privateMessageElements = this.panel.querySelectorAll('.message.private');\r\n    privateMessageElements.forEach(element => element.remove());\r\n  }\r\n\r\n  removeIgnoredMessages() {\r\n    // Get all ignored users\r\n    const { forever, temporary } = (0,_components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_6__.getAllIgnoredUsers)();\r\n    const ignoredUsers = [...forever, ...temporary];\r\n\r\n    // Remove messages from ignored users\r\n    for (const [id, message] of this.messageMap.entries()) {\r\n      if (ignoredUsers.includes(message.from)) {\r\n        this.messageMap.delete(id);\r\n        this.renderedMessageIds.delete(id);\r\n      }\r\n    }\r\n\r\n    // Remove ignored user message elements from DOM\r\n    const ignoredMessageElements = Array.from(this.panel.querySelectorAll('.message'))\r\n      .filter(el => ignoredUsers.includes(el.querySelector('.username').textContent.trim()));\r\n    ignoredMessageElements.forEach(element => element.remove());\r\n\r\n    // Remove ignored users from the user list in the DOM based on the new HTML structure.\r\n    const userList = document.getElementById(\"user-list\");\r\n    if (userList) {\r\n      const userItems = userList.querySelectorAll(\".user-item\");\r\n      userItems.forEach(item => {\r\n        const itemUsername = item.querySelector(\".username\")?.textContent;\r\n        if (ignoredUsers.includes(itemUsername)) {\r\n          item.remove();\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/managers/messageManager.js?");

/***/ }),

/***/ "./src/managers/userManager.js":
/*!*************************************!*\
  !*** ./src/managers/userManager.js ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ UserManager)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_animations_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/animations.js */ \"./src/data/animations.js\");\n/* harmony import */ var _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers/chatUsernameColors.js */ \"./src/helpers/chatUsernameColors.js\");\n/* harmony import */ var _components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../components/ignoredUsersPanel.js */ \"./src/components/ignoredUsersPanel.js\");\n/* harmony import */ var _helpers_iframeProfileLoader_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../helpers/iframeProfileLoader.js */ \"./src/helpers/iframeProfileLoader.js\");\n/* harmony import */ var _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../helpers/privateMessagesHandler.js */ \"./src/helpers/privateMessagesHandler.js\");\n/* harmony import */ var _helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../helpers/tooltip.js */ \"./src/helpers/tooltip.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Utility function to generate a dynamic timestamp for the rand parameter\r\nconst generateRandomParam = () => `rand=${Date.now()}`;\r\n\r\nclass UserManager {\r\n  constructor(containerId = 'user-list') {\r\n    this.container = document.getElementById(containerId);\r\n    this.activeUsers = new Map();\r\n    this.isFirstLoad = true;\r\n    this.avatarCache = this.loadAvatarCache();\r\n    this.cacheDate = new Date().toDateString();\r\n    this.changes = false; // For tracking changes\r\n    this.pendingUserJIDs = new Set(); // For tracking new users\r\n    this.updatedUserJIDs = new Set(); // For tracking updated users\r\n    this.updateUITimeout = null; // For debouncing UI updates\r\n    this.raceStats = new Map(); // Track race stats per userId: { count, lastGameId }\r\n\r\n    // Role-based icons\r\n    this.roleIcons = {\r\n      'visitor': '🚫',\r\n      'participant': '',\r\n      'moderator': '⚔️️'\r\n    };\r\n\r\n    // Role priority for sorting\r\n    this.rolePriority = {\r\n      'moderator': 1,\r\n      'participant': 2,\r\n      'visitor': 3\r\n    };\r\n\r\n    // Attach event listeners\r\n    this.setupEventListeners();\r\n  }\r\n\r\n  loadAvatarCache() {\r\n    try {\r\n      const cacheData = localStorage.getItem('userAvatarCache');\r\n      if (cacheData) {\r\n        const cache = JSON.parse(cacheData);\r\n        if (cache.date === new Date().toDateString()) {\r\n          console.log(\"🗃️ Loaded avatar cache from localStorage\");\r\n          return cache.avatars || {};\r\n        } else {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n            en: \"Avatar cache expired, creating fresh cache.\",\r\n            ru: \"Кэш аватаров устарел, создаётся новый.\"\r\n          }, 'info');\r\n          return {};\r\n        }\r\n      }\r\n    } catch (error) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n        en: `Error loading avatar cache: ${error.message}`,\r\n        ru: `Ошибка загрузки кэша аватаров: ${error.message}`\r\n      }, 'error');\r\n    }\r\n    return {};\r\n  }\r\n\r\n  saveAvatarCache() {\r\n    try {\r\n      localStorage.setItem('userAvatarCache', JSON.stringify({\r\n        date: this.cacheDate,\r\n        avatars: this.avatarCache\r\n      }));\r\n    } catch (error) {\r\n      (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n        en: `Error saving avatar cache: ${error.message}`,\r\n        ru: `Ошибка сохранения кэша аватаров: ${error.message}`\r\n      }, 'error');\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Updates the avatar cache for a specific user.\r\n   * @param {string} userId - The unique identifier of the user.\r\n   * @param {boolean} hasAvatar - Flag indicating if the user has an avatar url.\r\n   * @param {string} avatarData - Either the avatar URL or emoji character, depending on hasAvatar.\r\n   * @param {string} username - The display name of the user.\r\n   * @returns {boolean} - Returns true if cache was updated, false if no update was needed.\r\n   */\r\n  updateAvatarCache(userId, hasAvatar, avatarData, username) {\r\n    const cached = this.avatarCache[userId];\r\n    // Only update if there's no previous cache or if hasAvatar status changed\r\n    if (!cached || cached.hasAvatar !== hasAvatar) {\r\n      this.avatarCache[userId] = {\r\n        hasAvatar: hasAvatar,\r\n        ...(hasAvatar ? { avatarUrl: avatarData } : { emoji: avatarData })\r\n      };\r\n\r\n      // Log the update\r\n      const icon = hasAvatar ? '🖼️' : '😊';\r\n      const type = hasAvatar ? 'avatar' : 'emoji';\r\n      console.log(`${icon} Set ${type} for [${username}] (${userId}):`, avatarData);\r\n\r\n      this.saveAvatarCache();\r\n      return true; // Indicate cache was updated\r\n    }\r\n    return false; // Indicate no update needed\r\n  }\r\n\r\n  // Handles private message input for a specific user\r\n  handlePrivateMode(username) {\r\n    const messageInput = document.getElementById('message-input');\r\n    messageInput.value = `/pm ${username} `;\r\n    (0,_helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_6__.handlePrivateMessageInput)(messageInput);\r\n    messageInput.focus();\r\n  }\r\n\r\n  // Sets up long press event for the user list container user elements\r\n  setupLongPressEvent(container, callback) {\r\n    let timer;\r\n    let longPressTriggered = false;\r\n\r\n    const handlePressStart = (event, eventType) => {\r\n      if (event.target.classList.contains('username')) {\r\n        longPressTriggered = false;\r\n\r\n        const startLongPress = () => {\r\n          longPressTriggered = true;\r\n          callback(event.target);\r\n        };\r\n\r\n        const clearLongPress = () => {\r\n          clearTimeout(timer);\r\n        };\r\n\r\n        timer = setTimeout(startLongPress, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.longPressDuration);\r\n\r\n        const endEvents = eventType === 'mouse'\r\n          ? ['mouseup', 'mouseleave']\r\n          : ['touchend', 'touchmove'];\r\n\r\n        endEvents.forEach(eventName => {\r\n          event.target.addEventListener(eventName, clearLongPress, { once: true });\r\n        });\r\n      }\r\n    };\r\n\r\n    container.addEventListener('mousedown', e => handlePressStart(e, 'mouse'));\r\n    container.addEventListener('touchstart', e => handlePressStart(e, 'touch'));\r\n\r\n    return () => longPressTriggered; // Return a boolean indicating if long press was triggered\r\n  }\r\n\r\n  // Sets up event listeners for user interactions\r\n  setupEventListeners() {\r\n    // Double-click on the user list container toggles user list mode\r\n    this.container.addEventListener('dblclick', (event) => {\r\n      // Only if double-clicked directly on the container (not on a user)\r\n      if (event.currentTarget === event.target) {\r\n        UserManager.toggleUserListMode(event.currentTarget);\r\n      }\r\n    });\r\n\r\n    const wasLongPress = this.setupLongPressEvent(this.container, (target) => {\r\n      const username = target.textContent.trim();\r\n      this.handlePrivateMode(username);\r\n    });\r\n\r\n    this.container.addEventListener('click', (event) => {\r\n      // Handle username clicks\r\n      if (event.target.classList.contains('username')) {\r\n        const dataUserId = event.target.getAttribute('data-user-id');\r\n        if (dataUserId) {\r\n          const username = event.target.textContent.trim();\r\n\r\n          if (event.ctrlKey) {\r\n            this.handlePrivateMode(username);\r\n          } else if (!wasLongPress()) {\r\n            // Normal click: Navigate to profile\r\n            const userIdValue = dataUserId.split('/')[1].split('#')[0];\r\n            const profileUrl = `https://klavogonki.ru/u/#/${userIdValue}/`;\r\n            (0,_helpers_iframeProfileLoader_js__WEBPACK_IMPORTED_MODULE_5__.loadProfileIntoIframe)(profileUrl);\r\n          }\r\n        }\r\n        return;\r\n      }\r\n\r\n      // Handle game indicator clicks\r\n      if (event.target.closest('.game-indicator')) {\r\n        const gameIndicator = event.target.closest('.game-indicator');\r\n        const gameId = gameIndicator.getAttribute('data-game-id');\r\n        if (gameId) {\r\n          event.stopPropagation();\r\n          window.location.href = `https://klavogonki.ru/g/?gmid=${gameId}`;\r\n        }\r\n        return;\r\n      }\r\n    });\r\n  }\r\n\r\n  async updatePresence(xmlResponse) {\r\n    const parser = new DOMParser();\r\n    const doc = parser.parseFromString(xmlResponse, \"text/xml\");\r\n    const presences = doc.getElementsByTagName(\"presence\");\r\n\r\n    if (xmlResponse.includes('<presence id=\"initialChatLoad\"')) {\r\n      console.log(\"🔄 Initial room join detected, requesting full roster\");\r\n      this.requestFullRoster();\r\n      return;\r\n    }\r\n\r\n    // Reset change tracking variables for this update cycle\r\n    this.changes = false;\r\n    this.updatedUserJIDs.clear();\r\n\r\n    for (let i = 0; i < presences.length; i++) {\r\n      const presence = presences[i];\r\n      const from = presence.getAttribute('from');\r\n      const type = presence.getAttribute('type');\r\n\r\n      // Skip if not from the conference room\r\n      if (!from || !from.includes('[email protected]/')) {\r\n        continue;\r\n      }\r\n\r\n      // Extract username from JID\r\n      const usernameFromJid = from.split('/').pop();\r\n      if (!usernameFromJid) continue;\r\n\r\n      // Skip Клавобот (unified check)\r\n      if (usernameFromJid.toLowerCase() === 'клавобот' || from.toLowerCase().includes('#клавобот')) {\r\n        continue;\r\n      }\r\n\r\n      // Handle user leaving\r\n      if (type === 'unavailable') {\r\n        if (this.activeUsers.has(from)) {\r\n          const departingUser = this.activeUsers.get(from);\r\n          const userId = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(from);\r\n          const cleanLogin = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(departingUser.login);\r\n\r\n          if (!this.isFirstLoad) {\r\n            // console.log(`🚪 User left: ${cleanLogin} ID: (${userId})`);\r\n          }\r\n          this.activeUsers.delete(from);\r\n          this.changes = true;\r\n        }\r\n        continue;\r\n      }\r\n\r\n      const existingUser = this.activeUsers.get(from) || {};\r\n      const userId = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(from);\r\n      const cachedAvatarInfo = this.avatarCache[userId];\r\n\r\n      // Initialize userData\r\n      let userData = {\r\n        jid: from,\r\n        login: usernameFromJid,\r\n        color: _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.FALLBACK_COLOR,\r\n        // Normalize the username before calling getColor:\r\n        usernameColor: _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_3__.usernameColors.getColor((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(usernameFromJid)),\r\n        role: 'participant',\r\n        gameId: null,\r\n        avatar: null\r\n      };\r\n\r\n      // Process x elements\r\n      const xElements = presence.getElementsByTagName(\"x\");\r\n      let foundAvatar = false;\r\n\r\n      Array.from(xElements).forEach(element => {\r\n        const xmlns = element.getAttribute(\"xmlns\");\r\n\r\n        if (xmlns === \"klavogonki:userdata\") {\r\n          const userNode = element.getElementsByTagName(\"user\")[0];\r\n\r\n          if (userNode) {\r\n            const loginElement = userNode.getElementsByTagName(\"login\")[0];\r\n            if (loginElement && loginElement.textContent) {\r\n              userData.login = loginElement.textContent;\r\n              userData.usernameColor = _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_3__.usernameColors.getColor((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(userData.login));\r\n            }\r\n\r\n            const avatarElement = userNode.getElementsByTagName(\"avatar\")[0];\r\n            if (avatarElement && avatarElement.textContent) {\r\n              userData.avatar = avatarElement.textContent;\r\n              foundAvatar = true;\r\n            }\r\n\r\n            const moderatorNode = userNode.getElementsByTagName(\"moderator\")[0];\r\n            if (moderatorNode && moderatorNode.textContent === '1') {\r\n              userData.role = 'moderator';\r\n            }\r\n          }\r\n\r\n          const gameIdElement = element.getElementsByTagName(\"game_id\")[0];\r\n          if (gameIdElement && gameIdElement.textContent) {\r\n            userData.gameId = gameIdElement.textContent;\r\n          }\r\n        }\r\n\r\n        if (xmlns === \"http://jabber.org/protocol/muc#user\") {\r\n          const itemNode = element.getElementsByTagName(\"item\")[0];\r\n          if (itemNode) {\r\n            const role = itemNode.getAttribute(\"role\");\r\n            if (role && userData.role !== 'moderator') {\r\n              userData.role = role;\r\n            }\r\n          }\r\n        }\r\n      });\r\n\r\n      // If no avatar in update but exists in user data, keep it\r\n      if (!foundAvatar && existingUser && existingUser.avatar) {\r\n        userData.avatar = existingUser.avatar;\r\n      }\r\n\r\n      // Handle avatar (use cache or set default)\r\n      if (!userData.avatar && cachedAvatarInfo) {\r\n        if (cachedAvatarInfo.hasAvatar) {\r\n          userData.avatar = cachedAvatarInfo.avatarUrl;\r\n        }\r\n      }\r\n\r\n      const cleanLogin = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(userData.login);\r\n\r\n      // Update race stats\r\n      let stats = this.raceStats.get(userId);\r\n      if (!stats) {\r\n        stats = { count: 0, lastGameId: null };\r\n        this.raceStats.set(userId, stats);\r\n      }\r\n      if (userData.gameId) {\r\n        if (stats.lastGameId !== userData.gameId) {\r\n          stats.count += 1;\r\n          stats.lastGameId = userData.gameId;\r\n        }\r\n      } else {\r\n        stats.count = 0;\r\n        stats.lastGameId = null;\r\n      }\r\n\r\n      // Determine if user is new or updated\r\n      if (!this.activeUsers.has(from)) {\r\n        if (!this.isFirstLoad) {\r\n          // console.log(`👤 User joined: ${cleanLogin} ID: (${userId})`);\r\n        }\r\n        this.activeUsers.set(from, userData);\r\n        this.changes = true;\r\n        this.pendingUserJIDs.add(from);\r\n      } else if (JSON.stringify(existingUser) !== JSON.stringify(userData)) {\r\n        this.activeUsers.set(from, userData);\r\n        this.changes = true;\r\n        this.updatedUserJIDs.add(from);\r\n      }\r\n    }\r\n\r\n    if (this.changes) {\r\n      if (!this.isFirstLoad) {\r\n        // Debounce UI updates to avoid excessive DOM manipulation\r\n        if (this.updateUITimeout) {\r\n          clearTimeout(this.updateUITimeout);\r\n        }\r\n        this.updateUITimeout = setTimeout(() => {\r\n          this.updateUI();\r\n          this.updateUITimeout = null; // Reset timeout reference\r\n          this.pendingUserJIDs.clear(); // Clear after UI update\r\n        }, _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.pendingUserDelay); // Use pendingUserDelay for UI update debounce\r\n      } else {\r\n        // Initial load, update UI immediately\r\n        this.updateUI();\r\n        this.pendingUserJIDs.clear(); // Clear after UI update\r\n      }\r\n    }\r\n  }\r\n\r\n  updateRoleTooltip(roleElement, role) {\r\n    if (role === 'moderator') {\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_7__.createCustomTooltip)(roleElement, {\r\n        en: 'Chat Moderator',\r\n        ru: 'Модератор чата'\r\n      });\r\n    } else if (role === 'visitor') {\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_7__.createCustomTooltip)(roleElement, {\r\n        en: 'Banned User',\r\n        ru: 'Забаненный пользователь'\r\n      });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Cycles the user list mode between\r\n   * 'normal', 'race', and 'chat',\r\n   * updates localStorage, and refreshes the UI.\r\n   */\r\n  static toggleUserListMode() {\r\n    const modes = ['normal', 'race', 'chat'];\r\n    const userListModeMessages = {\r\n      normal: {\r\n        en: 'User list mode set to normal',\r\n        ru: 'Список пользователей: обычный режим'\r\n      },\r\n      race: {\r\n        en: 'User list mode set to race',\r\n        ru: 'Список пользователей: заезды сверху'\r\n      },\r\n      chat: {\r\n        en: 'User list mode set to general chat',\r\n        ru: 'Список пользователей: общий чат сверху'\r\n      }\r\n    };\r\n    const current = localStorage.getItem('userlistMode') || 'normal';\r\n    const idx = modes.indexOf(current);\r\n    const next = modes[(idx + 1) % modes.length];\r\n    localStorage.setItem('userlistMode', next);\r\n    if (window.userManager) {\r\n      window.userManager.updateUI();\r\n    }\r\n    // Log the change\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)(userListModeMessages[next], 'info');\r\n    return next;\r\n  }\r\n\r\n  sortByRoleAndName(users) {\r\n    return users.sort((a, b) => {\r\n      const priorityDiff = this.rolePriority[a.role] - this.rolePriority[b.role];\r\n      return priorityDiff !== 0 ? priorityDiff : (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(a.login).localeCompare((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(b.login));\r\n    });\r\n  }\r\n\r\n  sortByRaceCount(users) {\r\n    return users.sort((a, b) => {\r\n      const ac = this.raceStats.get((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(a.jid))?.count || 0;\r\n      const bc = this.raceStats.get((0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(b.jid))?.count || 0;\r\n      return bc - ac;\r\n    });\r\n  }\r\n\r\n  updateUI() {\r\n    // Use centralized helper for ignored users\r\n    const { forever, temporary } = (0,_components_ignoredUsersPanel_js__WEBPACK_IMPORTED_MODULE_4__.getAllIgnoredUsers)();\r\n    const ignoredUsers = [...forever, ...temporary];\r\n\r\n    // Build map of existing DOM elements\r\n    const existingElements = new Map();\r\n    this.container.querySelectorAll('.user-item').forEach(el => {\r\n      existingElements.set(el.getAttribute('data-jid'), el);\r\n    });\r\n\r\n    // --- Userlist mode logic ---\r\n    const userlistMode = localStorage.getItem('userlistMode') || 'normal';\r\n    let sortedUsers = Array.from(this.activeUsers.values()).filter(user => {\r\n      const cleanLogin = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(user.login);\r\n\r\n      // Ignore users in the ignored list to avoid displaying them in the user list\r\n      return !ignoredUsers.includes(cleanLogin);\r\n    });\r\n\r\n    // Separate users into those in a game and those not in a game\r\n    const usersInRace = sortedUsers.filter(u => u.gameId);\r\n    const usersNotInRace = sortedUsers.filter(u => !u.gameId);\r\n\r\n    // Sort users based on the mode\r\n    if (userlistMode === 'race') {\r\n      sortedUsers = [\r\n        ...this.sortByRaceCount(usersInRace),\r\n        ...this.sortByRoleAndName(usersNotInRace)\r\n      ];\r\n    } else if (userlistMode === 'chat') {\r\n      sortedUsers = [\r\n        ...this.sortByRoleAndName(usersNotInRace),\r\n        ...this.sortByRaceCount(usersInRace)\r\n      ];\r\n    } else {\r\n      sortedUsers = this.sortByRoleAndName(sortedUsers);\r\n    }\r\n\r\n    // Calculate the index where the \"separation\" class should be added\r\n    let separationIndex = -1;\r\n    if (userlistMode === 'race' && usersInRace.length > 0) {\r\n      // In \"race\" mode, add \"separation\" to the last user in usersInRace\r\n      separationIndex = usersInRace.length - 1;\r\n    } else if (userlistMode === 'chat' && usersNotInRace.length > 0) {\r\n      // In \"chat\" mode, add \"separation\" to the last user in usersNotInRace\r\n      separationIndex = usersNotInRace.length - 1;\r\n    }\r\n    // For \"normal\" mode, separationIndex remains -1, so no class is added\r\n\r\n    // Build the updated user list\r\n    const fragment = document.createDocumentFragment();\r\n\r\n    sortedUsers.forEach((user, index) => {\r\n      let userElement = existingElements.get(user.jid);\r\n      const userId = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(user.jid);\r\n      const cleanLogin = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUsername)(user.login);\r\n\r\n      // Create new user element if it doesn’t exist\r\n      if (!userElement) {\r\n        userElement = document.createElement('div');\r\n        userElement.classList.add('user-item');\r\n        userElement.setAttribute('data-jid', user.jid);\r\n        const roleIcon = this.roleIcons[user.role];\r\n\r\n        const avatarContainer = document.createElement('span');\r\n        avatarContainer.className = 'avatar-container';\r\n        this.setUserAvatar(avatarContainer, user, userId, cleanLogin);\r\n\r\n        const userInfo = document.createElement('div');\r\n        userInfo.className = 'user-info';\r\n        userInfo.innerHTML = `\r\n        <span class=\"username\" style=\"color: ${user.usernameColor}\" data-user-id=\"${user.jid}\">${cleanLogin}</span>\r\n        <span class=\"role ${user.role}\">${roleIcon}</span>\r\n      `;\r\n\r\n        const roleEl = userInfo.querySelector('.role');\r\n        this.updateRoleTooltip(roleEl, user.role);\r\n\r\n        userElement.appendChild(avatarContainer);\r\n        userElement.appendChild(userInfo);\r\n      } else {\r\n        // Update existing element if necessary\r\n        if (!userElement.querySelector('.avatar-container')) {\r\n          const avatarContainer = document.createElement('span');\r\n          avatarContainer.className = 'avatar-container';\r\n          this.setUserAvatar(avatarContainer, user, userId, cleanLogin);\r\n          userElement.insertBefore(avatarContainer, userElement.firstChild);\r\n        }\r\n\r\n        existingElements.delete(user.jid);\r\n\r\n        const roleElement = userElement.querySelector('.role');\r\n        const newRoleIcon = this.roleIcons[user.role];\r\n        if (roleElement && roleElement.textContent !== newRoleIcon) {\r\n          roleElement.textContent = newRoleIcon;\r\n          if (!roleElement.classList.contains(user.role)) {\r\n            roleElement.className = `role ${user.role}`;\r\n            this.updateRoleTooltip(roleElement, user.role);\r\n          }\r\n        }\r\n\r\n        const usernameElement = userElement.querySelector('.username');\r\n        if (usernameElement && usernameElement.style.color !== user.usernameColor) {\r\n          usernameElement.style.color = user.usernameColor;\r\n        }\r\n      }\r\n\r\n      // Update game indicator\r\n      this.updateGameIndicator(userElement, user);\r\n\r\n      // Add or remove the \"separation\" class based on the index\r\n      userElement.classList.toggle('separation', index === separationIndex);\r\n\r\n      // Append the user element to the fragment\r\n      fragment.appendChild(userElement);\r\n    });\r\n\r\n    // Clear the container and append the new fragment\r\n    this.container.innerHTML = '';\r\n    this.container.appendChild(fragment);\r\n\r\n    // Remove elements for users no longer active\r\n    existingElements.forEach((el) => {\r\n      if (el && el.parentNode) {\r\n        el.remove();\r\n      }\r\n    });\r\n\r\n    // Apply shake effect for new users\r\n    if (!this.isFirstLoad) {\r\n      this.pendingUserJIDs.forEach(jid => {\r\n        const userElement = this.container.querySelector(`.user-item[data-jid=\"${jid}\"]`);\r\n        if (userElement && userElement.parentNode) {\r\n          (0,_data_animations_js__WEBPACK_IMPORTED_MODULE_2__.addShakeEffect)(userElement);\r\n        }\r\n      });\r\n    }\r\n\r\n    if (this.isFirstLoad) {\r\n      this.isFirstLoad = false;\r\n    }\r\n  }\r\n\r\n  setUserAvatar(avatarContainer, user, userId, cleanLogin) {\r\n    const cachedAvatarInfo = this.avatarCache[userId];\r\n\r\n    // Display avatar based on available information\r\n    if (user.avatar) {\r\n      const avatarUrl = cachedAvatarInfo?.avatarUrl || `${_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.BASE_URL}/storage/avatars/${userId}_big.png?${generateRandomParam()}`;\r\n      const avatarImg = document.createElement('img');\r\n      avatarImg.className = 'user-avatar image-avatar';\r\n      avatarImg.src = avatarUrl;\r\n      avatarImg.alt = `${cleanLogin}'s avatar`;\r\n\r\n      // Handle error by replacing with emoji\r\n      avatarImg.addEventListener('error', () => {\r\n        const fallbackEmoji = cachedAvatarInfo?.emoji || (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.getRandomEmojiAvatar)();\r\n        avatarContainer.innerHTML = '';\r\n        const fallbackSpan = document.createElement('span');\r\n        fallbackSpan.className = 'user-avatar svg-avatar';\r\n        fallbackSpan.textContent = fallbackEmoji;\r\n        avatarContainer.appendChild(fallbackSpan);\r\n\r\n        // Update cache using helper\r\n        this.updateAvatarCache(userId, false, fallbackEmoji, cleanLogin);\r\n      });\r\n\r\n      // On successful load, update cache only if not already set\r\n      avatarImg.addEventListener('load', () => {\r\n        this.updateAvatarCache(userId, true, avatarUrl, cleanLogin);\r\n      });\r\n\r\n      avatarContainer.appendChild(avatarImg);\r\n\r\n    } else if (cachedAvatarInfo) {\r\n      // Use cached information\r\n      if (cachedAvatarInfo.hasAvatar) {\r\n        const avatarImg = document.createElement('img');\r\n        avatarImg.className = 'user-avatar image-avatar';\r\n        avatarImg.src = cachedAvatarInfo.avatarUrl;\r\n        avatarImg.alt = `${cleanLogin}'s avatar`;\r\n\r\n        // Handle error if cache is incorrect\r\n        avatarImg.addEventListener('error', () => {\r\n          const fallbackEmoji = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.getRandomEmojiAvatar)();\r\n          avatarContainer.innerHTML = '';\r\n          const fallbackSpan = document.createElement('span');\r\n          fallbackSpan.className = 'user-avatar svg-avatar';\r\n          fallbackSpan.textContent = fallbackEmoji;\r\n          avatarContainer.appendChild(fallbackSpan);\r\n\r\n          // Update cache using helper\r\n          this.updateAvatarCache(userId, false, fallbackEmoji, cleanLogin);\r\n        });\r\n\r\n        avatarContainer.appendChild(avatarImg);\r\n      } else {\r\n        // Use cached emoji\r\n        const fallbackSpan = document.createElement('span');\r\n        fallbackSpan.className = 'user-avatar svg-avatar';\r\n        fallbackSpan.textContent = cachedAvatarInfo.emoji;\r\n        avatarContainer.appendChild(fallbackSpan);\r\n      }\r\n    } else {\r\n      // No cached info - try to fetch avatar\r\n      const avatarUrl = `${_data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.BASE_URL}/storage/avatars/${userId}_big.png?${generateRandomParam()}`;\r\n      const avatarImg = document.createElement('img');\r\n      avatarImg.className = 'user-avatar image-avatar';\r\n      avatarImg.src = avatarUrl;\r\n      avatarImg.alt = `${cleanLogin}'s avatar`;\r\n\r\n      // Handle error\r\n      avatarImg.addEventListener('error', () => {\r\n        const fallbackEmoji = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.getRandomEmojiAvatar)();\r\n        avatarContainer.innerHTML = '';\r\n        const fallbackSpan = document.createElement('span');\r\n        fallbackSpan.className = 'user-avatar svg-avatar';\r\n        fallbackSpan.textContent = fallbackEmoji;\r\n        avatarContainer.appendChild(fallbackSpan);\r\n\r\n        // Update cache using helper\r\n        this.updateAvatarCache(userId, false, fallbackEmoji, cleanLogin);\r\n      });\r\n\r\n      // On successful load, cache positive result\r\n      avatarImg.addEventListener('load', () => {\r\n        this.updateAvatarCache(userId, true, avatarUrl, cleanLogin);\r\n      });\r\n\r\n      avatarContainer.appendChild(avatarImg);\r\n    }\r\n  }\r\n\r\n  updateGameIndicator(userElement, user) {\r\n    const userInfoContainer = userElement.querySelector('.user-info');\r\n    let gameIndicator = userElement.querySelector('.game-indicator');\r\n    const userId = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.extractUserId)(user.jid || user.login || '');\r\n\r\n    // Get current stats\r\n    const stats = this.raceStats.get(userId) || { count: 0, lastGameId: null };\r\n\r\n    function setAttributes(indicator, gameId, raceCount) {\r\n      indicator.setAttribute('data-game-id', gameId);\r\n      (0,_helpers_tooltip_js__WEBPACK_IMPORTED_MODULE_7__.createCustomTooltip)(indicator, {\r\n        en: `[Game ID] ${gameId} [Races] ${raceCount}`,\r\n        ru: `[Игра] ${gameId} [Заездов] ${raceCount}`\r\n      });\r\n    }\r\n\r\n    if (user.gameId) { // Only show indicator if gameId received by presence \r\n      if (!gameIndicator) { // Create if it doesn't exist\r\n        gameIndicator = document.createElement('span');\r\n        gameIndicator.className = 'game-indicator';\r\n        const trafficIcon = document.createElement('span');\r\n        trafficIcon.className = 'traffic-icon';\r\n        trafficIcon.textContent = '🚦';\r\n        const gamesCount = document.createElement('span');\r\n        gamesCount.className = 'games-count';\r\n        gamesCount.textContent = stats.count;\r\n        gameIndicator.append(trafficIcon, gamesCount);\r\n        userInfoContainer.appendChild(gameIndicator);\r\n      } else { // Update existing indicator\r\n        const gamesCountSpan = gameIndicator.querySelector('.games-count');\r\n        if (gamesCountSpan) {\r\n          gamesCountSpan.textContent = stats.count;\r\n        }\r\n      }\r\n      setAttributes(gameIndicator, user.gameId, stats.count);\r\n    } else if (gameIndicator) { // Remove indicator if no gameId received by presence\r\n      gameIndicator.remove();\r\n    }\r\n  }\r\n\r\n  async requestFullRoster() {\r\n    console.log(\"📑 Would request full roster here (using existing data for now)\");\r\n    this.updateUI();\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/managers/userManager.js?");

/***/ }),

/***/ "./src/styles/animationKeyframes.scss":
/*!********************************************!*\
  !*** ./src/styles/animationKeyframes.scss ***!
  \********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./animationKeyframes.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/animationKeyframes.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_animationKeyframes_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/animationKeyframes.scss?");

/***/ }),

/***/ "./src/styles/chatUsernameColors.scss":
/*!********************************************!*\
  !*** ./src/styles/chatUsernameColors.scss ***!
  \********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./chatUsernameColors.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/chatUsernameColors.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_chatUsernameColors_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/chatUsernameColors.scss?");

/***/ }),

/***/ "./src/styles/emojiPanel.scss":
/*!************************************!*\
  !*** ./src/styles/emojiPanel.scss ***!
  \************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./emojiPanel.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/emojiPanel.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_emojiPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/emojiPanel.scss?");

/***/ }),

/***/ "./src/styles/eventsPanel.scss":
/*!*************************************!*\
  !*** ./src/styles/eventsPanel.scss ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./eventsPanel.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/eventsPanel.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_eventsPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/eventsPanel.scss?");

/***/ }),

/***/ "./src/styles/helpPanel.scss":
/*!***********************************!*\
  !*** ./src/styles/helpPanel.scss ***!
  \***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_helpPanel_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./helpPanel.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/helpPanel.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_helpPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_helpPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_helpPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_helpPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/helpPanel.scss?");

/***/ }),

/***/ "./src/styles/ignoredUsers.scss":
/*!**************************************!*\
  !*** ./src/styles/ignoredUsers.scss ***!
  \**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./ignoredUsers.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/ignoredUsers.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_ignoredUsers_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/ignoredUsers.scss?");

/***/ }),

/***/ "./src/styles/style.scss":
/*!*******************************!*\
  !*** ./src/styles/style.scss ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./style.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/style.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_style_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_style_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_style_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_style_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/style.scss?");

/***/ }),

/***/ "./src/styles/themesPanel.scss":
/*!*************************************!*\
  !*** ./src/styles/themesPanel.scss ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_themesPanel_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./themesPanel.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/themesPanel.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_themesPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_themesPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_themesPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_themesPanel_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/themesPanel.scss?");

/***/ }),

/***/ "./src/styles/updateCheck.scss":
/*!*************************************!*\
  !*** ./src/styles/updateCheck.scss ***!
  \*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_updateCheck_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./updateCheck.scss */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/updateCheck.scss\");\n\n      \n      \n      \n      \n      \n      \n      \n      \n      \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n      options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n    \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_updateCheck_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n       /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_updateCheck_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_updateCheck_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_sass_loader_dist_cjs_js_updateCheck_scss__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/styles/updateCheck.scss?");

/***/ }),

/***/ "./src/xmpp/xmppClient.js":
/*!********************************!*\
  !*** ./src/xmpp/xmppClient.js ***!
  \********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   createXMPPClient: () => (/* binding */ createXMPPClient)\n/* harmony export */ });\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers/privateMessagesHandler.js */ \"./src/helpers/privateMessagesHandler.js\");\n/* harmony import */ var _helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers/chatUsernameColors.js */ \"./src/helpers/chatUsernameColors.js\");\n\r\n\r\n\r\n\r\n\r\n\r\nfunction createXMPPClient(xmppConnection, userManager, messageManager, username) {\r\n  // Compact wrapper functions.\r\n  const safeUpdatePresence = (xmlResponse) =>\r\n    xmlResponse && userManager.updatePresence(xmlResponse);\r\n\r\n  const safeProcessMessages = (xmlResponse) =>\r\n    xmlResponse && messageManager.processMessages(xmlResponse);\r\n\r\n  function getUserInfo() {\r\n    const cleanedUsername = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.extractUsername)(username);\r\n    const baseAvatarPath = `/storage/avatars/${username.split('#')[0]}.png`;\r\n    const timestamp = Math.floor(Date.now() / 1000);\r\n\r\n    // Get color from localStorage or use fallback\r\n    const storedColor = localStorage.getItem('chatUsernameColor');\r\n    const chatUsernameColor = (0,_helpers_chatUsernameColors_js__WEBPACK_IMPORTED_MODULE_3__.optimizeColor)(storedColor) || _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.FALLBACK_COLOR;\r\n\r\n    return {\r\n      cleanedUsername, chatUsernameColor, baseAvatarPath, timestamp\r\n    };\r\n  }\r\n\r\n  let userInfo = getUserInfo(); // Initialize user info\r\n\r\n  const xmppClient = {\r\n    userManager,\r\n    messageManager,\r\n    isHttpBindingActive: false,\r\n    isReconnecting: false,\r\n    isConnected: false,\r\n    messageQueue: new Map(),\r\n    lastSentMessage: null,\r\n    isReloading: false,\r\n    shouldCheckConnection: false,\r\n    checkConnectionTimeoutId: null,\r\n\r\n    clearCheckConnectionTimeout() {\r\n      if (this.checkConnectionTimeoutId) {\r\n        clearTimeout(this.checkConnectionTimeoutId);\r\n        this.checkConnectionTimeoutId = null;\r\n      }\r\n    },\r\n\r\n    // Helper: Create the XML stanza for a message.\r\n    _createMessageStanza(text, messageId, isPrivate, fullJid) {\r\n\r\n      const info = userInfo;\r\n\r\n      // Create the user data block\r\n      const userDataBlock = `\r\n      <x xmlns='klavogonki:userdata'>\r\n        <user>\r\n          <login>${info.cleanedUsername}</login>\r\n          <avatar>${info.baseAvatarPath}?updated=${info.timestamp}</avatar>\r\n          <background>${info.chatUsernameColor}</background>\r\n        </user>\r\n      </x>\r\n      `;\r\n\r\n      // Determine the destination and message type\r\n      const destination = isPrivate && fullJid\r\n        ? fullJid\r\n        : '[email protected]';\r\n      const messageType = isPrivate ? 'chat' : 'groupchat';\r\n\r\n      // Create the full message stanza with readable formatting\r\n      const formattedXML = `\r\n      <body rid='${xmppConnection.nextRid()}' sid='${xmppConnection.sid}' xmlns='http://jabber.org/protocol/httpbind'>\r\n        <message \r\n          from='${username}@jabber.klavogonki.ru/web' \r\n          to='${destination}' \r\n          type='${messageType}' \r\n          id='${messageId}' \r\n          xmlns='jabber:client'>\r\n          <body>${text}</body>\r\n          ${userDataBlock}\r\n        </message>\r\n      </body>\r\n      `;\r\n\r\n      // Return the compacted version for actual use\r\n      return (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.compactXML)(formattedXML);\r\n    },\r\n\r\n    // Process queued messages sequentially.\r\n    async processQueue() {\r\n      if (!this.isConnected || this.isReconnecting) return;\r\n\r\n      for (const [messageId, msg] of this.messageQueue) {\r\n        const messageStanza = this._createMessageStanza(msg.text, msg.id, msg.isPrivate, msg.fullJid);\r\n        try {\r\n          await xmppConnection.sendRequestWithRetry(messageStanza);\r\n          // On success, remove the message from the queue.\r\n          this.messageQueue.delete(messageId);\r\n          // Optionally, update the UI to remove the pending flag.\r\n          messageManager.updatePendingStatus(msg.id, false);\r\n          // Optionally, process messages if needed\r\n          // safeProcessMessages(null);\r\n        } catch (error) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: `Failed to send queued message (${msg.id}): ${error.message}`,\r\n            ru: `Не удалось отправить сообщение из очереди (${msg.id}): ${error.message}`\r\n          }, 'error');\r\n          // Stop processing; the message remains in the queue for later retry.\r\n          break;\r\n        }\r\n      }\r\n    },\r\n\r\n    async connect() {\r\n      try {\r\n        // Stop any existing HTTP binding\r\n        this.stopHttpBinding();\r\n\r\n        let retries = 5;\r\n        while (retries > 0 && !this.isConnected) {\r\n          try {\r\n            const session = await xmppConnection.connect();\r\n            console.log('💬 Step 8: Joining chat room...');\r\n\r\n            const info = userInfo;\r\n\r\n            const joinPayload = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.compactXML)(`\r\n            <body rid='${xmppConnection.nextRid()}' xmlns='http://jabber.org/protocol/httpbind' sid='${session.sid}'>\r\n              <presence from='${username}@jabber.klavogonki.ru/web' to='[email protected]/${username}' xmlns='jabber:client'>\r\n                <x xmlns='http://jabber.org/protocol/muc'/>\r\n                <x xmlns='klavogonki:userdata'>\r\n                  <user>\r\n                    <login>${info.cleanedUsername}</login>\r\n                    <avatar>${info.baseAvatarPath}?updated=${info.timestamp}</avatar>\r\n                    <background>${info.chatUsernameColor}</background>\r\n                  </user>\r\n                </x>\r\n              </presence>\r\n            </body>\r\n            `);\r\n\r\n            const joinResponse = await xmppConnection.sendRequestWithRetry(joinPayload);\r\n\r\n            console.log('📥 Join response:', joinResponse);\r\n\r\n            safeUpdatePresence(joinResponse);\r\n            safeProcessMessages(joinResponse);\r\n\r\n            const infoPayload = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.compactXML)(`\r\n              <body \r\n                rid='${xmppConnection.nextRid()}' \r\n                sid='${session.sid}' \r\n                xmlns='http://jabber.org/protocol/httpbind'>\r\n                <iq \r\n                  type='get' \r\n                  id='info_${Math.random().toString(36).substring(2, 10)}' \r\n                  xmlns='jabber:client' \r\n                  to='[email protected]'>\r\n                  <query xmlns='http://jabber.org/protocol/disco#info'/>\r\n                </iq>\r\n              </body>\r\n            `);\r\n\r\n            await xmppConnection.sendRequestWithRetry(infoPayload);\r\n            console.log('🚀 Step 10: Connected!');\r\n\r\n            this.isConnected = true;\r\n            this.shouldCheckConnection = true;\r\n            if (this.isReconnecting) {\r\n              (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n                en: \"Chat connected successfully.\",\r\n                ru: \"Чат успешно подключён.\"\r\n              }, 'success');\r\n              messageManager.refreshMessages(true);\r\n              this.isReconnecting = false;\r\n            }\r\n\r\n            this.startHttpBinding(); // Start HTTP binding\r\n            this.processQueue(); // Process the message queue\r\n            this.checkConnection(); // Start the periodic connection check\r\n            break; // Exit the retry loop on success\r\n          } catch (error) {\r\n            (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n              en: `XMPP Client: Connection error: ${error.message}`,\r\n              ru: `XMPP клиент: ошибка соединения: ${error.message}`\r\n            }, 'error');\r\n            retries--;\r\n            if (retries === 0) {\r\n              (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n                en: `Scheduling reconnection attempt in ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay / 1000} seconds...`,\r\n                ru: `Переподключение через ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay / 1000} секунд...`\r\n              }, 'warning');\r\n              this.isReconnecting = true;\r\n              setTimeout(() => this.connect(), _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay);\r\n            } else {\r\n              (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n                en: `Retrying connection... (${retries} attempts left)`,\r\n                ru: `Повторное подключение... (осталось попыток: ${retries})`\r\n              }, 'warning');\r\n              await new Promise(resolve => setTimeout(resolve, _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay));\r\n            }\r\n          }\r\n        }\r\n      } catch (error) {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: `XMPP Client: Final connection error: ${error.message}`,\r\n          ru: `XMPP клиент: окончательная ошибка соединения: ${error.message}`\r\n        }, 'error');\r\n        this.isConnected = false;\r\n        if (!this.isReconnecting) {\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n            en: `Scheduling reconnection attempt in ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay / 1000} seconds...`,\r\n            ru: `Переподключение через ${_data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay / 1000} секунд...`\r\n          }, 'warning');\r\n          this.isReconnecting = true;\r\n          setTimeout(() => this.connect(), _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.reconnectionDelay);\r\n        }\r\n      }\r\n    },\r\n\r\n    // Start HTTP binding for XMPP server updates\r\n    async startHttpBinding() {\r\n      if (this.isHttpBindingActive) return;\r\n      this.isHttpBindingActive = true;\r\n      console.log('💬 Starting XMPP HTTP binding...');\r\n\r\n      const pollRequest = async () => {\r\n        if (!this.isConnected || this.isReconnecting || !this.isHttpBindingActive) {\r\n          this.isHttpBindingActive = false;\r\n          return;\r\n        }\r\n\r\n        try {\r\n          // Define the bind payload\r\n          const bindPayload = `<body rid='${xmppConnection.nextRid()}' sid='${xmppConnection.sid}' xmlns='http://jabber.org/protocol/httpbind'/>`;\r\n\r\n          // Send a request that the server can respond to when it has updates\r\n          const xmlResponse = await xmppConnection.sendRequestWithRetry(bindPayload);\r\n\r\n          // Process any updates in the response\r\n          safeUpdatePresence(xmlResponse);\r\n          safeProcessMessages(xmlResponse);\r\n\r\n          // Immediately send another request to maintain the HTTP binding connection\r\n          if (this.isHttpBindingActive) {\r\n            pollRequest();\r\n          }\r\n        } catch (error) {\r\n          if (error.message.includes('404') && !this.isReconnecting) {\r\n            (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n              en: \"Chat connection lost.\",\r\n              ru: \"Соединение с чатом потеряно.\"\r\n            }, 'warning');\r\n            messageManager.refreshMessages(false);\r\n            this.shouldCheckConnection = false;\r\n            this.clearCheckConnectionTimeout();\r\n            this.isReconnecting = true;\r\n            this.isConnected = false;\r\n            this.isHttpBindingActive = false;\r\n            this.connect();\r\n          }\r\n        }\r\n      };\r\n\r\n      // Start the initial poll\r\n      pollRequest();\r\n    },\r\n\r\n    stopHttpBinding() {\r\n      if (this.isHttpBindingActive) {\r\n        this.isHttpBindingActive = false;\r\n      }\r\n    },\r\n\r\n    sendMessage(text) {\r\n      const messageId = `msg_${Date.now()}`;\r\n      let isPrivate = false;\r\n      let fullJid = null;\r\n      let recipient = null;\r\n\r\n      // Only mark as pending if we're disconnected\r\n      const isPending = !this.isConnected || this.isReconnecting;\r\n\r\n      if (_helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_2__.privateMessageState.isPrivateMode && _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_2__.privateMessageState.fullJid) {\r\n        isPrivate = true;\r\n        fullJid = _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_2__.privateMessageState.fullJid;\r\n        recipient = _helpers_privateMessagesHandler_js__WEBPACK_IMPORTED_MODULE_2__.privateMessageState.targetUsername;\r\n        messageManager.addSentMessage(text, {\r\n          isPrivate: true,\r\n          recipient,\r\n          pending: isPending\r\n        });\r\n      } else {\r\n        messageManager.addSentMessage(text, { pending: isPending });\r\n      }\r\n\r\n      const now = Date.now();\r\n\r\n      // Check against the last sent message.\r\n      if (this.lastSentMessage && this.lastSentMessage.text === text && (now - this.lastSentMessage.timestamp) < _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.deduplicationDelay) {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: `Prevented duplicate message: ${text}`,\r\n          ru: `Предотвращено дублирование сообщения: ${text}`\r\n        }, 'warning');\r\n        return;\r\n      }\r\n\r\n      // Prevent duplicate messages in the queue\r\n      if (this.messageQueue.has(messageId)) {\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n          en: `Message already queued for sending: ${messageId}`,\r\n          ru: `Сообщение уже в очереди на отправку: ${messageId}`\r\n        }, 'warning');\r\n        return;\r\n      }\r\n      this.lastSentMessage = { text, timestamp: now };\r\n\r\n      // Prepare the message object for queueing\r\n      const msgObj = {\r\n        text,\r\n        id: messageId,\r\n        isPrivate,\r\n        fullJid,\r\n        recipient,\r\n        pending: isPending,\r\n        enqueueTime: now\r\n      };\r\n\r\n      // If connected, try to send immediately, else queue\r\n      if (this.isConnected && !this.isReconnecting) {\r\n        const messageStanza = this._createMessageStanza(text, messageId, isPrivate, fullJid);\r\n        xmppConnection.sendRequestWithRetry(messageStanza)\r\n          .then(() => {\r\n            // Success: update UI, do not queue\r\n            messageManager.updatePendingStatus(messageId, false);\r\n          })\r\n          .catch((error) => {\r\n            // Failure: queue for retry\r\n            (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n              en: `Failed to send message (${messageId}): ${error.message}`,\r\n              ru: `Не удалось отправить сообщение (${messageId}): ${error.message}`\r\n            }, 'error');\r\n            this.messageQueue.set(messageId, msgObj);\r\n            messageManager.updatePendingStatus(messageId, true);\r\n          });\r\n      } else {\r\n        // Not connected: always queue\r\n        this.messageQueue.set(messageId, msgObj);\r\n        messageManager.updatePendingStatus(messageId, true);\r\n      }\r\n    },\r\n\r\n    async checkConnection() {\r\n      if (!this.shouldCheckConnection) return; // Prevent multiple checks\r\n      try {\r\n        const pingPayload = `<body rid='${xmppConnection.nextRid()}' sid='${xmppConnection.sid}' xmlns='http://jabber.org/protocol/httpbind'/>`;\r\n        await xmppConnection.sendRequestWithRetry(pingPayload);\r\n      } catch (error) {\r\n        if (!this.shouldCheckConnection) return; // Don't log or reconnect if page is unloading\r\n        (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({ en: \"Ping failed.\", ru: \"Пинг не удался.\" }, 'warning');\r\n        // Prevent multiple reconnections\r\n        if (!this.isReconnecting) {\r\n          this.shouldCheckConnection = false;\r\n          this.clearCheckConnectionTimeout();\r\n          this.isReconnecting = true;\r\n          this.isConnected = false;\r\n          this.isHttpBindingActive = false;\r\n          this.connect();\r\n        }\r\n      }\r\n      if (this.shouldCheckConnection) {\r\n        this.checkConnectionTimeoutId = setTimeout(() => this.checkConnection(), _data_definitions_js__WEBPACK_IMPORTED_MODULE_1__.settings.pingInterval);\r\n      }\r\n    }\r\n  };\r\n\r\n  // --- Network connectivity handling ---\r\n  // Listen for offline events to stop HTTP binding.\r\n  window.addEventListener('offline', () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Network connection lost.\",\r\n      ru: \"Сетевое соединение потеряно.\"\r\n    }, 'warning');\r\n    xmppClient.stopHttpBinding();\r\n    xmppClient.isConnected = false;\r\n    xmppClient.shouldCheckConnection = false;\r\n    xmppClient.clearCheckConnectionTimeout();\r\n    messageManager.refreshMessages(false, 'network');\r\n  });\r\n\r\n  // Listen for online events to attempt reconnection immediately.\r\n  window.addEventListener('online', () => {\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_0__.logMessage)({\r\n      en: \"Network connection restored.\",\r\n      ru: \"Сетевое соединение восстановлено.\"\r\n    }, 'success');\r\n    if (!xmppClient.isConnected && !xmppClient.isReconnecting) {\r\n      xmppClient.connect();\r\n    }\r\n    messageManager.refreshMessages(true, 'network');\r\n  });\r\n\r\n  // Listen for visibility change to trigger a connection check when document becomes visible\r\n  document.addEventListener('visibilitychange', () => {\r\n    if (document.visibilityState === 'visible' && xmppClient.shouldCheckConnection && !xmppClient.isReconnecting) {\r\n      xmppClient.clearCheckConnectionTimeout();\r\n      xmppClient.checkConnection();\r\n    }\r\n  });\r\n\r\n  // Prevent connection checks during page reload or navigation\r\n  window.addEventListener('beforeunload', () => {\r\n    xmppClient.shouldCheckConnection = false;\r\n    xmppClient.clearCheckConnectionTimeout();\r\n  });\r\n\r\n  return xmppClient;\r\n}\r\n\n\n//# sourceURL=webpack://tampermonkey-script/./src/xmpp/xmppClient.js?");

/***/ }),

/***/ "./src/xmpp/xmppConnection.js":
/*!************************************!*\
  !*** ./src/xmpp/xmppConnection.js ***!
  \************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ XMPPConnection)\n/* harmony export */ });\n/* harmony import */ var _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../data/definitions.js */ \"./src/data/definitions.js\");\n/* harmony import */ var _helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers/helpers.js */ \"./src/helpers/helpers.js\");\n\r\n\r\n\r\nclass XMPPConnection {\r\n  constructor({\r\n    username,\r\n    password,\r\n    bindUrl = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.XMPP_BIND_URL,\r\n    delay = _data_definitions_js__WEBPACK_IMPORTED_MODULE_0__.settings.connectionDelay\r\n  }) {\r\n    this.username = username;\r\n    this.password = password;\r\n    this.bindUrl = bindUrl;\r\n    this.delay = delay;\r\n    this.sid = null;\r\n    this.rid = 0;\r\n  }\r\n\r\n  nextRid() {\r\n    return ++this.rid;\r\n  }\r\n\r\n  async sendRequest(payload) {\r\n    const response = await fetch(this.bindUrl, {\r\n      method: 'POST',\r\n      headers: {\r\n        'Content-Type': 'text/xml; charset=UTF-8',\r\n        'User-Agent': 'Mozilla/5.0'\r\n      },\r\n      body: payload\r\n    });\r\n    if (!response.ok) {\r\n      throw new Error(`HTTP error! status: ${response.status}`);\r\n    }\r\n    return await response.text();\r\n  }\r\n\r\n  async sendRequestWithRetry(payload, maxRetries = 5) {\r\n    let lastError;\r\n    let baseWaitTime = this.delay;\r\n    for (let attempt = 1; attempt <= maxRetries; attempt++) {\r\n      try {\r\n        return await this.sendRequest(payload);\r\n      } catch (error) {\r\n        lastError = error;\r\n        if (error.message.includes('429')) {\r\n          const waitTime = baseWaitTime * Math.pow(2, attempt);\r\n          (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n            en: `Rate limited (attempt ${attempt}/${maxRetries}). Waiting ${waitTime}ms...`,\r\n            ru: `Превышен лимит (попытка ${attempt}/${maxRetries}). Ожидание ${waitTime}мс...`\r\n          }, 'warning');\r\n          await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(waitTime);\r\n        } else {\r\n          throw error;\r\n        }\r\n      }\r\n    }\r\n    (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.logMessage)({\r\n      en: `Max retries reached. Last error: ${lastError.message}`,\r\n      ru: `Достигнут лимит попыток. Последняя ошибка: ${lastError.message}`\r\n    }, 'error');\r\n    throw new Error(`Max retries reached. Last error: ${lastError.message}`);\r\n  }\r\n\r\n  async connect() {\r\n    console.log('🌐 Step 1: Connecting to XMPP server...');\r\n\r\n    // BOSH uses a longer wait time (60s) to enable server-side event pushing\r\n    const initPayload = `<body xmlns='http://jabber.org/protocol/httpbind'\r\n               rid='${this.nextRid()}'\r\n               to='jabber.klavogonki.ru'\r\n               xml:lang='en'\r\n               wait='60'\r\n               hold='1'\r\n               ver='1.6'\r\n               xmpp:version='1.0'\r\n               xmlns:xmpp='urn:xmpp:xbosh'/>`;\r\n    const initResponse = await this.sendRequestWithRetry(initPayload);\r\n    this.sid = initResponse.match(/sid=['\"]([^'\"]+)['\"]/)[1];\r\n\r\n    console.log(`🔑 Step 2: Session ID received: ${this.sid}`);\r\n\r\n    await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(this.delay);\r\n\r\n    console.log('🔐 Step 3: Authenticating...');\r\n\r\n    const authString = (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.base64Encode)('\\x00' + this.username + '\\x00' + this.password);\r\n    const authPayload = `<body rid='${this.nextRid()}' sid='${this.sid}'\r\n               xmlns='http://jabber.org/protocol/httpbind'>\r\n          <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>${authString}</auth>\r\n        </body>`;\r\n    const authResponse = await this.sendRequestWithRetry(authPayload);\r\n    if (!authResponse.includes('<success')) {\r\n      throw new Error('❌ Authentication failed');\r\n    }\r\n    console.log('✅ Step 4: Authentication successful!');\r\n\r\n    await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(this.delay);\r\n\r\n    console.log('🔄 Step 5: Restarting stream...');\r\n\r\n    const restartPayload = `<body rid='${this.nextRid()}' sid='${this.sid}'\r\n               xmlns='http://jabber.org/protocol/httpbind'\r\n               to='jabber.klavogonki.ru'\r\n               xmpp:restart='true'\r\n               xmlns:xmpp='urn:xmpp:xbosh'/>`;\r\n    await this.sendRequestWithRetry(restartPayload);\r\n\r\n    await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(this.delay);\r\n\r\n    console.log('📦 Step 6: Binding resource...');\r\n\r\n    const bindPayload = `<body rid='${this.nextRid()}' sid='${this.sid}'\r\n               xmlns='http://jabber.org/protocol/httpbind'>\r\n          <iq type='set' id='bind_1' xmlns='jabber:client'>\r\n            <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>\r\n              <resource>web</resource>\r\n            </bind>\r\n          </iq>\r\n        </body>`;\r\n    await this.sendRequestWithRetry(bindPayload);\r\n\r\n    await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(this.delay);\r\n\r\n    console.log('🔌 Step 7: Establishing session...');\r\n\r\n    const sessionPayload = `<body rid='${this.nextRid()}' sid='${this.sid}'\r\n               xmlns='http://jabber.org/protocol/httpbind'>\r\n          <iq type='set' id='session_1' xmlns='jabber:client'>\r\n            <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>\r\n          </iq>\r\n        </body>`;\r\n    await this.sendRequestWithRetry(sessionPayload);\r\n\r\n    await (0,_helpers_helpers_js__WEBPACK_IMPORTED_MODULE_1__.sleep)(this.delay);\r\n\r\n    // Return session details for further use.\r\n    return { sid: this.sid, rid: this.rid };\r\n  }\r\n}\n\n//# sourceURL=webpack://tampermonkey-script/./src/xmpp/xmppConnection.js?");

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			id: moduleId,
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/compat get default export */
/******/ 	(() => {
/******/ 		// getDefaultExport function for compatibility with non-harmony modules
/******/ 		__webpack_require__.n = (module) => {
/******/ 			var getter = module && module.__esModule ?
/******/ 				() => (module['default']) :
/******/ 				() => (module);
/******/ 			__webpack_require__.d(getter, { a: getter });
/******/ 			return getter;
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/nonce */
/******/ 	(() => {
/******/ 		__webpack_require__.nc = undefined;
/******/ 	})();
/******/ 	
/************************************************************************/
/******/ 	
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module can't be inlined because the eval devtool is used.
/******/ 	var __webpack_exports__ = __webpack_require__("./src/main.js");
/******/ 	
/******/ })()
;