Greasy Fork is available in English.

CatWar UwU

Визуальное обновление CatWar'а, и не только...

// ==UserScript==
// @name         CatWar UwU
// @namespace    http://tampermonkey.net/
// @version      v1.32.0-10.24
// @description  Визуальное обновление CatWar'а, и не только...
// @author       Ibirtem / Затменная ( https://catwar.net/cat1477928 )
// @copyright    2024, Ibirtem (https://openuserjs.org/users/Ibirtem)
// @supportURL   https://catwar.net/cat1477928
// @homepageURL  https://openuserjs.org/scripts/Ibirtem/CatWar_UwU
// @match        http*://*.catwar.net/*
// @license      MIT
// @iconURL      https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/partly_sunny_rain.png
// ==/UserScript==

"use strict"; // Делаю вид что крутой.

// ====================================================================================================================
//   . . . DEFAULT НАСТРОЙКИ . . .
// ====================================================================================================================
const current_uwu_version = "1.32.0";
// ✨🦐✨🦐✨
const uwuDefaultSettings = {
  settingsTheme: "dark",

  weatherEnabled: false,
  weatherDrops: false,
  lowPerformanceMode: false,
  minecraftStyle: false,
  alwaysDay: false,
  manualWeatherPanel: false,
  skyInHeader: false,
  auroraPos: "1",

  backgroundRepeat: false,
  backgroundUser: false,
  backgroundUserImageURL: "",
  gameFieldBackgroundUser: false,
  gameFieldBackgroundUserImageURL: "",
  userTheme: false,
  showOtherCatsList: "2",
  commentsAvatars: false,

  chatHeight: "275",
  newChat: false,
  reverseChat: false, 
  newChatInput: false,
  namesForNotification: "",

  notificationPM: false,
  notificationActionEnd: false,
  notificationInMouth: false,
  notificationInFightMode: false,
  showHintWhenToSniff: false,
  duplicateTimeInBrowserTab: false,


  cellsBorders: false,
  cellsBordersThickness: "1",
  cellsBordersColor: "#ffffff",
  cellsNumbers: false,
  fastStyles: false,
  displayParametersPercentages: false,
  compactMouth: false,
  showMoreCatInfo: false,
  showParametersDetails: false,

  draggingFightPanel: false,
  compactFightLog: false,
  fightPanelAdjustableHeight: false,
  fightPanelHeight: "70",
  fightTeams: false,
  fightTeamsColors: {
    team1: ["#41cd70", "#cd4141"],
    team2: ["#c968ff", "#cd4141"],
    team3: ["#44bcff", "#cd4141"],
    team4: ["#FFFF00", "#cd4141"],
  },
  fightTeamsPanelHight: "100",

  highlightResources: false,
  highlightResourcesStyle: "background",

  showClock: false,
  clockStyle: "compact",
  clockFontSize: "14",
  clockPosition: "fly",

  describeHuntingSmell: false,
  huntingVirtualJoystick: false,
  sizeHuntingVirtualJoystick: "150",

  climbingPanel: false,
  climbingPanelOrientation: "vertical",
  climbingNotificationsNumbers: false,
  climbingRefreshNotification: false,
  climbingRefreshNotificationSound: "notificationSound1",
  climbingRefreshNotificationVolume: "5",

  myNameNotificationSound: "notificationSound2",
  notificationMyNameVolume: "5",

  userQuickLinks: "",
  historyHeight: "215",

  parametersColors: {
    dream: ["#008000", "#008000", "#ff0000", "#ff0000"],
    hunger: ["#008000", "#008000", "#ff0000", "#ff0000"],
    thirst: ["#008000", "#008000", "#ff0000", "#ff0000"],
    need: ["#008000", "#008000", "#ff0000", "#ff0000"],
    health: ["#008000", "#008000", "#ff0000", "#ff0000"],
    clean: ["#008000", "#008000", "#ff0000", "#ff0000"],

    smell: ["#008000", "#008000", "#cccccc", "#cccccc"],
    dig: ["#008000", "#008000", "#cccccc", "#cccccc"],
    swim: ["#008000", "#008000", "#cccccc", "#cccccc"],
    might: ["#008000", "#008000", "#cccccc", "#cccccc"],
    tree: ["#008000", "#008000", "#cccccc", "#cccccc"],
    observ: ["#008000", "#008000", "#cccccc", "#cccccc"],

    other: ["#008000", "#008000", "#cccccc", "#cccccc"],
  },
  parametersBackgroundImage: false,
  parametersUserBackgroundImage: false,
  parametersUserBackgroundImageURL: "",

  restoreBlogCreation: false,
  moreBBCodes: false,
  commentPreview: false,
  moreCommentButtons: false,
  lsWrapPreview: false,
  calculators: false,

  extendedSettingsPanel: false,
  showUpdateNotification: false,
  showSplashScreens: false,
  extendedHints: true,
  GMbetaTest: false,
};

