Steam Badge Info for Booster Creator

Injects badge information into the booster creator page using a user-defined ID. Includes a favorites list using IndexedDB and Steam-styled controls. Caches SteamSets API data using IndexedDB with a 1-week timeout. Adds import/export for favorites. Displays badge unlock date if available.

// ==UserScript==
// @name         Steam Badge Info for Booster Creator
// @namespace    https://github.com/encumber/
// @version      1.29
// @description  Injects badge information into the booster creator page using a user-defined ID. Includes a favorites list using IndexedDB and Steam-styled controls. Caches SteamSets API data using IndexedDB with a 1-week timeout. Adds import/export for favorites. Displays badge unlock date if available.
// @author       Nitoned
// @match        https://steamcommunity.com/tradingcards/boostercreator/*
// @match        https://steamcommunity.com//tradingcards/boostercreator/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_openInTab
// @grant        GM_notification
// @grant        indexedDB
// ==/UserScript==

// ====================================================================
// === USER CONFIGURATION - EDIT THESE VALUES BEFORE SAVING SCRIPT ===
// ====================================================================

// IMPORTANT: Replace the placeholder value below with your actual Steam ID.
// This can be your custom URL name (e.g., 'myprofile') or your SteamID64 (e.g., '76561198012345678').
const USER_STEAM_ID = "client"; // <--- PUT YOUR STEAM ID HERE

// steamsets api key for listing all badge icons
// If you are getting 401 errors, double-check your key on the SteamSets website.
// It's possible the key expired, was revoked, or you copied it correctly.
const SteamSetsAPI = ""; // <--- PUT YOUR SteamSets API KEY HERE

// Set this to 'true' if the USER_STEAM_ID you entered is a SteamID64.
// Set this to 'false' if the USER_STEAM_ID you entered is a custom URL name.
const STEAM_ID_IS_STEAMID64 = false; // <--- SET TO true FOR STEAMID64, false FOR CUSTOM URL NAME

// Set this to 'true' to enable detailed logging messages in your browser's console.
// Set this to 'false' to disable all console logs from this script.
const ENABLE_CONSOLE_LOGS = true; // <--- SET TO true OR false FOR LOGGING - KEEP TRUE FOR NOW

// Default sort order for favorites ('appid_asc', 'appid_desc', 'foil_first', 'foil_last')
// This is saved using GM_setValue/GM_getValue
let currentFavoritesSortOrder = GM_getValue('favoritesSortOrder', 'appid_asc'); // Load saved sort order

// Cache timeout for SteamSets API data in milliseconds (1 week)
const API_CACHE_TIMEOUT_MS = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds

// ====================================================================
// === END USER CONFIGURATION - DO NOT EDIT BELOW THIS LINE UNLESS ===
// === YOU UNDERSTAND THE CODE                                     ===
// ====================================================================

