Twitch Pokemon Community Game Helper - NO TIMER

Twitch PokéBall Drag and Drop to chat! !pokecatch <balltype> Pokemoncommunitygame Timer and Spawn Helper. Pokemon stats and more!

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Twitch Pokemon Community Game Helper - NO TIMER
// @namespace    http://tampermonkey.net/
// @version      19
// @description  Twitch PokéBall Drag and Drop to chat! !pokecatch <balltype> Pokemoncommunitygame Timer and Spawn Helper. Pokemon stats and more!
// @match        https://www.twitch.tv/*
// @icon         https://static.twitchcdn.net/assets/favicon-32-e29e246c157142c94346.png
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    class PokeballHelper {
        constructor() {
            this.catchBalls = {
                dollars: { command: '$', tooltip: 'Poke Dollars', image: 'https://i.postimg.cc/T20dR1qH/f547e065261b657c49d5702826b0deca.png', quantity: 0 },
                check: { command: '!pokecheck', tooltip: 'Poke Check', image: 'https://i.postimg.cc/0N7vhyyn/ea9752334aa08543e2f148c0a903719e.png', quantity: 0 },
                poke: { command: '!pokecatch', tooltip: 'Poke Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/poke_ball.png', quantity: 0 },
                great: { command: '!pokecatch greatball', tooltip: 'Great Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/great_ball.png', quantity: 0 },
                ultra: { command: '!pokecatch ultraball', tooltip: 'Ultra Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/ultra_ball.png', quantity: 0 },
                premier: { command: '!pokecatch premierball', tooltip: 'Premier Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/premier_ball.png', quantity: 0 },
                basic: { command: '!pokecatch basicball', tooltip: 'Basic Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/basic_ball.png', quantity: 0 },
                heavy: { command: '!pokecatch heavyball', tooltip: 'Heavy Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/heavy_ball.png', quantity: 0 },
                feather: { command: '!pokecatch featherball', tooltip: 'Feather Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/feather_ball.png', quantity: 0 },
                timer: { command: '!pokecatch timerball', tooltip: 'Timer Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/timer_ball.png', quantity: 0 },
                quick: { command: '!pokecatch quickball', tooltip: 'Quick Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/quick_ball.png', quantity: 0 },
                nest: { command: '!pokecatch nestball', tooltip: 'Nest Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/nest_ball.png', quantity: 0 },
                fast: { command: '!pokecatch fastball', tooltip: 'Fast Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/fast_ball.png', quantity: 0 },
                heal: { command: '!pokecatch healball', tooltip: 'Heal Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/heal_ball.png', quantity: 0 },
                repeat: { command: '!pokecatch repeatball', tooltip: 'Repeat Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/repeat_ball.png', quantity: 0 },
                friend: { command: '!pokecatch friendball', tooltip: 'Friend Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/friend_ball.png', quantity: 0 },
                frozen: { command: '!pokecatch frozenball', tooltip: 'Frozen Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/frozen_ball.png', quantity: 0 },
                night: { command: '!pokecatch nightball', tooltip: 'Night Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/night_ball.png', quantity: 0 },
                phantom: { command: '!pokecatch phantomball', tooltip: 'Phantom Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/phantom_ball.png', quantity: 0 },
                cipher: { command: '!pokecatch cipherball', tooltip: 'Cipher Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/cipher_ball.png', quantity: 0 },
                magnet: { command: '!pokecatch magnetball', tooltip: 'Magnet Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/magnet_ball.png', quantity: 0 },
                net: { command: '!pokecatch netball', tooltip: 'Net Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/net_ball.png', quantity: 0 },
                luxury: { command: '!pokecatch luxuryball', tooltip: 'Luxury Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/luxury_ball.png', quantity: 0 },
                stone: { command: '!pokecatch stoneball', tooltip: 'Stone Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/stone_ball.png', quantity: 0 },
                level: { command: '!pokecatch levelball', tooltip: 'Level Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/level_ball.png', quantity: 0 },
                clone: { command: '!pokecatch cloneball', tooltip: 'Clone Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/clone_ball.png', quantity: 0 },
                sun: { command: '!pokecatch sunball', tooltip: 'Sun Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/sun_ball.png', quantity: 0 },
                fantasy: { command: '!pokecatch fantasyball', tooltip: 'Fantasy Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/fantasy_ball.png', quantity: 0 },
                mach: { command: '!pokecatch machball', tooltip: 'Mach Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/mach_ball.png', quantity: 0 },
                geo: { command: '!pokecatch geoball', tooltip: 'Geo Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/geo_ball.png', quantity: 0 },
                dive: { command: '!pokecatch diveball', tooltip: 'Dive Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/dive_ball.png', quantity: 0 },
                master: { command: '!pokecatch masterball', tooltip: 'Master Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/master_ball.png', quantity: 0 },
                cherish: { command: '!pokecatch cherishball', tooltip: 'Cherish Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/cherish_ball.png', quantity: 0 },
                greatCherish: { command: '!pokecatch greatcherishball', tooltip: 'Great Cherish', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/great_cherish_ball.png', quantity: 0 },
                ultraCherish: { command: '!pokecatch ultracherishball', tooltip: 'Ultra Cherish', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/ultra_cherish_ball.png', quantity: 0 }
            };

            this.shopBalls = {
                pokeball: { command: '!pokeshop pokeball', tooltip: 'Poke Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/poke_ball.png' },
                great: { command: '!pokeshop greatball', tooltip: 'Great Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/great_ball.png' },
                ultra: { command: '!pokeshop ultraball', tooltip: 'Ultra Ball', image: 'https://poketwitch.bframework.de/static/twitchextension/items/ball/ultra_ball.png' },
                gift: { command: '!pokegift', tooltip: 'Poke Gift', image: 'https://i.postimg.cc/CxNNP2Zz/Pngtree-gift-box-3d-illustration-6508903.png' },
                v5: { command: ' 5', tooltip: '5', image: 'https://i.postimg.cc/wM8LT5tC/pngaaa-com-3588470.png' },
                v10: { command: ' 10', tooltip: '10', image: 'https://i.postimg.cc/NjJXrv97/pngaaa-com-2133853.png' },
                v25: { command: ' 25', tooltip: '25', image: 'https://i.postimg.cc/wTFySYV8/pngaaa-com-1433934.png' },
                v50: { command: ' 50', tooltip: '50', image: 'https://i.postimg.cc/bNqSCw19/pngaaa-com-973335.png' }
            };
this.currentTab = 'catch';
this.allPokemonList = null;
this.isDragging = false;
this.startX = 0;
this.startY = 0;
this.containerStartLeft = 0;
this.containerStartTop = 0;
this.wasDragging = false;

// Bind drag methods.
this.dragStart = this.dragStart.bind(this);
this.drag = this.drag.bind(this);
this.dragEnd = this.dragEnd.bind(this);

// Initialize UI and observers.
this.init();
this.gridContainer = document.getElementById('grid-container');
this.tooltip = null;
this.initIntersectionObserver();
this.initInventoryObserver();
}

initIntersectionObserver() {
    const lazyImages = document.querySelectorAll('img.lazy');
    const observer = new IntersectionObserver((entries, obs) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                img.addEventListener('load', () => {
                    img.classList.add('fade-in', 'visible');
                });
                obs.unobserve(img);
            }
        });
    });
    lazyImages.forEach(img => observer.observe(img));
}

init() {
    this.setupStyles();
    this.waitForChat().then(() => {
        this.createInterface();
        // Removed timer element creation.
        this.addEventListeners();
        this.renderGrid();
        this.initSearchButtons();
        this.imageUpdateStarted = false;
        // Removed spawn timer update.
        this.updateInventoryFromDOM();
    });
}

handleSearch(query) {
    switch (this.currentTab) {
        case 'advanced':
            this.searchAdvancedPokemon(query);
            break;
        case 'browse':
            this.renderBrowseGrid();
            break;
        default:
            this.filterGrid();
    }
}

initSearchButtons() {
    document.querySelectorAll('.pball-search-container').forEach(container => {
        const input = container.querySelector('.pball-search');
        if (!input || container.dataset.initialized) return;

        const btnContainer = document.createElement('div');
        btnContainer.className = 'search-buttons';

        const enterButton = Object.assign(document.createElement('button'), {
            className: 'search-enter-button',
            innerHTML: '✔',
            title: 'Search (Enter)',
            onclick: () => this.handleSearch(input.value.trim())
        });

        const clearButton = Object.assign(document.createElement('button'), {
            className: 'pball-clear-btn',
            innerHTML: '×',
            title: 'Clear search',
            style: 'display: none;',
            onclick: () => {
                input.value = '';
                input.focus();
                this.handleSearch('');
                clearButton.style.display = 'none';
            }
        });

        input.addEventListener('input', () => {
            clearButton.style.display = input.value ? 'flex' : 'none';
        });

        input.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') enterButton.click();
        });

        btnContainer.append(enterButton, clearButton);
        container.append(btnContainer);
        container.dataset.initialized = true;
    });
}

createInterface() {
    let inventoryDisplay = document.getElementById('inventory-display');
    if (!inventoryDisplay) {
        inventoryDisplay = document.createElement('div');
        inventoryDisplay.id = 'inventory-display';
        Object.assign(inventoryDisplay.style, {
            position: 'fixed',
            top: '10px',
            right: '10px',
            backgroundColor: '#fff',
            border: '1px solid #ccc',
            padding: '10px',
            zIndex: '9999'
        });
        document.body.appendChild(inventoryDisplay);
    }
    inventoryDisplay.innerHTML = `
        <h3>Inventory</h3>
        <div id="dollars-display">Poke Dollars: 0</div>
        <ul id="balls-list"></ul>
    `;
}

loadPosition() {
    const savedPos = localStorage.getItem('pballPosition');
    if (savedPos) {
        const { x, y } = JSON.parse(savedPos);
        this.container.style.left = `${x}px`;
        this.container.style.top = `${y}px`;
    }
}

dragStart(e) {
    e.preventDefault();
    this.wasDragging = false;
    const startX = e.clientX;
    const startY = e.clientY;
    const rect = this.container.getBoundingClientRect();
    const origLeft = rect.left;
    const origTop = rect.top;

    const onMouseMove = (moveEvent) => {
        const deltaX = moveEvent.clientX - startX;
        const deltaY = moveEvent.clientY - startY;
        if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
            this.wasDragging = true;
        }
        this.container.style.left = `${origLeft + deltaX}px`;
        this.container.style.top = `${origTop + deltaY}px`;
    };

    const onMouseUp = () => {
        window.removeEventListener('mousemove', onMouseMove);
        window.removeEventListener('mouseup', onMouseUp);
        const ballImg = e.target.closest('.pball-item img');
        if (ballImg) {
            ballImg.style.cursor = 'grab';
        }
    };

    const ballImg = e.target.closest('.pball-item img');
    if (ballImg) {
        ballImg.style.cursor = 'grabbing';
    }

    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('mouseup', onMouseUp);
}

drag(e) {
    this.container.classList.remove('dragging');
    e.preventDefault();
    const dx = e.clientX - this.startX;
    const dy = e.clientY - this.startY;
    if (!this.isDragging && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
        this.isDragging = true;
    }
    if (this.isDragging) {
        let newX = this.containerStartLeft + dx;
        let newY = this.containerStartTop + dy;
        const chatWindow = document.querySelector('.chat-window');
        if (chatWindow) {
            const chatRect = chatWindow.getBoundingClientRect();
            const ballRect = this.container.getBoundingClientRect();
            newX = Math.max(chatRect.left, Math.min(newX, chatRect.right - ballRect.width));
            newY = Math.max(chatRect.top, Math.min(newY, chatRect.bottom - ballRect.height));
        }
        requestAnimationFrame(() => {
            this.container.style.left = `${newX}px`;
            this.container.style.top = `${newY}px`;
        });
    }
}

dragEnd(e) {
    document.removeEventListener('mousemove', this.drag);
    document.removeEventListener('mouseup', this.dragEnd);
    if (this.isDragging) {
        this.wasDragging = true;
        const left = this.container.offsetLeft;
        const top = this.container.offsetTop;
        localStorage.setItem('pballPosition', JSON.stringify({ x: left, y: top }));
    }
    this.container.style.transition = '';
}