// ====================================================================================================================
//   . . . ТАРГЕТНЫЕ ССЫЛКИ . . .
// ====================================================================================================================
const targetSettings = /^https:\/\/catwar\.net\/settings/;
const targetCW3 = "https://catwar.net/cw3/";
const targetCW3Hunt = "https://catwar.net/cw3/jagd";
const targetMainProfile = /^https:\/\/catwar\.net\/$/;
const targetProfile = /^https:\/\/catwar\.net\/cat\d+$/;
const targetLs = /^https:\/\/catwar\.net\/ls/;
const targetLsNew = /^https:\/\/catwar\.net\/ls\?new(=.*)?$/;
const targetChats = /^https:\/\/catwar\.net\/chat/;
const targetBlog = /^https:\/\/catwar\.net\/(?:blog\d+|blogs)(?:$|[/?#])/i;
const targetBlogsCreation = /^https:\/\/catwar\.net\/blogs\?creation/;
const targetSniff = /^https:\/\/catwar\.net\/sniff(?:\d+|)(?:$|[/?#])/i;
const targetSniffCreation = /^https:\/\/catwar\.net\/sniff\?creation/;

// ====================================================================================================================
//   . . . СТАНДАРТНЫЕ ЦВЕТОВЫЕ ТЕМЫ . . .
// ====================================================================================================================
const defaultThemes = {
  "Тёмная Тема": {
    colors: {
      backgroundColor: "#161616",
      blocksColor: "#242424",
      chatColor: "#242424",
      textColor: "#d5d5d5",
      catTooltipBackground: "#242424",
      fightPanelBackground: "#242424",
      linkColor: "#d5d5d5",
      accentColor1: "#111111",
      accentColor2: "#2e2e2e82",
      accentColor3: "#fc872a",
      moveNameColor: "#d5d5d5",
      moveNameBackground: "#242424",
    },
  },
};

// ====================================================================================================================
//   . . . HTML ПАНЕЛЬ НАСТРОЕК . . .
// ====================================================================================================================
const uwusettings = // html
`
<div id="uwusettings">

  <div id="uwusettings-header">
    <div id="uwusettings-header-glass">
      <div class="main-settings-container">
        <div id="settingsTheme" class="custom-select">
          <label for="settingsTheme">Тема настроек:</label>
          <div class="select-selected">Классическая</div>
          <div class="select-items">
            <!-- Опции будут добавлены сюда -->
          </div>
        </div>

          <h1>Настройки CatWar UwU</h1>
        <div class="link-container" title="ВК Группа по Скрипту/Моду.">
          <a href="https://vk.com/catwar_uwu" target="_blank" rel="noopener noreferrer">
            <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/VK_logo.png" alt="Иконка" width="36" height="36">
          </a>
        </div>
      </div>

      <hr id="uwu-hr" class="uwu-hr-head">
      <div id="button-container">
        <button id="effects-button" class="active">
          <h2>
            Природные эффекты
            <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/partly_sunny_rain.png" alt="Иконка"
              width="24" height="24" />
          </h2>
        </button>
        <button id="theme-button">
          <h2>
            Оформление
            <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/sparkles.png" alt="Иконка" width="24"
              height="24" />
          </h2>
        </button>
        <button id="utility-button">
          <h2>
            Инструментарий
            <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/flashlight.png" alt="Иконка" width="24"
              height="24" />
          </h2>
        </button>
        <button id="modules-button">
          <h2>
            Надстройки
            <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/construction.png" alt="Иконка" width="24"
              height="24" />
          </h2>
        </button>
      </div>
      <hr id="uwu-hr" class="uwu-hr-head">
    </div>
  </div>

  <div id="uwusettings-main">
    <div id="effects-panel">

    <h2>Природа и окружение</h2>

      <div>
        <p>
          Включает генерацию Динамичной погоды в Игровой, такие как дождь, снегопады или Северные Сияния.
        </p>
        <input type="checkbox" id="weather-enabled" data-setting="weatherEnabled" />
        <label for="weather-enabled">Показывать природные эффекты</label>
      </div>

      <div>
        <p>
        Сокращает количество частиц динамичной погоды, увеличивая тем самым производительность на слабых устройствах.
        </p>
      <input type="checkbox" id="low-Performance-Mode" data-setting="lowPerformanceMode" />
      <label for="low-Performance-Mode">Режим низкой производительности</label>
      </div>

      <div>
        <p>Может немного повлиять на производительность из-за возрастания количества частиц на экране.</p>
        <input type="checkbox" id="weather-drops" data-setting="weatherDrops" />
        <label for="weather-drops">Эффекты приземления частиц</label>
      </div>

      <div>
        <p>Замена стандартных частиц на знакомые всеми пиксельные частицы.</p>
        <input type="checkbox" id="minecraft-style" data-setting="minecraftStyle" />
        <label for="minecraft-style-enabled">Minecraft частицы</label>
      </div>

      <div>
        <p>Убирает затемнение Игрового поля.</p>
        <input type="checkbox" id="always-day" data-setting="alwaysDay" />
        <label for="always-day">Всегда день/ярко</label>
      </div>

      <div>
        <p>Отображает панель Ручного управления погодой в ⚙️Панели Расширенных Настройках Игровой. Выключает натуральную генерацию погоды.</p>
        <input type="checkbox" id="manual-Weather-Panel" data-setting="manualWeatherPanel" />
        <label for="manual-Weather-Panel">Ручное управление погоды</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <p>Расположение Северного Сияния</p>
      <div id="auroraPanel">
        <input type="range" min="1" max="2" value="1" class="uwu-range-slider" id="aurora-pos" list="auroraStep"
          data-setting="auroraPos">
        <datalist id="auroraStep">
          <option value="1">Верх</option>
          <option value="2">Низ</option>
        </datalist>
      </div>

      <div>
        <p>Делает небо шапкой страницы, пряча под игровую, а так же по факту чинит его потерю при Редизайне игровой. Будет
          выглядеть не очень на широкоформатных мониторах из-за растягивания изображения.</p>
        <input type="checkbox" id="sky-in-the-sky" data-setting="skyInHeader" />
        <label for="sky-in-the-sky">Небо в небе.</label>
      </div>

    </div>

    <div id="theme-panel">

    <h2>Поле Игровой</h2>

    <div>
      <p> Заменяет все фоны игровых локаций на выбранный вами фон. Помните, что для правильного отображения нужно изображение 1000х1000 px.</p>
      <input type="checkbox" id="game-Field-background-User" data-setting="gameFieldBackgroundUser" />
      <label for="game-Field-background-User-enabled">Статичный фон локации:</label>
      <input type="text" id="gameFieldSettingImageURLField" placeholder="Вставьте URL" data-setting="gameFieldBackgroundUserImageURL" />
      <button id="SettingSaveButton1" class="uwu-button install-button">Сохранить</button>
    </div>

    <div>
      <p>Отрисовывает границы клеток Игрового поля.</p>
      <input type="checkbox" id="cells-Borders" data-setting="cellsBorders" />
      <label for="cells-Borders">Границы клеток</label>
    </div>
    <p>Толщина/Яркость границ</p>
    <div id="step-slider">
      <input type="range" min="1" max="9" value="1" id="cells-Borders-Thickness" class="uwu-range-slider" list="ThicknessStep" data-setting="cellsBordersThickness">
      <datalist id="ThicknessStep">
      <option value="1">0.1</option>
      <option value="5">0.5</option>
      <option value="9">0.9</option>
      </datalist>
    </div>
    <div>
      <label for="cells-Borders-Color">Цвет границы клеток</label>
      <input type="color" id="cells-Borders-Color" data-setting="cellsBordersColor" value="#ffffff">
    </div>
    
    <div>
    <p>Обозначает клетки Игрового поля числами.</p>
      <input type="checkbox" id="cells-Numbers" data-setting="cellsNumbers" />
      <label for="cells-Numbers">Нумерация клеток</label>
    </div>

      <div>
        <p>
          Ставит на страницу фон, повторяющий фон Игровой локации, а так же
          размывает и затемняет его.
        </p>
        <input type="checkbox" id="background-repeat" data-setting="backgroundRepeat" />
        <label for="weather-enabled">Фон страницы из локации</label>
      </div>

      <div>
        <p>Ставит на страницу фон из предоставленной ссылки.</p>
        <input type="checkbox" id="background-user" data-setting="backgroundUser" />
        <label for="background-user-enabled">Свой фон страницы:</label>
        <input type="text" id="SettingImageURLField" placeholder="Вставьте URL" data-setting="backgroundUserImageURL" />
        <button id="SettingSaveButton1" class="uwu-button install-button">Сохранить</button>
      </div>

      <div>
        <p>Позволяет быстро сменять стили в ⚙️Панели Расширенных настроек в Игровой.</p>
        <input type="checkbox" id="fast-Styles" data-setting="fastStyles" />
        <label for="fast-Styles">Быстрые стили</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Темы и цвета Игровой</h2>

      <p>
        Здесь вы можете выставить собственные цвета для игровой. Принимаются "HEX"
        значения (Пример: #000) с поддержкой прозрачности. Будьте аккуратны и
        не забывайте выключать другие цвета/темы в других скриптах/модах. Очистите поле
        чтобы вернуться к стандартным цветам.
      </p>
      <input type="checkbox" id="user-theme" data-setting="userTheme" />
      <label for="user-theme-enabled">Использовать свои цвета</label>

    <div id="theme-selector" class="uwu-select">
      <label for="theme-select">Выберите тему:</label>
      <select id="theme-select" class="uwu-select-selected"></select>
      <button id="addThemeButton" class="uwu-button install-button">Добавить тему</button>
      <button id="removeThemeButton" style="display: none;" class="uwu-button remove-button">Удалить тему</button>
    </div>

      <div id="color-picker">
        <div id="color-picker-input">
          <input type="text" id="backgroundColorField" placeholder="Вставьте HEX код"
            data-color="backgroundColor" />
          <label>Цвет фона</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="blocksColorField" placeholder="Вставьте HEX код"
            data-color="blocksColor" />
          <label>Основной цвет блоков</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="chatColorField" placeholder="Вставьте HEX код" data-color="chatColor" />
          <label>Основной цвет чата</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="SettingTextColorField" placeholder="Вставьте HEX код" data-color="textColor" />
          <label>Цвет текста</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="colorField" placeholder="Вставьте HEX код" data-color="linkColor" />
          <label>Цвет ссылок</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="catTooltipBackgroundField" placeholder="Вставьте HEX код"
            data-color="catTooltipBackground" />
          <label>Цвет фона подсказки "О Коте"</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="settingFightPanelBackgroundField" placeholder="Вставьте HEX код"
            data-color="fightPanelBackground" />
          <label>Цвет панели Боевого режима</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="settingsMoveNameColorField" placeholder="Вставьте HEX код"
            data-color="moveNameColor" />
          <label>Цвет текста перехода</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="settingsMoveNameBackgroundField" placeholder="Вставьте HEX код"
            data-color="moveNameBackground" />
          <label>Цвет фона перехода</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="accentColorField1" placeholder="Вставьте HEX код"
            data-color="accentColor1" />
          <label
            title="В основном всякие кнопки, слайдеры и строки ввода + цвет букв упоминания вас в Чате. Старайтесь пока делать просто оттенки чёрного цвета.">[?]
            Акценты 1</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="accentColorField2" placeholder="Вставьте HEX код"
            data-color="accentColor2" />
          <label title="Линии в чате и некоторых других частях, кружочек слайдера громкости.">[?] Акценты 2</label>
        </div>
        <div id="color-picker-input">
          <input type="text" id="accentColorField3" placeholder="Вставьте HEX код"
            data-color="accentColor3" />
          <label title="Цвет уведомлений. Например ЛС и вашего имени в Чате">[?] Акценты 3</label>
        </div>

        <div style="flex: 0 0 100%">
          <button id="saveThemeButton" class="uwu-button install-button">Сохранить</button>
          <p>
            Отличный сайт для выбора цветов с поддержкой прозрачности:
            <a href="https://get-color.ru/transparent/" target="_blank">https://get-color.ru/transparent/</a>
          </p>
        </div>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Шрифты и текст</h2>
      
      <div>
        <p>Кастомная настройка шрифтов в Игровой</p>
        <input type="checkbox" id="use-User-Fonts" data-setting="useUserFonts" />
        <label for="use-User-Fonts">Свой шрифт</label>
      </div>

      <div>
        <input type="text" id="font-Size-Body" placeholder="14" data-font-size="fontSizeBody" />
        <label for="font-Size-Body">px; Размер общего шрифт</label>
      </div>

      <div>
        <input type="text" id="font-Size-Small" placeholder="12" data-font-size="fontSizeSmall" />
        <label for="font-Size-Small">px; Размер шрифта быстрых ссылок</label>
      </div>

      <div>
        <input type="text" id="font-Size-Location" placeholder="14" data-font-size="fontSizeLocation" />
        <label for="font-Size-Location">px; Размер шрифта локации</label>
      </div>

      <div>
        <input type="text" id="font-Family-Body" placeholder="Verdana" data-font-size="fontFamilyBody" />
        <label for="font-Family-Body">Название вида шрифта</label>
      </div>

      <details>
        <summary style="cursor: pointer; font-size: 16px; font-weight: bold;">Настройка шрифта громкости сообщений в чате</summary>
        <div>
          <input type="text" id="vlm0" placeholder="10" data-font-size="vlm0" />
          <label for="vlm0">px; Громкость 0 (Самый тихий)</label>
        </div>
        <div>
          <input type="text" id="vlm1" placeholder="11" data-font-size="vlm1" />
          <label for="vlm1">px; Громкость 1</label>
        </div>
        <div>
          <input type="text" id="vlm2" placeholder="11.5" data-font-size="vlm2" />
          <label for="vlm2">px; Громкость 2</label>
        </div>
        <div>
          <input type="text" id="vlm3" placeholder="12" data-font-size="vlm3" />
          <label for="vlm3">px; Громкость 3</label>
        </div>
        <div>
          <input type="text" id="vlm4" placeholder="12.5" data-font-size="vlm4" />
          <label for="vlm4">px; Громкость 4</label>
        </div>
        <div>
          <input type="text" id="vlm5" placeholder="13" data-font-size="vlm5" />
          <label for="vlm5">px; Громкость 5 (Стандартная громкость)</label>
        </div>
        <div>
          <input type="text" id="vlm6" placeholder="15" data-font-size="vlm6" />
          <label for="vlm6">px; Громкость 6</label>
        </div>
        <div>
          <input type="text" id="vlm7" placeholder="17" data-font-size="vlm7" />
          <label for="vlm7">px; Громкость 7</label>
        </div>
        <div>
          <input type="text" id="vlm8" placeholder="19" data-font-size="vlm8" />
          <label for="vlm8">px; Громкость 8</label>
        </div>
        <div>
          <input type="text" id="vlm9" placeholder="21" data-font-size="vlm9" />
          <label for="vlm9">px; Громкость 9</label>
        </div>
        <div>
          <input type="text" id="vlm10" placeholder="23" data-font-size="vlm10" />
          <label for="vlm10">px; Громкость 10 (Самая громкая)</label>
        </div>
      </details>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Редизайны Игровой</h2>

      <p>Тот самый знаменитный редизайн, но с почти более расширенной кастомизацией.</p>
      <input type="checkbox" id="custom-layout" data-setting="customLayout" />
      <label for="custom-layout">Компактный редизайн</label>

      <div id="layout-customizer">
        <div id="layout-preview">
          <div class="column left">
            <!-- Левая колонка -->
          </div>
          <div class="column center">
            <!-- Центральная колонка -->
            <div class="block center-block">Поле Игровой</div>
          </div>
          <div class="column right">
            <!-- Правая колонка -->
          </div>
          <ul id="block-list">
            <!-- Элементы списка блоков -->
          </ul>
        </div>
      </div>
      <button id="SettingSaveButton4" class="uwu-button install-button">Сохранить</button>

      <div>
        <input type="text" id="chat-height" placeholder="Вставьте значение" data-setting="chatHeight" />
        <label for="chat-height">px; Высота Чата</label>
      </div>

      <div>
        <input type="text" id="history-height" placeholder="Вставьте значение" data-setting="historyHeight" />
        <label for="history-height">px; Высота Истории</label>
      </div>

      <label>Отображать Душевых котов:</label>
      <div class="custom-select" id="showOtherCatsList">
        <div class="select-selected">Выберите стиль отображения Душевых котов</div>
        <div class="select-items">
          <!-- Опции будут добавлены сюда -->
        </div>
      </div>

      <div>
        <p>Визуальное разделение блока "Информация" на меньшие блоки "Параметров, Истории и Родственные связи".</p>
        <input type="checkbox" id="slice-info-block" data-setting="sliceInfoBlock" />
        <label for="slice-info-block">Разделить блок Информации</label>
      </div>

      <div>
        <p>Скругляет края блоков в Игровой.</p>
        <input type="checkbox" id="edge-trim-blocks" data-setting="edgeTrimBlocks" />
        <label for="edge-trim-blocks">Скругление блоков</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Общение</h2>

      <div>
        <p>Добавляет аватар с профиля отправителя на его комментарий в лентах и блогах.</p>
        <input type="checkbox" id="comments-avatars" data-setting="commentsAvatars" />
        <label for="comments-avatars">Аватарки в комментариях</label>
      </div>

      <div>
        <p>Более функциональный Чат: допись ID отправителя и звуковое уведомление при вашем упоминании.
        </p>
        <input type="checkbox" id="new-chat" data-setting="newChat" />
        <label for="new-chat">Современный Чат</label>
      </div>

      <div>
        <p>Работает только с "Современным чатом". Отображет чат снизу вверх, а так же смещает окно ввода сообщения под чат.</p>
        <input type="checkbox" id="reverse-Chat" data-setting="reverseChat" />
        <label for="reverse-Chat">Инверсия чата</label>
      </div>

      <div id="myNameNotificationSoundContainer">
        <div class="custom-select" id="myNameNotificationSound">
          <div class="select-selected">Выберите звук</div>
          <div class="select-items">
            <!-- Опции будут добавлены сюда -->
        </div>
      </div>
    
      <div id="notification-volume">
      <p>Громкость</p>
        <input type="range" min="1" max="10" value="5" class="uwu-range-slider" id="notification-MyName-Volume" list="volumeStep"
          data-setting="notificationMyNameVolume">
        <datalist id="volumeStep">
          <option value="1">10%</option>
          <option value="5">50%</option>
          <option value="10">100%</option>
        </datalist>
      </div>
    </div>

    <div>
      <p>Ваши собственные имена и клички на упоминания в чате. Просто пропишите их через запятую. Пример: Мяу, Мяуич, МяуВкин</p>
      <input type="text" id="names-For-Notification" placeholder=". . ." data-setting="namesForNotification" />
    </div>

      <div>
        <p>Более удобная строка ввода сообщений над чатом с возможностью растягивания. Пока что насильно берёт цвета с "Использовать свои цвета".</p>
        <input type="checkbox" id="new-chat-input" data-setting="newChatInput" />
        <label for="new-chat-input">Альтернативная строка ввода сообщений</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Параметры и навыки</h2>
      
      <div>
        <p>Параметр наглядно отображает рядом с собой свой процент.</p>
        <input type="checkbox" id="display-Parameters-Percentages" data-setting="displayParametersPercentages" />
        <label for="display-Parameters-Percentages">Отображать проценты Параметров</label>
      </div>

      <div>
        <p>Заменяет стандартное оформление Параметров и Навыков на ваш.</p>
        <input type="checkbox" id="user-Parameters-Theme" data-setting="userParametersTheme" />
        <label for="user-Parameters-Theme">Использовать своё оформление</label>
      </div>

  <div id="parameters-color-settings" class="parameters-color-settings">
    <table class="parameters-color-table">
      <thead>
        <tr>
          <th class="parameters-color-table--header">Градиент</th>
          <th class="parameters-color-table--header">От</th>
          <th class="parameters-color-table--header">До</th>
          <th class="parameters-color-table--header">От</th>
          <th class="parameters-color-table--header">До</th>
        </tr>
      </thead>
      <tbody id="color-settings-body" class="parameters-color-table--body">
        <tr>
          <th class="parameters-color-table--cell" colspan="5">Параметры</th>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Сон</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dream" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dream" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dream" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dream" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Голод</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="hunger" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="hunger" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="hunger" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="hunger" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Жажда</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="thirst" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="thirst" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="thirst" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="thirst" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Нужда</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="need" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="need" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="need" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="need" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Здоровье</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="health" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="health" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="health" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="health" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Чистота</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="clean" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="clean" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="clean" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="clean" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <th class="parameters-color-table--cell" colspan="5">Навыки</th>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Запах</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="smell" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="smell" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="smell" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="smell" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Копание</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dig" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dig" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dig" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="dig" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Плавание</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="swim" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="swim" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="swim" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="swim" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">БУ</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="might" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="might" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="might" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="might" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Лазание</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="tree" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="tree" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="tree" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="tree" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <td class="parameters-color-table--cell">Зоркость</td>
          <td class="parameters-color-table--cell"><input type="color" data-param="observ" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="observ" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="observ" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="observ" data-color-type="bg-to"></td>
        </tr>
        <tr>
          <th class="parameters-color-table--cell" colspan="5">Уникальные навыки</th>
        </tr>
        <tr>
          <td class="parameters-color-table--cell"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="other" data-color-type="bar-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="other" data-color-type="bar-to"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="other" data-color-type="bg-from"></td>
          <td class="parameters-color-table--cell"><input type="color" data-param="other" data-color-type="bg-to"></td>
        </tr>
      </tbody>
    </table>
  </div>

      <div>
        <p>Накладывает поверх цветов изображение с узорами.</p>
        <input type="checkbox" id="parameters-Background-Image" data-setting="parametersBackgroundImage" />
        <label for="parameters-Background-Image">Узоры</label>
      </div>

      <div>
        <p>Накладывает поверх уже ваше изображение.</p>
        <input type="checkbox" id="parameters-User-Background-Image" data-setting="parametersUserBackgroundImage" />
        <label for="parameters-User-Background-Image">Свои узоры:</label>
        <input type="text" id="parametersUserBackgroundImageField" placeholder="Вставьте URL" data-setting="parametersUserBackgroundImageURL" />
        <button id="SettingSaveButton1" class="uwu-button install-button">Сохранить</button>
      </div>

    </div>

    <div id="utility-panel">

      <h2>Подсветка</h2>

      <div>
        <p>Подсвечивает обводкой клетки полезные, и не очень, ресурсы</p>
        <input type="checkbox" id="highlight-Resources" data-setting="highlightResources" />
        <label for="highlight-Resources">Подсветка ресурсов</label>
      </div>

      <label>Стиль подсветки предметов:</label>
      <div class="custom-select" id="highlightResourcesStyle">
        <div class="select-selected">Выберите стиль подсветки предметов</div>
        <div class="select-items">
          <!-- Опции будут добавлены сюда -->
        </div>
      </div>
      <label id="uwu-what-this" title="Стиль 'Фон' подсвечивает всю клетку и не нагружает Игровую. Стиль 'Свечение' дублирует содержимое ячейки и стилизует его, что может нагружать Игровую.">[?]</label>

      <table class="uwu-table-highlight-Resources">
        <thead>
            <tr>
                <th>Название</th>
                <th>Цвет</th>
                <th>Подсвечивать?</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Травы</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Травы" value="#90EE90"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Травы"></td>
            </tr>
            <tr>
                <td>Мох</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Мох" value="#90EE90"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Мох"></td>
            </tr>
            <tr>
                <td>Паутина</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Паутина" value="#90EE90"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Паутина"></td>
            </tr>
            <tr>
                <td>Пыль</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Пыль" value="#DDA0DD"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Пыль"></td>
            </tr>
            <tr>
                <td>Ветки, вьюнки, костоправы</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Ветки, вьюнки, костоправы" value="#90EE90"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Ветки, вьюнки, костоправы"></td>
            </tr>
            <tr>
                <td>Травящие предметы</td>
                <td><input type="color" class="uwu-color-picker" data-resource="Травящие предметы" value="#FF0000"></td>
                <td class="uwu-checkbox-cell"><input type="checkbox" class="uwu-highlight-checkbox" data-resource="Травящие предметы"></td>
            </tr>
        </tbody>
      </table>

      <hr class="uwu-hr-head" />

      <h2>Шаблоны</h2>

      <div>
        <p>Позволяет создавать и быстро использовать собственные шаблоны сообщений.</p>
        <input type="checkbox" id="show-Templates" data-setting="showTemplates" />
        <label for="show-Templates">Отображать шаблоны</label>
      </div>

      <table id="uwu-table-templates">
      <thead>
          <tr>
              <th>Сообщения</th>
              <th>Чаты</th>
              <th>Блоги и Лента</th>
          </tr>
        </thead>
        <tbody>
          <tr>
              <td class="uwu-checkbox-cell"><input type="checkbox" data-setting="templatesInLs"></td>
              <td class="uwu-checkbox-cell"><input type="checkbox" data-setting="templatesInChats"></td>
              <td class="uwu-checkbox-cell"><input type="checkbox" data-setting="templatesInBlogsAndSniffs"></td>
          </tr>
        </tbody>
        </table>

      <hr class="uwu-hr-head" />

      <h2>Боевой режим</h2>

      <div>
        <p>Позволяет перетаскивать панель Боевого режима за штучку.</p>
        <input type="checkbox" id="dragging-Fight-Panel" data-setting="draggingFightPanel" />
        <label for="dragging-Fight-Panel">Перетаскивание панели Боевого режима</label>
      </div>

      <div>
        <p>Сокращает и прописывает количество повторяющихся ударов.</p>
        <input type="checkbox" id="compact-Fight-Log" data-setting="compactFightLog" />
        <label for="compact-Fight-Log">Компактный боевой лог</label>
      </div>

      <div>
        <p>Возможность растягивать высоту панели и её начальная высота.</p>
        <input type="checkbox" id="fight-Panel-Adjustable-Height" data-setting="fightPanelAdjustableHeight" />
        <label for="fight-Panel-Adjustable-Height">Настраиваемая высота панели</label>
        <input type="text" id="fightPanelHeightField" placeholder=". . ." data-setting="fightPanelHeight" />
        <label>px; - Начальная высота панели</label>
      </div>

      <div>
        <p>Возможность перекрашивать и создавать команды в Панели Боевого Режима.</p>
        <input type="checkbox" id="Fight-Teams" data-setting="fightTeams" />
        <label for="fight-Teams">Команды в Боевом Режиме</label>
        <input type="text" id="fightTeamsPanelHightField" placeholder=". . ." data-setting="fightTeamsPanelHight" />
        <label>px; - Начальная высота панели Командного Боя</label>
      </div>

  <table id="colorSettingsTable">
    <thead>
      <tr>
        <th></th>
        <th>Энергия</th>
        <th>Снесено</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Команда 1</td>
        <td><input type="color" data-team="1" data-part="green" value="#41cd70"></td>
        <td><input type="color" data-team="1" data-part="red" value="#cd4141"></td>
      </tr>
      <tr>
        <td>Команда 2</td>
        <td><input type="color" data-team="2" data-part="green" value="#c968ff"></td>
        <td><input type="color" data-team="2" data-part="red" value="#cd4141"></td>
      </tr>
      <tr>
        <td>Команда 3</td>
        <td><input type="color" data-team="3" data-part="green" value="#44bcff"></td>
        <td><input type="color" data-team="3" data-part="red" value="#cd4141"></td>
      </tr>
      <tr>
        <td>Команда 4</td>
        <td><input type="color" data-team="4" data-part="green" value="#FFFF00"></td>
        <td><input type="color" data-team="4" data-part="red" value="#cd4141"></td>
      </tr>
    </tbody>
  </table>
    
    <hr id="uwu-hr" class="uwu-hr">
    <h2>Часы</h2>

    <div>
      <p>Показывать ли часы в Игровой?</p>
      <input type="checkbox" id="describe-show-clock" data-setting="showClock" />
      <label for="describe-show-clock">Часы в Игровой</label>
    </div>

    <label>Стиль часов:</label>
    <div class="custom-select" id="clockStyle">
      <div class="select-selected">Выберите стиль часов</div>
      <div class="select-items">
        <!-- Опции будут добавлены сюда -->
      </div>
    </div>

    <div><!-- Деление --></div>

    <label>Где вставлять часы:</label>
    <div class="custom-select" id="clockPosition">
      <div class="select-selected">Выберите положение часов</div>
      <div class="select-items">
        <!-- Опции будут добавлены сюда -->
      </div>
    </div>

    <div>
      <input type="checkbox" id="describe-clock-Moscow-Time" data-setting="clockMoscowTime" />
      <label for="describe-clock-Moscow-Time">Московское время</label>
    </div>

    <div>
      <p>Размер шрифта часов</p>
      <input type="text" id="clock-Font-Size" placeholder=". . ." data-setting="clockFontSize" />
    </div>

    <div>
      <button id="resetClockPosition" class="uwu-button remove-button">Сброс позиции часов</button>
    </div>

    <hr id="uwu-hr" class="uwu-hr">
    <h2>Охота</h2>

      <div>
        <p>Дописывает на запахе, во время охоты, приближаетесь вы или отдаляетесь от цели, а так же включает таймер.</p>
        <input type="checkbox" id="describe-Hunting-Smell" data-setting="describeHuntingSmell" />
        <label for="describe-Hunting-Smell">Подсказки на запахе</label>
      </div>

    <hr id="uwu-hr" class="uwu-hr">
    <h2>Джойстики</h2>

      <div>
        <p>Отображает Виртуальную сенсорную Джойстиковую кнопку для мобильных устройств во время охоты для более удобного управления.</p>
        <input type="checkbox" id="hunting-Virtual-Joystick" data-setting="huntingVirtualJoystick" />
        <label for="hunting-Virtual-Joystick">Виртуальный джойстик для охоты</label>
        <input type="text" id="sizeHuntingVirtualJoystickField" placeholder=". . ." data-setting="sizeHuntingVirtualJoystick" />
        <label>px; - Размер Джойстика. Стандартный размер - 150 px;</label>
      </div>

    <hr id="uwu-hr" class="uwu-hr">
    <h2>"О котах"</h2>

      <div>
        <p>Добавляет во всплывающее окно "О коте" кнопку "Подробнее" для просмотра большей полезной информации.</p>
        <input type="checkbox" id="show-More-Cat-Info" data-setting="showMoreCatInfo" />
        <label for="show-More-Cat-Info">Больше информации о Коте</label>
      </div>

      <div>
        <p>Сокращает и прописывает количество повторяющихся предметов в "О коте".</p>
        <input type="checkbox" id="compact-Mouth" data-setting="compactMouth" />
        <label for="compact-Mouth">Компактные инвентари</label>
      </div>

      <div>
        <p>Добавляет над собственными параметрами кнопку "Подробнее" для просмотра большей полезной информации.</p>
        <input type="checkbox" id="show-Parameter-Details" data-setting="showParametersDetails" />
        <label for="show-Parameter-Details">Подробные параметры</label>
      </div>

      <div>
        <p>Показывает дополнительную информацию в профиле кота, например БУ цифрой.</p>
        <input type="checkbox" id="more-Profile-Info" data-setting="moreProfileInfo" />
        <label for="more-Profile-Info">Больше информации в профиле</label>
      </div>

      <div>
        <p>Добавляет полезные калькуляторы для вычислений в профиля.</p>
        <input type="checkbox" id="calculators" data-setting="calculators" />
        <label for="calculators">Калькуляторы активностей и лун.</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Минное поле</h2>

      <div>
      <p>ЛКМ - выбрать клетку. С клавиатуры мины ставятся от "0" до "7". Знак "минус" ( - ) равняется красной клетке, а "равно" ( = ) ставит более яркую клетку, например для переходов,
      которая не будет очищаться при "Очистить всё поле/таблицу". Два раза ЛКМ на ячейку, чтобы очистить её значение.</p>
        <p>Включает окно для расчерчивания минного поля в Игровой.</p>
        <input type="checkbox" id="climbing-panel" data-setting="climbingPanel" />
        <label for="climbing-panel">Минное поле</label>
        <p>Здесь вы можете добавить/удалить Вкладки для хранения Таблиц и количество самих таблиц в выбранной вкладке.</p>
          <h4>Вкладки</h4>
          <div id="uwu-buttonRow1-settings"></div>
          <h4>Локации / Таблицы</h4>
          <div id="uwu-buttonRow2-settings"></div>
      </div>

      <label>Дизайн окна минного поля:</label>
      <div class="custom-select" id="climbingPanelOrientation">
        <div class="select-selected">Вертикальный</div>
        <div class="select-items">
          <!-- Опции будут добавлены сюда -->
        </div>
      </div>

      <div>
        <p>Дописывает в чате громкость уведомлений числом. В случае с лазательными локациями - количество опасных клеток вокруг вас.</p>
        <input type="checkbox" id="climbing-Notifications-Numbers" data-setting="climbingNotificationsNumbers" />
        <label for="climbing-Notifications-Numbers">Подписывать громкость уведомления</label>
      </div>

      <div>
        <p>Звуковое уведомление, когда карта локации обновляется.</p>
        <input type="checkbox" id="climbing-Refresh-Notification" data-setting="climbingRefreshNotification" />
        <label for="climbing-Refresh-Notification">Уведомлять об перестановке</label>
      </div>

      <div id="climbingRefreshNotificationSoundContainer">
        <div class="custom-select" id="climbingRefreshNotificationSound">
          <div class="select-selected">Выберите звук</div>
        <div class="select-items">
          <!-- Опции будут добавлены сюда -->
        </div>
      </div>
    
      <div id="notification-volume">
      <p>Громкость</p>
        <input type="range" min="1" max="10" value="5" class="uwu-range-slider" id="climbing-Refresh-Notification-Volume" list="volumeStep"
          data-setting="climbingRefreshNotificationVolume">
        <datalist id="volumeStep">
          <option value="1">10%</option>
          <option value="5">50%</option>
          <option value="10">100%</option>
        </datalist>
      </div>
    </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Быстрые ссылки</h2>

      <p>Быстрые ссылки в Игровой.</p>
      <div>
        <input type="checkbox" id="quick-Link1" data-setting="quickLink1" />
        <label for="quick-Link1">Настройки</label>
      </div>

      <div>
        <input type="checkbox" id="quick-Link2" data-setting="quickLink2" />
        <label for="quick-Link2">Памятка</label>
      </div>

      <div>
        <input type="checkbox" id="quick-Link3" data-setting="quickLink3" />
        <label for="quick-Link3">Блоги</label>
      </div>

      <div>
        <input type="checkbox" id="quick-Link4" data-setting="quickLink4" />
        <label for="quick-Link4">Лента</label>
      </div>

      <div>
        <p>Ваши ссылки. Вставляете ссылку, пробел и пишите название. Для множества просто пишите через запятую. Пример:
          https://мяу Котики, https://мяу2 Больше-котиков</p>
        <input type="text" id="users-quick-Links" placeholder=". . ." data-setting="userQuickLinks" />
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <div>
        <h2>Уведомления</h2>
        <p>Уведомлять звуком, когда:</p>
      </div>
      
      <div>
        <input type="checkbox" id="notification-PM" data-setting="notificationPM" />
        <label for="notification-PM">Новое Личное Сообщение</label>
      </div>

      <div>
        <input type="checkbox" id="notification-Action-End" data-setting="notificationActionEnd" />
        <label for="notification-Action-End">Действие закончилось</label>
      </div>

      <div>
        <input type="checkbox" id="notification-In-Mouth" data-setting="notificationInMouth" />
        <label for="notification-In-Mouth">Кто-то меня поднял</label>
      </div>

      <div>
        <input type="checkbox" id="notification-In-Fight-Mode" data-setting="notificationInFightMode" />
        <label for="notification-In-Fight-Mode">Ввели в боевую стойку через Т+2 или Т+3</label>
      </div>

      <div>
        <p>Дублирует время действий на название браузерной вкладки.</p>
        <input type="checkbox" id="duplicate-Time-In-Browser-Tab" data-setting="duplicateTimeInBrowserTab" />
        <label for="duplicate-Time-In-Browser-Tab">Показывать время действия на вкладке</label>
      </div>

      <div>
        <p>Подсказывает оставшееся время до возможности понюхать.</p>
        <input type="checkbox" id="show-Hint-When-To-Sniff" data-setting="showHintWhenToSniff" />
        <label for="show-Hint-When-To-Sniff">Когда нюхать?</label>
      </div>

      <hr id="uwu-hr" class="uwu-hr">
      <h2>Общение</h2>

      <div>
        <p>Автоматически сохраняет и восстанавливает редактируемый текст блога. Теперь вы не потеряете его случайно.</p>
        <input type="checkbox" id="restore-Blog-Creation" data-setting="restoreBlogCreation" />
        <label for="restore-Blog-Creation">Восстановление содержимого Блога</label>
      </div>

      <div>
        <p>Говорит само за себя.</p>
        <input type="checkbox" id="more-BB-Codes" data-setting="moreBBCodes" />
        <label for="more-BB-Codes">Дополнительные BB-Коды</label>
      </div>

      <div>
        <p>Позволяет предпросматривать отправляемые сообщения в лентах и блогах.</p>
        <input type="checkbox" id="comment-Preview" data-setting="commentPreview" />
        <label for="comment-Preview">Предпросмотр сообщений</label>
      </div>

      <div>
        <p>Позволяет "отвечать" и "цитировать" сообщения в лентах и блогах. При цитировании вы можете выделить кусочек 
        текста на который хотите ответить.</p>
        <input type="checkbox" id="more-Comment-Buttons" data-setting="moreCommentButtons" />
        <label for="more-Comment-Buttons">Кнопки "Отправить" и "Цитировать"</label>
      </div>

      <div>
        <p>Оборачивает предпросмотр письма в оболочку, похожую на ту которая во "Входящие".</p>
        <input type="checkbox" id="ls-Wrap-Preview" data-setting="lsWrapPreview" />
        <label for="ls-Wrap-Preview">Наглядный предпросмотр письма</label>
      </div>

    </div>

    <div id="modules-panel">

      <h2>Главное</h2>
      <div>
        <p>Постоянное отображание Панели Расширенных Настроек в Игровой. Сама по себе пустая.</p>
        <input type="checkbox" id="extended-settings-Panel" data-setting="extendedSettingsPanel" />
        <label for="extended-settings-Panel">⚙️Панель Расширенных Настроек</label>
      </div>

      <div>
        <p>Отображает уведомление в ⚙️Панели Расширенных настроек в Игровой.</p>
        <input type="checkbox" id="show-Update-Notification" data-setting="showUpdateNotification" />
        <label for="show-Update-Notification">Уведомлять об обновлении Скрипта/Мода UwU</label>
      </div>

      <div>
        <p>⚙️Панели Расширенных Настроек не будет так скучно с рандомными фразами.</p>
        <input type="checkbox" id="show-Splash-Screens" data-setting="showSplashScreens" />
        <label for="show-Splash-Screens">Показывать Splash надписи.</label>
      </div>

      <div>
        <p>Скрывать или отображать расширенные подсказки к настройкам. Привет, я та самая расширенная подсказка. Делает Настройки CatWar UwU очень компактным на вид.</p>
        <input type="checkbox" id="extended-Hints" data-setting="extendedHints" />
        <label for="extended-Hints">Расширенные подсказки</label>
      </div>

    <hr id="uwu-hr" class="uwu-hr">
      <h2>Сборник стилей</h2>
      <p>Онлайн сборник стилей от Разработчика.</p>
    <hr id="uwu-hr" class="uwu-hr">
      <div id="module-info">
        <!-- Сюда модули -->
      </div>

    <hr id="uwu-hr" class="uwu-hr">
      <h2>Импорт/Экспорт</h2>

      <div>
        <p>Импорт/Экспорт всех настроек (Пока без расставленных блоков Компактной Игровой, Сборника Стилей и Минного поля).</p>
        <input type="text" id="exportSettings" placeholder="Экспорт"/>
        <input type="text" id="importSettings" placeholder="Импорт"/>
        <button id="importSettingsButton" class="uwu-button install-button">Вставить</button>
      </div>
      
      <div>
        <p>Удаляет все настройки. В очень редких случаях может помочь при проблемных проблемах.</p>
        <button id="resetAllSaves" class="uwu-button remove-button">Сброс сохранений</button>
      </div>

    </div>

  </div>
  <hr id="uwu-hr" class="uwu-hr-head">
</div>
`;
// ====================================================================================================================
//   . . . HTML БЛОК НОВОСТЕЙ . . .
// ====================================================================================================================
const newsPanel = // html
`
<div id="news-panel">
    <button id="news-button">
        v${current_uwu_version} - 🎃 Полировочка.
    </button>
    <div id="news-list" style="display: none">
        <h3>Главное</h3>
        <p>— Ба бу бэ)) Часы теперь можно вставлять в блок Погоды, это затычка на крайняк.</p>
        <hr id="uwu-hr" class="uwu-hr">
        <h3>Внешний вид</h3>
        <p>— Текст в информации в "О коте" сдвинута к левому краю и сделалась чуть компактнее.</p>
        <p>— При выборе московского времени, "MSK" теперь пишется около значка откуда берётся время. 
        Ну те самые 🌍︎ или ⌨.</p>
        <p>— Небольшой редизайн кнопки разворачивания Минного Поля.</p>
        <p>— Цвет текста в Шаблонах стал белым. Извените кому нравилось цветное, как нибудь потом.</p>
        <hr id="uwu-hr" class="uwu-hr">
        <h3>Изменения кода</h3>
        <p>— Немного почистил и чёта там поменял с высотами панели БР. 
        Надеюсь кому-то чёта починило если нет то хихи хаха.</p>
        <p>— Починина подсветка ресурсов в режиме "Подсветка".</p>
        <p>— Теперь не будет использовать последний цвет из сохранения для подсветки всех ресурсов.</p>
        <p>— Немного переписан код Дублирования действий на вкладку, а так же + ...</p>
        <p>— ... теперь на название вкладки дублируется подняли ли вас, и кто поднял.</p>
        <p>— Убраны console.warn от установок прослушок из-за как таковой ненадобности в общем пользовании. 
        Консоль браузера теперь чистенькая 😊</p>
        <p>— Чуть переписаны handleCommentActions и toggleAurora афигеть как круто сделано вау надо чаще так делать.</p>
        <hr id="uwu-hr" class="uwu-hr">
        <p>Дата выпуска: 10.10.24</p>
    </div>
</div>
`;
// ====================================================================================================================
//   . . . HTML ПАНЕЛЬ РАСШИРЕННЫХ НАСТРОЕК . . .
// ====================================================================================================================
const extendedSettingsButton = // html
`
<div id="uwu-extended-settings">
  <button type="button" id="extended-settings-button">
    <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/partly_sunny_rain.png" alt="Иконка"
      width="36" height="36">
  </button>

  <div id="extended-settings-container">
    <div id="splash-screen-panel"></div>

  </div>
</div>
`;
// ====================================================================================================================
//   . . . HTML БЛОК РУЧНОГО УПРАВЛЕНИЯ ПОГОДЫ . . .
// ====================================================================================================================
const manualWeatherPanel = // html
`
<div id="manual-weather-panel">
<p>Изменения, сделанные в этой панели, носят временный характер и не сохраняются.</p>
<h3>Переключить погоду</h3>
<input type="range" min="1" max="3" value="1" class="uwu-range-slider" id="manualWeather" list="WeatherStep">
<datalist id="WeatherStep">
  <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/sunny.png" width="36" height="36" option
    value="1"></option>
  <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/rain_cloud.png" width="36" height="36"
    option value="2"></option>
  <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/snow_cloud.png" width="36" height="36"
    option value="3"></option>
</datalist>
<div id="temperature-container">
  <p id="temperature"
    title="На это умножается скорость частиц и делится их размер. В будущем будет возможность сохранять и изменять это значение под свой вкус.">
    [?] Текущий модификатор: ...уточнение...</p>
</div>

<h3>Северное Сияние</h3>
<div class="button-container-1">
  <button type="button" id="manualAurora-Off" class="uwu-button-round">
    <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/icons8-nothern-lights-96.png"
      alt="Иконка" width="48" height="48">
  </button>
  <button type="button" id="manualAurora-B" class="uwu-button-round">
    <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/icons8-nothern-lights-96_blue.png"
      alt="Иконка" width="48" height="48">
  </button>
  <button type="button" id="manualAurora-G" class="uwu-button-round">
    <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/icons8-nothern-lights-96_green.png"
      alt="Иконка" width="48" height="48">
  </button>
</div>

<h3>Светлячки</h3>
<div class="button-container-2">
  <button type="button" id="manualFirefly-On" class="uwu-button-round">
    <img src="https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/firefly.png" alt="Иконка" width="48"
      height="48" title="Включает/Выключает">
  </button>
</div>

</div>
<div id="aurora-settings-panel">
<p>Изменения, сделанные в этой панели, сохранятся!</p>
<h5>Здесь будет возможность переместить Северное Сияние в реальном времени, исключать локации из генерации погоды,
  либо запрещать
  определённой погоде существовать на выбранной локации. Но это всё пока что лишь мечта...</h5>
</div>
`;
// ====================================================================================================================
//   . . . ГЛАВНЫЙ CSS СТИЛЬ . . .
// ====================================================================================================================
// TODO - Унифицировать шрифты, цвета текстов, прозрачность, закруглённость штучек ну кароче всё как надо чтобы не сделать в итоге лабиринт.
const css_uwu_main =
`
#uwu-settings {
    margin-top: 10px;
    margin-bottom: 10px;
}

#uwusettings {
  font-family: "Montserrat", sans-serif;
  margin: 0 auto;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}
.main-settings-container {
  padding: 10px 15px 10px 15px;
}

#uwusettings-main {
  padding: 0px 15px 0px 15px;
}

#news-panel {
  padding: 5px 15px 15px 15px;
}

#uwu-what-this {
  color: #83e5ff;
  font: caption;
}

.main-settings-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
}

#uwusettings h1,
#uwusettings h2 {
  font-family: "Montserrat", sans-serif;
  margin-top: 10px;
  margin-bottom: 15px;
  text-align: center;
}

#uwusettings h4 {
  margin-top: 5px;
  margin-left: 5px;
  margin-bottom: 5px;
}

#uwusettings p {
  margin-bottom: 0px;
}

#uwusettings label {
  font-size: 16px;
}

#uwusettings ul {
  font-family: "Montserrat", sans-serif;
  list-style-type: "+ ";
}

.uwu-hr-head {
  border: rgba(255, 255, 255, 0.1) solid;
  border-radius: 0px;
}

.uwu-hr {
  border: rgba(255, 255, 255, 0.1) solid;
  border-radius: 15px;
}

#uwusettings .parameters-color-table,
#uwusettings .parameters-color-table tr,
#uwusettings .parameters-color-table td {
  border: 1px #383838 solid;
}

#colorSettingsTable,
#colorSettingsTable tr,
#colorSettingsTable td {
  border: 1px #383838 solid;
}

.uwu-table-highlight-Resources,
#uwu-table-templates {
  margin-top: 5px;
}
.uwu-table-highlight-Resources th, .uwu-table-highlight-Resources td,
#uwu-table-templates th, #uwu-table-templates td {
  border: 1px solid #383838;
}

.uwu-color-picker {
  border: none;
  vertical-align: middle;
}

.uwu-checkbox-cell {
  text-align: center;
  vertical-align: middle;
}

#uwusettings .parameters-color-table,
#colorSettingsTable {
  margin-top: 8px;
}

.header-rounded-image {
  background-repeat: repeat;
  background-attachment: fixed;
  border-radius: 20px 20px 0px 0px;
}

.main-rounded-image {
  background-repeat: repeat;
  background-attachment: fixed;
  border-radius: 20px;
}

#button-container-1 {
  display: flex;
  justify-content: space-evenly;
  width: 100%;
}

#button-container button {
  background-color: transparent;
  border: none;

  color: #ffffff57;

  padding: 10px 20px;
  cursor: pointer;
  transition: box-shadow 0.4s ease;
}

#button-container button.active {
  box-shadow: inset 0 -2px 0 0 #ffffff4d;
  transition: box-shadow 0.4s ease;
}

#button-container button.active h2 {
  color: #ffffff;
  transition: color 0.4s ease;
}

#modules-panel {
  display: none;
}

.module-container {
  width: 300px;
  min-height: 150px;
  position: relative;

  box-sizing: border-box;
  margin: 10px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 15px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  background-color: rgba(255, 255, 255, 0.03);
}

.module-info {
  flex-grow: 1;
  margin-bottom: 10px;
}

.module-panel {
  display: flex;
  justify-content: space-between;
  align-items: center;

  position: absolute;
  bottom: 10px;
  left: 10px;
  right: 10px;
}

#module-info {
  flex-grow: 1;
  margin-bottom: 10px;

  display: flex;
  flex-wrap: wrap;
  flex-basis: 100%;
}

.module-container label {
  margin-top: 10px;
}

#private-module-input {
  margin: 10px;
}

.module-container button {
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 5px 10px;
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 5px;
}

.install-button {
  background-color: #78c8ff87 !important;
}

.remove-button {
  background-color: #ff787887 !important;
}

#module-info input[type="checkbox"] {
  margin: 10px;
}

#color-picker {
  display: flex;
  flex-wrap: wrap;
}

#color-picker-input {
  flex: 30%;
}

#auroraPanel {
  width: 120px;
}

#notification-volume,
#step-slider {
  width: 150px;
}

#layout-preview button {
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 5px 10px;
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 5px;
}

#layout-customizer #layout-preview {
  display: flex;
  justify-content: center;
  margin-bottom: 1rem;
}

#layout-customizer .column {
  width: 200px;
  border: 1px solid #ffffff1a;
  border-radius: 10px;
  padding: 5px;
  margin: 0 5px;
}

#layout-customizer .block {
  border-radius: 10px;
  background-color: #ffffff08;
  padding: 5px;
  margin-bottom: 5px;
}

#layout-customizer .center-block {
  height: 100%;
  box-sizing: border-box;

  border-radius: 10px;
  background-color: #ffffff08;
}

#uwu-buttonRow1-settings,
#uwu-buttonRow2-settings {
  display: flex;
  margin-top: 3px;
}

#uwu-buttonRow1-settings button,
#uwu-buttonRow2-settings button  {
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 2px 10px;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 3px;
  margin-left: 0px;
}

#uwu-buttonRow1-settings > div > button.tab-button.active, #uwu-buttonRow2-settings > div > button.table-button.active {
  background-color: #abf6ffb0;
}

#uwu-buttonRow1-settings > .tab-container,
#uwu-buttonRow2-settings > .table-container {
  border-radius: 15px;
  background-color: #54545473;
  margin-right: 5px;
  padding-left: 4px;
  padding-right: 2px;
  padding-top: 2px;
  border-bottom-width: 2px;
  padding-bottom: 2px;
}

#uwu-global-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}

#uwu-main-container {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  pointer-events: none;
}

.weatherCanvas {
  pointer-events: none;
  position: fixed;
}

#extended-settings-button {
  position: fixed;
  bottom: 30px;
  right: 30px;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  backdrop-filter: blur(16px);
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: auto;
  cursor: pointer;

  background-color: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 2em;
  font-weight: bold;
  color: #ff00ff;
}

#extended-settings-container {
  font-family: "Montserrat", sans-serif;
  color: white;
  font-size: 15px;
  text-align: center;

  position: fixed;
  bottom: 100px;
  right: 30px;
  width: 400px;
  height: 400px;
  backdrop-filter: blur(16px);
  border-radius: 10px;
  display: none;
  pointer-events: auto;

  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);

  display: grid;
  place-items: center;
  padding: 15px;
  box-sizing: border-box;
  overflow-y: auto;
}

.extended-settings-block {
  border-radius: 10px;
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 5px;
  margin-bottom: 8px;
}

#news {
  margin-top: 20px;
}

#manual-weather-panel,
#news,
#news-button {
  width: 100%;
  border-radius: 10px;

  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);

  padding: 15px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  box-sizing: border-box;
}

#color-picker {
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);

  margin-top: 10px;
  padding: 15px;
  border-radius: 10px;
}

#news-button,
#news-list {
  font-family: "Montserrat", sans-serif;
  font-size: 15px;
  cursor: pointer;
}

#news-list h3 {
  margin-left: 40px;
}

#news-list p {
  margin-top: 3px;
  margin-bottom: 3px;
  margin-left: 20px;
}

#aurora-settings-panel {
  width: 100%;
  border-radius: 10px;

  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);

  padding: 15px;
  margin-top: 20px;
  box-sizing: border-box;
}

#WeatherStep,
#auroraStep,
#volumeStep,
#ThicknessStep,
.uwu-range-step {
  margin-top: 10px;
  display: flex;
  justify-content: space-between;
  width: 100%;
}

#extended-settings-container::-webkit-scrollbar {
  width: 10px;
}

#extended-settings-container::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}

#extended-settings-container::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3);
  border-radius: 4px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  cursor: pointer;
}

#extended-settings-container::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.4);
}

#button-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  width: 100%;
}

.button-container-1 {
  display: flex;
  justify-content: space-between;
  width: 100%;
}

.button-container-2 {
  display: flex;
  justify-content: space-evenly;
  width: 100%;
}

.uwu-button-round {
  width: 60px;
  height: 60px;
  cursor: pointer;
  border-radius: 50%;

  background-color: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

#extended-settings-button:hover,
.uwu-button-round:hover {
  background-color: rgba(255, 255, 255, 0.15);
}

@property --gradient-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@keyframes aurora-spin {
  0% {
    --gradient-angle: 0deg;
  }

  100% {
    --gradient-angle: 360deg;
  }
}

@keyframes auroraFadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes auroraFadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.firefly {
  position: fixed;
  background-color: rgba(255, 255, 153, 1);
  border-radius: 50%;
  filter: blur(5px);
  pointer-events: none;

  animation: fadeIn 6s ease-in-out;
}

.firefly-glow {
  position: fixed;
  background-color: rgba(255, 255, 153, 0.2);
  border-radius: 50%;
  filter: blur(40px);
  pointer-events: none;

  animation: fadeIn 6s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.firefly-disappearing {
  animation: fadeOut 6s ease-in-out forwards;
}

.custom-select {
  position: relative;
  display: inline-block;
}

.select-selected, .uwu-select-selected {
  margin-top: 10px;
  width: fit-content;
  border-radius: 10px;
  color: white;
  background-color: #5c5c5c;
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px); 
  padding: 10px;
  cursor: pointer;
}

.uwu-select-selected {
  width: fit-content;
}

.select-items, uwu-select-items {
  margin-top: 5px;
  display: none;
  position: absolute;
  border-radius: 10px;
  width: max-content;
  color: white;
  background-color: #5c5c5c;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px); 
  z-index: 1;
}

.select-items div {
  padding: 8px 16px;
  cursor: pointer;
}

.select-items div:hover {
  background-color: #757575;
}

.custom-select.active .select-items {
  display: block;
}

#climbingRefreshNotificationSoundContainer button,
#myNameNotificationSoundContainer button {
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 2px 10px;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 3px;
  margin-left: 0px;
}

#climbingRefreshNotificationSoundContainer,
#myNameNotificationSoundContainer {
  gap: 5px;
  display: flex;
  align-items: center;
}

.update-notification {
  background-color: #78c8ff69;
  padding: 10px;
  border-radius: 10px;
  margin-bottom: 10px;
}

.new-update::before {
  content: "•";
  color: #78c8ff;
  font-size: 2em;
  position: absolute;
  top: -20px;
  right: -5px;
}

.random-phrase-block {
  margin-bottom: 10px;
  width: 100%;
  border-radius: 10px;

  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);

  box-sizing: border-box;
  padding: 5px;
}

`;

document.head.insertAdjacentHTML(
  "beforeend",
  `<style id="css-uwu-main">${css_uwu_main}</style>`
);

// ====================================================================================================================
//   . . . ПРОЗРАЧНЫЙ CSS СТИЛЬ . . .
// ====================================================================================================================
// Glassmorphism вперёд Glassmorphism вперёд Glassmorphism вперёд Glassmorphism вперёд Glassmorphism вперёд
const css_uwu_glass = // css
`
#uwusettings {
  backdrop-filter: blur(16px);
  background-color: rgba(255, 255, 255, 0.03);
}

.uwu-button {
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 8px 15px;
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 5px;
  margin-left: 0px;
  color: #d5d5d5;
}

.uwu-button:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.uwu-range-slider {
  width: 100%;
  cursor: pointer;
  -webkit-appearance: none;
  background-color: rgba(255, 255, 255, 0.06) !important;
  border: 1px solid rgba(255, 255, 255, 0.1) !important;
  border-radius: 10px;
  height: 10px;
  outline: none;
}

.uwu-range-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  cursor: pointer;
}

.uwu-range-slider::-webkit-slider-thumb {
  transform: translateY(-35%);
}

#uwusettings input[type="checkbox"] {
  margin-right: 8px;
  appearance: none;
  transform: translate(-10%, 30%);
  width: 35px;
  height: 18px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
}

#uwusettings input[type="checkbox"]:checked {
  background-color: #90ff78a8;
}

#uwusettings input[type="checkbox"]:not(:checked) {
  background-color: rgba(255, 255, 255, 0.1);
}

#uwusettings input[type="checkbox"]:before {
  content: "";
  position: absolute;
  top: 50%;
  left: 4px;
  transform: translate(-50%, -50%);
  width: 25px;
  height: 25px;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: background-color 0.2s ease-in-out, left 0.2s ease-in-out;
}

#uwusettings input[type="checkbox"]:checked:before {
  left: calc(100% - 4px);
}

#uwusettings input[type="text"] {
  width: 150px;
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 8px;
  border-radius: 10px;
  outline: none;
  margin: 5px;
  margin-left: 0px;
}
`;
// ====================================================================================================================
//   . . . ТЁМНАЯ ТЕМА . . .
// ====================================================================================================================
const css_uwu_dark = // css
`
#uwusettings {
  background-color: #242424;
  color: #dddddd;
}

#uwusettings-header-glass {
  border-radius: 20px 20px 0px 0px;
  backdrop-filter: blur(16px) brightness(0.9);
}

#news-button {
  color: #dddddd;
}

.uwu-button {
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 8px 15px;
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 5px;
  margin-left: 0px;
}

.uwu-button:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.uwu-range-slider {
  width: 100%;
  cursor: pointer;
  -webkit-appearance: none;
  background-color: rgba(255, 255, 255, 0.06) !important;
  border: 1px solid rgba(255, 255, 255, 0.1) !important;
  border-radius: 10px;
  height: 10px;
  outline: none;
}

.uwu-range-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  cursor: pointer;
}

.uwu-range-slider::-webkit-slider-thumb {
  transform: translateY(-35%);
}

#uwusettings input[type="checkbox"] {
  margin-right: 8px;
  appearance: none;
  transform: translate(-10%, 30%);
  width: 35px;
  height: 18px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
}

#uwusettings input[type="checkbox"]:checked {
  background-color: #90ff78a8;
}

#uwusettings input[type="checkbox"]:not(:checked) {
  background-color: rgba(255, 255, 255, 0.1);
}

#uwusettings input[type="checkbox"]:before {
  content: "";
  position: absolute;
  top: 50%;
  left: 4px;
  transform: translate(-50%, -50%);
  width: 25px;
  height: 25px;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: background-color 0.2s ease-in-out, left 0.2s ease-in-out;
}

#uwusettings input[type="checkbox"]:checked:before {
  left: calc(100% - 4px);
}

#uwusettings input[type="text"] {
  width: 150px;
  background-color: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 8px;
  border-radius: 10px;
  outline: none;
  margin: 5px;
  margin-left: 0px;
}
`;
// ====================================================================================================================
//   . . . КЛАССИЧЕСКАЯ ТЕМА . . .
// ====================================================================================================================
// лол а где
const css_uwu_classic = `

`;
// ====================================================================================================================
//   . . . топовой шрифт кто не согласен тому в глаз 👅👅👅👅👅👅бе бе бе мяу мяу мяу мяу мяу мяу . . .
// ====================================================================================================================
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css?family=Montserrat';
document.head.appendChild(link);
// TODO - автоматически подкачивать шрифты нужные пользователю по названию в "Название вида шрифта" в Настройках
// ====================================================================================================================
//  . . . СОХРАНЕНИЯ И ЗАГРУЗКА НАСТРОЕК . . .
// ====================================================================================================================
let settings;

function saveSettings() {
  try {
    localStorage.setItem("uwu_settings", JSON.stringify(settings));
    // console.log("Настройки сохранены:", settings);
  } catch (error) {
    console.error("Не удалось сохранить настройки:", error);
  }
}

function loadSettings() {
  const storedSettings = localStorage.getItem("uwu_settings");
  if (storedSettings && typeof storedSettings === "string") {
    const loadedSettings = JSON.parse(storedSettings);
    settings = { ...uwuDefaultSettings, ...loadedSettings };
  } else {
    settings = { ...uwuDefaultSettings };
    console.log("Нет сохраненных настроек");
  }
}
// ====================================================================================================================
//   . . . ДИНАМИЧНЫЕ ОБОЗРЕВАТЕЛИ . . .
// ====================================================================================================================
function debounce(func, wait) {
  let timeout;
  return function (...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

// Когда нужно вставить прослушку на какой-то элемент, который ещё не успел появиться.
async function setupMutationObserver(
  selector,
  callback,
  options = { attributes: true, attributeFilter: ["style"] },
  maxAttempts = 8,
  delay = 500,
  debounceTime = 100,
) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const element = document.querySelector(selector);
    if (element) {
      const observer = new MutationObserver(debounce(callback, debounceTime));
      observer.observe(element, options);
      // console.log(`Наблюдатель установлен для элемента с селектором "${selector}".`);
      callback();
      return;
    }
    await new Promise((resolve) => setTimeout(resolve, delay));
  }
  // console.warn(
  //   `Элемент с селектором "${selector}" не найден после ${maxAttempts} попыток.`
  // );
}

// Когда нужно вставить что-то в какой-то элемент, который ещё не успел появиться.
async function setupSingleCallback(
  selector,
  callback,
  maxAttempts = 8,
  delay = 500,
) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const element = document.querySelector(selector);
    if (element) {
      callback();
      return;
    }
    await new Promise((resolve) => setTimeout(resolve, delay));
  }
  // console.warn(
  //   `Элемент с селектором "${selector}" не найден после ${maxAttempts} попыток.`
  // );
}
// ====================================================================================================================
//   . . . СОХРАНЕНИЕ И РАБОТА С ЦВЕТОВЫМИ ТЕМАМИ . . .
// ====================================================================================================================
function getThemes() {
  const storedThemes = localStorage.getItem("uwu_colorThemes");
  const userThemes = storedThemes ? JSON.parse(storedThemes) : {};
  return { ...userThemes, ...defaultThemes };
}

function saveThemes(themes) {
  const themesToSave = Object.keys(themes)
    .filter(themeName => !isDefaultTheme(themeName))
    .reduce((obj, key) => {
      obj[key] = themes[key];
      return obj;
    }, {}); 

  localStorage.setItem("uwu_colorThemes", JSON.stringify(themesToSave));
}

function getCurrentThemeName() {
  return localStorage.getItem("uwu_currentTheme") || "Тёмная Тема";
}

function setCurrentThemeName(themeName) {
  localStorage.setItem("uwu_currentTheme", themeName);
}

function isDefaultTheme(themeName) {
  return Object.keys(defaultThemes).includes(themeName);
}

function updateSaveButtonState() {
  saveThemeButton.disabled = isDefaultTheme(currentThemeName);
}

// ====================================================================================================================
//  . . . ВНЕШНИЙ ВИД ПАНЕЛИ НАСТРОЕК . . .
// ====================================================================================================================
function applyBackgroundImage(element, backgroundImage) {
  element.style.backgroundImage = backgroundImage;
}

function createSettingsBlock(blockId, content) {
  const siteTable = document.querySelector("#site_table");
  const isMobile = siteTable.getAttribute("data-mobile") === "0";

  const settingsElement = document.createElement("div");
  settingsElement.id = blockId;
  settingsElement.innerHTML = content;

  const settingsContainer = isMobile
    ? document.querySelector("#branch")
    : siteTable;
  settingsContainer.appendChild(settingsElement);
}
// ====================================================================================================================
//  . . . РАБОТА ПАНЕЛИ НАСТРОЕК . . .
// ====================================================================================================================
if (targetSettings.test(window.location.href)) {
  createSettingsBlock("uwu-settings", uwusettings);

  const uwuSettingsElement = document.getElementById("uwusettings");
  if (uwuSettingsElement) {
    uwuSettingsElement.insertAdjacentHTML("beforeend", newsPanel);
  }

  loadSettings();

  if (!settings.extendedHints) {
    const uwuHideHints = document.createElement("style");
    uwuHideHints.innerHTML = `
    #uwusettings p {
      display: none;
    }
    `;
    document.head.appendChild(uwuHideHints);
  }

  document
    .querySelectorAll("#uwusettings [data-setting]")
    .forEach((element) => {
      const setting = element.dataset.setting;
      if (element.type === "checkbox") {
        element.checked = settings[setting];
      } else {
        element.value = settings[setting];
      }
    });

  // ====================================================================================================================
  //  . . . ТЕМА UWU . . .
  // ====================================================================================================================
  function applySettingsTheme(theme) {
    let css;
    const settingsBlock = document.getElementById("uwu-settings");
    const settingsHeader = document.getElementById("uwusettings-header");
  
    switch (theme) {
      case "classic":
        css = css_uwu_classic;
        break;
      case "dark":
        css = css_uwu_dark;
        const backgroundImageDark = window.getComputedStyle(document.body).backgroundImage;
        applyBackgroundImage(settingsHeader, backgroundImageDark);
        settingsHeader.classList.add("header-rounded-image");
        break;
      case "glass":
        css = css_uwu_glass;
        const backgroundImageGlass = window.getComputedStyle(document.body).backgroundImage;
        applyBackgroundImage(settingsBlock, backgroundImageGlass);
        settingsBlock.classList.add("main-rounded-image");
        break;
      default:
        css = css_uwu_classic;
        break;
    }
  
    const oldStyle = document.getElementById("css-uwu-theme");
    if (oldStyle) {
      oldStyle.remove();
    }
  
    document.head.insertAdjacentHTML(
      "beforeend",
      `<style id="css-uwu-theme">${css}</style>`
    );
  }
  
  applySettingsTheme(settings.settingsTheme);
  // ====================================================================================================================
  //  . . . ШРИФТ ГРОМКОСТИ ЧАТА . . .
  // ====================================================================================================================
  function saveFontSettings() {
    let fontSize = {};
  
    document.querySelectorAll('input[data-font-size]').forEach(input => {
      fontSize[input.dataset.fontSize] = input.value;
    });
  
    localStorage.setItem('uwu_fontSize', JSON.stringify(fontSize));
  }
  
  function loadFontSettings() {
    let defaultFontSize = {
      vlm0: '10',
      vlm1: '11',
      vlm2: '11.5',
      vlm3: '12',
      vlm4: '12.5',
      vlm5: '13',
      vlm6: '15',
      vlm7: '17',
      vlm8: '19',
      vlm9: '21',
      vlm10: '23',
      fontSizeBody: '14',
      fontSizeSmall: '12',
      fontSizeLocation: '14',
      fontFamilyBody: 'Verdana'
    };
  
    let fontSize = JSON.parse(localStorage.getItem('uwu_fontSize')) || defaultFontSize;
  
    document.querySelectorAll('input[data-font-size]').forEach(input => {
      input.value = fontSize[input.dataset.fontSize] || ''; 
    });

    saveFontSettings();
  }
  
  document.querySelectorAll('input[data-font-size]').forEach(input => {
    input.addEventListener('input', saveFontSettings); 
  });
  
  loadFontSettings();
  // ====================================================================================================================
  //  . . . ТЕМЫ И ЦВЕТА ИГРОВОЙ . . .
  // ====================================================================================================================
  const colorInputs = document.querySelectorAll("#color-picker input[type='text']");
  const saveThemeButton = document.getElementById("saveThemeButton");
  const themeSelect = document.getElementById("theme-select");
  const addThemeButton = document.getElementById("addThemeButton");
  const removeThemeButton = document.getElementById("removeThemeButton");
  
  let currentThemeName = getCurrentThemeName();
  let allThemes = getThemes();
  
  function loadThemeToInputs(themeName) {
    const theme = allThemes[themeName]?.colors;
    colorInputs.forEach((input) => {
      const colorKey = input.dataset.color;
      input.value = theme?.[colorKey] || "";
    });
  }
  
  function saveThemeFromInputs() {
    const themeData = { colors: {} };
    colorInputs.forEach((input) => {
      const colorKey = input.dataset.color;
      themeData.colors[colorKey] = input.value;
    });
    allThemes[currentThemeName] = themeData; 
    saveThemes(allThemes);
    console.log(`Тема "${currentThemeName}" сохранена!`);
  }
  
  function updateThemeSelect() {
    themeSelect.innerHTML = "";
    Object.keys(allThemes).forEach((name) => {
      const option = document.createElement("option");
      option.value = name;
      option.textContent = name;
      themeSelect.appendChild(option);
    });
    themeSelect.value = currentThemeName;
    removeThemeButton.style.display = Object.keys(defaultThemes).includes(currentThemeName) ? "none" : "inline";
  }
  
  themeSelect.addEventListener("change", (event) => {
    currentThemeName = event.target.value;
    setCurrentThemeName(currentThemeName);
    loadThemeToInputs(currentThemeName);
    updateThemeSelect(); 
    updateSaveButtonState();
  });
  
  addThemeButton.addEventListener("click", () => {
    const newThemeName = prompt("Введите название новой темы:");
    if (newThemeName && !allThemes[newThemeName]) {
      allThemes[newThemeName] = { colors: {} };
      saveThemes(allThemes);
      updateThemeSelect();
      themeSelect.value = newThemeName;
      currentThemeName = newThemeName;
      setCurrentThemeName(currentThemeName);
      loadThemeToInputs(currentThemeName);
    }
  });
  
  removeThemeButton.addEventListener("click", () => {
    if (!Object.keys(defaultThemes).includes(currentThemeName)) {
      delete allThemes[currentThemeName];
      saveThemes(allThemes);
      currentThemeName = "Тёмная Тема";
      setCurrentThemeName(currentThemeName);
      updateThemeSelect();
      loadThemeToInputs(currentThemeName);
    }
  });
  
  saveThemeButton.addEventListener("click", () => {
    if (isDefaultTheme(currentThemeName)) {
      alert("Вы не можете изменять стандартные темы. Пожалуйста, создайте свою собственную тему.");
    } else {
      saveThemeFromInputs();
    }
  });
  
  colorInputs.forEach((input) => {
    input.addEventListener("input", () => {
      if (isDefaultTheme(currentThemeName)) {
        alert("Вы не можете изменять стандартные темы. Пожалуйста, создайте свою собственную тему.");
        loadThemeToInputs(currentThemeName); 
      } else {
        saveThemeFromInputs(); 
      }
    });
  });
  
  updateThemeSelect();
  loadThemeToInputs(currentThemeName);
  // ====================================================================================================================
  //  . . . РАБОТА ЦВЕТОВ НАВЫКОВ И ПАРАМЕТРОВ . . .
  // ====================================================================================================================
  document
    .querySelectorAll('#parameters-color-settings input[type="color"]')
    .forEach((element) => {
      element.addEventListener("change", () => {
        const paramId = element.dataset.param;
        const colorType = element.dataset.colorType;
        const colorValue = element.value;

        if (!settings.parametersColors[paramId]) {
          settings.parametersColors[paramId] = [];
        }
        const colorIndex =
          colorType === "bar-from"
            ? 0
            : colorType === "bar-to"
            ? 1
            : colorType === "bg-from"
            ? 2
            : 3;
        settings.parametersColors[paramId][colorIndex] = colorValue;

        saveSettings();
      });
    });

  function restoreColorPickers() {
    for (const paramId in settings.parametersColors) {
      const colors = settings.parametersColors[paramId];

      const barFromInput = document.querySelector(
        `#parameters-color-settings input[type="color"][data-param="${paramId}"][data-color-type="bar-from"]`
      );
      const barToInput = document.querySelector(
        `#parameters-color-settings input[type="color"][data-param="${paramId}"][data-color-type="bar-to"]`
      );
      const bgFromInput = document.querySelector(
        `#parameters-color-settings input[type="color"][data-param="${paramId}"][data-color-type="bg-from"]`
      );
      const bgToInput = document.querySelector(
        `#parameters-color-settings input[type="color"][data-param="${paramId}"][data-color-type="bg-to"]`
      );

      if (barFromInput) barFromInput.value = colors[0];
      if (barToInput) barToInput.value = colors[1];
      if (bgFromInput) bgFromInput.value = colors[2];
      if (bgToInput) bgToInput.value = colors[3];
    }
  }
  restoreColorPickers();
  // ====================================================================================================================
  //  . . . ПОДСВЕТКА РЕСУРСОВ . . .
  // ====================================================================================================================
  function saveHighlightSettings() {
    const highlightResources = [];
  
    document.querySelectorAll('.uwu-table-highlight-Resources tbody tr').forEach(row => {
      const resourceName = row.querySelector('.uwu-color-picker').dataset.resource;
      const colorPicker = row.querySelector('.uwu-color-picker');
      const checkbox = row.querySelector('.uwu-highlight-checkbox');
  
      const resource = {
        name: resourceName,
        color: colorPicker.value,
        highlight: checkbox.checked
      };
  
      highlightResources.push(resource);
    });
  
    localStorage.setItem('uwu_highlightResources', JSON.stringify(highlightResources));
  }
  
  function restoreHighlightSettings() {
    const savedSettings = localStorage.getItem('uwu_highlightResources');
    if (savedSettings) {
      const highlightResources = JSON.parse(savedSettings);
  
      highlightResources.forEach(resource => {
        const colorPicker = document.querySelector(`.uwu-color-picker[data-resource="${resource.name}"]`);
        const checkbox = document.querySelector(`.uwu-highlight-checkbox[data-resource="${resource.name}"]`);
  
        if (colorPicker) colorPicker.value = resource.color;
        if (checkbox) checkbox.checked = resource.highlight;
      });
    }
  }

restoreHighlightSettings();

document.querySelectorAll('.uwu-color-picker').forEach(element => {
  element.addEventListener('input', saveHighlightSettings);
});

document.querySelectorAll('.uwu-highlight-checkbox').forEach(element => {
  element.addEventListener('change', saveHighlightSettings);
});

  // ====================================================================================================================
  //  . . . ЦВЕТА КОМАНДНЫХ БОЁВ . . .
  // ====================================================================================================================
  document
    .querySelectorAll('#colorSettingsTable input[type="color"]')
    .forEach((element) => {
      element.addEventListener("change", () => {
        const team = `team${element.dataset.team}`;
        const part = element.dataset.part === "green" ? 0 : 1;
        const colorValue = element.value;
        settings.fightTeamsColors[team][part] = colorValue;
        saveSettings();
      });
    });

  function restoreColorTeamsPickers() {
    document
      .querySelectorAll('#colorSettingsTable input[type="color"]')
      .forEach((element) => {
        element.addEventListener("change", () => {
          const team = `team${element.dataset.team}`;
          const part = element.dataset.part === "green" ? 0 : 1;
          const colorValue = element.value;
          settings.fightTeamsColors[team][part] = colorValue;
          saveSettings();
        });
      });
  }

  restoreColorTeamsPickers();
  // ====================================================================================================================
  //   . . . СБРОС НАСТРОЕК . . .
  // ====================================================================================================================
  const settingsKeys = [
    "uwu_settings",
    "uwu_version",
    "uwu_layoutSettings",
    "uwu_climbingPanelState",
    "uwu_moduleStates",
    "uwu_fightPanelPosition",
    "uwu_climbingPanelStatus",
    "uwu_privateModules",
    "uwu_colorThemes",
    "uwu_currentTheme",
    "uwu_fontSize",
    "uwu_clock",
  ];

  function resetAllSaves() {
    const confirmReset = confirm(
      "Точно сбросить все UwU Настройки? Это удалить даже ваши карты Минных полей, темы и многое другое!"
    );
    if (confirmReset) {
      settingsKeys.forEach((key) => {
        localStorage.removeItem(key);
        console.log(`Удалено ${key}`);
      });
      console.log("Все настройки сброшены");
    } else {
      console.log("Сброс настроек отменен");
    }
  }

  document
    .getElementById("resetAllSaves")
    .addEventListener("click", resetAllSaves);
  // ====================================================================================================================
  //  . . . ВЗАИМОИСКЛЮЧАЮЩИЕСЯ ЧЕКБОКСЫ . . .
  // ====================================================================================================================
  const exclusiveCheckboxGroups = [
    ["backgroundRepeat", "backgroundUser"],
    ["parametersBackgroundImage", "parametersUserBackgroundImage"],
  ];

  document
    .querySelectorAll("#uwusettings [data-setting]")
    .forEach((element) => {
      const setting = element.dataset.setting;
      element.addEventListener("change", () => {
        if (element.type === "checkbox") {
          const group = exclusiveCheckboxGroups.find((g) =>
            g.includes(setting)
          );
          if (group) {
            group.forEach((s) => {
              if (s !== setting) {
                settings[s] = false;
                document.querySelector(
                  `#uwusettings [data-setting="${s}"]`
                ).checked = false;
              }
            });
          }
          settings[setting] = element.checked;
        } else {
          settings[setting] = element.value;
        }
        saveSettings();
      });
    });
  // ====================================================================================================================
  //  . . . СОЗДАНИЕ ВЫПАДАЮЩИХ СПИСКОВ ПРИ ПОМОЩИ ФУНКЦИИ createCustomSelect . . .
  // ====================================================================================================================
  loadSettings();
  // Звуки звуки звуки, вуху.
  const notificationSounds = [
    { name: "Звук 1", id: "notificationSound1" },
    { name: "Звук 2", id: "notificationSound2" },
    { name: "Звук 3", id: "notificationSound3" },
  ];

  createCustomSelect("climbingRefreshNotificationSound", notificationSounds);
  createCustomSelect("myNameNotificationSound", notificationSounds);
  // ==============================================================================
  const howShowOtherCatsList = [
    { name: "Не отображать", id: "1" },
    { name: "Компактно", id: "2" },
    { name: "Целиком", id: "3" },
  ];

  createCustomSelect("showOtherCatsList", howShowOtherCatsList);
  // ==============================================================================
  const themeOptions = [
    { id: "classic", name: "Классическая" },
    { id: "dark", name: "Тёмная" },
    { id: "glass", name: "Стеклянная" },
  ];
  
  createCustomSelect("settingsTheme", themeOptions);
  // ==============================================================================
  const climbingPanelOrientations = [
    { id: "vertical", name: "Вертикальный" },
    { id: "horizontal", name: "Горизонтальный" },
  ]

  createCustomSelect("climbingPanelOrientation", climbingPanelOrientations);
    // ==============================================================================
    const clockStyles = [
      { id: "compact", name: "Компактный" },
      { id: "standard", name: "Стандартный" },
    ]
  
    createCustomSelect("clockStyle", clockStyles);
    // ==============================================================================
    const clockPositions = [
      { id: "fly", name: "Свободно" },
      { id: "tos", name: "В блоке погоды" },
    ]
  
    createCustomSelect("clockPosition", clockPositions);
    // ==============================================================================
    const highlightResourcesStyles = [
      { id: "background", name: "Фон / Быстро" },
      { id: "glow", name: "Свечение / Медленно" },
    ]
    
    createCustomSelect("highlightResourcesStyle", highlightResourcesStyles);
  // ====================================================================================================================
  //   . . . СОЗДАНИЕ ВЫПАДАЮЩИХ СПИСКОВ . . .
  // ====================================================================================================================
  function createCustomSelect(selectId, options) {
  
    const selectContainer = document.getElementById(selectId);
    const selectedElement = selectContainer.querySelector(".select-selected");
    const optionsContainer = selectContainer.querySelector(".select-items");
  
    if (settings && settings[selectId] !== undefined) {
      const selectedOption = options.find(
        (option) => option.id === settings[selectId]
      );
      if (selectedOption) {
        selectedElement.textContent = selectedOption.name;
      }
    }
  
    options.forEach((option, index) => {
      const optionElement = document.createElement("div");
      optionElement.textContent = option.name;
      optionElement.dataset.id = option.id;
  
      optionElement.addEventListener("click", () => {
        selectedElement.textContent = option.name;
        settings[selectId] = option.id;
        saveSettings();
        selectContainer.classList.remove("active");
      });
  
      optionsContainer.appendChild(optionElement);
    });
  
    selectedElement.addEventListener("click", () => {
      selectContainer.classList.toggle("active");
    });
  }
  // ====================================================================================================================
  //  . . . КНОПКА НОВОСТЕЙ . . .
  // ====================================================================================================================
  window.addEventListener("load", () => {
    const newsButton = document.getElementById("news-button");
    const newsList = document.getElementById("news-list");

    if (newsButton && newsList) {
      newsButton.addEventListener("click", () => {
        if (newsList.style.display === "none") {
          newsList.style.display = "block";
        } else {
          newsList.style.display = "none";
        }
      });
    }
  });
  // ====================================================================================================================
  //   . . . КНОПКА ТЕСТА ЗВУКОВ . . .
  // ====================================================================================================================
  function addSoundTestButton(
    containerId,
    settingsKeyForSound,
    settingsKeyForVolume
  ) {
    const container = document.getElementById(containerId);
    if (!container) {
      console.error(`Контейнер с ID ${containerId} не найден.`);
      return;
    }

    const testButton = document.createElement("button");
    testButton.textContent = "Тест звука";
    testButton.addEventListener("click", () => {
      const selectedSoundId = settings[settingsKeyForSound];
      const volume = settings[settingsKeyForVolume] || 5;
      if (selectedSoundId) {
        soundManager.playSound(selectedSoundId, volume);
      } else {
        console.error(
          `Выбранный звук для контейнера ${containerId} не найден.`
        );
      }
    });

    container.appendChild(testButton);
  }

  addSoundTestButton(
    "climbingRefreshNotificationSoundContainer",
    "climbingRefreshNotificationSound",
    "climbingRefreshNotificationVolume"
  );
  addSoundTestButton(
    "myNameNotificationSoundContainer",
    "myNameNotificationSound",
    "notificationMyNameVolume"
  );
  // ====================================================================================================================
  //  . . . СБРОС ПОЗИЦИИ ЧАСИКОВ . . .
  // ====================================================================================================================
  document.getElementById('resetClockPosition').addEventListener('click', () => {
    const defaultPosition = { x: 10, y: 10 };
    localStorage.setItem("uwu_clock", JSON.stringify(defaultPosition));
  });
  // ====================================================================================================================
  //  . . . ИМПОРТ / ЭКСПОРТ НАСТРОЕК . . .
  // ====================================================================================================================
  const importButton = document.getElementById("importSettingsButton");
  const importSettingsInput = document.getElementById("importSettings");
  const exportSettingsInput = document.getElementById("exportSettings");

  importButton.addEventListener("click", () => {
    const importedSettings = importSettingsInput.value;

    try {
      const parsedSettings = JSON.parse(importedSettings);
      settings = { ...settings, ...parsedSettings };
      localStorage.setItem("uwu_settings", JSON.stringify(settings));
      console.log("Настройки импортированы:", settings);
    } catch (error) {
      console.error("Ошибка при импорте настроек:", error);
    }
    updateExportField();
  });

  function updateExportField() {
    const settingsToExport = JSON.stringify(settings);
    exportSettingsInput.value = settingsToExport;
  }

  loadSettings();
  updateExportField();
  // ====================================================================================================================
  //  . . . МАКЕТ КАСТОМИЗАЦИИ ИГРОВОЙ . . .
  // ====================================================================================================================
  const blockNames = {
    tr_info: "Информация",
    tr_tos: "Погода",
    tr_chat: "Чат",
    tr_actions: "Действия",
    tr_mouth: "Во рту",
    // 'tr_sky': 'Небо',
  };
  const leftColumn = document.querySelector("#layout-customizer .column.left");
  const rightColumn = document.querySelector(
    "#layout-customizer .column.right"
  );

  function createBlockElement(blockId) {
    const blockElement = document.createElement("div");
    blockElement.classList.add("block", blockId);

    const blockName = document.createElement("span");
    blockName.textContent = blockNames[blockId];
    blockElement.appendChild(blockName);

    const controlsWrapper = document.createElement("div");
    controlsWrapper.classList.add("controls");

    if (blockId === "tr_info") {
      const moveInfoButton = document.createElement("button");
      moveInfoButton.textContent = "⏪Переместить⏩";
      moveInfoButton.classList.add("move-info", "install-button");
      moveInfoButton.addEventListener("click", () => {
        swapColumns(blockElement);
      });
      controlsWrapper.appendChild(moveInfoButton);
    } else {
      const moveUpButton = document.createElement("button");
      moveUpButton.textContent = "🔼Вверх";
      moveUpButton.classList.add("move-up", "install-button");
      moveUpButton.addEventListener("click", () => {
        const previousBlock = blockElement.previousElementSibling;
        if (previousBlock) {
          blockElement.parentNode.insertBefore(blockElement, previousBlock);
        }
      });
      controlsWrapper.appendChild(moveUpButton);

      const moveDownButton = document.createElement("button");
      moveDownButton.textContent = "🔽Вниз";
      moveDownButton.classList.add("move-down", "install-button");
      moveDownButton.addEventListener("click", () => {
        const nextBlock = blockElement.nextElementSibling;
        if (nextBlock) {
          blockElement.parentNode.insertBefore(nextBlock, blockElement);
        }
      });
      controlsWrapper.appendChild(moveDownButton);
    }

    blockElement.appendChild(controlsWrapper);
    return blockElement;
  }

  function swapColumns(blockElement) {
    if (blockElement.parentNode === leftColumn) {
      const rightColumnBlocks = Array.from(rightColumn.children);
      rightColumn.innerHTML = "";
      rightColumn.appendChild(blockElement);
      rightColumnBlocks.forEach((block) => leftColumn.appendChild(block));
    } else {
      const leftColumnBlocks = Array.from(leftColumn.children);
      leftColumn.innerHTML = "";
      leftColumn.appendChild(blockElement);
      leftColumnBlocks.forEach((block) => rightColumn.appendChild(block));
    }
  }

  const saveButton = document.getElementById("SettingSaveButton4");

  saveButton.addEventListener("click", () => {
    const leftBlocks = Array.from(leftColumn.querySelectorAll(".block")).map(
      (block) => block.classList[1]
    );
    const rightBlocks = Array.from(rightColumn.querySelectorAll(".block")).map(
      (block) => block.classList[1]
    );

    const layoutSettings = {
      leftBlocks,
      rightBlocks,
    };

    localStorage.setItem("uwu_layoutSettings", JSON.stringify(layoutSettings));
  });

  function loadLayoutSettings() {
    const savedSettings = localStorage.getItem("uwu_layoutSettings");
    if (savedSettings) {
      const { leftBlocks, rightBlocks } = JSON.parse(savedSettings);

      leftColumn.innerHTML = "";
      rightColumn.innerHTML = "";

      leftBlocks.forEach((blockId) => {
        const blockElement = createBlockElement(blockId);
        leftColumn.appendChild(blockElement);
      });

      rightBlocks.forEach((blockId) => {
        const blockElement = createBlockElement(blockId);
        rightColumn.appendChild(blockElement);
      });
    } else {
      const defaultLeftBlocks = ["tr_info"];
      const defaultRightBlocks = [
        "tr_tos",
        "tr_chat",
        "tr_actions",
        "tr_mouth",
      ];

      defaultLeftBlocks.forEach((blockId) => {
        leftColumn.appendChild(createBlockElement(blockId));
      });

      defaultRightBlocks.forEach((blockId) => {
        rightColumn.appendChild(createBlockElement(blockId));
      });

      const layoutSettings = {
        leftBlocks: defaultLeftBlocks,
        rightBlocks: defaultRightBlocks,
      };
      localStorage.setItem(
        "uwu_layoutSettings",
        JSON.stringify(layoutSettings)
      );
    }
  }

  window.addEventListener("load", loadLayoutSettings);
  // ====================================================================================================================
  //  . . . РЕДАКТОР ВКЛАДОК И ТАБЛИЦ МИННОГО ПОЛЯ . . .
  // ====================================================================================================================
  // как же я ненавижу минное поле как же я ненавижу минное поле как же я ненавижу минное поле
  const tabManager = {
    tabs: [],
    currentTabIndex: 0,
  
    createTab(name) {
      const newTab = {
        name: name,
        tables: [],
        currentTableId: 0,
      };
  
      this.tabs.push(newTab);
      this.render();
      this.switchTab(this.tabs.length - 1);
    },
  
    createTable(
      tableName = `Локация ${this.tabs[this.currentTabIndex].tables.length + 1}`
    ) {
      const currentTab = this.tabs[this.currentTabIndex];
      currentTab.tables.push({ name: tableName });
      this.saveState();
      this.render();
    },
  
    removeTable(tableIndex) {
      const currentTab = this.tabs[this.currentTabIndex];
      if (currentTab && currentTab.tables[tableIndex]) {
        currentTab.tables.splice(tableIndex, 1);
        if (currentTab.currentTableId === tableIndex) {
          currentTab.currentTableId = Math.max(
            0,
            currentTab.currentTableId - 1
          );
        }
        this.saveState();
        this.render();
      }
    },
  
    removeTab(index) {
      this.tabs.splice(index, 1);
      if (index === this.currentTabIndex) {
        this.currentTabIndex = Math.max(0, this.currentTabIndex - 1);
      }
      this.saveState();
      this.render();
    },
  
    switchTab(index) {
      this.currentTabIndex = index;
      this.render();
    },
  
    switchTable(tableIndex) {
      const currentTab = this.tabs[this.currentTabIndex];
      if (currentTab) {
        currentTab.currentTableId = tableIndex;
        this.saveState();
        this.render();
      }
    },
  
    renameTab(index) {
      const newName = prompt("Введите новое имя вкладки:", this.tabs[index].name);
      if (newName) {
        this.tabs[index].name = newName;
        this.saveState();
        this.render();
      }
    },
  
    renameTable(tableIndex) {
      const currentTab = this.tabs[this.currentTabIndex];
      if (currentTab) {
        const newName = prompt("Введите новое имя поля:", currentTab.tables[tableIndex].name);
        if (newName) {
          currentTab.tables[tableIndex].name = newName;
          this.saveState();
          this.render();
        }
      }
    },
  
    saveState() {
      localStorage.setItem("uwu_climbingPanelState", JSON.stringify(this));
    },
  
    render() {
      this.renderTabs();
      this.renderTables();
    },
  
    renderTabs() {
      const tabRow = document.getElementById("uwu-buttonRow1-settings");
      tabRow.innerHTML = "";
  
      this.tabs.forEach((tab, index) => {
        const tabButton = document.createElement("button");
        tabButton.textContent = tab.name;
        tabButton.classList.add("tab-button");
  
        if (index === this.currentTabIndex) {
          tabButton.classList.add("active");
        }
  
        tabButton.addEventListener("click", () => this.switchTab(index));
  
        const removeButton = document.createElement("button");
        removeButton.textContent = "X";
        removeButton.classList.add("remove-button");
  
        removeButton.addEventListener("click", () => this.removeTab(index));
  
        const renameButton = document.createElement("button");
        renameButton.textContent = "✎";
        renameButton.classList.add("rename-button");
  
        renameButton.addEventListener("click", () => this.renameTab(index));
  
        const tabContainer = document.createElement("div");
        tabContainer.classList.add("tab-container");
        tabContainer.appendChild(tabButton);
        tabContainer.appendChild(renameButton);
        tabContainer.appendChild(removeButton);
  
        tabRow.appendChild(tabContainer);
      });
  
      const addTabButton = document.createElement("button");
      addTabButton.textContent = "+";
      addTabButton.classList.add("add-button");
      addTabButton.addEventListener("click", () => {
        const tabName = prompt("Введите имя вкладки:");
        if (tabName) {
          this.createTab(tabName);
        }
      });
      tabRow.appendChild(addTabButton);
    },
  
    renderTables() {
      const tableRow = document.getElementById("uwu-buttonRow2-settings");
      tableRow.innerHTML = "";
  
      const currentTab = this.tabs[this.currentTabIndex];
  
      if (currentTab) {
        currentTab.tables.forEach((table, index) => {
          const tableButton = document.createElement("button");
          tableButton.textContent = table.name;
          tableButton.classList.add("table-button");
  
          tableButton.addEventListener("click", () => this.switchTable(index));
  
          const removeButton = document.createElement("button");
          removeButton.textContent = "X";
          removeButton.classList.add("remove-button");
  
          removeButton.addEventListener("click", () => this.removeTable(index));
  
          const renameButton = document.createElement("button");
          renameButton.textContent = "✎";
          renameButton.classList.add("rename-button");
  
          renameButton.addEventListener("click", () => this.renameTable(index));
  
          const tableContainer = document.createElement("div");
          tableContainer.classList.add("table-container");
          tableContainer.appendChild(tableButton);
          tableContainer.appendChild(renameButton);
          tableContainer.appendChild(removeButton);
  
          tableRow.appendChild(tableContainer);
        });
  
        const addTableButton = document.createElement("button");
        addTableButton.textContent = "+";
        addTableButton.classList.add("add-button");
  
        addTableButton.addEventListener("click", () => {
          const tableName = prompt("Введите имя поля:");
          if (tableName) {
            this.createTable(tableName);
          }
        });
  
        tableRow.appendChild(addTableButton);
      }
    },
  };
  
  const savedState = localStorage.getItem("uwu_climbingPanelState");
  if (!savedState) {
    tabManager.createTab("Вкладка 1");
    for (let i = 0; i < 5; i++) {
      tabManager.createTable(`Поле ${i + 1}`);
    }
  
    tabManager.createTab("Вкладка 2");
    for (let i = 0; i < 5; i++) {
      tabManager.createTable(`Поле ${i + 1}`);
    }
  
    tabManager.saveState();
  } else {
    const state = JSON.parse(savedState);
    Object.assign(tabManager, state);
  }
  
  tabManager.render();
}
// ====================================================================================================================
//  . . . ВКЛАДКИ ГЛАВНЫХ НАСТРОЕК . . .
// ====================================================================================================================
if (targetSettings.test(window.location.href)) {
  const buttonContainer = document.getElementById("button-container");

  buttonContainer.addEventListener("click", (event) => {
    const clickedElement = event.target;
    const clickedButton = clickedElement.closest("button");
    if (!clickedButton) return;

    const panelId = clickedButton.id.replace("button", "panel");
    const targetPanel = document.getElementById(panelId);

    buttonContainer.querySelectorAll("button").forEach((button) => {
      const correspondingPanelId = button.id.replace("button", "panel");
      const correspondingPanel = document.getElementById(correspondingPanelId);

      correspondingPanel.style.display =
        correspondingPanel === targetPanel ? "block" : "none";
      button.classList.toggle("active", button === clickedButton);
    });
  });

  const defaultButton = buttonContainer.querySelector("button");
  const defaultPanelId = defaultButton.id.replace("button", "panel");
  const defaultPanel = document.getElementById(defaultPanelId);

  buttonContainer.querySelectorAll("button").forEach((button) => {
    const correspondingPanelId = button.id.replace("button", "panel");
    const correspondingPanel = document.getElementById(correspondingPanelId);

    if (correspondingPanel !== defaultPanel) {
      correspondingPanel.style.display = "none";
    }
  });

  defaultPanel.style.display = "block";
  defaultButton.classList.add("active");
}
// ====================================================================================================================
//  . . . ОНЛАЙН МАГАЗИН СТИЛЕЙ . . .
// ====================================================================================================================
// буду вечно задаваться вопросом, а зачем я это вообще сделал..................
const moduleStates = {};
const defaultModules = [
  // "style.css",
  // ...
];
const privateModules = {};

function loadModuleStates() {
  const storedModuleStates = localStorage.getItem("uwu_moduleStates");
  if (storedModuleStates) {
    const loadedModuleStates = JSON.parse(storedModuleStates);
    Object.assign(moduleStates, loadedModuleStates);
  } else {
    for (const moduleName of defaultModules) {
      moduleStates[moduleName] = true;
    }
  }

  const storedPrivateModules = localStorage.getItem("uwu_privateModules");
  if (storedPrivateModules) {
    Object.assign(privateModules, JSON.parse(storedPrivateModules));
  }
}

async function loadModuleListOnSettings() {
  const url =
    "https://raw.githubusercontent.com/Ibirtem/CatWar/main/modules/modules.txt";

  const targetSettings = /^https:\/\/catwar\.net\/settings/;
  if (!targetSettings.test(window.location.href)) {
    return;
  }

  try {
    const response = await fetch(url);
    const moduleList = await response.text();
    const modules = moduleList.split("\n").filter((line) => line.trim() !== "");

    const moduleInfoContainer = document.getElementById("module-info");

    if (!moduleInfoContainer) {
      console.error("Контейнер модулей не найден!");
      return;
    }

    for (const moduleInfo of modules) {
      const [moduleName, description, version] = moduleInfo.split("|");
      const isOnlineModule = !localStorage.getItem(moduleName);
      const moduleContainer = createModuleContainer(
        moduleName,
        description,
        version,
        isOnlineModule
      );
      moduleInfoContainer.appendChild(moduleContainer);

      if (moduleStates[moduleName]) {
        loadModule(moduleName, description, version);
      }
    }

    for (const [moduleName, moduleInfo] of Object.entries(privateModules)) {
      const { description, version } = moduleInfo;
      const isPrivateModule = true;
      const moduleContainer = createModuleContainer(
        moduleName,
        description,
        version,
        false,
        isPrivateModule
      );
      moduleInfoContainer.appendChild(moduleContainer);

      if (moduleStates[moduleName]) {
        loadModule(moduleName, description, version);
      }
    }
  } catch (error) {
    console.error("Ошибка при загрузке списка модулей:", error);
  }
}

async function activateModules() {
  const url =
    "https://raw.githubusercontent.com/Ibirtem/CatWar/main/modules/modules.txt";

  try {
    const response = await fetch(url);
    const moduleList = await response.text();
    const modules = moduleList.split("\n").filter((line) => line.trim() !== "");

    for (const moduleInfo of modules) {
      const [moduleName, description, version] = moduleInfo.split("|");
      const isOnlineModule = !localStorage.getItem(moduleName);

      if (moduleStates[moduleName]) {
        loadModule(moduleName, description, version);
      }
    }

    for (const [moduleName, moduleInfo] of Object.entries(privateModules)) {
      const { description, version } = moduleInfo;

      if (moduleStates[moduleName]) {
        loadModule(moduleName, description, version);
      }
    }
  } catch (error) {
    console.error("Ошибка при активации модулей:", error);
  }
}

function createModuleContainer(
  moduleName,
  description,
  version,
  isOnlineModule = false,
  isPrivateModule = false
) {
  const moduleContainer = document.createElement("div");
  moduleContainer.classList.add("module-container");

  const moduleInfo = document.createElement("div");
  moduleInfo.classList.add("module-info");
  moduleInfo.textContent = `${description}`;

  const modulePanel = document.createElement("div");
  modulePanel.classList.add("module-panel");

  const versionInfo = document.createElement("span");
  versionInfo.textContent = `Версия: ${version}`;
  modulePanel.appendChild(versionInfo);

  if (isOnlineModule) {
    const installButton = document.createElement("button");
    installButton.textContent = "Установить";
    installButton.classList.add("install-button");
    installButton.addEventListener("click", () => {
      loadModule(moduleName, description, version);
      moduleContainer.remove();
      createModuleContainer(
        moduleName,
        description,
        version,
        false,
        isPrivateModule
      );
    });
    modulePanel.appendChild(installButton);
  } else {
    const checkboxContainer = document.createElement("div");
    checkboxContainer.classList.add("checkbox-container");

    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.id = moduleName;
    checkbox.checked = moduleStates[moduleName] || false;
    checkboxContainer.appendChild(checkbox);

    const removeButton = document.createElement("button");
    removeButton.textContent = "Удалить";
    removeButton.classList.add("remove-button");
    removeButton.addEventListener("click", () => {
      unloadModule(moduleName);
      moduleContainer.remove();
    });
    modulePanel.appendChild(removeButton);

    checkbox.addEventListener("change", () => {
      moduleStates[moduleName] = checkbox.checked;
      localStorage.setItem("uwu_moduleStates", JSON.stringify(moduleStates));

      if (checkbox.checked) {
        loadModule(moduleName, description, version);
      }
    });

    moduleInfo.appendChild(checkboxContainer);
  }

  moduleContainer.appendChild(moduleInfo);
  moduleContainer.appendChild(modulePanel);

  return moduleContainer;
}

async function loadModule(moduleName, description, version) {
  const cachedModule = localStorage.getItem(moduleName);

  if (cachedModule) {
    activateModule(cachedModule, moduleName, description, version);
  } else {
    const url = `https://raw.githubusercontent.com/Ibirtem/CatWar/main/modules/${moduleName}`;
    try {
      const response = await fetch(url);
      if (response.ok) {
        const data = await response.text();
        localStorage.setItem(moduleName, data);
        activateModule(data, moduleName, description, version);

        moduleStates[moduleName] = true;
        localStorage.setItem("uwu_moduleStates", JSON.stringify(moduleStates));

        createModuleContainer(moduleName, description, version, false);

        loadModuleStates();
        clearModuleInfoContainer();
        loadModuleListOnSettings();
      } else {
        console.error(
          `Ошибка при загрузке модуля "${moduleName}": ${response.status} ${response.statusText}`
        );
      }
    } catch (error) {
      console.error("Ошибка при загрузке модуля:", error);
    }
  }
}

function addStyle(css) {
  const style = document.createElement('style');
  style.appendChild(document.createTextNode(css));
  document.head.appendChild(style);
}

function activateModule(data, moduleName, description, version) {
  if (moduleName.endsWith(".css")) {
    addStyle(data);
  } else if (moduleName.endsWith(".js")) {
    try {
      new Function(data);
      eval(data);
    } catch (error) {
      console.error(`Ошибка при активации модуля "${moduleName}":`, error);
    }
  }
}

function unloadModule(moduleName) {
  localStorage.removeItem(moduleName);
  delete moduleStates[moduleName];
  localStorage.setItem("uwu_moduleStates", JSON.stringify(moduleStates));

  if (privateModules[moduleName]) {
    delete privateModules[moduleName];
    localStorage.setItem("uwu_privateModules", JSON.stringify(privateModules));
  }

  loadModuleStates();
  clearModuleInfoContainer();
  loadModuleListOnSettings();
}

function clearModuleInfoContainer() {
  const moduleInfoContainer = document.getElementById("module-info");
  while (moduleInfoContainer.firstChild) {
    moduleInfoContainer.removeChild(moduleInfoContainer.firstChild);
  }
}

loadModuleStates();
loadModuleListOnSettings();
window.addEventListener("load", activateModules);
// ====================================================================================================================
//   . . . ЗАГРУЗКА НАСТРОЕК . . .
// ====================================================================================================================
loadSettings();
// ====================================================================================================================
//   . . . АВАТАРЫ В КОММЕНТАРИЯХ . . .
// ====================================================================================================================
if (window.location.href !== targetCW3) {
  if (settings.commentsAvatars) {
    const styleElement = document.createElement("style");
    styleElement.textContent = `
      .avatar-img {
        width: 100px;
        height: 100px;
        object-fit: cover;
        float: left;
        margin: 5px;
        border: black solid 1px;
      }
    `;
    document.head.appendChild(styleElement);

    startCheckingForComments();
  }

  function startCheckingForComments() {
    setupMutationObserver("#view_comments", insertAvatars, {
      childList: true,
    });
  }

  function insertAvatars() {
    const comments = document.querySelectorAll(".view-comment");
    comments.forEach((comment) => {
      if (!comment.querySelector('.avatar-img')) {
        const authorLink = comment.querySelector(".author");
        const catId = authorLink ? authorLink.getAttribute("href").match(/\/cat(\d+)/)?.[1] : null;

        const avatarImg = document.createElement("img");
        avatarImg.alt = "Аватар пользователя";
        avatarImg.classList.add("avatar-img");

        if (!catId) {
          avatarImg.src = "https://e.catwar.net/avatar/0.jpg";
        } else {
          loadAvatar(catId, (avatarUrl) => {
            avatarImg.src = avatarUrl || "https://e.catwar.net/avatar/0.jpg";
          });
        }

        comment.insertBefore(avatarImg, comment.firstChild);
      }
    });
  }

  function loadAvatar(catId, callback) {
    const formats = ["png", "jpg", "gif"];
    let currentFormat = 0;

    function tryNextFormat() {
      const url = `https://e.catwar.net/avatar/${catId}.${formats[currentFormat]}`;
      const img = new Image();

      img.onload = () => callback(url);
      img.onerror = () => {
        currentFormat++;
        if (currentFormat < formats.length) {
          tryNextFormat();
        } else {
          callback(null);
        }
      };

      img.src = url;
    }

    tryNextFormat();
  }
}
// ====================================================================================================================
//   . . . МЕНЕДЖЕР ЗВУКОВ . . .
// ====================================================================================================================
function createSoundManager() {
  const sounds = {};
  let isUserInteracted = false;
  let lastPendingSound = null;

  function loadSound(id, url) {
    const audio = new Audio(url);
    sounds[id] = audio;
  }

  function playSound(id, volume) {
    return new Promise((resolve, reject) => {
      if (sounds[id]) {
        sounds[id].currentTime = 0;
        sounds[id].volume = volume / 10;
        sounds[id]
          .play()
          .then(resolve)
          .catch((error) => {
            if (!isUserInteracted) {
              console.warn(
                "Политика браузера заблокировала звук. Ждём взаимодействия со стороны пользователя для новой попытки."
              );
              lastPendingSound = { id, volume, resolve };
            } else {
              reject(error);
            }
          });
      } else {
        reject(new Error(`Звук с ID ${id} не найден.`));
      }
    });
  }

  function playSoundNow(id, volume, resolve) {
    sounds[id]
      .play()
      .then(resolve)
      .catch((error) => {
        console.error(`Не удалось воспроизвести звук с ID ${id}:`, error);
        resolve();
      });
  }

  function handleUserInteraction() {
    isUserInteracted = true;
    document.removeEventListener("click", handleUserInteraction);
    document.removeEventListener("touchstart", handleUserInteraction);
    document.removeEventListener("keydown", handleUserInteraction);

    if (lastPendingSound) {
      const { id, volume, resolve } = lastPendingSound;
      playSoundNow(id, volume, resolve);
      lastPendingSound = null;
    }
  }

  document.addEventListener("click", handleUserInteraction);
  document.addEventListener("touchstart", handleUserInteraction);
  document.addEventListener("keydown", handleUserInteraction);

  return {
    loadSound,
    playSound,
  };
}

const soundManager = createSoundManager();

// ===================== СПИСОК ДОСТУПНЫХ ЗВУКОВ =====================

soundManager.loadSound(
  "notificationSound1",
  "https://github.com/Ibirtem/CatWar/raw/main/sounds/notification_1.mp3"
);
soundManager.loadSound(
  "notificationSound2",
  "https://github.com/Ibirtem/CatWar/raw/main/sounds/notification_2.mp3"
);
soundManager.loadSound(
  "notificationSound3",
  "https://github.com/Ibirtem/CatWar/raw/main/sounds/notification_3.mp3"
);

// ====================================================================================================================
//  . . . ЗАГРУЗКА КОДА В ИГРОВОЙ . . .
// ====================================================================================================================
// Игровая ли... Я чё знаю?
if (window.location.href === targetCW3) {
  const containerElement = document.querySelector("body");
  const globalContainerElement = document.createElement("div");
  globalContainerElement.id = "uwu-global-container";
  containerElement.appendChild(globalContainerElement);

  const mainContainerElement = document.createElement("div");
  mainContainerElement.id = "uwu-main-container";
  globalContainerElement.appendChild(mainContainerElement);

  // ====================================================================================================================
  //  . . . ПОДГРУЗКА ЦВЕТОВЫХ ТЕМ . . .
  // ====================================================================================================================
  const currentThemeName = getCurrentThemeName();
  const allThemes = getThemes();
  const theme = allThemes[currentThemeName]?.colors || {};
  // ====================================================================================================================
  //  . . . РАСШИРЕННЫЕ НАСТРОЙКИ . . .
  // ====================================================================================================================
  const extendedSettingsButtonElement = document.createElement("div");
  extendedSettingsButtonElement.innerHTML = extendedSettingsButton;
  mainContainerElement.appendChild(extendedSettingsButtonElement);

  const panel = extendedSettingsButtonElement.querySelector(
    "#uwu-extended-settings"
  );
  const extendedSettingsContainer = extendedSettingsButtonElement.querySelector(
    "#extended-settings-container"
  );
  const button = extendedSettingsButtonElement.querySelector(
    "#extended-settings-button"
  );

  extendedSettingsContainer.style.display = "none";

  const shouldShowPanel = () => {
    return (
      settings.extendedSettingsPanel ||
      settings.showSplashScreens ||
      settings.showUpdateNotification ||
      settings.manualWeatherPanel ||
      settings.fastStyles
    );
  };

  if (shouldShowPanel()) {
    panel.style.display = "block";
  } else {
    panel.style.display = "none";
  }

  button.addEventListener("click", () => {
    extendedSettingsContainer.style.display =
      extendedSettingsContainer.style.display === "none" ? "block" : "none";

    button.classList.remove("new-update");
  });
  // ====================================================================================================================
  //  . . . СПЛЕШ СКРИН . . .
  // ====================================================================================================================
  if (settings.showSplashScreens) {
    const randomPhraseBlock = document.createElement("div");
    const splashPanel = extendedSettingsButtonElement.querySelector(
      "#splash-screen-panel"
    );
    randomPhraseBlock.classList.add("random-phrase-block");
    splashPanel.appendChild(randomPhraseBlock);

    function loadRandomPhrase(url) {
      fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw new Error(`Ошибка загрузки: ${response.status}`);
          }
          return response.text();
        })
        .then((text) => {
          const phrases = text.split("\n").filter((line) => line.trim() !== "");
          const randomIndex = Math.floor(Math.random() * phrases.length);
          randomPhraseBlock.innerHTML = parseColorCodes(phrases[randomIndex]);
        })
        .catch((error) => {
          console.error("Ошибка при загрузке случайной фразы:", error);
          randomPhraseBlock.textContent = "Не удалось загрузить фразу :(";
        });
    }

    function parseColorCodes(text) {
      const colorMap = {
        "&0": "</span>", // - Сброс -
        "&1": "<span style='color: blue;'>", // Синий
        "&2": "<span style='color: green;'>", // Зеленый
        "&3": "<span style='color: aqua;'>", // Бирюзовый
        "&4": "<span style='color: red;'>", // Красный
        "&5": "<span style='color: #dc00dc;'>", // Фиолетовый
        "&6": "<span style='color: gold;'>", // Золотой
        "&7": "<span style='color: pink;'>", // Розовый
        "&8": "<span style='color: white;'>", // Белый
        "&9": "<span style='color: black;'>", // Черный
      };

      text = "<b>" + text;

      for (const code in colorMap) {
        text = text.replace(new RegExp(code, "g"), colorMap[code]);
      }

      return text;
    }

    window.addEventListener("load", () => {
      loadRandomPhrase(
        "https://raw.githubusercontent.com/Ibirtem/CatWar/main/texts/text.txt"
      );
    });
  }
  // ====================================================================================================================
  //  . . . УВЕДОМЛЕНИЕ ОБ ОБНОВЛЕНИИ . . .
  // ====================================================================================================================
  function showUpdateNotification(oldVersion) {
    const panel = document.getElementById("extended-settings-container");
    const notificationBlock = document.createElement("div");
    notificationBlock.classList.add("update-notification");
    notificationBlock.innerHTML = `
          <p>Скрипт/Мод UwU был обновлен с версии v${
            oldVersion || "неизвестной"
          } до версии v${current_uwu_version}!</p>
          <p>Можете посетить <a href="https://catwar.net/settings" target="_blank">Настройки</a> для ознакомления с изменениями.</p>
        `;
    panel.appendChild(notificationBlock);
    const button = extendedSettingsButtonElement.querySelector("button");
    button.classList.add("new-update");
  }

  window.addEventListener("load", () => {
    const savedVersion = localStorage.getItem("uwu_version");
    if (savedVersion !== current_uwu_version) {
      localStorage.setItem("uwu_version", current_uwu_version);
    }
    if (
      settings.showUpdateNotification &&
      savedVersion !== current_uwu_version
    ) {
      showUpdateNotification(savedVersion);
    }
  });

  // ====================================================================================================================
  //  . . . РУЧНОЕ УПРАВЛЕНИЕ ПОГОДОЙ . . .
  // ====================================================================================================================
  if (settings.manualWeatherPanel) {
    const panel = extendedSettingsButtonElement.querySelector(
      "#extended-settings-container"
    );
    panel.innerHTML += manualWeatherPanel;

    const manualAuroraOffButton = document.getElementById("manualAurora-Off");
    const manualAuroraBButton = document.getElementById("manualAurora-B");
    const manualAuroraGButton = document.getElementById("manualAurora-G");

    const fireflyOnButton = document.getElementById("manualFirefly-On");

    manualAuroraOffButton.addEventListener("click", () => {
      for (const auroraElement of auroras) {
        removeAurora(auroraElement);
      }
    });

    manualAuroraBButton.addEventListener("click", () => {
      createAurora("blue");
    });

    manualAuroraGButton.addEventListener("click", () => {
      createAurora("green");
    });

    fireflyOnButton.addEventListener("click", () => {
      toggleFireflies();
    });
  }
  // ====================================================================================================================
  //   . . . ЧАСЫ . . .
  // ====================================================================================================================
  if (settings.showClock) {
    const style = document.createElement("style");
    style.textContent = // css
    `
        #uwu-clock {
          border-radius: 10px;
          width: min-content;
          height: min-content;
          background-color: ${theme?.blocksColor || "#242424"};
          color: ${theme?.textColor || "#d5d5d5"};
          border: 1px solid #ffffff1a;
          display: grid;
          grid-template-columns: auto 1fr;
          grid-template-rows: auto auto;
          align-items: center;
          justify-content: space-between;
          font-family: Arial, sans-serif;
          text-align: center;
          cursor: move;
          pointer-events: auto;
          position: absolute;
          z-index: 10;
          padding: 5px;
          font-size: ${settings.clockFontSize || 14}px;
        }

        #uwu-clock .time {
          font-size: 2em;
        }

        #uwu-clock .icon {
          cursor: help;
        }

        .compact #uwu-clock {
          column-gap: 5px;
          grid-template-columns: auto 1fr;
          grid-template-rows: auto auto;
        }

        .compact #uwu-clock .time {
          grid-column: 1 / 2;
          grid-row: 1 / 3;
        }

        .compact #uwu-clock .icon {
          grid-column: 2 / 3;
          grid-row: 1 / 2;
        }

        .compact #uwu-clock .date {
          grid-column: 2 / 3;
          grid-row: 2 / 3;
        }

        .standard #uwu-clock {
          grid-template-columns: auto auto;
          grid-template-rows: auto auto;
        }

        .standard #uwu-clock .time {
          text-align: start;
          grid-column: 1 / 2;
          grid-row: 1 / 2;
        }

        .standard #uwu-clock .icon {
          grid-column: 2 / 3;
          grid-row: 1 / 2;
        }

        .standard #uwu-clock .date {
          font-size: 1.2em;
          grid-column: 1 / 3;
          grid-row: 2 / 3;
          width: max-content;
        }
    `;
    document.head.appendChild(style);

    const tosStyle = document.createElement("style");
    tosStyle.textContent = `
      #uwu-clock {
        position: relative;
      }
    `;
    
    const flyStyle = document.createElement("style");
    flyStyle.textContent = `

    `;

    const container = document.getElementById("uwu-global-container");
    const clockElement = document.createElement("div");
    clockElement.id = "uwu-clock";

    const timeElement = document.createElement("span");
    timeElement.className = "time";
    clockElement.appendChild(timeElement);

    const iconElement = document.createElement("span");
    iconElement.className = "icon";
    clockElement.appendChild(iconElement);

    const dateElement = document.createElement("span");
    dateElement.className = "date";
    clockElement.appendChild(dateElement);

    if (settings.clockPosition === "fly") {
      container.appendChild(clockElement);
      document.head.appendChild(flyStyle);
  } else if (settings.clockPosition === "tos") {
      const trTos = document.getElementById("tr_tos").querySelector("tbody tr");
      const newTd = document.createElement("td");
      newTd.appendChild(clockElement);
      trTos.appendChild(newTd);
      document.head.appendChild(tosStyle);
  }

    let useInternetTime = false;
    let isDragging = false;
    let offsetX, offsetY;
    let internetTime = null;
    let timerInterval = null;

    function updateClock(timeSource = new Date()) {
      const hours = String(timeSource.getHours()).padStart(2, "0");
      const minutes = String(timeSource.getMinutes()).padStart(2, "0");
      const seconds = String(timeSource.getSeconds()).padStart(2, "0");
      const day = String(timeSource.getDate()).padStart(2, "0");
      const month = String(timeSource.getMonth() + 1).padStart(2, "0");
      const year = String(timeSource.getFullYear());
  
      timeElement.textContent = `${hours}:${minutes}:${seconds}`;
  
      if (settings.clockStyle === "compact") {
          dateElement.textContent = `${day}.${month}.${year.slice(-2)}`;
      } else if (settings.clockStyle === "standard") {
          const dayOfWeek = ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"][timeSource.getDay()];
          const monthNames = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"];
          const monthName = monthNames[timeSource.getMonth()];
          dateElement.textContent = `${day} (${dayOfWeek}), ${monthName}, ${year}`;
      }
  
      if (useInternetTime) {
          iconElement.textContent = "🌍︎";
          iconElement.title = "Точное онлайн время";
          if (settings.clockMoscowTime) {
              iconElement.textContent += " MSK";
          }
      } else {
          iconElement.textContent = "⌨";
          iconElement.title =
              "Не удалось получить точное онлайн время! Используется локальное время устройства";
      }
  }

    async function fetchInternetTime() {
        try {
            const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
            const url = settings.clockMoscowTime
                ? "https://timeapi.io/api/Time/current/zone?timeZone=Europe/Moscow"
                : `https://timeapi.io/api/Time/current/zone?timeZone=${userTimezone}`;
            const response = await fetch(url);
            if (!response.ok) throw new Error(`Онлайн ответ выдал ошибку: ${response.status} ${response.statusText}`);
            const data = await response.json();
            internetTime = new Date(data.dateTime);
            useInternetTime = true;
            updateClockWithInternetTime();
        } catch (error) {
            console.error('Ошибка при получении онлайн времени:', error);
            useInternetTime = false;
            updateClock();
        }
        startTimer();
    }

    function updateClockWithInternetTime() {
      if (internetTime) {
          internetTime.setSeconds(internetTime.getSeconds() + 1);
          updateClock(internetTime);
          if (settings.clockMoscowTime) {
              iconElement.textContent = "🌍︎ MSK";
          }
      }
  }

    function startTimer() {
        if (timerInterval) {
            clearInterval(timerInterval);
        }
        timerInterval = setInterval(() => {
            if (useInternetTime) {
                updateClockWithInternetTime();
            } else {
                updateClock();
            }
        }, 1000);
    }

    if (settings.clockPosition === "fly") {
        clockElement.addEventListener("mousedown", (e) => {
            isDragging = true;
            offsetX = e.clientX - clockElement.offsetLeft;
            offsetY = e.clientY - clockElement.offsetTop;
            document.body.style.userSelect = "none";
        });

        document.addEventListener("mousemove", (e) => {
            if (isDragging) {
                clockElement.style.left = `${e.clientX - offsetX}px`;
                clockElement.style.top = `${e.clientY - offsetY}px`;
            }
        });

        document.addEventListener("mouseup", () => {
            isDragging = false;
            document.body.style.userSelect = "auto";
            saveClockPosition();
        });
    }

    function saveClockPosition() {
        const clockPosition = {
            x: clockElement.offsetLeft,
            y: clockElement.offsetTop,
        };
        localStorage.setItem("uwu_clock", JSON.stringify(clockPosition));
    }

    function loadClockPosition() {
        const storedPosition = localStorage.getItem("uwu_clock");
        if (storedPosition) {
            const clockPosition = JSON.parse(storedPosition);
            clockElement.style.left = `${clockPosition.x}px`;
            clockElement.style.top = `${clockPosition.y}px`;
        }
    }

    document.addEventListener("visibilitychange", () => {
        if (!document.hidden) {
            fetchInternetTime();
        }
    });

    window.addEventListener("focus", () => {
        fetchInternetTime();
    });

    fetchInternetTime();
    if (settings.clockPosition === "fly") {
        loadClockPosition();
    }

    document.body.classList.add(settings.clockStyle);
}
  // ====================================================================================================================
  //  . . . ДЕЙСТВИЯ ПРИ НАВОДКЕ НА .cat . . .
  // ====================================================================================================================
  document.addEventListener("mouseover", (event) => {
    const catElement = event.target.closest(".cat");

    if (catElement) {
      const catTooltip = catElement.querySelector(".cat_tooltip");

      if (
        settings.showMoreCatInfo &&
        !catTooltip.querySelector(".more-info-link")
      ) {
        const moreInfoLink = document.createElement("a");
        moreInfoLink.classList.add("more-info-link");
        moreInfoLink.textContent = "Подробнее";
        moreInfoLink.addEventListener("click", () => {
          showCatInfo(catElement);
        });

        const moreInfoContainer = document.createElement("div");
        moreInfoContainer.classList.add("more-info-container");
        moreInfoContainer.appendChild(moreInfoLink);

        const onlineSpan = catTooltip.querySelector("span.online");
        onlineSpan.parentNode.insertBefore(moreInfoContainer, onlineSpan);
      }

      if (settings.compactMouth) {
        compactInventory(catElement);
      }
    }
  });
  // ====================================================================================================================
  //  . . . КОМПАКТНЫЙ РОТ АХХАХХА . . .
  // ====================================================================================================================
  function compactInventory(cat) {
    const originalMouth = cat.querySelector(".cat_tooltip .mouth");

    if (originalMouth) {
      const existingSortedMouths = cat.querySelectorAll(".mouth.uwu-sorted");
      existingSortedMouths.forEach((mouth) => mouth.remove());

      const newMouth = document.createElement("ol");
      newMouth.classList.add("mouth", "uwu-sorted");
      originalMouth.parentNode.insertBefore(
        newMouth,
        originalMouth.nextSibling
      );

      originalMouth.style.display = "none";

      const inventory = new Map();
      const cats = [];

      [...originalMouth.querySelectorAll("li img")].forEach((img) => {
        const itemSrc = img.getAttribute("src");
        inventory.set(itemSrc, (inventory.get(itemSrc) || 0) + 1);
      });

      [...originalMouth.querySelectorAll("li")].forEach((item) => {
        if (!item.querySelector("img")) {
          cats.push(item.innerHTML);
        }
      });

      newMouth.innerHTML = "";
      for (const [itemSrc, count] of inventory) {
        const listItem = document.createElement("li");
        const itemImage = document.createElement("img");
        itemImage.setAttribute("src", itemSrc);
        listItem.appendChild(itemImage);

        if (count > 1) {
          const countSpan = document.createElement("span");
          countSpan.textContent = `x${count}`;
          listItem.appendChild(countSpan);
        }

        newMouth.appendChild(listItem);
      }

      cats.forEach((catHtml) => {
        const listItem = document.createElement("li");
        listItem.innerHTML = catHtml;
        newMouth.appendChild(listItem);
      });
    }
  }
  // ====================================================================================================================
  //  . . . ИНФОРМАЦИОННЫЙ КОНТЕЙНЕР . . .
  // ====================================================================================================================
  let globalContainer = document.getElementById("uwu-global-container");
  if (!globalContainer) {
    globalContainer = document.createElement("div");
    globalContainer.id = "uwu-global-container";
    globalContainer.style.display = "none";
    document.body.appendChild(globalContainer);
  }

  function createCatInfoContainer() {
    const catInfoElement = document.createElement("div");
    catInfoElement.classList.add("cat-info");

    const contentContainer = document.createElement("div");
    contentContainer.classList.add("content-container");
    catInfoElement.appendChild(contentContainer);

    const closeButton = document.createElement("button");
    closeButton.textContent = "Закрыть";
    closeButton.classList.add("close-info");
    closeButton.addEventListener("click", () => {
      globalContainer.removeChild(catInfoElement);
    });
    catInfoElement.appendChild(closeButton);

    const css_catDefects = document.createElement("style");
    css_catDefects.innerHTML = // css
    `
      .cat-info {
        pointer-events: auto;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        padding: 20px;
        border-radius: 5px;
        box-shadow: 0 0 10px #00000033;
        z-index: 5;
        width: 300px;
        text-align: center;
        display: block;
        background-color: white;
        color: black;
      }

      .other-cat-info-container {
      display: grid;
      grid-template-columns: 1fr 2fr;
      }
    
      .close-info-container {
        text-align: right;
      }
    
      .close-info {
        cursor: pointer;
      }
    
      .more-info-container {
        cursor: pointer;
      }

      .parameter-details-container {
        text-align: left;
      }

      .cat-details {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        margin-left: 8px;
      }

      .cat-details > p,
      .cat-details > div > p {
        margin-top: 5px;
        margin-bottom: 5px;
      }

      #uwu-global-container > div.cat-info > div > div > div.cat-details > div {
        margin-top: 8px;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
    `;

    document.head.appendChild(css_catDefects);

    return { catInfoElement, contentContainer };
  }
  // ====================================================================================================================
  //  . . . БОЛЬШЕ ИНФОРМАЦИИ В "О КОТЕ" . . .
  // ====================================================================================================================
  const defectsInfo = {
    wound: {
      name: "Раны",
      states: {
        1: "царапины",
        2: "лёгкие раны",
        3: "глубокие раны",
        4: "смертельные раны",
      },
    },
    poisoning: {
      name: "Отравление",
      states: {
        1: "недомогание",
        2: "лёгкое отравление",
        3: "сильное отравление",
        4: "смертельное отравление",
      },
    },
    drown: {
      name: "Травмы от утопления",
      states: {
        1: "ссадины",
        2: "небольшие кровоподтёки",
        3: "сильные травмы",
        4: "смертельные травмы",
      },
    },
    disease: {
      name: "Болезнь",
      states: {
        1: "кашель",
        2: "кашель",
        3: "кашель",
        4: "кашель",
      },
    },
    trauma: {
      name: "Переломы",
      states: {
        1: "синяки",
        2: "лёгкие ушибы",
        3: "сильные ушибы",
        4: "смертельные ушибы",
      },
    },
    dirt: {
      name: "Грязь",
      states: {
        1: "грязные лапы",
        2: "грязевые пятна",
        3: "клещи",
        4: "блохи",
      },
    },
  };

  function showCatInfo(cat) {
    const catName = cat.querySelector(".cat_tooltip a").textContent;
    const catSize = cat.querySelector(".d .first").style.backgroundSize;
    const catImage = cat
      .querySelector(".d .first")
      .style.backgroundImage.slice(5, -2);

    const defectElements = Array.from(
      cat.querySelectorAll(".d > div:not(.first)")
    );

    const uniqueDefects = new Set();

    const catDefects = defectElements
      .map((element) => {
        const defectUrl = element.style.backgroundImage;

        if (defectUrl.includes("/defects/")) {
          const defectParts = defectUrl.split("/");
          const lastPart = defectParts.pop();
          const defectLevel = parseInt(lastPart.split("/")[0]);
          const defectType = defectParts[5];
          const defectKey = `${defectType}-${defectLevel}`;

          if (!uniqueDefects.has(defectKey)) {
            uniqueDefects.add(defectKey);
            return { type: defectType, level: defectLevel };
          }
        }
        return null;
      })
      .filter(Boolean);

    const catId = cat
      .querySelector(".cat_tooltip a")
      .getAttribute("href")
      .slice(4);

    let { catInfoElement, contentContainer } = createCatInfoContainer();

    contentContainer.innerHTML = // html
    `
      <h2>${catName}</h2>
      <div class="other-cat-info-container">
        <div>
          <img src="${catImage}" class="cat-image">
        </div>
        <div class="cat-details">
          <p><strong>ID</strong>: ${catId}</p>
          <p><strong>Размер</strong>: ${catSize}</p>
        </div>
      </div>
    `;

    const defectsContainer = document.createElement("div");
    if (catDefects.length > 0) {
      defectsContainer.innerHTML = "<p>Дефекты:</p>";
      catDefects.forEach((defect) => {
        const defectData = defectsInfo[defect.type];
        if (defectData) {
          const defectState = defectData.states[defect.level] || "";
          const defectLine = document.createElement("p");
          const defectNameSpan = document.createElement("strong");
          defectNameSpan.textContent = defectData.name;
          defectLine.appendChild(defectNameSpan);
          defectLine.insertAdjacentHTML(
            "beforeend",
            ` (${defect.level} стадия, ${defectState})`
          );

          defectsContainer.appendChild(defectLine);
        }
      });
      contentContainer
        .querySelector(".cat-details")
        .appendChild(defectsContainer);
    } else {
      contentContainer.querySelector(".cat-details").innerHTML +=
        "<p><strong>Здоровый</strong></p>";
    }

    globalContainer.appendChild(catInfoElement);
  }
  // ====================================================================================================================
  //  . . . СОБСТВЕННЫЙ ФОН ЛОКАЦИИ ИГРОВОЙ . . .
  // ====================================================================================================================
  if (settings.gameFieldBackgroundUser) {
    const css_gameField = document.createElement("style");
    css_gameField.textContent = `
      #cages_div {
          background-image: url(${settings.gameFieldBackgroundUserImageURL}) !important;
      }
  `;
    document.head.appendChild(css_gameField);
  }
  // ====================================================================================================================
  //  . . . ГРАНИЦЫ ЯЧЕЕК . . . cellsNumbers
  // ====================================================================================================================
  function updateCellsBordersStyle(checked) {
    let styleElement = document.getElementById("cellsBordersStyle");
    const cellsBordersStyle = `
      .cage {
        box-shadow: inset 0 0 0 0.${settingsMap.uwu_settings.cellsBordersThickness}px ${settings.cellsBordersColor};
      }
    `;

    if (checked) {
      if (!styleElement) {
        styleElement = document.createElement("style");
        styleElement.id = "cellsBordersStyle";
        styleElement.innerHTML = cellsBordersStyle;
        document.head.appendChild(styleElement);
      }
    } else {
      if (styleElement) {
        document.head.removeChild(styleElement);
      }
    }
  }
  // ====================================================================================================================
  //  . . . НУМЕРАЦИЯ ЯЧЕЕК . . .
  // ====================================================================================================================
  if (settings.cellsNumbers) {
    function createCellNumbers(style) {
      let css = // css
      `
        #cages_div { position: relative; }
        #cages > tbody > tr > td { position: relative; }
        #cages > tbody > tr > td::before { 
          content: attr(data-cell-num);
          position: absolute; 
          z-index: 0; 
          top: 5px; 
          right: 5px;
          color: ${style.color || "#000"}; 
          opacity: ${style.opacity || 0.4}; 
          font-size: 16px; 
          font-weight: bold;
        }
      `;
  
      let cagesNums = document.createElement("style");
      cagesNums.id = "cages_nums";
      cagesNums.innerHTML = css;
      document.head.appendChild(cagesNums);
  
      let table = document.getElementById("cages");
      if (!table) return;
      let rows = table.querySelectorAll("tbody > tr");
      for (let i = 0; i < rows.length; i++) {
        let cells = rows[i].querySelectorAll("td");
        for (let j = 0; j < cells.length; j++) {
          cells[j].setAttribute("data-cell-num", (j + 1).toString());
        }
      }
    }
  
    createCellNumbers({
      color: "white",
      opacity: 0.8,
    });
  }
  // ====================================================================================================================
  //   . . . ПРОЦЕНТЫ ПАРАМЕТРОВ . . .
  // ====================================================================================================================
  if (settings.displayParametersPercentages) {
    const parameterTableIds = [
      "dream_table",
      "hunger_table",
      "thirst_table",
      "need_table",
      "health_table",
      "clean_table",
    ];

    function updateParameterPercentages(tableId) {
      const table = document.getElementById(tableId);
      if (table) {
        const row = table.querySelector("tbody tr");
        if (!row) {
          console.warn(`Строка не найдена в таблице с ID "${tableId}".`);
          return;
        }
        const greenBar = row.querySelector(
          "td[style*='background-color: green;']"
        );
        const redBar = row.querySelector("td[style*='background-color: red;']");
        if (!greenBar || !redBar) {
          console.warn(`Бары не найдены в строке таблицы с ID "${tableId}".`);
          return;
        }
        const greenBarWidth = parseInt(greenBar.style.width, 10);
        const redBarWidth = parseInt(redBar.style.width, 10);
        const totalWidth = greenBarWidth + redBarWidth;
        let percentage = (greenBarWidth / totalWidth) * 100;
        percentage =
          percentage % 1 !== 0 ? percentage.toFixed(2) : Math.round(percentage);

        let percentageCell = row.querySelector(".percentage-cell");
        if (!percentageCell) {
          percentageCell = document.createElement("td");
          percentageCell.classList.add("percentage-cell");
          row.appendChild(percentageCell);
        }
        percentageCell.textContent = `${percentage}%`;
      } else {
        console.warn(`Таблица с ID "${tableId}" не найдена.`);
      }
    }

    async function setupTableObservers() {
      for (const tableId of parameterTableIds) {
        const tableSelector = `#${tableId}`;
        const rowSelector = `${tableSelector} tbody tr`;
        const greenBarSelector = `${rowSelector} td[style*='background-color: green;']`;
        const redBarSelector = `${rowSelector} td[style*='background-color: red;']`;

        await setupMutationObserver(tableSelector, () =>
          updateParameterPercentages(tableId)
        );
        await setupMutationObserver(greenBarSelector, () =>
          updateParameterPercentages(tableId)
        );
        await setupMutationObserver(redBarSelector, () =>
          updateParameterPercentages(tableId)
        );
      }
    }

    window.addEventListener("load", setupTableObservers);
  }
  // ====================================================================================================================
  //   . . . ПОДРОБНЕЕ О ПАРАМЕТРАХ (И НАВЫКОВ?) . . .
  // ====================================================================================================================
  function createMoreInfoButton() {
    const parametersBlock = document.getElementById("parameters_block");

    const buttonContainer = document.createElement("div");
    buttonContainer.classList.add("button-container");
    buttonContainer.style.paddingBottom = "5px";

    const moreInfoLink = document.createElement("a");
    moreInfoLink.href = "#";
    moreInfoLink.textContent = "Подробнее";
    moreInfoLink.classList.add("more-info-link");
    moreInfoLink.addEventListener("click", (event) => {
        event.preventDefault();
        showParameterDetails();
    });

    buttonContainer.appendChild(moreInfoLink);

    parametersBlock.insertBefore(buttonContainer, parametersBlock.firstChild);
  }

  function showParameterDetails() {
    const parameters = [
      {
        id: "dream_table",
        name: "Сонливость",
        timePerPixel: 20,
        formula: null,
      },
      {
        id: "hunger_table",
        name: "Голод",
        timePerPixel: null,
        formula: (red) => Math.ceil((red / 150) * 9) * 15,
      },
      { id: "thirst_table", name: "Жажда", timePerPixel: 60, formula: null },
      { id: "need_table", name: "Нужда", timePerPixel: 30, formula: null },
      {
        id: "health_table",
        name: "Здоровье",
        timePerPixel: null,
        formula: null,
      },
      {
        id: "clean_table",
        name: "Чистота",
        timePerPixel: null,
        formula: (red) => {
          red = red % 3 ? red : red - 0.5;
          return ((red - 1) / 1.5) * 100 + 100;
        },
      },
    ];

    let { catInfoElement, contentContainer } = createCatInfoContainer();
    contentContainer.classList.add("parameter-details-container");

    parameters.forEach(({ id, name, timePerPixel, formula }) => {
      const table = document.getElementById(id);
      if (table) {
        const row = table.querySelector("tbody tr");
        if (!row) {
          console.warn(`Строка не найдена в таблице с ID "${id}".`);
          return;
        }
        const greenBar = row.querySelector(
          "td[style*='background-color: green;']"
        );
        const redBar = row.querySelector("td[style*='background-color: red;']");
        if (!greenBar || !redBar) {
          console.warn(`Бары не найдены в строке таблицы с ID "${id}".`);
          return;
        }
        const greenBarWidth = parseInt(greenBar.style.width, 10);
        const redBarWidth = parseInt(redBar.style.width, 10);
        const totalWidth = greenBarWidth + redBarWidth;
        let percentage = (greenBarWidth / totalWidth) * 100;
        percentage =
          percentage % 1 !== 0 ? percentage.toFixed(2) : Math.round(percentage);

        let timeInfo = "";
        let totalTimeSeconds;
        if (formula) {
          totalTimeSeconds = formula(redBarWidth);
        } else if (timePerPixel !== null) {
          totalTimeSeconds = redBarWidth * timePerPixel;
        }

        if (totalTimeSeconds !== undefined) {
          const hours = Math.floor(totalTimeSeconds / 3600);
          const minutes = Math.floor((totalTimeSeconds % 3600) / 60);
          const seconds = totalTimeSeconds % 60;
          if (hours > 0) {
            timeInfo = ` (> ${hours} ч ${minutes} мин)`;
          } else if (minutes > 0) {
            timeInfo = ` (${minutes} мин ${seconds} сек)`;
          } else {
            timeInfo = ` (${seconds} сек)`;
          }
        }

        const detailLine = document.createElement("p");
        detailLine.innerHTML = `<strong>${name}:</strong> <span style="color: #00cc00;">${greenBarWidth}px</span> / <span style="color: red;">${redBarWidth}px</span> - ${percentage}%`;
        detailLine.style.marginBottom = "0";
        contentContainer.appendChild(detailLine);

        if (timeInfo) {
          const detailLineTime = document.createElement("p");
          detailLineTime.innerHTML = `≈${timeInfo}`;
          detailLineTime.style.marginTop = "0";
          contentContainer.appendChild(detailLineTime);
        }
      } else {
        console.warn(`Таблица с ID "${id}" не найдена.`);
      }
    });

    globalContainer.appendChild(catInfoElement);
  }

  if (settings.showParametersDetails) {
    setupSingleCallback("#dream_table", createMoreInfoButton);
  }
  // ====================================================================================================================
  //   . . . ЧИСЛОВАЯ ГРОМКОСТЬ УВЕДОМЛЕНИЙ . . .
  // ====================================================================================================================
  if (settings.climbingNotificationsNumbers) {
    function addClimbingNotificationsStyles() {
      const styles = Array.from(
        { length: 11 },
        (_, i) => `
          .vlm${i} > .nick[style*="italic"]:after {
            content: " [${i}]";
          }
        `
      ).join("");

      const styleElement = document.createElement("style");
      styleElement.textContent = styles;
      document.head.appendChild(styleElement);
    }

    addClimbingNotificationsStyles();
  }
  // ====================================================================================================================
  //   . . . ЗВУКОВОЕ УВЕДОМЛЕНИЕ ПРИ ОБНОВЛЕНИИ КЛЕТОК . . .
  // ====================================================================================================================
  // TODO - debounceTimer, если не сработает решение со сравнением историй. P.S. Вроде работает.
  if (settings.climbingRefreshNotification) {
    function handleClimbingRefresh() {
      const refreshRegex = /Услышала? оглушительн/;
      let previousHistory = "";

      const updateHistory = () => {
        const istElement = document.getElementById("ist");
        const currentHistory = istElement.innerHTML;

        if (currentHistory !== previousHistory) {
          previousHistory = currentHistory;

          const entries = currentHistory.split(".");
          const lastEntry = entries[entries.length - 2];

          if (lastEntry !== undefined && refreshRegex.test(lastEntry)) {
            const lastPlayedEntry = entries[entries.length - 3];

            if (!lastPlayedEntry || !refreshRegex.test(lastPlayedEntry)) {
              soundManager.playSound(
                settings.climbingRefreshNotificationSound,
                settings.climbingRefreshNotificationVolume
              );
            }
          }
        }
      };

      const historyBlock = document.getElementById("history_block");
      const observer = new MutationObserver(() => {
        updateHistory();
      });

      const config = {
        childList: true,
        subtree: true,
        characterData: true,
      };
      observer.observe(historyBlock, config);
    }

    handleClimbingRefresh();
  }
  // ====================================================================================================================
  //   . . . МИННОЕ ПОЛЕ . . .
  // ====================================================================================================================
  // Вторая по ненависти работа с кодами. Но уже к самому себе а не к сайту.........
  // чат уже ничего не перебьёт....... наверно????????????
  // TODO - Переписать всё это мессиво к чертям, это кошмар какой-то. Как оно вообще ещё работает?????? Что я употреблял?????????????????????
  if (settings.climbingPanel) {
    let isDragging = false;
    let initialX;
    let initialY;
    let currentX;
    let currentY;
    let wasDragging = false;

    function saveClimbingPanelStatus() {
      const status = {
        x: currentX,
        y: currentY,
        isOpen: climbingPanelContainer.classList.contains("open"),
        isChecked: transferCheckbox.checked,
        currentTabIndex: tabManager.currentTabIndex,
        currentTableId: tabManager.currentTableId,
      };
      localStorage.setItem("uwu_climbingPanelStatus", JSON.stringify(status));
    }

    function loadClimbingPanelStatus() {
      const savedStatus = localStorage.getItem("uwu_climbingPanelStatus");

      if (savedStatus) {
        const status = JSON.parse(savedStatus);

        currentX = status.x;
        currentY = status.y;

        climbingPanelContainer.classList.toggle("open", status.isOpen);
        transferCheckbox.checked = status.isChecked;

        tabManager.currentTabIndex = status.currentTabIndex;
        if (
          status.currentTableId !== null &&
          tabManager.tabs[status.currentTabIndex].tables[status.currentTableId]
        ) {
          tabManager.currentTableId = status.currentTableId;
        }

        tabManager.render();

        if (status.isChecked) {
          transferColors();
        }
      } else {
        tabManager.render();
      }

      checkAndResetPanelPosition();
    }

    function updateCell(cell, value) {
      cell.dataset.value = value || "";
      cell.textContent = value === "mine" || value === "transit" ? "" : value;
      switch (value) {
        case "mine":
          cell.style.backgroundColor = "#5b000073";
          break;
        case "transit":
          cell.style.backgroundColor = "#ffffff87";
          break;
        default:
          cell.style.backgroundColor = "";
      }
    }

    function transferColors() {
      const transferCheckbox = document.getElementById("uwu-transferCheckbox");
      if (!transferCheckbox.checked) return;

      const climbingPanelCells = Array.from(
        document.querySelectorAll("#uwu-climbingPanel td")
      );
      const cagesCells = Array.from(
        document.querySelectorAll("#cages tbody td.cage")
      );

      climbingPanelCells.forEach((cell, i) => {
        if (cagesCells[i]) {
          cagesCells[i].style.backgroundColor =
            getComputedStyle(cell).backgroundColor;
        }
      });
    }

    function clearColors() {
      const cagesCells = document.querySelectorAll("#cages tbody td.cage");
      cagesCells.forEach((cell) => {
        cell.style.backgroundColor = "";
      });
    }

    let lastClickedCell = null;

    function handleCellClick(event) {
      const cell = event.target.closest("td");
      if (!cell || !cell.closest("#uwu-climbingPanel")) return;

      if (lastClickedCell === cell) {
        updateCell(cell, "");
        saveTableData(tabManager.currentTableId);
        transferColors();
        lastClickedCell = null;
      } else {
        lastClickedCell = cell;
      }
    }

    function handleKeyDown(event) {
      const keyPressed = event.key;
      const activeElement = document.activeElement;

      if (
        activeElement &&
        activeElement.tagName === "TD" &&
        activeElement.closest("#uwu-climbingPanel")
      ) {
        switch (keyPressed) {
          case "0":
          case "1":
          case "2":
          case "3":
          case "4":
          case "5":
          case "6":
          case "7":
            updateCell(activeElement, keyPressed);
            break;
          case "-":
            updateCell(activeElement, "mine");
            break;
          case "=":
            updateCell(activeElement, "transit");
            break;
          default:
            return;
        }

        saveTableData(tabManager.currentTableId);
        transferColors();
      }
    }

    function handleTransferCheckboxChange(event) {
      event.target.checked ? transferColors() : clearColors();
      saveClimbingPanelStatus();
    }

    const uwuClimbingPanelContainer = // html
    `
      <div id="uwu-climbingMainPanel">
        <div id="uwu-climbingPanelButton">
            <div class="left-content">
                <h2>Минное поле</h2>
            </div>
            <div class="right-content">
                <span id="uwu-arrow">▼</span>
            </div>
        </div>
      <div id="uwu-climbingPanelContainer">
          <div id="uwu-climbingPanelContent">
              <div id="uwu-buttonContainer">
                  <h3>Вкладка</h3>
                  <div id="uwu-buttonRow1"></div>
                  <hr id="uwu-hr">
                  <h3>Локация</h3>
                  <div id="uwu-buttonRow2"></div>
              </div>
              <div id="uwu-functionButtonsContainer">
                  <input type="checkbox" id="uwu-transferCheckbox">
                  <label for="uwu-transferCheckbox">Перенос на Игровое поле</label>
              </div>
              <div id="uwu-tableContainer"></div>
          </div>
      </div>
      </div>
    `;

    function createClimbingPanel() {
      const globalContainer = document.getElementById("uwu-global-container");
      globalContainer.insertAdjacentHTML(
        "beforeend",
        uwuClimbingPanelContainer
      );

      const transferCheckbox = document.getElementById("uwu-transferCheckbox");

      document.addEventListener("keydown", handleKeyDown);
      transferCheckbox.addEventListener("change", handleTransferCheckboxChange);
    }

    function saveTableData(tableIndex) {
      const climbingPanel = document.getElementById("uwu-climbingPanel");
      if (!climbingPanel) return;

      const tableData = getTableData(climbingPanel.id);
      const currentTab = tabManager.tabs[tabManager.currentTabIndex];
      currentTab.tables[tableIndex] = {
        name: currentTab.tables[tableIndex].name,
        data: tableData,
      };
      tabManager.saveState();
    }

    function clearTable() {
      const climbingPanel = document.getElementById("uwu-climbingPanel");
      if (!climbingPanel) return;

      const cells = Array.from(climbingPanel.querySelectorAll("td"));
      cells.forEach((cell) => {
        if (cell.dataset.value !== "transit") {
          updateCell(cell, "");
        }
      });

      const currentTab = tabManager.tabs[tabManager.currentTabIndex];
      currentTab.tables[tabManager.currentTableId] = {
        name: currentTab.tables[tabManager.currentTableId].name,
        data: getTableData(climbingPanel.id),
      };
      tabManager.saveState();
      transferColors();
    }

    const tabManager = {
      tabs: [],
      currentTabIndex: 0,
      currentTableId: 0,

      createTab(name) {
        const newTab = {
          name: name,
          tables: [],
        };

        this.tabs.push(newTab);
        this.render();
        this.switchTab(this.tabs.length - 1);
      },

      switchTab(index) {
        this.currentTabIndex = index;
        const currentTab = this.tabs[this.currentTabIndex];
        this.currentTableId =
          currentTab && currentTab.tables.length > 0 ? 0 : null;

        if (currentTab && currentTab.tables.length === 0) {
          this.renderNoTableMessage();
        } else {
          this.render();
        }

        transferColors();
        saveClimbingPanelStatus();
      },

      switchTable(tableIndex) {
        this.currentTableId = tableIndex;
        this.render();
        transferColors();
        saveClimbingPanelStatus();
      },

      saveState() {
        localStorage.setItem("uwu_climbingPanelState", JSON.stringify(this));
      },

      render() {
        this.renderTabs();
        this.renderTables();
        if (this.currentTableId !== null) {
          this.renderTable(this.currentTableId);
        }
      },

      renderTabs() {
        const tabRow = document.getElementById("uwu-buttonRow1");
        tabRow.innerHTML = "";

        this.tabs.forEach((tab, index) => {
          const tabButton = document.createElement("button");
          tabButton.textContent = tab.name;
          tabButton.classList.add("tab-button");

          if (index === this.currentTabIndex) {
            tabButton.classList.add("active");
          }

          tabButton.addEventListener("click", () => this.switchTab(index));

          const tabContainer = document.createElement("div");
          tabContainer.classList.add("tab-container");
          tabContainer.appendChild(tabButton);

          tabRow.appendChild(tabContainer);
        });
      },

      renderTables() {
        const tableRow = document.getElementById("uwu-buttonRow2");
        tableRow.innerHTML = "";

        const currentTab = this.tabs[this.currentTabIndex];
        if (currentTab) {
          currentTab.tables.forEach((table, index) => {
            const tableButton = document.createElement("button");
            tableButton.textContent = table.name || `Локация ${index + 1}`;
            tableButton.classList.add("table-button");

            if (index === this.currentTableId) {
              tableButton.classList.add("active");
            }

            tableButton.addEventListener("click", () =>
              this.switchTable(index)
            );

            const tableContainer = document.createElement("div");
            tableContainer.classList.add("table-container");
            tableContainer.appendChild(tableButton);

            tableRow.appendChild(tableContainer);
          });
        }
      },

      renderTable(tableIndex) {
        const tableContainer = document.getElementById("uwu-tableContainer");
        tableContainer.innerHTML = "";

        const currentTab = this.tabs[this.currentTabIndex];
        const climbingPanel = document.createElement("table");
        climbingPanel.id = "uwu-climbingPanel";

        for (let i = 0; i < 6; i++) {
          const row = document.createElement("tr");
          for (let j = 0; j < 10; j++) {
            const cell = document.createElement("td");
            cell.setAttribute("tabindex", "0");
            cell.addEventListener("click", handleCellClick);
            row.appendChild(cell);
          }
          climbingPanel.appendChild(row);
        }

        const tableData = currentTab.tables[tableIndex]?.data;

        if (tableData) {
          tableData.forEach((rowData, i) => {
            rowData.forEach((cellData, j) => {
              updateCell(climbingPanel.rows[i].cells[j], cellData.value);
            });
          });
        }

        tableContainer.appendChild(climbingPanel);

        const clearButton = document.createElement("button");
        clearButton.textContent = "Очистить всё поле/таблицу";
        clearButton.id = "button-clear-table";
        clearButton.addEventListener("click", clearTable);
        tableContainer.appendChild(clearButton);
      },

      renderNoTableMessage() {
        const tableContainer = document.getElementById("uwu-tableContainer");
        tableContainer.innerHTML = "";

        const message = document.createElement("div");
        message.textContent = "Добавьте поле/таблицу в настройках";
        message.style.textAlign = "center";
        message.style.marginTop = "20px";
        tableContainer.appendChild(message);

        this.renderTabs();
        this.renderTables();
      },
    };

    function loadSavedState() {
      const savedState = localStorage.getItem("uwu_climbingPanelState");
      if (savedState) {
        const state = JSON.parse(savedState);
        Object.assign(tabManager, state);
        tabManager.currentTabIndex = 0;

        const currentTab = tabManager.tabs[tabManager.currentTabIndex];
        if (currentTab && currentTab.tables.length > 0) {
          if (tabManager.currentTableId >= currentTab.tables.length) {
            tabManager.currentTableId = 0;
          }
        } else {
          tabManager.currentTableId = null;
        }
      }
    }

    loadSavedState();
    createClimbingPanel();
    tabManager.render();

    function getTableData(tableId) {
      const table = document.getElementById(tableId);
      if (!table) {
        console.error(`Таблица с id ${tableId} не найдена`);
        return [];
      }

      const tableData = [];

      for (let i = 0; i < table.rows.length; i++) {
        const rowData = [];
        for (let j = 0; j < table.rows[i].cells.length; j++) {
          const cell = table.rows[i].cells[j];
          rowData.push({
            value: cell.dataset.value || "",
          });
        }
        tableData.push(rowData);
      }

      return tableData;
    }

    // ===================== ПЕРЕТАСКИВАНИЕ =====================

    const climbingMainPanel = document.getElementById("uwu-climbingMainPanel");
    const climbingPanelButton = document.getElementById(
      "uwu-climbingPanelButton"
    );
    const climbingPanelContainer = document.getElementById(
      "uwu-climbingPanelContainer"
    );
    const transferCheckbox = document.getElementById("uwu-transferCheckbox");

    function dragStart(e) {
      e.preventDefault();
      const savedStatus = JSON.parse(
        localStorage.getItem("uwu_climbingPanelStatus")
      );
      initialX =
        e.clientX -
        (savedStatus ? savedStatus.x : climbingMainPanel.offsetLeft);
      initialY =
        e.clientY - (savedStatus ? savedStatus.y : climbingMainPanel.offsetTop);

      if (e.target === climbingPanelButton) {
        isDragging = true;
        wasDragging = false;
      }
    }

    function drag(e) {
      if (isDragging) {
        e.preventDefault();

        currentX = e.clientX - initialX;
        currentY = e.clientY - initialY;

        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        const panelWidth = climbingMainPanel.offsetWidth;
        const panelHeight = climbingMainPanel.offsetHeight;

        const maxX = windowWidth - panelWidth;
        currentX = Math.max(0, Math.min(currentX, maxX));

        const maxY = windowHeight - panelHeight;
        currentY = Math.max(0, Math.min(currentY, maxY));

        setPosition(currentX, currentY, climbingMainPanel);

        wasDragging = true;
      }
    }

    function dragEnd(e) {
      if (isDragging) {
        saveClimbingPanelStatus();
      }
      isDragging = false;
    }

    function setPosition(x, y, el) {
      el.style.left = `${x}px`;
      el.style.top = `${y}px`;
    }

    function togglePanelContainer(e) {
      if (!wasDragging) {
        const arrow = document.getElementById("uwu-arrow");
        climbingPanelContainer.classList.toggle("open");
        saveClimbingPanelStatus();
  
        if (climbingPanelContainer.classList.contains("open")) {
          arrow.textContent = "▲";
        } else {
          arrow.textContent = "▼";
        }
      }
      wasDragging = false;
    }

    function checkAndResetPanelPosition() {
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;
      const panelWidth = climbingMainPanel.offsetWidth;
      const panelHeight = climbingMainPanel.offsetHeight;

      const savedStatus = JSON.parse(
        localStorage.getItem("uwu_climbingPanelStatus")
      );

      if (savedStatus) {
        currentX = savedStatus.x;
        currentY = savedStatus.y;
      } else {
        currentX = 0;
        currentY = 0;
      }

      if (
        currentX + panelWidth > windowWidth ||
        currentY + panelHeight > windowHeight
      ) {
        currentX = 0;
        currentY = 0;
        saveClimbingPanelStatus();
      }

      setPosition(currentX, currentY, climbingMainPanel);
    }

    climbingPanelButton.addEventListener("mousedown", dragStart);
    document.addEventListener("mouseup", dragEnd);
    document.addEventListener("mousemove", drag);
    climbingPanelButton.addEventListener("click", togglePanelContainer);

    setTimeout(loadClimbingPanelStatus, 10);

    const uwuClimbingPanel = document.createElement("style");
    uwuClimbingPanel.innerHTML = // css
    `
    #uwu-climbingPanelContainer {
      background-color: "";
      display: none;
      padding: 5px;
    }
    
    #uwu-climbingPanelContainer.open {
      display: block;
    }

    #uwu-climbingMainPanel {
      z-index: 2;
      pointer-events: auto;
      width: 260px;
      position: absolute;
      background-color: #ffffff08;
      border: 1px solid #ffffff1a;
      backdrop-filter: blur(20px);
      border-radius: 10px;
    }

    #uwu-climbingPanelButton .left-content {
      pointer-events: none;
      width: 90%;
    }

    #uwu-climbingPanelButton .right-content {
      pointer-events: none;
      width: 10%;
      text-align: right;
    }

    #uwu-arrow {
      font-size: 18px;
      margin-right: 8px;
    }

    #uwu-climbingPanelButton {
      cursor: grab;
      background-color: #00000026;
      border-radius: 10px;
      border: 1px solid #ffffff1a;
      display: flex;
      align-items: center;
      justify-content: space-around;
    }

    #uwu-climbingPanelButton h2 {
      display: flex;
      margin-top: 2px;
      margin-bottom: 2px;
      justify-content: center;
      pointer-events: none;
    }

    #uwu-climbingPanel {
      font-size: 26px;
      border-collapse: collapse;
      width: fit-content;
      background-color: #ffffff1a;
      border: 2px solid black;
    }
  
    #uwu-climbingPanel > tr> td {
      width: 23px;
      height: 32px;
      border: 1px solid black;
      text-align: center;
      cursor: pointer;
      pointer-events: auto;
      position: relative;
    }

    #uwu-climbingPanelContainer h3 {
      margin-top: 5px;
      margin-bottom: 5px;
    }

    #uwu-functionButtonsContainer {
      height: 25px;
    }

    #uwu-climbingPanel > tr > td:focus {
      outline: 2px solid white;
    }

    #uwu-climbingPanel > tr > td:not(:empty) {
      background-color: #cccccc4d;
    }

    #uwu-transferCheckbox, #uwu-transferValuesCheckbox {
    pointer-events: auto;
    cursor: pointer;
    }

    #uwu-buttonRow1,
    #uwu-buttonRow2 {
      display: flex;
      flex-wrap: wrap;
    }

    #uwu-climbingPanel > tab-container, #uwu-climbingPanel > table-container {
      display: inline-block;
      margin-right: 10px;
    }
  
    #uwu-climbingPanelContainer button {
      background-color: #ffffff4d;
      border: 1px solid rgba(255, 255, 255, 0.1);
      padding: 2px 10px;
      border-radius: 10px;
      cursor: pointer;
      transition: background-color 0.3s ease;
      margin: 3px;
      margin-left: 0px;
    }

    #uwu-buttonRow1 > div > button.tab-button.active,
    #uwu-buttonRow2 > div > button.table-button.active {
      background-color: #abf6ffb0;
    }

    #button-clear-table {
      margin-top: 5px !important;
      width: 100%;
      border-radius: 5px !important;
    }
  `;
    document.head.appendChild(uwuClimbingPanel);

    const uwuClimbingPanelHorizontal = document.createElement("style");
    uwuClimbingPanelHorizontal.innerHTML = // css
    `
    #uwu-climbingMainPanel {
      width: 390px !important;
    }

    #uwu-climbingPanelContent {
      display: grid !important;
      grid-template-columns: 1fr 2fr;
      grid-template-rows: auto auto;
    }
    
    #uwu-buttonContainer {
      overflow-y: auto;
      grid-column: 1 / 2;
      grid-row: 1 / 3;
    }
    
    #uwu-functionButtonsContainer {
      grid-column: 2 / 3;
      grid-row: 1 / 2;
    }
    
    #uwu-tableContainer {
      grid-column: 2 / 3;
      grid-row: 2 / 3;
    }
    `;

    if (settings.climbingPanelOrientation === "horizontal") {
      document.head.appendChild(uwuClimbingPanelHorizontal);
    }
  }
  // ====================================================================================================================
  //   . . . БЫСТРЫЕ СТИЛИ . . .
  // ====================================================================================================================
  const settingsContainer = document.getElementById(
    "extended-settings-container"
  );
  if (!settingsContainer) {
    console.error("Контейнер #extended-settings-container не найден");
    return;
  }

  const checkboxes = [
    {
      label: "Не показывать всплывающее окно 'О коте'",
      key: "hideCatTooltip",
      storageKey: "uwu_fastStyles",
      style: ".cat_tooltip { display: none !important; }",
      callback: function (checked) {
        if (checked) {
          const style = document.createElement("style");
          style.innerHTML = this.style;
          document.head.appendChild(style);
        } else {
          const styles = document.head.querySelectorAll("style");
          styles.forEach((style) => {
            if (style.innerHTML === this.style) {
              document.head.removeChild(style);
            }
          });
        }
      },
    },
    {
      label: "Скрыть Игровое поле",
      key: "hideGameField",
      storageKey: "uwu_fastStyles",
      style: "#cages_overflow { visibility: hidden !important; }",
      callback: function (checked) {
        if (checked) {
          const style = document.createElement("style");
          style.innerHTML = this.style;
          document.head.appendChild(style);
        } else {
          const styles = document.head.querySelectorAll("style");
          styles.forEach((style) => {
            if (style.innerHTML === this.style) {
              document.head.removeChild(style);
            }
          });
        }
      },
    },
    {
      label: "Скрыть фон Игрового Поля",
      key: "hideGameFieldBackground",
      storageKey: "uwu_fastStyles",
      style: "#cages_div { background-image: none !important; }",
      callback: function (checked) {
        if (checked) {
          const style = document.createElement("style");
          style.innerHTML = this.style;
          document.head.appendChild(style);
        } else {
          const styles = document.head.querySelectorAll("style");
          styles.forEach((style) => {
            if (style.innerHTML === this.style) {
              document.head.removeChild(style);
            }
          });
        }
      },
    },
    {
      label: "Скрыть Небо",
      key: "hideSky",
      storageKey: "uwu_fastStyles",
      style: "#tr_sky { display: none !important; }",
      callback: function (checked) {
        if (checked) {
          const style = document.createElement("style");
          style.innerHTML = this.style;
          document.head.appendChild(style);
        } else {
          const styles = document.head.querySelectorAll("style");
          styles.forEach((style) => {
            if (style.innerHTML === this.style) {
              document.head.removeChild(style);
            }
          });
        }
      },
    },
    {
      label: "Всегда день/ярко",
      key: "alwaysDay",
      storageKey: "uwu_settings",
      callback: function (checked) {
        updateAlwaysDayStyle(checked);
      },
    },
    {
      label: "Границы клеток",
      key: "cellsBorders",
      storageKey: "uwu_settings",
      callback: function (checked) {
        updateCellsBordersStyle(checked);
      },
    },
  ];

  const loadSettings = (storageKey) => {
    const savedSettings = localStorage.getItem(storageKey);
    return savedSettings ? JSON.parse(savedSettings) : {};
  };

  const saveSettings = (storageKey, settings) => {
    localStorage.setItem(storageKey, JSON.stringify(settings));
  };

  const settingsMap = {
    uwu_fastStyles: loadSettings("uwu_fastStyles"),
    uwu_settings: loadSettings("uwu_settings"),
  };

  const applyStyles = () => {
    checkboxes.forEach((checkbox) => {
      if (settingsMap[checkbox.storageKey][checkbox.key] === true) {
        checkbox.callback.call(checkbox, true);
      }
    });
  };

  if (settings.fastStyles) {
    const settingsDiv = document.createElement("div");
    settingsDiv.id = "fast-Styles-container";
    settingsDiv.classList.add("extended-settings-block");

    checkboxes.forEach((checkbox) => {
      const label = document.createElement("div");
      const input = document.createElement("input");
      input.type = "checkbox";
      input.name = checkbox.key;

      const storedValue = settingsMap[checkbox.storageKey][checkbox.key];
      if (storedValue === true) {
        input.checked = true;
        checkbox.callback.call(checkbox, true);
      }

      input.addEventListener("change", function () {
        settingsMap[checkbox.storageKey][checkbox.key] = this.checked;
        saveSettings(checkbox.storageKey, settingsMap[checkbox.storageKey]);
        checkbox.callback.call(checkbox, this.checked);
      });

      label.appendChild(input);
      label.appendChild(document.createTextNode(checkbox.label));
      settingsDiv.appendChild(label);
    });

    settingsContainer.appendChild(settingsDiv);

    const style = document.createElement("style");
    style.innerHTML = `
      .extended-settings-block {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
      .extended-settings-block div {
        display: flex;
       align-items: center;
      }
    `;
    document.head.appendChild(style);
  } else {
    applyStyles();
  }
  // ====================================================================================================================
  //   . . . БЫСТРЫЕ ССЫЛКИ В ИГРОВОЙ . . .
  // ====================================================================================================================
  const quickLinks = {
    quickLink1: {
      href: "/settings",
      text: "Настройки",
    },
    quickLink2: {
      href: "/ls?id=0",
      text: "Памятка",
    },
    quickLink3: {
      href: "/blogs",
      text: "Блоги",
    },
    quickLink4: {
      href: "/sniff",
      text: "Лента",
    },
  };

  const spanElement = document.querySelector("span.small");

  Object.entries(quickLinks).forEach(([key, link]) => {
    if (settings[key]) {
      const newLink = document.createElement("a");
      newLink.href = link.href;
      newLink.textContent = link.text;

      const pipe = document.createTextNode(" | ");
      spanElement.appendChild(pipe);
      spanElement.appendChild(newLink);
    }
  });

  if (settings.userQuickLinks) {
    const userLinksArray = settings.userQuickLinks.split(", ");

    userLinksArray.forEach((userLink) => {
      const [href, text] = userLink.trim().split(" ");

      const newLink = document.createElement("a");
      newLink.href = href;
      newLink.textContent = text;

      const pipe = document.createTextNode(" | ");
      spanElement.appendChild(pipe);
      spanElement.appendChild(newLink);
    });
  }
  // ====================================================================================================================
  //  . . . ПОДСВЕТКА РЕСУРСОВ . . .
  // ====================================================================================================================
  if (settings.highlightResources) {
    function hexToRGBA(hex, alpha) {
      const r = parseInt(hex.slice(1, 3), 16);
      const g = parseInt(hex.slice(3, 5), 16);
      const b = parseInt(hex.slice(5, 7), 16);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }
  
    const ITEM_MAP = {
      'Травы': ['13', '15', '17', '19', '21', '23', '25', '26', '106', '108', '109', '110', '111', '112', '115', '116', '119', '655'],
      'Мох': ['75', '78', '95'],
      'Паутина': ['20'],
      'Пыль': ['94', '385', '386', '387', '388', '389', '390', '391', '392'],
      'Ветки, вьюнки, костоправы': ['565', '566', '562', '563', '3993'],
      'Травящие предметы': ['985', '986', '987', '988', '989', '44', '180', '77', '7801', '7802', '7803', '7804', '7805', '7806']
    };
  
    function generateHighlightStyles(cageItem) {
      const savedSettings = localStorage.getItem('uwu_highlightResources');
      if (!savedSettings) return;
    
      const uwu_highlightResources = JSON.parse(savedSettings);
    
      if (settings.highlightResourcesStyle === "background") {
        const styleElement = document.getElementById('resourcesStyle') || document.createElement('style');
        styleElement.id = 'resourcesStyle';
        styleElement.textContent = '';
    
        uwu_highlightResources.forEach(resource => {
          if (resource.highlight) {
            const rgbaColor = hexToRGBA(resource.color, 0.4);
            let cssRules = '';
    
            const items = ITEM_MAP[resource.name];
            if (!items) {
              console.warn("Неизвестный ресурс:", resource.name);
              return;
            }
    
            items.forEach(itemName => {
              cssRules += `
                .cage_items[style*='things/${itemName}.png'] {
                  background-color: ${rgbaColor} !important;
                }`;
            });
    
            if (cssRules) {
              styleElement.textContent += cssRules;
            }
          }
        });
    
        document.head.appendChild(styleElement);
      } else if (settings.highlightResourcesStyle === "glow") {
        const style = cageItem.getAttribute("style");
        if (!style) return;
    
        const oldHighlights = cageItem.querySelectorAll("style.uwu_itemHighlight");
        oldHighlights.forEach(oldHighlight => oldHighlight.remove());
    
        cageItem.style.position = 'relative';
    
        uwu_highlightResources.forEach((resource) => {
          if (resource.highlight) {
            const rgbaColor = hexToRGBA(resource.color, 1);
            let highlightedItems = [];
    
            const items = ITEM_MAP[resource.name];
            if (!items) {
              console.warn("Неизвестный ресурс:", resource.name);
              return;
            }
    
            items.forEach((itemName) => {
              const backgroundImages = style.match(/url\("things\/(.*?)\.png"\) (\d+)% (\d+)% no-repeat/g) || [];
    
              backgroundImages.forEach((backgroundImage) => {
                if (backgroundImage.includes(`things/${itemName}.png`)) {
                  const positionMatch = backgroundImage.match(/(url\("things\/(.*?)\.png"\)) (\d+)% (\d+)% no-repeat/);
                  const imageUrl = positionMatch ? positionMatch[1] : "";
                  const positionX = positionMatch ? positionMatch[3] : "0";
                  const positionY = positionMatch ? positionMatch[4] : "0";
    
                  highlightedItems.push(
                    `${imageUrl} ${positionX}% ${positionY}% no-repeat`
                  );
                }
              });
            });
    
            if (highlightedItems.length > 0) {
              const styleBody = `
                content: '';
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                pointer-events: none;
                background: ${highlightedItems.join(", ")};
                filter: drop-shadow(0 0 8px ${rgbaColor}) drop-shadow(0 0 8px ${rgbaColor});
              `;
    
              const styleElement = document.createElement('style');
              styleElement.classList.add('uwu_itemHighlight');
              styleElement.textContent = `
                .cage_items[style*='${style}']::before {
                  ${styleBody}
                }
              `;
              cageItem.appendChild(styleElement);
            }
          }
        });
      }
    }
  
    function setupMutationObserver(targetNode, callback, config) {
      const observer = new MutationObserver((mutationsList, observer) => {
        for (let mutation of mutationsList) {
          if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
            callback(targetNode);
          }
        }
      });
  
      observer.observe(targetNode, config);
    }
  
    document.querySelectorAll(".cage_items").forEach((cageItem) => {
      generateHighlightStyles(cageItem);
      setupMutationObserver(cageItem, generateHighlightStyles, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    });
  }
  // ====================================================================================================================
  //   . . . ПОЛЬЗОВАТЕЛЬКИЙ ФОН . . .
  // ====================================================================================================================
  const cagesDiv = document.querySelector("#cages_div");

  function createBackgroundDiv() {
    const backgroundDiv = document.createElement("div");
    backgroundDiv.style.position = "fixed";
    backgroundDiv.style.top = "-1%";
    backgroundDiv.style.left = "-1%";
    backgroundDiv.style.width = "102%";
    backgroundDiv.style.height = "102%";
    backgroundDiv.style.zIndex = "-2";
    backgroundDiv.style.overflow = "hidden";
    return backgroundDiv;
  }

  function updateBackgroundImage(backgroundDiv, imageUrl) {
    if (imageUrl) {
      backgroundDiv.style.backgroundImage = `url(${imageUrl})`;
      backgroundDiv.style.backgroundSize = "cover";
      backgroundDiv.style.backgroundPosition = "center";
      backgroundDiv.style.backgroundRepeat = "no-repeat";
    } else {
      backgroundDiv.style.backgroundImage = "none";
    }
  }

  if (settings.backgroundRepeat) {
    const backgroundDiv = createBackgroundDiv();

    backgroundDiv.style.filter = "blur(16px)";
    backgroundDiv.style.backgroundBlendMode = "overlay";
    backgroundDiv.style.backgroundColor = "rgba(0, 0, 0, 0.5)";

    const backgroundImageStyle =
      window.getComputedStyle(cagesDiv).backgroundImage;
    const url = backgroundImageStyle.match(/url\("?(.+?)"?\)/);
    const backgroundImageUrl = url ? url[1] : null;

    updateBackgroundImage(backgroundDiv, backgroundImageUrl);
    globalContainerElement.appendChild(backgroundDiv);

    setupMutationObserver(
      "#cages_div",
      () => {
        const backgroundImageStyle =
          window.getComputedStyle(cagesDiv).backgroundImage;
        const url = backgroundImageStyle.match(/url\("?(.+?)"?\)/);
        const backgroundImageUrl = url ? url[1] : null;
        updateBackgroundImage(backgroundDiv, backgroundImageUrl);
      },
      { attributes: true, attributeFilter: ["style"] },
      8,
      500,
      10
    );
  }

  if (settings.backgroundUser) {
    const backgroundDiv = createBackgroundDiv();
    updateBackgroundImage(backgroundDiv, settings.backgroundUserImageURL);
    globalContainerElement.appendChild(backgroundDiv);
  }
  // ====================================================================================================================
  //   . . . ПОЛЬЗОВАТЕЛЬСКИЕ ЦВЕТА НАВЫКОВ И ПАРАМЕТРОВ . . .
  // ====================================================================================================================
  if (settings.userParametersTheme) {
    const defaultBackgroundImageUrl =
      "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/parametersBackgroundImageURL.png";

    function applyParameterColors() {
      let cssStyles = "";

      const otherColors = settings.parametersColors.other;
      const otherFirstCellBackground = `linear-gradient(to right, ${otherColors[0]}, ${otherColors[1]})`;
      const otherLastCellBackground = `linear-gradient(to right, ${otherColors[2]}, ${otherColors[3]})`;

      cssStyles += `#parameters_block .parameter td:first-child { background: ${otherFirstCellBackground}; }\n`;
      cssStyles += `#parameters_block .parameter td:last-child { background: ${otherLastCellBackground}; }\n`;

      for (const paramId in settings.parametersColors) {
        if (paramId === "other") continue;

        const colors = settings.parametersColors[paramId];
        const backgroundImageURL = settings.parametersUserBackgroundImage
          ? settings.parametersUserBackgroundImageURL
          : defaultBackgroundImageUrl;
        const firstCellBackground =
          settings.parametersBackgroundImage ||
          settings.parametersUserBackgroundImage
            ? `url(${backgroundImageURL}), linear-gradient(to right, ${colors[0]}, ${colors[1]})`
            : `linear-gradient(to right, ${colors[0]}, ${colors[1]})`;
        const lastCellBackground =
          settings.parametersBackgroundImage ||
          settings.parametersUserBackgroundImage
            ? `url(${backgroundImageURL}), linear-gradient(to right, ${colors[2]}, ${colors[3]})`
            : `linear-gradient(to right, ${colors[2]}, ${colors[3]})`;

        cssStyles += `#${paramId}_table .parameter td:first-child { background: ${firstCellBackground}; }\n`;
        cssStyles += `#${paramId}_table .parameter td:last-child { background: ${lastCellBackground}; }\n`;
      }

      const styleTag = document.createElement("style");
      styleTag.id = "custom-parameter-styles";
      styleTag.innerHTML = cssStyles;
      document.head.appendChild(styleTag);
    }

    applyParameterColors();
  }
  // ====================================================================================================================
  //   . . . ПОЛЬЗОВАТЕЛЬСКИЙ ШРИФТ . . .
  // ====================================================================================================================
  let fontSize = JSON.parse(localStorage.getItem('uwu_fontSize'));
  function applyFonts() {
    const newFontStyle = document.createElement("style");
    newFontStyle.innerHTML = // css
      `
      body {
        font-size: ${fontSize?.fontSizeBody}px;
        font-family: ${fontSize?.fontFamilyBody};
      }

      .small {
        font-size: ${fontSize?.fontSizeSmall}px;
      }

      #location {
        font-size: ${fontSize?.fontSizeLocation}px !important;
      }

      .vlm0 {
        font-size: ${fontSize?.vlm0}px; }

      .vlm1 {
        font-size: ${fontSize?.vlm1}px; }

      .vlm2 {
        font-size: ${fontSize?.vlm2}px; }

      .vlm3 {
        font-size: ${fontSize?.vlm3}px; }

      .vlm4 {
        font-size: ${fontSize?.vlm4}px; }

      .vlm5 {
        font-size: ${fontSize?.vlm5}px; }

      .vlm6 {
        font-size: ${fontSize?.vlm6}px; }

      .vlm7 {
        font-size: ${fontSize?.vlm7}px; }

      .vlm8 {
        font-size: ${fontSize?.vlm8}px; }

      .vlm9 {
        font-size: ${fontSize?.vlm9}px; }

      .vlm10 {
        font-size: ${fontSize?.vlm10}px; }
      `;
    document.head.appendChild(newFontStyle);
  }

  if (settings.useUserFonts) {
    applyFonts();
  }

  // ====================================================================================================================
  //   . . . ПОЛЬЗОВАТЕЛЬСКИЕ ТЕМЫ / ЦВЕТА . . .
  // ====================================================================================================================
  function applyTheme() {
    const newStyle = document.createElement("style");
    newStyle.innerHTML = // css
    `
      body {
        background: ${theme?.backgroundColor || ""};
      }

      #cages_overflow {
        background: black;
      } 

      #tr_actions > td, #tr_mouth > td, #location, .small {
        background-color: ${theme?.blocksColor || ""};
      }

      #history_block > div {
        background-color: unset !important;
      }

      #main_table, #tr_mouth, #tr_actions, #info_main {
        background-color: unset;
        background: none;
      }
    
      #tr_chat {
        background-color: ${theme?.chatColor || ""};
      }
    
      body, input, select, .ui-slider-handle {
        color: ${theme?.textColor || ""};
      }
    
      input, select, .ui-slider-horizontal {
        background-color: ${theme?.accentColor1 || ""};
        background: ${theme?.accentColor1 || ""};
        border: solid 1px ${theme?.accentColor2 || ""};
      }

      .ui-widget-content .ui-state-default {
        background: ${theme?.accentColor2 || ""};
        border: solid 1px ${theme?.accentColor2 || ""};
      } 

      hr {
        border: solid 1px ${theme?.accentColor2 || ""};
      }

      .myname {
        color: ${theme?.accentColor1 || ""};
        background: ${theme?.accentColor3 || ""};
      }

      span.cat_tooltip {
        background: ${theme?.catTooltipBackground || ""} !important;
        color: ${theme?.textColor || ""} !important;
        border: 2px solid ${theme?.accentColor2 || ""} !important;
      } 

      span.cat_tooltip > span.online {
        filter: brightness(2) contrast(150%);
      }
      
      .cat:hover .cat_tooltip a, .other_cats_list > a { 
        color: ${theme?.linkColor || ""}; 
      }

      .move_name {
        color: ${theme?.moveNameColor || ""};
        background-color: ${theme?.moveNameBackground || ""} !important;
      }
    
      a, a:hover {
        color: ${theme?.linkColor || ""};
      }

      #fightPanel {
        background-color: ${theme?.fightPanelBackground || ""};
      }

      .hotkey {
        background-color: ${theme?.accentColor1 || ""};
      }

      #newchat, #newls {
        color: ${theme?.accentColor3 || ""};
      }

      .cat-info {
      background-color: ${theme?.catTooltipBackground || ""} !important;
      color: ${theme?.textColor || ""} !important;
      }
      `;
    document.head.appendChild(newStyle);
  }

  if (settings.userTheme) {
    applyTheme();
  }
  // ====================================================================================================================
  //   . . . РЕДИЗАЙН ИГРОВОЙ . . .
  // ====================================================================================================================
  if (settings.customLayout) {
    // ==================================================================
    function prependOtherCatsListContent() {
      const otherCatsList = document.querySelector(".other_cats_list");
      const smallContainer = document.querySelector(".small");

      if (!otherCatsList || !smallContainer) return;

      const catsListContent = otherCatsList.innerHTML;

      switch (settings.showOtherCatsList) {
        case "1":
          break;
        case "2":
          const clickableBlockHTML =
            '<span style="display: inline; cursor: pointer;"><a href="#" style="display: inline; pointer-events: none;">Душевые коты</a></span>';
          smallContainer.insertAdjacentHTML(
            "afterbegin",
            clickableBlockHTML + " || "
          );

          const clickableBlock = smallContainer.firstChild;

          const catsListContainer = document.createElement("span");
          catsListContainer.id = "catsListContainer";
          catsListContainer.innerHTML = ": " + catsListContent;
          catsListContainer.style.display = "none";
          smallContainer.insertBefore(
            catsListContainer,
            smallContainer.firstChild.nextSibling
          );

          clickableBlock.addEventListener("click", (event) => {
            event.preventDefault();
            if (catsListContainer.style.display === "none") {
              catsListContainer.style.display = "inline";
            } else {
              catsListContainer.style.display = "none";
            }
          });
          break;
        case "3":
          smallContainer.insertAdjacentHTML(
            "afterbegin",
            catsListContent + " || "
          );
          break;
        default:
          break;
      }
    }

    setupSingleCallback(".other_cats_list", prependOtherCatsListContent);
    // ==================================================================

    function applyLayoutSettings() {
      const savedSettings = localStorage.getItem("uwu_layoutSettings");
      if (savedSettings) {
        const { leftBlocks, rightBlocks } = JSON.parse(savedSettings);

        const mainTable = document.getElementById("main_table");
        const tbody = mainTable.getElementsByTagName("tbody")[0];
        const blocks = Array.from(tbody.children);

        resetBlockStyles(tbody);

        const gridAreaTemplate = generateGridTemplate(leftBlocks, rightBlocks);

        // console.log(gridAreaTemplate);

        tbody.style.display = "grid";
        tbody.style.gridTemplateAreas = gridAreaTemplate;
        tbody.style.gridTemplateColumns = "1fr auto 1fr";
        tbody.style.gridTemplateRows = generateGridRowStyles(
          leftBlocks,
          rightBlocks
        );

        blocks.forEach((block) => {
          if (block.id) {
            block.style.gridArea = block.id;
          }
        });
      }
    }

    function generateGridRowStyles(leftBlocks, rightBlocks) {
      const numRows = Math.max(leftBlocks.length, rightBlocks.length);
      let rowStyles = [];

      for (let i = 0; i < numRows; i++) {
        let rowHeight = "auto";
        rowStyles.push(rowHeight);
      }

      const rowStylesString = rowStyles.join(" ");
      return rowStylesString;
    }

    function generateGridTemplate(leftBlocks, rightBlocks) {
      const numRows = Math.max(leftBlocks.length, rightBlocks.length);
      let template = "";
      let lastLeftBlockId = "";
      let lastRightBlockId = "";
      let isFirstRow = true;

      for (let i = 0; i < numRows; i++) {
        const leftBlockId = leftBlocks[i] || lastLeftBlockId;
        const rightBlockId = rightBlocks[i] || lastRightBlockId;

        if (isFirstRow) {
          template += `"${leftBlockId} tr_field ${rightBlockId}" `;
          isFirstRow = false;
        } else {
          template += `"${
            leftBlockId === lastLeftBlockId ? "." : leftBlockId
          } . ${rightBlockId === lastRightBlockId ? "." : rightBlockId}" `;
        }

        if (leftBlockId) {
          lastLeftBlockId = leftBlockId;
        }
        if (rightBlockId) {
          lastRightBlockId = rightBlockId;
        }
      }

      return template;
    }

    function resetBlockStyles(parent) {
      const blocks = parent.querySelectorAll("tr > *");
      blocks.forEach((block) => {
        block.style.gridArea = "";
      });
    }

    // Больше фикс стилей.
    const fixStyle = document.createElement("style");
    fixStyle.innerHTML = // css
    `
      #main_table {
        width: 100%;
        max-width: unset;
        height: 100%;

        background: none;
        border-spacing: 0px !important;
      }

      #main_table > tbody {
        margin-top: 10px;
      }

      #app {
        width: 100%;
        height: 100%;
      }
      
      #chat_msg, #cws_chat_msg {
        height: ${settings.chatHeight}px;
        width: auto;
      }

      #history_block > div { 
        visibility: hidden; 
      }

      #history_block {
        display: block;
        height: ${settings.historyHeight}px; 
        overflow-y: auto;
        resize: vertical;
      }

      #family { 
        display: block;
        overflow-y: auto;
        resize: vertical;
      }

      .infos {
        width: auto;
      }

      #cages_overflow {
        background: black;
      }

      .chat_text {
        width: auto !important;
        overflow-wrap: anywhere;
      }

      #chat_form {
        margin: unset;
        margin: 5px;
      }

      #volume {
        margin: 5px;
      }

      #app > p:last-of-type {
        position: fixed;
        bottom: 0px;
        margin: 8px;
      }

      h2 {
        margin-top: 5px;
        margin-bottom: 10px;
      }

      #itemList {
        overflow-y: auto;
        max-height: 180px;
        display: flex;
        flex-wrap: wrap;
      }

      #location {
        visibility: visible;
        position: fixed;
        right: 0px;
        top: 0px;
        font-size: 1.5rem;
        background-color: ${theme?.blocksColor};
        z-index: 1;
      }

      .small {
        position: fixed;
        left: 0px;
        top: 0px;
        font-size: ${fontSize?.fontSizeSmall || 16}px;
        z-index: 1;
      }

      body {
        overflow-y: scroll;
      }

      #tr_chat, #tr_actions > td, #tr_mouth > td, #location, .small, #info_main > tbody > tr > td {
        padding: 5px !important;
      }

      #tr_chat > td {
        display: contents;
      }

      #chat_msg, #cws_chat_msg {
        height: ${theme?.chatHeight}px;
        resize: vertical;
      }

      #tr_field, #tr_info {
        height: 10px;
      }

      #newchat, #newls {
        background-color: transparent;
      }

      .other_cats_list {
        display: none;
      }
    `;
    document.head.appendChild(fixStyle);
    applyLayoutSettings();

    const paragraph = document.querySelector("#app > p > b");
    paragraph.textContent = "ТБ:";

    function applyLayoutSettingsForInfoMain() {
      const infoMainTable = document.getElementById("info_main");
      const tableRow = infoMainTable.querySelector("tr");
      const tds = tableRow.getElementsByTagName("td");

      for (const td of tds) {
        td.style.gridArea = "";
      }

      tableRow.style.display = "grid";
      // хахахах поглядите на смешного строчного
      tableRow.style.gridTemplateAreas = `"parameter"
                                          "history"
                                          "family"`;

      tds[0].style.gridArea = "family";
      tds[1].style.gridArea = "history";
      tds[2].style.gridArea = "parameter";
    }
    applyLayoutSettingsForInfoMain();
  }

  // ====================================================================================================================
  //   . . . ПОДСКАЗЫВАТЬ ОСТАВШЕЕСЯ ВРЕМЯ ДО НЮХА . . .
  // ====================================================================================================================
  if (settings.showHintWhenToSniff) {
    let firstNote = "";
    let timerStartTime = null;
    let initialTimerValue = 0;
    
    const smellTimer = {
      0: 3600,
      1: 3600,
      2: 3600,
      3: 3600,
      4: 1800,
      5: 1200,
      6: 900,
      7: 720,
      8: 600,
      9: 0,
    };
    
    function formatTime(seconds) {
      const hours = Math.floor(seconds / 3600);
      const minutes = Math.floor((seconds % 3600) / 60);
      const remainingSeconds = seconds % 60;
      return `${hours ? `${hours} ч ` : ""}${
        minutes ? `${minutes} мин ` : ""
      }${remainingSeconds} с`;
    }
    
    function updateSmellTimer() {
      const timerElement = document.getElementById("uwu_sniff_timer");
      if (!timerElement) return;
    
      if (timerStartTime !== null) {
        const isActive = document.querySelector('#dein a[data-id="14"]') !== null;
        if (isActive) {
          timerStartTime = null;
          initialTimerValue = 0;
          timerElement.setAttribute("value", 0);
          timerElement.textContent = "";
          soundManager.playSound("notificationSound3", settings.notificationMyNameVolume);
          return;
        }
    
        const currentTime = Date.now();
        const elapsedTime = Math.floor((currentTime - timerStartTime) / 1000);
        let remainingTime = initialTimerValue - elapsedTime;
    
        if (remainingTime <= 0) {
          remainingTime = 0;
          timerStartTime = null;
          initialTimerValue = 0;
          soundManager.playSound("notificationSound3", settings.notificationMyNameVolume);
        }
    
        timerElement.setAttribute("value", remainingTime);
        timerElement.textContent = remainingTime > 0 ? ` | Нюх через: ${formatTime(remainingTime)}` : "";
      }
    }
    
    setInterval(updateSmellTimer, 1000);
    
    function smellIconClick() {
      firstNote = document.getElementById("error").innerHTML;
      document.getElementById("smell_icon").click();
    }
    
    function errorObserver() {
      const errorElement = document.getElementById("error");
      const html = errorElement.innerHTML;
      if (html && html.includes("Следующее обнюхивание")) {
        const text = html.replace(
          "Следующее обнюхивание будет доступно через ",
          ""
        );
        const smellMin =
          (text.match(/(\d+) мин/g) || [])
            .map((num) => parseInt(num.replace(/\D/g, ""), 10))
            .shift() || 0;
        const smellSec = parseInt(
          (text.match(/(\d+) с/g) || [])
            .map((num) => num.replace(/\D/g, ""))
            .shift(),
          10
        );
        const totalSec = smellMin * 60 + smellSec;
        const timerElement = document.getElementById("uwu_sniff_timer");
        timerElement.setAttribute("value", totalSec);
        timerElement.textContent = ` | Нюх через: ${smellMin} мин ${smellSec} с`;
        timerStartTime = Date.now();
        initialTimerValue = totalSec;
        if (firstNote !== "") {
          errorElement.innerHTML = firstNote;
          firstNote = "";
        }
      } else if (html.includes("Час уже прошёл") && firstNote !== "") {
        errorElement.innerHTML = firstNote;
        firstNote = "";
      }
    }
    
    function messObserver() {
      const blockMessElement = document.getElementById("block_mess");
      if (!blockMessElement) return;
    
      const isActive = document.querySelector('#dein a[data-id="14"]') !== null;
      if (!isActive && blockMessElement.children.length === 0 && timerStartTime === null) {
        const smellLevel = document.querySelector("#smell b").textContent;
        const smellTime = smellTimer[smellLevel];
        const timerElement = document.getElementById("uwu_sniff_timer");
        timerElement.setAttribute("value", smellTime);
        timerElement.textContent = ` | Нюх через: ${formatTime(smellTime)}`;
        timerStartTime = Date.now();
        initialTimerValue = smellTime;
      }
    }
    
    function timerElement() {
      const smallElement = document.querySelector(".small");
      if (smallElement) {
        smallElement.insertAdjacentHTML(
          "beforeend",
          '<span id="uwu_sniff_timer" value="0"></span>'
        );
      }
    }
    
    window.addEventListener("load", function () {
      setupSingleCallback(".small", timerElement);
      setupSingleCallback("#smell_icon", smellIconClick);
      setupMutationObserver("#error", errorObserver, {
        childList: true,
        subtree: true,
      });
      setupMutationObserver("#block_mess", messObserver, {
        childList: true,
        subtree: true,
      }, 8, 500, 20);
    });
  }
  // ====================================================================================================================
  //   . . . ДУБЛИРОВАНИЕ ДЕЙСТВИЙ НА ВКЛАДКУ БРАУЗЕРА . . .
  // ====================================================================================================================
  if (settings.duplicateTimeInBrowserTab) {
    const blockMess = document.getElementById("block_mess");
    const titleElement = document.querySelector("title");
    let previousTime = null;
    let previousMessage = null;
  
    function updateTitle() {
      const timeElement = blockMess.querySelector("#sek");
      const messageText = blockMess.textContent.trim();
  
      if (messageText === previousMessage) return;
  
      const catNameMatch = messageText.match(/^(.+?)\s+держит/);
      const catName = catNameMatch ? catNameMatch[1] : "";
  
      if (catName) {
        titleElement.textContent = `Поднят. Во рту | ${catName}`;
      } else if (timeElement) {
        const currentTime = timeElement.textContent.trim();
        if (currentTime !== previousTime) {
          const actionText = messageText
            .replace(currentTime, "")
            .replace(/\s*\.\s*Отменить$/, "")
            .trim();
          titleElement.textContent = `${currentTime} | ${actionText}`;
          previousTime = currentTime;
        }
      } else {
        titleElement.textContent = "Игровая / CatWar";
        previousTime = null;
      }
  
      previousMessage = messageText;
    }
  
    setupMutationObserver("#block_mess", updateTitle, { childList: true, subtree: true });
  }
  // ====================================================================================================================
  //   . . . ЗВУКОВЫЕ УВЕДОМЛЕНИЯ . . .
  // ====================================================================================================================
  // мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу
  // ====================================================================================================================
  //   . . . ЛИЧНЫЕ СООБЩЕНИЯ . . .
  // ====================================================================================================================
  let previousCount = 0;

  if (settings.notificationPM) {
    const newlsElement = document.getElementById("newls");
    if (newlsElement) {
      const observer = new MutationObserver(handleNewlsChange);
      observer.observe(newlsElement, {
        characterData: true,
        subtree: true,
      });
    }

    function handleNewlsChange(mutations) {
      if (mutations.length > 0) {
        const currentText = newlsElement.textContent;
        const currentCount = parseInt(
          currentText.match(/\(\d+\)/)?.[0].slice(1, -1) || 0,
          10
        );

        if (!isNaN(currentCount) && currentCount > previousCount) {
          soundManager.playSound(
            "notificationSound1",
            settings.notificationMyNameVolume
          );
          previousCount = currentCount;
        } else if (!isNaN(currentCount)) {
          previousCount = currentCount;
        }
      }
    }
  }
  // ====================================================================================================================
  //   . . . ОКОНЧАНИЕ ДЕЙСТВИЯ . . .
  // ====================================================================================================================
  if (settings.notificationActionEnd) {
    const blockMess = document.getElementById("block_mess");
    let wasBlockMessEmpty = blockMess.innerHTML.trim() === "";
    let actionStartTime = null;

    const observer = new MutationObserver(() => {
      const isBlockMessEmptyNow = blockMess.innerHTML.trim() === "";

      if (!isBlockMessEmptyNow && !actionStartTime) {
        actionStartTime = Date.now();
      } else if (isBlockMessEmptyNow && actionStartTime) {
        const actionEndTime = Date.now();
        const actionDuration = actionEndTime - actionStartTime;

        if (actionDuration >= 6000) {
          soundManager.playSound(
            "notificationSound3",
            settings.notificationMyNameVolume
          );
        }
        actionStartTime = null;
      }

      wasBlockMessEmpty = isBlockMessEmptyNow;
    });

    observer.observe(blockMess, { childList: true, subtree: true });
  }
  // ====================================================================================================================
  //   . . . ПОДНЯЛИ В РОТ . . .
  // ====================================================================================================================
  if (settings.notificationInMouth) {
    const blockMess = document.getElementById("block_mess");

    const observer = new MutationObserver(() => {
      if (blockMess.innerHTML.includes("во рту. Вы не сможете выбраться")) {
        soundManager.playSound(
          "notificationSound1",
          settings.notificationMyNameVolume
        );
      }
    });

    observer.observe(blockMess, { childList: true, subtree: true });
  }
  // ====================================================================================================================
  //   . . . ВВЕЛИ В БОЕВУЮ СТОЙКУ . . .
  // ====================================================================================================================
  if (settings.notificationInFightMode) {
    const attackRegex = /в боевую стойку, поскольку на меня напал/;
    let previousHistory = "";

    const updateHistory = () => {
      const istElement = document.getElementById("ist");
      const currentHistory = istElement.innerHTML;

      if (currentHistory !== previousHistory) {
        previousHistory = currentHistory;

        const entries = currentHistory.split(".");
        const lastEntry = entries[entries.length - 2];

        if (lastEntry !== undefined && attackRegex.test(lastEntry)) {
          soundManager.playSound(
            "notificationSound1",
            settings.notificationMyNameVolume
          );
        }
      }
    };

    const historyBlock = document.getElementById("history_block");
    const observer = new MutationObserver(() => {
      updateHistory();
    });

    const config = {
      childList: true,
      subtree: true,
      characterData: true,
    };
    observer.observe(historyBlock, config);
  }
  // ====================================================================================================================
  // мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу мяу
  // ====================================================================================================================
  //   . . . СОВРЕМЕННЫЙ (НОВЫЙ) ЧАТ . . .
  // ====================================================================================================================
  // я на этом инвалиде потерял все нервы кетвар желаю тебе счастья удачи и всего хорошего 😌😌😌😌😌😌😌😌😌😌
  // И ДО СИХ ПОР ТЕРЯЮ ААААА
  // TODO - как-то пределать шоле
  if (settings.newChat) {
    const newChatContainer = document.createElement("div");
    newChatContainer.id = "uwu_chat_msg";
    const chatForm = document.getElementById("chat_form");
    chatForm.parentNode.insertBefore(newChatContainer, chatForm.nextSibling);

    newChatContainer.addEventListener("click", function (event) {
      const target = event.target;

      const nickElement = target.closest(".nick");
      if (nickElement) {
        const textArea = document.getElementById("text");
        textArea.value += nickElement.textContent;
        textArea.focus();
        return;
      }

      const reportButton = target.closest(".msg_report");
      if (reportButton) {
        const dataId = reportButton.getAttribute("data-id");
        const originalReportLink = document.querySelector(
          `#chat_msg .msg_report[data-id="${dataId}"]`
        );
        if (originalReportLink) {
          originalReportLink.click();
        }
        return;
      }
    });

    const chatElement = document.getElementById("chat_msg");
    if (chatElement) {
      const observer = new MutationObserver(handleNewChatMessage);
      observer.observe(chatElement, { childList: true, subtree: true });
    }

    let addedSpanCount = 0;

    function handleNewChatMessage(mutations) {
      const addedNodes = Array.from(mutations)
        .flatMap((mutation) => Array.from(mutation.addedNodes))
        .filter(
          (node) =>
            node.nodeName === "SPAN" && node.querySelector("td > .chat_text")
        );

      addedSpanCount += addedNodes.length;
      processChatMessages(addedSpanCount);
      addedSpanCount = 0;
    }

    function processChatMessages(messageCount) {
      const chatMessages = document.querySelectorAll("#chat_msg > span");
      const messagesArray = Array.from(chatMessages);
      const messagesToProcess = messagesArray.slice(0, messageCount);
      messagesToProcess.reverse();

      messagesToProcess.forEach((message) => {
        copyMessageToNewChat(message);
      });
    }

    function copyMessageToNewChat(chatMessage) {
      const chatTextSpan = chatMessage.querySelector("td > .chat_text");
      const messageSpan = chatTextSpan.querySelector("span");
      const messageText = messageSpan ? messageSpan.innerHTML : "";
      const nickElement = chatTextSpan.querySelector(".nick");
      const nickName = nickElement ? nickElement.textContent.trim() : "";
      const chatTextClasses = chatTextSpan.className;
      const nickStyle = nickElement ? nickElement.getAttribute("style") : "";
      let nameFound = false;

      let processedText = messageText;

      if (settings.namesForNotification) {
        const names = settings.namesForNotification
          .trim()
          .split(/\s*,\s*/)
          .filter((name) => name);

        names.forEach((name) => {
          const regex = new RegExp(
            `(^|\\s|[.,!?])(${name})(?=$|\\s|[.,!?])`,
            "gi"
          );
          processedText = processedText.replace(regex, (match, p1, p2) => {
            nameFound = true;
            return `${p1}<span class="myname">${p2}</span>`;
          });
        });
      }

      if (!nameFound && messageSpan && messageSpan.querySelector(".myname")) {
        nameFound = true;
      }

      if (nameFound) {
        soundManager.playSound(
          settings.myNameNotificationSound,
          settings.notificationMyNameVolume
        );
      }

      const profileLink = chatMessage.querySelector('a[href^="/cat"]').href;
      const catIdMatch = profileLink.match(/\/cat(\d+)/);
      const catId = catIdMatch ? catIdMatch[1] : ". . .";

      const reportLink = chatMessage.querySelector(".msg_report");
      const dataId = reportLink ? reportLink.getAttribute("data-id") : "";

      const newChatMessageHTML = // html
      `
        <hr>
        <div id="msg">
          <div class="${chatTextClasses}">${processedText} - <b class="nick" style="${nickStyle}">${nickName}</b> <i>[${catId}]</i></div>
          <div style="display: flex; width: 42px; justify-content: flex-end; margin-right: 2px;">
            <a href="${profileLink}" title="Перейти в профиль" target="_blank" rel="noopener noreferrer">➝</a>&nbsp;|&nbsp;
            <a href="#" title="Пожаловаться на нарушение ОПИ" class="msg_report" data-id="${dataId}">X</a>
          </div>
        </div>
      `;
      newChatContainer.insertAdjacentHTML("afterbegin", newChatMessageHTML);
    }

    const uwuChatMsg = document.createElement("style");
    uwuChatMsg.innerHTML = `
        #uwu_chat_msg {
          height: ${settings.chatHeight}px;
          resize: vertical;
          overflow-y: auto;
          display: flex;
          flex-direction: ${settings.reverseChat ? "column-reverse" : "column"};
        }
  
        #chat_msg {
          display: none;
        }
  
        #msg {
          display: flex;
          justify-content: space-between;
        }

        #uwu_chat_msg > hr {
          width: -webkit-fill-available;
        }
     `;
    document.head.appendChild(uwuChatMsg);
  }
  // ====================================================================================================================
  //   . . . НОВЫЙ ВВОД ЧАТА . . .
  // ====================================================================================================================
  const chatForm = document.getElementById("chat_form");
  const trChatTd = document.querySelector("#tr_chat > td");

  function updateChatFormPosition() {
    if (settings.reverseChat) {
      trChatTd.appendChild(chatForm);
    } else {
      trChatTd.prepend(chatForm);
    }
  }
  updateChatFormPosition();

  if (settings.newChatInput) {
    const txtSpan = document.getElementById("txt");
    const selectField = txtSpan.querySelector("select#text");

    let textarea;

    function initTextarea(id, value) {
      const textarea = document.createElement("textarea");
      textarea.id = id;
      textarea.maxLength = 255;
      textarea.style.height = "auto";
      textarea.style.width = "100%";
      textarea.style.resize = "vertical";
      textarea.value = value || "";
      return textarea;
    }

    if (selectField) {
      textarea =
        document.getElementById("text-hide") || initTextarea("text-hide");
      textarea.style.display = "none";
    } else {
      const inputField = txtSpan.querySelector("input#text");

      textarea = initTextarea("text", inputField ? inputField.value : "");
      txtSpan.insertBefore(textarea, inputField);
    }

    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === "childList") {
          const selectField = txtSpan.querySelector("select#text");
          if (selectField) {
            textarea.style.display = "none";
            textarea.id = "text-hide";
          } else {
            textarea.style.display = "";
            textarea.id = "text";
          }
        }
      });
    });

    observer.observe(txtSpan, { childList: true });

    // Make Enter great again!
    textarea.addEventListener("keydown", function (event) {
      if (event.key === "Enter") {
        if (event.shiftKey) {
          event.preventDefault();
          textarea.value += "\n";
        } else {
          event.preventDefault();
          const sendButton = document.getElementById("msg_send");
          sendButton.click();
        }
      }
    });

    const NewChatDesign = document.createElement("style");
    NewChatDesign.innerHTML = `
  input#text {
    display: none;
  }

  #text, #text-hide {
    color: ${theme?.textColor};
    background: ${theme?.accentColor1};
    border: solid 1px ${theme?.accentColor2};
    font-family: Verdana;
  }
`;
    document.head.appendChild(NewChatDesign);
  }
  // ====================================================================================================================
  //   . . . РЕДИЗАЙНЫ + + ЗАКРУГЛЕНИЕ БЛОКОВ . . .
  // ====================================================================================================================
  const sliceInfoStyle = document.createElement("style");

  if (settings.sliceInfoBlock) {
    sliceInfoStyle.innerHTML = `
      #info_main > tbody > tr > td {
        background-color: ${theme?.blocksColor || ""};
        margin-bottom: 5px;
      }
    `;
    document.head.appendChild(sliceInfoStyle);
  } else {
    sliceInfoStyle.innerHTML = `
      #tr_info > td {
        background-color: ${theme?.blocksColor || ""};
      }
    `;
    document.head.appendChild(sliceInfoStyle);
  }

  const edgeTrimBlocksStyle = document.createElement("style");
  if (settings.edgeTrimBlocks) {
    edgeTrimBlocksStyle.innerHTML = // css
    `
    #info_main > tbody > tr > td {
      width: fit-content;
      border-radius: 10px;
      margin-bottom: 10px;
    }
    
    #info_main,
    #tos,
    #cages_overflow,
    #cages_div {
      border-radius: 10px;
    }
    
    #main_table > tbody > #tr_actions,
    #main_table > tbody > #tr_mouth,
    #main_table > tbody > #tr_chat,
    #main_table > tbody > #tr_tos,
    #main_table > tbody > #tr_info {
      margin: 0px 10px 10px 10px;
    }
    
    #tr_chat,
    #tr_actions > td,
    #tr_mouth > td,
    #location,
    .small,
    #tr_info > td {
      border-radius: 10px;
    }
    `;
    document.head.appendChild(edgeTrimBlocksStyle);
  }
  // ====================================================================================================================
  //  . . . КОМАНДЫ В БОЕВОМ РЕЖИМЕ . . .
  // ====================================================================================================================
  if (settings.fightTeams) {
    const colors = settings.fightTeamsColors;
  
    const fightPanel = document.getElementById("fightPanel");
    const buttonHTML =
      '<button id="updateTableButton" style="width: 100%;">Обновить команды</button>';
    fightPanel.insertAdjacentHTML("beforeend", buttonHTML);
  
    document.getElementById("updateTableButton").onclick = () => {
      if (!document.getElementById("uwu-team-settings")) {
        createTeamTable();
      }
      updateTeamTable();
    };
  
    function createTeamTable() {
      const tableHTML = // html
      `
        <div id="uwu-team-settings" style="height: ${
          settings.fightTeamsPanelHight || "auto"
        }px; overflow-y: scroll; resize: vertical;">
          <table id="uwu-team-settings-table" style="width: 100%; border-collapse: collapse;">
            <thead>
              <tr>
                <th style="border: 1px solid #000; padding: 5px;">Имя</th>
                <th style="border: 1px solid #000; padding: 5px;">Команда</th>
              </tr>
            </thead>
            <tbody id="teamTableBody"></tbody>
          </table>
        </div>
      `;
      const updateButton = document.getElementById("updateTableButton");
      updateButton.insertAdjacentHTML("beforebegin", tableHTML);
    }
  
    function updateTeamTable() {
      const tbody = document.getElementById("teamTableBody");
      tbody.innerHTML = "";
      const cages = document.querySelectorAll("#cages .cage");
  
      cages.forEach((cage) => {
        const catName = cage.querySelector(".cat_tooltip a")?.textContent;
        const arrow = cage.querySelector(".arrow.arrow-paws");
  
        if (catName && arrow) {
          const arrowId = arrow.id;
          const buttonsHTML = Object.keys(colors)
            .map((team) => {
              return `
                <button 
                  class="team-color-button"
                  data-arrow-id="${arrowId}"
                  data-team="${team}"
                  style="background-color: ${colors[team][0]}; width: 21%; height: 16px;"
                ></button>
              `;
            })
            .join("");
  
          const rowHTML = `
            <tr>
              <td style="border: 1px solid #000; padding: 5px;">${catName}</td>
              <td style="border: 1px solid #000; padding: 5px;">${buttonsHTML}</td>
            </tr>
          `;
          tbody.insertAdjacentHTML("beforeend", rowHTML);
        }
      });
  
      const teamColorButtons = document.querySelectorAll('.team-color-button');
      teamColorButtons.forEach(button => {
        button.addEventListener('click', () => {
          const arrowId = button.getAttribute('data-arrow-id');
          const team = button.getAttribute('data-team');
          applyTeamColors(arrowId, team);
        });
      });
    }
  
    function applyTeamColors(arrowId, team) {
      const styleElement = document.createElement('style');
      styleElement.type = 'text/css';
      const cssRule = `
        #${arrowId} .arrow_green { background-color: ${colors[team][0]} !important; }
        #${arrowId} .arrow_red { background-color: ${colors[team][1]} !important; }
      `;
      styleElement.appendChild(document.createTextNode(cssRule));
      document.head.appendChild(styleElement);
    }
  }
  // ====================================================================================================================
  //   . . . ПЕРЕТАСКИВАНИЕ ПАНЕЛИ БОЕВОГО РЕЖИМА . . .
  // ====================================================================================================================
  if (settings.draggingFightPanel) {
    const dragDiv = document.createElement("div");
    dragDiv.style.cursor = "move";
    dragDiv.style.display = "inline-block";

    const dragImage = document.createElement("img");
    dragImage.src =
      "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/drag-move.png";
    dragImage.style.width = "24px";
    dragImage.style.height = "24px";
    dragImage.style.pointerEvents = "none";
    dragDiv.appendChild(dragImage);

    const fightPanel = document.getElementById("fightPanel");
    const firstImage = fightPanel.querySelector("img");
    fightPanel.insertBefore(dragDiv, firstImage);

    let mouseX = 0;
    let mouseY = 0;
    let panelX = 0;
    let panelY = 0;
    let isDragging = false;

    function saveFightPanelPosition(x, y) {
      localStorage.setItem("uwu_fightPanelPosition", JSON.stringify({ x, y }));
    }

    function loadFightPanelPosition() {
      const savedPosition = localStorage.getItem("uwu_fightPanelPosition");
      if (savedPosition) {
        const position = JSON.parse(savedPosition);
        panelX = position.x;
        panelY = position.y;
      }
    }

    function setFightPanelPosition(x, y) {
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;
      const panelWidth = fightPanel.offsetWidth;
      const panelHeight = fightPanel.offsetHeight;

      const maxX = windowWidth - panelWidth;
      x = Math.max(0, Math.min(x, maxX));

      const maxY = windowHeight - panelHeight;
      y = Math.max(0, Math.min(y, maxY));

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

      saveFightPanelPosition(x, y);
    }

    dragDiv.addEventListener("mousedown", (e) => {
      e.preventDefault();
      isDragging = true;
      mouseX = e.clientX;
      mouseY = e.clientY;

      loadFightPanelPosition();

      document.body.style.userSelect = "none";
    });

    document.addEventListener("mousemove", (e) => {
      if (isDragging) {
        e.preventDefault();

        const dx = e.clientX - mouseX;
        const dy = e.clientY - mouseY;

        setFightPanelPosition(panelX + dx, panelY + dy);
      }
    });

    document.addEventListener("mouseup", () => {
      isDragging = false;

      document.body.style.userSelect = "auto";
    });

    loadFightPanelPosition();
    setFightPanelPosition(panelX, panelY);
  }
  // ====================================================================================================================
  //   . . . СОКРАЩЕНИЕ ЛОГА БОЕВОГО РЕЖИМА . . .
  // ====================================================================================================================
  // емааааа ужасное решение
  // TODO - исправить переделать уничтожить пересобрать заамогусить чё за фигню я сделал
  if (settings.compactFightLog) {
    function compactFightLog() {
      const fightLog = document.getElementById("fightLog");
      fightLog.style.display = "none";

      let compactedFightLog = document.getElementById(
        "uwu-Compacted-Fight-Log"
      );
      if (!compactedFightLog) {
        compactedFightLog = document.createElement("div");
        compactedFightLog.id = "uwu-Compacted-Fight-Log";
        compactedFightLog.style.height = settings.fightPanelHeight + "px";
        fightLog.parentNode.insertBefore(compactedFightLog, fightLog);
      }

      const logEntries = Array.from(fightLog.childNodes).filter(
        (entry) => entry.tagName === "SPAN"
      );

      if (logEntries.length > 0) {
        const firstEntry = logEntries[0];
        const text = firstEntry.textContent.trim();
        const match = text.match(/^(.*) x(\d+)$/);
        const originalText = match ? match[1] : text;
        const count = match ? parseInt(match[2], 10) : 1;

        const latestEntry = compactedFightLog.firstElementChild;

        if (latestEntry) {
          const latestTextSpan = latestEntry.querySelector(".text");

          if (
            latestTextSpan &&
            latestTextSpan.textContent.trim() === originalText
          ) {
            const countLabel = latestEntry.querySelector(".count");
            const existingCount = parseInt(
              countLabel.textContent.match(/x(\d+)$/)[1],
              10
            );
            countLabel.textContent = ` x${existingCount + count}`;
          } else {
            const newEntryHTML = createEntryHTML(
              firstEntry.className,
              originalText,
              count
            );
            compactedFightLog.insertAdjacentHTML("afterbegin", newEntryHTML);
          }
        } else {
          const newEntryHTML = createEntryHTML(
            firstEntry.className,
            originalText,
            count
          );
          compactedFightLog.insertAdjacentHTML("afterbegin", newEntryHTML);
        }

        fightLog.removeChild(firstEntry);
      }
    }

    function createEntryHTML(className, originalText, count) {
      return `
        <div class="${className}">
          <span class="text">${originalText}</span>
          <label class="count"> x${count}</label>
        </div>
      `;
    }

    setupMutationObserver(
      "#fightLog",
      compactFightLog,
      {
        attributes: true,
        childList: true,
      },
      8,
      500,
      10
    );
  }
  // ====================================================================================================================
  //   . . . ИЗМЕНЯЕМАЯ ВЫСОТА ПАНЕЛИ БОЕВОГО РЕЖИМА . . .
  // ====================================================================================================================
  if (settings.FightPanelAdjustableHeight) {
    const uwuFightLog = document.createElement("style");
    uwuFightLog.innerHTML = `
      #fightPanel {
        height: auto;
      }

      #fightLog {
        resize: vertical;
        overflow-y: scroll;
      }
      
      #uwu-Compacted-Fight-Log {
        resize: vertical;
        overflow-y: scroll;
      } 
      `;
    document.head.appendChild(uwuFightLog);

    const fightLogElement = document.getElementById("fightLog");
    if (fightLogElement) {
        fightLogElement.style.height = `${settings.fightPanelHeight || 70}px`;
    }
}
  // ====================================================================================================================
  //   . . . ВСЕГДА ДЕНЬ В ИГРОВОЙ . . .
  // ====================================================================================================================
  // Вот бы всё писалось так кратко и легко...........
  function updateAlwaysDayStyle(checked) {
    const alwaysDayStyle = `
      #cages_div {
        opacity: 1 !important;
      }   
    `;

    const styles = document.head.querySelectorAll("style");
    let styleFound = false;

    styles.forEach((style) => {
      if (style.innerHTML === alwaysDayStyle) {
        if (!checked) {
          document.head.removeChild(style);
        }
        styleFound = true;
      }
    });

    if (checked && !styleFound) {
      const alwaysDay = document.createElement("style");
      alwaysDay.innerHTML = alwaysDayStyle;
      document.head.appendChild(alwaysDay);
    }
  }
  // ====================================================================================================================
  //   . . . НЕБО - ШАПКА . . .
  // ====================================================================================================================
  if (settings.skyInHeader) {
    function getSkyUrl() {
      const skyElement = document.querySelector("#sky");
      if (skyElement) {
        const skyStyle = skyElement.getAttribute("style");
        const match = skyStyle.match(/url\((.*?)\)/);
        if (match) {
          return match[1].trim();
        } else {
          console.log("Не удалось найти URL изображения неба");
        }
      }
      return "";
    }

    const skyDiv = document.createElement("div");
    skyDiv.id = "skyDuplicate";

    const globalContainerElement = document.getElementById(
      "uwu-global-container"
    );
    globalContainerElement.appendChild(skyDiv);

    const skyStyle = document.createElement("style");
    skyStyle.innerHTML = `
      #skyDuplicate {
        height: 15%;
        width: 100%;
        mask-image: linear-gradient(to bottom, 
          rgba(0, 0, 0, 1), 
          rgba(0, 0, 0, 0.40) 50%,
          rgba(0, 0, 0, 0)
        );
        top: 0;
        left: 0;
        z-index: -1;
        position: absolute;
        background-size: cover;
      }
    `;
    document.head.appendChild(skyStyle);

    const originalSkyStyle = document.createElement("style");
    originalSkyStyle.innerHTML = `
      #tr_sky {
        display: none;
      }
    `;
    document.head.appendChild(originalSkyStyle);

    function updateSkyImage() {
      const skyUrl = getSkyUrl();
      if (skyUrl) {
        skyDiv.style.backgroundImage = `url(${skyUrl})`;
      }
    }

    updateSkyImage();

    setupMutationObserver(
      "#sky",
      updateSkyImage,
      { attributes: true, attributeFilter: ["style"] },
      8,
      500,
      10
    );
  }
  // ====================================================================================================================
  //   . . . ОПРЕДЕЛЕНИЕ ПОГОДЫ В ИГРОВОЙ . . . 🛠️
  // ====================================================================================================================
  let currentWeather = "null";
  let currentHour = "null";
  let currentSeason = "null";
  let currentTemperature = "null";
  let temperatureDescription = "null";
  // ахахаха глянье на этих незнающих
  let weatherModifier = 1;

  if (settings.manualWeatherPanel) {
    const manualWeatherSlider = document.getElementById("manualWeather");

    manualWeatherSlider.addEventListener("change", () => {
      const selectedWeather = manualWeatherSlider.value;

      if (selectedWeather === "1") {
        currentWeather = "clear";
      } else if (selectedWeather === "2") {
        if (settings.minecraftStyle) {
          currentWeather = "pixelRain";
        } else {
          currentWeather = "rain";
        }
      } else if (selectedWeather === "3") {
        if (settings.minecraftStyle) {
          currentWeather = "pixelSnow";
        } else {
          currentWeather = "snow";
        }
      }
    });
  }

  function getSkyType() {
    const skyElement = document.querySelector("#sky");
    const skyStyle = skyElement.getAttribute("style");

    if (settings.weatherEnabled) {
      const match = skyStyle.match(/\/(\d+)\.png/);
      if (match) {
        const skyNumber = parseInt(match[1]);

        switch (skyNumber) {
          case 2:
          case 4:
            if (settings.minecraftStyle) {
              currentWeather = "pixelRain";
            } else {
              currentWeather = "rain";
            }
            break;
          case 7:
          case 8:
            if (settings.minecraftStyle) {
              currentWeather = "pixelSnow";
            } else {
              currentWeather = "snow";
            }
            break;
          case 22:
            currentWeather = "northernLights";
            break;
          default:
            currentWeather = "clear";
        }
      } else {
        console.log("Потерял небо, небо найдись пж...");
        currentWeather = "unknown";
      }
    }
  }

  function getTime() {
    const timeElement = document.querySelector("#hour");
    const hourTime = timeElement.querySelector("img").getAttribute("src");

    if (settings.weatherEnabled) {
      const hourNumber = parseInt(hourTime.match(/(\d+)\.png$/)[1]);

      if (hourNumber >= 6 && hourNumber <= 12) {
        currentHour = "morning";
      } else if (hourNumber >= 13 && hourNumber <= 18) {
        currentHour = "day";
      } else if (hourNumber >= 19 && hourNumber <= 21) {
        currentHour = "evening";
      } else {
        currentHour = "night";
      }
      // console.log("Текущий час:", hourNumber);
    }
  }

  function getSeason() {
    const seasonElement = document.querySelector("img[src*='symbole/season']");
    const seasonSrc = seasonElement.getAttribute("src");
    const match = seasonSrc.match(/season(\d+)\.png/);

    if (match) {
      const seasonNumber = parseInt(match[1]);
      switch (seasonNumber) {
        case 0:
          currentSeason = "winter";
          break;
        case 1:
          currentSeason = "spring";
          break;
        case 2:
          currentSeason = "summer";
          break;
        case 3:
          currentSeason = "autumn";
          break;
      }
      // console.log("Текущий сезон:", currentSeason);
    }
  }

  function getTemperature() {
    const temperatureElement = document.querySelector("#tos");
    const temperatureElementHTML = temperatureElement.outerHTML;
    const backgroundValue = /background:\s*([a-zA-Z0-9#()]+);/.exec(
      temperatureElementHTML
    );

    if (backgroundValue && backgroundValue.length > 1) {
      const foundBackground = backgroundValue[1];

      const temperatureRanges = [
        {
          description: "Очень холодно",
          temperature: -3,
          colors: [
            "#94BDD2",
            "#9DC5D8",
            "#B2D8E5",
            "#C3E8EF",
            "#AED4E2",
            "#AAD1E0",
            "#A5CDDD",
          ],
        },
        {
          description: "Холодно",
          temperature: -2,
          colors: [
            "#7FAAC5",
            "#76A2C0",
            "#6A96B8",
            "#6593B6",
            "#618FB3",
            "#7BA6C3",
          ],
        },
        {
          description: "Прохладно",
          temperature: -1,
          colors: [
            "#3B6C9B",
            "#4C7BA6",
            "#5887AE",
            "#5D8BB0",
            "#4777A3",
            "#366899",
            "#3F709E",
            "#4374A1",
            "#5483AB",
          ],
        },
        {
          description: "Тепло",
          temperature: 1,
          colors: ["#FCBD8E", "#F8A37A", "#F79E77", "#FDC291", "#FCB88A"],
        },
        {
          description: "Жарковато",
          temperature: 2,
          colors: [
            "#F79973",
            "#F6946F",
            "#F58F6B",
            "#F28060",
            "#F38563",
            "#F17A5C",
            "#EF6B50",
            "#F07054",
          ],
        },
        {
          description: "Жарко",
          temperature: 3,
          colors: [
            "#EE664D",
            "#ED6149",
            "#EB5741",
            "#EB523D",
            "#E73D2E",
            "#E6382A",
          ],
        },
        {
          description: "Засуха",
          temperature: 4,
          colors: ["#DF0A08", "#E3241B", "#E4291F", "#E52E22", "#E63326"],
        },
      ];

      let foundTemperature = null;

      for (const range of temperatureRanges) {
        if (range.colors.includes(foundBackground)) {
          foundTemperature = range;
          break;
        }
      }

      if (foundTemperature) {
        currentTemperature = foundTemperature.temperature;
        temperatureDescription = foundTemperature.description;
      } else {
        currentTemperature = 1;
        temperatureDescription =
          "Неизвестная температура. Разработчик скорее всего уже в курсе и в скором времени выпустит правку.";
        console.warn("Неизвестная температура:", foundBackground);
      }

      switch (currentTemperature) {
        case 1:
        case -1:
          weatherModifier = 2;
          break;
        case 2:
        case -2:
          weatherModifier = 1.5;
          break;
        case 3:
        case -3:
          weatherModifier = 1;
          break;
        default:
          weatherModifier = 1;
      }

      // console.log("Температура:", currentTemperature);

      const temperatureDisplayElement = document.getElementById("temperature");
      if (temperatureDisplayElement) {
        temperatureDisplayElement.innerHTML = `[?] Текущий модификатор: ${weatherModifier} (${temperatureDescription})`;
      }
    } else {
      console.log("...я временно потерял бекграунд температуры🌡️...");
    }
  }
  // ====================================================================================================================
  if (!settings.manualWeatherPanel) {
    setupMutationObserver("#sky", getSkyType);

    setupMutationObserver("#hour", getTime, {
      attributes: true,
      attributeFilter: ["src"],
      subtree: true,
    });

    setupMutationObserver("img[src*='symbole/season']", getSeason, {
      attributes: true,
      attributeFilter: ["src"],
    });
  }

  setupMutationObserver("#tos", getTemperature, {
    attributes: true,
    subtree: true,
  });
  // ====================================================================================================================
  //   . . . ПОДГОТОВКА КОНТЕЙНЕРОВ / ИЗОБРАЖЕНИЙ . . . 🖼️
  // ====================================================================================================================
  const weatherContainer = document.getElementById("uwu-main-container");
  const weatherCanvas = document.createElement("canvas");
  weatherCanvas.classList.add("weatherCanvas");
  weatherContainer.appendChild(weatherCanvas);
  const weatherCtx = weatherCanvas.getContext("2d");

  function resizeCanvasElement() {
    weatherCanvas.width = weatherCanvas.parentNode.offsetWidth;
    weatherCanvas.height = weatherCanvas.parentNode.offsetHeight;
  }

  window.addEventListener("resize", resizeCanvasElement);
  resizeCanvasElement();

  const images = {
    pixelSnow: [
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/snowflake1.png",
      },
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/snowflake2.png",
      },
    ],
    pixelRain: [
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/rain1.png",
      },
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/rain2.png",
      },
    ],
    pixelSplash: [
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/splash_0.png",
      },
      {
        url: "https://raw.githubusercontent.com/Ibirtem/CatWar/main/images/splash_1.png",
      },
    ],
    sus: [
      {
        url: "https://firebasestorage.googleapis.com/v0/b/xwx-823ac.appspot.com/o/images%2Ftiny-red-among-us.png?alt=media&token=354b34c6-6297-4a4d-8a73-f36a903170c0",
      },
    ],
  };

  async function loadImages(type) {
    const imagesForType = images[type];
    if (!imagesForType) {
      console.error(`Чё ета...?: ${type}`);
      return;
    }

    const promises = [];

    for (const image of imagesForType) {
      promises.push(
        new Promise((resolve, reject) => {
          const img = new Image();
          img.src = image.url;
          img.onload = function () {
            image.image = this;
            resolve();
          };
          img.onerror = function () {
            console.error(`Чёта не скачалось: ${image.url}`);
            reject();
          };
        })
      );
    }

    await Promise.all(promises);
  }
  loadImages("pixelSnow");
  loadImages("pixelRain");
  loadImages("pixelSplash");
  loadImages("sus");

  const { raindrops } = generateRain();
  const { snowflakes } = generateSnowflakes();
  const { pixelRaindrops } = generatePixelRain();
  const { pixelSnowflakes } = generatePixelSnow();

  // ====================================================================================================================
  //   . . . РЕЖИМ НИЗКОЙ ПРОИЗВОДИТЕЛЬНОСТИ . . .
  // ====================================================================================================================
  // Может быть уже даже готовка к динамичному количеству частиц.
  var rainNumParticles = 10;
  var snowTimerValue = 120;
  var desiredNumberOfFireflies = 10;

  function setWeatherPerformanceMode() {
    rainNumParticles = settings.lowPerformanceMode ? 4 : 10;
    snowTimerValue = settings.lowPerformanceMode ? 240 : 120;
    desiredNumberOfFireflies = settings.lowPerformanceMode ? 6 : 10;

    return { rainNumParticles, snowTimerValue, desiredNumberOfFireflies };
  }

  setWeatherPerformanceMode();
  // ====================================================================================================================
  //   . . . ДОЖДЬ . . . 🌧️
  // ====================================================================================================================
  function generateRain() {
    const raindrops = [];

    setInterval(() => {
      if (currentWeather === "rain") {
        for (let i = 0; i < rainNumParticles; i++) {
          const raindrop = generateRaindrop();
          if (raindrop) {
            raindrops.push(raindrop);
          }
        }
      }
    }, 80);

    function generateRaindrop() {
      if (document.hidden) {
        return;
      }
      const x = Math.random() * weatherCanvas.width;
      const y = Math.random() * -100;
      const length = (Math.random() * 20 + 40) / weatherModifier;
      const width = (Math.random() * 1 + 1) / weatherModifier;
      const ySpeed = length * 0.2 * weatherModifier;
      const xSpeed = Math.random() * 1;

      return { x, y, length, width, ySpeed, xSpeed };
    }

    return { raindrops };
  }

  function drawRaindrop(raindrop) {
    weatherCtx.beginPath();
    weatherCtx.ellipse(
      raindrop.x,
      raindrop.y,
      raindrop.width,
      raindrop.length,
      0,
      Math.PI,
      2 * Math.PI
    );
    weatherCtx.fillStyle = "rgba(150, 150, 150, 0.4)";
    weatherCtx.fill();
  }
  // ====================================================================================================================
  //   . . . СНЕГ . . . 🌨️
  // ====================================================================================================================
  function generateSnowflakes() {
    const snowflakes = [];
    const snowTimerValue = setWeatherPerformanceMode().snowTimerValue;

    setInterval(() => {
      if (currentWeather === "snow") {
        for (let i = 0; i < 1; i++) {
          const snowflake = generateSnowflake();
          if (snowflake) {
            snowflakes.push(snowflake);
          }
        }
      }
    }, snowTimerValue);

    function generateSnowflake() {
      if (document.hidden) {
        return;
      }
      const y = Math.random() * -100;
      const x = Math.random() * weatherCanvas.width;
      const size = (Math.random() * 5 + 2) / weatherModifier;
      const ySpeed = size * 0.1 * weatherModifier;
      const xSpeed = (Math.random() - Math.random()) * 0.2;
      const opacity = 1;

      return { x, y, size, ySpeed, xSpeed, opacity };
    }

    return { snowflakes };
  }

  function drawSnowflake(x, y, size) {
    weatherCtx.beginPath();
    weatherCtx.ellipse(x, y, size, size, 0, 0, 2 * Math.PI);
    weatherCtx.fillStyle = "white";
    weatherCtx.fill();
  }
  // ====================================================================================================================
  //   . . . ПИКСЕЛЬНЫЙ ДОЖДЬ . . . 🌧️
  // ====================================================================================================================
  function generatePixelRain() {
    const pixelRaindrops = [];

    setInterval(() => {
      if (currentWeather === "pixelRain") {
        for (let i = 0; i < rainNumParticles; i++) {
          const pixelRaindrop = generatePixelRaindrop();
          if (pixelRaindrop) {
            pixelRaindrops.push(pixelRaindrop);
          }
        }
      }
    }, 80);

    function generatePixelRaindrop() {
      if (document.hidden) {
        return;
      }
      const x = Math.random() * weatherCanvas.width;
      const y = Math.random() * -100;
      const size = (Math.random() * 26 + 26) / Math.pow(weatherModifier, 0.5);
      const ySpeed = size * 0.2 * Math.pow(weatherModifier, 0.5);
      const xSpeed = Math.random() * 0.2 - 0.1;
      const imageData =
        images.pixelRain[Math.floor(Math.random() * images.pixelRain.length)];
      const image = imageData.image;

      return { x, y, size, ySpeed, xSpeed, image };
    }

    return { pixelRaindrops };
  }

  function drawPixelRaindrop(pixelRaindrop) {
    const imageWidth = pixelRaindrop.image.width;
    const imageHeight = pixelRaindrop.image.height;
    const scaleFactor = pixelRaindrop.size / Math.max(imageWidth, imageHeight);

    weatherCtx.drawImage(
      pixelRaindrop.image,
      pixelRaindrop.x,
      pixelRaindrop.y,
      imageWidth * scaleFactor,
      imageHeight * scaleFactor
    );
  }
  // ====================================================================================================================
  //   . . . ПИКСЕЛЬНЫЙ СНЕГ . . . 🌨️
  // ====================================================================================================================
  function generatePixelSnow() {
    const pixelSnowflakes = [];
    const snowTimerValue = setWeatherPerformanceMode().snowTimerValue;

    setInterval(() => {
      if (currentWeather === "pixelSnow") {
        for (let i = 0; i < 1; i++) {
          const pixelSnowflake = generatePixelSnowflake();
          if (pixelSnowflake) {
            pixelSnowflakes.push(pixelSnowflake);
          }
        }
      }
    }, snowTimerValue);

    function generatePixelSnowflake() {
      if (document.hidden) {
        return;
      }
      const y = Math.random() * -100;
      const x = Math.random() * weatherCanvas.width;
      const size = (Math.random() * 8 + 8) / Math.pow(weatherModifier, 0.8); // TODO - Протестить, сильно ли влияет Math.pow на производительность или нет
      const ySpeed = size * 0.1 * Math.pow(weatherModifier, 0.8) - 0.6;
      const xSpeed = (Math.random() - Math.random()) * 0.2;
      const imageData =
        images.pixelSnow[Math.floor(Math.random() * images.pixelSnow.length)];
      const image = imageData.image;
      const opacity = 1;

      return { x, y, size, ySpeed, xSpeed, image, opacity };
    }

    return { pixelSnowflakes };
  }

  function drawPixelSnowflake(x, y, size, image) {
    weatherCtx.drawImage(image, x - size / 2, y - size / 2, size, size);
  }
  // ====================================================================================================================
  //   . . . АНИМАЦИЯ ПОГОДЫ / ЧАСТИЦ . . .
  // ====================================================================================================================
  function animateWeather() {
    weatherCtx.clearRect(0, 0, weatherCanvas.width, weatherCanvas.height);

    if (raindrops.length > 0) {
      for (const raindrop of raindrops) {
        raindrop.y += raindrop.ySpeed;
        raindrop.x += raindrop.xSpeed;
        drawRaindrop(raindrop);
      }
    }

    if (snowflakes.length > 0) {
      for (const snowflake of snowflakes) {
        snowflake.y += snowflake.ySpeed;
        snowflake.x += snowflake.xSpeed;
        drawSnowflake(snowflake.x, snowflake.y, snowflake.size);
      }
    }

    if (pixelSnowflakes.length > 0) {
      for (const pixelSnowflake of pixelSnowflakes) {
        pixelSnowflake.y += pixelSnowflake.ySpeed;
        pixelSnowflake.x += pixelSnowflake.xSpeed;
        drawPixelSnowflake(
          pixelSnowflake.x,
          pixelSnowflake.y,
          pixelSnowflake.size,
          pixelSnowflake.image
        );
      }
    }

    if (pixelRaindrops.length > 0) {
      for (const pixelRaindrop of pixelRaindrops) {
        pixelRaindrop.y += pixelRaindrop.ySpeed;
        pixelRaindrop.x += pixelRaindrop.xSpeed;
        drawPixelRaindrop(pixelRaindrop);
      }
    }

    requestAnimationFrame(animateWeather);
  }
  if (settings.weatherEnabled || settings.manualWeatherPanel) {
    animateWeather();
  }
  // ====================================================================================================================
  //   . . . СЕВЕРНОЕ СИЯНИЕ . . . 🌟
  // ====================================================================================================================
  const auroraColors = {
    green: {
      1: "#aaff9d",
      2: "#00faa0",
      3: "#00ff62",
    },
    blue: {
      1: "#9DF5ED",
      2: "#82BBF5",
      3: "#725DFA",
    },
  };
  const auroras = [];

  function removeAurora(auroraElement) {
    auroraElement.style.animation = "auroraFadeOut 6s ease-in-out";

    setTimeout(() => {
      weatherContainer.removeChild(auroraElement);
      const index = auroras.indexOf(auroraElement);
      if (index > -1) {
        auroras.splice(index, 1);
      }
    }, 6000);
  }

  function createAurora(color) {
    for (const auroraElement of auroras) {
      removeAurora(auroraElement);
    }

    const newAurora = document.createElement("div");

    newAurora.style.cssText = `
    transform: translate(0, 60%);
    z-index: -1;
    position: fixed;
    left: 0;
    width: 100%;
    height: 30%;
    filter: blur(4rem);
    animation: aurora-spin 15s linear infinite, auroraFadeIn 6s ease-in-out;
    background: conic-gradient(from var(--gradient-angle),
    ${auroraColors[color][1]},
    ${auroraColors[color][2]},
    ${auroraColors[color][3]},
    ${auroraColors[color][2]},
    ${auroraColors[color][1]});
    `;

    if (settings.auroraPos === "1") {
      newAurora.style.top = "-30%";
    } else if (settings.auroraPos === "2") {
      newAurora.style.bottom = "0";
    }

    weatherContainer.appendChild(newAurora);
    auroras.push(newAurora);
  }

  function toggleAurora() {
      if (settings.manualWeatherPanel) return;

      const isAuroraConditionMet = 
          currentWeather === "northernLights" || 
          (currentWeather === "clear" && 
          currentHour === "night" && 
          (currentSeason === "autumn" || currentSeason === "winter"));

      if (isAuroraConditionMet) {
          if (auroras.length === 0) {
              const auroraColor = Math.random() > 0.5 ? "green" : "blue";
              createAurora(auroraColor);
          }
      } else {
          auroras.forEach(removeAurora);
      }
  }

  setInterval(() => {
    toggleAurora();
    if (!settings.manualWeatherPanel) {
      generateFirefliesNaturally();
    }
  }, 2000);
  // ====================================================================================================================
  //   . . . СВЕТЛЯЧКИ . . . 🪲
  // ====================================================================================================================
  const fireflies = [];
  const glowSizeMultiplier = 12;

  function generateFirefly() {
    const x = Math.random() * weatherCanvas.width;
    const y = Math.random() * weatherCanvas.height;
    const size = Math.random() * 5 + 10;
    const xSpeed = (Math.random() - 0.5) * 0.5;
    const ySpeed = (Math.random() - 0.5) * 0.5;

    const firefly = document.createElement("div");
    firefly.className = "firefly";
    firefly.style.left = x + "px";
    firefly.style.top = y + "px";
    firefly.style.width = size + "px";
    firefly.style.height = size + "px";

    const glow = document.createElement("div");
    glow.className = "firefly-glow";
    glow.style.left = x + "px";
    glow.style.top = y + "px";
    glow.style.width = size * glowSizeMultiplier + "px";
    glow.style.height = size * glowSizeMultiplier + "px";

    return { element: firefly, glowElement: glow, x, y, size, xSpeed, ySpeed };
  }

  function createNewFirefliesIfNeeded() {
    const missingFireflies = desiredNumberOfFireflies - fireflies.length;

    for (let i = 0; i < missingFireflies; i++) {
      const newFirefly = generateFirefly();
      fireflies.push(newFirefly);
      weatherContainer.appendChild(newFirefly.element);
      weatherContainer.appendChild(newFirefly.glowElement);
    }
  }

  function removeFireflies() {
    for (const firefly of fireflies) {
      weatherContainer.removeChild(firefly.element);
      weatherContainer.removeChild(firefly.glowElement);
    }
    fireflies.length = 0;
  }

  function toggleFireflies() {
    if (settings.manualWeatherPanel) {
      if (fireflies.length === 0) {
        for (let i = 0; i < desiredNumberOfFireflies; i++) {
          fireflies.push(generateFirefly());
          weatherContainer.appendChild(fireflies[i].element);
          weatherContainer.appendChild(fireflies[i].glowElement);
        }
      } else {
        for (const firefly of fireflies) {
          firefly.element.classList.add("firefly-disappearing");
          firefly.glowElement.classList.add("firefly-disappearing");
        }
        setTimeout(() => {
          removeFireflies();
        }, 6000);
      }
    }
  }

  function generateFirefliesNaturally() {
    if (
      currentWeather === "clear" &&
      currentHour === "night" &&
      currentSeason === "summer"
    ) {
      if (fireflies.length === 0) {
        for (let i = 0; i < desiredNumberOfFireflies; i++) {
          fireflies.push(generateFirefly());
          weatherContainer.appendChild(fireflies[i].element);
          weatherContainer.appendChild(fireflies[i].glowElement);
        }
      }
    } else {
      for (const firefly of fireflies) {
        firefly.element.classList.add("firefly-disappearing");
        firefly.glowElement.classList.add("firefly-disappearing");
      }
      setTimeout(() => {
        removeFireflies();
      }, 6000);
    }
  }

  function animateFireflies() {
    for (let i = fireflies.length - 1; i >= 0; i--) {
      const firefly = fireflies[i];
      firefly.x += firefly.xSpeed;
      firefly.y += firefly.ySpeed;

      if (firefly.x < 0 || firefly.x + firefly.size > weatherCanvas.width) {
        firefly.xSpeed *= -1;
      }
      if (firefly.y < 0 || firefly.y + firefly.size > weatherCanvas.height) {
        firefly.ySpeed *= -1;
      }

      firefly.element.style.left = firefly.x + "px";
      firefly.element.style.top = firefly.y + "px";

      firefly.glowElement.style.left =
        firefly.x - (firefly.size * glowSizeMultiplier) / 2 + "px";
      firefly.glowElement.style.top =
        firefly.y - (firefly.size * glowSizeMultiplier) / 2 + "px";

      createNewFirefliesIfNeeded();
    }

    requestAnimationFrame(animateFireflies);
  }

  if (settings.weatherEnabled || settings.manualWeatherPanel) {
    animateFireflies();
  }
  // ====================================================================================================================
  //   . . . ПРИЗЕМЛЕНИЕ ЧАСТИЦ . . . ☔
  // ====================================================================================================================
  const landedSnowflakes = [];
  const landedPixelSnowflakes = [];
  const splashes = [];
  const pixelSplashes = [];

  switch (true) {
    case settings.manualWeatherPanel && !settings.weatherDrops:
    case settings.weatherEnabled && !settings.weatherDrops:
      setInterval(() => {
        checkElements(raindrops, weatherContainer);
        checkElements(snowflakes, weatherContainer);
        checkElements(pixelSnowflakes, weatherContainer);
        checkElements(pixelRaindrops, weatherContainer);
      }, 120);
      break;

    case settings.manualWeatherPanel && settings.weatherDrops:
    case settings.weatherEnabled && settings.weatherDrops:
      animateLanding();
      break;

    default:
      break;
  }

  function checkElements(elements, container) {
    for (let i = elements.length - 1; i >= 0; i--) {
      const element = elements[i];

      if (
        element &&
        (element.y >= container.offsetHeight ||
          element.x >= container.offsetWidth ||
          element.x <= 0)
      ) {
        elements.splice(i, 1);
      }
    }
    // console.log(`Количество элементов: ${elements.length}`)
  }

  function animateLanding() {
    for (let i = snowflakes.length - 1; i >= 0; i--) {
      const snowflake = snowflakes[i];
      if (snowflake.y >= weatherCanvas.height - snowflake.size) {
        snowflakes.splice(i, 1);
        landedSnowflakes.push(snowflake);
      }
    }
    for (let i = pixelSnowflakes.length - 1; i >= 0; i--) {
      const pixelSnowflake = pixelSnowflakes[i];
      if (pixelSnowflake.y >= weatherCanvas.height - pixelSnowflake.size) {
        pixelSnowflakes.splice(i, 1);
        landedPixelSnowflakes.push(pixelSnowflake);
      }
    }
    for (let i = landedSnowflakes.length - 1; i >= 0; i--) {
      const snowflake = landedSnowflakes[i];
      snowflake.opacity -= 0.001;
      if (snowflake.opacity <= 0) {
        landedSnowflakes.splice(i, 1);
      }
    }
    for (const snowflake of landedSnowflakes) {
      weatherCtx.globalAlpha = snowflake.opacity;
      drawSnowflake(snowflake.x, snowflake.y, snowflake.size);
    }

    for (let i = landedPixelSnowflakes.length - 1; i >= 0; i--) {
      const pixelSnowflake = landedPixelSnowflakes[i];
      pixelSnowflake.opacity -= 0.001;

      if (pixelSnowflake.opacity <= 0) {
        landedPixelSnowflakes.splice(i, 1);
      }
    }
    for (const pixelSnowflake of landedPixelSnowflakes) {
      weatherCtx.globalAlpha = pixelSnowflake.opacity;
      drawPixelSnowflake(
        pixelSnowflake.x,
        pixelSnowflake.y,
        pixelSnowflake.size,
        pixelSnowflake.image
      );
    }

    for (let i = raindrops.length - 1; i >= 0; i--) {
      const raindrop = raindrops[i];
      if (raindrop.y >= weatherCanvas.height - raindrop.length) {
        raindrops.splice(i, 1);
        splashes.push(generateSplash(raindrop.x, weatherCanvas.height));
      }
    }

    for (let i = pixelRaindrops.length - 1; i >= 0; i--) {
      const pixelRaindrop = pixelRaindrops[i];
      if (pixelRaindrop.y >= weatherCanvas.height - pixelRaindrop.size) {
        pixelRaindrops.splice(i, 1);
        pixelSplashes.push(
          generateSplash(pixelRaindrop.x, weatherCanvas.height - 24)
        );
      }
    }

    for (const splash of splashes) {
      splash.x += splash.xSpeed;
      splash.y += splash.ySpeed;
      splash.ySpeed += 0.1;

      weatherCtx.beginPath();
      weatherCtx.arc(
        splash.x,
        splash.y,
        splash.size / 1.2 / weatherModifier,
        0,
        Math.PI * 2
      );
      weatherCtx.fillStyle = "rgba(150, 150, 150, 0.4)";
      weatherCtx.fill();
    }

    for (const pixelSplash of pixelSplashes) {
      pixelSplash.x += pixelSplash.xSpeed;
      pixelSplash.y += pixelSplash.ySpeed;
      pixelSplash.ySpeed += 0.1;
      weatherCtx.drawImage(
        pixelSplash.image,
        pixelSplash.x,
        pixelSplash.y,
        pixelSplash.size * weatherModifier * 2,
        pixelSplash.size * weatherModifier * 2
      );
    }

    checkSplashes();
    checkPixelSplashes();
    weatherCtx.globalAlpha = 1;
    requestAnimationFrame(animateLanding);
  }

  function generateSplash(x, y) {
    const size = Math.random() * 5 + 2;
    const xSpeed = (Math.random() - 0.5) * 2;
    const ySpeed = -Math.random() * 2 - 1;
    const imageData =
      images.pixelSplash[Math.floor(Math.random() * images.pixelSplash.length)];
    const image = imageData.image;

    return { x, y, size, xSpeed, ySpeed, image };
  }

  function checkSplashes() {
    for (let i = splashes.length - 1; i >= 0; i--) {
      const splash = splashes[i];
      if (
        splash.y >= weatherCanvas.height ||
        splash.x >= weatherCanvas.width ||
        splash.x <= 0
      ) {
        splashes.splice(i, 1);
      }
    }
    // console.log(`Количество сплешев: ${splashes.length}`)
  }
  function checkPixelSplashes() {
    for (let i = pixelSplashes.length - 1; i >= 0; i--) {
      const pixelSplash = pixelSplashes[i];
      if (
        pixelSplash.y >= weatherCanvas.height ||
        pixelSplash.x >= weatherCanvas.width ||
        pixelSplash.x <= 0
      ) {
        pixelSplashes.splice(i, 1);
      }
    }
  }