(function() {
    'use strict';

    // --- Logging Helper ---
    function log(...args) {
        if (ENABLE_CONSOLE_LOGS) {
            console.log('[Steam Badge Info]', ...args);
        }
    }

    function logError(...args) {
         if (ENABLE_CONSOLE_LOGS) {
            console.error('[Steam Badge Info]', ...args);
        }
     }
    function logWarn(...args) {
         if (ENABLE_CONSOLE_LOGS) {
            console.warn('[Steam Badge Info]', ...args);
        }
     }
    function logDebug(...args) {
        if (ENABLE_CONSOLE_LOGS) {
            console.debug('[Steam Badge Info Debug]', ...args);
        }
    }
    // --- End Logging Helper ---

    // --- Global State for Scroll Back ---
    let scrollPositionBeforeUpdate = 0;
    let clickedFavoriteAppId = null; // Store the app ID of the clicked favorite
    let clickedFavoriteIsFoil = null; // Store the foil status of the clicked favorite
    // --- End Global State ---


    // --- IndexedDB Setup ---
    const DB_NAME = 'SteamBadgeCache';
    const API_CACHE_STORE_NAME = 'steamSetsBadges';
    const FAVORITES_STORE_NAME = 'favorites'; // New store for favorites
    const DB_VERSION = 2; // Version 2 includes the 'favorites' store
    let db = null;

    function openDatabase() {
        return new Promise((resolve, reject) => {
            if (db) {
                logDebug('Database already open, resolving.');
                resolve(db);
                return;
            }

            // Explicitly access indexedDB from the window object
            const browserIndexedDB = window.indexedDB || window.mozIndexedIndexedDB || window.webkitIndexedIndexedDB || window.msIndexedIndexedDB;

            if (!browserIndexedDB) {
                const error = new Error('IndexedDB is not supported in this environment.');
                logError('IndexedDB not supported:', error);
                reject(error);
                return;
            }

            logDebug(`Opening IndexedDB: ${DB_NAME} (Version ${DB_VERSION})`);
            const request = browserIndexedDB.open(DB_NAME, DB_VERSION);

            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                logDebug(`IndexedDB upgrade needed: oldVersion=${event.oldVersion}, newVersion=${event.newVersion}`);

                // Create object store for API cache if it doesn't exist
                if (!db.objectStoreNames.contains(API_CACHE_STORE_NAME)) {
                    const apiStore = db.createObjectStore(API_CACHE_STORE_NAME, { keyPath: 'appId' });
                    logDebug(`IndexedDB upgrade: store "${API_CACHE_STORE_NAME}" created.`);
                } else {
                     logDebug(`IndexedDB upgrade: store "${API_CACHE_STORE_NAME}" already exists.`);
                }

                 // Create object store for favorites if it doesn't exist
                 if (!db.objectStoreNames.contains(FAVORITES_STORE_NAME)) {
                     // Favorites need a unique key, combination of appId and isFoil
                     const favoritesStore = db.createObjectStore(FAVORITES_STORE_NAME, { keyPath: 'id' });
                      // We can add indexes for easier querying if needed later, e.g., by appId
                      // favoritesStore.createIndex('appId', 'appId', { unique: false });
                      // favoritesStore.createIndex('isFoil', 'isFoil', { unique: false });
                     logDebug(`IndexedDB upgrade: store "${FAVORITES_STORE_NAME}" created.`);
                 } else {
                      logDebug(`IndexedDB upgrade: store "${FAVORITES_STORE_NAME}" already exists.`);
                 }
                 logDebug('IndexedDB upgrade finished.');
            };

            request.onsuccess = (event) => {
                db = event.target.result;
                logDebug('IndexedDB opened successfully.');
                resolve(db);
            };

            request.onerror = (event) => {
                logError('IndexedDB error:', event.target.error);
                reject(event.target.error);
            };
        });
    }

    // --- API Cache Functions ---

    async function getCachedData(appId) {
        try {
            logDebug(`Attempting to get cached data for App ID ${appId}.`);
            const database = await openDatabase(); // <-- Ensure this resolves
            logDebug(`Database opened for getting cached data for App ID ${appId}.`);
            const transaction = database.transaction(API_CACHE_STORE_NAME, 'readonly');
            const store = transaction.objectStore(API_CACHE_STORE_NAME);
            const request = store.get(parseInt(appId));

            return new Promise((resolve, reject) => {
                request.onsuccess = (event) => {
                    const cachedItem = event.target.result;
                    if (cachedItem) {
                        const now = Date.now();
                        if (now - cachedItem.timestamp < API_CACHE_TIMEOUT_MS) {
                            logDebug(`API Cache hit for App ID ${appId}. Data is fresh.`);
                            resolve(cachedItem.data);
                        } else {
                            logDebug(`API Cache hit for App ID ${appId}, but data is stale. Will re-fetch.`);
                            resolve(null); // Data is stale
                        }
                    } else {
                         logDebug(`API Cache miss for App ID ${appId}.`);
                         resolve(null); // No cached item found
                    }
                };
                request.onerror = (event) => {
                    logError('Error getting data from API cache IndexedDB request:', event.target.error);
                    // Crucially, reject the promise here so the catch block in fetchAndDisplayBadgeList is triggered
                    reject(event.target.error);
                };
            });
        } catch (error) {
            logError('Error opening IndexedDB for API cache get:', error);
            // Crucially, re-throw or reject here so the catch block in fetchAndDisplayBadgeList is triggered
            throw error; // Re-throw the error
        }
    }

    async function cacheData(appId, data) {
        try {
            logDebug(`Attempting to cache data for App ID ${appId}.`);
            const database = await openDatabase(); // <-- Ensure this resolves
             logDebug(`Database opened for caching data for App ID ${appId}.`);
            const transaction = database.transaction(API_CACHE_STORE_NAME, 'readwrite');
            const store = transaction.objectStore(API_CACHE_STORE_NAME);
            const itemToCache = {
                appId: parseInt(appId),
                timestamp: Date.now(),
                data: data
            };
            const request = store.put(itemToCache);

            return new Promise((resolve, reject) => {
                request.onsuccess = () => {
                    logDebug(`Data for App ID ${appId} cached successfully.`);
                    resolve();
                };
                request.onerror = (event) => {
                    logError('Error caching data in API cache IndexedDB request:', event.target.error);
                     // Crucially, reject the promise here
                    reject(event.target.error);
                };
                 // Add transaction completion handler for additional logging
                 transaction.oncomplete = () => {
                     logDebug(`API cache transaction for App ID ${appId} completed.`);
                 };
                 transaction.onerror = (event) => {
                      logError(`API cache transaction for App ID ${appId} failed:`, event.target.error);
                 };
                 transaction.onabort = (event) => {
                      logWarn(`API cache transaction for App ID ${appId} aborted:`, event.target.error);
                 };
            });
        } catch (error) {
            logError('Error opening IndexedDB for API cache:', error);
             // Crucially, re-throw or reject here
            throw error; // Re-throw the error
        }
    }


     async function clearStaleApiCache() {
         try {
             const database = await openDatabase();
             const transaction = database.transaction(API_CACHE_STORE_NAME, 'readwrite');
             const store = transaction.objectStore(API_CACHE_STORE_NAME);
             const now = Date.now();

             const request = store.openCursor();
             request.onsuccess = (event) => {
                 const cursor = event.target.result;
                 if (cursor) {
                     if (now - cursor.value.timestamp > API_CACHE_TIMEOUT_MS) {
                         logDebug(`Deleting stale API cache for App ID ${cursor.value.appId}`);
                         cursor.delete();
                     }
                     cursor.continue();
                 } else {
                     logDebug('Finished clearing stale API cache.');
                 }
             };
             request.onerror = (event) => {
                 logError('Error clearing stale API cache:', event.target.error);
             };
         } catch (error) {
             logError('Error opening IndexedDB for clearing stale API cache:', error);
         }
     }


    // --- Favorites Functions (using IndexedDB) ---

    async function getFavorites() {
        logDebug('Attempting to get favorites from IndexedDB...');
        try {
            const database = await openDatabase();
            const transaction = database.transaction(FAVORITES_STORE_NAME, 'readonly');
            const store = transaction.objectStore(FAVORITES_STORE_NAME);
            const request = store.getAll(); // Get all items

            return new Promise((resolve, reject) => {
                request.onsuccess = (event) => {
                    const favorites = event.target.result || [];
                    logDebug('Successfully fetched favorites from IndexedDB:', favorites);
                    resolve(favorites);
                };
                request.onerror = (event) => {
                    logError('Error getting favorites from IndexedDB request:', event.target.error);
                    reject(event.target.error);
                };
            });
        } catch (error) {
            logError('Error opening IndexedDB for getting favorites:', error);
            // Resolve with empty array if database opening fails
            return [];
        }
    }

    async function toggleFavorite(badgeData) {
        logDebug('Attempting to toggle favorite:', badgeData);
        const favoriteId = `${badgeData.appId}_${badgeData.isFoil ? 'foil' : 'regular'}`;
        logDebug(`Generated favorite ID: ${favoriteId}`);

        try {
            const database = await openDatabase();
            const transaction = database.transaction(FAVORITES_STORE_NAME, 'readwrite');
            const store = transaction.objectStore(FAVORITES_STORE_NAME);

            const getRequest = store.get(favoriteId); // Check if it exists

            getRequest.onsuccess = async (event) => {
                const existingFavorite = event.target.result;
                logDebug(`IndexedDB get result for ID ${favoriteId}:`, existingFavorite);

                if (existingFavorite) {
                    // Item exists, remove it
                    logDebug(`Favorite ${favoriteId} exists, attempting to delete.`);
                    const deleteRequest = store.delete(favoriteId);
                    deleteRequest.onsuccess = () => {
                         log(`Removed favorite: App ID ${badgeData.appId}, Foil: ${badgeData.isFoil}`);
                         displayFavorites(); // Refresh the displayed list
                    };
                    deleteRequest.onerror = (event) => {
                         logError('Error deleting favorite:', event.target.error);
                         // Even on delete error, try to refresh display
                         displayFavorites();
                    };
                } else {
                    // Item does not exist, add it
                    logDebug(`Favorite ${favoriteId} does not exist, attempting to add.`);
                    const newFavorite = {
                        id: favoriteId, // Add the unique ID
                        appId: badgeData.appId,
                        name: badgeData.name || 'Unknown Badge',
                        imageUrl: badgeData.imageUrl,
                        isFoil: badgeData.isFoil // Should already be boolean from createBadgeListItem
                    };
                     logDebug('New favorite data to add:', newFavorite);
                    const putRequest = store.put(newFavorite);
                    putRequest.onsuccess = () => {
                        log(`Added favorite: App ID ${badgeData.appId}, Foil: ${badgeData.isFoil}`);
                        displayFavorites(); // Refresh the displayed list
                    };
                     putRequest.onerror = (event) => {
                         logError('Error adding favorite:', event.target.error);
                          // Even on add error, try to refresh display
                         displayFavorites();
                     };
                }
            };

            getRequest.onerror = (event) => {
                 logError('Error checking for existing favorite in IndexedDB:', event.target.error);
                 // If checking fails, we can't proceed, but let's still try to display current state
                 displayFavorites();
            };

        } catch (error) {
            logError('Error opening IndexedDB for toggling favorite:', error);
            // If opening fails, we can't proceed, but let's still try to display current state
            displayFavorites();
        }
    }


     function sortFavorites(favorites, order) {
        switch (order) {
            case 'appid_asc':
                return favorites.sort((a, b) => parseInt(a.appId) - parseInt(b.appId));
            case 'appid_desc':
                return favorites.sort((a, b) => parseInt(b.appId) - parseInt(a.appId));
            case 'foil_first':
                // Changed sort order based on the dropdown text
                return favorites.sort((a, b) => {
                    if (a.isFoil !== b.isFoil) {
                        return a.isFoil ? -1 : 1; // true (foil) comes before false (non-foil)
                    }
                    return parseInt(a.appId) - parseInt(b.appId); // Secondary sort by appid
                });
            case 'foil_last':
                 // Changed sort order based on the dropdown text
                 return favorites.sort((a, b) => {
                    if (a.isFoil !== b.isFoil) {
                        return a.isFoil ? 1 : -1; // false (non-foil) comes before true (foil)
                    }
                    return parseInt(a.appId) - parseInt(a.appId); // Secondary sort by appid
                });
            default:
                return favorites; // Default to appid_asc if unknown order
        }
     }


        async function displayFavorites() {
        logDebug('Attempting to display favorites...');
        const favoritesContainer = document.querySelector('.favorites-container');
        if (!favoritesContainer) {
            logWarn('Favorites container not found. Cannot display favorites.');
            return;
        }

        // Find or create the items wrapper
        let itemsWrapper = favoritesContainer.querySelector('.favorites-items-wrapper');
        if (!itemsWrapper) {
             logDebug('Favorites items wrapper not found, creating.');
            itemsWrapper = document.createElement('div');
            itemsWrapper.className = 'favorites-items-wrapper';
            favoritesContainer.appendChild(itemsWrapper);
        }
         itemsWrapper.innerHTML = ''; // Clear current items

        try {
            const favorites = await getFavorites(); // Get favorites asynchronously
            logDebug(`Fetched ${favorites.length} favorites for display.`);
            const sortedFavorites = sortFavorites([...favorites], currentFavoritesSortOrder); // Sort a copy

            if (sortedFavorites.length === 0) {
                itemsWrapper.textContent = 'No favorites added yet. Click a badge below to add it!';
                 itemsWrapper.style.color = '#B8B6B4';
                 itemsWrapper.style.textAlign = 'center';
                 itemsWrapper.style.width = '100%';
                 itemsWrapper.style.marginTop = '10px';
                 itemsWrapper.style.minHeight = '100px'; // Give it a minimum height even when empty
            } else {
                 itemsWrapper.style.color = ''; // Reset styles
                 itemsWrapper.style.textAlign = '';
                 itemsWrapper.style.width = '';
                 itemsWrapper.style.marginTop = '';
                 itemsWrapper.style.minHeight = ''; // Remove min-height when populated

                sortedFavorites.forEach(fav => {
                    itemsWrapper.appendChild(createFavoriteItemElement(fav));
                });
            }
             logDebug(`Successfully displayed ${sortedFavorites.length} favorites.`);

             // After displaying favorites, check if we need to scroll back
             // Add a 1-second delay before attempting to scroll
             if (clickedFavoriteAppId !== null) {
                 logDebug('Clicked favorite detected. Waiting 1 second before scrolling back.');
                 setTimeout(() => {
                     scrollToClickedFavorite();
                 }, 1000); // 1000 milliseconds = 1 second
             }


        } catch (error) {
             logError('Error displaying favorites:', error);
             itemsWrapper.textContent = 'Error loading favorites.';
             itemsWrapper.style.color = 'red';
             itemsWrapper.style.textAlign = 'center';
             itemsWrapper.style.width = '100%';
             itemsWrapper.style.marginTop = '10px';
              itemsWrapper.style.minHeight = '100px'; // Give it a minimum height
        }
    }

     function scrollToClickedFavorite() {
         if (clickedFavoriteAppId === null) {
             logDebug('No favorite item click recorded to scroll back to.');
             return;
         }

         logDebug(`Attempting to scroll back to favorite App ID ${clickedFavoriteAppId}, Foil: ${clickedFavoriteIsFoil}`);

         // Find the element corresponding to the clicked favorite
         const selector = `.favorite-item[data-appid="${clickedFavoriteAppId}"][data-is-foil="${clickedFavoriteIsFoil}"]`;
         const clickedElement = document.querySelector(selector);

         if (clickedElement) {
             logDebug('Found clicked favorite element, scrolling into view.');
             // Use scrollIntoView with options for smoother scrolling
             clickedElement.scrollIntoView({
                 behavior: 'smooth', // Use smooth scrolling
                 block: 'center'    // Align the element to the center of the viewport
             });
         } else {
             logWarn(`Clicked favorite element not found after update: ${selector}`);
             // If the element wasn't found (e.g., it was just deleted),
             // we could potentially scroll back to the saved scroll position,
             // but scrolling into view of the item is generally better.
             // For now, just log a warning.
         }

         // Reset the global state after attempting to scroll
         clickedFavoriteAppId = null;
         clickedFavoriteIsFoil = null;
         scrollPositionBeforeUpdate = 0; // Reset scroll position too
     }


    // --- Import/Export Functions ---

    async function exportFavorites() {
        logDebug('Attempting to export favorites...');
        try {
            const favorites = await getFavorites();
            // Exclude the 'id' field for cleaner export, as it's derived
            const exportableFavorites = favorites.map(fav => ({
                 appId: fav.appId,
                 name: fav.name,
                 imageUrl: fav.imageUrl,
                 isFoil: fav.isFoil
            }));
            const jsonString = JSON.stringify(exportableFavorites, null, 2); // Pretty print JSON

            // Display the JSON to the user
            displayExportJson(jsonString);

        } catch (error) {
            logError('Error exporting favorites:', error);
            alert('Error exporting favorites. Check console for details.');
        }
    }

    function displayExportJson(jsonString) {
        // Create a modal-like overlay or inject into a dedicated area
        let exportArea = document.getElementById('favorites-export-area');
        if (!exportArea) {
            exportArea = document.createElement('div');
            exportArea.id = 'favorites-export-area';
            exportArea.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                z-index: 1000;
                background: #1b2838; /* Steam dark background */
                border: 1px solid #333;
                padding: 20px;
                border-radius: 5px;
                box-shadow: 0 0 20px rgba(0,0,0,0.5);
                color: #B8B6B4;
                width: 80%;
                max-width: 600px;
                max-height: 80%;
                overflow-y: auto;
            `;
            document.body.appendChild(exportArea);

            const closeButton = document.createElement('span');
            closeButton.textContent = 'X';
            closeButton.style.cssText = `
                position: absolute;
                top: 10px;
                right: 10px;
                font-size: 18px;
                cursor: pointer;
                color: #B8B6B4;
            `;
            closeButton.onclick = () => exportArea.remove();
            exportArea.appendChild(closeButton);

             const title = document.createElement('h3');
             title.textContent = 'Exported Favorites (Copy Below)';
             title.style.color = '#8BC53F';
             title.style.marginTop = '0';
             exportArea.appendChild(title);

            const textArea = document.createElement('textarea');
            textArea.style.cssText = `
                width: 100%;
                height: 200px;
                margin-top: 10px;
                background: #000;
                color: #B8B6B4;
                border: 1px solid #333;
                padding: 10px;
                resize: vertical;
                font-family: monospace;
            `;
            textArea.value = jsonString;
            exportArea.appendChild(textArea);

             // Select text on focus for easy copying
             textArea.onfocus = () => {
                 textArea.select();
             };
             // Also select on click for mobile or quick copy
             textArea.onclick = () => {
                  textArea.select();
             };


        } else {
             // If area already exists, just update the text area content
             const textArea = exportArea.querySelector('textarea');
             if (textArea) {
                 textArea.value = jsonString;
                 textArea.focus();
                 textArea.select(); // Select for easy copying
             }
             exportArea.style.display = 'block'; // Show if hidden
        }
    }


    function showImportArea() {
         // Create a modal-like overlay or inject into a dedicated area
         let importArea = document.getElementById('favorites-import-area');
         if (!importArea) {
             importArea = document.createElement('div');
             importArea.id = 'favorites-import-area';
             importArea.style.cssText = `
                 position: fixed;
                 top: 50%;
                 left: 50%;
                 transform: translate(-50%, -50%);
                 z-index: 1000;
                 background: #1b2838; /* Steam dark background */
                 border: 1px solid #333;
                 padding: 20px;
                 border-radius: 5px;
                 box-shadow: 0 0 20px rgba(0,0,0,0.5);
                 color: #B8B6B4;
                 width: 80%;
                 max-width: 600px;
                 max-height: 80%;
                 overflow-y: auto;
             `;
             document.body.appendChild(importArea);

             const closeButton = document.createElement('span');
             closeButton.textContent = 'X';
             closeButton.style.cssText = `
                 position: absolute;
                 top: 10px;
                 right: 10px;
                 font-size: 18px;
                 cursor: pointer;
                 color: #B8B6B4;
             `;
             closeButton.onclick = () => importArea.remove();
             importArea.appendChild(closeButton);

             const title = document.createElement('h3');
             title.textContent = 'Import Favorites (Paste JSON Below)';
             title.style.color = '#8BC53F';
             title.style.marginTop = '0';
             importArea.appendChild(title);

             const textArea = document.createElement('textarea');
             textArea.id = 'favorites-import-textarea';
             textArea.style.cssText = `
                 width: 100%;
                 height: 200px;
                 margin-top: 10px;
                 background: #000;
                 color: #B8B6B4;
                 border: 1px solid #333;
                 padding: 10px;
                 resize: vertical;
                 font-family: monospace;
             `;
             importArea.appendChild(textArea);

             const importButton = document.createElement('button');
             importButton.className = 'btn_green_steamui btn_medium'; // Steam button style
             importButton.style.marginTop = '15px';
             importButton.textContent = 'Import Favorites';
             importButton.onclick = () => importFavoritesFromTextarea();
             importArea.appendChild(importButton);

             const warning = document.createElement('p');
              warning.style.fontSize = '11px';
              warning.style.color = '#ff6600'; // Orange color
              warning.textContent = 'Warning: Importing favorites will add them to your existing list. Duplicate items will be updated.';
              importArea.appendChild(warning);

         } else {
              // If area already exists, clear textarea and show
              const textArea = importArea.querySelector('textarea');
              if (textArea) {
                  textArea.value = '';
              }
              importArea.style.display = 'block'; // Show if hidden
         }
    }


    async function importFavoritesFromTextarea() {
        logDebug('Attempting to import favorites from textarea...');
        const importArea = document.getElementById('favorites-import-area');
        const textArea = document.getElementById('favorites-import-textarea');
        if (!textArea || !importArea) {
            logError('Import area or textarea not found.');
            return;
        }

        const jsonString = textArea.value.trim();
        if (!jsonString) {
            alert('Please paste the JSON data into the text area.');
            return;
        }

        try {
            const importedData = JSON.parse(jsonString);

            if (!Array.isArray(importedData)) {
                alert('Import failed: Data is not a valid JSON array.');
                logError('Import failed: Data is not an array.', importedData);
                return;
            }

            const validFavorites = importedData.filter(item =>
                item &&
                (typeof item.appId === 'number' || typeof item.appId === 'string') &&
                typeof item.name === 'string' &&
                typeof item.imageUrl === 'string' &&
                typeof item.isFoil === 'boolean'
            ).map(item => ({
                 // Ensure appId is string for consistency with ID generation
                 appId: String(item.appId),
                 name: item.name,
                 imageUrl: item.imageUrl,
                 isFoil: item.isFoil,
                 // Re-generate the ID for consistency and uniqueness in the DB
                 id: `${String(item.appId)}_${item.isFoil ? 'foil' : 'regular'}`
            }));

            if (validFavorites.length === 0) {
                alert('Import failed: No valid favorite items found in the data.');
                logError('Import failed: No valid favorite items found after filtering.', importedData);
                return;
            }

            logDebug(`Attempting to add ${validFavorites.length} valid favorites to IndexedDB.`);

            const database = await openDatabase();
            const transaction = database.transaction(FAVORITES_STORE_NAME, 'readwrite');
            const store = transaction.objectStore(FAVORITES_STORE_NAME);

            let addedCount = 0;
            let errorCount = 0;

            validFavorites.forEach(fav => {
                const request = store.put(fav); // Use put to add or update
                request.onsuccess = () => {
                     addedCount++;
                };
                request.onerror = (event) => {
                    logError(`Error adding/updating favorite ${fav.id} during import:`, event.target.error);
                    errorCount++;
                };
            });

             transaction.oncomplete = () => {
                 log(`Import transaction complete. Processed: ${validFavorites.length}, Errors: ${errorCount}`);
                 alert(`Import complete!\nProcessed: ${validFavorites.length}\nErrors: ${errorCount}\n(Note: Existing items with the same App ID and Foil status were updated.)`);
                 importArea.remove(); // Close modal after import
                 displayFavorites(); // Refresh displayed list
             };
             transaction.onerror = (event) => {
                 logError('Import transaction failed:', event.target.error);
                 alert(`Import failed: Transaction error. Check console.`);
                 // Keep modal open to show error? Or close? Let's close for now.
                 importArea.remove();
                 displayFavorites(); // Still try to refresh display
             };
             transaction.onabort = (event) => {
                 logWarn('Import transaction aborted:', event.target.error);
                 alert(`Import aborted. Check console.`);
                 importArea.remove();
                 displayFavorites(); // Still try to refresh display
             };


        } catch (error) {
            logError('Error parsing or processing imported JSON:', error);
            alert(`Import failed: Invalid JSON format or processing error.\nDetails: ${error.message}. Check console for more details.`);
        }
    }


    // --- End Import/Export Functions ---


    const style = `
        .badge-container {
            display: flex;
            gap: 40px;
            margin-top: 20px;
            padding: 10px;
            background: rgba(0, 0, 0, 0.2);
            border-radius: 3px;
            justify-content: center;
            min-height: 180px; /* Placeholder height for badge container */
            align-items: center; /* Center content vertically during loading */
        }

        .badge-list-container, .favorites-container {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
            padding: 10px;
            background: rgba(0, 0, 0, 0.2);
            border-radius: 3px;
            justify-content: flex-start; /* Align items to the start */
            flex-wrap: wrap;
            align-items: flex-start; /* Align rows to the start */
            min-height: 200px; /* Placeholder height for list containers */
            align-content: flex-start; /* Align rows to the start during loading */
        }

        .favorites-container {
            margin-top: 20px; /* Space above favorites */
            flex-direction: column; /* Stack controls and items */
        }

        .favorites-controls {
             display: flex;
             gap: 10px;
             margin-bottom: 10px;
             align-items: center;
             flex-wrap: wrap; /* Allow controls to wrap on smaller screens */
             /* Added to push groups to edges */
             justify-content: space-between;
             width: 100%; /* Ensure it takes full width */
        }

        /* Group sort controls */
        .favorites-controls .sort-group {
            display: flex;
            gap: 10px;
            align-items: center;
        }

        /* Group import/export buttons */
         .favorites-controls .button-group {
            display: flex;
            gap: 10px;
            align-items: center;
         }


        .favorites-controls label {
            color: #B8B6B4;
            font-size: 12px;
        }

         /* --- Steam-like Dropdown Styling --- */
        .favorites-controls .btn_grey_black {
            padding: 0 8px; /* Adjust padding */
            height: 24px; /* Adjust height */
            line-height: 24px; /* Center text vertically */
            font-size: 12px; /* Match label font size */
            position: relative; /* Needed for arrow positioning */
            cursor: pointer;
            background: linear-gradient( to right, #333, #444 ); /* Darker gradient */
            border-radius: 3px;
            border: none; /* Remove default border */
            color: #B8B6B4;
            text-shadow: none; /* Remove default text shadow */
            /* Added min-width to ensure text visibility */
            min-width: 150px; /* Adjust as needed based on longest option text */
            display: inline-block; /* Ensure it behaves like a block for width */
            box-sizing: border-box; /* Include padding and border in element's total width and height */
        }

        .favorites-controls .btn_grey_black select {
            -webkit-appearance: none; /* Remove default dropdown arrow */
            -moz-appearance: none;
            appearance: none;
            background: transparent; /* Make select background transparent */
            border: none;
            padding: 0;
            margin: 0;
            color: #B8B6B4;
            font-size: 12px;
            cursor: pointer;
            outline: none; /* Remove focus outline */
            width: 100%; /* Take full width of parent button */
            height: 100%; /* Take full height of parent button */
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 2; /* Place select above the custom arrow */
             padding-right: 20px; /* Add padding on the right to make space for the arrow */
        }

        /* Custom arrow */
        .favorites-controls .btn_grey_black::after {
            content: '▼'; /* Unicode down arrow */
            position: absolute;
            top: 50%;
            right: 5px; /* Position arrow */
            transform: translateY(-50%);
            font-size: 8px; /* Smaller arrow */
            color: #B8B6B4;
            pointer-events: none; /* Allow clicks to pass through to select */
            z-index: 1; /* Place arrow below select */
        }

        /* Hover effect for the button */
        .favorites-controls .btn_grey_black:hover {
            background: linear-gradient( to right, #444, #555 ); /* Lighter gradient on hover */
            color: #CFCFCF;
        }

        /* Focus effect for the button */
        .favorites-controls .btn_grey_black:focus-within {
             outline: 1px solid #8BC53F; /* Green outline on focus */
        }

         .favorites-controls .btn_grey_black option {
             background-color: #333; /* Background for dropdown options */
             color: #B8B6B4;
         }

        /* --- End Steam-like Dropdown Styling --- */

         /* --- Import/Export Button Styling --- */
         .favorites-controls .steam-button {
             display: inline-block;
             padding: 0 15px;
             height: 24px;
             line-height: 24px;
             font-size: 12px;
             text-decoration: none;
             text-align: center;
             cursor: pointer;
             border-radius: 3px;
             border: none;
             color: #B8B6B4;
             background: linear-gradient( to right, #333, #444 );
             box-sizing: border-box;
         }

         .favorites-controls .steam-button:hover {
             background: linear-gradient( to right, #444, #555 );
             color: #CFCFCF;
         }

         .favorites-controls .steam-button:active {
             background: linear-gradient( to right, #222, #333 );
             color: #B8B6B4;
         }
        /* --- End Import/Export Button Styling --- */


        .favorites-items-wrapper {
            display: flex;
            flex-wrap: wrap;
            gap: 20px; /* Gap between items */
            width: 100%; /* Take full width of container */
        }

        .badge-box, .badge-list-box, .favorite-item {
            flex: 0 0 calc(16.666% - 17px); /* Calculate width for 6 items per row, adjusting for gap */
            text-align: center;
            padding: 15px;
            border-radius: 5px;
            background: rgba(0, 0, 0, 0.1);
            min-width: 100px;
            max-width: 150px;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: center;
            cursor: pointer; /* Indicate clickable */
            transition: background-color 0.2s ease; /* Smooth hover effect */
        }

         .favorite-item {
             flex: 0 0 calc(16.666% - 17px); /* Ensure 6 items per row */
             cursor: pointer;
         }

        .badge-box:hover, .badge-list-box:hover, .favorite-item:hover {
            background-color: rgba(255, 255, 255, 0.05); /* Subtle hover effect */
        }


        .badge-box.foil, .badge-list-box.foil, .favorite-item.foil {
            background: linear-gradient(
                45deg,
                rgba(0, 0, 0, 0.1) 0%,
                rgba(255, 255, 255, 0.1) 50%,
                rgba(0, 0, 0, 0.1) 100%
            );
            animation: shine 3000s linear infinite;
            border: 1px solid rgba(255, 255, 255, 0.1);
            box-shadow: 0 0 15px rgba(255, 255, 245, 0.1);
        }
        @keyframes shine {
            0% {
                background-position: -200% center;
            }
            100% {
                background-position: 200% center;
            }
        }
        .badge-title, .badge-list-title, .favorite-title {
            margin-bottom: 10px;
            color: #8BC53F;
            font-weight: bold;
            font-size: 14px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            width: 100%;
        }
        .badge-image, .badge-list-image, .favorite-image {
            max-width: 100%;
            height: auto;
            display: block;
            margin: 0 auto;
            flex-shrink: 0;
        }
        .badge_empty_circle, .badge_list_empty_circle, .favorite_empty_circle {
            width: 80px;
            height: 80px;
            background: rgba(0, 0, 0, 0.2);
            border-radius: 50%;
            margin: 0 auto;
             flex-shrink: 0;
        }

        .badge-link, .badge-list-link, .favorite-link {
            text-decoration: none;
            color: inherit;
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            min-height: 80px;
            box-sizing: border-box;
            margin-bottom: 5px;
        }

        .badge-level, .badge-list-scarcity, .favorite-appid {
            margin-top: 10px;
            color: #B8B6B4;
            font-size: 12px;
        }
         .badge-list-level { /* New style for level in the list */
            margin-top: 4px;
            color: #8BC53F;
            font-size: 11px;
         }
         .foil .badge-list-level {
             color: #CFE6F5;
         }

        .badge-link:hover, .badge-list-link:hover {
            opacity: 0.8;
        }
        .foil .badge-title, .foil .badge-list-title, .foil .favorite-title {
            color: #CFE6F5;
            text-shadow: 0 0 5px rgba(207, 230, 245, 0.5);
        }
        .badge-progress {
            margin-top: 8px;
            color: #B8B6B4;
            font-size: 12px;
        }
        .badge-sets {
            margin-top: 4px;
            color: #8BC53F;
            font-size: 12px;
        }
        .foil .badge-sets {
            color: #CFE6F5;
        }
        .badge-list-scarcity, .favorite-appid {
            margin-top: auto;
            font-size: 11px;
            color: #B8B6B4;
        }

        /* New style for unlocked info */
        .badge-unlocked {
            margin-top: 4px; /* Space below progress */
            color: #B8B6B4;
            font-size: 11px; /* Slightly smaller font */
        }


        /* Styles for Import/Export Modals */
        #favorites-export-area, #favorites-import-area {
             /* Added styles in the JS function for positioning and basics */
             /* Add more specific styles here if needed */
        }

    `;

    function addStyle(css) {
        const styleSheet = document.createElement("style");
        styleSheet.textContent = css;
        // Ensure document.head is available before appending
        if (document.head) {
            document.head.appendChild(styleSheet);
        } else {
            // Fallback if head is not available immediately
            document.documentElement.appendChild(styleSheet);
        }
    }

    function getAppId() {
        const url = window.location.href;
        const match = url.match(/\d+$/);
        return match ? match[0] : null;
    }

    function parseBadgeData(html, isFoil, userId, isSteamId64, appId) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');

        // Find the main badge info container first for more precise selection
        // Look for a common parent like .badge_row or .badge_info
        const mainBadgeInfoArea = doc.querySelector('.badge_row, .badge_info'); // Use comma to try multiple selectors
        const context = mainBadgeInfoArea || doc; // Use the main area if found, otherwise the whole doc

        const badgeImage = context.querySelector('.badge_info_image .badge_icon');
        const badgeName = context.querySelector('.badge_info_title');
        const badgeLevel = context.querySelector('.badge_info_description'); // This might contain "Level X" or other text

         // <--- Refined: Get unlocked element within the badge_empty_right div inside the context --->
         const badgeEmptyRight = context.querySelector('.badge_empty_right');
         const badgeUnlocked = badgeEmptyRight ? badgeEmptyRight.querySelector('.badge_info_unlocked') : null;
         // <--- End Refined --->


        const cardElements = doc.querySelectorAll('.badge_card_set_card'); // Card elements are usually in the same doc
        const cardQuantities = [];
        const cardInfo = []; // To store card name and quantity together

        cardElements.forEach(cardElement => {
            const qtyElement = cardElement.querySelector('.badge_card_set_text_qty');
            const nameElement = cardElement.querySelector('.badge_card_set_text_cardname');

            const quantityMatch = qtyElement ? qtyElement.textContent.match(/\((\d+)\)/) : null;
            const quantity = quantityMatch ? parseInt(quantityMatch[1]) : 0; // Treat empty quantity as 0
            cardQuantities.push(quantity);

            const name = nameElement ? nameElement.textContent.trim() : 'Unknown Card';
            cardInfo.push({ name: name, quantity: quantity });
        });

        logDebug(`${isFoil ? 'Foil' : 'Regular'} Badge Cards Found:`);
        logDebug(cardInfo); // Use logDebug for potentially large data

        const totalCards = cardElements.length;
        const completeSets = cardQuantities.length > 0 ? Math.min(...cardQuantities) : 0;
        const ownedCards = cardQuantities.filter(qty => qty > 0).length;

        logDebug(`${isFoil ? 'Foil' : 'Regular'} Badge Summary:`);
        logDebug(`  Total Cards in Set: ${totalCards}`);
        logDebug(`  Owned Card Types: ${ownedCards}`);
        logDebug(`  Complete Sets: ${completeSets}`);

        const levelMatch = badgeLevel ? badgeLevel.textContent.match(/Level (\d+)/) : null;

        // Construct the badge URL using the provided ID and type
        const badgeBaseUrl = userId ? `https://steamcommunity.com/${isSteamId64 ? 'profiles' : 'id'}/${userId}/gamecards/${appId}` : null;
        const badgeUrl = badgeBaseUrl ? `${badgeBaseUrl}${isFoil ? '?border=1' : ''}` : null;

        return {
            imageUrl: badgeImage ? badgeImage.src : null,
            name: badgeName ? badgeName.textContent.trim() : null,
            level: levelMatch ? levelMatch[1] : null,
            badgeUrl: badgeUrl,
            cardProgress: {
                owned: ownedCards,
                total: totalCards,
                completeSets: completeSets
            },
            unlockedInfo: badgeUnlocked ? badgeUnlocked.textContent.trim() : null // Extract unlocked info
        };
    }

    function createBadgeElement(badgeData, isFoil) {
        const badgeBox = document.createElement('div');
        badgeBox.className = `badge-box ${isFoil ? 'foil' : ''}`;

        const title = document.createElement('div');
        title.className = 'badge-title';
        title.textContent = isFoil ? 'Foil Badge' : 'Regular Badge';
        badgeBox.appendChild(title);

        const link = document.createElement('a');
        link.className = 'badge-link';
        if (badgeData.badgeUrl) {
            link.href = badgeData.badgeUrl;
             link.target = '_blank'; // Open link in a new tab
        } else {
             link.style.cursor = 'default';
        }

        if (badgeData.imageUrl) {
            const image = document.createElement('img');
            image.className = 'badge-image';
            image.src = badgeData.imageUrl;
            image.alt = badgeData.name || 'Badge Image'; // Add alt text
            link.appendChild(image);
        } else {
            const emptyCircle = document.createElement('div');
            emptyCircle.className = 'badge_empty_circle';
            link.appendChild(emptyCircle);
        }

        badgeBox.appendChild(link);

        if (badgeData.level) {
            const level = document.createElement('div');
            level.className = 'badge-level';
            level.textContent = `Level ${badgeData.level}`;
            badgeBox.appendChild(level);
        }

        if (badgeData.cardProgress) {
            const progress = document.createElement('div');
            progress.className = 'badge-progress';
            if (badgeData.cardProgress.total > 0) {
                 if (badgeData.cardProgress.owned === 0 || badgeData.cardProgress.owned === badgeData.cardProgress.total) {
                    progress.textContent = ''; // No progress text if 0/total or total/total
                } else {
                    progress.textContent = `${badgeData.cardProgress.owned}/${badgeData.cardProgress.total} Cards`;
                }

                if (badgeData.cardProgress.completeSets > 0) {
                    const sets = document.createElement('div');
                    sets.className = 'badge-sets';
                    sets.textContent = `${badgeData.cardProgress.completeSets} Complete ${badgeData.cardProgress.completeSets === 1 ? 'Set' : 'Sets'}`;
                    progress.appendChild(sets);
                }
            } else {
                 progress.textContent = 'No cards in this set';
            }

            badgeBox.appendChild(progress);
        }

        // Add unlocked info below progress
        if (badgeData.unlockedInfo) {
             const unlocked = document.createElement('div');
             unlocked.className = 'badge-unlocked';
             unlocked.textContent = badgeData.unlockedInfo;
             badgeBox.appendChild(unlocked);
        }


        return badgeBox;
    }

    function createBadgeListItem(badgeData) {
        const badgeListBox = document.createElement('div');
        badgeListBox.className = `badge-list-box ${badgeData.isFoil ? 'foil' : ''}`;
        // Store data attributes for easy access when clicking
        badgeListBox.dataset.appid = badgeData.appId;
        badgeListBox.dataset.badgeImage = badgeData.badgeImage;
        badgeListBox.dataset.isFoil = badgeData.isFoil;
        badgeListBox.dataset.name = badgeData.name || 'Unknown Badge';

        const title = document.createElement('div');
        title.className = 'badge-list-title';
        title.textContent = badgeData.name || 'Unknown Badge';
        badgeListBox.appendChild(title);

        const link = document.createElement('a');
        link.className = 'badge-list-link';
        link.style.cursor = 'pointer'; // Make it look clickable

        let badgeImageUrl = null;
        if (badgeData.appId && badgeData.badgeImage &&
            (typeof badgeData.appId === 'number' || typeof badgeData.appId === 'string') &&
            typeof badgeData.badgeImage === 'string' && badgeData.badgeImage.length > 0) {

            badgeImageUrl = `https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/items/${badgeData.appId}/${badgeData.badgeImage}`;
            badgeListBox.dataset.imageUrl = badgeImageUrl; // Store image URL

            const image = document.createElement('img');
            image.className = 'badge-list-image';
            image.src = badgeImageUrl;
            image.alt = badgeData.name || 'Badge Image';
            image.onerror = () => {
                logError(`Failed to load constructed image for badge list item: ${badgeData.name} from URL: ${badgeImageUrl}`);
                link.innerHTML = '';
                const emptyCircle = document.createElement('div');
                emptyCircle.className = 'badge_list_empty_circle';
                link.appendChild(emptyCircle);
                 badgeListBox.dataset.imageUrl = ''; // Clear failed image URL
            };
            link.appendChild(image);

        } else {
            const emptyCircle = document.createElement('div');
            emptyCircle.className = 'badge_list_empty_circle';
            link.appendChild(emptyCircle);
             badgeListBox.dataset.imageUrl = ''; // Store empty image URL
        }

        badgeListBox.appendChild(link);

        // Display scarcity
        const scarcity = document.createElement('div');
        scarcity.className = 'badge-list-scarcity';
        if (badgeData.scarcity !== undefined && badgeData.scarcity !== null) {
            scarcity.textContent = `Scarcity: ${badgeData.scarcity.toFixed(0)}`; // Format scarcity to 0 decimal places
             if (badgeData.isFoil) {
                 scarcity.style.color = '#CFE6F5'; // Foil color for foil scarcity
             }
        } else {
             scarcity.textContent = badgeData.isFoil ? 'Scarcity (Foil): N/A' : 'Scarcity: N/A'; // Indicate foil or N/A
             scarcity.style.fontStyle = 'italic';
             scarcity.style.color = badgeData.isFoil ? '#CFE6F5' : '#666'; // Foil color or grey for N/A
        }
        badgeListBox.appendChild(scarcity);

        // Display level for non-foil badges if available
        if (!badgeData.isFoil && badgeData.highestLevel !== undefined && badgeData.highestLevel !== null) {
            const level = document.createElement('div');
            level.className = 'badge-list-level';
            level.textContent = `Level ${badgeData.highestLevel}`;
            badgeListBox.appendChild(level);
        }


        // Add click listener to save/remove from favorites
        badgeListBox.addEventListener('click', () => {
            toggleFavorite({
                appId: badgeData.appId,
                name: badgeData.name || 'Unknown Badge',
                imageUrl: badgeListBox.dataset.imageUrl, // Use stored URL
                isFoil: badgeData.isFoil === 'true' || badgeData.isFoil === true // Ensure boolean
            });
        });


        return badgeListBox;
    }

     function createFavoriteItemElement(favoriteData) {
        const favoriteItem = document.createElement('div');
        favoriteItem.className = `favorite-item ${favoriteData.isFoil ? 'foil' : ''}`;
        favoriteItem.dataset.appid = favoriteData.appId;
        favoriteItem.dataset.isFoil = favoriteData.isFoil;

        const title = document.createElement('div');
        title.className = 'favorite-title';
        title.textContent = favoriteData.name || `App ${favoriteData.appId}`;
        favoriteItem.appendChild(title);

        const link = document.createElement('a');
        link.className = 'favorite-link';
        link.href = `#${favoriteData.appId}`; // Set the URL hash
        link.addEventListener('click', (event) => {
            event.preventDefault(); // Prevent default link behavior

            // --- Store scroll position and clicked item info ---
            scrollPositionBeforeUpdate = window.scrollY || document.documentElement.scrollTop;
            clickedFavoriteAppId = favoriteData.appId;
            clickedFavoriteIsFoil = favoriteData.isFoil;
            logDebug(`Clicked favorite item: App ID ${clickedFavoriteAppId}, Foil: ${clickedFavoriteIsFoil}. Saved scroll position: ${scrollPositionBeforeUpdate}`);
            // --- End Store ---

            // Change the URL hash without a full page reload
            window.location.hash = `${favoriteData.appId}`;
             // Manually trigger the update as hash change might not trigger MutationObserver reliably across all browsers/frameworks
            setTimeout(updateBadgeInfo, 100); // Add a small delay
        });


        if (favoriteData.imageUrl) {
            const image = document.createElement('img');
            image.className = 'favorite-image';
            image.src = favoriteData.imageUrl;
            image.alt = favoriteData.name || 'Badge Image';
             image.onerror = () => {
                logError(`Failed to load image for favorite item: ${favoriteData.name} from URL: ${favoriteData.imageUrl}`);
                link.innerHTML = ''; // Clear any failed image
                const emptyCircle = document.createElement('div');
                emptyCircle.className = 'favorite_empty_circle';
                link.appendChild(emptyCircle);
            };
            link.appendChild(image);
        } else {
            const emptyCircle = document.createElement('div');
            emptyCircle.className = 'favorite_empty_circle';
            link.appendChild(emptyCircle);
        }

        favoriteItem.appendChild(link);

        const appidElement = document.createElement('div');
        appidElement.className = 'favorite-appid';
        appidElement.textContent = `App ID: ${favoriteData.appId}`;
         if (favoriteData.isFoil) {
             const foilIndicator = document.createElement('span');
             foilIndicator.textContent = ' (Foil)';
             foilIndicator.style.color = '#CFE6F5';
             appidElement.appendChild(foilIndicator);
         }
        favoriteItem.appendChild(appidElement);

         // Add a click listener specifically for removing the item
         // This listener is on the item itself. We now check if the clicked
         // element is the title or part of the link before removing.
        favoriteItem.addEventListener('click', (event) => {
             const clickedElement = event.target;
             // Check if the clicked element is the title OR is inside the link
             const isTitle = clickedElement.classList.contains('favorite-title');
             const isInsideLink = clickedElement.closest('.favorite-link');
             const isAppID = clickedElement.closest('.favorite-appid');

             if (!isTitle && !isInsideLink && !isAppID) {
                 logDebug('Clicked outside the title and link, attempting to remove favorite.');
                 toggleFavorite({
                     appId: favoriteData.appId,
                     name: favoriteData.name,
                     imageUrl: favoriteData.imageUrl,
                     isFoil: favoriteData.isFoil
                 });
             } else if (isTitle) {
                  logDebug('Clicked on the favorite title, not removing favorite.');
             } else if (isInsideLink) {
                  logDebug('Clicked on the favorite link, not removing favorite.');
             }else if (isAppID) {
                  logDebug('Clicked on the favorite link, not removing favorite.');
             }
        });


        return favoriteItem;
    }


    async function fetchAndDisplayBadgeList(appId) {
         if (!SteamSetsAPI || SteamSetsAPI === "ss_YOUR_API_KEY") {
            logWarn("SteamSets API key not configured or is placeholder. Skipping badge list fetch.");
            let badgeListContainer = document.querySelector('.badge-list-container');
            if (!badgeListContainer) {
                 badgeListContainer = document.createElement('div');
                 badgeListContainer.className = 'badge-list-container';
                 const target = document.querySelector('.booster_creator_left');
                  if (target) {
                     target.insertAdjacentElement('afterend', badgeListContainer);
                 }
            }
            if (badgeListContainer) {
                 badgeListContainer.innerHTML = '';
                 badgeListContainer.textContent = 'SteamSets API key is not set. Badge list unavailable.';
                 badgeListContainer.style.color = 'orange';
                 badgeListContainer.style.textAlign = 'center';
                  badgeListContainer.style.minHeight = '100px'; // Keep a minimum height for the message
                  badgeListContainer.style.display = 'flex'; // Ensure flex properties apply for centering
                  badgeListContainer.style.alignItems = 'center';
                  badgeListContainer.style.justifyContent = 'center';

            }
            return;
        }

        log(`Attempting to fetch badge list for App ID: ${appId}. Checking cache first.`);

        let badgeListContainer = document.querySelector('.badge-list-container');
         if (!badgeListContainer) {
             badgeListContainer = document.createElement('div');
             badgeListContainer.className = 'badge-list-container';
             const target = document.querySelector('.booster_creator_left');
              if (target) {
                 target.insertAdjacentElement('afterend', badgeListContainer);
             } else {
                 logWarn('Target element .booster_creator_left not found for badge list container insertion.');
                 return;
             }
         }

        badgeListContainer.innerHTML = ''; // Clear previous content
        // Temporarily add a loading message and apply centering styles
        const loadingMessage = document.createElement('div');
        loadingMessage.textContent = 'Loading available badges...';
        loadingMessage.style.color = '#B8B6B4';
        loadingMessage.style.textAlign = 'center';
        loadingMessage.style.width = '100%'; // Ensure text centers horizontally
        badgeListContainer.appendChild(loadingMessage);

         // Apply centering to the container itself while loading
         badgeListContainer.style.display = 'flex';
         badgeListContainer.style.alignItems = 'center';
         badgeListContainer.style.justifyContent = 'center';
         badgeListContainer.style.flexWrap = 'wrap'; // Keep wrap for items later


        try {
            const cachedData = await getCachedData(appId); // <-- Await the promise here

            if (cachedData) {
                logDebug(`Using cached data for App ID ${appId}.`);
                displayBadgeList(cachedData, appId);
                // Reset centering styles once content is loaded
                badgeListContainer.style.display = 'flex'; // Keep flex for items
                badgeListContainer.style.alignItems = 'flex-start'; // Reset alignment
                badgeListContainer.style.justifyContent = 'flex-start'; // Reset alignment
                badgeListContainer.style.color = ''; // Reset style
                 badgeListContainer.style.textAlign = '';

            } else {
                log(`Fetching badge list for App ID: ${appId} from SteamSets API.`);
                 loadingMessage.textContent = 'Fetching available badges...'; // Update loading state

                GM_xmlhttpRequest({
                    method: 'POST',
                    url: 'https://api.steamsets.com/v1/app.listBadges',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${SteamSetsAPI}`
                    },
                    data: JSON.stringify({
                        appId: parseInt(appId) // Ensure appId is an integer
                    }),
                    onload: response => {
                        log(`SteamSets API response status: ${response.status}`);
                        badgeListContainer.innerHTML = ''; // Clear loading message

                        if (response.status === 200) {
                            try {
                                const data = JSON.parse(response.responseText);

                                if (data && data.badges && Array.isArray(data.badges)) {
                                    log(`Fetched ${data.badges.length} badges from SteamSets API.`);
                                    // Cache the successful response
                                    cacheData(appId, data.badges).catch(cacheError => {
                                         logError('Error caching data after successful API fetch:', cacheError);
                                         // Continue displaying even if caching fails
                                    });
                                    displayBadgeList(data.badges, appId);
                                     // Reset centering styles
                                     badgeListContainer.style.display = 'flex';
                                     badgeListContainer.style.alignItems = 'flex-start';
                                     badgeListContainer.style.justifyContent = 'flex-start';
                                     badgeListContainer.style.color = '';
                                      badgeListContainer.style.textAlign = '';


                                } else {
                                    logError('SteamSets API response did not contain expected badge data structure:', data);
                                    badgeListContainer.textContent = 'Error fetching badge list: Invalid data format.';
                                     badgeListContainer.style.color = 'orange';
                                     badgeListContainer.style.textAlign = 'center';
                                      // Keep centering for error message
                                     badgeListContainer.style.display = 'flex';
                                     badgeListContainer.style.alignItems = 'center';
                                     badgeListContainer.style.justifyContent = 'center';
                                }
                            } catch (e) {
                                logError('Error parsing SteamSets API response:', e);
                                badgeListContainer.textContent = 'Error fetching badge list: Invalid JSON response.';
                                 badgeListContainer.style.color = 'orange';
                                 badgeListContainer.style.textAlign = 'center';
                                  // Keep centering for error message
                                 badgeListContainer.style.display = 'flex';
                                 badgeListContainer.style.alignItems = 'center';
                                 badgeListContainer.style.justifyContent = 'center';
                            }
                        } else if (response.status === 401) {
                             logError(`SteamSets API request failed with status 401 (Unauthorized). Check your API key.`, response.responseText);
                             badgeListContainer.innerHTML = '';
                             badgeListContainer.textContent = 'SteamSets API Error: Unauthorized (401). Please check your API key configuration.';
                             badgeListContainer.style.color = 'red';
                             badgeListContainer.style.textAlign = 'center';
                              // Keep centering for error message
                             badgeListContainer.style.display = 'flex';
                             badgeListContainer.style.alignItems = 'center';
                             badgeListContainer.style.justifyContent = 'center';

                        }
                        else {
                             logError(`SteamSets API request failed with status: ${response.status}`, response.responseText);
                             let errorMessage = `Error fetching badge list. Status: ${response.status}.`;
                             if (response.responseText) {
                                 try {
                                      const errorData = JSON.parse(response.responseText);
                                      if (errorData.message) {
                                           errorMessage += ` Message: ${errorData.message}`;
                                      }
                                 } catch (e) {
                                     // Ignore JSON parsing error if responseText is not JSON
                                 }
                             }
                            badgeListContainer.innerHTML = '';
                            badgeListContainer.textContent = errorMessage;
                             badgeListContainer.style.color = 'orange';
                             badgeListContainer.style.textAlign = 'center';
                              // Keep centering for error message
                             badgeListContainer.style.display = 'flex';
                             badgeListContainer.style.alignItems = 'center';
                             badgeListContainer.style.justifyContent = 'center';
                        }
                    },
                    onerror: (error) => {
                        logError(`SteamSets API request failed:`, error);
                        badgeListContainer.innerHTML = ''; // Clear loading message
                        badgeListContainer.textContent = `Network error fetching badge list.`;
                         badgeListContainer.style.color = 'red';
                         badgeListContainer.style.textAlign = 'center';
                          // Keep centering for error message
                         badgeListContainer.style.display = 'flex';
                         badgeListContainer.style.alignItems = 'center';
                         badgeListContainer.style.justifyContent = 'center';
                    }
                });
            }
        } catch (error) {
            // Catch errors from openDatabase or getCachedData
            logError('Error during API cache retrieval or database open:', error);
            badgeListContainer.innerHTML = ''; // Clear loading message
            badgeListContainer.textContent = `Error accessing badge data cache.`;
             badgeListContainer.style.color = 'red';
             badgeListContainer.style.textAlign = 'center';
              // Keep centering for error message
             badgeListContainer.style.display = 'flex';
             badgeListContainer.style.alignItems = 'center';
             badgeListContainer.style.justifyContent = 'center';
        }
    }

    function displayBadgeList(badges, appId) {
         const badgeListContainer = document.querySelector('.badge-list-container');
         if (!badgeListContainer) {
             logWarn('Badge list container not found during display.');
             return;
         }
         badgeListContainer.innerHTML = ''; // Clear existing content

         if (!badges || badges.length === 0) {
            badgeListContainer.textContent = 'No badges found for this app via SteamSets API.';
             badgeListContainer.style.color = '#B8B6B4';
             badgeListContainer.style.textAlign = 'center';
             // Keep centering for message
             badgeListContainer.style.display = 'flex';
             badgeListContainer.style.alignItems = 'center';
             badgeListContainer.style.justifyContent = 'center';
            return;
         }

         // Sort badges
        const sortedBadges = badges.sort((a, b) => {
            // Sort non-foil badges first
            if (a.isFoil !== b.isFoil) {
                return a.isFoil ? 1 : -1; // non-foil first
            }

            // If both are non-foil, sort by highestLevel ascending (1 to 5)
            if (!a.isFoil && !b.isFoil) {
                // Handle cases where highestLevel might be missing or null
                const levelA = a.highestLevel !== undefined && a.highestLevel !== null ? a.highestLevel : Infinity;
                const levelB = b.highestLevel !== undefined && b.highestLevel !== null ? b.highestLevel : Infinity;
                if (levelA !== levelB) {
                    return levelA - levelB;
                }
                // If levels are the same or missing, sort by scarcity
                 const scarcityA = a.scarcity !== undefined && a.scarcity !== null ? a.scarcity : Infinity;
                 const scarcityB = b.scarcity !== undefined && b.scarcity !== null ? b.scarcity : Infinity;
                 if (scarcityA !== scarcityB) {
                     return scarcityA - scarcityB;
                 }
            }

            // If both are foil, sort by rarity ascending if available, otherwise scarcity, otherwise name
            if (a.isFoil && b.isFoil) {
                 const rarityA = a.rarity !== undefined && a.rarity !== null ? a.rarity : Infinity;
                 const rarityB = b.rarity !== undefined && b.rarity !== null ? b.rarity : Infinity;
                 if (rarityA !== rarityB) {
                     return rarityA - rarityB;
                 }
                  const scarcityA = a.scarcity !== undefined && a.scarcity !== null ? a.scarcity : Infinity;
                  const scarcityB = b.scarcity !== undefined && b.scarcity !== null ? b.scarcity : Infinity;
                  if (scarcityA !== scarcityB) {
                      return scarcityA - scarcityB;
                  }
            }

            // Fallback: Sort by name if other criteria are the same or missing
            return (a.name || '').localeCompare(b.name || '');
        });


        logDebug(`Displaying all available badges (${sortedBadges.length}):`);
        sortedBadges.forEach(badge => {
            // Add appId to the badge data before creating the item
            badge.appId = appId;
            badgeListContainer.appendChild(createBadgeListItem(badge));
        });
         // Reset centering styles for displaying items
         badgeListContainer.style.display = 'flex';
         badgeListContainer.style.alignItems = 'flex-start';
         badgeListContainer.style.justifyContent = 'flex-start';
         badgeListContainer.style.color = ''; // Reset style
         badgeListContainer.style.textAlign = '';
    }


    // Main function to fetch and display badge info
    async function updateBadgeInfo() {
        const appId = getAppId();
        if (!appId) {
            logWarn('Could not get App ID from URL. Displaying favorites only.');
            // If no App ID, clear badge containers and only show favorites
            clearBadgeContainers(false); // Don't remove favorites container
            addFavoritesContainerWithControls(); // Ensure favorites container is present
            displayFavorites(); // Display favorites even if no app ID
            return;
        }

        const userId = USER_STEAM_ID;
        const isSteamId64 = STEAM_ID_IS_STEAMID64;

        if (userId === "REPLACE_WITH_YOUR_STEAM_ID" || SteamSetsAPI === "ss_YOUR_API_KEY") {
            logError("Please update the USER_STEAM_ID and/or SteamSetsAPI variables in the script.");
            const errorDiv = document.createElement('div');
            errorDiv.style.cssText = 'color: red; font-weight: bold; margin-top: 20px; text-align: center;';
            errorDiv.textContent = "Steam Badge Info Injector: Please edit the script and update the configuration variables.";
            const target = document.querySelector('.booster_creator_left');
            if (target) {
                 target.insertAdjacentElement('afterend', errorDiv);
            } else {
                 document.body.prepend(errorDiv);
            }
            clearBadgeContainers(false); // Clear any old containers except favorites
            addFavoritesContainerWithControls(); // Ensure favorites container is present
            displayFavorites(); // Still show favorites if available
            return;
        }

        // Remove existing containers before adding new ones (except favorites)
        clearBadgeContainers(true); // Remove badge containers

        log(`Fetching badge data for App ID: ${appId} and User ID: ${userId} (Type: ${isSteamId64 ? 'SteamID64' : 'Custom ID'})`);

        // Create and insert the badge list container first with loading state
        const badgeListContainer = document.createElement('div');
        badgeListContainer.className = 'badge-list-container';
        badgeListContainer.textContent = 'Loading available badges...'; // Initial loading state
        // Apply centering and min-height immediately
        badgeListContainer.style.display = 'flex';
        badgeListContainer.style.alignItems = 'center';
        badgeListContainer.style.justifyContent = 'center';
        badgeListContainer.style.flexWrap = 'wrap'; // Keep wrap for items later


        const target = document.querySelector('.booster_creator_left');
         if (!target) {
            logWarn('Target element .booster_creator_left not found. Containers not inserted.');
             // Still display favorites even if main container fails
             addFavoritesContainerWithControls(); // Ensure favorites container is present
             displayFavorites();
             return;
        }
        target.insertAdjacentElement('afterend', badgeListContainer); // Insert list container


        // Create and insert the main badge container with loading state
        const mainContainer = document.createElement('div');
        mainContainer.className = 'badge-container';
        mainContainer.textContent = 'Loading your badge info...'; // Initial loading state
         // Apply centering and min-height immediately
         mainContainer.style.display = 'flex';
         mainContainer.style.alignItems = 'center';
         mainContainer.style.justifyContent = 'center';


        // Insert the main container after the badge list container
         badgeListContainer.insertAdjacentElement('afterend', mainContainer);


         // Create and insert the favorites container if it doesn't exist
        addFavoritesContainerWithControls();
         // Always display favorites when updateBadgeInfo runs
         displayFavorites();


        // Fetch and display the list of available badges (this will update the badgeListContainer)
        fetchAndDisplayBadgeList(appId); // This function now handles updating the content and styles


        // Construct URLs using the provided user ID and type
        const userPath = isSteamId64 ? 'profiles' : 'id';
        const regularUrl = `https://steamcommunity.com/${userPath}/${userId}/gamecards/${appId}`;
        const foilUrl = `https://steamcommunity.com/${userPath}/${userId}/gamecards/${appId}?border=1`;

        Promise.all([
            new Promise(resolve => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: regularUrl,
                    onload: response => {
                        log(`Regular badge request status: ${response.status}`);
                         if (response.status === 200) {
                            resolve(parseBadgeData(response.responseText, false, userId, isSteamId64, appId));
                         } else {
                             logError(`Failed to load regular badge (Status ${response.status})`);
                             resolve({ imageUrl: null, name: `Error loading regular badge (${response.status})`, level: null, badgeUrl: regularUrl, cardProgress: null, unlockedInfo: null }); // Include unlockedInfo
                         }
                    },
                    onerror: (error) => {
                         logError(`Error loading regular badge:`, error);
                         resolve({ imageUrl: null, name: 'Error loading regular badge', level: null, badgeUrl: regularUrl, cardProgress: null, unlockedInfo: null }); // Include unlockedInfo
                    }
                });
            }),
            new Promise(resolve => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: foilUrl,
                    onload: response => {
                        log(`Foil badge request status: ${response.status}`);
                         if (response.status === 200) {
                            resolve(parseBadgeData(response.responseText, true, userId, isSteamId64, appId));
                         } else {
                              logError(`Failed to load foil badge (Status ${response.status})`);
                             resolve({ imageUrl: null, name: `Error loading foil badge (${response.status})`, level: null, badgeUrl: foilUrl, cardProgress: null, unlockedInfo: null }); // Include unlockedInfo
                         }
                    },
                    onerror: (error) => {
                        logError(`Error loading foil badge:`, error);
                        resolve({ imageUrl: null, name: 'Error loading foil badge', level: null, badgeUrl: foilUrl, cardProgress: null, unlockedInfo: null }); // Include unlockedInfo
                    }
                });
            })
        ]).then(([regularBadge, foilBadge]) => {
            mainContainer.innerHTML = ''; // Clear loading message
            mainContainer.appendChild(createBadgeElement(regularBadge, false));
            mainContainer.appendChild(createBadgeElement(foilBadge, true));
             // Reset centering styles once content is loaded
             mainContainer.style.display = 'flex'; // Keep flex
             mainContainer.style.alignItems = 'center'; // Reset alignment (items are centered by default in flex row)
             mainContainer.style.justifyContent = 'center'; // Reset alignment (items are centered by default in flex row)


        }).catch(error => {
             logError('Error in Promise.all fetching badge data:', error);
             mainContainer.innerHTML = ''; // Clear loading message
             mainContainer.textContent = 'Error loading your badge info.';
              // Keep centering for error message
             mainContainer.style.display = 'flex';
             mainContainer.style.alignItems = 'center';
             mainContainer.style.justifyContent = 'center';
        });
    }

     function clearBadgeContainers(removeFavorites = false) {
         const existingMainContainer = document.querySelector('.badge-container');
         if (existingMainContainer) {
             existingMainContainer.remove();
         }
         const existingListContainer = document.querySelector('.badge-list-container');
         if (existingListContainer) {
             existingListContainer.remove();
         }
         if (removeFavorites) {
              const existingFavoritesContainer = document.querySelector('.favorites-container');
              if (existingFavoritesContainer) {
                  existingFavoritesContainer.remove();
              }
         }
         const existingError = document.querySelector('div[style*="color: red"], div[style*="color: orange"]');
         if(existingError) {
             existingError.remove();
         }
     }

      function addFavoritesContainerWithControls() {
         let favoritesContainer = document.querySelector('.favorites-container');
         if (!favoritesContainer) {
              logDebug('Favorites container not found, creating and adding controls.');
              favoritesContainer = document.createElement('div');
              favoritesContainer.className = 'favorites-container';

              // Add sort controls
              const controlsDiv = document.createElement('div');
              controlsDiv.className = 'favorites-controls';

              // Group sort controls
              const sortGroup = document.createElement('div');
              sortGroup.className = 'sort-group';

              const label = document.createElement('label');
              label.textContent = 'Sort Favorites:';
              label.htmlFor = 'favorites-sort';
              sortGroup.appendChild(label);

              // Create the button wrapper for the select
              const selectWrapper = document.createElement('div');
              selectWrapper.className = 'btn_grey_black'; // Apply Steam button class

              const select = document.createElement('select');
              select.id = 'favorites-sort';
              select.innerHTML = `
                 <option value="appid_asc">App ID (Asc)</option>
                 <option value="appid_desc">App ID (Desc)</option>
                 <option value="foil_first">Foil First</option> <!-- Corrected order based on common preference -->
                 <option value="foil_last">Foil Last</option>
              `;
              select.value = currentFavoritesSortOrder; // Set initial value
              select.addEventListener('change', (event) => {
                  currentFavoritesSortOrder = event.target.value;
                  GM_setValue('favoritesSortOrder', currentFavoritesSortOrder); // Save sort order
                  displayFavorites(); // Redraw favorites with new sort order
              });
              selectWrapper.appendChild(select); // Append select inside the button wrapper
              sortGroup.appendChild(selectWrapper); // Append button wrapper to sort group

              controlsDiv.appendChild(sortGroup); // Add sort group to controls


              // Group import/export buttons
              const buttonGroup = document.createElement('div');
              buttonGroup.className = 'button-group';

              // Add Export Button
              const exportButton = document.createElement('button');
              exportButton.className = 'steam-button'; // Custom Steam-like style
              exportButton.textContent = 'Export Favorites';
              exportButton.onclick = exportFavorites;
              buttonGroup.appendChild(exportButton);

              // Add Import Button
              const importButton = document.createElement('button');
              importButton.className = 'steam-button'; // Custom Steam-like style
              importButton.textContent = 'Import Favorites';
              importButton.onclick = showImportArea; // Show the import modal
              buttonGroup.appendChild(importButton);

              controlsDiv.appendChild(buttonGroup); // Add button group to controls


              favoritesContainer.appendChild(controlsDiv);

              // Find a suitable insertion point
              const mainContainer = document.querySelector('.badge-container');
              const listContainer = document.querySelector('.badge-list-container');
              const target = document.querySelector('.booster_creator_left');

              if (mainContainer) {
                  mainContainer.insertAdjacentElement('afterend', favoritesContainer);
                   logDebug('Favorites container inserted after main badge container.');
              } else if (listContainer) {
                  listContainer.insertAdjacentElement('afterend', favoritesContainer);
                   logDebug('Favorites container inserted after badge list container.');
              } else if (target) {
                  target.insertAdjacentElement('afterend', favoritesContainer);
                   logDebug('Favorites container inserted after .booster_creator_left.');
              } else {
                  logWarn('Could not find insertion point for favorites container. Favorites will not be displayed.');
                  return; // Don't proceed if no target found
              }
              logDebug('Favorites container and controls added.');
         } else {
             // If container exists, just ensure the sort select value is correct
              logDebug('Favorites container already exists, ensuring sort select value is correct.');
              const sortSelect = favoritesContainer.querySelector('#favorites-sort');
              if (sortSelect) {
                  sortSelect.value = currentFavoritesSortOrder;
              }
              // Ensure controls structure is correct (especially after updates)
              const controlsDiv = favoritesContainer.querySelector('.favorites-controls');
              if (controlsDiv) {
                  // Check if the grouping divs exist, if not, rebuild the controls
                  if (!controlsDiv.querySelector('.sort-group') || !controlsDiv.querySelector('.button-group')) {
                      logDebug('Favorites controls structure outdated, rebuilding controls div.');
                      // Clear existing controls
                      controlsDiv.innerHTML = '';

                      // Rebuild sort group
                      const sortGroup = document.createElement('div');
                      sortGroup.className = 'sort-group';
                      const label = document.createElement('label');
                      label.textContent = 'Sort Favorites:';
                      label.htmlFor = 'favorites-sort';
                      sortGroup.appendChild(label);
                       const selectWrapper = document.createElement('div');
                       selectWrapper.className = 'btn_grey_black';
                       const select = document.createElement('select');
                       select.id = 'favorites-sort';
                       select.innerHTML = `
                          <option value="appid_asc">App ID (Asc)</option>
                          <option value="appid_desc">App ID (Desc)</option>
                          <option value="foil_last">Foil First</option>
                          <option value="foil_first">Foil Last</option>
                       `;
                       select.value = currentFavoritesSortOrder;
                       select.addEventListener('change', (event) => {
                           currentFavoritesSortOrder = event.target.value;
                           GM_setValue('favoritesSortOrder', currentFavoritesSortOrder);
                           displayFavorites();
                       });
                       selectWrapper.appendChild(select);
                       sortGroup.appendChild(selectWrapper);
                       controlsDiv.appendChild(sortGroup);


                      // Rebuild button group
                       const buttonGroup = document.createElement('div');
                       buttonGroup.className = 'button-group';

                       const exportButton = document.createElement('button');
                       exportButton.className = 'steam-button';
                       exportButton.textContent = 'Export Favorites';
                       exportButton.onclick = exportFavorites;
                       buttonGroup.appendChild(exportButton);

                       const importButton = document.createElement('button');
                       importButton.className = 'steam-button';
                       importButton.textContent = 'Import Favorites';
                       importButton.onclick = showImportArea;
                       buttonGroup.appendChild(importButton);

                       controlsDiv.appendChild(buttonGroup);

                       logDebug('Favorites controls div rebuilt.');

                  } else {
                       // If groups exist, just ensure buttons are inside the button-group
                       const buttonGroup = controlsDiv.querySelector('.button-group');
                       if (buttonGroup) {
                           // Find existing buttons outside the group and move them
                           controlsDiv.querySelectorAll('.steam-button').forEach(btn => {
                                if (!buttonGroup.contains(btn)) {
                                    logDebug('Moving existing steam-button into button-group.');
                                    buttonGroup.appendChild(btn);
                                }
                           });
                       }
                  }
              } else {
                   logWarn('Favorites controls div not found in existing container.');
              }
         }
     }


    // --- Initial Run and Observers ---

    addStyle(style);

    // Use a small delay to allow the page structure to load
    setTimeout(updateBadgeInfo, 500);

    // Use MutationObserver to detect URL changes within the page
    // Observe the body for subtree and child list changes to catch SPA navigation
    let lastUrl = window.location.href;
    const observer = new MutationObserver(() => {
        const currentUrl = window.location.href;
        // Check if the appId part of the URL has changed
        const lastAppId = lastUrl.match(/\d+$/);
        const currentAppId = currentUrl.match(/\d+$/);

        const appIdChanged = (lastAppId && currentAppId && lastAppId[0] !== currentAppId[0]) ||
                             (!lastAppId && currentAppId) ||
                             (lastAppId && !currentAppId);

        if (currentUrl !== lastUrl && appIdChanged) {
            lastUrl = currentUrl;
            log(`URL changed, App ID updated. Updating badge info.`);
            // Add a small delay before updating to ensure the page structure is ready
            setTimeout(updateBadgeInfo, 200);
        } else if (currentUrl !== lastUrl && !appIdChanged) {
             // If URL changed but App ID is the same (e.g., hash change for something else),
             // just re-display favorites in case the container was removed by page script.
             log(`URL changed, but App ID is the same. Redisplaying favorites.`);
             lastUrl = currentUrl; // Still update lastUrl
             // Ensure the favorites container exists before trying to display
             if (!document.querySelector('.favorites-container')) {
                 logDebug('Favorites container missing during non-AppID URL change, attempting to re-add.');
                 addFavoritesContainerWithControls(); // Re-add container if necessary
             }
             setTimeout(displayFavorites, 100); // Always try to display favorites
        } else if (currentUrl === lastUrl) {
             // Check if the favorites container needs to be re-added
             if (!document.querySelector('.favorites-container')) {
                 logDebug('Favorites container missing, re-adding.');
                 addFavoritesContainerWithControls(); // Re-add container and controls
                 displayFavorites(); // Populate the re-added container
             }
        }
    });

    // Start observing the document body
    observer.observe(document.body, { subtree: true, childList: true });

    // Also try to run updateBadgeInfo on DOMContentLoaded
    document.addEventListener('DOMContentLoaded', () => {
        log('DOMContentLoaded event fired.');
        // Clear stale API cache on DOMContentLoaded (doesn't need to block anything)
        clearStaleApiCache();
        setTimeout(updateBadgeInfo, 300);
    });

    // Initial display of favorites on load
    // We need to wait for the DB to be ready before displaying favorites
    openDatabase().then(() => {
        logDebug('Database ready for initial favorites display.');
        addFavoritesContainerWithControls(); // Ensure container is present early
        displayFavorites();
    }).catch(error => {
         logError('Failed to open database for initial favorites display:', error);
         // Still try to add the container and show an error message
         addFavoritesContainerWithControls();
         const favoritesContainer = document.querySelector('.favorites-container');
          if (favoritesContainer) {
              let itemsWrapper = favoritesContainer.querySelector('.favorites-items-wrapper');
              if (!itemsWrapper) {
                 itemsWrapper = document.createElement('div');
                 itemsWrapper.className = 'favorites-items-wrapper';
                 favoritesContainer.appendChild(itemsWrapper);
              }
              itemsWrapper.textContent = 'Error initializing favorites database.';
              itemsWrapper.style.color = 'red';
              itemsWrapper.style.textAlign = 'center';
              itemsWrapper.style.width = '100%';
              itemsWrapper.style.marginTop = '10px';
          }
    });


    // Clear stale API cache periodically or on load
    clearStaleApiCache();


})();