KG_Chat_Application

Enhance the chat abilities

目前為 2025-05-27 提交的版本,檢視 最新版本

// ==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");
/******/ 	
/******/ })()
;