// ====================================================================================================================
} // Конец грандиозного, но и начало чево то нового... Зогдачно......
// ====================================================================================================================
// 🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨🦐✨
// ====================================================================================================================
//   . . . ТАРГЕТИНГ ОКНА ОХОТЫ И ПОДГОТОВКА КОНТЕЙНЕРОВ . . .
// ====================================================================================================================
if (window.location.href === targetCW3Hunt) {
  amogusSus();
  const containerElement = document.querySelector("body");
  const globalContainerElement = document.createElement("div");
  globalContainerElement.id = "uwu-main-container";
  containerElement.appendChild(globalContainerElement);
  // ====================================================================================================================
  //   . . . ПОДПИСЫВАТЬ ЗАПАХ . . .
  // ====================================================================================================================
  if (settings.describeHuntingSmell) {
    const smellElement = document.getElementById("smell");
    let smellText = null;
    let smellTimer = null;
    let previousRed = null;
    let seconds = 0;

    function updateHintText(currentRed) {
      if (currentRed === 0) {
        smellText.textContent = "Потерян";
      } else if (previousRed !== null) {
        if (currentRed > previousRed) {
          smellText.textContent = "Ближе";
        } else if (currentRed < previousRed) {
          smellText.textContent = "Дальше";
        }
      } else {
        smellText.textContent = " ";
      }
      previousRed = currentRed;
    }

    function updateTimer() {
      const minutes = Math.floor(seconds / 60);
      const remainingSeconds = seconds % 60;
      smellTimer.textContent = `${String(minutes).padStart(2, "0")}:${String(
        remainingSeconds
      ).padStart(2, "0")}`;
      seconds++;
    }

    function handleSmellChange() {
      const style = window.getComputedStyle(smellElement);
      const currentColor = style.backgroundColor;

      if (
        currentColor !== "rgba(0, 0, 0, 0)" &&
        currentColor !== "transparent"
      ) {
        if (!smellText) {
          smellText = document.createElement("div");
          smellText.id = "smellText";
          smellTimer = document.createElement("div");
          smellTimer.id = "smellTimer";
          document.body.appendChild(smellText);
          document.body.appendChild(smellTimer);

          intervalId = setInterval(updateTimer, 1000);
        }

        const currentRed = parseInt(
          currentColor.slice(
            currentColor.indexOf("(") + 1,
            currentColor.indexOf(",")
          )
        );
        updateHintText(currentRed);
      }
    }

    new MutationObserver(handleSmellChange).observe(smellElement, {
      attributes: true,
      attributeFilter: ["style"],
    });

    const describeHuntingSmell = document.createElement("style");
    describeHuntingSmell.innerHTML = `
  #smellText {
    font-size: 20px;
    background: white;
    color: black;
    text-align: center;
    width: 100px;
    position: absolute;
    z-index: 3;
    bottom: 60px;
  }
  
  #smellTimer {
    font-size: 18px;
    background: white;
    color: black;
    text-align: center;
    width: 100px;
    position: absolute;
    z-index: 3;
    bottom: 40px; 
  }
  `;
    document.head.appendChild(describeHuntingSmell);
  }
  // ====================================================================================================================
  //   . . . ВИРТУАЛЬНЫЙ ДЖОЙСТИК . . .
  // ====================================================================================================================
  // Работаем с сайтовым обработчиком нажатий: "//e.catwar.net/js/key.js?268881668"
  if (settings.huntingVirtualJoystick) {
    function createJoystick() {
      const joystickHTML = `
        <div id="joystick-container">
          <div id="joystick-base">
            <div id="joystick-head"></div>
          </div>
        </div>
      `;

      const uwuContainer = document.getElementById("uwu-main-container");
      uwuContainer.insertAdjacentHTML("beforeend", joystickHTML);

      const css = // css
      `
        #nav_buttons_wrapper {
          display: none;
        }
  
        #joystick-container {
          pointer-events: auto;
          position: fixed;
          bottom: 20px;
          right: 20px;
          width: ${settings.sizeHuntingVirtualJoystick}px; 
          height: ${settings.sizeHuntingVirtualJoystick}px;
          z-index: 10; 
        }
  
        #joystick-base {
          width: 100%;
          height: 100%;
          border-radius: 50%;
          background-color: rgba(128, 128, 128, 0.5);
          position: relative;
        }
  
        #joystick-head {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          width: ${settings.sizeHuntingVirtualJoystick / 2}px;
          height: ${settings.sizeHuntingVirtualJoystick / 2}px;
          border-radius: 50%;
          background-color: #808080;
          touch-action: none; 
        }
      `;
      const style = document.createElement("style");
      style.innerHTML = css;
      document.head.appendChild(style);

      const joystickContainer = document.getElementById("joystick-container");
      const joystickHead = document.getElementById("joystick-head");
      const baseRadius = joystickContainer.offsetWidth / 2;
      let activeTouchId = null;
      let keys = {};

      function handleTouchStart(event) {
        if (activeTouchId === null) {
          const touch = event.touches[0];
          activeTouchId = touch.identifier;
          updateJoystickPosition(touch.clientX, touch.clientY);
        }
      }

      function handleTouchMove(event) {
        event.preventDefault();
        for (let i = 0; i < event.touches.length; i++) {
          const touch = event.touches[i];
          if (touch.identifier === activeTouchId) {
            updateJoystickPosition(touch.clientX, touch.clientY);
            break;
          }
        }
      }

      function handleTouchEnd(event) {
        activeTouchId = null;
        resetJoystick();
        releaseAllKeys();
      }

      function updateJoystickPosition(x, y) {
        const containerRect = joystickContainer.getBoundingClientRect();
        const deltaX = x - (containerRect.left + baseRadius);
        const deltaY = y - (containerRect.top + baseRadius);
        const angle = Math.atan2(deltaY, deltaX);
        const distance = Math.min(Math.hypot(deltaX, deltaY), baseRadius * 0.8);

        joystickHead.style.left = `${
          baseRadius + distance * Math.cos(angle)
        }px`;
        joystickHead.style.top = `${baseRadius + distance * Math.sin(angle)}px`;

        const threshold = 0.3;
        const newDirections = {
          w: false,
          a: false,
          s: false,
          d: false,
          q: false,
          e: false,
          z: false,
          x: false,
        };

        simulateKeyRelease("w");
        simulateKeyRelease("a");
        simulateKeyRelease("s");
        simulateKeyRelease("d");
        simulateKeyRelease("q");
        simulateKeyRelease("e");
        simulateKeyRelease("z");
        simulateKeyRelease("x");

        if (distance > baseRadius * threshold) {
          if (angle >= -Math.PI * 0.125 && angle < Math.PI * 0.125) {
            newDirections.d = true;
          } else if (angle >= Math.PI * 0.125 && angle < Math.PI * 0.375) {
            newDirections.x = true;
          } else if (angle >= Math.PI * 0.375 && angle < Math.PI * 0.625) {
            newDirections.s = true;
          } else if (angle >= Math.PI * 0.625 && angle < Math.PI * 0.875) {
            newDirections.z = true;
          } else if (angle >= Math.PI * 0.875 || angle < -Math.PI * 0.875) {
            newDirections.a = true;
          } else if (angle >= -Math.PI * 0.875 && angle < -Math.PI * 0.625) {
            newDirections.q = true;
          } else if (angle >= -Math.PI * 0.625 && angle < -Math.PI * 0.375) {
            newDirections.w = true;
          } else if (angle >= -Math.PI * 0.375 && angle < -Math.PI * 0.125) {
            newDirections.e = true;
          }
        }

        for (const key in newDirections) {
          if (newDirections[key] !== keys[key]) {
            if (newDirections[key]) {
              simulateKeyPress(key);
            } else {
              simulateKeyRelease(key);
            }
            keys[key] = newDirections[key];
          }
        }
      }

      function resetJoystick() {
        joystickHead.style.left = "50%";
        joystickHead.style.top = "50%";
      }

      function releaseAllKeys() {
        for (const key in keys) {
          if (keys[key]) {
            simulateKeyRelease(key);
            keys[key] = false;
          }
        }
      }

      function simulateKeyPress(key) {
        const keyCode = Key.dict[key];
        if (keyCode && !Key.keys.includes(keyCode)) {
          Key.push(keyCode);
          const mockEvent = createMockEvent(keyCode);
          Key.keydown(mockEvent);
        }
      }

      function simulateKeyRelease(key) {
        const keyCode = Key.dict[key];
        if (keyCode) {
          const mockEvent = createMockEvent(keyCode);
          Key.keyup(mockEvent);
          const index = Key.keys.indexOf(keyCode);
          if (index > -1) {
            Key.keys.splice(index, 1);
          }
        }
      }

      function createMockEvent(keyCode) {
        return {
          keyCode: keyCode,
          ctrlKey: false,
          shiftKey: false,
          altKey: false,
          preventDefault: () => {},
          repeat: false,
        };
      }

      joystickContainer.addEventListener("touchstart", handleTouchStart);
      joystickContainer.addEventListener("touchmove", handleTouchMove);
      joystickContainer.addEventListener("touchend", handleTouchEnd);
      joystickContainer.addEventListener("touchcancel", handleTouchEnd);

      window.addEventListener("blur", function () {
        releaseAllKeys();
        resetJoystick();
      });
    }

    createJoystick();
  }
  // ====================================================================================================================
}
// ====================================================================================================================
function amogusSus() {
  console.log("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣤⣤⣤⣤⣤⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠛⠉⠙⠛⠛⠛⠛⠻⢿⣿⣷⣤⡀⠀⠀⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⠋⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⠈⢻⣿⣿⡄⠀⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⣸⣿⡏⠀⠀⠀⣠⣶⣾⣿⣿⣿⠿⠿⠿⢿⣿⣿⣿⣄⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⣿⣿⠁⠀⠀⢰⣿⣿⣯⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢿⣷⡄⠀ ");
  console.log("⠀⠀⣀⣤⣴⣶⣶⣿⡟⠀⠀⢸⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⠀ ");
  console.log("⠀⢰⣿⡟⠋⠉⣹⣿⡇⠀⠀⠘⣿⣿⣿⣿⣷⣦⣤⣤⣤⣶⣶⣶⣶⣿⣿⣿⠀ ");
  console.log("⠀⢸⣿⡇⠀⠀⣿⣿⡇⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀ ");
  console.log("⠀⣸⣿⡇⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠉⠻⠿⣿⣿⣿⣿⡿⠿⠿⠛⢻⣿⡇⠀⠀ ");
  console.log("⠀⣿⣿⠁⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣧⠀⠀ ");
  console.log("⠀⣿⣿⠀⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀ ");
  console.log("⠀⣿⣿⠀⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀ ");
  console.log("⠀⢿⣿⡆⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡇⠀⠀ ");
  console.log("⠀⠸⣿⣧⡀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠃⠀⠀ ");
  console.log("⠀⠀⠛⢿⣿⣿⣿⣿⣇⠀⠀⠀⠀⣰⣿⣿⣷⣶⣶⣶⣶⠶⠀⠀⢠⣿⣿⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⠀⠀⠀⣿⣿⡇⠀⣽⣿⡏⠁⠀⠀⠀⢸⣿⡇⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⠀⠀⠀⣿⣿⡇⠀⢹⣿⡆⠀⠀⠀⠀⣸⣿⠇⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⢿⣿⣦⣄⣀⣠⣴⣿⣿⠁⠀⠈⠻⣿⣿⣿⣿⡿⠏⠀⠀⠀⠀ ");
  console.log("⠀⠀⠀⠀⠀⠀⠀⠈⠛⠻⠿⠿⠿⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀");
}
// ====================================================================================================================
//   . . . ТАРГЕТИНГ БЛОГОВОЙ СТРАНИЦЫ . . .
// ====================================================================================================================
if (targetBlogsCreation.test(window.location.href)) {
  // ====================================================================================================================
  //   . . . ВОССТАНОВЛЕНИЕ БЛОГОВОГО ТЕКСТА . . .
  // ====================================================================================================================
  if (settings.restoreBlogCreation) {
    const textarea = document.getElementById("creation-text");

    function saveTextToStorage(text) {
      localStorage.setItem("uwu_blogCreation", text);
    }

    function restoreTextFromStorage() {
      const savedText = localStorage.getItem("uwu_blogCreation");
      if (savedText && !textarea.value) {
        textarea.value = savedText;
      }
    }

    textarea.addEventListener("input", () => {
      saveTextToStorage(textarea.value);
    });

    window.addEventListener("beforeunload", () => {
      saveTextToStorage(textarea.value);
    });

    restoreTextFromStorage();
  }
}