setupStyles() {
  const style = document.createElement('style');
  style.textContent = `
  /* ============================================
     Ultra Stunning UI & Theme – Dark Transparent with Soft White Illuminations
     ============================================ */

  /*--------------------------------------------------
    Import Fonts
  --------------------------------------------------*/
  @import url('https://fonts.googleapis.com/css2?family=Segment7Standard&display=swap');
  @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
  @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

  /*--------------------------------------------------
    Global Variables & Base Styles
  --------------------------------------------------*/
  :root {
    --color-primary: rgba(255, 255, 255, 0.8);
    --color-secondary: rgba(255, 255, 255, 0.8);
    --color-accent: rgba(255, 255, 255, 0.6);
    --color-dark: #1c1c1e;
    --color-darker: #141414;
    --color-card: rgba(20, 20, 20, 0.8);
    --color-border: rgba(255, 255, 255, 0.1);
    --color-glass: rgba(255, 255, 255, 0.05);
    --gradient-accent: linear-gradient(90deg, rgba(255,255,255,0.5), rgba(255,255,255,0.2));
    --gradient-bg: radial-gradient(circle at top left, rgba(10,10,10,1), rgba(0,0,0,1));
    --color-text: #fefefe;
    --font-base: 'Roboto', sans-serif;
    --font-led: 'Segment7Standard', monospace;
    --font-label: 'Press Start 2P', cursive;
    --font-size-base: clamp(0.9rem, 1vw + 0.8rem, 1.1rem);
    --border-radius-small: 4px;
    --border-radius-medium: 12px;
    --border-radius-large: 16px;
    --spacing-small: 8px;
    --spacing-medium: 16px;
    --spacing-large: 24px;
    --transition-fast: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    --transition-medium: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    --box-shadow-light: 0 2px 12px rgba(0, 0, 0, 0.4);
    --box-shadow-heavy: 0 4px 20px rgba(0, 0, 0, 0.6);
    --backdrop-blur: blur(10px);
    --neon-glow: drop-shadow(0 0 8px rgba(255,255,255,0.7)) drop-shadow(0 0 8px rgba(255,255,255,0.7));
    --soft-glow: drop-shadow(0 0 10px rgba(255,255,255,0.8));
    --breakpoint-md: 768px;
    --breakpoint-sm: 600px;
  }

  *, *::before, *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: var(--font-base);
    transition: background var(--transition-fast), color var(--transition-fast);
  }

  html {
    scroll-behavior: smooth;
  }

  body {
    background: var(--gradient-bg);
    color: var(--color-text);
    font-size: var(--font-size-base);
    line-height: 1.5;
  }

  /*--------------------------------------------------
    Scrollbar Styles
  --------------------------------------------------*/
  ::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }
  ::-webkit-scrollbar-track {
    background: var(--color-darker);
    border-radius: var(--border-radius-medium);
  }
  ::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: var(--border-radius-medium);
    border: 1px solid var(--color-dark);
  }
  ::-webkit-scrollbar-thumb:hover {
    background: rgba(255,255,255,0.3);
  }
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) var(--color-darker);
  }

  /*--------------------------------------------------
    Main UI Components
  --------------------------------------------------*/
  .pball-container {
    position: fixed;
    bottom: calc(var(--spacing-large) + 50px);
    right: var(--spacing-medium);
    z-index: 10000;
    pointer-events: none;
    transform: scale(1);
    transform-origin: top right;
    width: fit-content;
    height: fit-content;
  }
  .pball-container > * {
    pointer-events: auto;
  }
  .pball-button {
    position: relative;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    cursor: pointer;
    transition: transform var(--transition-fast), filter var(--transition-fast);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .pball-button img {
    width: 48px;
    height: 48px;
    object-fit: contain;
    transition: transform var(--transition-fast), filter var(--transition-fast);
  }
  .pball-button:hover,
  .pball-button:focus-visible {
    transform: scale(1.25) rotate(3deg);
    filter: var(--soft-glow);
    outline: none;
  }
  .pball-button:hover img,
  .pball-button:focus-visible img {
    transform: scale(1.1);
  }

  /*--------------------------------------------------
    Panel & Tab System
  --------------------------------------------------*/
  .pball-panel {
    position: absolute;
    bottom: calc(100% + var(--spacing-small));
    right: 0;
    width: 340px;
    height: 500px;
    min-width: 300px;
    min-height: 300px;
    overflow: auto;
    background: var(--color-card);
    backdrop-filter: var(--backdrop-blur);
    border-radius: var(--border-radius-large);
    border: 1px solid var(--color-border);
    box-shadow: var(--box-shadow-heavy);
    opacity: 0;
    visibility: hidden;
    transform: translateY(var(--spacing-small));
    transition: opacity var(--transition-medium), transform var(--transition-medium), visibility var(--transition-medium);
  }
  .pball-panel.active {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }
  .pball-tabs {
    display: flex;
    background: var(--color-darker);
    border-bottom: 1px solid var(--color-border);
    border-top-left-radius: var(--border-radius-large);
    border-top-right-radius: var(--border-radius-large);
    overflow: hidden;
  }
  .pball-tab {
    position: relative;
    flex: 1;
    padding: var(--spacing-small);
    text-align: center;
    font-size: 15px;
    cursor: pointer;
    color: var(--color-text);
    transition: background var(--transition-fast), color var(--transition-fast);
  }
  .pball-tab.active::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 60%;
    height: 3px;
    background: var(--color-primary);
    box-shadow: 0 0 12px var(--color-primary);
    border-radius: 2px;
    transform: translateX(-50%);
  }

  /*--------------------------------------------------
    Search & Input Components
  --------------------------------------------------*/
  .pball-search-container {
    position: relative;
    margin: var(--spacing-medium);
    background: var(--color-card);
    backdrop-filter: var(--backdrop-blur);
    border-radius: var(--border-radius-medium);
    border: 1px solid var(--color-border);
    overflow: hidden;
  }
  .pball-search {
    width: 100%;
    padding: calc(var(--spacing-small) + 2px) var(--spacing-medium);
    padding-right: 70px;
    border: none;
    background: transparent;
    color: var(--color-text);
    font-size: 15px;
    outline: none;
  }
  .search-buttons {
    position: absolute;
    right: var(--spacing-small);
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: var(--spacing-small);
  }

  /*--------------------------------------------------
    Grid Layouts & Item Cards
  --------------------------------------------------*/
  .pball-grid {
    padding: var(--spacing-medium);
    display: grid;
    gap: var(--spacing-medium);
    max-height: 320px;
    overflow-y: auto;
  }
  .pball-panel.shop .pball-grid,
  .pball-panel.catch-shop .pball-grid {
    grid-template-columns: repeat(3, minmax(80px, 1fr));
    justify-content: center;
  }
  .pball-grid.ball-items {
    grid-template-columns: repeat(auto-fit, minmax(50px, 1fr));
    justify-items: center;
  }

  /*--------------------------------------------------
    Item Cards & Catch Tab Overrides
  --------------------------------------------------*/
  .pball-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 50%;
    padding: var(--spacing-small);
    transition: transform var(--transition-fast);
  }
  .pball-item img {
    width: 40px;
    height: 40px;
    transition: transform var(--transition-fast);
    cursor: grab;
  }
  .pball-item img:hover,
  .pball-item img:focus-visible {
    transform: scale(1.2);
    outline: none;
  }
  .pball-item img:active,
  .pball-item img.grabbing {
    filter: var(--neon-glow);
    animation: neonPulse 0.26s infinite alternate;
  }
  @keyframes neonPulse {
    0% {
      filter: drop-shadow(0 0 8px rgba(255,255,255,0.7)) drop-shadow(0 0 8px rgba(255,255,255,0.7));
    }
    100% {
      filter: drop-shadow(0 0 12px rgba(255,255,255,0.7)) drop-shadow(0 0 12px rgba(255,255,255,0.7));
    }
  }
  .pball-item .pball-label {
    margin-top: var(--spacing-small);
    font-size: 14px;
    color: var(--color-text);
    text-align: center;
  }
  .catch-shop .pball-item {
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
  }
  .catch-shop .pball-item img {
    margin-right: var(--spacing-small);
  }
  .catch-shop .pball-item .pball-label {
    margin-top: 0;
    text-align: left;
  }

  /*--------------------------------------------------
    Pokémon Card Styles - Transparent Version
  --------------------------------------------------*/
  .pokemon-card {
    background: transparent !important;
    border-radius: 12px;
    padding: 10px;
    text-align: center;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    position: relative;
    overflow: hidden;
    cursor: pointer;
  }
  .pokemon-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 6px 16px rgba(255,255,255,0.5);
  }
  .dex-number {
    position: absolute;
    top: 6px;
    left: 8px;
    font-weight: bold;
    background: rgba(0, 0, 0, 0.4);
    padding: 4px 8px;
    border-radius: 8px;
    color: #fff;
  }
  .pokemon-image {
    max-width: 100px;
    max-height: 100px;
    object-fit: contain;
    transition: transform var(--transition-fast);
    background: transparent !important;
  }
  .pokemon-card:hover .pokemon-image,
  .pokemon-card:hover .pball-label,
  .pball-item:hover img {
    filter: drop-shadow(0px 0px 10px rgba(255,255,255,0.8));
    transition: filter var(--transition-fast);
  }

  /*--------------------------------------------------
    Utility Classes
  --------------------------------------------------*/
  .spinner {
    margin: 1.5rem auto;
    border: 4px solid var(--color-border);
    border-top: 4px solid var(--color-primary);
    border-radius: 50%;
    width: 2.8rem;
    height: 2.8rem;
    animation: spin 1s linear infinite;
  }
  .animate-fadeIn {
    opacity: 0;
    transform: translateY(20px);
    animation: fadeInUp 0.5s forwards;
  }

  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  @keyframes fadeInUp {
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /*--------------------------------------------------
    Responsive Adjustments for Auto-Alignment
  --------------------------------------------------*/
  @media (max-width: var(--breakpoint-md)) {
    .pball-panel {
      width: 90%;
      height: auto;
      bottom: var(--spacing-medium);
      right: var(--spacing-medium);
    }
  }
  `;
  document.head.appendChild(style);
}

// -----------------------------
// Helper: Debounce Function
// -----------------------------
debounce(func, wait) {
  let timeout;
  return function(...args) {
    const context = this;
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(context, args), wait);
  };
}

