Diep.io Build Browser & Share by Kronati

Browse & share public builds for diep.io tanks, with highscores, slash stats and a menu button next to "Shop".

目前為 2025-11-20 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Diep.io Build Browser & Share by Kronati
// @namespace    https://diep.kronea.app
// @version      0.1.0
// @description  Browse & share public builds for diep.io tanks, with highscores, slash stats and a menu button next to "Shop".
// @author       Kronati
// @match        *://diep.io/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
  
    const API_BASE = 'https://diep.kronea.app';
  
    const API_ROUTES = {
      tanks: '/api/tanks',
      buildsByTank: '/api/builds?tankId=',
      buildsAll: '/api/builds/all',
      createBuild: '/api/builds',
      voteBuild: (buildId) => `/api/builds/${buildId}/vote`,
      submitHighscore: (buildId) => `/api/builds/${buildId}/highscore`
    };
  
    const TANK_IMAGE_BASE = 'https://diep.kronea.app/img/tanks/';
  
    const TANK_IMAGE_FALLBACK_COLOR = '#60a5fa';

    let uiRoot = null;
    let tanksCache = null;
    let currentTankId = null;
    let currentTankName = null;
    let currentView = 'general';
    let currentSortBy = 'rating';
    let currentSortOrder = 'desc';
    let currentSearch = '';
    let settingsOpen = false;

    const DEFAULT_SETTINGS = {
    };
    
    function loadSettings() {
      try {
        const saved = localStorage.getItem('kbui_settings');
        if (saved) {
          return { ...DEFAULT_SETTINGS, ...JSON.parse(saved) };
        }
      } catch (e) {
        console.error('[KBUI] Failed to load settings:', e);
      }
      return { ...DEFAULT_SETTINGS };
    }
    
    function saveSettings(settings) {
      try {
        localStorage.setItem('kbui_settings', JSON.stringify(settings));
      } catch (e) {
        console.error('[KBUI] Failed to save settings:', e);
      }
    }
    
    let currentSettings = loadSettings();
    let currentTankSearch = '';
  
    function injectStyles() {
      if (document.getElementById('kronati-build-ui-style')) return;
      const style = document.createElement('style');
      style.id = 'kronati-build-ui-style';
      style.textContent = `
        .kbui-root {
          position: fixed;
          inset: 0;
          z-index: 99998;
          display: none;
          align-items: center;
          justify-content: center;
          font-family: "Nunito", "Segoe UI", sans-serif;
        }
        .kbui-root.visible {
          display: flex;
        }
        .kbui-backdrop {
          position: absolute;
          inset: 0;
          background: radial-gradient(circle at top, rgba(0,0,0,0.7), rgba(0,0,0,0.9));
        }
        .kbui-panel {
          position: relative;
          width: min(95vw, 1400px);
          height: min(85vh, 800px);
          background: #2b3238;
          border-radius: 12px;
          border: 2px solid #4b5966;
          box-shadow: 0 0 40px rgba(0,0,0,0.8);
          padding: 20px 24px;
          display: flex;
          flex-direction: column;
          color: #dfe9f4;
        }
        .kbui-header {
          display: flex;
          align-items: center;
          justify-content: space-between;
          margin-bottom: 16px;
        }
        .kbui-title {
          font-size: 24px;
          font-weight: 700;
          color: #f1f5f9;
        }
        .kbui-subtitle {
          font-size: 13px;
          opacity: 0.75;
        }
        .kbui-close-btn {
          cursor: pointer;
          border: 1px solid #8b99a6;
          border-radius: 8px;
          padding: 6px 14px;
          background: #1c2126;
          color: #f8fafc;
          font-size: 13px;
          text-transform: uppercase;
          letter-spacing: 0.04em;
        }
        .kbui-close-btn:hover {
          border-color: #facc15;
          color: #facc15;
        }
        .kbui-body {
          flex: 1;
          display: flex;
          gap: 16px;
          overflow: hidden;
        }
        .kbui-sidebar {
          width: 300px;
          border-right: 1px solid #3b454f;
          padding-right: 12px;
          display: flex;
          flex-direction: column;
        }
        .kbui-main {
          flex: 1;
          display: flex;
          flex-direction: column;
          overflow: hidden;
        }
        .kbui-section-title {
          font-size: 14px;
          text-transform: uppercase;
          letter-spacing: 0.08em;
          color: #9ca3af;
          margin-bottom: 10px;
        }
        .kbui-tank-grid {
          display: flex;
          flex-direction: column;
          overflow-y: auto;
          padding-right: 6px;
          gap: 8px;
        }
        .kbui-level-header {
          font-size: 12px;
          font-weight: 700;
          color: #facc15;
          text-transform: uppercase;
          letter-spacing: 0.1em;
          margin-top: 8px;
          margin-bottom: 4px;
          padding: 4px 0;
          border-bottom: 1px solid #374151;
        }
        .kbui-tank-grid-level {
          display: grid;
          grid-template-columns: repeat(3, minmax(0,1fr));
          gap: 8px;
        }
        .kbui-tank-card {
          background: #1f252b;
          border-radius: 10px;
          border: 1px solid #3b444f;
          padding: 10px 6px;
          cursor: pointer;
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 6px;
          transition: background 0.1s, transform 0.08s, border-color 0.1s;
        }
        .kbui-tank-card:hover {
          background: #27313a;
          transform: translateY(-1px);
          border-color: #facc15;
        }
        .kbui-tank-card.selected {
          border-color: #22c55e;
          box-shadow: 0 0 0 1px rgba(34,197,94,0.5);
        }
        .kbui-tank-icon {
          width: 40px;
          height: 40px;
          border-radius: 8px;
          background-size: contain;
          background-position: center;
          background-repeat: no-repeat;
          background-color: #111827;
          border: 1px solid #4b5563;
        }
        .kbui-tank-name {
          font-size: 13px;
          text-align: center;
        }
        .kbui-list-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-bottom: 10px;
          flex-wrap: wrap;
          gap: 8px;
        }
        .kbui-tabs {
          display: flex;
          gap: 6px;
          margin-bottom: 10px;
        }
        .kbui-tab {
          padding: 6px 14px;
          border-radius: 8px;
          border: 1px solid #4b5563;
          background: #1f252b;
          color: #9ca3af;
          cursor: pointer;
          font-size: 13px;
          font-weight: 600;
          transition: all 0.1s;
        }
        .kbui-tab:hover {
          border-color: #facc15;
          color: #facc15;
        }
        .kbui-tab.active {
          background: #facc15;
          color: #111827;
          border-color: #facc15;
        }
        .kbui-search-sort {
          display: flex;
          gap: 6px;
          align-items: center;
          flex-wrap: wrap;
        }
        .kbui-search-input {
          border-radius: 8px;
          border: 1px solid #4b5563;
          background: #020617;
          color: #e5e7eb;
          padding: 8px 12px;
          font-size: 13px;
          min-width: 200px;
        }
        .kbui-search-input:focus {
          outline: none;
          border-color: #facc15;
          box-shadow: 0 0 0 1px rgba(250,204,21,0.4);
        }
        .kbui-sort-select {
          border-radius: 8px;
          border: 1px solid #4b5563;
          background: #020617;
          color: #e5e7eb;
          padding: 8px 12px;
          font-size: 13px;
          cursor: pointer;
        }
        .kbui-sort-select:focus {
          outline: none;
          border-color: #facc15;
          box-shadow: 0 0 0 1px rgba(250,204,21,0.4);
        }
        .kbui-build-list {
          flex: 1;
          overflow-y: auto;
          border-radius: 10px;
          border: 1px solid #38414a;
          background: radial-gradient(circle at top, #232a30, #181c20);
          padding: 10px;
        }
        .kbui-build-card {
          border-radius: 10px;
          border: 1px solid #374151;
          padding: 12px 14px;
          margin-bottom: 8px;
          background: rgba(15,23,42,0.7);
          display: flex;
          flex-direction: column;
          gap: 8px;
        }
        .kbui-build-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
        }
        .kbui-build-name {
          font-size: 16px;
          font-weight: 600;
        }
        .kbui-rating {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          font-size: 13px;
        }
        .kbui-rating button {
          border-radius: 999px;
          border: 1px solid #4b5563;
          background: #111827;
          color: #e5e7eb;
          padding: 4px 10px;
          font-size: 12px;
          cursor: pointer;
          min-width: 32px;
        }
        .kbui-rating button:hover {
          border-color: #facc15;
          color: #facc15;
        }
        .kbui-stat-grid {
          display: grid;
          grid-template-columns: repeat(4, minmax(0,1fr));
          gap: 6px 12px;
          font-size: 12px;
        }
        .kbui-stat-label {
          opacity: 0.75;
        }
        .kbui-stat-value {
          font-weight: 600;
          color: #e5e7eb;
          font-size: 13px;
        }
        .kbui-slash-stats {
          margin: 8px 0;
          padding: 10px 12px;
          background: rgba(15,23,42,0.5);
          border-radius: 8px;
          border: 1px solid #374151;
          font-family: 'Courier New', monospace;
          font-size: 16px;
          font-weight: 600;
          color: #facc15;
          text-align: center;
          letter-spacing: 0.05em;
        }
        .kbui-build-footer {
          display: flex;
          justify-content: space-between;
          align-items: center;
          font-size: 12px;
          opacity: 0.75;
        }
        .kbui-pill {
          border-radius: 999px;
          border: 1px solid #4b5563;
          padding: 4px 10px;
        }
        .kbui-button-main {
          border-radius: 999px;
          border: 1px solid #fbbf24;
          background: linear-gradient(135deg, #facc15, #f97316);
          color: #111827;
          font-size: 13px;
          padding: 8px 16px;
          cursor: pointer;
          font-weight: 600;
          box-shadow: 0 0 12px rgba(250,204,21,0.4);
        }
        .kbui-button-main:hover {
          filter: brightness(1.05);
        }
        .kbui-form {
          margin-top: 10px;
          border-radius: 10px;
          border: 1px solid #374151;
          padding: 12px 14px;
          background: rgba(15,23,42,0.8);
          display: flex;
          flex-direction: column;
          gap: 8px;
          font-size: 13px;
        }
        .kbui-form-row {
          display: flex;
          gap: 8px;
        }
        .kbui-form-group {
          flex: 1;
          display: flex;
          flex-direction: column;
          gap: 4px;
        }
        .kbui-form-group label {
          opacity: 0.75;
          font-size: 12px;
        }
        .kbui-form-group input,
        .kbui-form-group select {
          border-radius: 8px;
          border: 1px solid #4b5563;
          background: #020617;
          color: #e5e7eb;
          padding: 8px 10px;
          font-size: 13px;
        }
        .kbui-form-group input:focus,
        .kbui-form-group select:focus {
          outline: none;
          border-color: #facc15;
          box-shadow: 0 0 0 1px rgba(250,204,21,0.4);
        }
        .kbui-form-footer {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-top: 8px;
        }
        .kbui-small {
          font-size: 12px;
          opacity: 0.7;
        }
        .kbui-toast {
          position: fixed;
          bottom: 20px;
          right: 20px;
          background: rgba(15,23,42,0.95);
          color: #e5e7eb;
          padding: 10px 16px;
          border-radius: 999px;
          border: 1px solid #4b5563;
          font-size: 13px;
          z-index: 99999;
          opacity: 0;
          transform: translateY(8px);
          transition: opacity 0.15s ease, transform 0.15s ease;
        }
        .kbui-toast.visible {
          opacity: 1;
          transform: translateY(0);
        }
  #kbui-builds-menu-button.kbui-builds-btn {
    --color: var(--ui-color-3);
    margin-left: 6px;
    position: relative;
    overflow: hidden;
    font-family: "Nunito", "Verdana", sans-serif !important;
    background: #2b3238 !important;
    border: 1px solid #374151 !important;
    opacity: 1 !important;
    visibility: visible !important;
  }
  
  #kbui-builds-menu-button.kbui-builds-btn::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(255,255,255,0.1), rgba(0,0,0,0.1));
    opacity: 0.6;
    pointer-events: none;
    z-index: 1;
  }
  
  #kbui-builds-menu-button .kbui-builds-icon {
    width: 1.5em;
    height: 1.5em;
    border-radius: 50%;
    background: radial-gradient(circle at 30% 20%, #a5b4fc, #6366f1);
    border: 2px solid rgba(15,23,42,0.9);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: "Nunito", "Verdana", sans-serif !important;
    font-weight: 800;
    font-size: 0.9em;
    color: #ffffff;
    text-shadow: 0 0 3px rgba(0,0,0,0.45);
  }
  
  #kbui-builds-menu-button .kbui-builds-inner {
    position: relative;
    z-index: 2;
  }
  
  #kbui-builds-menu-button .kbui-no-icon {
    padding: 0 16px;
  }
  
  #kbui-builds-menu-button .kbui-builds-label {
    font-family: "Nunito", "Verdana", sans-serif !important;
    font-size: 16px;
    font-weight: 700;
    color: #f1f5f9 !important;
    text-shadow: 0 1px 2px rgba(0,0,0,0.5);
    position: relative;
    z-index: 2;
  }
  
  #kbui-builds-menu-button:hover {
    background: #374151 !important;
    filter: brightness(1.1);
  }
  
  #kbui-builds-menu-button:active {
    background: #1f2937 !important;
  }
  
  
      `;
      document.head.appendChild(style);
    }
  
    let toastEl = null;
    let toastTimeout = null;
  
    function showToast(message) {
      if (!toastEl) {
        toastEl = document.createElement('div');
        toastEl.className = 'kbui-toast';
        document.body.appendChild(toastEl);
      }
      toastEl.textContent = message;
      toastEl.classList.add('visible');
      if (toastTimeout) clearTimeout(toastTimeout);
      toastTimeout = setTimeout(() => {
        toastEl.classList.remove('visible');
      }, 2200);
    }
  
    async function apiGet(path) {
      const res = await fetch(API_BASE + path, { credentials: 'omit' });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return res.json();
    }
  
    async function apiPost(path, body) {
      const res = await fetch(API_BASE + path, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'omit',
        body: JSON.stringify(body)
      });
      if (!res.ok) {
        let errorMessage = `HTTP ${res.status}`;
        try {
          const errorData = await res.json();
          if (errorData.error) {
            errorMessage = errorData.error;
          }
          if (errorData.message) {
            errorMessage = errorData.message;
          }
          const error = new Error(errorMessage);
          error.status = res.status;
          error.data = errorData;
          throw error;
        } catch (parseError) {
          const error = new Error(errorMessage);
          error.status = res.status;
          throw error;
        }
      }
      return res.json();
    }

    async function apiPostFormData(path, formData) {
      const res = await fetch(API_BASE + path, {
        method: 'POST',
        credentials: 'omit',
        body: formData
      });
      if (!res.ok) {
        const errorText = await res.text();
        throw new Error(`HTTP ${res.status}: ${errorText}`);
      }
      return res.json();
    }
  
    async function copyToClipboard(text) {
      try {
        await navigator.clipboard.writeText(text);
        return true;
      } catch (err) {
        try {
          const textArea = document.createElement('textarea');
          textArea.value = text;
          textArea.style.position = 'fixed';
          textArea.style.left = '-999999px';
          textArea.style.top = '-999999px';
          document.body.appendChild(textArea);
          textArea.focus();
          textArea.select();
          const successful = document.execCommand('copy');
          document.body.removeChild(textArea);
          return successful;
        } catch (e) {
          return false;
        }
      }
    }

    function createUIRoot() {
      if (uiRoot) return uiRoot;
      uiRoot = document.createElement('div');
      uiRoot.className = 'kbui-root';
  
      const backdrop = document.createElement('div');
      backdrop.className = 'kbui-backdrop';
      backdrop.addEventListener('click', () => toggleUI(false));
  
      const panel = document.createElement('div');
      panel.className = 'kbui-panel';
  
      const header = document.createElement('div');
      header.className = 'kbui-header';
  
      const leftHeader = document.createElement('div');
      const title = document.createElement('div');
      title.className = 'kbui-title';
      title.textContent = 'Diep.io Build Browser';
  
      const subtitle = document.createElement('div');
      subtitle.className = 'kbui-subtitle';
      subtitle.textContent = 'Browse & share public builds – by Kronati';
  
      leftHeader.appendChild(title);
      leftHeader.appendChild(subtitle);

      const rightHeader = document.createElement('div');
      rightHeader.style.display = 'flex';
      rightHeader.style.alignItems = 'center';
      rightHeader.style.gap = '10px';

      const settingsBtn = document.createElement('button');
      settingsBtn.className = 'kbui-button-main';
      settingsBtn.innerHTML = '⚙️';
      settingsBtn.style.padding = '6px 10px';
      settingsBtn.style.fontSize = '16px';
      settingsBtn.style.cursor = 'pointer';
      settingsBtn.title = 'Settings';
      settingsBtn.addEventListener('click', () => openSettings());

      const closeBtn = document.createElement('button');
      closeBtn.className = 'kbui-close-btn';
      closeBtn.textContent = 'Close';
      closeBtn.addEventListener('click', () => toggleUI(false));

      rightHeader.appendChild(settingsBtn);
      rightHeader.appendChild(closeBtn);

      header.appendChild(leftHeader);
      header.appendChild(rightHeader);
  
      const body = document.createElement('div');
      body.className = 'kbui-body';
  
      const sidebar = document.createElement('div');
      sidebar.className = 'kbui-sidebar';

      const sidebarTitle = document.createElement('div');
      sidebarTitle.className = 'kbui-section-title';
      sidebarTitle.textContent = 'Tanks';

      const tankSearchInput = document.createElement('input');
      tankSearchInput.type = 'text';
      tankSearchInput.className = 'kbui-search-input';
      tankSearchInput.placeholder = 'Search tanks...';
      tankSearchInput.id = 'kbui-tank-search-input';
      tankSearchInput.style.marginBottom = '10px';
      let tankSearchTimeout = null;
      tankSearchInput.addEventListener('input', (e) => {
        clearTimeout(tankSearchTimeout);
        tankSearchTimeout = setTimeout(() => {
          currentTankSearch = e.target.value.trim().toLowerCase();
          loadTanks().then(renderTankGrid).catch((e) => console.error(e));
        }, 200);
      });

      const tankGrid = document.createElement('div');
      tankGrid.className = 'kbui-tank-grid';
      tankGrid.id = 'kbui-tank-grid';

      sidebar.appendChild(sidebarTitle);
      sidebar.appendChild(tankSearchInput);
      sidebar.appendChild(tankGrid);
  
      const main = document.createElement('div');
      main.className = 'kbui-main';

      const tabs = document.createElement('div');
      tabs.className = 'kbui-tabs';
      
      const generalTab = document.createElement('button');
      generalTab.className = 'kbui-tab active';
      generalTab.textContent = 'General';
      generalTab.addEventListener('click', () => switchView('general'));
      
      const tankTab = document.createElement('button');
      tankTab.className = 'kbui-tab';
      tankTab.textContent = 'By Tank';
      tankTab.addEventListener('click', () => switchView('tank'));
      
      tabs.appendChild(generalTab);
      tabs.appendChild(tankTab);

      const listHeader = document.createElement('div');
      listHeader.className = 'kbui-list-header';

      const listHeaderLeft = document.createElement('div');
      listHeaderLeft.style.display = 'flex';
      listHeaderLeft.style.flexDirection = 'column';
      listHeaderLeft.style.gap = '6px';
      listHeaderLeft.style.flex = '1';

      const listTitle = document.createElement('div');
      listTitle.className = 'kbui-section-title';
      listTitle.textContent = 'Builds';

      const searchSort = document.createElement('div');
      searchSort.className = 'kbui-search-sort';
      
      const searchInput = document.createElement('input');
      searchInput.type = 'text';
      searchInput.className = 'kbui-search-input';
      searchInput.placeholder = 'Search builds...';
      searchInput.id = 'kbui-search-input';
      let searchTimeout = null;
      searchInput.addEventListener('input', (e) => {
        clearTimeout(searchTimeout);
        searchTimeout = setTimeout(() => {
          currentSearch = e.target.value.trim();
          if (currentView === 'general') {
            loadAllBuilds();
          }
        }, 300);
      });

      const sortSelect = document.createElement('select');
      sortSelect.className = 'kbui-sort-select';
      sortSelect.id = 'kbui-sort-select';
      sortSelect.innerHTML = `
        <option value="rating">Rating</option>
        <option value="highscore">Highscore</option>
        <option value="upvotes">Upvotes</option>
        <option value="downvotes">Downvotes</option>
        <option value="name">Name</option>
      `;
      sortSelect.value = currentSortBy;
      sortSelect.addEventListener('change', (e) => {
        currentSortBy = e.target.value;
        if (currentView === 'general') {
          loadAllBuilds();
        }
      });

      const orderSelect = document.createElement('select');
      orderSelect.className = 'kbui-sort-select';
      orderSelect.id = 'kbui-order-select';
      orderSelect.innerHTML = `
        <option value="desc">Descending</option>
        <option value="asc">Ascending</option>
      `;
      orderSelect.value = currentSortOrder;
      orderSelect.addEventListener('change', (e) => {
        currentSortOrder = e.target.value;
        if (currentView === 'general') {
          loadAllBuilds();
        }
      });

      searchSort.appendChild(searchInput);
      searchSort.appendChild(sortSelect);
      searchSort.appendChild(orderSelect);

      listHeaderLeft.appendChild(listTitle);
      listHeaderLeft.appendChild(searchSort);

      const createBtn = document.createElement('button');
      createBtn.className = 'kbui-button-main';
      createBtn.textContent = 'Create Build';
      createBtn.addEventListener('click', () => openCreateBuildForm());

      listHeader.appendChild(listHeaderLeft);
      listHeader.appendChild(createBtn);

      const buildList = document.createElement('div');
      buildList.className = 'kbui-build-list';
      buildList.id = 'kbui-build-list';
      buildList.textContent = 'Loading builds...';

      main.appendChild(tabs);
      main.appendChild(listHeader);
      main.appendChild(buildList);
  
      body.appendChild(sidebar);
      body.appendChild(main);
  
      panel.appendChild(header);
      panel.appendChild(body);
  
      uiRoot.appendChild(backdrop);
      uiRoot.appendChild(panel);
      document.body.appendChild(uiRoot);
      return uiRoot;
    }
  
    function toggleUI(show) {
      const root = createUIRoot();
      if (show) {
        root.classList.add('visible');
        if (currentView === 'general') {
          loadAllBuilds();
        }
      } else {
        root.classList.remove('visible');
      }
    }

    function switchView(view) {
      currentView = view;
      const tabs = document.querySelectorAll('.kbui-tab');
      tabs.forEach(tab => tab.classList.remove('active'));
      
      if (view === 'general') {
        tabs[0].classList.add('active');
        document.getElementById('kbui-search-input').style.display = '';
        document.getElementById('kbui-sort-select').style.display = '';
        document.getElementById('kbui-order-select').style.display = '';
        loadAllBuilds();
      } else {
        tabs[1].classList.add('active');
        document.getElementById('kbui-search-input').style.display = 'none';
        document.getElementById('kbui-sort-select').style.display = 'none';
        document.getElementById('kbui-order-select').style.display = 'none';
        if (currentTankId) {
          loadBuildsForTank(currentTankId, currentTankName);
        } else {
          const list = document.getElementById('kbui-build-list');
          if (list) list.textContent = 'Select a tank on the left to view builds.';
        }
      }
    }
  
  function injectMenuBuildButton() {
    if (document.getElementById('kbui-builds-menu-button')) return;
  
    const container = document.querySelector('.corner-buttons.top.left[data-is-active="true"]');
    if (!container) return;
  
    const btn = document.createElement('button');
    btn.id = 'kbui-builds-menu-button';
    btn.className = 'updated-standard-button active minimal diep-style-button kbui-builds-btn';
    btn.setAttribute('tabindex', '-1');
    btn.setAttribute('data-is-clickable', 'true');
    btn.setAttribute('data-is-flashing', 'false');
    btn.style.setProperty('--color', 'var(--ui-color-3)');
  
    const inner = document.createElement('div');
    inner.className = 'kbui-builds-inner kbui-no-icon';
    const label = document.createElement('div');
    label.className = 'kbui-builds-label';
    label.textContent = 'Builds';
    inner.appendChild(label);
    btn.appendChild(inner);
  
    btn.addEventListener('click', (e) => {
      e.stopPropagation();
      toggleUI(true);
    });
  
    container.appendChild(btn);
  }
    async function loadTanks() {
      if (tanksCache) return tanksCache;
      const tanks = await apiGet(API_ROUTES.tanks);
      tanksCache = tanks;
      return tanks;
    }
  
    function renderTankGrid(tanks) {
      const grid = document.getElementById('kbui-tank-grid');
      if (!grid) return;
      grid.innerHTML = '';
  
      if (!tanks || !tanks.length) {
        const msg = document.createElement('div');
        msg.className = 'kbui-small';
        msg.textContent = 'No tanks from API yet. Configure your backend.';
        grid.appendChild(msg);
        return;
      }
  
      let filteredTanks = tanks;
      if (currentTankSearch) {
        filteredTanks = tanks.filter(tank => {
          const name = (tank.name || '').toLowerCase();
          const shortName = (tank.shortName || '').toLowerCase();
          return name.includes(currentTankSearch) || shortName.includes(currentTankSearch);
        });
      }

      if (!filteredTanks.length) {
        const msg = document.createElement('div');
        msg.className = 'kbui-small';
        msg.textContent = 'No tanks found matching your search.';
        grid.appendChild(msg);
        return;
      }

      const tanksByLevel = {
        1: [],
        15: [],
        30: [],
        45: []
      };

      filteredTanks.forEach(tank => {
        const level = tank.level || tank.sortOrder || 0;
        if (level === 1) tanksByLevel[1].push(tank);
        else if (level === 15) tanksByLevel[15].push(tank);
        else if (level === 30) tanksByLevel[30].push(tank);
        else if (level === 45) tanksByLevel[45].push(tank);
        else tanksByLevel[45].push(tank);
      });

      const levels = [1, 15, 30, 45];
      levels.forEach(level => {
        const levelTanks = tanksByLevel[level];
        if (levelTanks.length === 0) return;

        const levelHeader = document.createElement('div');
        levelHeader.className = 'kbui-level-header';
        levelHeader.textContent = `Level ${level}`;
        grid.appendChild(levelHeader);

        const levelGrid = document.createElement('div');
        levelGrid.className = 'kbui-tank-grid-level';
        levelGrid.style.gridTemplateColumns = 'repeat(3, minmax(0,1fr))';
        levelGrid.style.gap = '8px';
        levelGrid.style.marginBottom = '12px';

        levelTanks.forEach((tank) => {
          const card = document.createElement('div');
          card.className = 'kbui-tank-card';
          card.dataset.tankId = tank.id;
          card.dataset.tankName = tank.name;

          const icon = document.createElement('div');
          icon.className = 'kbui-tank-icon';

          let imgUrl = tank.imageUrl || null;
          if (!imgUrl && TANK_IMAGE_BASE && tank.imageKey) {
            imgUrl = TANK_IMAGE_BASE + tank.imageKey;
          }
          if (imgUrl) {
            icon.style.backgroundImage = `url("${imgUrl}")`;
          } else {
            icon.style.borderRadius = '50%';
            icon.style.border = '3px solid rgba(0,0,0,0.8)';
            icon.style.backgroundImage = '';
            icon.style.backgroundColor = tank.colorHex || TANK_IMAGE_FALLBACK_COLOR;
          }

          const name = document.createElement('div');
          name.className = 'kbui-tank-name';
          name.textContent = tank.shortName || tank.name;

          card.appendChild(icon);
          card.appendChild(name);

          card.addEventListener('click', () => {
            document
              .querySelectorAll('.kbui-tank-card.selected')
              .forEach((el) => el.classList.remove('selected'));
            card.classList.add('selected');
            currentTankId = tank.id;
            currentTankName = tank.name;
            switchView('tank');
            loadBuildsForTank(tank.id, tank.name);
          });

          levelGrid.appendChild(card);
        });

        grid.appendChild(levelGrid);
      });
    }
  
    async function loadAllBuilds() {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;
      list.innerHTML = 'Loading builds...';

      try {
        const params = new URLSearchParams({
          all: 'true',
          sortBy: currentSortBy,
          sortOrder: currentSortOrder
        });
        if (currentSearch) {
          params.append('search', currentSearch);
        }
        const builds = await apiGet(API_ROUTES.buildsAll + '?' + params.toString());
        renderBuildList(builds, null, true);
      } catch (e) {
        list.innerHTML = '';
        const msg = document.createElement('div');
        msg.className = 'kbui-small';
        msg.textContent = 'Failed to load builds. Check console.';
        list.appendChild(msg);
        console.error(e);
      }
    }

    async function loadBuildsForTank(tankId, tankName) {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;
      list.innerHTML = 'Loading builds...';

      try {
        const builds = await apiGet(API_ROUTES.buildsByTank + encodeURIComponent(tankId));
        renderBuildList(builds, tankName, false);
      } catch (e) {
        list.innerHTML = '';
        const msg = document.createElement('div');
        msg.className = 'kbui-small';
        msg.textContent = 'Failed to load builds. Check console.';
        list.appendChild(msg);
        console.error(e);
      }
    }
  
    function renderBuildList(builds, tankName, isGeneral = false) {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;
      list.innerHTML = '';

      if (!isGeneral && tankName) {
        const headerLine = document.createElement('div');
        headerLine.className = 'kbui-small';
        headerLine.textContent = `Tank: ${tankName || 'Unknown'}`;
        list.appendChild(headerLine);
      }

      if (!builds || !builds.length) {
        const msg = document.createElement('div');
        msg.className = 'kbui-small';
        msg.style.marginTop = '6px';
        msg.textContent = isGeneral 
          ? (currentSearch ? 'No builds found matching your search.' : 'No builds yet. Be the first to create one!')
          : 'No builds yet. Be the first to create one!';
        list.appendChild(msg);
        return;
      }

      builds.forEach((build) => {
        const card = document.createElement('div');
        card.className = 'kbui-build-card';

        const header = document.createElement('div');
        header.className = 'kbui-build-header';

        const nameContainer = document.createElement('div');
        nameContainer.style.display = 'flex';
        nameContainer.style.flexDirection = 'column';
        nameContainer.style.gap = '2px';

        const name = document.createElement('div');
        name.className = 'kbui-build-name';
        name.textContent = build.name || 'Unnamed Build';

        if (isGeneral && build.tankName) {
          const tankLabel = document.createElement('div');
          tankLabel.className = 'kbui-small';
          tankLabel.style.opacity = '0.7';
          tankLabel.textContent = `Tank: ${build.tankName}`;
          nameContainer.appendChild(name);
          nameContainer.appendChild(tankLabel);
        } else {
          nameContainer.appendChild(name);
        }

        const ratingBox = document.createElement('div');
        ratingBox.className = 'kbui-rating';
        ratingBox.style.display = 'flex';
        ratingBox.style.flexDirection = 'column';
        ratingBox.style.alignItems = 'flex-end';
        ratingBox.style.gap = '2px';

        const ratingValue = document.createElement('span');
        ratingValue.textContent = `Score: ${build.rating ?? 0}`;

        const voteCounts = document.createElement('div');
        voteCounts.className = 'kbui-small';
        voteCounts.style.opacity = '0.7';
        voteCounts.style.fontSize = '11px';
        voteCounts.textContent = `▲${build.upvotes || 0} ▼${build.downvotes || 0}`;

        const voteButtons = document.createElement('div');
        voteButtons.style.display = 'flex';
        voteButtons.style.gap = '4px';
        const upBtn = document.createElement('button');
        upBtn.textContent = '▲';
        upBtn.setAttribute('data-build-id', build.id);
        const downBtn = document.createElement('button');
        downBtn.textContent = '▼';
        downBtn.setAttribute('data-build-id', build.id);

        upBtn.addEventListener('click', () => voteBuild(build.id, +1, ratingValue, voteCounts, build));
        downBtn.addEventListener('click', () => voteBuild(build.id, -1, ratingValue, voteCounts, build));

        voteButtons.appendChild(upBtn);
        voteButtons.appendChild(downBtn);

        ratingBox.appendChild(ratingValue);
        ratingBox.appendChild(voteCounts);
        ratingBox.appendChild(voteButtons);

        header.appendChild(nameContainer);
        header.appendChild(ratingBox);
  
        const stats = build.stats || {};
        const statGrid = document.createElement('div');
        statGrid.className = 'kbui-stat-grid';
  
        const statColors = {
          healthRegen: '#e8b08a',
          maxHealth: '#e666ea',
          bodyDamage: '#9466ea',
          bulletSpeed: '#638ce4',
          bulletPenetration: '#ead366',
          bulletDamage: '#ea6666',
          reload: '#92ea66',
          movementSpeed: '#66eae6'
        };

        const statDefs = [
          ['Health Regen', 'healthRegen'],
          ['Max Health', 'maxHealth'],
          ['Body Damage', 'bodyDamage'],
          ['Bullet Speed', 'bulletSpeed'],
          ['Bullet Penetration', 'bulletPenetration'],
          ['Bullet Damage', 'bulletDamage'],
          ['Reload', 'reload'],
          ['Movement Speed', 'movementSpeed']
        ];
  
        statDefs.forEach(([label, key]) => {
          const wrap = document.createElement('div');
          const l = document.createElement('div');
          l.className = 'kbui-stat-label';
          l.textContent = label;
          const v = document.createElement('div');
          v.className = 'kbui-stat-value';
          v.textContent = stats[key] ?? '-';
          if (stats[key] !== null && stats[key] !== undefined) {
            v.style.color = statColors[key] || '#e5e7eb';
          }
          wrap.appendChild(l);
          wrap.appendChild(v);
          statGrid.appendChild(wrap);
        });

        const slashStatsContainer = document.createElement('div');
        slashStatsContainer.style.display = 'flex';
        slashStatsContainer.style.alignItems = 'center';
        slashStatsContainer.style.gap = '10px';
        slashStatsContainer.style.marginTop = '8px';

        const keysInOrder = [
          'healthRegen',
          'maxHealth',
          'bodyDamage',
          'bulletSpeed',
          'bulletPenetration',
          'bulletDamage',
          'reload',
          'movementSpeed'
        ];
        const slashValues = keysInOrder.map(key => stats[key] ?? 0);
        const slashValuesString = slashValues.join('/');

        const slashStats = document.createElement('div');
        slashStats.className = 'kbui-slash-stats';
        slashStats.style.display = 'flex';
        slashStats.style.alignItems = 'center';
        slashStats.style.justifyContent = 'center';
        slashStats.style.gap = '2px';
        slashStats.style.cursor = 'text';
        slashStats.style.userSelect = 'all';
        slashStats.title = 'Click to select and copy';

        slashValues.forEach((value, index) => {
          const span = document.createElement('span');
          span.textContent = value;
          span.style.color = statColors[keysInOrder[index]] || '#facc15';
          span.style.fontWeight = '600';
          slashStats.appendChild(span);
          
          if (index < slashValues.length - 1) {
            const slash = document.createElement('span');
            slash.textContent = '/';
            slash.style.color = '#facc15';
            slashStats.appendChild(slash);
          }
        });

        const copyBtn = document.createElement('button');
        copyBtn.className = 'kbui-button-main';
        copyBtn.textContent = 'Copy';
        copyBtn.style.padding = '4px 10px';
        copyBtn.style.fontSize = '11px';
        copyBtn.style.cursor = 'pointer';
        copyBtn.addEventListener('click', async () => {
          const success = await copyToClipboard(slashValuesString);
          if (success) {
            showToast('Copied to clipboard!');
            copyBtn.textContent = 'Copied!';
            setTimeout(() => {
              copyBtn.textContent = 'Copy';
            }, 2000);
          } else {
            showToast('Failed to copy');
          }
        });

        slashStatsContainer.appendChild(slashStats);
        slashStatsContainer.appendChild(copyBtn);

        const footer = document.createElement('div');
        footer.className = 'kbui-build-footer';
  
        function formatScore(score) {
          if (!score || score === null) return '-';
          if (score >= 1000000) {
            return (score / 1000000).toFixed(1).replace(/\.0$/, '') + 'm';
          } else if (score >= 1000) {
            return (score / 1000).toFixed(0) + 'K';
          }
          return score.toString();
        }

        const best = document.createElement('div');
        best.className = 'kbui-pill';
        const scoreText = build.bestScoreFormatted || formatScore(build.bestScore);
        const usernameText = build.bestUsername ? ` by ${build.bestUsername}` : '';
        best.textContent = `Best: ${scoreText}${usernameText}${build.bestLevel ? ` (LVL ${build.bestLevel})` : ''}${build.bestTime ? `, ${build.bestTime}` : ''}`;
  
        const highscoreBtn = document.createElement('button');
        highscoreBtn.className = 'kbui-button-main';
        highscoreBtn.textContent = 'Submit Highscore';
        highscoreBtn.style.padding = '2px 8px';
        highscoreBtn.style.fontSize = '12px';
        highscoreBtn.addEventListener('click', () => openHighscoreForm(build));
  
        footer.appendChild(best);
        footer.appendChild(highscoreBtn);
  
        card.appendChild(header);
        card.appendChild(statGrid);
        card.appendChild(slashStatsContainer);
        card.appendChild(footer);
  
        list.appendChild(card);
      });
    }
  
    async function voteBuild(buildId, value, ratingLabelEl, voteCountsEl, build) {
      const buttons = document.querySelectorAll(`[data-build-id="${buildId}"] button`);
      buttons.forEach(btn => btn.disabled = true);

      try {
        const res = await apiPost(API_ROUTES.voteBuild(buildId), { value });
        if (ratingLabelEl && res && typeof res.newRating === 'number') {
          ratingLabelEl.textContent = `Score: ${res.newRating}`;
        }
        if (voteCountsEl && build) {
          if (res && res.alreadyVoted) {
          }
        }
        if (res && res.alreadyVoted) {
          showToast('Vote changed');
        } else {
          showToast('Vote submitted');
        }
        if (currentView === 'general') {
          loadAllBuilds();
        } else if (currentTankId) {
          loadBuildsForTank(currentTankId, currentTankName);
        }
      } catch (e) {
        const errorMsg = e.message || 'Vote failed';
        if (errorMsg.includes('already voted')) {
          showToast('You already voted on this build');
        } else {
          showToast('Vote failed: ' + errorMsg);
        }
        console.error(e);
      } finally {
        buttons.forEach(btn => btn.disabled = false);
      }
    }
  
    function openCreateBuildForm() {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;
  
      list.innerHTML = '';
  
      const form = document.createElement('div');
      form.className = 'kbui-form';
  
      const title = document.createElement('div');
      title.className = 'kbui-section-title';
      title.textContent = 'Create Build';
  
      const info = document.createElement('div');
      info.className = 'kbui-small';
      info.textContent = 'Choose how to enter stats: separate fields or "0/0/0/0/0/0/0/0".';
  
      const nameRow = document.createElement('div');
      nameRow.className = 'kbui-form-row';
  
      const tankGroup = document.createElement('div');
      tankGroup.className = 'kbui-form-group';
      const tankLabel = document.createElement('label');
      tankLabel.textContent = 'Tank *';
      const tankSelect = document.createElement('select');
      tankSelect.id = 'kbui-tank-select';
      tankSelect.required = true;
      
      loadTanks().then(tanks => {
        if (!tanks || !tanks.length) {
          const option = document.createElement('option');
          option.value = '';
          option.textContent = 'No tanks available';
          tankSelect.appendChild(option);
          return;
        }

        const sortedTanks = [...tanks].sort((a, b) => {
          const levelA = a.level || a.sortOrder || 999;
          const levelB = b.level || b.sortOrder || 999;
          if (levelA !== levelB) return levelA - levelB;
          return (a.name || '').localeCompare(b.name || '');
        });

        const defaultOption = document.createElement('option');
        defaultOption.value = '';
        defaultOption.textContent = '-- Select Tank --';
        if (!currentTankId) {
          defaultOption.selected = true;
        }
        tankSelect.appendChild(defaultOption);

        const levels = [1, 15, 30, 45];
        const processedTankIds = new Set();
        
        levels.forEach(level => {
          const levelTanks = sortedTanks.filter(t => {
            const tankLevel = t.level || t.sortOrder || 0;
            return tankLevel === level;
          });
          if (levelTanks.length === 0) return;

          const optgroup = document.createElement('optgroup');
          optgroup.label = `Level ${level}`;
          
          levelTanks.forEach(tank => {
            processedTankIds.add(tank.id);
            const option = document.createElement('option');
            option.value = tank.id;
            option.textContent = tank.name;
            if (currentTankId && tank.id === currentTankId) {
              option.selected = true;
            }
            optgroup.appendChild(option);
          });
          
          tankSelect.appendChild(optgroup);
        });

        const otherTanks = sortedTanks.filter(t => !processedTankIds.has(t.id));
        if (otherTanks.length > 0) {
          const optgroup = document.createElement('optgroup');
          optgroup.label = 'Other';
          
          otherTanks.forEach(tank => {
            const option = document.createElement('option');
            option.value = tank.id;
            option.textContent = tank.name;
            if (currentTankId && tank.id === currentTankId) {
              option.selected = true;
            }
            optgroup.appendChild(option);
          });
          
          tankSelect.appendChild(optgroup);
        }
      }).catch(err => {
        console.error('Failed to load tanks:', err);
        const option = document.createElement('option');
        option.value = '';
        option.textContent = 'Error loading tanks';
        tankSelect.appendChild(option);
      });

      tankGroup.appendChild(tankLabel);
      tankGroup.appendChild(tankSelect);
  
      const nameGroup = document.createElement('div');
      nameGroup.className = 'kbui-form-group';
      const nameLabel = document.createElement('label');
      nameLabel.textContent = 'Build Name';
      const nameInput = document.createElement('input');
      nameInput.type = 'text';
      nameInput.placeholder = 'My sniper build';
      nameGroup.appendChild(nameLabel);
      nameGroup.appendChild(nameInput);
  
      nameRow.appendChild(tankGroup);
      nameRow.appendChild(nameGroup);
  
      let inputMode = 'fields';
  
      const modeRow = document.createElement('div');
      modeRow.className = 'kbui-form-row';
      const modeGroup = document.createElement('div');
      modeGroup.className = 'kbui-form-group';
      const modeLabel = document.createElement('label');
      modeLabel.textContent = 'Stats input mode';
  
      const modeOptions = document.createElement('div');
      modeOptions.style.display = 'flex';
      modeOptions.style.gap = '8px';
      modeOptions.style.alignItems = 'center';
  
      const fieldsRadio = document.createElement('input');
      fieldsRadio.type = 'radio';
      fieldsRadio.name = 'kbui-stat-mode';
      fieldsRadio.checked = true;
      const fieldsLabel = document.createElement('span');
      fieldsLabel.textContent = 'Fields';
  
      const slashRadio = document.createElement('input');
      slashRadio.type = 'radio';
      slashRadio.name = 'kbui-stat-mode';
      const slashLabel = document.createElement('span');
      slashLabel.textContent = 'Slash "0/0/0/0/0/0/0/0"';
  
      modeOptions.appendChild(fieldsRadio);
      modeOptions.appendChild(fieldsLabel);
      modeOptions.appendChild(slashRadio);
      modeOptions.appendChild(slashLabel);
  
      modeGroup.appendChild(modeLabel);
      modeGroup.appendChild(modeOptions);
      modeRow.appendChild(modeGroup);
  
      const statsFieldRows = [];
  
      function makeStatRow(labels) {
        const row = document.createElement('div');
        row.className = 'kbui-form-row';
        labels.forEach(([label, key]) => {
          const g = document.createElement('div');
          g.className = 'kbui-form-group';
          const l = document.createElement('label');
          l.textContent = label;
          const inp = document.createElement('input');
          inp.type = 'number';
          inp.min = '0';
          inp.max = '7';
          inp.step = '1';
          inp.dataset.statKey = key;
          g.appendChild(l);
          g.appendChild(inp);
          row.appendChild(g);
        });
        return row;
      }
  
      statsFieldRows.push(
        makeStatRow([
          ['Health Regen', 'healthRegen'],
          ['Max Health', 'maxHealth']
        ]),
        makeStatRow([
          ['Body Damage', 'bodyDamage'],
          ['Bullet Speed', 'bulletSpeed']
        ]),
        makeStatRow([
          ['Bullet Penetration', 'bulletPenetration'],
          ['Bullet Damage', 'bulletDamage']
        ]),
        makeStatRow([
          ['Reload', 'reload'],
          ['Movement Speed', 'movementSpeed']
        ])
      );
  
      const statsFieldsWrapper = document.createElement('div');
      statsFieldRows.forEach(r => statsFieldsWrapper.appendChild(r));
  
      const statsSlashWrapper = document.createElement('div');
      statsSlashWrapper.style.display = 'none';
      statsSlashWrapper.className = 'kbui-form-group';
      const slashInfo = document.createElement('label');
      slashInfo.textContent = 'Stats (HR/HP/BD/BS/BP/BDmg/RL/MS) - Use /, space, comma, ; or |';
      const slashInput = document.createElement('input');
      slashInput.type = 'text';
      slashInput.placeholder = '0/0/0/0/0/0/0/0 or 0 0 0 0 0 0 0 0';
      statsSlashWrapper.appendChild(slashInfo);
      statsSlashWrapper.appendChild(slashInput);
  
      fieldsRadio.addEventListener('change', () => {
        if (fieldsRadio.checked) {
          inputMode = 'fields';
          statsFieldsWrapper.style.display = '';
          statsSlashWrapper.style.display = 'none';
        }
      });
      slashRadio.addEventListener('change', () => {
        if (slashRadio.checked) {
          inputMode = 'string';
          statsFieldsWrapper.style.display = 'none';
          statsSlashWrapper.style.display = '';
        }
      });
  
      const footer = document.createElement('div');
      footer.className = 'kbui-form-footer';
  
      const hint = document.createElement('div');
      hint.className = 'kbui-small';
      hint.textContent = 'Stats 0–7. You can set highscores later via "Submit Highscore".';
  
      const saveBtn = document.createElement('button');
      saveBtn.className = 'kbui-button-main';
      saveBtn.textContent = 'Save Build';
  
      saveBtn.addEventListener('click', async () => {
        const name = nameInput.value.trim() || 'Unnamed Build';
        const selectedTankId = tankSelect.value ? parseInt(tankSelect.value, 10) : null;
        
        if (!selectedTankId || !Number.isFinite(selectedTankId)) {
          showToast('Please select a tank');
          return;
        }

        const stats = {};
  
        const keysInOrder = [
          'healthRegen',
          'maxHealth',
          'bodyDamage',
          'bulletSpeed',
          'bulletPenetration',
          'bulletDamage',
          'reload',
          'movementSpeed'
        ];
  
        if (inputMode === 'fields') {
          form.querySelectorAll('input[data-stat-key]').forEach((inp) => {
            const key = inp.dataset.statKey;
            const v = inp.value.trim();
            stats[key] = v === '' ? null : Number(v);
          });
        } else {
          const raw = slashInput.value.trim();
          if (!raw) {
            showToast('Please enter stats like "0/0/0/0/0/0/0/0" or "0 0 0 0 0 0 0 0" or "0,0,0,0,0,0,0,0"');
            return;
          }
          
          let parts = raw.split('/');
          if (parts.length !== 8) {
            parts = raw.split(/\s+/);
          }
          if (parts.length !== 8) {
            parts = raw.split(',');
          }
          if (parts.length !== 8) {
            parts = raw.split(';');
          }
          if (parts.length !== 8) {
            parts = raw.split('|');
          }
          
          if (parts.length !== 8) {
            showToast('Exactly 8 values required. Use /, space, comma, semicolon, or | as separator');
            return;
          }
          
          for (let i = 0; i < 8; i++) {
            const num = Number(parts[i].trim());
            if (!Number.isFinite(num) || num < 0 || num > 7) {
              showToast('Stats must be numbers 0–7');
              return;
            }
            stats[keysInOrder[i]] = num;
          }
        }

        const totalStats = Object.values(stats).reduce((sum, val) => sum + (val || 0), 0);
        if (totalStats > 33) {
          showToast(`Total stats (${totalStats}) exceeds maximum of 33. Max: 4×7 + 1×5 = 33`);
          return;
        }

        const payload = {
          tankId: selectedTankId,
          name,
          stats
        };
  
        try {
          await apiPost(API_ROUTES.createBuild, payload);
          showToast('Build saved');
          if (currentView === 'tank' && currentTankId) {
            loadBuildsForTank(currentTankId, currentTankName);
          } else if (currentView === 'general') {
            loadAllBuilds();
          }
        } catch (e) {
          let errorMessage = 'Saving failed';
          try {
            if (e.data) {
              const errorData = e.data;
              if (errorData.error === 'DUPLICATE_BUILD' || errorData.message) {
                const details = errorData.details || {};
                const statsStr = details.stats || `${stats.healthRegen || 0}/${stats.maxHealth || 0}/${stats.bodyDamage || 0}/${stats.bulletSpeed || 0}/${stats.bulletPenetration || 0}/${stats.bulletDamage || 0}/${stats.reload || 0}/${stats.movementSpeed || 0}`;
                errorMessage = `${errorData.message || 'A build with identical stats already exists for this tank.'}\n\nTank: ${details.tankName || 'Unknown'}\nExisting Build: "${details.buildName || 'Unknown'}"\nStats: ${statsStr}`;
              } else {
                errorMessage = errorData.error || errorData.message || e.message || 'Unknown error';
              }
            } else {
              const errorText = e.message || '';
              if (errorText.includes('identical stats already exists') || errorText.includes('DUPLICATE_BUILD')) {
                const statsString = `${stats.healthRegen || 0}/${stats.maxHealth || 0}/${stats.bodyDamage || 0}/${stats.bulletSpeed || 0}/${stats.bulletPenetration || 0}/${stats.bulletDamage || 0}/${stats.reload || 0}/${stats.movementSpeed || 0}`;
                errorMessage = `A build with identical stats already exists for this tank.\n\nStats: ${statsString}`;
              } else {
                errorMessage = errorText || 'Unknown error';
              }
            }
          } catch (parseError) {
            errorMessage = e.message || 'Unknown error';
          }
          
          showToast(errorMessage);
          console.error('[KBUI] Build save error:', e);
        }
      });
  
      footer.appendChild(hint);
      footer.appendChild(saveBtn);
  
      form.appendChild(title);
      form.appendChild(info);
      form.appendChild(nameRow);
      form.appendChild(modeRow);
      form.appendChild(statsFieldsWrapper);
      form.appendChild(statsSlashWrapper);
      form.appendChild(footer);
  
      list.appendChild(form);
    }
  
    function openSettings() {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;

      list.innerHTML = '';

      const form = document.createElement('div');
      form.className = 'kbui-form';

      const title = document.createElement('div');
      title.className = 'kbui-section-title';
      title.textContent = 'Settings - Special Options';

      const info = document.createElement('div');
      info.className = 'kbui-small';
      info.style.marginTop = '16px';
      info.style.opacity = '0.7';
      info.textContent = 'No special options available at the moment.';

      const footer = document.createElement('div');
      footer.className = 'kbui-form-footer';
      footer.style.marginTop = '20px';

      const backBtn = document.createElement('button');
      backBtn.className = 'kbui-button-main';
      backBtn.textContent = 'Back';
      backBtn.addEventListener('click', () => {
        if (currentView === 'general') {
          loadAllBuilds();
        } else if (currentTankId) {
          loadBuildsForTank(currentTankId, currentTankName);
        }
      });

      footer.appendChild(backBtn);

      form.appendChild(title);
      form.appendChild(info);
      form.appendChild(footer);

      list.appendChild(form);
    }

    function openHighscoreForm(build) {
      const list = document.getElementById('kbui-build-list');
      if (!list) return;

      list.innerHTML = '';

      const form = document.createElement('div');
      form.className = 'kbui-form';

      const title = document.createElement('div');
      title.className = 'kbui-section-title';
      title.textContent = `Submit Highscore for "${build.name || 'Build'}"`;

      const info = document.createElement('div');
      info.className = 'kbui-small';
      info.textContent = 'Upload a screenshot showing your score, level, time, and the build. Admin will verify and approve.';

      const row1 = document.createElement('div');
      row1.className = 'kbui-form-row';

      const usernameGroup = document.createElement('div');
      usernameGroup.className = 'kbui-form-group';
      const usernameLabel = document.createElement('label');
      usernameLabel.textContent = 'Username *';
      const usernameInput = document.createElement('input');
      usernameInput.type = 'text';
      usernameInput.placeholder = 'Your username';
      usernameInput.maxLength = 50;
      usernameGroup.appendChild(usernameLabel);
      usernameGroup.appendChild(usernameInput);

      row1.appendChild(usernameGroup);

      const row2 = document.createElement('div');
      row2.className = 'kbui-form-row';

      const imageGroup = document.createElement('div');
      imageGroup.className = 'kbui-form-group';
      imageGroup.style.flex = '1';
      const imageLabel = document.createElement('label');
      imageLabel.textContent = 'Screenshot (Proof) *';
      const imageInput = document.createElement('input');
      imageInput.type = 'file';
      imageInput.accept = 'image/jpeg,image/jpg,image/png,image/gif,image/webp';
      imageInput.style.width = '100%';
      imageInput.style.padding = '4px';
      imageGroup.appendChild(imageLabel);
      imageGroup.appendChild(imageInput);

      row2.appendChild(imageGroup);

      const footer = document.createElement('div');
      footer.className = 'kbui-form-footer';

      const hint = document.createElement('div');
      hint.className = 'kbui-small';
      hint.textContent = 'Screenshot must show: Score, Level, Time, and the Build. Max 10MB.';

      const submitBtn = document.createElement('button');
      submitBtn.className = 'kbui-button-main';
      submitBtn.textContent = 'Submit Highscore';

      submitBtn.addEventListener('click', async () => {
        const username = usernameInput.value.trim();
        const imageFile = imageInput.files[0];

        if (!username) {
          showToast('Username is required');
          return;
        }

        if (!imageFile) {
          showToast('Screenshot is required');
          return;
        }

        if (imageFile.size > 10 * 1024 * 1024) {
          showToast('Image must be smaller than 10MB');
          return;
        }

        const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
        if (!allowedTypes.includes(imageFile.type)) {
          showToast('Only image files are allowed (jpeg, jpg, png, gif, webp)');
          return;
        }

        try {
          submitBtn.disabled = true;
          submitBtn.textContent = 'Uploading...';

          const formData = new FormData();
          formData.append('image', imageFile);
          formData.append('username', username);

          await apiPostFormData(API_ROUTES.submitHighscore(build.id), formData);
          showToast('Highscore submitted! Waiting for admin approval.');
          if (currentTankId) {
            loadBuildsForTank(currentTankId, currentTankName);
          }
        } catch (e) {
          showToast('Submit failed: ' + (e.message || 'Unknown error'));
          console.error(e);
        } finally {
          submitBtn.disabled = false;
          submitBtn.textContent = 'Submit Highscore';
        }
      });

      footer.appendChild(hint);
      footer.appendChild(submitBtn);

      form.appendChild(title);
      form.appendChild(info);
      form.appendChild(row1);
      form.appendChild(row2);
      form.appendChild(footer);

      list.appendChild(form);
    }
  
    function init() {
      injectStyles();
      createUIRoot();

      currentSettings = loadSettings();

      loadTanks().then(renderTankGrid).catch((e) => console.error(e));
  
      injectMenuBuildButton();
      const mo = new MutationObserver(() => injectMenuBuildButton());
      mo.observe(document.body, { childList: true, subtree: true });
    }
  
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', init);
    } else {
      init();
    }
  })();