// ====================================================================================================================
//   . . . КНОПКИ BB-КОДОВ . . .
// ====================================================================================================================
if (settings.moreBBCodes) {
  function addBBCodeButtons() {
    const bbCodeContainers = document.querySelectorAll(".bbcode");

    const commonButtonsHTML = // html
    `
      <button class="bbcode" title="Абзац" data-code="p">p</button>
      <button class="bbcode" title="Перенос" data-code="br" data-parameter="0">br</button>
      <button class="bbcode" title="Таблица" data-code="table">table</button>
      <button class="bbcode" title="Строка таблицы" data-code="tr">tr</button>
      <button class="bbcode" title="Ячейка таблицы" data-code="td">td</button>
      <button class="bbcode" title="Нумерованный список" data-code="ol">ol</button>
      <button class="bbcode" title="Маркированный список" data-code="ul">ul</button>
      <button class="bbcode" title="Строка списка" data-code="li">li</button>
    `;

    const overblockButtonHTML = `
      <button class="bbcode" title="Раскрывающийся блок" data-code="overblock" data-parameter="1" data-text="Введите название раскрывающегося блока (то же, что и у заголовка, который раскрывает этот блок):">overblock</button>
    `;

    bbCodeContainers.forEach((bbCode) => {
      const container = bbCode.parentElement;
      if (!container) return;

      if (!container.querySelector('.bbcode[data-code="p"]')) {
        container.insertAdjacentHTML("beforeend", commonButtonsHTML);
      }

      const blockElement = container.querySelector('[data-code="block"]');
      if (
        blockElement &&
        !container.querySelector('.bbcode[data-code="overblock"]')
      ) {
        blockElement.insertAdjacentHTML("afterend", overblockButtonHTML);
      }
    });
  }

  setupSingleCallback(".bbcode", addBBCodeButtons);
}
// ====================================================================================================================
//   . . . ПРОФИЛЬ ИГРОКА . . .
// ====================================================================================================================
if (targetMainProfile.test(window.location.href)) {

  if (settings.calculators) {
    setupSingleCallback("#info", setupActivityCalc);
    setupSingleCallback("#info", moonCalculator);
  }

}
// ====================================================================================================================
//   . . . ПРОФИЛЯ ДРУГИХ ПОЛЬЗОВАТЕЛЕЙ . . .
// ====================================================================================================================
if (targetProfile.test(window.location.href)) {

  // ====================================================================================================================
  //   . . . БУ И ПРОЧЕЕ . . .
  // ====================================================================================================================
  if (settings.moreProfileInfo) {
    setupSingleCallback("tr:has(img[src='img/icon_kraft.png'])", addKraftLevel);
    
    function addKraftLevel() {
      const kraftLevels = {
        "блоха": 0,
        "котёночек": 1,
        "задира": 2,
        "гроза детской": 3,
        "страх барсуков": 4,
        "победитель псов": 5,
        "защитник племени": 6,
        "великий воин": 7,
        "достоин Львиного племени": 8,
        "идеальная": 9
      };
    
        const kraftRow = document.querySelector('tr:has(img[src="img/icon_kraft.png"])');
        const kraftTextElement = kraftRow.querySelector('b');
        const kraftText = kraftTextElement.textContent.trim();
        const kraftLevel = kraftLevels[kraftText];
        if (kraftLevel !== undefined) {
            kraftTextElement.textContent = `${kraftText} (${kraftLevel})`;
        }
    }
  }
  
  if (settings.calculators) {
    setupSingleCallback("#info", moonCalculator);
  }
}