// -----------------------------
// Wait for Chat Input to be Available
// -----------------------------
async waitForChat() {
  return new Promise((resolve) => {
    const chatSelector = '[data-test-selector="chat-input"]';
    if (document.querySelector(chatSelector)) {
      return resolve();
    }
    const observer = new MutationObserver((mutations, obs) => {
      if (document.querySelector(chatSelector)) {
        obs.disconnect();
        resolve();
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });
  });
}

// -----------------------------
// Create Interface Elements
// -----------------------------
createInterface() {
  this.container = document.createElement('div');
  this.container.className = 'pball-container';
  this.button = this.createMainButton();
  this.panel = this.createPanel();
  this.container.append(this.button, this.panel);
  document.body.appendChild(this.container);
}

// -----------------------------
// Create Main Button (Static)
// -----------------------------
createMainButton() {
  const button = document.createElement('div');
  button.className = 'pball-button';

  const icon = document.createElement('img');
  // Use the static pokeball image
  icon.src = this.catchBalls.poke.image;
  icon.style.width = '46px';
  icon.style.height = '46px';
  icon.style.filter = 'drop-shadow(0 2px 4px rgba(0,0,0,0.3))';

  button.appendChild(icon);
  this.buttonIcon = icon;
  return button;
}

// -----------------------------
// Create Panel with Tabs, Search, and Grid
// -----------------------------
createPanel() {
  const panel = document.createElement('div');
  panel.className = 'pball-panel';
  panel.draggable = false;

  const tabsContainer = document.createElement('div');
  tabsContainer.className = 'pball-tabs';

  const createTab = (name, isActive = false) => {
    const tab = document.createElement('div');
    tab.className = `pball-tab${isActive ? ' active' : ''}`;
    tab.textContent = name;
    tab.dataset.tab = name.toLowerCase();
    tab.addEventListener('click', () => {
      this.switchTab(name.toLowerCase());
    });
    return tab;
  };

  tabsContainer.appendChild(createTab('Catch', true));
  tabsContainer.appendChild(createTab('Shop'));
  tabsContainer.appendChild(createTab('Pokemon'));
  tabsContainer.appendChild(createTab('Moves'));
  tabsContainer.appendChild(createTab('Advanced'));

  const searchContainer = document.createElement('div');
  searchContainer.className = 'pball-search-container';

  this.searchInput = document.createElement('input');
  this.searchInput.type = 'text';
  this.searchInput.className = 'pball-search';
  this.searchInput.placeholder = 'Search...';
  this.searchInput.setAttribute('aria-label', 'Search Pokémon');

  this.clearBtn = document.createElement('button');
  this.clearBtn.setAttribute('aria-label', 'Clear Search');

  searchContainer.append(this.searchInput, this.clearBtn);

  this.gridContainer = document.createElement('div');
  this.gridContainer.className = 'pball-grid';

  this.tabContainers = {};
  ['catch', 'shop', 'pokemon', 'moves', 'advanced'].forEach(tabName => {
    const container = document.createElement('div');
    container.className = 'tab-content';
    container.dataset.tab = tabName;
    container.style.display = tabName === 'catch' ? 'block' : 'none';
    this.tabContainers[tabName] = container;
    this.gridContainer.appendChild(container);
  });

  const footer = document.createElement('div');
  Object.assign(footer.style, {
    position: 'absolute',
    bottom: '0',
    left: '0',
    width: '100%',
    padding: '4px 12px',
    borderTop: '1px solid rgba(255,255,255,0.1)',
    fontSize: '15px',
    color: '#666',
    textAlign: 'center'
  });

  const message = document.createTextNode('Like the extension? ');
  const cashTag = document.createElement('span');
  cashTag.textContent = '$yeetsquadcuz';
  Object.assign(cashTag.style, {
    color: '#888',
    fontWeight: '500',
    cursor: 'pointer',
    transition: 'color 0.2s ease',
    display: 'inline-flex',
    alignItems: 'center'
  });
  cashTag.onmouseenter = () => cashTag.style.color = '#aaa';
  cashTag.onmouseleave = () => cashTag.style.color = '#888';

  const cashLogo = document.createElement('img');
  cashLogo.src = 'https://i.postimg.cc/qq9LWcjm/pngegg.png';
  Object.assign(cashLogo.style, {
    width: '14px',
    height: '14px',
    marginLeft: '4px'
  });
  cashTag.appendChild(cashLogo);

  cashTag.addEventListener('click', () => {
    const audio = new Audio('https://www.myinstants.com/media/sounds/yeet.mp3');
    audio.volume = 0.1;
    audio.play();
  });

  footer.appendChild(message);
  footer.appendChild(cashTag);

  panel.append(tabsContainer, searchContainer, this.gridContainer, footer);
  return panel;
}

renderGrid() {
  // Cache control elements if they exist
  const movesControls = document.getElementById('moves-controls');
  const pokemonControls = document.getElementById('pokemon-controls');

  // Only remove controls if needed
  if (movesControls && this.currentTab !== 'moves') {
    movesControls.remove();
  }
  if (pokemonControls && this.currentTab !== 'pokemon') {
    pokemonControls.remove();
  }

  // Clear existing classes to avoid duplication
  this.gridContainer.classList.remove('ball-items', 'search-results');

  if (this.currentTab === 'advanced') {
    this.gridContainer.classList.add('search-results');
    this.renderAdvancedInstruction();
  } else if (this.currentTab === 'pokemon') {
    this.gridContainer.classList.add('search-results');
    this.renderPokemon();
  } else if (this.currentTab === 'moves') {
    this.gridContainer.classList.add('search-results');
    this.renderMoves();
  } else {
    // For "catch" and "shop" tabs
    this.gridContainer.classList.add('ball-items');
    // Clear out the container
    this.gridContainer.innerHTML = '';

    const balls = this.currentTab === 'catch' ? this.catchBalls : this.shopBalls;
    const fragment = document.createDocumentFragment();

    Object.entries(balls).forEach(([key, ball]) => {
      const item = document.createElement('div');
      item.className = 'pball-item';
      item.dataset.label = ball.tooltip.toLowerCase();

      const img = document.createElement('img');
      img.src = ball.image;
      img.dataset.ballType = ball.command;
      img.draggable = true;

      const label = document.createElement('div');
      label.className = 'pball-label';
      label.textContent = ball.tooltip;

      item.append(img, label);
      fragment.appendChild(item);
    });

    this.gridContainer.appendChild(fragment);
    this.filterGrid();
  }
}

renderMoves() {
  // Clear the grid container.
  this.gridContainer.innerHTML = '';
  // Render the custom controls panel above the grid.
  this.renderMovesControls();

  // Try to load from localStorage first.
  const cachedMoves = localStorage.getItem('movesList');
  if (cachedMoves) {
    this.movesList = JSON.parse(cachedMoves);
    this.renderMovesGrid();
  } else if (!this.movesList) {
    this.gridContainer.innerHTML += '<div class="spinner"></div>';
    fetch('https://pokeapi.co/api/v2/move?limit=1000')
      .then(response => response.json())
      .then(data => {
        this.movesList = data.results;
        // Cache the moves list in localStorage.
        localStorage.setItem('movesList', JSON.stringify(data.results));
        this.renderMovesGrid();
      })
      .catch(err => {
        this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">Error loading moves list</div>`;
      });
  } else {
    // Use the already fetched moves list.
    this.renderMovesGrid();
  }
}


renderMovesControls() {
  let controlsContainer = document.getElementById('moves-controls');
  if (!controlsContainer) {
    controlsContainer = document.createElement('div');
    controlsContainer.id = 'moves-controls';
    Object.assign(controlsContainer.style, {
      display: 'flex',
      flexWrap: 'nowrap',
      justifyContent: 'center', // Changed to center
      alignItems: 'center',
      marginBottom: '10px',
      backgroundColor: '#202020',
      color: '#fff',
      padding: '3px',
      borderRadius: '5px',
      gap: '4px',
      overflowX: 'auto',
      width: '100%' // Ensure full width for proper centering
    });
    this.gridContainer.parentNode.insertBefore(controlsContainer, this.gridContainer);
  }
  controlsContainer.innerHTML = '';

  // --- Filter Buttons ---
  const filterOptions = ['All', 'Physical', 'Special', 'Status'];
  const filterGroup = document.createElement('div');
  filterGroup.style.display = 'flex';
  filterGroup.style.gap = '4px';
  filterGroup.style.margin = '0';
  filterOptions.forEach(option => {
    const btn = document.createElement('button');
    btn.textContent = option;
    btn.dataset.filter = option.toLowerCase();
    Object.assign(btn.style, {
      backgroundColor: '#202020',
      color: '#fff',
      border: '1px solid #666',
      borderRadius: '3px',
      padding: '2px 4px',
      cursor: 'pointer',
      fontSize: '10px',
      height: '24px',
      transition: 'background-color 0.2s ease',
      whiteSpace: 'nowrap'
    });
    btn.addEventListener('click', () => {
      Array.from(filterGroup.children).forEach(child => {
        child.style.backgroundColor = '#202020';
      });
      btn.style.backgroundColor = '#444';
      this.selectedDamageFilter = btn.dataset.filter;
      this.renderMovesGrid();
    });
    filterGroup.appendChild(btn);
  });
  controlsContainer.appendChild(filterGroup);

  // --- Sort Dropdown ---
  const sortContainer = document.createElement('div');
  sortContainer.style.display = 'flex';
  sortContainer.style.alignItems= 'center';
  sortContainer.style.gap = '3px';
  const sortLabel = document.createElement('label');
  sortLabel.textContent = 'Sort:';
  Object.assign(sortLabel.style, {
    fontSize: '10px',
    color: '#fff',
    whiteSpace: 'nowrap',
    marginLeft: '8px' // Added spacing between filter buttons and sort
  });
  const sortSelect = document.createElement('select');
  sortSelect.id = 'moves-sort';
  Object.assign(sortSelect.style, {
    backgroundColor: '#202020',
    color: '#fff',
    border: '1px solid #666',
    borderRadius: '3px',
    padding: '2px',
    fontSize: '10px',
    height: '24px',
    cursor: 'pointer',
    minWidth: '72px'
  });
  sortSelect.innerHTML = `
    <option value="name-asc">A–Z</option>
    <option value="name-desc">Z–A</option>
  `;
  sortSelect.addEventListener('change', () => {
    this.renderMovesGrid();
  });
  sortContainer.appendChild(sortLabel);
  sortContainer.appendChild(sortSelect);
  controlsContainer.appendChild(sortContainer);
}

// Render the moves grid using the custom controls (all moves displayed, with search highlighting)
renderMovesGrid() {
  this.gridContainer.innerHTML = '';
  this.gridContainer.classList.add('browse-container');
  const query = this.searchInput.value.trim().toLowerCase();

  // Get the selected damage filter from the buttons (default to 'all' if not set)
  const damageFilter = this.selectedDamageFilter || 'all';
  const sortOption = document.getElementById('moves-sort')?.value || 'name-asc';

  // Filter moves by search query.
  let filtered = this.movesList.filter(move => move.name.includes(query));

  // Further filter by damage class if not set to 'all'
  if (damageFilter !== 'all') {
    filtered = filtered.filter(move => {
      if (this.moveDetailCache && this.moveDetailCache.has(move.url)) {
        const moveData = this.moveDetailCache.get(move.url);
        return moveData.damage_class.name === damageFilter;
      }
      // Include moves without loaded details by default.
      return true;
    });
  }

  // Sort moves alphabetically.
  if (sortOption === 'name-asc') {
    filtered.sort((a, b) => a.name.localeCompare(b.name));
  } else if (sortOption === 'name-desc') {
    filtered.sort((a, b) => b.name.localeCompare(a.name));
  }

  // Build the grid using a document fragment.
  const fragment = document.createDocumentFragment();
  filtered.forEach(move => {
    const tile = document.createElement('div');
    tile.className = 'browse-tile';
    tile.dataset.label = move.name.toLowerCase();

    // Card container for move info.
    const content = document.createElement('div');
    content.className = 'move-card';
    Object.assign(content.style, {
      padding: '12px',
      borderRadius: '12px',
      background: 'var(--background-darker)',
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      cursor: 'pointer',
      transition: 'box-shadow 0.2s ease-in-out, transform 0.2s ease-in-out'
    });

    // Hover glow effect.
    content.addEventListener('mouseenter', () => {
      content.style.boxShadow = '0 0 20px rgba(255, 255, 255, 0.6)';
      content.style.transform = 'scale(1.05)';
    });
    content.addEventListener('mouseleave', () => {
      content.style.boxShadow = '0 0 0px rgba(255, 255, 255)';
      content.style.transform = 'scale(1)';
    });

    // Highlight matching search text in move title.
    let titleText = move.name;
    if (query) {
      const regex = new RegExp(`(${query})`, 'gi');
      titleText = move.name.replace(regex, '<mark>$1</mark>');
    }
    const title = document.createElement('div');
    title.className = 'move-title';
    Object.assign(title.style, {
      fontSize: '28px',
      fontWeight: 'bold',
      marginBottom: '8px',
      color: 'var(--text-glow)',
      textShadow: '0 0 5px rgba(255, 255, 255, 0.8)',
      textAlign: 'center'
    });
    title.innerHTML = titleText;

    // Container for badges.
    const badgeContainer = document.createElement('div');
    badgeContainer.className = 'badge-container';
    Object.assign(badgeContainer.style, {
      display: 'flex',
      gap: '8px'
    });

    content.append(title, badgeContainer);
    tile.appendChild(content);

    // Click event to switch to advanced view.
    tile.addEventListener('click', (e) => {
      e.stopPropagation();
      this.panel.classList.add('active');
      this.changeTab('advanced');
      this.searchInput.value = move.name;
      this.searchAdvancedMove(move.name);
    });

    // Fetch move details for badges using caching.
    if (this.moveDetailCache && this.moveDetailCache.has(move.url)) {
      const moveData = this.moveDetailCache.get(move.url);
      const typeBadge = this.createBadge(moveData.type.name, this.getTypeColor(moveData.type.name));
      const damageColor = moveData.damage_class.name === 'physical' ? '#F08030' :
                          moveData.damage_class.name === 'special' ? '#6890F0' : '#A8A878';
      const damageBadge = this.createBadge(moveData.damage_class.name, damageColor);
      badgeContainer.append(typeBadge, damageBadge);
    } else {
      fetch(move.url)
        .then(response => response.json())
        .then(moveData => {
          if (!this.moveDetailCache) this.moveDetailCache = new Map();
          this.moveDetailCache.set(move.url, moveData);
          const typeBadge = this.createBadge(moveData.type.name, this.getTypeColor(moveData.type.name));
          const damageColor = moveData.damage_class.name === 'physical' ? '#F08030' :
                              moveData.damage_class.name === 'special' ? '#6890F0' : '#A8A878';
          const damageBadge = this.createBadge(moveData.damage_class.name, damageColor);
          badgeContainer.append(typeBadge, damageBadge);
        })
        .catch(err => {
          console.error('Error fetching move details for grid tile:', err);
        });
    }
    fragment.appendChild(tile);
  });
  this.gridContainer.appendChild(fragment);

  if (filtered.length === 0) {
    this.gridContainer.innerHTML = '<div style="padding:12px; color: var(--text-light); text-align: center;">No moves match your search.</div>';
  }
}

// -----------------------------
// Advanced Move Details Section
// -----------------------------
async searchAdvancedMove(moveName) {
  try {
    const normalizedMove = moveName.trim().toLowerCase();
    const response = await fetch(`https://pokeapi.co/api/v2/move/${normalizedMove}`);
    if (!response.ok) throw new Error('Move not found');
    const moveData = await response.json();
    this.displayAdvancedMoveData(moveData);
  } catch (error) {
    console.error("Error fetching move details:", error);
    this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">Error loading move details</div>`;
  }
}

displayAdvancedPokemonData(data, speciesData, evoData) {
  this.gridContainer.innerHTML = '';
  const card = document.createElement('div');
  card.className = 'poke-card animate-fadeIn';
  card.style.maxWidth = '100%';
  card.style.overflowX = 'hidden';
  card.style.display = 'flex';
  card.style.flexDirection = 'column';
  card.style.gap = '16px';

  // Assemble the card sections with animations
  card.append(
    this.createCardHeader(data),
    this.createBasicInfoSection(data),
    this.createStatsRadarChart(data),
    this.createAbilitiesSection(data),
    // Remove old type relations grid
    // Instead, add our new advanced analysis section:
    this.createAdvancedBattleAnalysisTab(data),
    this.createPokedexEntrySection(speciesData),
    this.createEvolutionVisualization(evoData.chain),
    this.createMovesSection(data)
  );

  // Append optional sections
  if (data.held_items && data.held_items.length > 0) {
    card.appendChild(this.createHeldItemsSection(data));
  }
  if (data.forms && data.forms.length > 0) {
    card.appendChild(this.createFormsSection(data));
  }

  this.gridContainer.appendChild(card);
  this.initIntersectionObserver(); // Reinitialize for new lazy images

  // Trigger an animation frame for smoother entrance
  requestAnimationFrame(() => {
    card.classList.add('visible');
  });
}

displayAdvancedMoveData(moveData) {
  this.gridContainer.innerHTML = '';
  const card = document.createElement('div');
  card.className = 'poke-card animate-fadeIn';
  card.style.maxWidth = '100%';
  card.style.overflowX = 'hidden';
  card.style.display = 'flex';
  card.style.flexDirection = 'column';
  card.style.gap = '16px';

  card.append(
    this.createMoveCardHeader(moveData),
    this.createMoveBasicInfoSection(moveData),
    this.createMoveStatsChart(moveData),
    this.createMoveDescriptionSection(moveData)
  );

  this.gridContainer.appendChild(card);
  requestAnimationFrame(() => card.classList.add('visible'));
}

// -----------------------------
// Helper: Create a Badge Element
// -----------------------------
createBadge(text, backgroundColor) {
  const badge = document.createElement('span');
  badge.className = 'type-badge';
  badge.textContent = text.toUpperCase();
  badge.style.background = backgroundColor;
  badge.style.padding = '3px 3px';
  badge.style.borderRadius = '5px';
  badge.style.fontSize = '10px';
  badge.style.fontWeight = '700';
  badge.style.color = '#fff';
  badge.style.textShadow = '0 1px 2px rgba(0,0,0,0.3)';
  return badge;
}

// -----------------------------
// Header: Move Title, Badges, and Numeric Details
// -----------------------------
createMoveCardHeader(moveData) {
  const header = document.createElement('header');
  header.className = 'poke-card-header animate-slideDown';
  header.setAttribute('role', 'banner');

  const title = document.createElement('h1');
  title.className = 'poke-title';
  title.style.fontSize = '32px';
  title.style.margin = '0 0 8px';
  title.textContent = moveData.name.charAt(0).toUpperCase() + moveData.name.slice(1);

  const badgeContainer = document.createElement('div');
  badgeContainer.style.display = 'flex';
  badgeContainer.style.gap = '8px';
  badgeContainer.style.marginBottom = '16px';

  const typeBadge = this.createBadge(moveData.type.name, this.getTypeColor(moveData.type.name));
  const damageColor = moveData.damage_class.name === 'physical'
    ? '#F08030'
    : moveData.damage_class.name === 'special'
      ? '#6890F0'
      : '#A8A878';
  const damageBadge = this.createBadge(moveData.damage_class.name, damageColor);

  badgeContainer.append(typeBadge, damageBadge);

  const details = document.createElement('div');
  details.style.display = 'grid';
  details.style.gridTemplateColumns = 'repeat(4, auto)';
  details.style.gap = '16px';
  details.innerHTML = `
    <div class="detail-item">
      <span class="detail-label">POWER</span>
      <span class="detail-value">${moveData.power !== null ? moveData.power : '—'}</span>
    </div>
    <div class="detail-item">
      <span class="detail-label">ACC</span>
      <span class="detail-value">${moveData.accuracy !== null ? moveData.accuracy : '—'}</span>
    </div>
    <div class="detail-item">
      <span class="detail-label">PP</span>
      <span class="detail-value">${moveData.pp}</span>
    </div>
    <div class="detail-item">
      <span class="detail-label">PRI</span>
      <span class="detail-value">${moveData.priority}</span>
    </div>
  `;

  header.append(title, badgeContainer, details);
  return header;
}

// -----------------------------
// Basic Info Section: Additional Move Details
// -----------------------------
createMoveBasicInfoSection(moveData) {
  const section = document.createElement('section');
  section.className = 'info-grid animate-fadeInUp';
  section.innerHTML = `
    <h3 class="section-title">BASIC INFO</h3>
    <div class="metric">
      <span class="label">CATEGORY</span>
      <span class="value">${moveData.damage_class.name.toUpperCase()}</span>
    </div>
    <div class="metric">
      <span class="label">TARGET</span>
      <span class="value">${moveData.target.name.replace(/-/g, ' ').toUpperCase()}</span>
    </div>
    <div class="metric">
      <span class="label">EFFECT CHANCE</span>
      <span class="value">${moveData.effect_chance !== null ? moveData.effect_chance + '%' : '—'}</span>
    </div>
  `;
  return section;
}

// -----------------------------
// Statistics Chart Section: Visualize Move Data with Chart.js
// -----------------------------
createMoveStatsChart(moveData) {
  const section = document.createElement('section');
  section.className = 'stats-chart-card animate-fadeInUp';
  section.innerHTML = `<h3 class="section-title">STATISTICS</h3>`;

  const chartContainer = document.createElement('div');
  chartContainer.className = 'chart-container';
  chartContainer.style.position = 'relative';
  chartContainer.style.height = '220px';
  chartContainer.style.width = '100%';
  chartContainer.style.margin = '16px 0';

  const canvas = document.createElement('canvas');
  canvas.setAttribute('aria-label', 'Move statistics chart');
  canvas.style.touchAction = 'none';
  canvas.style.width = '100%';
  canvas.style.height = '100%';

  const renderChart = () => {
    const ctx = canvas.getContext('2d');
    const labels = [];
    const dataValues = [];

    if (moveData.power !== null) {
      labels.push('Power');
      dataValues.push(moveData.power);
    }
    if (moveData.accuracy !== null) {
      labels.push('Accuracy');
      dataValues.push(moveData.accuracy);
    }
    labels.push('PP');
    dataValues.push(moveData.pp);
    labels.push('Priority');
    dataValues.push(moveData.priority);

    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: labels,
        datasets: [{
          label: moveData.name.toUpperCase(),
          data: dataValues,
          backgroundColor: [
            'rgba(145,70,255,0.6)',
            'rgba(245,25,255,0.6)',
            'rgba(255,159,64,0.6)',
            'rgba(255,64,64,0.6)'
          ],
          borderColor: [
            'rgba(145,70,255,1)',
            'rgba(245,25,255,1)',
            'rgba(255,159,64,1)',
            'rgba(255,64,64,1)'
          ],
          borderWidth: 1
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
          y: { beginAtZero: true }
        },
        plugins: {
          legend: { display: false }
        }
      }
    });
  };

  if (typeof Chart === 'undefined') {
    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
    script.onload = renderChart;
    script.onerror = () => {
      console.error("Failed to load Chart.js");
      section.innerHTML += `<div style="padding:12px; color: var(--text-light);">Failed to load chart library.</div>`;
    };
    document.head.appendChild(script);
  } else {
    renderChart();
  }

  chartContainer.appendChild(canvas);
  section.appendChild(chartContainer);
  return section;
}

// -----------------------------
// Move Description Section: Display Move Effect Text
// -----------------------------
createMoveDescriptionSection(moveData) {
  const section = document.createElement('section');
  section.className = 'move-description-section animate-fadeInUp';
  section.innerHTML = `<h3 class="section-title">MOVE DESCRIPTION</h3>`;

  const effectEntry = moveData.effect_entries.find(e => e.language.name === 'en');
  const effectText = effectEntry
    ? effectEntry.effect.replace(/\n|\f/g, ' ')
    : 'No description available.';

  const descContainer = document.createElement('div');
  descContainer.className = 'move-description';
  descContainer.style.background = 'var(--background-darker)';
  descContainer.style.padding = '16px';
  descContainer.style.borderRadius = '8px';
  descContainer.style.fontSize = '14px';
  descContainer.style.lineHeight = '1.5';
  descContainer.style.color = 'var(--text-muted)';
  descContainer.textContent = effectText;

  section.appendChild(descContainer);
  return section;
}

// -----------------------------
// Instruction & Browse Sections
// -----------------------------
renderAdvancedInstruction() {
  this.gridContainer.innerHTML = '';
  const info = document.createElement('div');
  info.style.padding = '12px';
  info.style.textAlign = 'center';
  info.style.color = 'var(--text-light)';
  info.textContent = 'Enter a Pokémon name and press Enter for detailed info.';
  this.gridContainer.appendChild(info);
}

renderBrowse() {
  this.gridContainer.innerHTML = '';
  if (!this.pokemonList) {
    this.gridContainer.innerHTML = '<div class="spinner"></div>';
    fetch('https://pokeapi.co/api/v2/pokemon?limit=20000')
      .then(response => response.json())
      .then(data => {
        this.pokemonList = data.results;
        this.renderBrowseGrid();
      })
      .catch(err => {
        this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">Error loading Pokémon list</div>`;
      });
  } else {
    this.renderBrowseGrid();
  }
}