// ===================================================================================================================
// Калькуляторы возраста/лун и активности частично под авторством "CatWar Mod (Варомод) от Хвойницы"
// ====================================================================================================================
//   . . . КАЛЬКУЛЯТОР ВОЗРАСТА / ЛУН . . .
// ====================================================================================================================
function moonCalculator() {
  const months = [
    "января", "февраля", "марта", "апреля", "мая", "июня",
    "июля", "августа", "сентября", "октября", "ноября", "декабря"
  ];

  const catTimeStart = 1200000000000;

  const infoElement = document.getElementById("info");
  if (!infoElement) return;

  const style = document.createElement("style");
  style.textContent = `
    .calculator-error { color: darkred; }
    .hidden { display: none; }
    .calculator-style { max-width: 400px; margin: 5px; padding: 5px; border-radius: 10px; background: #ffffff08; }
  `;
  document.head.appendChild(style);

  let calculatorAgeElement = document.getElementById("calculator-age");
  if (!calculatorAgeElement) {
    infoElement.insertAdjacentHTML('afterend', `<div id="calculator-age" class="calculator-style hidden"></div>`);
    calculatorAgeElement = document.getElementById("calculator-age");
  }

  const infoObserver = new MutationObserver((mutations) => {
    mutations.forEach(() => {
      if (!infoElement.textContent.match("Дата")) {
        calculatorAgeElement.classList.add("hidden");
        return;
      }

      calculatorAgeElement.classList.remove("hidden");

      const birthDateString = infoElement.textContent.match(/\d{4}-\d\d-\d\d \d\d:\d\d/)[0].replace(" ", "T");
      const nowDateString = formatDate(new Date());

      const ageMoons = getMoonsFromElement("age_icon");
      const age2Moons = getMoonsFromElement("age2_icon");

      const sex = document.querySelector('[src^="//e.catwar.net/avatar"]').style.borderColor;
      const isRegistrationDate = /регистрац/.test(infoElement.textContent);
      const moonsNow = age2Moons ? (isRegistrationDate ? ageMoons : age2Moons) : ageMoons;

      const bornWord = getBornWord(sex, isRegistrationDate);
      const catTimeString = formatCatTime(Date.parse(birthDateString), moonsNow);

      calculatorAgeElement.innerHTML = `
        <p><b>Калькулятор возраста</b></p>
        <label>Дата и время: <input type="datetime-local" id="calculator-date" min="${birthDateString}" value="${nowDateString}" max="9999-12-31T23:59"></label> <span id="calculator-error-date" class="calculator-error"></span>
        <br><label>Возраст: <input type="number" id="calculator-moons" min="0" step="0.1" value="${moonsNow}" style="width: 60px"></label> <span id="moon-word"></span> <span id="calculator-error-moons" class="calculator-error"></span>
        <br>${bornWord} ${catTimeString} по кошачьему времени.
        <br><br>
      `;

      updateMoonWord(moonsNow);

      const calculatorDateElement = document.getElementById("calculator-date");
      const calculatorMoonsElement = document.getElementById("calculator-moons");

      calculatorDateElement.addEventListener("input", function () {
        handleDateInput.call(this, birthDateString);
      });

      calculatorMoonsElement.addEventListener("input", function () {
        handleMoonsInput.call(this, birthDateString);
      });
    });
  });

  infoObserver.observe(infoElement, { childList: true });

  function getMoonsFromElement(iconId) {
    const iconElement = document.querySelector(`img[id="${iconId}"]`);
    if (!iconElement) return 0;
    const ageElement = iconElement.closest("tr").querySelector("td:nth-child(2) b");
    return parseFloat(ageElement.textContent);
  }

  function getBornWord(sex, isRegistrationDate) {
    const sexWords = {
      pink: ["Зарегистрировалась", "Родилась"],
      blue: ["Зарегистрировался", "Родился"],
      default: ["Зарегистрировалось", "Родилось"],
    };
    return isRegistrationDate ? (sexWords[sex] ? sexWords[sex][0] : sexWords.default[0]) : (sexWords[sex] ? sexWords[sex][1] : sexWords.default[1]);
  }

  function formatDate(date) {
    const pad = (num) => String(num).padStart(2, "0");
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
  }

  function formatCatTime(birthTimestamp, moons) {
    const daysToAdd = moons * 4;
    const targetDate = new Date(birthTimestamp + daysToAdd * 24 * 60 * 60 * 1000);
    const ms = birthTimestamp - catTimeStart;
    let time = Math.round(ms / 1000 * 7);
    const secInYear = 12 * 28 * 24 * 60 * 60;
    const secInMonth = 28 * 24 * 60 * 60;
    const year = Math.floor(time / secInYear);
    time -= year * secInYear;
    const month = Math.floor(time / secInMonth);
    time -= month * secInMonth;
    const day = Math.floor(time / (24 * 60 * 60)) + 1;
    time -= (day - 1) * 24 * 60 * 60;
    const hour = Math.floor(time / (60 * 60));
    time -= hour * 60 * 60;
    const minute = Math.floor(time / 60);
    const pad = (num) => String(num).padStart(2, "0");
    return `${day} ${months[month]} ${year} года в ${pad(hour)}:${pad(minute)}`;
  }

  function handleDateInput(birthDateString) {
    const dateString = this.value;
    const date = Date.parse(dateString);
    const errorDateElement = document.getElementById("calculator-error-date");
    errorDateElement.textContent = "";

    if (isNaN(date) || date < Date.parse(birthDateString)) {
      errorDateElement.textContent = "Ошибка!";
      return;
    }

    const moons = getMoonsFromDate(birthDateString, dateString);
    const calcMoonsElement = document.getElementById("calculator-moons");
    if (calcMoonsElement) {
      calcMoonsElement.value = moons;
      updateMoonWord(moons);
      const catTimeString = formatCatTime(Date.parse(birthDateString), moons);
      document.querySelector("br").nextSibling.textContent = `${catTimeString} по кошачьему времени.`;
    }
    updateMoonWord(moons);
  }

  function handleMoonsInput(birthDateString) {
    const moons = Number(this.value);
    const errorMoonsElement = document.getElementById("calculator-error-moons");
    errorMoonsElement.textContent = "";

    if (moons < 0 || isNaN(moons)) {
      errorMoonsElement.textContent = "Ошибка!";
      return;
    }

    const calcDateElement = document.getElementById("calculator-date");
    if (calcDateElement) {
      calcDateElement.value = getDateStringFromMoons(birthDateString, moons);
      updateMoonWord(moons);
      const catTimeString = formatCatTime(Date.parse(birthDateString), moons);
      document.querySelector("br").nextSibling.textContent = `${catTimeString} по кошачьему времени.`;
    }
    updateMoonWord(moons);
  }

  function getMoonsFromDate(birthDateString, dateString) {
    const birthday = Date.parse(birthDateString);
    const date = Date.parse(dateString);
    const moons = Math.floor((date - birthday) / (1000 * 60 * 60 * 24 * 4) * 10) / 10;
    return moons;
  }

  function getDateStringFromMoons(birthDateString, moons) {
    const birthday = Date.parse(birthDateString);
    const age = Math.round(moons * 4 * 24 * 60 * 60 * 1000);
    return formatDate(new Date(birthday + age));
  }

  function updateMoonWord(moons) {
    const integerMoons = Math.floor(moons);
    document.getElementById("moon-word").textContent = declOfNum(integerMoons, ['луна', 'луны', 'лун']);
  }

  function declOfNum(number, titles) {
    const cases = [2, 0, 1, 1, 1, 2];
    return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
  }
}
// ====================================================================================================================
//   . . . КАЛЬКУЛЯТОР АКТИВНОСТИ . . .
// ====================================================================================================================
// TODO - Переписать, сделать рефакторинг и как-то объединить и упростить код с калькулятором выше.
function setupActivityCalc() {
  const catId = document.getElementById("id_val").textContent;

  const activityStages = [
    { name: "пустое место", fromZero: -5000 },
    { name: "подлежащий удалению", fromZero: -5000 },
    { name: "покинувший игру", fromZero: -2000 },
    { name: "забывший про игру", fromZero: -1000 },
    { name: "забытый кот", fromZero: -750 },
    { name: "ужаснейшая", fromZero: -500 },
    { name: "ужасная", fromZero: -300 },
    { name: "ухудшающаяся", fromZero: -150 },
    { name: "отрицательная", fromZero: -50 },
    { name: "переходная", fromZero: -5 },
    { name: "положительная", fromZero: 5 },
    { name: "улучшающаяся", fromZero: 50 },
    { name: "замечательная", fromZero: 150 },
    { name: "переход 2 мин 15 с", fromZero: 225 },
    { name: "замечательнейшая", fromZero: 300 },
    { name: "переход 2 мин", fromZero: 450 },
    { name: "любимый кот", fromZero: 500 },
    { name: "переход 1 мин 45 с", fromZero: 675 },
    { name: "легенда сайта", fromZero: 750 },
    { name: "переход 1 мин 30 с", fromZero: 900 },
    { name: "ходячий миф", fromZero: 1000 },
    { name: "переход 1 мин 15 с", fromZero: 1125 },
    { name: "переход 1 мин", fromZero: 1350 },
    { name: "переход 45 c", fromZero: 1575 },
    { name: "император Игровой", fromZero: 2000 },
    { name: "частичка Игровой", fromZero: 5000 },
    { name: "хранитель Игровой", fromZero: 20000 },
    { name: "идеальная", fromZero: 75000 },
    { name: "сверхидеальная", fromZero: 150000 },
  ];

  const months = [
    "января", "февраля", "марта", "апреля", "мая", "июня",
    "июля", "августа", "сентября", "октября", "ноября", "декабря"
  ];

  const activitySettings = JSON.parse(
    window.localStorage.getItem("uwu_activity") || "{}"
  );

  if (!activitySettings[catId]) {
    activitySettings[catId] = { hours: 24, opened: false };
  }

  if (activitySettings[catId].actgoal) {
    activityStages.forEach(function (stage, index) {
      if (index && Number(activitySettings[catId].actgoal) === stage.fromZero) {
        activitySettings[catId].goal = index;
        delete activitySettings[catId].actgoal;
      }
    });
  }

  function calculateActivityLength(days) {
    const minus = activitySettings[catId].minus || 0;
    if (days <= 14) return 150 - minus;
    else if (days >= 1575) return 45 - minus;
    else return Math.ceil(150 - days / 15) - minus;
  }

  function calculateRemainingTime(currentActivity, goal, hoursPerDay) {
    const secondsPerDay = convertTime("h s", hoursPerDay);
    if (calculateActivityLength(currentActivity) * 4 + 1 > secondsPerDay) {
      return { actions: "∞", time: "∞", date: "никогда" };
    }

    const actionsWithoutDecrease = goal - currentActivity;
    let days = 0;
    let secondsToday;

    while (currentActivity < goal) {
      secondsToday = 0;
      while (secondsToday < secondsPerDay) {
        currentActivity++;
        secondsToday += calculateActivityLength(currentActivity);
        if (currentActivity >= goal) break;
      }
      if (currentActivity >= goal) break;
      days++;
      currentActivity -= 4.8;
    }

    const actionsDecrease = Math.floor(
      days * 4.8 + convertTime("s h", secondsToday) / 5
    );
    const totalTime = secondsPerDay * days + secondsToday;

    const now = new Date();
    const tomorrow = new Date(
      now.getFullYear(),
      now.getMonth(),
      now.getDate() + 1
    );
    const secondsToTomorrow = convertTime("ms s", tomorrow - now);
    if (days === 0 && secondsToday > secondsToTomorrow) days++;

    const targetDate = new Date(Date.now() + convertTime("d ms", days));

    return {
      actions: actionsWithoutDecrease + actionsDecrease,
      time: secondsToTime(totalTime),
      date:
        targetDate.getDate() +
        " " +
        months[targetDate.getMonth()] +
        " " +
        targetDate.getFullYear(),
    };
  }

  function updateGoalProgress() {
    if (progress.stage === activityStages.length - 1) {
      document.getElementById("goal-progress").style.display = "none";
      return;
    }
    const goalIndex = Number(document.getElementById("activity-list").value);
    const result = calculateRemainingTime(
      progress.doneFromZero,
      activityStages[goalIndex].fromZero,
      activitySettings[catId].hours
    );
    document.querySelector("#goal-progress > ul").innerHTML = `
      <li>${result.actions} ${declensionOfNumber(result.actions, [
      "переход",
      "перехода",
      "переходов",
    ])} (${result.time})</li>
      <li>будет достигнута ${result.date}</li>
    `;
  }

  const activity = document
    .querySelector("#act_name b")
    .textContent.split(" (");
  const progress = {};

  const currentStage = activityStages.find(stage => stage.name === activity[0]);

  if (currentStage) {
    progress.doneFromZero = currentStage.fromZero + Number(activity[1].split("/")[0]);
    progress.stage = activityStages.indexOf(currentStage); 
  }

  const activityInfoHTML = // html
    `
      <details id="calculator-activity" class="calculator-style">
        <summary id="open-calculator"><b>Калькулятор активности</b></summary>
        <div id="calculator-content" style="margin-top: 10px;">
          <p id="congratulations" style="display:none"></p>
          <div id="activity-length"><b>Переход</b>: ${secondsToTime(calculateActivityLength(progress.doneFromZero))}</div>
          <div>Мой переход изменён на <input id="minus" type="number" value="${activitySettings[catId].minus || 0}" min="-60" max="10" step="1" style="width: 50px;"> <span id="minus-word"></span></nobr></div>
          <div>Я качаю активность <input id="hours-per-day" type="number" step="0.25" min="0" max="24" value="${activitySettings[catId].hours}" style="width: 60px"> <span id="hour-word"></span> в сутки</div>
          <div id="goal-progress">
            <b>Цель: <select style="display: inline" id="activity-list"></select></b>:
            <ul style="margin: 0.5em"></ul>
          </div>
          <div id="to-fall-container" style="display: none;">Переход начнёт падать <span id="to-fall"></span></div>
        </div>
      </details>
    `;

  document
    .getElementById("info")
    .insertAdjacentHTML("afterend", activityInfoHTML);

  if (activitySettings[catId].opened) {
    document.getElementById("calculator-activity").open = true;
  }

  for (let i = progress.stage + 1; i < activityStages.length; i++) {
    const option = document.createElement("option");
    option.value = i;
    option.textContent = activityStages[i].name;
    document.getElementById("activity-list").appendChild(option);
  }

  function showCongratulations() {

    document.getElementById("congratulations").innerHTML = // html
    `
      Цель <b>«${activityStages[activitySettings[catId].goal].name}»</b> достигнута!
      <center><img src="/img/stickers/systempaw3/6.png"></center>
      <input id="congratulations-button" type="button" value="Скрыть">
      <br><input id="never-show-congratulations" type="checkbox"> Больше не поздравлять на этом персонаже
    `;

    document.getElementById("congratulations").style.display = "block";
    document
      .getElementById("congratulations-button")
      .addEventListener("click", function () {
        document.getElementById("congratulations").style.display = "none";
        activitySettings[catId].goal = Number(
          document.getElementById("activity-list").value
        );
        activitySettings[catId].noGrats = document.getElementById(
          "never-show-congratulations"
        ).checked;
        saveData(activitySettings);
      });
  }

  if (activitySettings[catId].goal > progress.stage || activitySettings[catId].noGrats) {
    document.querySelector(
      `#activity-list > [value="${activitySettings[catId].goal}"]`
    ).selected = true;
  } else if (activitySettings[catId].goal) {
    showCongratulations();
  }

  if (activitySettings[catId].minus) {
    document.getElementById("minus").value = activitySettings[catId].minus;
  }

  const hours = activitySettings[catId].hours;
  const minusValue = activitySettings[catId].minus || 0;

  updateHourWord(hours);
  updateGoalProgress();
  updateMinusWord(minusValue);

  if (calculateActivityLength(progress.doneFromZero) !== 45) {
    document.getElementById("to-fall-container").style.display = "none";
  } else {
    const timeFall = new Date(
      Date.now() + (progress.doneFromZero - 1575) * 5 * 3600000
    );
    document.getElementById("to-fall").innerHTML =
      timeFall.getDate() +
      " " +
      months[timeFall.getMonth()] +
      " " +
      timeFall.getFullYear();
    document.getElementById("to-fall-container").style.display = "block";
  }

  document.getElementById("minus").addEventListener("change", function () {
    activitySettings[catId].minus = this.value;
    saveData(activitySettings);
    updateGoalProgress();
    document.getElementById(
      "activity-length"
    ).innerHTML = `<b>Переход</b>: ${secondsToTime(
      calculateActivityLength(progress.doneFromZero)
    )}`;
    updateMinusWord(this.value);
  });

  document.getElementById("activity-list").addEventListener("change", function () {
    activitySettings[catId].goal = Number(this.value);
    saveData(activitySettings);
    updateGoalProgress();
  });

  document
    .getElementById("hours-per-day")
    .addEventListener("input", function () {
      const hours = Number(this.value);
      if (hours < 0 || hours > 24 || !Number.isInteger(hours * 1000)) {
        this.value = activitySettings[catId].hours;
        return;
      }
      activitySettings[catId].hours = hours;
      saveData(activitySettings);
      updateHourWord(hours);
      updateGoalProgress();
    });

  document.getElementById("open-calculator").addEventListener("click", function () {
    activitySettings[catId].opened = !document.getElementById("calculator-activity").open;
    saveData(activitySettings);
  });

  function saveData(data) {
    window.localStorage.setItem("uwu_activity", JSON.stringify(data));
  }

  function declensionOfNumber(number, titles) {
    const cases = [2, 0, 1, 1, 1, 2];
    const absNumber = Math.abs(number);
    return titles[
      absNumber % 100 > 4 && absNumber % 100 < 20
        ? 2
        : cases[absNumber % 10 < 5 ? absNumber % 10 : 5]
    ];
  }

  function convertTime(from, value) {
    const factors = {
      ms: 1,
      s: 1000,
      m: 60000,
      h: 3600000,
      d: 86400000,
    };
    const [fromUnit, toUnit] = from.split(" ");
    return (value * factors[fromUnit]) / factors[toUnit];
  }

  function secondsToTime(seconds) {
    const days = Math.floor(seconds / 86400);
    const hours = Math.floor((seconds % 86400) / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = seconds % 60;
    let result = "";
    if (days > 0) result += `${days} д `;
    if (hours > 0) result += `${hours} ч `;
    if (minutes > 0) result += `${minutes} мин `;
    if (secs > 0 || result === "") result += `${secs} с`;
    return result.trim();
  }

  function updateHourWord(hours) {
    document.getElementById("hour-word").textContent = declensionOfNumber(hours, ["час", "часа", "часов"]);
  }
  
  function updateMinusWord(minusValue) {
    document.getElementById("minus-word").textContent = declensionOfNumber(minusValue, ["секунду", "секунды", "секунд"]);
  }
}
// ====================================================================================================================
//   . . . ПИСЬМА . . .
// ====================================================================================================================
if (targetLs.test(window.location.href)) {

  if (settings.lsWrapPreview) {
    setupMutationObserver("#main", setupPreviewButton, {
      childList: true,
      subtree: true,
    }); 
  }

}
// ====================================================================================================================
//   . . . БЛОГИ . . .
// ====================================================================================================================
if (targetBlog.test(window.location.href)) {

  if (settings.commentPreview) {
    setupMutationObserver("#site_table", addCommentPreview); 
  }

  if (settings.moreCommentButtons) {
    setupMutationObserver("#view_comments", addCommentButtons, {
      childList: true,
      subtree: true,
    });
    setupSingleCallback("#view_comments", handleCommentActions);
  }

}

// ====================================================================================================================
//   . . . ЛЕНТА . . .
// ====================================================================================================================
if (targetSniff.test(window.location.href)) {
  
  if (settings.commentPreview) {
    setupMutationObserver("#site_table", addCommentPreview); 
  }

  if (settings.moreCommentButtons) {
    setupMutationObserver("#view_comments", addCommentButtons, {
      childList: true,
      subtree: true,
    });
    setupSingleCallback("#view_comments", handleCommentActions);
  }

}

// ====================================================================================================================
//   . . . ПРЕДПРОСМОТР КОММЕНТАРИЯ . . .
// ====================================================================================================================
function addCommentPreview() {
  const form = document.querySelector("#send_comment_form");
  if (!form || document.getElementById("comment-preview")) return;

  const lastParagraph = form.querySelector("p:last-child");
  lastParagraph.insertAdjacentHTML( "afterbegin",
    `
    <input type="button" id="comment-preview" value="Предпросмотр"> 
    `
  );

  form.insertAdjacentHTML( "afterend",
    `
    <p id="comment-preview-hide" style="display: none; margin: 0.5em 0;"><a href="#">Скрыть предпросмотр</a></p>
    <div id="comment-preview-div" style="display: none;"></div>
    `
  );

  const previewButton = document.getElementById("comment-preview");
  const hideParagraph = document.getElementById("comment-preview-hide");
  const previewDiv = document.getElementById("comment-preview-div");

  const ws = io(window.location.origin, {
    path: "/ws/blogs/socket.io",
    reconnectionDelay: 10000,
    reconnectionDelayMax: 20000,
  });

  ws.on('creation preview', (data) => {
    previewDiv.innerHTML = data;
    previewDiv.style.display = 'block';
    hideParagraph.style.display = 'block';
  });

  previewButton.addEventListener('click', function() {
    const commentText = document.getElementById('comment').value;
    ws.emit('creation preview', commentText);
  });

  form
    .querySelector('[type="submit"]')
    .addEventListener("click", hideCommentPreview);
  hideParagraph.addEventListener("click", function (e) {
    e.preventDefault();
    hideCommentPreview();
  });

  function hideCommentPreview() {
    hideParagraph.style.display = "none";
    previewDiv.innerHTML = "";
    previewDiv.style.display = "none";
  }
};
// ====================================================================================================================
//   . . . КНОПКИ ОТВЕТИТЬ И ЦИТИРОВАТЬ . . .
// ====================================================================================================================
function addCommentButtons() {
  const comments = document.querySelectorAll('#view_comments .view-comment');
  comments.forEach(comment => {
      if (!comment.querySelector('.comment-answer-buttons')) {
          comment.insertAdjacentHTML('beforeend', // html
            `
              <p class="comment-answer-buttons">
                  <a class="comment-answer" href="#">Ответить</a>
                  <span class="comment-cite-wrap"> | <a class="comment-cite" href="#">Цитировать</a></span>
              </p>
          `);
      }
  });
}

function getCommentInfo(comment) {
  const commentId = comment.getAttribute('data-id');
  const commentNum = comment.querySelector('.num').textContent;
  const authorLink = comment.querySelector('.comment-info a.author');
  const authorSpan = comment.querySelector('.comment-info span[data-id]');
  const authorName = authorLink ? authorLink.textContent : (authorSpan ? authorSpan.textContent : '...');
  const authorProfile = authorLink ? authorLink.getAttribute('href').replace('/cat', '') : null;
  const commentText = comment.querySelector('.comment-text .parsed').innerText;
  const commentInfo = comment.querySelector('.comment-info');
  const commentTime = commentInfo.innerHTML.split('</b>')[1].split(' @')[0].trim();

  return {
    commentId,
    commentNum,
    authorName,
    authorProfile,
    commentText,
    commentTime
  };
}

function handleAnswerAction(commentInfo) {
  const textarea = document.getElementById('comment');
  if (commentInfo.authorProfile) {
      textarea.value = `[link${commentInfo.authorProfile}] (#${commentInfo.commentNum}), `;
  } else {
      textarea.value = `[b][code]${commentInfo.authorName}[/code][/b] (#${commentInfo.commentNum}), `;
  }
}

function handleCiteAction(commentInfo) {
  const selectedText = window.getSelection().toString().trim();
  const quoteText = selectedText ? selectedText : commentInfo.commentText;
  const profileLink = commentInfo.authorProfile ? `[link${commentInfo.authorProfile}]` : commentInfo.authorName;

  const quote = `[table][tr][td][size=10][i]Цитата:[/i] [b]#${commentInfo.commentNum}[/b] ${commentInfo.commentTime} @ ${profileLink}[/size][/td][/tr][tr][td][table=0][tr][td]  [/td][td]${quoteText}[/td][/tr][/table][/td][/tr][/table]`;

  const textarea = document.getElementById('comment');
  textarea.value = quote;
}

function handleCommentActions() {
    const viewComments = document.getElementById('view_comments');

    viewComments.addEventListener('click', function(event) {
        const target = event.target;
        const actionMap = {
            'comment-answer': handleAnswerAction,
            'comment-cite': handleCiteAction
        };

        for (const className in actionMap) {
            if (target.classList.contains(className)) {
                event.preventDefault();
                const comment = target.closest('.view-comment');
                const commentInfo = getCommentInfo(comment);
                actionMap[className](commentInfo);
                break;
            }
        }
    });
}

// ====================================================================================================================
//   . . . КРАСИВЫЙ ПРЕДПРОСМОТР ПИСЬМА . . .
// ====================================================================================================================
function setupPreviewButton() {
  const previewButton = document.getElementById('preview');
  if (previewButton) {
      previewButton.addEventListener('click', wrapPreviewInTable);
  }
}

function wrapPreviewInTable() {
  const previewDiv = document.getElementById('preview_div');
  if (!previewDiv) return;

  const mainElement = document.getElementById('main');
  const senderId = mainElement.getAttribute('data-id');
  const senderLogin = mainElement.getAttribute('data-login');
  const subject = document.getElementById('subject').value;
  const currentDate = new Date().toLocaleString('ru-RU', {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit'
  });

  const newTable = document.createElement('table');
  newTable.border = "1";
  newTable.style.width = "90%";
  newTable.style.maxWidth = "500px";

  newTable.innerHTML = // html
  `
      <tbody>
          <tr><td id="preview-subject" colspan="2">${subject}</td></tr>
          <tr>
              <td valign="top" id="msg_info">
                  Отправитель: <span id="preview-sender"><a href="cat${senderId}">${senderLogin}</a></span>
                  <br>${currentDate}
                  <br>Переписка: <u><big><b>+</b></big></u> …
              </td>
              <td id="preview-text">${previewDiv.outerHTML}</td>
          </tr>
      </tbody>
  `;

  const existingTable = document.querySelector('table');
  if (existingTable) {
      existingTable.parentNode.replaceChild(newTable, existingTable);
  } else {
      previewDiv.parentNode.insertBefore(newTable, previewDiv);
      previewDiv.style.display = 'none';
  }
}

// ====================================================================================================================
//   . . . ШАБЛОНЫ . . .
// ====================================================================================================================
function initializeTemplates() {
  if (!settings.showTemplates) return;

  const templateContainer = // html
  `
      <div id="uwu-templates">
          <h2>ШАБЛОНЫ</h2>
          <div id="uwu-templates-list"></div>
          <div class="button-container">
              <button id="create-template-button" class="uwu-button install-button">Создать шаблон ✎</button>
          </div>
      </div>
  `;

  const templateItem = // html
  `
      <div class="uwu-template-item">
          <div class="template-name-container">
              <span class="template-name"></span>
              <button class="rename-button uwu-button install-button" title="Переименовать шаблон">✎</button>
          </div>
          <div class="template-actions-container">
              <button class="update-button uwu-button install-button" title="Обновить шаблон">↻</button>
              <button class="remove-button uwu-button install-button" title="Удалить шаблон">X</button>
          </div>
      </div>
  `;

  const cssStyles = // css
  `
      #uwu-templates {
        font-family: Montserrat;
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 20px;
        background-color: #242424;
        margin-bottom: 5px;
        margin-top: 5px;
        color: #d5d5d5;
      }
      
      #uwu-templates > h2 {
        font-size: 2em;
        text-align: center;
        margin-top: 10px;
        margin-bottom: 10px;
        letter-spacing: 20px;
      }

      #uwu-templates-list {
        max-height: 220px;
        overflow-x: auto;
        border-radius: 20px;
        background-color: #2e2e2e;
      }

      .uwu-template-item {
        padding-left: 10px;
        padding-right: 10px;
        padding-top: 5px;
        padding-bottom: 5px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      #uwu-templates > div.button-container {
        display: flex;
        justify-content: flex-end;
        padding-left: 10px;
        padding-right: 4px;
        padding-top: 5px;
        padding-bottom: 5px;
      }

      .template-name {
        cursor: pointer;
        text-decoration: underline;
      }

      .uwu-button {
        background-color: rgba(255, 255, 255, 0.03);
        border: 1px solid rgba(255, 255, 255, 0.1);
        padding: 5px 10px;
        border-radius: 20px;
        cursor: pointer;
        transition: background-color 0.3s ease;
      }
      
      .uwu-button:hover {
        background-color: rgba(255, 255, 255, 0.2);
      }
  `;

  document.head.insertAdjacentHTML('beforeend', `<style>${cssStyles}</style>`);

  function setupTemplates(targetElementId, contentElementId, subjectElementId = null, pageType) {
    const targetElement = document.getElementById(targetElementId);

    if (!document.getElementById('uwu-templates')) {
        if (targetElementId === 'mess_form') {
            targetElement.insertAdjacentHTML('beforeend', templateContainer);
        } else {
            targetElement.insertAdjacentHTML('afterbegin', templateContainer);
        }
    }

      const templatesList = document.getElementById('uwu-templates-list');
      const createButton = document.getElementById('create-template-button');

      createButton.addEventListener('click', (event) => {
          event.preventDefault();
          createTemplate(contentElementId, subjectElementId, pageType);
      });

      function createTemplate(contentElementId, subjectElementId, pageType) {
          const templateName = prompt('Введите название шаблона:');
          if (templateName) {
              const template = {
                  name: templateName,
                  content: document.getElementById(contentElementId).innerText || document.getElementById(contentElementId).value,
                  subject: subjectElementId ? document.getElementById(subjectElementId).value || "" : "",
                  pageType: pageType
              };
              saveTemplate(template);
              renderTemplates(pageType);
          }
      }

      function saveTemplate(template) {
          if (!localStorage.getItem('uwu_templates')) {
              localStorage.setItem('uwu_templates', JSON.stringify([]));
          }
          const templates = JSON.parse(localStorage.getItem('uwu_templates'));
          templates.push(template);
          localStorage.setItem('uwu_templates', JSON.stringify(templates));
      }

      function renderTemplates(pageType) {
          const templates = JSON.parse(localStorage.getItem('uwu_templates')) || [];
          templatesList.innerHTML = '';

          templates.forEach((template, index) => {
              if (template.pageType === pageType) {
                  const templateItemHTML = document.createElement('div');
                  templateItemHTML.innerHTML = templateItem;
                  const templateItemElement = templateItemHTML.children[0];

                  const templateName = templateItemElement.querySelector('.template-name');
                  templateName.textContent = template.name;
                  templateName.addEventListener('click', () => {
                      if (document.getElementById(contentElementId).tagName === 'DIV') {
                          document.getElementById(contentElementId).innerText = template.content;
                      } else {
                          document.getElementById(contentElementId).value = template.content;
                      }
                      if (subjectElementId) {
                          document.getElementById(subjectElementId).value = template.subject || "";
                      }
                  });

                  const renameButton = templateItemElement.querySelector('.rename-button');
                  renameButton.addEventListener('click', () => renameTemplate(index));

                  const updateButton = templateItemElement.querySelector('.update-button');
                  updateButton.addEventListener('click', () => updateTemplate(index, contentElementId, subjectElementId));

                  const removeButton = templateItemElement.querySelector('.remove-button');
                  removeButton.addEventListener('click', () => removeTemplate(index));

                  templatesList.appendChild(templateItemElement);
              }
          });
      }

      function renameTemplate(index) {
          const newName = prompt('Введите новое название шаблона:');
          if (newName) {
              const templates = JSON.parse(localStorage.getItem('uwu_templates'));
              templates[index].name = newName;
              localStorage.setItem('uwu_templates', JSON.stringify(templates));
              renderTemplates(pageType);
          }
      }

      function updateTemplate(index, contentElementId, subjectElementId) {
          const templates = JSON.parse(localStorage.getItem('uwu_templates'));
          if (document.getElementById(contentElementId).tagName === 'DIV') {
              templates[index].content = document.getElementById(contentElementId).innerText;
          } else {
              templates[index].content = document.getElementById(contentElementId).value;
          }
          if (subjectElementId) {
              templates[index].subject = document.getElementById(subjectElementId).value || "";
          }
          localStorage.setItem('uwu_templates', JSON.stringify(templates));
          renderTemplates(pageType);
      }

      function removeTemplate(index) {
        const confirmation = confirm('Вы уверены, что хотите удалить этот шаблон?');
        if (confirmation) {
            const templates = JSON.parse(localStorage.getItem('uwu_templates'));
            templates.splice(index, 1);
            localStorage.setItem('uwu_templates', JSON.stringify(templates));
            renderTemplates(pageType);
        }
    }

      renderTemplates(pageType);
  }

  function checkUrlAndSetup() {
    if (targetLsNew.test(window.location.href) && settings.templatesInLs) {
        setupSingleCallback("#write_form", () => setupTemplates("write_div", "text", "subject", "ls"));
    } else if ((targetBlogsCreation.test(window.location.href) || targetSniffCreation.test(window.location.href)) && settings.templatesInBlogsAndSniffs) {
        setupSingleCallback(".creation_form", () => setupTemplates("creation_form", "creation-text", "creation-title", "blogsAndSniffs"));
    } else if (targetChats.test(window.location.href) && settings.templatesInChats) {
        setupSingleCallback("#mess_form", () => setupTemplates("mess_form", "mess", null, "chat"));
    }
}

setupMutationObserver("#main", checkUrlAndSetup, {
  childList: true,
  attributes: true,
});

setupMutationObserver("#branch", checkUrlAndSetup, {
  childList: true,
});
}

initializeTemplates();