renderBrowseGrid() {
  this.gridContainer.innerHTML = '';
  this.gridContainer.classList.add('browse-container');
  const query = this.searchInput.value.trim().toLowerCase();
  const filtered = this.pokemonList.filter(poke => poke.name.includes(query));
  const fragment = document.createDocumentFragment();

  filtered.forEach(poke => {
    const tile = document.createElement('div');
    tile.className = 'browse-tile';
    tile.dataset.label = poke.name.toLowerCase();

    const idMatch = poke.url.match(/\/pokemon\/(\d+)\//);
    const id = idMatch ? idMatch[1] : '';

    const img = document.createElement('img');
    img.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`;

    const label = document.createElement('div');
    label.className = 'tile-label';
    label.textContent = poke.name;

    tile.append(img, label);
    tile.addEventListener('click', (e) => {
      e.stopPropagation();
      this.panel.classList.add('active');
      this.changeTab('advanced');
      this.searchInput.value = poke.name;
      this.searchAdvancedPokemon(poke.name);
    });

    fragment.appendChild(tile);
  });

  this.gridContainer.appendChild(fragment);
  if (filtered.length === 0) {
    this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">No Pokémon match your search.</div>`;
  }
}

// -----------------------------
// Render Pokémon with Sorting & Filtering via Dropdowns (with BST)
// -----------------------------
renderPokemon() {
  this.gridContainer.innerHTML = '';
  // Render the custom controls panel for Pokémon filters and sort.
  this.renderPokemonControls();
  if (!this.pokemonList) {
    this.gridContainer.innerHTML = '<div class="spinner"></div>';
    fetch('https://pokeapi.co/api/v2/pokemon?limit=20000')
      .then(response => response.json())
      .then(data => {
        this.pokemonList = data.results;
        this.renderPokemonGrid();
      })
      .catch(err => {
        this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">Error loading Pokémon list</div>`;
      });
  } else {
    this.renderPokemonGrid();
  }
}

renderPokemonControls() {
  let controlsContainer = document.getElementById('pokemon-controls');
  if (!controlsContainer) {
    controlsContainer = document.createElement('div');
    controlsContainer.id = 'pokemon-controls';
    Object.assign(controlsContainer.style, {
      display: 'flex',
      flexDirection: 'row',
      flexWrap: 'nowrap',
      justifyContent: 'flex-start',
      alignItems: 'center',
      gap: '2px', // Slightly increased from 3px
      marginBottom: '5px',
      backgroundColor: '#202020',
      color: '#fff',
      padding: '1.8px', // Slightly increased from 2px
      borderRadius: '5px',
      overflowX: 'auto'
    });
    this.gridContainer.parentNode.insertBefore(controlsContainer, this.gridContainer);
  }

  controlsContainer.innerHTML = '';

  // Updated helper function with slight size increases
  const createControl = (labelText, id, optionsHTML, onChange) => {
    const container = document.createElement('div');
    Object.assign(container.style, {
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      gap: '1.2px', // Slightly increased from 1px
      flexShrink: '0',
      minWidth: '50px', // Increased from 48px
      maxWidth: '76px' // Increased from 72px
    });

    const label = document.createElement('div');
    label.textContent = labelText;
    Object.assign(label.style, {
      fontSize: '11px', // Increased from 10px
      textAlign: 'center',
      whiteSpace: 'nowrap',
      padding: '0 2px'
    });

    const select = document.createElement('select');
    select.id = id;
    Object.assign(select.style, {
      backgroundColor: '#202020',
      color: '#fff',
      border: '1px solid #666',
      borderRadius: '3px',
      padding: '2px', // Increased from 1px
      fontSize: '10px', // Increased from 9px
      width: '92%',
      height: '22px', // Increased from 22px
      cursor: 'pointer'
    });
    select.innerHTML = optionsHTML;
    select.addEventListener('change', onChange);
    container.appendChild(label);
    container.appendChild(select);
    return container;
  };

  // Create all controls
  const typeControl = createControl('Type', 'pokemon-type-filter', `
    <option value="all">All</option>
    <option value="normal">Normal</option>
    <option value="fire">Fire</option>
    <option value="water">Water</option>
    <option value="grass">Grass</option>
    <option value="electric">Electric</option>
    <option value="ice">Ice</option>
    <option value="fighting">Fighting</option>
    <option value="poison">Poison</option>
    <option value="ground">Ground</option>
    <option value="flying">Flying</option>
    <option value="psychic">Psychic</option>
    <option value="bug">Bug</option>
    <option value="rock">Rock</option>
    <option value="ghost">Ghost</option>
    <option value="dragon">Dragon</option>
    <option value="dark">Dark</option>
    <option value="steel">Steel</option>
    <option value="fairy">Fairy</option>
  `, () => {
    this.selectedTypeFilter = document.getElementById('pokemon-type-filter').value;
    this.renderPokemonGrid();
  });

  const weightControl = createControl('Weight', 'pokemon-weight-filter', `
    <option value="all">All</option>
    <option value="light">&lt;30kg</option>
    <option value="medium">30-70kg</option>
    <option value="heavy">&gt;70kg</option>
  `, () => {
    this.selectedWeightFilter = document.getElementById('pokemon-weight-filter').value;
    this.renderPokemonGrid();
  });

  const heightControl = createControl('Height', 'pokemon-height-filter', `
    <option value="all">All</option>
    <option value="short">&lt;1m</option>
    <option value="medium">1-2m</option>
    <option value="tall">&gt;2m</option>
  `, () => {
    this.selectedHeightFilter = document.getElementById('pokemon-height-filter').value;
    this.renderPokemonGrid();
  });

  const bstControl = createControl('BST', 'pokemon-bst-filter', `
    <option value="all">All</option>
    <option value="low">&lt;400</option>
    <option value="medium">400-600</option>
    <option value="high">&gt;600</option>
  `, () => {
    this.selectedBSTFilter = document.getElementById('pokemon-bst-filter').value;
    this.renderPokemonGrid();
  });

  const sortControl = createControl('Sort', 'pokemon-sort', `
    <option value="name-asc">Name A-Z</option>
    <option value="name-desc">Name Z-A</option>
    <option value="dex-asc">Dex Ascending</option>
    <option value="dex-desc">Dex Descending</option>
    <option value="bst-asc">BST Ascending</option>
    <option value="bst-desc">BST Descending</option>
  `, () => {
    this.renderPokemonGrid();
  });

  // Append controls together
  controlsContainer.appendChild(typeControl);
  controlsContainer.appendChild(weightControl);
  controlsContainer.appendChild(heightControl);
  controlsContainer.appendChild(bstControl);
  controlsContainer.appendChild(sortControl);
}

/**
 * This function should be called when switching tabs to ensure
 * the sorting controls are removed and re-rendered correctly.
 */
switchTab(tabName) {
  console.log(`Switching to tab: ${tabName}`);

  // Clear and rebuild controls
  this.renderPokemonControls();
  this.renderPokemonGrid(); // Re-render grid to reflect any new filters
}


// Render the Pokémon grid with search, filtering (Type, Weight, Height, BST), and sorting.
renderPokemonGrid() {
  this.gridContainer.innerHTML = '';
  this.gridContainer.classList.add('browse-container');
  const query = this.searchInput.value.trim().toLowerCase();
  let filtered = this.pokemonList.filter(poke => poke.name.includes(query));

  // Filter by Type if selected.
  if (this.selectedTypeFilter && this.selectedTypeFilter !== 'all') {
    filtered = filtered.filter(poke => {
      if (this.pokemonDetailCache && this.pokemonDetailCache.has(poke.url)) {
        const pokeData = this.pokemonDetailCache.get(poke.url);
        return pokeData.types.some(typeInfo => typeInfo.type.name === this.selectedTypeFilter);
      }
      return true;
    });
  }

  // Filter by Weight if selected.
  if (this.selectedWeightFilter && this.selectedWeightFilter !== 'all') {
    filtered = filtered.filter(poke => {
      if (this.pokemonDetailCache && this.pokemonDetailCache.has(poke.url)) {
        const pokeData = this.pokemonDetailCache.get(poke.url);
        const weightKg = pokeData.weight / 10;
        if (this.selectedWeightFilter === 'light') {
          return weightKg < 30;
        } else if (this.selectedWeightFilter === 'medium') {
          return weightKg >= 30 && weightKg <= 70;
        } else if (this.selectedWeightFilter === 'heavy') {
          return weightKg > 70;
        }
      }
      return true;
    });
  }

  // Filter by Height if selected.
  if (this.selectedHeightFilter && this.selectedHeightFilter !== 'all') {
    filtered = filtered.filter(poke => {
      if (this.pokemonDetailCache && this.pokemonDetailCache.has(poke.url)) {
        const pokeData = this.pokemonDetailCache.get(poke.url);
        const heightM = pokeData.height / 10;
        if (this.selectedHeightFilter === 'short') {
          return heightM < 1;
        } else if (this.selectedHeightFilter === 'medium') {
          return heightM >= 1 && heightM <= 2;
        } else if (this.selectedHeightFilter === 'tall') {
          return heightM > 2;
        }
      }
      return true;
    });
  }

  // Filter by BST if selected.
  if (this.selectedBSTFilter && this.selectedBSTFilter !== 'all') {
    filtered = filtered.filter(poke => {
      if (this.pokemonDetailCache && this.pokemonDetailCache.has(poke.url)) {
        const pokeData = this.pokemonDetailCache.get(poke.url);
        const totalStats = pokeData.stats.reduce((sum, stat) => sum + stat.base_stat, 0);
        if (this.selectedBSTFilter === 'low') {
          return totalStats < 400;
        } else if (this.selectedBSTFilter === 'medium') {
          return totalStats >= 400 && totalStats <= 600;
        } else if (this.selectedBSTFilter === 'high') {
          return totalStats > 600;
        }
      }
      return true;
    });
  }

  // Sort the filtered Pokémon.
  const sortOption = document.getElementById('pokemon-sort')?.value || 'name-asc';
  if (sortOption === 'name-asc') {
    filtered.sort((a, b) => a.name.localeCompare(b.name));
  } else if (sortOption === 'name-desc') {
    filtered.sort((a, b) => b.name.localeCompare(a.name));
  } else if (sortOption === 'dex-asc') {
    filtered.sort((a, b) => {
      const idA = parseInt(a.url.match(/\/pokemon\/(\d+)\//)[1]);
      const idB = parseInt(b.url.match(/\/pokemon\/(\d+)\//)[1]);
      return idA - idB;
    });
  } else if (sortOption === 'dex-desc') {
    filtered.sort((a, b) => {
      const idA = parseInt(a.url.match(/\/pokemon\/(\d+)\//)[1]);
      const idB = parseInt(b.url.match(/\/pokemon\/(\d+)\//)[1]);
      return idB - idA;
    });
  } else if (sortOption === 'bst-asc') {
    filtered.sort((a, b) => {
      const bstA = (this.pokemonDetailCache && this.pokemonDetailCache.has(a.url))
        ? this.pokemonDetailCache.get(a.url).stats.reduce((sum, stat) => sum + stat.base_stat, 0)
        : 0;
      const bstB = (this.pokemonDetailCache && this.pokemonDetailCache.has(b.url))
        ? this.pokemonDetailCache.get(b.url).stats.reduce((sum, stat) => sum + stat.base_stat, 0)
        : 0;
      return bstA - bstB;
    });
  } else if (sortOption === 'bst-desc') {
    filtered.sort((a, b) => {
      const bstA = (this.pokemonDetailCache && this.pokemonDetailCache.has(a.url))
        ? this.pokemonDetailCache.get(a.url).stats.reduce((sum, stat) => sum + stat.base_stat, 0)
        : 0;
      const bstB = (this.pokemonDetailCache && this.pokemonDetailCache.has(b.url))
        ? this.pokemonDetailCache.get(b.url).stats.reduce((sum, stat) => sum + stat.base_stat, 0)
        : 0;
      return bstB - bstA;
    });
  }

  // Build the grid as before.
  const fragment = document.createDocumentFragment();
  filtered.forEach(poke => {
    const tile = document.createElement('div');
    tile.className = 'pokemon-card';

    // Hover effects.
    tile.addEventListener('mouseenter', () => {
      tile.style.boxShadow = '0 0 15px rgba(255, 255, 255, 0.6)';
      tile.style.transform = 'scale(1.05)';
    });
    tile.addEventListener('mouseleave', () => {
      tile.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.1)';
      tile.style.transform = 'scale(1)';
    });

    // Dex Number (Top Left)
    const dexNumber = document.createElement('div');
    dexNumber.className = 'dex-number';
    tile.appendChild(dexNumber);

    // Image Container
    const imageContainer = document.createElement('div');
    imageContainer.className = 'pokemon-image-container';
    tile.appendChild(imageContainer);

    // Pokémon Image with lazy loading.
    const img = document.createElement('img');
    img.className = 'pokemon-image';
    img.loading = 'lazy';
    imageContainer.appendChild(img);

    // Extract Pokémon ID from URL.
    const idMatch = poke.url.match(/\/pokemon\/(\d+)\//);
    const id = idMatch ? idMatch[1] : '';

    // Try several image sources with fallbacks.
    const imageSources = [
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/showdown/${id}.gif`,
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${id}.png`,
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/${id}.svg`,
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`,
      `https://via.placeholder.com/150x150?text=No+Image`
    ];
    let imgIndex = 0;
    function loadNextImage() {
      if (imgIndex >= imageSources.length) return;
      img.src = imageSources[imgIndex];
      img.onerror = () => {
        imgIndex++;
        loadNextImage();
      };
    }
    loadNextImage();

    // Pokémon Name
    const nameLabel = document.createElement('div');
    nameLabel.className = 'pokemon-name';
    nameLabel.textContent = poke.name;
    tile.appendChild(nameLabel);

    // Type Badges (Centered)
    const typesContainer = document.createElement('div');
    typesContainer.className = 'pokemon-types';
    tile.appendChild(typesContainer);

    // Basic Info container (for height, weight, BST, etc.)
    const basicInfoContainer = document.createElement('div');
    basicInfoContainer.className = 'pokemon-info';
    basicInfoContainer.textContent = 'Loading info...';
    tile.appendChild(basicInfoContainer);

    // Function to update the tile with fetched Pokémon details.
    const updatePokemonDetails = (detail) => {
      dexNumber.textContent = `#${detail.id}`;
      typesContainer.innerHTML = '';
      detail.types.forEach(typeInfo => {
        const badge = this.createBadge(
          typeInfo.type.name,
          this.getTypeColor(typeInfo.type.name)
        );
        typesContainer.appendChild(badge);
      });
      const height = (detail.height / 10).toFixed(1);
      const weight = (detail.weight / 10).toFixed(1);
      const baseExp = detail.base_experience;
      const totalStats = detail.stats.reduce((sum, stat) => sum + stat.base_stat, 0);
      basicInfoContainer.innerHTML = `
        <span> ${height}m | ${weight}kg </span>
        <span> Exp: ${baseExp} | BST: ${totalStats} </span>
      `;
    };

    // Fetch details if not already cached.
    if (this.pokemonDetailCache && this.pokemonDetailCache.has(poke.url)) {
      const cachedDetail = this.pokemonDetailCache.get(poke.url);
      updatePokemonDetails(cachedDetail);
    } else {
      fetch(poke.url)
        .then(response => response.json())
        .then(detail => {
          if (!this.pokemonDetailCache) this.pokemonDetailCache = new Map();
          this.pokemonDetailCache.set(poke.url, detail);
          updatePokemonDetails(detail);
        })
        .catch(err => {
          console.error("Error fetching Pokémon detail:", err);
          basicInfoContainer.textContent = 'Info not available';
        });
    }

    // Click event for showing detailed view.
    tile.addEventListener('click', (e) => {
      e.stopPropagation();
      this.panel.classList.add('active');
      this.changeTab('advanced');
      this.searchInput.value = poke.name;
      this.searchAdvancedPokemon(poke.name);
    });

    fragment.appendChild(tile);
  });

  this.gridContainer.appendChild(fragment);
  if (filtered.length === 0) {
    this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">No Pokémon match your search.</div>`;
  }
}


// -----------------------------
// Add Global Event Listeners
// -----------------------------
addEventListeners() {
  this.button.addEventListener('mousedown', this.dragStart);

  this.button.addEventListener('click', (e) => {
    if (this.wasDragging) {
      this.wasDragging = false;
      return;
    }
    e.stopPropagation();
    this.panel.classList.toggle('active');
    if (this.panel.classList.contains('active')) {
      this.searchInput.focus();
    }
  });

  document.addEventListener('click', (e) => {
    if (!this.container.contains(e.target)) {
      this.panel.classList.remove('active');
    }
  });

  this.panel.addEventListener('dragstart', (e) => {
    const ballImg = e.target.closest('.pball-item img');
    if (ballImg) {
      e.dataTransfer.setData('text/plain', ballImg.dataset.ballType);

      const dragImg = new Image();
      dragImg.src = ballImg.src;
      dragImg.style.width = '36px';
      dragImg.style.height = '36px';
      dragImg.style.position = 'absolute';
      dragImg.style.left = '-9999px';
      document.body.appendChild(dragImg);

      e.dataTransfer.setDragImage(dragImg, 18, 18);
      setTimeout(() => document.body.removeChild(dragImg), 0);

      ballImg.classList.add('dragging');
      const onDragEnd = () => {
        ballImg.classList.remove('dragging');
        document.removeEventListener('dragend', onDragEnd);
      };
      document.addEventListener('dragend', onDragEnd);
    }
  });

  const chatInput = document.querySelector('#chatInput');
  if (chatInput) {
    chatInput.addEventListener('dragover', (e) => {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'copy';
    });

    chatInput.addEventListener('drop', (e) => {
      e.preventDefault();
      const ballType = e.dataTransfer.getData('text/plain');
      if (ballType) {
        chatInput.value += ` ${ballType}`;
      }
    });
  }

  const tabs = this.panel.querySelectorAll('.pball-tab');
  tabs.forEach(tab => {
    tab.addEventListener('click', (e) => {
      e.stopPropagation();
      this.changeTab(tab.dataset.tab);
    });
  });

  // Use debounced handler for the search input
  const debouncedSearch = this.debounce(() => {
    if (this.currentTab !== 'advanced') {
      this.filterGrid();
      if (this.currentTab === 'pokemon') {
        this.renderPokemonGrid();
      }
    }
    this.clearBtn.style.display = this.searchInput.value.trim() ? 'block' : 'none';
  }, 300);
  this.searchInput.addEventListener('input', debouncedSearch);

  this.clearBtn.addEventListener('click', () => {
    this.searchInput.value = '';
    this.clearBtn.style.display = 'none';
    if (this.currentTab !== 'advanced') {
      this.filterGrid();
      if (this.currentTab === 'browse') {
        this.renderBrowseGrid();
      }
    }
  });

  this.searchInput.addEventListener('keydown', (e) => {
    if (this.currentTab === 'advanced' && e.key === 'Enter') {
      this.searchAdvancedPokemon(this.searchInput.value.trim());
    }
  });
}

// 2. Update changeTab() to handle the new "moves" tab
changeTab(tabName) {
  this.currentTab = tabName;
  const tabs = this.panel.querySelectorAll('.pball-tab');
  tabs.forEach(tab => {
    tab.classList.toggle('active', tab.dataset.tab === tabName);
  });
  if (tabName === 'advanced') {
    this.searchInput.placeholder = 'Enter Pokémon name for detailed info...';
  } else if (tabName === 'pokemon') {
    this.searchInput.placeholder = 'Filter Pokémon...';
  } else if (tabName === 'moves') {
    this.searchInput.placeholder = 'Filter moves...';
  } else {
    this.searchInput.placeholder = 'Search...';
  }
  this.searchInput.value = '';
  this.clearBtn.style.display = 'none';
  this.renderGrid();
}

      filterGrid() {
        const query = this.searchInput.value.trim().toLowerCase();
        const items = this.gridContainer.querySelectorAll('.pball-item, .browse-tile');
        items.forEach(item => {
          if (!query || item.dataset.label.includes(query)) {
            item.style.display = 'flex';
          } else {
            item.style.display = 'none';
          }
        });
      }

      getChatInput() {
        return document.querySelector('[data-a-target="chat-input"]');
      }

      insertCommand(ballType) {
        const chatInput = this.getChatInput();
        if (!chatInput) return;
        chatInput.focus();
        this.clearChatInput();
        this.insertText(ballType);
        this.triggerInputEvent(chatInput);
      }

      clearChatInput() {
        const chatInput = this.getChatInput();
        if (chatInput) {
          chatInput.value = '';
          this.triggerInputEvent(chatInput);
        }
      }

      insertText(text) {
        document.execCommand('insertText', false, text);
      }

      triggerInputEvent(element) {
        element.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
      }

      searchAdvancedPokemon(name) {
        if (!name) return;
        this.gridContainer.innerHTML = '<div class="spinner"></div>';
        fetch(`https://pokeapi.co/api/v2/pokemon/${name.toLowerCase()}`)
          .then(response => {
            if (!response.ok) { throw new Error("Pokémon not found"); }
            return response.json();
          })
          .then(data => {
            return fetch(data.species.url)
              .then(res => {
                if (!res.ok) { throw new Error("Species data not found"); }
                return res.json().then(speciesData => ({ data, speciesData }));
              });
          })
          .then(({ data, speciesData }) => {
            return fetch(speciesData.evolution_chain.url)
              .then(res => {
                if (!res.ok) { throw new Error("Evolution chain not found"); }
                return res.json().then(evoData => ({ data, speciesData, evoData }));
              });
          })
          .then(({ data, speciesData, evoData }) => {
            this.displayAdvancedPokemonData(data, speciesData, evoData);
          })
          .catch(err => {
            this.gridContainer.innerHTML = `<div style="padding:12px; color: var(--text-light);">${err.message}</div>`;
          });
      }

createAdvancedBattleAnalysisTab(data) {
  const container = document.createElement('section');
  container.className = 'advanced-battle-analysis animate-fadeInUp';
  container.style.padding = '1rem';
  container.style.borderTop = '1px solid var(--color-border)';

  // Section title
  const title = document.createElement('h3');
  title.className = 'section-title';
  title.textContent = 'Comprehensive Type Interactions';
  container.appendChild(title);

  // Grid container for type cards
  const grid = document.createElement('div');
  grid.style.display = 'grid';
  grid.style.gridTemplateColumns = 'repeat(auto-fit, minmax(250px, 1fr))';
  grid.style.gap = '16px';

  // Create an interactive card for each type
  data.types.forEach(typeObj => {
    const typeCard = document.createElement('div');
    typeCard.className = 'advanced-type-card';
    typeCard.style.border = '1px solid var(--color-border)';
    typeCard.style.borderRadius = '8px';
    typeCard.style.background = 'var(--color-card)';
    typeCard.style.boxShadow = 'var(--box-shadow-light)';
    typeCard.style.overflow = 'hidden';
    typeCard.style.display = 'flex';
    typeCard.style.flexDirection = 'column';

    // Card header with type name and color
    const header = document.createElement('div');
    header.textContent = typeObj.type.name.toUpperCase();
    header.style.background = this.getTypeColor(typeObj.type.name);
    header.style.color = '#fff';
    header.style.padding = '8px';
    header.style.fontWeight = 'bold';
    header.style.textAlign = 'center';
    typeCard.appendChild(header);

    // Tab header container for "Offense" and "Defense"
    const tabHeaderContainer = document.createElement('div');
    tabHeaderContainer.style.display = 'flex';

    // Both buttons now use the card's background
    const offenseTab = document.createElement('button');
    offenseTab.textContent = 'Offense';
    offenseTab.style.flex = '1';
    offenseTab.style.padding = '8px';
    offenseTab.style.border = 'none';
    offenseTab.style.cursor = 'pointer';
    offenseTab.style.background = 'var(--color-card)';
    offenseTab.style.fontWeight = 'bold';
    offenseTab.style.transition = 'border-bottom 0.2s ease';

    const defenseTab = document.createElement('button');
    defenseTab.textContent = 'Defense';
    defenseTab.style.flex = '1';
    defenseTab.style.padding = '8px';
    defenseTab.style.border = 'none';
    defenseTab.style.cursor = 'pointer';
    defenseTab.style.background = 'var(--color-card)';
    defenseTab.style.fontWeight = 'bold';
    defenseTab.style.transition = 'border-bottom 0.2s ease';

    tabHeaderContainer.append(offenseTab, defenseTab);
    typeCard.appendChild(tabHeaderContainer);

    // Create content containers for each tab
    const offenseContent = document.createElement('div');
    offenseContent.style.padding = '8px';
    offenseContent.style.display = 'block';

    const defenseContent = document.createElement('div');
    defenseContent.style.padding = '8px';
    defenseContent.style.display = 'none';

    typeCard.appendChild(offenseContent);
    typeCard.appendChild(defenseContent);

    // Fetch the type data and build the interactive details
    fetch(typeObj.type.url)
      .then(res => res.json())
      .then(typeData => {
        // --- Offense details ---
        const offenseSections = [
          { label: 'Double Damage To', data: typeData.damage_relations.double_damage_to },
          { label: 'Half Damage To', data: typeData.damage_relations.half_damage_to },
          { label: 'No Damage To', data: typeData.damage_relations.no_damage_to }
        ];
        offenseSections.forEach(section => {
          const sectionTitle = document.createElement('h4');
          sectionTitle.textContent = section.label;
          sectionTitle.style.marginBottom = '4px';
          sectionTitle.style.fontSize = '0.9rem';
          offenseContent.appendChild(sectionTitle);

          const sectionContent = document.createElement('div');
          sectionContent.style.display = 'flex';
          sectionContent.style.flexWrap = 'wrap';
          sectionContent.style.gap = '4px';
          if (section.data.length > 0) {
            section.data.forEach(item => {
              const badge = document.createElement('span');
              badge.textContent = item.name.toUpperCase();
              badge.style.background = this.getTypeColor(item.name);
              badge.style.color = '#fff';
              badge.style.padding = '2px 6px';
              badge.style.borderRadius = '4px';
              badge.style.fontSize = '0.8rem';
              sectionContent.appendChild(badge);
            });
          } else {
            const noData = document.createElement('span');
            noData.textContent = 'None';
            noData.style.fontSize = '0.8rem';
            sectionContent.appendChild(noData);
          }
          offenseContent.appendChild(sectionContent);
        });

        // --- Defense details ---
        const defenseSections = [
          { label: 'Double Damage From', data: typeData.damage_relations.double_damage_from },
          { label: 'Half Damage From', data: typeData.damage_relations.half_damage_from },
          { label: 'No Damage From', data: typeData.damage_relations.no_damage_from }
        ];
        defenseSections.forEach(section => {
          const sectionTitle = document.createElement('h4');
          sectionTitle.textContent = section.label;
          sectionTitle.style.marginBottom = '4px';
          sectionTitle.style.fontSize = '0.9rem';
          defenseContent.appendChild(sectionTitle);

          const sectionContent = document.createElement('div');
          sectionContent.style.display = 'flex';
          sectionContent.style.flexWrap = 'wrap';
          sectionContent.style.gap = '4px';
          if (section.data.length > 0) {
            section.data.forEach(item => {
              const badge = document.createElement('span');
              badge.textContent = item.name.toUpperCase();
              badge.style.background = this.getTypeColor(item.name);
              badge.style.color = '#fff';
              badge.style.padding = '2px 6px';
              badge.style.borderRadius = '4px';
              badge.style.fontSize = '0.8rem';
              sectionContent.appendChild(badge);
            });
          } else {
            const noData = document.createElement('span');
            noData.textContent = 'None';
            noData.style.fontSize = '0.8rem';
            sectionContent.appendChild(noData);
          }
          defenseContent.appendChild(sectionContent);
        });
      })
      .catch(err => {
        console.error('Error fetching type interactions:', err);
        offenseContent.textContent = 'Unable to load data.';
        defenseContent.textContent = 'Unable to load data.';
      });

    // --- Tab switching functionality ---
    // Instead of changing the background, we use a bottom border to indicate the active tab.
    offenseTab.addEventListener('click', () => {
      offenseTab.style.borderBottom = '2px solid var(--color-primary)';
      defenseTab.style.borderBottom = 'none';
      offenseContent.style.display = 'block';
      defenseContent.style.display = 'none';
    });
    defenseTab.addEventListener('click', () => {
      defenseTab.style.borderBottom = '2px solid var(--color-primary)';
      offenseTab.style.borderBottom = 'none';
      offenseContent.style.display = 'none';
      defenseContent.style.display = 'block';
    });

    // Set initial active state for offense tab
    offenseTab.style.borderBottom = '2px solid var(--color-primary)';

    grid.appendChild(typeCard);
  });

  container.appendChild(grid);
  return container;
}


  /**
   * Helper function to get a color based on the Pokémon type.
   * @param {string} typeName
   * @returns {string} The color string.
   */
  getTypeColor(typeName) {
    const typeColors = {
      normal: '#A8A878',
      fire: '#F08030',
      water: '#6890F0',
      electric: '#F8D030',
      grass: '#78C850',
      ice: '#98D8D8',
      fighting: '#C03028',
      poison: '#A040A0',
      ground: '#E0C068',
      flying: '#A890F0',
      psychic: '#F85888',
      bug: '#A8B820',
      rock: '#B8A038',
      ghost: '#705898',
      dragon: '#7038F8',
      dark: '#705848',
      steel: '#B8B8D0',
      fairy: '#EE99AC'
    };
    return typeColors[typeName] || '#68A090';
  }

  // CARD HEADER WITH IMAGE, NAME, AND DETAILS
  createCardHeader(data) {
    const header = document.createElement('header');
    header.className = 'poke-card-header animate-slideDown';
    header.setAttribute('role', 'banner');

    // Image container with lazy loading and type badges
    const imgContainer = document.createElement('div');
    imgContainer.style.position = 'relative';

    const img = document.createElement('img');
    img.className = 'poke-image lazy';
    img.style.width = '90px';
    img.style.height = '90px';
    img.style.borderRadius = '16px';
    img.style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
    img.dataset.src =
      data.sprites.other?.['official-artwork']?.front_default ||
      data.sprites.front_default;
    img.src = ''; // initially empty—loaded via IntersectionObserver

    // Type badges positioned over the image
    const typeBadges = document.createElement('div');
    typeBadges.style.display = 'flex';
    typeBadges.style.gap = '4px';
    typeBadges.style.position = 'absolute';
    typeBadges.style.bottom = '60px';
    typeBadges.style.left = '80%';
    typeBadges.style.transform = 'translateX(-50%)';
    data.types.forEach(type => {
      const badge = document.createElement('span');
      badge.className = 'type-badge';
      badge.textContent = type.type.name.toUpperCase();
      badge.style.background = this.getTypeColor(type.type.name);
      badge.style.padding = '3px 3px';
      badge.style.borderRadius = '5px';
      badge.style.fontSize = '12px';
      badge.style.fontWeight = '700';
      badge.style.color = '#fff';
      badge.style.textShadow = '0 1px 2px rgba(0,0,0,0.3)';
      typeBadges.appendChild(badge);
    });
    imgContainer.append(img, typeBadges);

    // Title and details section
    const titleSection = document.createElement('div');
    const title = document.createElement('h1');
    title.className = 'poke-title';
    title.style.fontSize = '32px';
    title.style.margin = '0 0 8px';
    title.textContent =
      data.name.charAt(0).toUpperCase() + data.name.slice(1);

    const details = document.createElement('div');
    details.style.display = 'grid';
    details.style.gridTemplateColumns = 'repeat(3, auto)';
    details.style.gap = '16px';
    details.innerHTML = `
      <div class="detail-item">
        <span class="detail-label">ID</span>
        <span class="detail-value">#${data.id
          .toString()
          .padStart(3, '0')}</span>
      </div>
      <div class="detail-item">
        <span class="detail-label">EXP</span>
        <span class="detail-value">${data.base_experience}</span>
      </div>
      <div class="detail-item">
        <span class="detail-label">SPECIES</span>
        <span class="detail-value">${data.species.name}</span>
      </div>
    `;
    titleSection.append(title, details);
    header.append(imgContainer, titleSection);
    return header;
  }

  // POKÉDEX ENTRY SECTION
  createPokedexEntrySection(speciesData) {
    const section = document.createElement('section');
    section.className = 'pokedex-entry-section animate-fadeInUp';
    section.innerHTML = `<h3 class="section-title">POKÉDEX ENTRY</h3>`;
    const entry = speciesData.flavor_text_entries.find(
      e => e.language.name === 'en'
    );
    const flavorText = entry
      ? entry.flavor_text.replace(/\f|\n/g, ' ')
      : 'No entry available.';
    const entryContainer = document.createElement('div');
    entryContainer.className = 'pokedex-entry';
    entryContainer.style.background = 'var(--background-darker)';
    entryContainer.style.padding = '16px';
    entryContainer.style.borderRadius = '8px';
    entryContainer.style.fontSize = '14px';
    entryContainer.style.lineHeight = '1.5';
    entryContainer.style.color = 'var(--text-muted)';
    entryContainer.textContent = flavorText;
    section.appendChild(entryContainer);
    return section;
  }

  // BASIC PHYSICAL INFORMATION SECTION
  createBasicInfoSection(data) {
    const section = document.createElement('section');
    section.className = 'info-grid animate-fadeInUp';
    section.innerHTML = `
      <h3 class="section-title">PHYSICAL TRAITS</h3>
      <div class="metric">
        <i class="icon-height"></i>
        <span class="label">Height</span>
        <span class="value">${data.height / 10}m</span>
      </div>
      <div class="metric">
        <i class="icon-weight"></i>
        <span class="label">Weight</span>
        <span class="value">${data.weight / 10}kg</span>
      </div>
      <div class="metric">
        <i class="icon-stats"></i>
        <span class="label">Total Stats</span>
        <span class="value">${data.stats.reduce(
          (sum, s) => sum + s.base_stat,
          0
        )}</span>
      </div>
    `;
    return section;
  }
// ABILITIES SECTION WITH TOOLTIP (using async/await)
createAbilitiesSection(data) {
  const section = document.createElement('section');
  section.className = 'abilities-section animate-fadeInUp';
  section.innerHTML = `<h3 class="section-title">ABILITIES</h3>`;
  const abilitiesGrid = document.createElement('div');
  abilitiesGrid.className = 'abilities-grid';
  abilitiesGrid.style.display = 'grid';
  abilitiesGrid.style.gridTemplateColumns = 'repeat(auto-fit, minmax(140px, 1fr))';
  abilitiesGrid.style.gap = '12px';

  data.abilities.forEach(ability => {
    const abilityCard = document.createElement('div');
    abilityCard.className = 'ability-card';
    abilityCard.style.background = 'var(--background-darker)';
    abilityCard.style.padding = '12px';
    abilityCard.style.borderRadius = '8px';
    abilityCard.style.textAlign = 'center';
    abilityCard.style.position = 'relative';
    abilityCard.style.cursor = 'pointer';

    const abilityName = document.createElement('div');
    abilityName.textContent = ability.ability.name.replace(/-/g, ' ');
    abilityName.style.fontWeight = '500';
    abilityName.style.textTransform = 'capitalize';

    if (ability.is_hidden) {
      const hiddenBadge = document.createElement('div');
      hiddenBadge.textContent = 'Hidden';
      hiddenBadge.style.position = 'absolute';
      hiddenBadge.style.top = '4px';
      hiddenBadge.style.right = '4px';
      hiddenBadge.style.background = '#FF6B6B';
      hiddenBadge.style.color = '#FFF';
      hiddenBadge.style.fontSize = '10px';
      hiddenBadge.style.padding = '2px 6px';
      hiddenBadge.style.borderRadius = '12px';
      abilityCard.appendChild(hiddenBadge);
    }
    abilityCard.appendChild(abilityName);
    abilitiesGrid.appendChild(abilityCard);

    // Use async/await for fetching ability descriptions
    abilityCard.addEventListener('mouseenter', async () => {
      try {
        const res = await fetch(ability.ability.url);
        const abilityData = await res.json();
        const description =
          abilityData.effect_entries.find(e => e.language.name === 'en')?.effect ||
          'No description available.';
        this.showTooltip(abilityCard, description);
      } catch (err) {
        console.error('Error fetching ability data:', err);
      }
    });
    abilityCard.addEventListener('mouseleave', () => {
      this.hideTooltip();
    });
  });
  section.appendChild(abilitiesGrid);
  return section;
}

// Show tooltip with smooth fade-in/out transitions using a solid background color
showTooltip(element, text) {
  if (this.tooltip) this.tooltip.remove();
  this.tooltip = document.createElement('div');
  this.tooltip.className = 'tooltip animate-fadeIn';
  this.tooltip.textContent = text;
  const rect = element.getBoundingClientRect();
  const viewportHeight = window.innerHeight;
  const tooltipHeight = 100; // estimated height
  let topPosition = rect.bottom + 8;
  if (topPosition + tooltipHeight > viewportHeight) {
    topPosition = rect.top - tooltipHeight - 8;
  }
  Object.assign(this.tooltip.style, {
    background: 'var(--color-card)', // Updated to a solid color
    color: 'var(--text-light)',
    borderRadius: '6px',
    padding: '8px 12px',
    position: 'fixed',
    top: `${topPosition}px`,
    left: `${rect.left}px`,
    maxWidth: '240px',
    zIndex: '10000',
    boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
    pointerEvents: 'none',
    opacity: '0',
    transition: 'opacity 0.3s ease'
  });
  document.body.appendChild(this.tooltip);
  requestAnimationFrame(() => {
    this.tooltip.style.opacity = '1';
  });
}

hideTooltip() {
  if (this.tooltip) {
    this.tooltip.style.opacity = '0';
    setTimeout(() => {
      if (this.tooltip) {
        this.tooltip.remove();
        this.tooltip = null;
      }
    }, 300);
  }
}

// MOVES SECTION WITH SEARCH AND DETAILED TOOLTIP
createMovesSection(data) {
  const section = document.createElement('section');
  section.className = 'moves-section animate-fadeInUp';
  section.innerHTML = `<h3 class="section-title">MOVES</h3>`;

  // Search container (same as before)
  const searchContainer = document.createElement('div');
  searchContainer.className = 'pball-search-container';
  const searchInput = document.createElement('input');
  searchInput.className = 'pball-search';
  searchInput.placeholder = 'Search moves...';
  searchInput.setAttribute('aria-label', 'Search moves');
  const searchButtons = document.createElement('div');
  searchButtons.className = 'search-buttons';
  const enterButton = document.createElement('button');
  enterButton.className = 'search-enter-button';
  enterButton.textContent = '✔';
  const clearButton = document.createElement('button');
  clearButton.className = 'pball-clear-btn';
  clearButton.textContent = 'X';

  let searchTimeout;
  const handleSearch = () => {
    clearTimeout(searchTimeout);
    searchTimeout = setTimeout(() => {
      const query = searchInput.value.trim().toLowerCase();
      Array.from(movesList.children).forEach(move => {
        move.style.display = move.textContent.toLowerCase().includes(query)
          ? 'block'
          : 'none';
      });
    }, 300);
  };

  searchInput.addEventListener('input', handleSearch);
  enterButton.addEventListener('click', handleSearch);
  clearButton.addEventListener('click', () => {
    searchInput.value = '';
    handleSearch();
  });
  searchButtons.append(enterButton, clearButton);
  searchContainer.append(searchInput, searchButtons);
  section.append(searchContainer);

  // Moves list container with virtual scroll behavior
  const movesList = document.createElement('div');
  movesList.className = 'moves-list';
  movesList.style.maxHeight = '200px';
  movesList.style.overflowY = 'auto';
  movesList.style.display = 'grid';
  movesList.style.gap = '8px';

  data.moves.forEach(move => {
    const moveItem = document.createElement('div');
    moveItem.className = 'move-item';
    moveItem.textContent = move.move.name.replace(/-/g, ' ');
    moveItem.style.padding = '8px 12px';
    moveItem.style.background = 'var(--background-darker)';
    moveItem.style.borderRadius = '6px';
    moveItem.style.textTransform = 'capitalize';
moveItem.style.cursor = 'pointer';

    // Fetch and show move details on hover
    moveItem.addEventListener('mouseenter', async () => {
      try {
        const res = await fetch(move.move.url);
        const moveData = await res.json();
        const effectEntry = moveData.effect_entries.find(
          e => e.language.name === 'en'
        );
        const effectText = effectEntry
          ? effectEntry.short_effect.replace(/\n|\f/g, ' ')
          : 'No description available.';
        // Format move details
        const details = `
Name: ${moveData.name.replace(/-/g, ' ')}
Type: ${moveData.type.name.toUpperCase()}
Category: ${moveData.damage_class.name.toUpperCase()}
Power: ${moveData.power || '—'}
Accuracy: ${moveData.accuracy || '—'}
PP: ${moveData.pp}
Priority: ${moveData.priority}
Effect: ${effectText}
        `;
        this.showTooltip(moveItem, details);
      } catch (error) {
        console.error('Error fetching move data:', error);
      }
    });

    moveItem.addEventListener('mouseleave', () => {
      this.hideTooltip();
    });

    movesList.appendChild(moveItem);
  });
  section.appendChild(movesList);
  return section;
}


  // HELD ITEMS SECTION
  createHeldItemsSection(data) {
    const section = document.createElement('section');
    section.className = 'held-items-section animate-fadeInUp';
    section.innerHTML = `<h3 class="section-title">HELD ITEMS</h3>`;
    const itemsGrid = document.createElement('div');
    itemsGrid.className = 'items-grid';
    itemsGrid.style.display = 'grid';
    itemsGrid.style.gridTemplateColumns =
      'repeat(auto-fit, minmax(120px, 1fr))';
    itemsGrid.style.gap = '12px';

    data.held_items.forEach(item => {
      const itemCard = document.createElement('div');
      itemCard.className = 'item-card';
      itemCard.textContent = item.item.name.replace(/-/g, ' ');
      itemCard.style.padding = '12px';
      itemCard.style.background = 'var(--background-darker)';
      itemCard.style.borderRadius = '8px';
      itemCard.style.textAlign = 'center';
      itemCard.style.textTransform = 'capitalize';
      itemsGrid.appendChild(itemCard);
    });
    section.appendChild(itemsGrid);
    return section;
  }

  // FORMS SECTION
  createFormsSection(data) {
    const section = document.createElement('section');
    section.className = 'forms-section animate-fadeInUp';
    section.innerHTML = `<h3 class="section-title">FORMS</h3>`;
    const formsGrid = document.createElement('div');
    formsGrid.className = 'forms-grid';
    formsGrid.style.display = 'grid';
    formsGrid.style.gridTemplateColumns =
      'repeat(auto-fit, minmax(120px, 1fr))';
    formsGrid.style.gap = '12px';

    data.forms.forEach(form => {
      const formCard = document.createElement('div');
      formCard.className = 'form-card';
      formCard.textContent = form.name.replace(/-/g, ' ');
      formCard.style.padding = '12px';
      formCard.style.background = 'var(--background-darker)';
      formCard.style.borderRadius = '8px';
      formCard.style.textAlign = 'center';
      formCard.style.textTransform = 'capitalize';
      formsGrid.appendChild(formCard);
    });
    section.appendChild(formsGrid);
    return section;
  }

  // STATS RADAR CHART SECTION (with Chart.js and animated rendering)
  createStatsRadarChart(data) {
    const section = document.createElement('section');
    section.className = 'stats-radar-card animate-fadeInUp';
    section.innerHTML = `
      <div class="stats-header">
        <h3 class="section-title">Stat Distribution</h3>
          </span>
          </div>
        </div>
      </div>
    `;
    const chartContainer = document.createElement('div');
    chartContainer.className = 'radar-container';
    chartContainer.style.position = 'relative';
    chartContainer.style.height = 'clamp(280px, 35vh, 400px)';
    chartContainer.style.margin = '16px 0';

    const canvas = document.createElement('canvas');
    canvas.setAttribute('aria-label', 'Pokémon stat radar chart');
    canvas.style.touchAction = 'none';

    const typeColor = this.getTypeColor(data.types[0].type.name);
    const gradient = {
      light: this.hexToRgba(typeColor, 0.3),
      dark: this.hexToRgba(typeColor, 0.1)
    };

    if (!window.Chart) {
      const script = document.createElement('script');
      script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
      script.onload = () => this.drawEnhancedRadar(canvas, data, gradient);
      script.onerror = () => this.showChartError(chartContainer);
      document.head.appendChild(script);
    } else {
      this.drawEnhancedRadar(canvas, data, gradient);
    }
    chartContainer.appendChild(canvas);
    section.appendChild(chartContainer);
    return section;
  }

  drawEnhancedRadar(canvas, data, gradient) {
    try {
      const ctx = canvas.getContext('2d');
      const stats = data.stats.map(s => s.base_stat);
      const labels = data.stats.map(s => ({
        full: s.stat.name.replace(/-/g, ' '),
        short: this.getStatAbbreviation(s.stat.name)
      }));
      const chartGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
      chartGradient.addColorStop(0, gradient.light);
      chartGradient.addColorStop(1, gradient.dark);

      new Chart(ctx, {
        type: 'radar',
        data: {
          labels: labels.map(l => l.short),
          datasets: [
            {
              data: stats,
              backgroundColor: chartGradient,
              borderColor: this.hexToRgba(gradient.light, 0.8),
              borderWidth: 1.8,
              pointBackgroundColor: '#ffffff',
              pointBorderColor: gradient.light,
              pointHoverRadius: 8,
              pointRadius: 4,
              pointHitRadius: 12,
              fill: true
            }
          ]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          animation: {
            duration: 800,
            easing: 'easeOutQuint'
          },
          scales: {
            r: {
              beginAtZero: true,
              max: Math.ceil(Math.max(...stats) / 10) * 10 + 10,
              ticks: {
                display: false,
                count: 5,
                z: 1
              },
              grid: {
                color: 'rgba(255, 255, 255, 0.12)',
                circular: true,
                lineWidth: 0.8
              },
              pointLabels: {
                color: '#ffffff',
                font: {
                  size: 13,
                  weight: '500'
                },
                callback: (value, index) => [`${value}`, stats[index]],
                padding: 18
              },
              angleLines: {
                color: 'rgba(255, 255, 255, 0.08)',
                lineWidth: 0.8
              }
            }
          },
          plugins: {
            legend: { display: false },
            tooltip: {
              enabled: true,
              intersect: false,
              callbacks: {
                title: items => labels[items[0].dataIndex].full,
                label: context => `Base Stat: ${context.raw}`
              },
              bodyFont: { size: 13 },
              titleFont: { size: 12 },
              padding: 14,
              backgroundColor: 'rgba(28, 28, 34, 0.96)',
              borderColor: 'rgba(255, 255, 255, 0.12)',
              borderWidth: 1,
              cornerRadius: 8,
              boxShadow: '0 4px 12px rgba(0,0,0,0.24)'
            },
            annotation: {
              annotations: {
                avgLine: {
                  type: 'line',
                  borderColor: 'rgba(255, 255, 255, 0.2)',
                  borderWidth: 1,
                  borderDash: [4, 4],
                  scaleID: 'r',
                  value: stats.reduce((a, b) => a + b, 0) / stats.length
                }
              }
            }
          },
          onHover: (event, elements) => {
            canvas.style.cursor = elements.length ? 'pointer' : 'default';
          }
        }
      });
    } catch (error) {
      this.showChartError(canvas.parentElement);
    }
  }

  // Utility to convert HEX to RGBA
  hexToRgba(hex, alpha = 1) {
    const [r, g, b] = hex.match(/\w\w/g).map(x => parseInt(x, 16));
    return `rgba(${r},${g},${b},${alpha})`;
  }

  // Abbreviate stat names
  getStatAbbreviation(statName) {
    const abbreviations = {
      hp: 'HP',
      attack: 'ATK',
      defense: 'DEF',
      'special-attack': 'SP.ATK',
      'special-defense': 'SP.DEF',
      speed: 'SPD'
    };
    return abbreviations[statName] || statName.slice(0, 3).toUpperCase();
  }

  // Display error if Chart.js fails
  showChartError(container) {
    container.innerHTML = `
      <div class="chart-error">
        <svg class="error-icon" viewBox="0 0 24 24" width="48" height="48">
          <path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
        </svg>
        <div class="error-message">
          <h4>Chart Unavailable</h4>
          <p>Failed to load stat visualization</p>
        </div>
      </div>
    `;
  }

  // TYPE INTERACTIONS SECTION
  createTypeRelationsGrid(data) {
    const section = document.createElement('section');
    section.className = 'type-relations-grid animate-fadeInUp';
    section.innerHTML = `<h3 class="section-title">TYPE INTERACTIONS</h3>`;
    const grid = document.createElement('div');
    grid.style.display = 'grid';
    grid.style.gridTemplateColumns =
      'repeat(auto-fit, minmax(160px, 1fr))';
    grid.style.gap = '12px';

    data.types.forEach(type => {
      const typeCard = document.createElement('div');
      typeCard.className = 'type-card';
      typeCard.innerHTML = `
        <div class="type-header">${type.type.name.toUpperCase()}</div>
        <div class="damage-relations">
          <div class="strengths">
            <h4>STRONG VS</h4>
            <div class="types-list"></div>
          </div>
          <div class="weaknesses">
            <h4>WEAK TO</h4>
            <div class="types-list"></div>
          </div>
        </div>
      `;
      const typeHeader = typeCard.querySelector('.type-header');
      typeHeader.style.background = this.getTypeColor(type.type.name);
      fetch(type.type.url)
        .then(res => res.json())
        .then(typeData => {
          const strengths = typeData.damage_relations.double_damage_to;
          const weaknesses = typeData.damage_relations.double_damage_from;
          strengths.forEach(t => {
            const badge = this.createTypeBadge(t.name);
            typeCard.querySelector('.strengths .types-list').appendChild(badge);
          });
          weaknesses.forEach(t => {
            const badge = this.createTypeBadge(t.name);
            typeCard.querySelector('.weaknesses .types-list').appendChild(badge);
          });
        });
      grid.appendChild(typeCard);
    });
    section.appendChild(grid);
    return section;
  }

  // Create a small type badge element
  createTypeBadge(typeName) {
    const badge = document.createElement('span');
    badge.className = 'type-badge small';
    badge.textContent = typeName.toUpperCase();
    badge.style.background = this.getTypeColor(typeName);
    badge.style.padding = '2px 8px';
    badge.style.borderRadius = '12px';
    badge.style.fontSize = '10px';
    return badge;
  }

  // Get a color based on the Pokémon type
  getTypeColor(typeName) {
    const typeColors = {
      normal: '#A8A878',
      fire: '#F08030',
      water: '#6890F0',
      electric: '#F8D030',
      grass: '#78C850',
      ice: '#98D8D8',
      fighting: '#C03028',
      poison: '#A040A0',
      ground: '#E0C068',
      flying: '#A890F0',
      psychic: '#F85888',
      bug: '#A8B820',
      rock: '#B8A038',
      ghost: '#705898',
      dragon: '#7038F8',
      dark: '#705848',
      steel: '#B8B8D0',
      fairy: '#EE99AC'
    };
    return typeColors[typeName] || '#68A090';
  }
// EVOLUTION CHAIN VISUALIZATION WITH MULTIPLE IMAGE SOURCES & FALLBACK HANDLING
createEvolutionVisualization(chain) {
  const section = document.createElement('section');
  section.className = 'evolution-chain animate-fadeInUp';
  section.innerHTML = `<h3 class="section-title">EVOLUTION LINE</h3>`;
  const stages = this.parseEvolutionChain(chain);
  const container = document.createElement('div');
  container.style.display = 'flex';
  container.style.justifyContent = 'center';
  container.style.gap = '0px';
  container.style.padding = '16px 0';

  stages.forEach((stage, index) => {
    const stageDiv = document.createElement('div');
    stageDiv.style.display = 'flex';
    stageDiv.style.flexDirection = 'column';
    stageDiv.style.alignItems = 'center';
    stageDiv.style.gap = '8px';

    if (index > 0) {
      const arrow = document.createElement('div');
      arrow.textContent = '→';
      arrow.style.fontSize = '24px';
      arrow.style.opacity = '0.6';
      container.appendChild(arrow);
    }
    const sprite = document.createElement('img');
    sprite.className = 'lazy';
    sprite.alt = stage.name;
    sprite.style.width = '64px';
    sprite.style.height = '64px';
    // Initially hidden until the image loads
    sprite.style.opacity = '0';

    // Attach onload event to reveal the image once it loads
    sprite.onload = () => {
      sprite.style.opacity = '1';
    };

    // Set multiple image sources and fallback handling
    const imageSources = [
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/showdown/${stage.id}.gif`, // Animated
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${stage.id}.png`, // Official
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/${stage.id}.svg`, // SVG
      `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${stage.id}.png`, // Default
      `https://via.placeholder.com/150x150?text=No+Image` // Placeholder
    ];

    let imgIndex = 0;
    function loadNextImage() {
      if (imgIndex >= imageSources.length) return;
      sprite.src = imageSources[imgIndex++];
      // If the current image fails to load, try the next one
      sprite.onerror = loadNextImage;
    }
    loadNextImage();

    const name = document.createElement('div');
    name.textContent = stage.name;
    name.style.fontWeight = '500';
    stageDiv.append(sprite, name);
    container.appendChild(stageDiv);
  });
  section.appendChild(container);
  // If you have a lazy loading observer, you may reinitialize it here:
  // this.initIntersectionObserver();
  return section;
}

// Recursively parse the evolution chain into an array of stages
parseEvolutionChain(chain, result = []) {
  const id = chain.species.url.split('/').slice(-2, -1)[0];
  result.push({ name: chain.species.name, id });
  if (chain.evolves_to.length > 0) {
    chain.evolves_to.forEach(e => this.parseEvolutionChain(e, result));
  }
  return result.filter((v, i, a) => a.findIndex(t => t.id === v.id) === i);
}


    }

    new PokeballHelper();
  })();