Counter-Strike 2 Script

Manage your CS2 storage units and inspect items

// ==UserScript==
// @name        Counter-Strike 2 Script
// @namespace   https://github.com/Citrinate
// @author      Citrinate
// @description Manage your CS2 storage units and inspect items
// @license     Apache-2.0
// @version     1.0.0.2
// @match       https://steamcommunity.com/id/*/inventory*
// @match       https://steamcommunity.com/profiles/*/inventory*
// @match       https://steamcommunity.com/market/listings/*
// @connect     localhost
// @connect     127.0.0.1
// @connect     *
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_addStyle
// @grant       GM_registerMenuCommand
// @grant       unsafeWindow
// @homepageURL https://github.com/Citrinate/CS2Script
// @supportURL  https://github.com/Citrinate/CS2Script/issues
// ==/UserScript==
(() => {
  // src/core/settings.js
  var SETTING_ASF_SERVER = "SETTING_ASF_SERVER";
  var SETTING_ASF_PORT = "SETTING_ASF_PORT";
  var SETTING_ASF_PASSWORD = "SETTING_ASF_PASSWORD";
  var SETTING_INSPECT_ITEMS = "SETTING_INSPECT_ITEMS";
  var SETTING_INSPECT_CACHE_TIME_HOURS = "SETTING_INSPECT_CACHE_TIME_HOURS";
  var SETTING_INTERFACE_AUTOSTOP_MINUTES = "SETTING_INTERFACE_AUTOSTOP_MINUTES";
  var DEFAULT_SETTINGS = {
    SETTING_ASF_SERVER: "http://localhost",
    SETTING_ASF_PORT: "1242",
    SETTING_ASF_PASSWORD: "",
    SETTING_INSPECT_ITEMS: true,
    SETTING_INSPECT_CACHE_TIME_HOURS: -1,
    SETTING_INTERFACE_AUTOSTOP_MINUTES: 15
  };
  function GetSetting(name) {
    return GM_getValue(name, DEFAULT_SETTINGS[name]);
  }
  function SetSetting(name, value) {
    GM_setValue(name, value);
  }

  // src/core/asf.js
  var asf_default = {
    Send: async function(operation, path, http_method, bot, data) {
      let payload = null;
      let parameters = "";
      if (data) {
        if (http_method === "GET") {
          parameters = "?" + new URLSearchParams(data).toString();
        } else if (http_method === "POST") {
          payload = JSON.stringify(data);
        }
      }
      const xhrResponse = await new Promise((resolve, reject) => {
        GM_xmlhttpRequest({
          url: `${GetSetting(SETTING_ASF_SERVER)}:${GetSetting(SETTING_ASF_PORT)}/Api/${operation}/${bot}/${path}${parameters}`,
          method: http_method,
          data: payload,
          responseType: "json",
          headers: {
            "Accept": "application/json",
            "Content-Type": "application/json",
            "Authentication": GetSetting(SETTING_ASF_PASSWORD)
          },
          onload: (response) => {
            if (typeof response.response === "string") {
              try {
                response.response = JSON.parse(response.response);
              } catch {
                ;
              }
            }
            resolve(response);
          },
          onerror: (e) => {
            const error = new Error(`(${e.status}) Request error from /Api/${operation}/${path}`);
            error.code = e.status;
            reject(error);
          },
          ontimeout: (e) => {
            const error = new Error(`(${e.status}) Request timed out on /Api/${operation}/${path}`);
            error.code = e.status;
            reject(error);
          }
        });
      });
      if (xhrResponse.status === 401) {
        const error = new Error(`(401) Missing or incorrect ASF IPC password. Please check your settings and verify your ASF IPC password.`);
        error.code = xhrResponse.status;
        error.response = xhrResponse.response;
        throw error;
      }
      if (xhrResponse.status === 403) {
        let errorMessage;
        if (!GetSetting(SETTING_ASF_SERVER).includes("127.0.0.1") && !GetSetting(SETTING_ASF_SERVER).toLowerCase().includes("localhost") && !GetSetting(SETTING_ASF_PASSWORD)) {
          errorMessage = "(403) You must use an ASF IPC password when connecting to ASF remotely.";
        } else {
          errorMessage = "(403) The ASF IPC password you entered was incorrect. Please wait or restart ASF, and then try again.";
        }
        const error = new Error(errorMessage);
        error.code = xhrResponse.status;
        error.response = xhrResponse.response;
        throw error;
      }
      if (!xhrResponse.response || xhrResponse.status !== 200) {
        let errorMessage = `(${xhrResponse.status}) ASF request error from /Api/${operation}/${path}`;
        if (xhrResponse.response?.Message) {
          errorMessage += `: ${xhrResponse.response?.Message}`;
        } else if (xhrResponse.status >= 500) {
          errorMessage += `: Please check your ASF logs for errors`;
        }
        const error = new Error(errorMessage);
        error.code = xhrResponse.status;
        error.response = xhrResponse.response;
        throw error;
      }
      if (!xhrResponse.response.Success) {
        let errorMessage = `(${xhrResponse.status}) ASF response error from /Api/${operation}/${path}`;
        if (xhrResponse.response.Message) {
          errorMessage += `: ${xhrResponse.response.Message}`;
        }
        const error = new Error(errorMessage);
        error.code = xhrResponse.status;
        error.response = xhrResponse.response;
        throw error;
      }
      return xhrResponse.response.Result ?? xhrResponse.response;
    },
    GetBot: async function(steamID, includePluginStatus = true) {
      if (steamID === false) {
        return;
      }
      const bots = await this.Send("Bot", "", "GET", "ASF");
      let pluginStatus;
      if (includePluginStatus) {
        pluginStatus = await this.GetPluginStatus();
      }
      const mergedBots = Object.fromEntries(
        Object.entries(bots).map(([key, value]) => [
          key,
          {
            ASF: value,
            Plugin: pluginStatus?.[key]
          }
        ])
      );
      if (steamID) {
        return Object.values(mergedBots).find((bot) => bot.ASF.SteamID == steamID);
      }
      return mergedBots;
    },
    GetPluginStatus: async function(botName) {
      const bots = await this.Send("CS2Interface", "Status", "GET", "ASF", { "refreshAutoStop": "true" });
      if (botName) {
        return bots[botName];
      }
      return bots;
    }
  };

  // src/cs2/constants.js
  var CS2_APPID = 730;
  var INVENTORY_ITEM_LIMIT = 1e3;
  var STORAGE_UNIT_ITEM_LIMIT = 1e3;
  var STICKER_MAX_COUNT = 5;
  var KEYCHAIN_MAX_COUNT = 1;
  var SEED_RANGE = { min: 0, max: 1e5 };
  var FLOAT_RANGE = { min: 0, max: 1 };
  var WEARS = [
    { min: 0, max: 0.07, name: "FN", nameLong: "Factory New" },
    { min: 0.07, max: 0.15, name: "MW", nameLong: "Minimum Wear" },
    { min: 0.15, max: 0.38, name: "FT", nameLong: "Field-Tested" },
    { min: 0.38, max: 0.45, name: "WW", nameLong: "Well-Worn" },
    { min: 0.45, max: 1, name: "BS", nameLong: "Battle-Scarred" }
  ];

  // src/utils/cache.js
  var Cache = class {
    static #dbName = "cs2_script";
    static #storeName = "kvp";
    static #version = 1;
    static #initPromise = null;
    static #keyName = "DB_ENCRYPTION_KEY";
    static #key = null;
    static async #Init() {
      if (this.#initPromise) {
        return this.#initPromise;
      }
      this.#initPromise = new Promise((resolve, reject) => {
        const request = indexedDB.open(this.#dbName, this.#version);
        request.onupgradeneeded = () => {
          const db = request.result;
          if (!db.objectStoreNames.contains(this.#storeName)) {
            db.createObjectStore(this.#storeName);
          }
        };
        request.onsuccess = async () => {
          const db = request.result;
          const testKey = "cache_validity_test";
          const testValue = 42;
          const storedKey = GM_getValue(this.#keyName, null);
          if (storedKey) {
            try {
              const raw = Uint8Array.from(atob(storedKey), (c) => c.charCodeAt(0));
              this.#key = await crypto.subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
              await this.#Encrypt({ test: true });
              if (await this.#Get(db, testKey) !== testValue) {
                throw new Error("Cache failed to validate");
              }
            } catch (e) {
              script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error("Clearing cache"));
              this.#key = null;
            }
          }
          if (!this.#key) {
            const rawKey = crypto.getRandomValues(new Uint8Array(32));
            this.#key = await crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
            GM_setValue(this.#keyName, btoa(String.fromCharCode(...rawKey)));
            await this.#Clear(db);
          }
          await this.#Set(db, testKey, testValue);
          resolve(db);
        };
        request.onerror = () => {
          reject(request.error);
        };
      });
      return this.#initPromise;
    }
    static async #Encrypt(data) {
      const encoded = new TextEncoder().encode(JSON.stringify(data));
      const iv = crypto.getRandomValues(new Uint8Array(12));
      const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, this.#key, encoded);
      const combined = new Uint8Array(iv.byteLength + ciphertext.byteLength);
      combined.set(iv, 0);
      combined.set(new Uint8Array(ciphertext), iv.byteLength);
      return combined.buffer;
    }
    static async #decrypt(buffer) {
      const combined = new Uint8Array(buffer);
      const iv = combined.slice(0, 12);
      const ciphertext = combined.slice(12);
      const encoded = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, this.#key, ciphertext);
      return JSON.parse(new TextDecoder().decode(encoded));
    }
    static async #Clear(db) {
      return new Promise((resolve, reject) => {
        const tx = db.transaction(this.#storeName, "readwrite");
        const store = tx.objectStore(this.#storeName);
        const req = store.clear();
        req.onsuccess = () => {
          resolve();
        };
        req.onerror = () => {
          reject(req.error);
        };
      });
    }
    static async #Get(db, key, defaultValue = null) {
      return new Promise((resolve, reject) => {
        const tx = db.transaction(this.#storeName, "readonly");
        const store = tx.objectStore(this.#storeName);
        const req = store.get(key);
        req.onsuccess = async () => {
          if (!req.result) {
            resolve(defaultValue);
            return;
          }
          try {
            resolve(await this.#decrypt(req.result));
          } catch (e) {
            script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
            resolve(defaultValue);
          }
        };
        req.onerror = () => {
          reject(req.error);
        };
      });
    }
    static async #Set(db, key, value) {
      const encrypted = await this.#Encrypt(value);
      return new Promise((resolve, reject) => {
        const tx = db.transaction(this.#storeName, "readwrite");
        const store = tx.objectStore(this.#storeName);
        const req = store.put(encrypted, key);
        req.onsuccess = () => {
          resolve();
        };
        req.onerror = () => {
          reject(req.error);
        };
      });
    }
    static async GetValue(key, defaultValue = null) {
      return this.#Get(await this.#Init(), key, defaultValue);
    }
    static async SetValue(key, value) {
      return this.#Set(await this.#Init(), key, value);
    }
  };

  // src/utils/helpers.js
  function Request(url) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", url, true);
      xhr.onload = function() {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.responseText);
        } else {
          reject(new Error(`Request failed with status: ${xhr.status}`));
        }
      };
      xhr.onerror = function() {
        reject(new Error("Network error occurred"));
      };
      xhr.ontimeout = function() {
        reject(new Error("Request timed out"));
      };
      xhr.send();
    });
  }
  function CreateElement(tag, options) {
    const el = document.createElement(tag);
    if (options) {
      for (const [key, value] of Object.entries(options)) {
        if (key === "class") {
          el.className = value;
        } else if (key === "html") {
          el.innerHTML = value;
        } else if (key === "text") {
          el.innerText = value;
        } else if (key === "hide" && value) {
          el.hide();
        } else if (key === "style") {
          Object.assign(el.style, value);
        } else if (key === "vars") {
          for (const [varName, varValue] of Object.entries(value)) {
            el.style.setProperty(`--${varName}`, varValue);
          }
        } else if (key === "dataset") {
          Object.assign(el.dataset, value);
        } else if (key === "disabled") {
          el.disabled = value;
        } else if (key === "selected") {
          el.selected = value;
        } else if (key.startsWith("on") && typeof value === "function") {
          el.addEventListener(key.slice(2).toLowerCase(), value);
        } else if (key === "htmlChildren") {
          for (const child of value) {
            if (!child) {
              continue;
            }
            el.insertAdjacentHTML("beforeend", child);
          }
        } else if (key === "children") {
          for (const child of value) {
            if (!child) {
              continue;
            }
            el.append(child instanceof Node ? child : document.createTextNode(child));
          }
        } else {
          el.setAttribute(key, value);
        }
      }
    }
    return el;
  }
  function CreateCachedAsyncFunction(asyncFunction) {
    let cache = null;
    let inProgress = null;
    const wrapped = async () => {
      if (cache !== null) {
        return cache;
      }
      if (inProgress) {
        return inProgress;
      }
      inProgress = asyncFunction().then((result) => {
        cache = result;
        return result;
      });
      return inProgress;
    };
    wrapped.willReturnImmediately = () => {
      return cache !== null;
    };
    return wrapped;
  }
  function BindTooltip(element, text) {
    if (element.unbindTooltip) {
      element.unbindTooltip();
    }
    const tooltip = CreateElement("div", {
      class: "cs2s_tooltip",
      text
    });
    let fadeOutAnimation = null;
    element.classList.add(`cs2s_has_tooltip`);
    function onMouseEnter() {
      if (fadeOutAnimation) {
        fadeOutAnimation.cancel();
        fadeOutAnimation = null;
      }
      const rect = element.getBoundingClientRect();
      document.body.appendChild(tooltip);
      void tooltip.offsetWidth;
      tooltip.style.top = `${rect.bottom + window.scrollY + 8}px`;
      tooltip.style.left = `${rect.left + window.scrollX + rect.width / 2 - tooltip.offsetWidth / 2}px`;
      Fade(tooltip, { from: 0, to: 1, duration: 200 });
    }
    function onMouseLeave() {
      fadeOutAnimation = Fade(tooltip, {
        from: 1,
        to: 0,
        duration: 200,
        onfinish: () => {
          tooltip.isConnected && tooltip.remove();
        }
      });
    }
    element.addEventListener("mouseenter", onMouseEnter);
    element.addEventListener("mouseleave", onMouseLeave);
    element.unbindTooltip = () => {
      element.removeEventListener("mouseenter", onMouseEnter);
      element.removeEventListener("mouseleave", onMouseLeave);
      element.classList.remove(`cs2s_has_tooltip`);
      element.unbindTooltip = null;
      tooltip.isConnected && tooltip.remove();
    };
    return tooltip;
  }
  function Fade(element, options) {
    const to = options.to ?? 1;
    if (typeof options.from !== "undefined") {
      element.style.opacity = options.from;
    }
    const animation = element.animate({
      opacity: to
    }, {
      duration: options.duration ?? 250,
      easing: "ease",
      fill: "forwards"
    });
    if (typeof options.onfinish === "function") {
      animation.onfinish = () => {
        options.onfinish();
      };
    }
    return animation;
  }
  function Sleep(milliseconds) {
    if (milliseconds <= 0) {
      return Promise.resolve();
    }
    return new Promise((resolve) => {
      setTimeout(resolve, milliseconds);
    });
  }
  function Random(min, max) {
    return Math.random() * (max - min) + min;
  }

  // src/cs2/items/inventory.js
  var Inventory = class _Inventory {
    items;
    storedItems;
    loadedFromCache;
    static iconURLsCacheID = "icon_urls";
    static iconURLs = null;
    constructor(items, loadedFromCache = false) {
      this.items = items;
      this.storedItems = [];
      this.loadedFromCache = loadedFromCache;
    }
    async LoadCrateContents(progressCallback) {
      _Inventory.iconURLs = await Cache.GetValue(_Inventory.iconURLsCacheID, {});
      let cratesOpened = 0;
      const numCrates = this.items.filter((item) => item.iteminfo.def_index === 1201).length;
      progressCallback(`Loading Storage Unit Contents (${cratesOpened}/${numCrates})`, cratesOpened / numCrates);
      for (const item of this.items) {
        if (item.iteminfo.def_index == 1201) {
          const storedItems = await this.#OpenCrate(item);
          if (storedItems) {
            this.storedItems = this.storedItems.concat(storedItems);
          }
          cratesOpened++;
          progressCallback(`Loading Storage Unit Contents (${cratesOpened}/${numCrates})`, cratesOpened / numCrates);
        }
        if (!_Inventory.iconURLs[item.full_name]) {
          const asset = unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory.m_rgAssets[item.iteminfo.id];
          if (asset) {
            _Inventory.iconURLs[item.full_name] = asset.description.icon_url;
          }
        }
      }
      Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
      const itemsToGetIconsFor = /* @__PURE__ */ new Set();
      const commodityItemsToGetIconsFor = /* @__PURE__ */ new Set();
      for (const item of [...this.items, ...this.storedItems]) {
        item.id = item.iteminfo.id;
        item.name = !!item.wear_name && item.full_name.includes(item.wear_name) ? item.full_name.slice(0, -(item.wear_name.length + 3)) : item.full_name;
        item.name_normalized = item.name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
        item.collection_name = item.set_name ?? item.crate_name?.replace(/( Autograph Capsule)$/, " Autographs").replace(/( Capsule)$/, "");
        item.collection = item.collection_name?.replace(/^(The )/, "").replace(/( Collection)$/, "").replace(/^(Operation )/, "").replace(/( Autographs)$/, "");
        item.rarity = item.collection || item.iteminfo.rarity > 1 ? item.iteminfo.rarity : void 0;
        item.seed = item.attributes["set item texture seed"] ? Math.floor(item.attributes["set item texture seed"]) : item.attributes["keychain slot 0 seed"];
        if (item.iteminfo.quality == 3) {
          item.quality = 3 + Number(item.stattrak === true);
        } else if (item.iteminfo.quality == 12) {
          item.quality = 2;
        } else {
          item.quality = Number(item.stattrak === true) * 2;
        }
        if (item.casket_id) {
          item.casket_name = this.items.find((x) => x.iteminfo.id == item.casket_id)?.attributes["custom name attr"] ?? item.casket_id;
        }
        if (item.stickers) {
          for (const sticker of Object.values(item.stickers)) {
            if (_Inventory.iconURLs[sticker.full_name] || _Inventory.iconURLs[sticker.full_name] === null) {
              continue;
            }
            commodityItemsToGetIconsFor.add(sticker.full_name);
          }
        }
        if (item.keychains) {
          for (const keychain of Object.values(item.keychains)) {
            if (_Inventory.iconURLs[keychain.full_name] || _Inventory.iconURLs[keychain.full_name] === null) {
              continue;
            }
            itemsToGetIconsFor.add(keychain.full_name);
          }
        }
        if (!item.moveable || _Inventory.iconURLs[item.full_name] || _Inventory.iconURLs[item.full_name] === null) {
          continue;
        }
        if (item.commodity) {
          commodityItemsToGetIconsFor.add(item.full_name);
        } else {
          itemsToGetIconsFor.add(item.full_name);
        }
      }
      await this.#FetchCommodityIcons(commodityItemsToGetIconsFor, progressCallback);
      await this.#FetchIcons(/* @__PURE__ */ new Set([...itemsToGetIconsFor, ...commodityItemsToGetIconsFor]), progressCallback);
    }
    async #OpenCrate(item) {
      if (item.iteminfo.def_index != 1201) {
        return;
      }
      const assetID = item.iteminfo.id;
      const attributes = item.attributes;
      const cache_id = `crate_${assetID}`;
      const cache = await Cache.GetValue(cache_id, null);
      if (cache) {
        if (this.loadedFromCache || cache.attributes["modification date"] == attributes["modification date"]) {
          return cache.items;
        }
      }
      if (this.loadedFromCache) {
        const error2 = new Error(`Failed to load crate ${assetID} from cache`);
        error2.OPERATION_ERROR = OPERATION_ERROR.INTERFACE_NOT_CONNECTED;
        throw error2;
      }
      for (let attempt = 0; attempt < 3; attempt++) {
        try {
          const storedItems = await asf_default.Send("CS2Interface", `GetCrateContents/${assetID}`, "GET", script_default.Bot.ASF.BotName);
          if (!storedItems) {
            break;
          }
          const crate = {
            attributes,
            items: storedItems
          };
          Cache.SetValue(cache_id, crate);
          await Sleep(2e3);
          return storedItems;
        } catch (e) {
          script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
          if (e.code === 504) {
            script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error("Timed out while opening storage unit, reconnecting to interface"));
            if (!await script_default.RestartInterface({ showProgress: false, errorLevel: ERROR_LEVEL.LOW })) {
              break;
            }
          }
        }
      }
      const error = new Error(`Failed to open crate ${assetID}`);
      error.OPERATION_ERROR = OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD;
      throw error;
    }
    async #FetchIcons(hashes, progressCallback) {
      if (hashes.size == 0) {
        return;
      }
      const iconsToFetch = hashes.size;
      let iconsFetched = 0;
      progressCallback("Fetching Item Icons", 0);
      for (const hash of hashes) {
        let success = false;
        const url = `${window.location.origin}/market/listings/${CS2_APPID}/${encodeURIComponent(hash)}`;
        for (let attempt = 0; attempt < 5; attempt++) {
          try {
            const listingPage = await Request(url);
            if (listingPage.includes("g_rgAssets = []")) {
              if (!listingPage.includes("Market_LoadOrderSpread")) {
                success = true;
                _Inventory.iconURLs[hash] = null;
                hashes.delete(hash);
                Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
                continue;
              }
              await Sleep(Random(1e3, 2e3));
              continue;
            }
            const matches = listingPage.match(/g_rgAssets\s*=\s*({.*?});/);
            if (!matches) {
              script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to find g_rgAssets at ${url}`));
              console.log(listingPage);
              return;
            }
            if (matches.length > 1) {
              let assets;
              try {
                assets = JSON.parse(matches[1]);
              } catch {
                script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to parse g_rgAssets at ${url}`));
                console.log(matches);
                return;
              }
              const asset = Object.values(assets?.[CS2_APPID]?.[2] ?? assets?.[CS2_APPID]?.[0] ?? {})?.[0];
              if (asset?.icon_url) {
                success = true;
                _Inventory.iconURLs[hash] = asset?.icon_url;
                hashes.delete(hash);
                Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
              }
            }
            break;
          } catch (e) {
            script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
            await Sleep(Random(1e3, 2e3));
          }
        }
        if (!success) {
          script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to get item icon at ${url}`));
        }
        iconsFetched++;
        progressCallback(`Fetching Item Icons (${iconsFetched}/${iconsToFetch})`, iconsFetched / iconsToFetch);
      }
    }
    async #FetchCommodityIcons(hashes, progressCallback) {
      if (hashes.size == 0) {
        return;
      }
      const itemLimit = 25;
      const chunkedHashes = Array.from(
        { length: Math.ceil(hashes.size / itemLimit) },
        (_, index) => [...hashes].slice(index * itemLimit, (index + 1) * itemLimit)
      );
      const iconsToFetch = hashes.size;
      let iconsFetched = 0;
      progressCallback("Fetching Commodity Item Icons", 0);
      for (const chunk of chunkedHashes) {
        const query = new URLSearchParams({
          appid: String(CS2_APPID),
          contextid: "2"
        });
        for (const hash of chunk) {
          query.append("items[]", hash);
        }
        const url = `${window.location.origin}/market/multisell?${query.toString()}`;
        let success = false;
        for (let attempt = 0; attempt < 5; attempt++) {
          try {
            const multiSellPage = await Request(url);
            if (multiSellPage.includes("error_ctn")) {
              continue;
            }
            const matches = multiSellPage.match(/g_rgAssets\s*=\s*({.*?});/);
            if (!matches) {
              script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to find g_rgAssets at ${url}`));
              console.log(multiSellPage);
              return;
            }
            if (matches.length > 1) {
              let assets;
              try {
                assets = JSON.parse(matches[1]);
              } catch (e) {
                script_default.ShowError({ level: ERROR_LEVEL.LOW }, e, new Error(`Failed to parse g_rgAssets at ${url}`));
                console.log(matches);
                return;
              }
              for (const asset of Object.values(assets?.[CS2_APPID]?.[2])) {
                for (const hash of chunk) {
                  if (asset?.description?.market_hash_name == hash && asset?.description?.icon_url) {
                    _Inventory.iconURLs[hash] = asset.description.icon_url;
                    hashes.delete(hash);
                    break;
                  }
                }
              }
              success = true;
              Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
            }
            break;
          } catch (e) {
            script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
            await Sleep(Random(1e3, 2e3));
          }
        }
        if (!success) {
          script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to get item icons at ${url}`));
        }
        iconsFetched += chunk.length;
        progressCallback(`Fetching Commodity Item Icons (${iconsFetched}/${iconsToFetch})`, iconsFetched / iconsToFetch);
      }
    }
    async StoreItem(asset, crateAsset) {
      await asf_default.Send("CS2Interface", `StoreItem/${crateAsset.iteminfo.id}/${asset.iteminfo.id}`, "GET", script_default.Bot.ASF.BotName);
    }
    async RetrieveItem(asset) {
      await asf_default.Send("CS2Interface", `RetrieveItem/${asset.casket_id}/${asset.iteminfo.id}`, "GET", script_default.Bot.ASF.BotName);
    }
  };

  // src/components/popup.js
  var Popup = class _Popup {
    static #numPopups = 0;
    #popoverMode;
    #onopen;
    #onclose;
    #fade;
    #popupContainer;
    #background;
    #visible = false;
    constructor(options) {
      this.#popoverMode = options.popoverMode ?? false;
      this.#onopen = options.onopen ?? false;
      this.#onclose = options.onclose ?? false;
      this.#fade = options.fade ?? true;
      _Popup.#numPopups++;
      const title = CreateElement("div", {
        class: "cs2s_popup_title",
        text: options.title ?? "",
        children: options.titleChildren ?? []
      });
      const simpleMode = options.simpleMode ?? false;
      const disableClose = options.disableClose ?? false;
      const closeButton = !simpleMode && CreateElement("div", {
        class: "cs2s_popup_close_button",
        onclick: () => {
          this.Hide();
        }
      });
      const popupBody = CreateElement("div", {
        class: `cs2s_popup_body`,
        children: [
          !disableClose && closeButton,
          title,
          ...options.body ?? []
        ]
      });
      if (simpleMode) {
        popupBody.classList.add("cs2s_popup_body_simple");
      }
      if (this.#popoverMode) {
        popupBody.classList.add("cs2s_popup_body_popover");
      }
      this.#background = CreateElement("div", {
        class: "cs2s_popup_background",
        style: {
          zIndex: 1e3 + _Popup.#numPopups
        }
      });
      this.#popupContainer = CreateElement("div", {
        class: "cs2s_popup_container",
        style: {
          zIndex: 1e3 + _Popup.#numPopups
        },
        children: [
          popupBody
        ]
      });
      if (!disableClose) {
        this.#popupContainer.addEventListener("dblclick", (event) => {
          const box = popupBody.getBoundingClientRect();
          const style = getComputedStyle(popupBody);
          if (event.clientY < box.top || event.clientX < box.left || event.clientY > box.bottom + parseInt(style.marginBottom) || event.clientX > box.right) {
            this.Hide();
          }
        });
        document.addEventListener("keydown", (event) => {
          if (!this.#visible) {
            return;
          }
          if (event.key === "Escape") {
            event.preventDefault();
            this.Hide();
          }
        });
      }
    }
    Show() {
      if (this.#visible) {
        return;
      }
      this.#visible = true;
      if (typeof this.#onopen === "function") {
        this.#onopen();
      }
      unsafeWindow.document.body.append(this.#background, this.#popupContainer);
      if (!this.#popoverMode) {
        if (this.#fade) {
          Fade(this.#background, {
            from: 0,
            to: getComputedStyle(this.#background).opacity
          });
        }
        unsafeWindow.document.body.classList.add("cs2s_popup_opened");
      }
    }
    Hide() {
      if (!this.#visible) {
        return;
      }
      this.#visible = false;
      if (typeof this.#onclose === "function") {
        this.#onclose();
      }
      if (this.#fade) {
        Fade(this.#background, {
          from: getComputedStyle(this.#background).opacity,
          to: 0,
          onfinish: () => {
            this.#background.isConnected && this.#background.remove();
          }
        });
      } else {
        this.#background.isConnected && this.#background.remove();
      }
      this.#popupContainer.isConnected && this.#popupContainer.remove();
      if (!this.#popoverMode) {
        unsafeWindow.document.body.classList.remove("cs2s_popup_opened");
      }
    }
  };

  // src/core/script.js
  var OPERATION_ERROR = {
    INTERFACE_NOT_CONNECTED: 0,
    INVENTORY_FAILED_TO_LOAD: 1
  };
  var ERROR_LEVEL = {
    HIGH: 0,
    MEDIUM: 1,
    LOW: 2
  };
  var Script = class {
    Bot;
    AccountsConnected = 0;
    #inventory = null;
    #statusUpdateListeners = [];
    #navigationButton;
    #navigationStatus;
    #navigationMenu;
    #errorTableBody;
    constructor() {
      const globalNavigation = unsafeWindow.document.getElementById(`account_dropdown`);
      if (!globalNavigation) {
        return;
      }
      this.#navigationStatus = CreateElement("span", {
        class: "account_name",
        text: "???"
      });
      this.#navigationButton = CreateElement("span", {
        class: "popup_menu_item cs2s_navigation_popup_menu_item",
        onmouseenter: () => {
          this.#ShowNavigationMenu();
        },
        onmouseleave: () => {
          this.#HideNavigationMenu();
        },
        children: [
          CreateElement("span", {
            html: (
              /*html*/
              `
					<span class="cs2s_navigation_icon">
						<svg
							width="173.27321"
							height="42.757812"
							viewBox="0 0 173.27321 42.757812"
							fill="currentColor"
							preserveAspectRatio="xMinYMin">
							<path
								d="m 79.808179,0 c -6.1207,1e-7 -11.646256,3.6370293 -14.035156,9.2363278 l -1.595704,3.7402352 -1.140625,2.667969 c -2.1334,4.9951 1.555679,10.533203 7.017579,10.533203 h 2.800781 22.875 l -2.935547,6.835937 H 58.10896 c -1.5238,0 -2.898,0.901969 -3.5,2.292969 l -3.222656,7.451172 h 39.164062 c 6.105704,0 11.625494,-3.621172 14.021494,-9.201172 l 2.87109,-6.683594 c 2.147,-4.9966 -1.54372,-10.548828 -7.01172,-10.548828 H 74.780835 l 1.884766,-4.402344 -4.792969,-2.3105472 h 40.464848 c 1.528,0 2.91081,-0.906287 3.50781,-2.304687 L 118.97029,0 Z M 24.497632,0.00195 C 18.410132,4.7e-4 12.905279,3.5995237 10.495679,9.1542936 L 0.6167727,32.216794 c -2.139226,4.9966 1.5490919,10.541016 7.0136719,10.541016 H 39.798413 c 1.5267,0 2.904906,-0.905381 3.503906,-2.300781 l 3.197266,-7.441404 H 12.644116 L 21.696851,11.923828 16.780835,9.6152348 h 37.253906 c 1.5267,0 2.904907,-0.905482 3.503906,-2.300782 L 60.679273,0.0058594 Z M 127.8824,0.00976 123.79451,9.6191351 h 37.17188 l -2.85157,6.7109369 h -27.21289 c -6.0365,0 -11.49792,3.620914 -13.86914,9.197266 l -0.0742,0.175781 -7.24804,17.052735 h 49.26758 l 1.89843,-4.466797 v -0.002 l 0.0742,-0.173828 v -0.01367 c 0.88057,-2.42168 -0.94013,-5.083985 -3.54101,-5.083985 h -31.46289 l 2.90625,-6.835937 h 32.1914 0.15039 0.01 c 2.95431,-0.06268 5.61224,-1.859402 6.77539,-4.597656 l 0.0742,-0.175782 4.61328,-10.851562 C 174.77935,5.5862411 171.10481,0.0097657 165.73201,0.0097657 Z" />
						</svg>
					</span>
				`
            )
          }),
          "CS2Script: ",
          this.#navigationStatus
        ]
      });
      globalNavigation.children[0].append(this.#navigationButton);
      GM_registerMenuCommand("Set ASF IPC Password", () => {
        const password = prompt("Enter ASF IPC Password", GetSetting(SETTING_ASF_PASSWORD));
        if (password !== null) {
          SetSetting(SETTING_ASF_PASSWORD, password);
          window.location.reload();
        }
      });
    }
    async #UpdateConnectionStatus() {
      try {
        const status = await asf_default.GetBot();
        if (this.Bot) {
          const oldBot = this.Bot;
          this.Bot = status[this.Bot.ASF.BotName];
          for (const listener of this.#statusUpdateListeners) {
            listener(this.Bot, oldBot);
          }
        }
        const currentAccountConnected = this.Bot && status[this.Bot.ASF.BotName].Plugin?.Connected;
        const numOtherAccountsConnected = Object.values(status).filter((x) => x.Plugin?.Connected).length - currentAccountConnected;
        const numOtherAccounts = Object.values(status).length - Number(this.Bot !== null);
        this.AccountsConnected = currentAccountConnected ? numOtherAccountsConnected + 1 : numOtherAccountsConnected;
        if (!this.#navigationStatus.tooltip) {
          this.#navigationStatus.tooltip = BindTooltip(this.#navigationStatus, "");
        }
        this.#navigationStatus.innerText = currentAccountConnected ? "1" : "0";
        this.#navigationStatus.tooltip.innerHTML = "Interface status for this account: ";
        if (currentAccountConnected) {
          this.#navigationStatus.tooltip.innerHTML += "<strong>Connected</strong>";
        } else {
          this.#navigationStatus.tooltip.innerHTML += "<strong>Not Connected</strong>";
        }
        if (numOtherAccounts > 0) {
          this.#navigationStatus.innerText += ` + ${numOtherAccountsConnected}`;
          this.#navigationStatus.tooltip.innerHTML += `<br>Interface is connected on <strong>${numOtherAccountsConnected}/${numOtherAccounts}</strong> other accounts`;
        }
      } catch (e) {
        this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
      }
    }
    AddStatusUpdateListener(listener) {
      this.#statusUpdateListeners.push(listener);
    }
    RemovetatusUpdateListener(listener) {
      this.#statusUpdateListeners = this.#statusUpdateListeners.filter((x) => x !== listener);
    }
    #ShowNavigationMenu(fade = true) {
      if (this.#navigationMenu && this.#navigationMenu.isConnected) {
        if (this.#navigationMenu.fade) {
          this.#navigationMenu.fade.cancel();
          this.#navigationMenu.fade = null;
        }
        Fade(this.#navigationMenu, {
          to: 1,
          duration: 200
        });
        return;
      }
      const errorButton = CreateElement("a", {
        class: "popup_menu_item",
        text: "View Errors",
        onclick: () => {
          unsafeWindow.document.body.click();
          this.ShowErrors();
        }
      });
      if (this.#navigationButton.classList.contains("cs2s_navigation_status_error_glow")) {
        errorButton.classList.add("cs2s_navigation_status_error_glow");
      }
      const botConnected = this.Bot?.Plugin?.Connected;
      const interfaceToggleButton = CreateElement("a", {
        class: "popup_menu_item",
        text: !botConnected ? "Start Interface" : "Stop Interface",
        onclick: () => {
          unsafeWindow.document.body.click();
          if (!botConnected) {
            this.StartInterface();
          } else {
            this.StopInterface();
          }
        }
      });
      const settingsButton = CreateElement("a", {
        class: "popup_menu_item",
        text: "Settings",
        onclick: () => {
          unsafeWindow.document.body.click();
          this.ShowSettings();
        }
      });
      this.#navigationMenu = CreateElement("div", {
        class: "popup_block_new",
        children: [
          CreateElement("div", {
            class: "popup_body popup_menu",
            children: [
              interfaceToggleButton,
              settingsButton,
              this.#errorTableBody && errorButton
            ]
          })
        ]
      });
      this.#navigationButton.append(this.#navigationMenu);
      this.#navigationMenu.style.top = `${this.#navigationButton.offsetTop}px`;
      this.#navigationMenu.style.left = `-${this.#navigationMenu.offsetWidth}px`;
      if (fade) {
        Fade(this.#navigationMenu, {
          from: 0,
          to: 1,
          duration: 200
        });
      }
    }
    #HideNavigationMenu() {
      if (!this.#navigationMenu) {
        return;
      }
      this.#navigationMenu.fade = Fade(this.#navigationMenu, {
        to: 0,
        duration: 200,
        onfinish: () => {
          this.#navigationMenu.isConnected && this.#navigationMenu.remove();
        }
      });
    }
    async VerifyConnection() {
      try {
        await asf_default.GetBot(null, false);
      } catch (e) {
        this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error('ArchiSteamFarm is not running or cannot be reached. Please verify that ASF is running. Under "Settings", verify that your ASF server, port, and password settings are all correct.'));
        return false;
      }
      try {
        await asf_default.GetPluginStatus();
      } catch (e) {
        this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error("CS2 Interface plugin is not installed"));
        return false;
      }
      try {
        const bot = await asf_default.GetBot(unsafeWindow.g_steamID);
        if (!bot) {
          throw new Error("ASF bot for this account was not found. If ASF was recently started, please wait until your bots come online and then reload the page.");
        }
        this.Bot = bot;
      } catch (e) {
        this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
        return false;
      }
      this.#UpdateConnectionStatus();
      setInterval(() => {
        if (unsafeWindow.document.visibilityState === "hidden") {
          return;
        }
        this.#UpdateConnectionStatus();
      }, 1e3);
      return true;
    }
    ShowError(options, ...errors) {
      if (!this.#errorTableBody) {
        this.#errorTableBody = CreateElement("tbody");
      }
      for (const error of errors) {
        console.log(error);
        this.#errorTableBody.prepend(
          CreateElement("tr", {
            children: [
              CreateElement("td", {
                text: (/* @__PURE__ */ new Date()).toLocaleString()
              }),
              CreateElement("td", {
                text: options.level == ERROR_LEVEL.HIGH ? "High" : options.level == ERROR_LEVEL.MEDIUM ? "Medium" : "Low"
              }),
              CreateElement("td", {
                text: error.message
              })
            ]
          })
        );
      }
      if (this.#errorTableBody.isConnected) {
        return;
      }
      if (options.level === ERROR_LEVEL.HIGH) {
        const popup = new Popup({
          title: "Counter-Strike 2 Script Error",
          simpleMode: true,
          popoverMode: true,
          fade: false,
          body: [
            CreateElement("div", {
              class: "cs2s_action_body",
              children: [
                CreateElement("div", {
                  class: "cs2s_action_message_tall cs2s_action_multi_message",
                  children: [
                    ...errors.map(
                      (error) => CreateElement("div", {
                        class: "cs2s_action_message",
                        text: error.message
                      })
                    )
                  ]
                }),
                CreateElement("div", {
                  class: "cs2s_action_buttons",
                  children: [
                    CreateElement("div", {
                      class: "cs2s_grey_long_button",
                      text: "Close",
                      onclick: () => {
                        popup.Hide();
                      }
                    })
                  ]
                })
              ]
            })
          ]
        });
        popup.Show();
      } else if (options.level === ERROR_LEVEL.MEDIUM) {
        const globalNavigationButton = unsafeWindow.document.getElementById(`account_pulldown`);
        this.#navigationButton.classList.add("cs2s_navigation_status_error_glow");
        globalNavigationButton && globalNavigationButton.classList.add("cs2s_navigation_status_error_pulse");
      }
    }
    ShowErrors() {
      const globalNavigationButton = unsafeWindow.document.getElementById(`account_pulldown`);
      this.#navigationButton.classList.remove("cs2s_navigation_status_error_glow");
      globalNavigationButton && globalNavigationButton.classList.remove("cs2s_navigation_status_error_pulse");
      const popup = new Popup({
        title: "Counter-Strike 2 Script Errors",
        body: [
          CreateElement("div", {
            text: "More detailed information can be found in your browser's developer console",
            style: {
              padding: "0px 0px 16px 16px",
              fontStyle: "italic"
            }
          }),
          CreateElement("div", {
            class: "cs2s_table_container cs2s_error_table_container",
            children: [
              CreateElement("table", {
                class: "cs2s_table",
                children: [
                  CreateElement("thead", {
                    children: [
                      CreateElement("tr", {
                        children: [
                          CreateElement("th", {
                            text: "Time"
                          }),
                          CreateElement("th", {
                            text: "Severity"
                          }),
                          CreateElement("th", {
                            text: "Error"
                          })
                        ]
                      })
                    ]
                  }),
                  this.#errorTableBody
                ]
              })
            ]
          })
        ]
      });
      popup.Show();
    }
    ShowSettings() {
      const form = CreateElement("form", {
        class: "cs2s_settings_form",
        html: (
          /*html*/
          `
				<div class="cs2s_settings_form_group_title">
					ASF Settings
				</div>
				<div class="cs2s_settings_form_group">
					<div class="cs2s_settings_form_group_item">
						<label for="${SETTING_ASF_SERVER}">
							ASF Server
						</label>
						<input type="text" name="${SETTING_ASF_SERVER}" placeholder="${DEFAULT_SETTINGS[SETTING_ASF_SERVER]}" value="${GetSetting(SETTING_ASF_SERVER)}">
					</div>
					<div class="cs2s_settings_form_group_item">
						<label for="${SETTING_ASF_PORT}">
							ASF Port
						</label>
						<input type="number" name="${SETTING_ASF_PORT}" placeholder="${DEFAULT_SETTINGS[SETTING_ASF_PORT]}" min="0" value="${GetSetting(SETTING_ASF_PORT)}">
					</div>
					<div class="cs2s_settings_form_group_item">
						<label>
							ASF IPC Password
						</label>
						<div class="cs2s_settings_form_message">
							This setting can be configured from your userscript manager's popup menu, found in your browser's extensions toolbar
						</div>
					</div>
				</div>

				<div class="cs2s_settings_form_group_title">
					Script Features
				</div>
				<div class="cs2s_settings_form_group">
					<div class="cs2s_settings_form_group_item cs2s_settings_form_group_item_checkbox">
						<input type="checkbox" name="${SETTING_INSPECT_ITEMS}" id="${SETTING_INSPECT_ITEMS}" ${GetSetting(SETTING_INSPECT_ITEMS) ? "checked" : ""}>							
						<label for="${SETTING_INSPECT_ITEMS}">
							Inspect Items
						</label>
					</div>
				</div>

				<div class="cs2s_settings_form_group_title">
					Script Settings
				</div>
				<div class="cs2s_settings_form_group">
					<div class="cs2s_settings_form_group_item">
						<label for="${SETTING_INTERFACE_AUTOSTOP_MINUTES}">
							Auto-stop interface if inactive for (minutes; 0 = never auto-stop${this.Bot?.Plugin?.Connected ? "; changes will apply on next start" : ""})
						</label>
						<input type="number" name="${SETTING_INTERFACE_AUTOSTOP_MINUTES}" placeholder="${DEFAULT_SETTINGS[SETTING_INTERFACE_AUTOSTOP_MINUTES]}" min="0" value="${GetSetting(SETTING_INTERFACE_AUTOSTOP_MINUTES)}">
					</div>
					<div class="cs2s_settings_form_group_item">
						<label for="${SETTING_INSPECT_CACHE_TIME_HOURS}">
							Re-inspect items after (hours; -1 = never re-inspect)
						</label>
						<input type="number" name="${SETTING_INSPECT_CACHE_TIME_HOURS}" placeholder="${DEFAULT_SETTINGS[SETTING_INSPECT_CACHE_TIME_HOURS]}" min="-1" value="${GetSetting(SETTING_INSPECT_CACHE_TIME_HOURS)}">
					</div>
				</div>
				
				<div class="cs2s_settings_form_submit_group">
					<button class="cs2s_blue_long_button" type="submit">Save</button>
					<button class="cs2s_grey_long_button" id="form_cancel" type="button">Cancel</button>
				</div>
			`
        ),
        onsubmit: (event) => {
          event.preventDefault();
          for (const element of event.target) {
            if (!element.name || !element.value && !element.placeholder) {
              continue;
            }
            const value = element.type === "checkbox" ? element.checked : element.value || element.placeholder;
            SetSetting(element.name, value);
          }
          window.location.reload();
        }
      });
      const popup = new Popup({
        title: "Counter-Strike 2 Script Settings",
        body: [form]
      });
      form.querySelector("#form_cancel").onclick = () => {
        popup.Hide();
      };
      popup.Show();
    }
    async StartInterface(options = {}) {
      const showProgress = options.showProgress ?? true;
      const errorLevel = options.errorLevel ?? ERROR_LEVEL.HIGH;
      if (!this.Bot) {
        this.ShowError({ level: errorLevel }, new Error("Cannot start interface. Check the error log for more information."));
        return false;
      }
      const loadingBody = CreateElement("div", {
        class: "cs2s_action_body",
        children: [
          CreateElement("div", {
            class: "cs2s_action_spinner"
          })
        ]
      });
      const successButton = CreateElement("div", {
        class: "cs2s_blue_long_button",
        text: "OK"
      });
      const successBody = CreateElement("div", {
        class: "cs2s_action_body",
        children: [
          CreateElement("div", {
            class: "cs2s_action_message cs2s_action_message_tall",
            text: "Interface successfully started"
          }),
          successButton
        ]
      });
      let interfaceStarted = false;
      const popup = new Popup({
        simpleMode: true,
        disableClose: true,
        popoverMode: options.popoverMode ?? false,
        fade: false,
        title: "Starting Interface",
        body: [
          loadingBody,
          successBody
        ],
        onopen: options.onopen,
        onclose: () => {
          if (typeof options.onclose === "function") {
            options.onclose();
          }
          if (interfaceStarted) {
            if (typeof options.onconnected === "function") {
              options.onconnected();
              return interfaceStarted;
            }
            window.location.reload();
          }
        }
      });
      successBody.hide();
      successButton.onclick = () => {
        popup.Hide();
      };
      if (showProgress) {
        popup.Show();
      }
      try {
        const response = await asf_default.Send("CS2Interface", `Start`, "GET", this.Bot.ASF.BotName, { autoStop: GetSetting(SETTING_INTERFACE_AUTOSTOP_MINUTES) });
        if (!response || !response[this.Bot.ASF.BotName]?.Success) {
          popup.Hide();
          this.ShowError({ level: errorLevel }, new Error("Interface failed to start"));
          return interfaceStarted;
        }
        let status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
        while (status && status.Connected && !status.InventoryLoaded) {
          await Sleep(1e3);
          status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
        }
        if (!status || !status.Connected || !status.InventoryLoaded) {
          popup.Hide();
          this.ShowError({ level: errorLevel }, new Error("Interface failed to start: Interface stopped while waiting for inventory to loaded"));
          return interfaceStarted;
        }
      } catch (e) {
        popup.Hide();
        this.ShowError({ level: errorLevel }, new Error(e.response?.Result?.[this.Bot.ASF.BotName]?.Message ?? e.message));
        return interfaceStarted;
      }
      interfaceStarted = true;
      if (options.autoClose) {
        popup.Hide();
        return interfaceStarted;
      }
      loadingBody.hide();
      successBody.show();
      return interfaceStarted;
    }
    async StopInterface(options = {}) {
      const showProgress = options.showProgress ?? true;
      const errorLevel = options.errorLevel ?? ERROR_LEVEL.HIGH;
      const loadingBody = CreateElement("div", {
        class: "cs2s_action_body",
        children: [
          CreateElement("div", {
            class: "cs2s_action_spinner"
          })
        ]
      });
      const successButton = CreateElement("div", {
        class: "cs2s_blue_long_button",
        text: "OK"
      });
      const successBody = CreateElement("div", {
        class: "cs2s_action_body",
        children: [
          CreateElement("div", {
            class: "cs2s_action_message cs2s_action_message_tall",
            text: "Interface successfully stopped"
          }),
          successButton
        ]
      });
      let interfaceStopped = false;
      const popup = new Popup({
        simpleMode: true,
        title: "Stopping Interface",
        body: [
          loadingBody,
          successBody
        ],
        onclose: () => {
          if (interfaceStopped) {
            window.location.reload();
          }
        }
      });
      successBody.hide();
      successButton.onclick = () => {
        popup.Hide();
      };
      if (showProgress) {
        popup.Show();
      }
      try {
        const response = await asf_default.Send("CS2Interface", `Stop`, "GET", this.Bot.ASF.BotName);
        if (!response || !response[this.Bot.ASF.BotName]?.Success) {
          popup.Hide();
          this.ShowError({ level: errorLevel }, new Error("Interface failed to stop"));
          return interfaceStopped;
        }
      } catch (e) {
        popup.Hide();
        this.ShowError({ level: errorLevel }, e);
        return interfaceStopped;
      }
      interfaceStopped = true;
      loadingBody.hide();
      successBody.show();
      return interfaceStopped;
    }
    async RestartInterface(options = {}) {
      return await this.StopInterface(options) && await this.StartInterface(options);
    }
    ShowStartInterfacePrompt(options = {}) {
      const popup = new Popup({
        title: "Start Interface?",
        simpleMode: true,
        popoverMode: options.popoverMode ?? false,
        onopen: options.onopen,
        onclose: options.onclose,
        fade: options.fade,
        body: [
          CreateElement("div", {
            class: "cs2s_action_body",
            children: [
              CreateElement("div", {
                class: "cs2s_action_message cs2s_action_message_tall",
                text: options.message ?? "Start the interface?"
              }),
              CreateElement("div", {
                class: "cs2s_action_buttons",
                children: [
                  CreateElement("div", {
                    class: "cs2s_blue_long_button",
                    text: "Start Interface",
                    onclick: () => {
                      popup.Hide();
                      this.StartInterface(options);
                    }
                  }),
                  CreateElement("div", {
                    class: "cs2s_grey_long_button",
                    text: "Cancel",
                    onclick: () => {
                      popup.Hide();
                    }
                  })
                ]
              })
            ]
          })
        ]
      });
      popup.Show();
    }
    async GetInventory(options = {}) {
      if (this.#inventory === null) {
        const progressMessage = CreateElement("div", {
          class: "cs2s_action_message"
        });
        const progressBar = CreateElement("div", {
          class: "cs2s_action_progress_bar"
        });
        this.GetInventory.closeButton = CreateElement("div", {
          class: "cs2s_grey_long_button",
          text: "Close"
        });
        this.GetInventory.progressBody = CreateElement("div", {
          class: "cs2s_action_body",
          children: [
            progressMessage,
            progressBar,
            this.GetInventory.closeButton
          ]
        });
        this.#inventory = CreateCachedAsyncFunction(async () => {
          const cache_id = `inventory_${unsafeWindow.g_steamID}`;
          const cache = await Cache.GetValue(cache_id, null);
          let inventory;
          if (this.Bot) {
            try {
              let status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
              if (status && status.Connected && status.InventoryLoaded) {
                if (!status.InventoryLoaded) {
                  do {
                    await Sleep(1e3);
                    status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
                  } while (status && status.Connected && !status.InventoryLoaded);
                }
                if (status && status.Connected && status.InventoryLoaded) {
                  const itemList = await asf_default.Send("CS2Interface", "Inventory", "GET", this.Bot.ASF.BotName);
                  if (itemList) {
                    inventory = new Inventory(itemList);
                    Cache.SetValue(cache_id, itemList);
                  }
                }
              }
            } catch (e) {
              this.ShowError({ level: ERROR_LEVEL.LOW }, e);
            }
          }
          if (!inventory) {
            if (!cache) {
              return OPERATION_ERROR.INTERFACE_NOT_CONNECTED;
            }
            inventory = new Inventory(cache, true);
          }
          try {
            await inventory.LoadCrateContents((message, progress) => {
              progressMessage.innerText = message;
              progressBar.style.setProperty("--percentage", `${(progress * 100).toFixed(0)}%`);
            });
            return inventory;
          } catch (e) {
            this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
            return e.OPERATION_ERROR ?? OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD;
          }
        });
      }
      let cancelled = false;
      const popup = new Popup({
        title: "Loading Inventory",
        body: [this.GetInventory.progressBody],
        simpleMode: true,
        onclose: () => {
          cancelled = true;
        }
      });
      this.GetInventory.closeButton.onclick = () => {
        popup.Hide();
      };
      const alreadyFinished = this.#inventory.willReturnImmediately();
      if (options.showProgress && !alreadyFinished) {
        popup.Show();
      }
      const success = await this.#inventory() !== void 0;
      if (cancelled || !success) {
        return;
      }
      if (options.showProgress && !alreadyFinished) {
        await Sleep(500);
        popup.Hide();
      }
      return await this.#inventory();
    }
  };
  var instance = new Script();
  var script_default = instance;

  // src/utils/worker.js
  var Worker = class {
    #queue = [];
    #activeTasks = 0;
    #concurrentLimit;
    #delay;
    #running = false;
    cancelled = false;
    constructor(options = {}) {
      const { concurrentLimit = 1, delay = 0 } = options;
      this.#concurrentLimit = typeof concurrentLimit === "function" ? concurrentLimit : () => concurrentLimit;
      this.#delay = delay;
    }
    Add(task, options = {}) {
      if (this.cancelled) {
        return;
      }
      if (options.priority ?? false) {
        this.#queue.unshift(task);
      } else {
        this.#queue.push(task);
      }
    }
    Run() {
      if (this.#running) {
        return;
      }
      this.#running = true;
      (async () => {
        while (this.#queue.length > 0) {
          if (this.#activeTasks < this.#concurrentLimit()) {
            const task = this.#queue.shift();
            this.#activeTasks++;
            (async () => {
              try {
                await task();
              } finally {
                this.#activeTasks--;
              }
            })();
          } else {
            await Sleep(50);
          }
          if (this.#queue.length > 0) {
            await Sleep(this.#delay);
          }
        }
        this.#running = false;
      })();
    }
    async Finish() {
      while (this.#activeTasks > 0 || this.#queue.length > 0) {
        await Sleep(50);
      }
    }
    async Cancel() {
      this.cancelled = true;
      this.#queue.length = 0;
      await this.Finish();
    }
  };

  // src/cs2/items/assets/asset.js
  var Asset = class _Asset {
    _assetid;
    _type;
    _inspectLink;
    _inspectData;
    _wearData;
    static _inspectionWorker = new Worker({
      concurrentLimit: () => {
        return script_default.AccountsConnected;
      }
    });
    static TYPE = {
      WEARABLE: 0,
      KEYCHAIN: 1,
      STORAGE_UNIT: 2,
      OTHER: 3
    };
    ShouldInspect() {
      return this._type == _Asset.TYPE.WEARABLE && this._inspectLink != "undefined";
    }
    async _Inspect(options = {}) {
      if (!this.ShouldInspect() || !this._assetid) {
        return;
      }
      const cacheOnly = options.cacheOnly ?? false;
      const cache_id = `item_${this._assetid}`;
      const cache = await Cache.GetValue(cache_id, null);
      if (cache) {
        const ageHours = (+/* @__PURE__ */ new Date() - cache.created) / 36e5;
        const maxAgeHours = GetSetting(SETTING_INSPECT_CACHE_TIME_HOURS);
        const cacheExpired = maxAgeHours >= 0 && ageHours >= maxAgeHours;
        if (!cacheExpired) {
          this._inspectData = cache;
        }
      }
      if (!this._inspectData) {
        if (cacheOnly) {
          return false;
        }
        let inspectData;
        for (let attempt = 0; attempt < 3; attempt++) {
          try {
            inspectData = await asf_default.Send("CS2Interface", "InspectItem", "GET", "ASF", { url: this._inspectLink });
            break;
          } catch (e) {
            if (e.code === 504) {
              script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
            } else {
              throw e;
            }
          }
        }
        if (!inspectData) {
          throw new Error(`Failed to inspect item: ${this._inspectLink}`);
        }
        if (!inspectData.iteminfo) {
          console.log(inspectData);
          throw new Error(`Invalid inspect data, check browser logs, ${this._inspectLink}`);
        }
        this._inspectData = {
          created: +/* @__PURE__ */ new Date()
        };
        if (typeof inspectData.wear !== "undefined" && typeof inspectData.wear_min !== "undefined" && typeof inspectData.wear_max !== "undefined") {
          this._inspectData.wear = inspectData.wear;
          this._inspectData.wearMin = inspectData.wear_min;
          this._inspectData.wearMax = inspectData.wear_max;
        }
        if (typeof inspectData.iteminfo.paintseed !== "undefined") {
          this._inspectData.seed = inspectData.iteminfo.paintseed;
        }
        if (typeof inspectData.iteminfo.rarity !== "undefined") {
          this._inspectData.rarity = inspectData.iteminfo.rarity;
        }
        if (typeof inspectData.iteminfo.quality !== "undefined") {
          this._inspectData.quality = inspectData.iteminfo.quality;
        }
        if (inspectData.stattrak === true) {
          this._inspectData.stattrak = true;
        }
        if ((inspectData.iteminfo.stickers?.length ?? 0) > 0) {
          this._inspectData.stickers = inspectData.iteminfo.stickers.map((sticker) => sticker.wear ?? 0);
        }
        if ((inspectData.iteminfo.keychains?.length ?? 0) > 0) {
          this._inspectData.charm = inspectData.iteminfo.keychains[0].pattern;
        }
        Cache.SetValue(cache_id, this._inspectData);
      }
      if (typeof this._inspectData.wear !== "undefined") {
        this._wearData = _Asset.GetWear(this._inspectData.wear);
        if (!this._wearData) {
          throw new Error(`Invalid item wear: ${this._inspectData.wear}, ${this._inspectLink}`);
        }
      }
      return true;
    }
    static GetWear(wearValue) {
      for (const wear of WEARS) {
        if (wearValue >= wear.min && wearValue <= wear.max) {
          return wear;
        }
      }
    }
    static GetPercentileElement(wear, wearValue, wearMin, wearMax, options = {}) {
      const showTooltip = options.showTooltip ?? false;
      const showRounded = options.rounded ?? true;
      const exteriorWearMin = Math.max(wearMin, wear.min);
      const exteriorWearMax = Math.min(wearMax, wear.max);
      const percentile = (1 - (wearValue - exteriorWearMin) / (exteriorWearMax - exteriorWearMin)) * 100;
      const percentileRounded = Math.min(99, Math.round(percentile));
      const percentileFixed = Math.min(99.99, parseFloat(percentile.toFixed(2)));
      const bestWear = _Asset.GetWear(wearMin);
      const worstWear = _Asset.GetWear(wearMax);
      let rank;
      if (wear == bestWear) {
        if (percentileFixed >= 99.9) {
          rank = "gold";
        } else if (percentileFixed >= 99.5) {
          rank = "silver";
        } else if (percentileRounded >= 99) {
          rank = "bronze";
        }
      } else if (wear == worstWear && percentileRounded == 0) {
        rank = "rust";
      }
      const percentileElement = CreateElement("span", {
        text: showRounded ? `(${percentileRounded}%)` : `(${percentileFixed}%)`
      });
      if (rank) {
        percentileElement.classList.add(`cs2s_asset_rank_${rank}`);
      }
      if (showTooltip) {
        BindTooltip(percentileElement, `Better than ${percentileFixed}% of ${wear.nameLong} floats`);
      }
      return percentileElement;
    }
    static GetNumCosmetics(item) {
      if (typeof item.cosmetics !== "undefined") {
        return item.cosmetics;
      }
      let count = 0;
      if (item.keychains) {
        count++;
      }
      if (item.stickers) {
        for (let slotNum = 0; slotNum < STICKER_MAX_COUNT; slotNum++) {
          let stickerID = item.attributes[`sticker slot ${slotNum} id`];
          if (stickerID) {
            count++;
          }
        }
      }
      item.cosmetics = count;
      return item.cosmetics;
    }
    _GetPercentileElement(options = {}) {
      if (!this._inspectData || !this._wearData) {
        return;
      }
      return _Asset.GetPercentileElement(this._wearData, this._inspectData.wear, this._inspectData.wearMin, this._inspectData.wearMax, options);
    }
    _GetWearRangeElement(highlightHalfwayPoint = false) {
      if (!this._inspectData.wear) {
        return;
      }
      const wearRangeElement = CreateElement("div", {
        class: "descriptor cs2s_asset_wear_range"
      });
      for (const wear of WEARS) {
        const { wearMin, wearMax, wear: actualWear } = this._inspectData;
        const range = wear.max - wear.min;
        const isMinWear = wearMin > 0 && wearMin >= wear.min && wearMin < wear.max;
        const isMaxWear = wearMax < 1 && wearMax > wear.min && wearMax <= wear.max;
        const isRollableWear = wearMax > wear.min && wearMin < wear.max;
        const wearGroupElement = CreateElement("div", {
          class: `cs2s_asset_wear_range_${wear.name.toLowerCase()}`
        });
        wearRangeElement.append(wearGroupElement);
        if (isMinWear) {
          const percentage = (1 - (wearMin - wear.min) / range) * 100;
          wearGroupElement.classList.add("cs2s_asset_wear_range_right");
          wearGroupElement.style.setProperty("--wear-percentage", `${percentage.toFixed(0)}%`);
          wearGroupElement.append(
            CreateElement("div", {
              class: "cs2s_asset_wear_range_low",
              wear_value: wearMin.toFixed(2),
              vars: {
                "wear-percentage": `${percentage.toFixed(0)}%`
              }
            })
          );
        }
        if (isMaxWear) {
          const percentage = (wearMax - wear.min) / range * 100;
          wearGroupElement.classList.add("cs2s_asset_wear_range_left");
          wearGroupElement.style.setProperty("--wear-percentage", `${percentage.toFixed(0)}%`);
          wearGroupElement.append(
            CreateElement("div", {
              class: "cs2s_asset_wear_range_high",
              wear_value: wearMax.toFixed(2),
              vars: {
                "wear-percentage": `${percentage.toFixed(0)}%`
              }
            })
          );
        }
        if (isRollableWear && !isMinWear && !isMaxWear) {
          wearGroupElement.classList.add("cs2s_asset_wear_range_full");
        }
        if (!isRollableWear) {
          wearGroupElement.classList.add("cs2s_asset_wear_range_empty");
        }
        if (this._wearData == wear) {
          let percentage;
          if (highlightHalfwayPoint) {
            const halfWayPoint = (Math.min(wear.max, wearMax) + Math.max(wear.min, wearMin)) / 2;
            percentage = (halfWayPoint - wear.min) / range * 100;
          } else {
            percentage = (actualWear - wear.min) / range * 100;
          }
          wearGroupElement.append(
            CreateElement("div", {
              class: "cs2s_asset_wear_range_marker",
              vars: {
                "wear-percentage": `${percentage.toFixed(0)}%`
              }
            })
          );
        }
      }
      return wearRangeElement;
    }
  };

  // src/components/table.js
  var Table = class _Table {
    #mode;
    #casket;
    #multiCasket;
    #data;
    #filteredData;
    #inventory;
    #selectionLimit;
    #rowElements = [];
    #selectedRows = /* @__PURE__ */ new Set();
    #selectedRowsSaved = /* @__PURE__ */ new Set();
    #lastStartRow;
    #lastRowClicked = null;
    #lastRowSelected = null;
    #inventoryChanged = false;
    #sortColumns = null;
    #sortDirection = null;
    #filterables = null;
    #filter = null;
    #searchQuery = null;
    static ROW_HEIGHT = 69;
    static BUFFER_ROWS = 3;
    #VISIBLE_ROWS;
    get #NUM_ROW_ELEMENTS() {
      return this.#VISIBLE_ROWS + _Table.BUFFER_ROWS * 2;
    }
    #popup;
    #tableContainer;
    #table;
    #tableBody;
    #spacer;
    #selectionLimitCount;
    #selectionCount;
    #clearSelectionButton;
    #filterCount;
    #actionButton;
    static MODE = {
      STORE: 0,
      RETRIEVE: 1
    };
    static SORT_DIRECTION = {
      ASC: 0,
      DESC: 1
    };
    constructor(data, inventory, options) {
      this.#data = data;
      this.#filteredData = data;
      this.#inventory = inventory;
      this.#mode = options.mode;
      this.#casket = options.casket ?? null;
      this.#multiCasket = options.multiCasket ?? false;
      this.#VISIBLE_ROWS = Math.max(1, Math.floor(unsafeWindow.innerHeight * 0.66 / _Table.ROW_HEIGHT));
      this.#data.map((item) => delete item.element);
      this.#tableBody = CreateElement("tbody");
      this.#spacer = CreateElement("div");
      this.#table = CreateElement("table", {
        class: "cs2s_table",
        children: [
          CreateElement("thead", {
            children: [
              CreateElement("tr", {
                children: [
                  CreateElement("th", {
                    class: "cs2s_table_image_column"
                  }),
                  CreateElement("th", {
                    class: "cs2s_table_name_column",
                    children: [
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Name",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["name", "wear"] });
                        }
                      }),
                      CreateElement("span", {
                        class: "cs2s_table_column_search cs2s_resizable_input",
                        children: [
                          CreateElement("input", {
                            type: "search",
                            placeholder: "Search",
                            oninput: (event) => {
                              event.target.style.width = "0px";
                              event.target.parentNode.dataset.value = event.target.value || event.target.placeholder;
                              event.target.style.width = `${event.target.parentNode.clientWidth}px`;
                              this.#searchQuery = event.currentTarget.value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
                              this.#FilterRows(false);
                            }
                          })
                        ]
                      })
                    ]
                  }),
                  CreateElement("th", {
                    class: "cs2s_table_collection_column",
                    children: [
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Quality",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["rarity", "quality", "collection", "name", "wear"] });
                        }
                      }),
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Collection",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["collection", "rarity", "quality", "name", "wear"] });
                        }
                      })
                    ]
                  }),
                  CreateElement("th", {
                    class: "cs2s_table_float_column",
                    children: [
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Float",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["wear"] });
                        }
                      })
                    ]
                  }),
                  CreateElement("th", {
                    class: "cs2s_table_seed_column",
                    children: [
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Seed",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["seed"] });
                        }
                      })
                    ]
                  }),
                  this.#multiCasket && CreateElement("th", {
                    class: "cs2s_table_crate_column",
                    children: [
                      CreateElement("span", {
                        class: "cs2s_table_column",
                        text: "Storage Unit",
                        children: [
                          CreateElement("div", {
                            class: "cs2s_table_column_sort"
                          })
                        ],
                        onclick: (event) => {
                          this.#SortRows({ event, columns: ["casket_name", "id"] });
                        }
                      })
                    ]
                  })
                ]
              })
            ]
          }),
          this.#tableBody,
          this.#spacer
        ]
      });
      this.#tableContainer = CreateElement("div", {
        class: "cs2s_table_container",
        style: {
          height: `${(this.#VISIBLE_ROWS + 1) * _Table.ROW_HEIGHT}px`
        },
        onscroll: () => {
          this.#UpdateRows();
        },
        children: [this.#table]
      });
      if (this.#mode === _Table.MODE.RETRIEVE) {
        this.#selectionLimit = INVENTORY_ITEM_LIMIT - inventory.items.length;
      } else {
        this.#selectionLimit = STORAGE_UNIT_ITEM_LIMIT - inventory.storedItems.filter((x) => x.casket_id == this.#casket.iteminfo.id).length;
      }
      const onStatusUpdate = (status) => {
        if (this.#mode !== _Table.MODE.RETRIEVE || typeof status.Plugin?.InventorySize === "undefined") {
          return;
        }
        this.#selectionLimit = INVENTORY_ITEM_LIMIT - status.Plugin.InventorySize;
        this.#UpdateFooter();
      };
      this.#filterCount = CreateElement("span", {
        class: "cs2s_table_footer_selection_count",
        text: this.#data.length.toLocaleString()
      });
      this.#selectionLimitCount = CreateElement("span", {
        class: "cs2s_table_footer_selection_count",
        text: this.#selectionLimit.toLocaleString()
      });
      this.#selectionCount = CreateElement("span", {
        class: "cs2s_table_footer_selection_count",
        text: 0
      });
      this.#clearSelectionButton = CreateElement("a", {
        class: "cs2s_table_footer_action_link",
        // text: "Clear",
        onclick: () => {
          this.#DeselectAll();
          this.#tableContainer.focus();
        },
        children: [
          CreateElement("span", {
            htmlChildren: [
              /*html*/
              `
						<svg width="16" height="16" viewBox="0 0 32 32" aria-hidden="true" stroke="none" fill="currentColor">
							<path d="m 15.5,29.5 c -7.18,0 -13,-5.82 -13,-13 0,-7.18 5.82,-13 13,-13 7.18,0 13,5.82 13,13 0,7.18 -5.82,13 -13,13 z m 6.438,-13.562 c 0,-0.552 -0.448,-1 -1,-1 h -11 c -0.553,0 -1,0.448 -1,1 v 1 c 0,0.553 0.447,1 1,1 h 11 c 0.552,0 1,-0.447 1,-1 z"></path>
						</svg>
					`
            ],
            children: [
              "Clear"
            ]
          })
        ]
      });
      this.#actionButton = CreateElement("a", {
        class: "cs2s_green_button cs2s_button_disabled",
        html: "<span>Proceed...</span>",
        onclick: () => {
          if (this.#actionButton.classList.contains("cs2s_button_disabled")) {
            return;
          }
          if (!script_default.Bot?.Plugin?.Connected) {
            script_default.ShowStartInterfacePrompt({
              message: this.#mode === _Table.MODE.RETRIEVE ? "Interface must running to retrieve items" : "Interface must running to store items",
              autoClose: true,
              popoverMode: true,
              fade: false,
              onclose: () => {
                this.#tableContainer.focus();
              },
              onconnected: () => {
                this.#inventoryChanged = true;
                this.#ProcessSelected();
              }
            });
            return;
          }
          this.#ProcessSelected();
        }
      });
      const footerContainer = CreateElement("div", {
        class: "cs2s_table_footer cs2s_popup_footer",
        children: [
          CreateElement("div", {
            class: "cs2s_table_footer_element_left",
            children: [
              CreateElement("span", {
                children: [
                  CreateElement("a", {
                    class: "cs2s_table_footer_action_link",
                    onclick: (event) => {
                      this.#ShowFilters(event.currentTarget);
                    },
                    children: [
                      CreateElement("span", {
                        htmlChildren: [
                          /*html*/
                          `
												<svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" fill="currentColor">
													<path d="m 3,5 h 18 a 1,1 0 1 1 0,2 H 3 A 1,1 0 1 1 3,5 Z m 3,6 h 12 a 1,1 0 1 1 0,2 H 6 a 1,1 0 1 1 0,-2 z m 3,6 h 6 a 1,1 0 1 1 0,2 H 9 a 1,1 0 1 1 0,-2 z"/>
												</svg>
											`
                        ],
                        children: [
                          "Filter"
                        ]
                      })
                    ]
                  }),
                  this.#filterCount,
                  " Item(s)"
                ]
              }),
              CreateElement("span", {
                children: [
                  CreateElement("form", {
                    style: {
                      display: "inline-block"
                    },
                    onsubmit: (event) => {
                      event.preventDefault();
                      const countInput = event.target.elements["count"];
                      const count = parseInt(countInput.value || countInput.placeholder);
                      this.#SelectFirst(count);
                    },
                    children: [
                      CreateElement("button", {
                        class: "cs2s_table_footer_action_link",
                        children: [
                          CreateElement("span", {
                            htmlChildren: [
                              /*html*/
                              `
														<svg width="16" height="16" viewBox="0 0 32 32" aria-hidden="true" stroke="none" fill="currentColor">
															<path d="M15.5 29.5c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13zM21.938 15.938c0-0.552-0.448-1-1-1h-4v-4c0-0.552-0.447-1-1-1h-1c-0.553 0-1 0.448-1 1v4h-4c-0.553 0-1 0.448-1 1v1c0 0.553 0.447 1 1 1h4v4c0 0.553 0.447 1 1 1h1c0.553 0 1-0.447 1-1v-4h4c0.552 0 1-0.447 1-1v-1z"></path>
														</svg>
													`
                            ],
                            children: [
                              "Select"
                            ]
                          })
                        ]
                      }),
                      CreateElement("span", {
                        onclick: (event) => {
                          const input = event.target.querySelector("input");
                          input && input.focus();
                        },
                        children: [
                          "First ",
                          CreateElement("span", {
                            class: "cs2s_table_footer_input cs2s_resizable_input",
                            children: [
                              CreateElement("input", {
                                type: "number",
                                name: "count",
                                min: 0,
                                placeholder: 0,
                                style: {
                                  width: "10px"
                                },
                                oninput: (event) => {
                                  event.target.style.width = "0px";
                                  event.target.parentNode.dataset.value = event.target.value || event.target.placeholder;
                                  event.target.style.width = `${event.target.parentNode.clientWidth}px`;
                                }
                              })
                            ]
                          }),
                          " Item(s)"
                        ]
                      })
                    ]
                  })
                ]
              })
            ]
          }),
          CreateElement("div", {
            class: "cs2s_table_footer_element_right",
            children: [
              CreateElement("span", {
                children: [
                  this.#selectionLimitCount,
                  " Space(s) Available"
                ]
              }),
              CreateElement("span", {
                children: [
                  this.#clearSelectionButton,
                  this.#selectionCount,
                  " Item(s) Selected"
                ]
              }),
              this.#actionButton
            ]
          })
        ]
      });
      const popupTitle = this.#mode === _Table.MODE.RETRIEVE ? "Select items to retrieve from " : "Select items to move into ";
      const cachedNotification = CreateElement("span", {
        text: "(Cached)"
      });
      BindTooltip(cachedNotification, "The information below was loaded from cache and may no longer be accurate.");
      const popupTitleCrateName = CreateElement("span", {
        class: "cs2s_table_title_casket",
        text: this.#multiCasket ? options.casketName : `"${options.casketName}"`,
        children: [
          this.#inventory.loadedFromCache && " ",
          this.#inventory.loadedFromCache && cachedNotification
        ]
      });
      if (this.#multiCasket) {
        popupTitleCrateName.classList.add("cs2s_table_title_casket_multiple");
      }
      script_default.AddStatusUpdateListener(onStatusUpdate);
      this.#popup = new Popup({
        title: popupTitle,
        titleChildren: [
          popupTitleCrateName
        ],
        body: [this.#tableContainer, footerContainer],
        onclose: () => {
          script_default.RemovetatusUpdateListener(onStatusUpdate);
          if (this.#inventoryChanged) {
            window.location.reload();
          }
        }
      });
    }
    Show() {
      this.#popup.Show();
      this.#UpdateTable();
      this.#tableContainer.focus();
      this.#tableContainer.style.width = `${this.#tableContainer.offsetWidth}px`;
      this.#tableContainer.querySelectorAll("thead th").forEach((th) => {
        th.style.width = getComputedStyle(th).width;
      });
    }
    #GetRowElement(item, buildIfDoesntExist = true) {
      if (item.element) {
        return item.element;
      }
      if (!buildIfDoesntExist) {
        return;
      }
      const cosmetics = CreateElement("div", {
        class: "cs2s_table_image_column_cosmetics"
      });
      if (item.keychains) {
        let keychainID = item.attributes[`keychain slot 0 id`];
        if (keychainID) {
          cosmetics.append(CreateElement("img", {
            src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.keychains[keychainID].full_name]}/25fx19f`
          }));
        }
      }
      if (item.stickers) {
        for (let slotNum = 0; slotNum < STICKER_MAX_COUNT; slotNum++) {
          let stickerID = item.attributes[`sticker slot ${slotNum} id`];
          if (stickerID) {
            cosmetics.append(CreateElement("img", {
              src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.stickers[stickerID].full_name]}/25fx19f`
            }));
          }
        }
      }
      const imageTD = CreateElement("td", {
        class: "cs2s_table_image_column",
        children: [
          CreateElement("img", {
            src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.full_name]}/93fx62f`
          }),
          cosmetics
        ]
      });
      const nameTD = CreateElement("td", {
        class: "cs2s_table_name_column",
        text: item.name,
        children: [
          CreateElement("a", {
            href: `https://steamcommunity.com/market/listings/${CS2_APPID}/${encodeURIComponent(item.full_name)}`,
            target: "_blank",
            html: (
              /*html*/
              `
						<svg viewBox="0 0 64 64" stroke-width="3" stroke="currentColor" fill="none">
							<path d="M55.4,32V53.58a1.81,1.81,0,0,1-1.82,1.82H10.42A1.81,1.81,0,0,1,8.6,53.58V10.42A1.81,1.81,0,0,1,10.42,8.6H32"/>
							<polyline points="40.32 8.6 55.4 8.6 55.4 24.18"/>
							<line x1="19.32" y1="45.72" x2="54.61" y2="8.91"/>
						</svg>
					`
            )
          })
        ]
      });
      const collectionTD = CreateElement("td", {
        class: "cs2s_table_collection_column"
      });
      if (item.collection) {
        collectionTD.innerText = item.collection;
      }
      if (item.collection || item.rarity > 1) {
        collectionTD.classList.add("cs2s_table_collection_column_has_rarity");
        collectionTD.classList.add(`cs2s_table_collection_column_rarity_${item.rarity}`);
        collectionTD.classList.add(`cs2s_table_collection_column_quality_${item.iteminfo.quality}`);
        if (item.stattrak) {
          collectionTD.classList.add(`cs2s_table_collection_column_stattrak`);
        }
      }
      const floatTD = CreateElement("td", {
        class: "cs2s_table_float_column"
      });
      if (typeof item.wear !== "undefined") {
        const wearData = Asset.GetWear(item.wear);
        floatTD.classList.add("cs2s_table_float_column_has_float");
        floatTD.classList.add(`cs2s_table_float_column_float_${wearData.name.toLowerCase()}`);
        floatTD.innerText = item.wear.toFixed(14);
        floatTD.append(" ");
        floatTD.append(Asset.GetPercentileElement(wearData, item.wear, item.wear_min, item.wear_max));
      }
      const seedTD = CreateElement("td", {
        class: "cs2s_table_seed_column",
        text: item.seed ?? ""
      });
      const casketTD = this.#multiCasket && CreateElement("td", {
        class: "cs2s_table_crate_column",
        text: item.casket_name
      });
      item.element = CreateElement("tr", {
        onmousedown: (event) => {
          if (event.target.nodeName === "A" || event.target.parentElement.nodeName === "A" || event.button !== 0) {
            return;
          }
          this.#SelectItem(event, item);
        },
        children: [
          imageTD,
          nameTD,
          collectionTD,
          floatTD,
          seedTD,
          casketTD
        ]
      });
      if (this.#selectedRows.has(item.iteminfo.id)) {
        item.element.classList.add("cs2s_table_row_selected");
      }
      return item.element;
    }
    #UpdateTable() {
      this.#lastStartRow = Number.POSITIVE_INFINITY;
      for (let i = 0; i < this.#rowElements.length; i++) {
        this.#rowElements[i].remove();
      }
      this.#rowElements = [];
      for (let i = 0; i < this.#NUM_ROW_ELEMENTS; i++) {
        if (i >= this.#filteredData.length) {
          break;
        }
        const rowElement = this.#GetRowElement(this.#filteredData[i]);
        this.#rowElements.push(rowElement);
        this.#tableBody.append(rowElement);
      }
      this.#spacer.style.height = "0px";
      this.#spacer.style.height = `${this.#filteredData.length * _Table.ROW_HEIGHT - this.#table.clientHeight + 31}px`;
      this.#UpdateRows();
      this.#UpdateFooter();
      if (this.#data.length == 0) {
        this.#tableBody.append(CreateElement("tr", {
          children: [
            CreateElement("td", {
              class: "cs2s_table_empty",
              colspan: 6,
              text: this.#mode == _Table.MODE.RETRIEVE ? "Storage Unit is empty" : "Inventory has no storable items"
            })
          ]
        }));
      }
    }
    #UpdateRows() {
      const startRow = Math.max(
        0,
        Math.min(
          this.#filteredData.length - this.#NUM_ROW_ELEMENTS,
          Math.floor(this.#tableContainer.scrollTop / _Table.ROW_HEIGHT) - _Table.BUFFER_ROWS
        )
      );
      if (startRow == this.#lastStartRow) {
        return;
      }
      const diff = Math.max(
        -this.#NUM_ROW_ELEMENTS,
        Math.min(
          this.#NUM_ROW_ELEMENTS,
          startRow - this.#lastStartRow
        )
      );
      this.#lastStartRow = startRow;
      if (diff > 0) {
        for (let i = 0; i < diff; i++) {
          const dataIndex = startRow + this.#NUM_ROW_ELEMENTS - diff + i;
          if (dataIndex >= this.#filteredData.length || dataIndex < 0) {
            continue;
          }
          const oldRow = this.#rowElements.shift();
          oldRow.remove();
          const newRow = this.#GetRowElement(this.#filteredData[dataIndex]);
          this.#rowElements.push(newRow);
          this.#tableBody.append(newRow);
        }
      } else {
        for (let i = 0; i < Math.abs(diff); i++) {
          const dataIndex = startRow - diff - i - 1;
          if (dataIndex >= this.#filteredData.length || dataIndex < 0) {
            continue;
          }
          const oldRow = this.#rowElements.pop();
          oldRow.remove();
          const newRow = this.#GetRowElement(this.#filteredData[dataIndex]);
          this.#rowElements.unshift(newRow);
          this.#tableBody.prepend(newRow);
        }
      }
      this.#tableBody.style.transform = `translate3d(0, ${startRow * _Table.ROW_HEIGHT}px, 0)`;
    }
    #UpdateFooter() {
      this.#selectionLimitCount.innerText = this.#selectionLimit.toLocaleString();
      this.#selectionCount.innerText = this.#selectedRows.size.toLocaleString();
      this.#filterCount.innerText = this.#filteredData.length.toLocaleString();
      if (this.#selectedRows.size <= 0) {
        this.#actionButton.classList.add("cs2s_button_disabled");
        BindTooltip(this.#actionButton, "No items selected");
      } else if (this.#selectedRows.size > this.#selectionLimit) {
        this.#actionButton.classList.add("cs2s_button_disabled");
        BindTooltip(this.#actionButton, "Too many items selected");
      } else {
        this.#actionButton.classList.remove("cs2s_button_disabled");
        this.#actionButton.unbindTooltip && this.#actionButton.unbindTooltip();
      }
      if (this.#selectedRows.size > 0) {
        this.#clearSelectionButton.show();
      } else {
        this.#clearSelectionButton.hide();
      }
    }
    #SelectItem(event, item) {
      if (event.shiftKey) {
        if (!this.#lastRowClicked || this.#lastRowClicked == item || this.#lastRowSelected === null) {
          return;
        }
        const start = this.#filteredData.indexOf(this.#lastRowClicked);
        const end = this.#filteredData.indexOf(item);
        if (start < 0 || end < 0) {
          return;
        }
        const from = Math.min(start, end);
        const to = Math.max(start, end);
        for (let i = from; i <= to; i++) {
          const rowItem = this.#filteredData[i];
          const row = this.#GetRowElement(rowItem, false);
          const assetID = rowItem.iteminfo.id;
          if (!this.#lastRowSelected && this.#selectedRows.has(assetID)) {
            this.#selectedRows.delete(assetID);
            row && row.classList.remove("cs2s_table_row_selected");
          } else if (this.#lastRowSelected) {
            this.#selectedRows.add(assetID);
            row && row.classList.add("cs2s_table_row_selected");
          }
        }
      } else {
        const row = this.#GetRowElement(item);
        const assetID = item.iteminfo.id;
        if (this.#selectedRows.has(assetID)) {
          this.#lastRowSelected = false;
          this.#selectedRows.delete(assetID);
          row.classList.remove("cs2s_table_row_selected");
        } else {
          this.#lastRowSelected = true;
          this.#selectedRows.add(assetID);
          row.classList.add("cs2s_table_row_selected");
        }
      }
      this.#lastRowClicked = item;
      this.#UpdateFooter();
    }
    #SelectFirst(count) {
      for (let i = 0; i < count; i++) {
        if (i >= this.#filteredData.length) {
          break;
        }
        const rowItem = this.#filteredData[i];
        const row = this.#GetRowElement(rowItem, false);
        const assetID = rowItem.iteminfo.id;
        if (!this.#selectedRows.has(assetID)) {
          this.#selectedRows.add(assetID);
          row && row.classList.add("cs2s_table_row_selected");
        }
      }
      this.#lastRowClicked = null;
      this.#UpdateFooter();
    }
    #DeselectAll() {
      for (const item of this.#data) {
        const assetID = item.iteminfo.id;
        if (!this.#selectedRows.has(assetID)) {
          continue;
        }
        this.#selectedRows.delete(assetID);
        const row = this.#GetRowElement(item, false);
        row && row.classList.remove("cs2s_table_row_selected");
      }
      this.#lastRowClicked = null;
      this.#UpdateFooter();
    }
    #SortRows(options = {}) {
      if (this.#data.length == 0) {
        return;
      }
      if (options.columns) {
        if (this.#sortDirection != null && this.#sortColumns[0] != options.columns[0]) {
          this.#sortDirection = null;
        }
        this.#sortColumns = options.columns;
      }
      let resetSort = false;
      if (options.event) {
        if (this.#sortDirection === _Table.SORT_DIRECTION.DESC) {
          this.#sortColumns = ["casket_id", "id"];
          this.#sortDirection = _Table.SORT_DIRECTION.DESC;
          resetSort = true;
        } else if (this.#sortDirection === _Table.SORT_DIRECTION.ASC) {
          this.#sortDirection = _Table.SORT_DIRECTION.DESC;
        }
      }
      if (!this.#sortColumns) {
        return;
      }
      if (!this.#sortDirection) {
        this.#sortDirection = _Table.SORT_DIRECTION.ASC;
      }
      const asc = this.#sortDirection === _Table.SORT_DIRECTION.ASC;
      this.#filteredData.sort((a, b) => {
        for (const column of this.#sortColumns) {
          let valueA = a[column];
          let valueB = b[column];
          if (valueA === valueB) {
            continue;
          }
          if (typeof valueA === "undefined") {
            return 1;
          }
          if (typeof valueB === "undefined") {
            return -1;
          }
          if (typeof valueA === "string") {
            return asc ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
          }
          return asc ? valueA - valueB : valueB - valueA;
        }
        return 0;
      });
      if (options.event) {
        document.querySelectorAll(".cs2s_table_column_sort_asc").forEach((el) => {
          el.classList.remove("cs2s_table_column_sort_asc");
        });
        document.querySelectorAll(".cs2s_table_column_sort_desc").forEach((el) => {
          el.classList.remove("cs2s_table_column_sort_desc");
        });
        if (!resetSort) {
          if (asc) {
            options.event.target.querySelector(".cs2s_table_column_sort").classList.add("cs2s_table_column_sort_asc");
          } else {
            options.event.target.querySelector(".cs2s_table_column_sort").classList.add("cs2s_table_column_sort_desc");
          }
        }
      }
      this.#UpdateTable();
    }
    #FilterRows(updateSelected = true) {
      if (this.#data.length == 0) {
        return;
      }
      const inRange = (value, { min, max }) => {
        return !(typeof value === "undefined" || min != null && value < min || max != null && value > max);
      };
      const matches = (item) => {
        if (this.#filter?.selected && !this.#selectedRowsSaved.has(item.iteminfo.id)) {
          return false;
        }
        if (this.#filter?.float && !inRange(item.wear, this.#filter.float)) {
          return false;
        }
        if (this.#filter?.seed && !inRange(item.seed, this.#filter.seed)) {
          return false;
        }
        if (this.#filter?.cosmetics && !inRange(item.cosmetics, this.#filter.cosmetics)) {
          return false;
        }
        if (this.#filter?.quality != null && item.quality !== this.#filter.quality) {
          return false;
        }
        if (this.#filter?.rarity) {
          switch (this.#filter.rarity.key) {
            case "weapons":
              if (typeof item.wear === "undefined" || item.type_name === "Gloves") {
                return false;
              }
              break;
            case "agents":
              if (item.type_name !== "Agent") {
                return false;
              }
              break;
            case "other":
              if (typeof item.wear !== "undefined" && item.type_name !== "Gloves" || item.type_name === "Agent") {
                return false;
              }
              break;
          }
          if (item.iteminfo.rarity !== this.#filter.rarity.value) {
            return false;
          }
        }
        if (this.#filter?.type) {
          switch (this.#filter.type.key) {
            case "weapons":
              if (item.weapon_name !== this.#filter.type.value) {
                return false;
              }
              break;
            case "other":
              if (item.type_name !== this.#filter.type.value) {
                return false;
              }
              break;
          }
        }
        if (this.#filter?.collection && item.collection_name !== this.#filter.collection) {
          return false;
        }
        if (this.#searchQuery && !item.name_normalized.includes(this.#searchQuery)) {
          return false;
        }
        return true;
      };
      if (updateSelected) {
        this.#selectedRowsSaved = new Set(this.#selectedRows);
      }
      if (!this.#searchQuery && !this.#filter) {
        this.#filteredData = this.#data;
      } else {
        this.#filteredData = this.#data.filter(matches);
      }
      this.#tableContainer.scrollTop = 0;
      this.#SortRows();
      this.#UpdateTable();
    }
    #ShowFilters(button) {
      if (this.#filterables == null) {
        this.#filterables = {
          types: {
            weapons: /* @__PURE__ */ new Set(),
            other: /* @__PURE__ */ new Set()
          },
          qualities: {},
          rarities: {
            weapons: {},
            agents: {},
            other: {}
          },
          float: {
            min: Number.POSITIVE_INFINITY,
            max: Number.NEGATIVE_INFINITY,
            wears: {}
          },
          seed: {
            min: Number.POSITIVE_INFINITY,
            max: Number.NEGATIVE_INFINITY
          },
          cosmetics: {
            min: Number.POSITIVE_INFINITY,
            max: Number.NEGATIVE_INFINITY
          },
          collections: {
            empty_exists: false,
            weapons: /* @__PURE__ */ new Set(),
            stickers: /* @__PURE__ */ new Set(),
            charms: /* @__PURE__ */ new Set(),
            agents: /* @__PURE__ */ new Set(),
            patches: /* @__PURE__ */ new Set(),
            graffiti: /* @__PURE__ */ new Set(),
            other: /* @__PURE__ */ new Set()
          }
        };
        for (const item of this.#data) {
          if (item.type_name) {
            this.#filterables.types.other.add(item.type_name);
          }
          if (item.weapon_name) {
            this.#filterables.types.weapons.add(item.weapon_name);
          }
          if (item.quality_name) {
            this.#filterables.qualities[item.quality_name] = item.quality;
          }
          if (item.rarity_name) {
            if (typeof item.wear !== "undefined" && item.type_name !== "Gloves") {
              this.#filterables.rarities.weapons[item.rarity_name] = item.iteminfo.rarity;
            } else if (item.type_name === "Agent") {
              this.#filterables.rarities.agents[item.rarity_name] = item.iteminfo.rarity;
            } else {
              this.#filterables.rarities.other[item.rarity_name] = item.iteminfo.rarity;
            }
          }
          if (typeof item.wear != "undefined") {
            this.#filterables.float.min = Math.min(this.#filterables.float.min, item.wear);
            this.#filterables.float.max = Math.max(this.#filterables.float.max, item.wear);
            this.#filterables.float.wears[Asset.GetWear(item.wear).name] = true;
          }
          if (typeof item.seed != "undefined") {
            this.#filterables.seed.min = Math.min(this.#filterables.seed.min, item.seed);
            this.#filterables.seed.max = Math.max(this.#filterables.seed.max, item.seed);
          }
          {
            const count = Asset.GetNumCosmetics(item);
            this.#filterables.cosmetics.min = Math.min(this.#filterables.cosmetics.min, count);
            this.#filterables.cosmetics.max = Math.max(this.#filterables.cosmetics.max, count);
          }
          if (item.collection_name) {
            if (typeof item.wear !== "undefined") {
              this.#filterables.collections.weapons.add(item.collection_name);
            } else if (item.type_name === "Sticker") {
              this.#filterables.collections.stickers.add(item.collection_name);
            } else if (item.type_name === "Charm") {
              this.#filterables.collections.charms.add(item.collection_name);
            } else if (item.type_name === "Agent") {
              this.#filterables.collections.agents.add(item.collection_name);
            } else if (item.type_name === "Patch") {
              this.#filterables.collections.patches.add(item.collection_name);
            } else if (item.type_name === "Graffiti") {
              this.#filterables.collections.graffiti.add(item.collection_name);
            } else {
              this.#filterables.collections.other.add(item.collection_name);
            }
          } else {
            this.#filterables.collections.empty_exists = true;
          }
        }
        this.#filterables.float.min = Math.floor(this.#filterables.float.min * 100) / 100;
        this.#filterables.float.max = Math.ceil(this.#filterables.float.max * 100) / 100;
      }
      const floatMinValue = FLOAT_RANGE.min;
      const floatMaxValue = FLOAT_RANGE.max;
      const seedMinValue = SEED_RANGE.min;
      const seedMaxValue = SEED_RANGE.max;
      const cosmeticsMinValue = 0;
      const cosmeticsMaxValue = STICKER_MAX_COUNT + KEYCHAIN_MAX_COUNT;
      const type = CreateElement("select", {
        id: "type",
        disabled: Object.values(this.#filterables.types).reduce((sum, set) => sum + (set.size ?? 0), 0) < 2,
        children: [
          CreateElement("option", {
            value: ""
          }),
          ...[
            { key: "other", label: "Base Types" },
            { key: "weapons", label: "Weapon Types" }
          ].filter(({ key }) => this.#filterables.types[key].size > 0).map(
            ({ key, label }) => CreateElement("optgroup", {
              label,
              children: [...this.#filterables.types[key]].sort().map(
                (name) => CreateElement("option", {
                  text: name,
                  value: name,
                  selected: this.#filter?.type?.key === key && this.#filter?.type?.value === name,
                  dataset: {
                    key
                  }
                })
              )
            })
          )
        ]
      });
      if (type.disabled) {
        type.selectedIndex = type.options.length - 1;
      }
      const quality = CreateElement("select", {
        id: "quality",
        disabled: Object.keys(this.#filterables.qualities).length < 2,
        children: [
          CreateElement("option", {
            value: ""
          }),
          ...Object.entries(this.#filterables.qualities).sort(([, v1], [, v2]) => v1 - v2).map(
            ([qualityName, qualityValue]) => CreateElement("option", {
              text: qualityValue == 0 ? "Normal" : qualityName,
              value: qualityValue,
              selected: this.#filter?.quality === qualityValue,
              class: `cs2s_color_quality_${qualityValue}`
            })
          )
        ]
      });
      if (quality.disabled) {
        quality.selectedIndex = quality.options.length - 1;
      }
      const rarity = CreateElement("select", {
        id: "rarity",
        disabled: Object.values(this.#filterables.rarities).reduce((sum, obj) => sum + Object.keys(obj).length, 0) < 2,
        children: [
          CreateElement("option", {
            value: ""
          }),
          ...[
            { key: "weapons", label: "Weapon Qualities" },
            { key: "agents", label: "Agent Qualities" },
            { key: "other", label: "Base Qualities" }
          ].filter(({ key }) => Object.keys(this.#filterables.rarities[key]).length > 0).map(
            ({ key, label }) => CreateElement("optgroup", {
              label,
              children: Object.entries(this.#filterables.rarities[key]).sort(([, v1], [, v2]) => v1 - v2).map(
                ([rarityName, rarityValue]) => CreateElement("option", {
                  text: rarityName,
                  value: rarityValue,
                  selected: this.#filter?.rarity?.key === key && this.#filter?.rarity?.value === rarityValue,
                  class: `cs2s_color_rarity_${rarityValue}`,
                  dataset: {
                    key
                  }
                })
              )
            })
          )
        ]
      });
      if (rarity.disabled) {
        rarity.selectedIndex = rarity.options.length - 1;
      }
      const collection = CreateElement("select", {
        id: "collection",
        disabled: Object.values(this.#filterables.collections).reduce((sum, set) => sum + (set.size ?? 0), 0) < 2 - this.#filterables.collections.empty_exists,
        children: [
          CreateElement("option", {
            value: ""
          }),
          ...[
            { key: "weapons", label: "Weapon Collections" },
            { key: "agents", label: "Agent Collections" },
            { key: "stickers", label: "Sticker Collections" },
            { key: "patches", label: "Patch Collections" },
            { key: "charms", label: "Charm Collections" },
            { key: "graffiti", label: "Graffiti Collections" },
            { key: "other", label: "Other Collections" }
          ].filter(({ key }) => this.#filterables.collections[key].size > 0).map(
            ({ key, label }) => CreateElement("optgroup", {
              label,
              children: [...this.#filterables.collections[key]].sort().map(
                (name) => CreateElement("option", {
                  text: name,
                  value: name,
                  selected: this.#filter?.collection === name
                })
              )
            })
          )
        ]
      });
      if (collection.disabled) {
        collection.selectedIndex = collection.options.length - 1;
      }
      const floatMin = CreateElement("input", {
        id: "float_min",
        type: "number",
        step: 0.01,
        min: floatMinValue,
        max: floatMaxValue,
        placeholder: this.#filterables.float.min === Number.POSITIVE_INFINITY ? "" : this.#filterables.float.min,
        disabled: this.#filterables.float.min === Number.POSITIVE_INFINITY,
        oninput: () => {
          float.value = "custom";
          const value = floatMin.value;
          if (floatMin.checkValidity()) {
            if (value === "") {
              floatMax.min = floatMinValue;
            } else {
              floatMax.min = value;
            }
          }
        }
      });
      const floatMax = CreateElement("input", {
        id: "float_max",
        type: "number",
        step: 0.01,
        min: floatMinValue,
        max: floatMaxValue,
        placeholder: this.#filterables.float.max === Number.NEGATIVE_INFINITY ? "" : this.#filterables.float.max,
        disabled: this.#filterables.float.max === Number.NEGATIVE_INFINITY,
        oninput: () => {
          float.value = "custom";
          const value = floatMax.value;
          if (floatMax.checkValidity()) {
            if (value === "") {
              floatMin.max = floatMaxValue;
            } else {
              floatMin.max = value;
            }
          }
        }
      });
      if (typeof this.#filter?.float?.min !== "undefined" && this.#filter.float.min !== null) {
        floatMin.value = floatMax.min = this.#filter.float.min;
      }
      if (typeof this.#filter?.float?.max !== "undefined" && this.#filter.float.max !== null) {
        floatMax.value = floatMin.max = this.#filter.float.max;
      }
      const float = CreateElement("select", {
        id: "float",
        disabled: this.#filterables.float.max === Number.NEGATIVE_INFINITY,
        children: [
          CreateElement("option", {
            value: ""
          }),
          CreateElement("option", {
            hidden: true,
            value: "custom"
          }),
          ...WEARS.filter((wear) => this.#filterables.float.wears[wear.name] === true).map((wear) => CreateElement("option", {
            value: wear.name,
            text: wear.nameLong,
            selected: this.#filter?.wear === wear.name,
            class: `cs2s_color_wear_${wear.name.toLowerCase()}`
          }))
        ],
        onchange: (event) => {
          const value = event.target.value;
          if (value === "") {
            floatMin.value = "";
            floatMax.value = "";
            floatMin.max = floatMaxValue;
            floatMax.min = floatMinValue;
            return;
          }
          for (const wear of WEARS) {
            if (wear.name === value) {
              floatMin.value = wear.min;
              floatMax.value = wear.max;
              floatMin.max = floatMax.value;
              floatMax.min = floatMin.value;
              return;
            }
          }
        }
      });
      const seedMin = CreateElement("input", {
        id: "seed_min",
        type: "number",
        step: 1,
        min: seedMinValue,
        max: seedMaxValue,
        placeholder: this.#filterables.seed.min === Number.POSITIVE_INFINITY ? "" : this.#filterables.seed.min,
        disabled: this.#filterables.seed.min === Number.POSITIVE_INFINITY,
        oninput: () => {
          const value = seedMin.value;
          if (seedMin.checkValidity()) {
            if (value === "") {
              seedMax.min = seedMinValue;
            } else {
              seedMax.min = value;
            }
          }
        }
      });
      const seedMax = CreateElement("input", {
        id: "seed_max",
        type: "number",
        step: 1,
        min: seedMinValue,
        max: seedMaxValue,
        placeholder: this.#filterables.seed.max === Number.NEGATIVE_INFINITY ? "" : this.#filterables.seed.max,
        disabled: this.#filterables.seed.max === Number.NEGATIVE_INFINITY,
        oninput: () => {
          const value = seedMax.value;
          if (seedMax.checkValidity()) {
            if (value === "") {
              seedMin.max = seedMaxValue;
            } else {
              seedMin.max = value;
            }
          }
        }
      });
      if (typeof this.#filter?.seed?.min !== "undefined" && this.#filter.seed.min !== null) {
        seedMin.value = seedMax.min = this.#filter.seed.min;
      }
      if (typeof this.#filter?.seed?.max !== "undefined" && this.#filter.seed.max !== null) {
        seedMax.value = seedMin.max = this.#filter.seed.max;
      }
      const cosmeticsMin = CreateElement("input", {
        id: "cosmetics_min",
        type: "number",
        step: 1,
        min: cosmeticsMinValue,
        max: cosmeticsMaxValue,
        placeholder: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0 ? "" : this.#filterables.cosmetics.min,
        disabled: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0,
        oninput: () => {
          const value = cosmeticsMin.value;
          if (cosmeticsMin.checkValidity()) {
            if (value === "") {
              cosmeticsMax.min = cosmeticsMinValue;
            } else {
              cosmeticsMax.min = value;
            }
          }
        }
      });
      const cosmeticsMax = CreateElement("input", {
        id: "cosmetics_max",
        type: "number",
        step: 1,
        min: cosmeticsMinValue,
        max: cosmeticsMaxValue,
        placeholder: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0 ? "" : this.#filterables.cosmetics.max,
        disabled: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0,
        oninput: () => {
          const value = cosmeticsMax.value;
          if (cosmeticsMax.checkValidity()) {
            if (value === "") {
              cosmeticsMin.max = cosmeticsMaxValue;
            } else {
              cosmeticsMin.max = value;
            }
          }
        }
      });
      if (typeof this.#filter?.cosmetics?.min !== "undefined" && this.#filter.cosmetics.min !== null) {
        cosmeticsMin.value = cosmeticsMax.min = this.#filter.cosmetics.min;
      }
      if (typeof this.#filter?.cosmetics?.max !== "undefined" && this.#filter.cosmetics.max !== null) {
        cosmeticsMax.value = cosmeticsMin.max = this.#filter.cosmetics.max;
      }
      const selected = CreateElement("input", {
        id: "selected",
        type: "checkbox",
        disabled: this.#selectedRows.size == 0
      });
      if (this.#filter?.selected && this.#selectedRows.size > 0) {
        selected.checked = true;
      }
      const form = CreateElement("form", {
        class: "cs2s_settings_form cs2s_settings_filter",
        onreset: () => {
          floatMin.max = floatMaxValue;
          floatMax.min = floatMinValue;
          seedMin.max = seedMaxValue;
          seedMax.min = seedMinValue;
          cosmeticsMin.max = cosmeticsMaxValue;
          cosmeticsMax.min = cosmeticsMinValue;
        },
        children: [
          CreateElement("div", {
            class: "cs2s_settings_form_group_title" + (type.disabled && quality.disabled && rarity.disabled ? " cs2s_settings_form_disabled" : ""),
            text: "Base Filters"
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_group",
            children: [
              CreateElement("div", {
                class: "cs2s_settings_form_group_row",
                children: [
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item" + (type.disabled ? " cs2s_settings_form_disabled" : ""),
                    children: [
                      CreateElement("label", {
                        text: "Type",
                        for: "type"
                      }),
                      type
                    ]
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item" + (quality.disabled ? " cs2s_settings_form_disabled" : ""),
                    children: [
                      CreateElement("label", {
                        text: "Category",
                        for: "quality"
                      }),
                      quality
                    ]
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item" + (rarity.disabled ? " cs2s_settings_form_disabled" : ""),
                    children: [
                      CreateElement("label", {
                        text: "Quality",
                        for: "rarity"
                      }),
                      rarity
                    ]
                  })
                ]
              })
            ]
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_group_title" + (floatMax.disabled && seedMax.disabled && cosmeticsMax.disabled ? " cs2s_settings_form_disabled" : ""),
            text: "Skin Filters"
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_group",
            children: [
              CreateElement("div", {
                class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (floatMax.disabled ? " cs2s_settings_form_disabled" : ""),
                children: [
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item",
                    children: [
                      CreateElement("label", {
                        text: "Exterior",
                        for: "float"
                      }),
                      float
                    ]
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item",
                    children: [
                      CreateElement("label", {
                        text: "Float Min",
                        for: "float_min"
                      }),
                      floatMin
                    ]
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_separator",
                    text: "\u2014"
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_item",
                    children: [
                      CreateElement("label", {
                        text: "Float Max",
                        for: "float_max"
                      }),
                      floatMax
                    ]
                  })
                ]
              }),
              CreateElement("div", {
                class: "cs2s_settings_form_group_row",
                children: [
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (seedMax.disabled ? " cs2s_settings_form_disabled" : ""),
                    children: [
                      CreateElement("div", {
                        class: "cs2s_settings_form_group_item",
                        children: [
                          CreateElement("label", {
                            text: "Seed Min",
                            for: "seed_min"
                          }),
                          seedMin
                        ]
                      }),
                      CreateElement("div", {
                        class: "cs2s_settings_form_separator",
                        text: "\u2014"
                      }),
                      CreateElement("div", {
                        class: "cs2s_settings_form_group_item",
                        children: [
                          CreateElement("label", {
                            text: "Seed Max",
                            for: "seed_max"
                          }),
                          seedMax
                        ]
                      })
                    ]
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_separator",
                    text: " "
                  }),
                  CreateElement("div", {
                    class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (cosmeticsMax.disabled ? " cs2s_settings_form_disabled" : ""),
                    children: [
                      CreateElement("div", {
                        class: "cs2s_settings_form_group_item",
                        children: [
                          CreateElement("label", {
                            text: "Num Cosmetics Min",
                            for: "cosmetics_min"
                          }),
                          cosmeticsMin
                        ]
                      }),
                      CreateElement("div", {
                        class: "cs2s_settings_form_separator",
                        text: "\u2014"
                      }),
                      CreateElement("div", {
                        class: "cs2s_settings_form_group_item",
                        children: [
                          CreateElement("label", {
                            text: "Num Cosmetics Max",
                            for: "cosmetics_max"
                          }),
                          cosmeticsMax
                        ]
                      })
                    ]
                  })
                ]
              })
            ]
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_group_title" + (collection.disabled && selected.disabled ? " cs2s_settings_form_disabled" : ""),
            text: "Group Filters"
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_group",
            children: [
              CreateElement("div", {
                class: "cs2s_settings_form_group_item" + (collection.disabled ? " cs2s_settings_form_disabled" : ""),
                children: [
                  CreateElement("label", {
                    text: "Collection",
                    for: "collection"
                  }),
                  collection
                ]
              }),
              CreateElement("div", {
                class: "cs2s_settings_form_group_item cs2s_settings_form_group_item_checkbox" + (selected.disabled ? " cs2s_settings_form_disabled" : ""),
                children: [
                  selected,
                  CreateElement("label", {
                    text: "Show only selected items",
                    for: "selected"
                  })
                ]
              })
            ]
          }),
          CreateElement("div", {
            class: "cs2s_settings_form_submit_group",
            children: [
              CreateElement("button", {
                class: "cs2s_blue_long_button",
                type: "submit",
                text: "Filter"
              }),
              CreateElement("button", {
                class: "cs2s_grey_long_button",
                type: "reset",
                text: "Reset"
              }),
              CreateElement("button", {
                class: "cs2s_grey_long_button",
                id: "form_cancel",
                text: "Cancel"
              })
            ]
          })
        ]
      });
      const popup = new Popup({
        title: "Filter Items",
        body: [form],
        popoverMode: true,
        onclose: () => {
          this.#tableContainer.focus();
        }
      });
      form.querySelector("#form_cancel").onclick = () => {
        popup.Hide();
      };
      form.onsubmit = (event) => {
        event.preventDefault();
        this.#filter = {
          type: type.disabled || type.selectedIndex == 0 ? null : {
            key: type.selectedOptions[0].dataset.key,
            value: type.value
          },
          quality: quality.disabled || quality.selectedIndex == 0 ? null : parseInt(quality.value),
          rarity: rarity.disabled || rarity.selectedIndex == 0 ? null : {
            key: rarity.selectedOptions[0].dataset.key,
            value: parseInt(rarity.value)
          },
          wear: float.value == "" ? null : float.value,
          float: floatMin.value == "" && floatMax.value == "" ? null : {
            min: floatMin.value == "" ? null : parseFloat(floatMin.value),
            max: floatMax.value == "" ? null : parseFloat(floatMax.value)
          },
          seed: seedMin.value == "" && seedMax.value == "" ? null : {
            min: seedMin.value == "" ? null : parseInt(seedMin.value),
            max: seedMax.value == "" ? null : parseInt(seedMax.value)
          },
          cosmetics: cosmeticsMin.value == "" && cosmeticsMax.value == "" ? null : {
            min: cosmeticsMin.value == "" ? null : parseInt(cosmeticsMin.value),
            max: cosmeticsMax.value == "" ? null : parseInt(cosmeticsMax.value)
          },
          collection: collection.disabled || collection.selectedIndex == 0 ? null : collection.value,
          selected: selected.checked ? true : null
        };
        if (Object.values(this.#filter).every((value) => value === null)) {
          this.#filter = null;
        }
        if (this.#filter === null) {
          button.classList.remove("cs2s_table_footer_action_link_active");
        } else {
          button.classList.add("cs2s_table_footer_action_link_active");
        }
        popup.Hide();
        this.#FilterRows();
      };
      popup.Show();
    }
    async #ProcessSelected() {
      if (this.#selectedRows.size == 0) {
        return;
      }
      const numItemsToProcess = this.#selectedRows.size;
      const itemWindow = CreateElement("div", {
        class: "cs2s_action_item_window"
      });
      const progressMessage = CreateElement("div", {
        class: "cs2s_action_message",
        text: this.#mode == _Table.MODE.RETRIEVE ? "Retrieving Items" : "Storing Items"
      });
      const progressBar = CreateElement("div", {
        class: "cs2s_action_progress_bar",
        vars: {
          "percentage": "0%"
        }
      });
      const closeButton = CreateElement("div", {
        class: "cs2s_grey_long_button",
        text: "Cancel"
      });
      const popupBody = CreateElement("div", {
        class: "cs2s_action_body",
        children: [
          itemWindow,
          progressMessage,
          progressBar,
          closeButton
        ]
      });
      const worker = new Worker({
        concurrentLimit: 6,
        delay: 1e3 / 6
      });
      const popup = new Popup({
        title: this.#mode == _Table.MODE.RETRIEVE ? "Retrieving From Storage Unit" : "Moving To Storage Unit",
        body: [popupBody],
        simpleMode: true,
        popoverMode: true,
        onclose: () => {
          this.#tableContainer.focus();
          worker.Cancel();
        }
      });
      closeButton.onclick = () => {
        popup.Hide();
      };
      popup.Show();
      let numItemsProcessed = 0;
      for (const assetID of this.#selectedRows) {
        worker.Add(async () => {
          const item = this.#data.find((item2) => item2.iteminfo.id == assetID);
          const itemImage = CreateElement("div", {
            class: "cs2s_action_item_window_image",
            html: this.#GetRowElement(item).children[0].innerHTML
          });
          const maxAttempts = 3;
          for (let attempt = 1; attempt <= maxAttempts; attempt++) {
            if (worker.cancelled) {
              return;
            }
            try {
              if (this.#mode == _Table.MODE.RETRIEVE) {
                await this.#inventory.RetrieveItem(item);
              } else {
                await this.#inventory.StoreItem(item, this.#casket);
              }
              break;
            } catch (e) {
              if (worker.cancelled || e.code === 504 && attempt < maxAttempts) {
                script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
                await Sleep(Random(1e3, 2e3));
                continue;
              }
              worker.Cancel();
              popup.Hide();
              script_default.ShowError({ level: ERROR_LEVEL.HIGH }, e, new Error(`Failed to ${this.#mode == _Table.MODE.RETRIEVE ? "retrieve" : "store"} "${item.full_name}".  If errors persist, reload the page and try again.`));
              return;
            }
          }
          const dataIndex = this.#data.findIndex((item2) => item2.iteminfo.id == assetID);
          this.#data.splice(dataIndex, 1);
          const filteredDataIndex = this.#filteredData.findIndex((item2) => item2.iteminfo.id == assetID);
          filteredDataIndex != -1 && this.#filteredData.splice(filteredDataIndex, 1);
          this.#selectedRows.delete(assetID);
          this.#selectionLimit--;
          this.#inventoryChanged = true;
          this.#UpdateTable();
          numItemsProcessed++;
          progressMessage.innerText = (this.#mode == _Table.MODE.RETRIEVE ? "Retrieving Items" : "Storing Items") + ` (${numItemsProcessed}/${numItemsToProcess})`;
          progressBar.style.setProperty("--percentage", `${(numItemsProcessed / numItemsToProcess * 100).toFixed(2)}%`);
          itemWindow.append(itemImage);
          const transform = getComputedStyle(itemImage).transform;
          itemImage.style.transformOrigin = "50% 700%";
          const rotateStart = Random(-20, -10);
          const rotateEnd = Random(10, 20);
          const scaleEnd = Random(0.7, 0.8);
          const translateYEnd = Random(-215, -165);
          const duration = Random(700, 800);
          const itemAnimationIn = itemImage.animate([
            { transform: `${transform} rotate(${rotateStart}deg)`, opacity: 0.75, offset: 0 },
            { opacity: 1, filter: "brightness(1)", offset: 0.5 },
            { transform: `${transform} rotate(${rotateEnd}deg) scale(${scaleEnd}) translateY(${translateYEnd}%)`, opacity: 0.5, filter: "brightness(0.1)", offset: 1 }
          ], {
            duration,
            easing: "cubic-bezier(.15, .50, .85, .50)"
          });
          itemAnimationIn.onfinish = () => {
            itemImage.remove();
          };
        });
      }
      worker.Run();
      await worker.Finish();
      await Sleep(1e3);
      popup.Hide();
    }
  };

  // src/cs2/items/assets/inventory_asset.js
  var InventoryAsset = class extends Asset {
    _asset;
    constructor(asset) {
      super();
      this._assetid = asset.assetid;
      this._asset = asset;
      if (asset.description.market_hash_name == "Storage Unit") {
        this._type = Asset.TYPE.STORAGE_UNIT;
      } else {
        for (const tag of asset.description.tags) {
          if (tag.category == "Weapon" || tag.internal_name == "Type_Hands") {
            this._type = Asset.TYPE.WEARABLE;
            break;
          } else if (tag.internal_name == "CSGO_Tool_Keychain") {
            this._type = Asset.TYPE.KEYCHAIN;
            break;
          }
        }
      }
      if (typeof this._type == "undefined") {
        this._type = Asset.TYPE.OTHER;
      }
      if (this._type == Asset.TYPE.WEARABLE) {
        for (const action of asset.description.actions) {
          if (action.link.includes("steam://rungame")) {
            this._inspectLink = action.link.replace("%owner_steamid%", unsafeWindow.g_ActiveUser.strSteamId).replace("%assetid%", asset.assetid);
            break;
          }
        }
      }
    }
    async BuildInventoryUI() {
      if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
        const build = () => {
          if (!this._inspectData) {
            return;
          }
          if (this._inspectData.wear && this._wearData) {
            this._asset.element.append(
              CreateElement("div", {
                class: `cs2s_asset_wear cs2s_asset_wear_${this._wearData.name.toLowerCase()}`,
                text: this._inspectData.wear.toFixed(6),
                children: [
                  " ",
                  this._GetPercentileElement()
                  // createElement("div", {
                  // 	class: "cs2s_asset_wear_name",
                  // 	text: this._wearData.name
                  // })
                ]
              })
            );
          }
          if (this._inspectData.seed) {
            this._asset.element.append(
              CreateElement("div", {
                class: "cs2s_asset_seed",
                text: this._inspectData.seed
              })
            );
          }
          if (this._inspectData.rarity) {
            const el = CreateElement("div", {
              class: `cs2s_asset_rarity cs2s_asset_rarity_${this._inspectData.rarity} cs2s_asset_quality_${this._inspectData.quality}`
            });
            if (this._inspectData.stattrak) {
              el.classList.add("cs2s_asset_stattrak");
            }
            this._asset.element.append(el);
          }
          const cosmetics = [];
          for (const description of this._asset.description.descriptions) {
            if (description.name == "sticker_info" || description.name == "keychain_info") {
              const parser = new DOMParser();
              const doc = parser.parseFromString(description.value, "text/html");
              for (const img of doc.querySelectorAll("img")) {
                cosmetics.push(CreateElement("img", {
                  src: img.src
                }));
              }
            }
          }
          if (cosmetics.length > 0) {
            this._asset.element.append(
              CreateElement("div", {
                class: "cs2s_asset_cosmetics",
                children: cosmetics
              })
            );
          }
        };
        let cached;
        try {
          cached = await this._Inspect({ cacheOnly: true });
        } catch (e) {
          script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
          return;
        }
        if (cached) {
          build();
        } else {
          Asset._inspectionWorker.Add(async () => {
            try {
              await this._Inspect();
            } catch (e) {
              script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
              return;
            }
            build();
          });
          Asset._inspectionWorker.Run();
        }
      } else if (this._type == Asset.TYPE.KEYCHAIN && GetSetting(SETTING_INSPECT_ITEMS)) {
        let template;
        for (const description of this._asset.description.descriptions) {
          if (description.name == "attr: keychain slot 0 seed") {
            const matches = description.value.match(/\d+/);
            if (matches) {
              template = matches[0];
            }
            break;
          }
        }
        if (template) {
          this._asset.element.appendChild(
            CreateElement("div", {
              class: "cs2s_asset_seed",
              text: template
            })
          );
        }
      } else if (this._type == Asset.TYPE.STORAGE_UNIT) {
        let nameTag;
        let itemCount;
        for (const description of this._asset.description.descriptions) {
          if (description.name == "nametag") {
            const matches = description.value.match(/.*?''(.*?)''/);
            if (matches) {
              nameTag = matches[1];
            }
          } else if (description.name == "attr: items count") {
            const matches = description.value.match(/\d+/);
            if (matches) {
              itemCount = matches[0];
            }
          }
        }
        if (nameTag) {
          this._asset.element.append(
            CreateElement("div", {
              class: "cs2s_asset_name",
              text: nameTag
            })
          );
        }
        if (itemCount) {
          this._asset.element.append(
            CreateElement("div", {
              class: "cs2s_asset_quantity",
              text: itemCount
            })
          );
        }
      }
    }
    async BuildSelectedUI() {
      const selectedItem = unsafeWindow.iActiveSelectView;
      const descriptionsElement = unsafeWindow.document.getElementById(`iteminfo${selectedItem}_item_descriptors`);
      const stickerElements = descriptionsElement.getElementsBySelector("#sticker_info img");
      const charmElements = descriptionsElement.getElementsBySelector("#keychain_info img");
      const ownerActionsElement = unsafeWindow.document.getElementById(`iteminfo${selectedItem}_item_owner_actions`);
      if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
        const build = () => {
          if (selectedItem != unsafeWindow.iActiveSelectView || this._asset != unsafeWindow.g_ActiveInventory.selectedItem || !this._inspectData) {
            return;
          }
          if (this._inspectData.wear && this._inspectData.seed) {
            descriptionsElement.prepend(
              this._GetWearRangeElement(),
              CreateElement("div", {
                class: "descriptor",
                text: `Float: ${this._inspectData.wear.toFixed(14)}`,
                children: [
                  " ",
                  this._GetPercentileElement({ showTooltip: true, rounded: false })
                ]
              }),
              CreateElement("div", {
                class: "descriptor",
                text: `Seed: ${this._inspectData.seed}`
              }),
              CreateElement("div", {
                class: "descriptor",
                text: "\xA0"
              })
            );
          }
          if (this._inspectData.stickers) {
            for (let i = 0; i < this._inspectData.stickers.length; i++) {
              if (typeof stickerElements[i] == "undefined") {
                break;
              }
              stickerElements[i].wrap(
                CreateElement("span", {
                  class: "cs2s_asset_sticker_wear",
                  wear: Math.round(this._inspectData.stickers[i] * 100)
                })
              );
            }
          }
          if (this._inspectData.charm) {
            if (typeof charmElements[0] != "undefined") {
              charmElements[0].wrap(
                CreateElement("span", {
                  class: "cs2s_asset_charm_template",
                  template: this._inspectData.charm
                })
              );
            }
          }
        };
        let cached;
        try {
          cached = await this._Inspect({ cacheOnly: true });
        } catch (e) {
          script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
          return;
        }
        if (cached) {
          build();
        } else {
          Asset._inspectionWorker.Add(async () => {
            try {
              await this._Inspect();
            } catch (e) {
              script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
              return;
            }
            build();
          }, {
            priority: true
          });
          Asset._inspectionWorker.Run();
        }
      } else if (this._type == Asset.TYPE.STORAGE_UNIT) {
        ownerActionsElement.style.display = "block";
        ownerActionsElement.append(
          CreateElement("a", {
            class: "btn_small btn_grey_white_innerfade",
            html: "<span>Retrieve Items</span>",
            onclick: async () => {
              const inventory = await script_default.GetInventory({ showProgress: true });
              if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
                script_default.ShowStartInterfacePrompt({
                  message: "Interface must be running to fetch stored items",
                  fade: false
                });
                return;
              }
              if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
                script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
                return;
              }
              if (!(inventory instanceof Inventory)) {
                return;
              }
              const casket = inventory.items.find((x) => x.iteminfo.id == this._assetid);
              const table = new Table(inventory.storedItems.filter((x) => x.casket_id == this._assetid), inventory, {
                mode: Table.MODE.RETRIEVE,
                casket,
                casketName: casket.attributes["custom name attr"]
              });
              table.Show();
            }
          }),
          CreateElement("a", {
            class: "btn_small btn_grey_white_innerfade",
            html: "<span>Deposit Items</span>",
            onclick: async () => {
              const inventory = await script_default.GetInventory({ showProgress: true });
              if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
                script_default.ShowStartInterfacePrompt({
                  message: "Interface must be running to fetch inventory items"
                });
                return;
              }
              if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
                script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
                return;
              }
              if (!(inventory instanceof Inventory)) {
                return;
              }
              const casket = inventory.items.find((x) => x.iteminfo.id == this._assetid);
              const table = new Table(inventory.items.filter((x) => x.moveable), inventory, {
                mode: Table.MODE.STORE,
                casket,
                casketName: casket.attributes["custom name attr"]
              });
              table.Show();
            }
          })
        );
      }
    }
  };

  // src/cs2/items/assets/market_asset.js
  var MarketAsset = class _MarketAsset extends Asset {
    _listingid;
    static #builtItemPageUI = false;
    constructor(asset, listing) {
      super();
      this._assetid = asset.id;
      this._listingid = listing?.listingid;
      for (const description of asset.descriptions) {
        if (description.name == "exterior_wear") {
          this._type = Asset.TYPE.WEARABLE;
          break;
        }
      }
      if (typeof this._type == "undefined") {
        this._type = Asset.TYPE.OTHER;
      }
      if (this._type == Asset.TYPE.WEARABLE) {
        for (const action of asset.market_actions) {
          if (action.link.includes("steam://rungame")) {
            this._inspectLink = action.link.replace("%assetid%", this._assetid);
            break;
          }
        }
      }
    }
    async BuildListingUI() {
      if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
        const build = () => {
          if (!this._inspectData) {
            return;
          }
          const listingDetailsElement = unsafeWindow.document.getElementById(`listing_${this._listingid}_details`);
          if (!listingDetailsElement) {
            return;
          }
          if (listingDetailsElement.getElementsBySelector(".cs2s_listing_info").length != 0) {
            return;
          }
          const stickerElements = listingDetailsElement.getElementsBySelector("#sticker_info img");
          const charmElements = listingDetailsElement.getElementsBySelector("#keychain_info img");
          if (this._inspectData.wear && this._inspectData.seed) {
            if (!_MarketAsset.#builtItemPageUI) {
              _MarketAsset.#builtItemPageUI = true;
              this.#BuiltItemPageUI();
            }
            listingDetailsElement.prepend(
              CreateElement("div", {
                class: "cs2s_listing_info",
                children: [
                  CreateElement("div", {
                    text: `Float: ${this._inspectData.wear.toFixed(14)}`,
                    children: [
                      " ",
                      this._GetPercentileElement({ showTooltip: true, rounded: false })
                    ]
                  }),
                  CreateElement("div", {
                    text: `Seed: ${this._inspectData.seed}`
                  })
                ]
              })
            );
          }
          if (this._inspectData.stickers) {
            for (let i = 0; i < this._inspectData.stickers.length; i++) {
              if (typeof stickerElements[i] == "undefined") {
                break;
              }
              stickerElements[i].wrap(
                CreateElement("span", {
                  class: "cs2s_asset_sticker_wear cs2s_asset_cosmetic_small",
                  wear: Math.round(this._inspectData.stickers[i] * 100)
                })
              );
            }
          }
          if (this._inspectData.charm) {
            if (typeof charmElements[0] != "undefined") {
              charmElements[0].wrap(
                CreateElement("span", {
                  class: "cs2s_asset_charm_template cs2s_asset_cosmetic_small",
                  template: this._inspectData.charm
                })
              );
            }
          }
        };
        let cached;
        try {
          cached = await this._Inspect({ cacheOnly: true });
        } catch (e) {
          script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
          return;
        }
        if (cached) {
          build();
        } else {
          Asset._inspectionWorker.Add(async () => {
            const listingDetailsElement = unsafeWindow.document.getElementById(`listing_${this._listingid}_details`);
            if (!listingDetailsElement) {
              return;
            }
            try {
              await this._Inspect();
            } catch (e) {
              script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
              return;
            }
            build();
          });
          Asset._inspectionWorker.Run();
        }
      }
    }
    #BuiltItemPageUI() {
      if (this._inspectData.wear && this._inspectData.seed) {
        const descriptionsElement = unsafeWindow.document.getElementById(`largeiteminfo_item_descriptors`);
        if (descriptionsElement) {
          descriptionsElement.prepend(this._GetWearRangeElement(true));
        }
      }
    }
  };

  // src/css/style.css
  var style_default = `:root {
	--cs2s-wear-fn-color: #35cdff;
	--cs2s-wear-mw-color: #0bb52f;
	--cs2s-wear-ft-color: #e8c805;
	--cs2s-wear-ww-color: #e86f24;
	--cs2s-wear-bs-color: #ea2828;
	--cs2s-stattrak-color: #cf6a32;
	--cs2s-quality-3-color: #8650ac;
	--cs2s-quality-12-color: #ffd700;
	--cs2s-rarity-7-color: #e4ae33;
	--cs2s-rarity-6-color: #eb4b4b;
	--cs2s-rarity-5-color: #d32ce6;
	--cs2s-rarity-4-color: #8847ff;
	--cs2s-rarity-3-color: #4b69ff;
	--cs2s-rarity-2-color: #5e98d9;
	--cs2s-rarity-1-color: #b0c3d9;
}

.cs2s_color_wear_fn { color: var(--cs2s-wear-fn-color) !important; }
.cs2s_color_wear_mw { color: var(--cs2s-wear-mw-color) !important; }
.cs2s_color_wear_ft { color: var(--cs2s-wear-ft-color) !important; }
.cs2s_color_wear_ww { color: var(--cs2s-wear-ww-color) !important; }
.cs2s_color_wear_bs { color: var(--cs2s-wear-bs-color) !important; }
.cs2s_color_rarity_7 { color: var(--cs2s-rarity-7-color) !important; }
.cs2s_color_rarity_6 { color: var(--cs2s-rarity-6-color) !important; }
.cs2s_color_rarity_5 { color: var(--cs2s-rarity-5-color) !important; }
.cs2s_color_rarity_4 { color: var(--cs2s-rarity-4-color) !important; }
.cs2s_color_rarity_3 { color: var(--cs2s-rarity-3-color) !important; }
.cs2s_color_rarity_2 { color: var(--cs2s-rarity-2-color) !important; }
.cs2s_color_rarity_1 { color: var(--cs2s-rarity-1-color) !important; }
.cs2s_color_quality_1 { color: var(--cs2s-stattrak-color) !important; }
.cs2s_color_quality_2 { color: var(--cs2s-quality-12-color) !important; }
.cs2s_color_quality_3  { color: var(--cs2s-quality-3-color) !important; }
.cs2s_color_quality_4  { color: var(--cs2s-quality-3-color) !important; }

.cs2s_asset_wear {
	position: absolute;
	bottom: 0px;
	right: 0px;
	left: 0px;
	padding-right: 4px;
	text-align: right;
	text-overflow: ellipsis;
	font-size: 8pt;
	max-width: 100%;
	color: #b7becd;

	&::after {
		content: "";
		position: absolute;
		top: 0;
		right: 2px;
		left: 2px;
		height: 4px;
		border-radius: 4px;
		opacity: 85%;
	}

	.cs2s_asset_wear_name {
		position: absolute;
		z-index: 1;
		bottom: 12px;
		right: 6px;
		font-size: 8pt;
		font-weight: 800;
		opacity: 95%;
		text-shadow: 0px 2px 4px #000000bf;

		&::before {
			content: '';
			position: absolute;
			top: 4px;
			left: -6px;
			width: 0;
			height: 0;
			border: 8px solid transparent;
			border-radius: 100%;
			transform: rotate(315deg);
		}
	}

	&.cs2s_asset_wear_fn {
		color: color-mix(in srgb, var(--cs2s-wear-fn-color), #cdcdcd 66%);
		text-shadow: -3px -1px 10px var(--cs2s-wear-fn-color);
		background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 85%) 2px);

		&::after {
			background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%), transparent);
		}

		.cs2s_asset_wear_name {
			color: var(--cs2s-wear-fn-color);

			&::before {
				border-top-color: color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%);
				border-right-color: color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 65%);
			}

			&::after {
				background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%), transparent);
			}
		}
	}

	&.cs2s_asset_wear_mw {
		color: color-mix(in srgb, var(--cs2s-wear-mw-color), #cdcdcd 66%);
		text-shadow: -3px -1px 10px var(--cs2s-wear-mw-color);
		background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 85%) 2px);

		&::after {
			background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%), transparent);
		}

		.cs2s_asset_wear_name {
			color: var(--cs2s-wear-mw-color);

			&::before {
				border-top-color: color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%);
				border-right-color: color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 65%);
			}

			&::after {
				background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%), transparent);
			}
		}
	}
	&.cs2s_asset_wear_ft {
		color: color-mix(in srgb, var(--cs2s-wear-ft-color), #cdcdcd 66%);
		text-shadow: -3px -1px 10px var(--cs2s-wear-ft-color);
		background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 85%) 2px);

		&::after {
			background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%), transparent);
		}

		.cs2s_asset_wear_name {
			color: var(--cs2s-wear-ft-color);

			&::before {
				border-top-color: color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%);
				border-right-color: color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 65%);
			}

			&::after {
				background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%), transparent);
			}
		}
	}
	&.cs2s_asset_wear_ww {
		color: color-mix(in srgb, var(--cs2s-wear-ww-color), #cdcdcd 66%);
		text-shadow: -3px -1px 10px var(--cs2s-wear-ww-color);
		background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 85%) 2px);

		&::after {
			background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%), transparent);
		}

		.cs2s_asset_wear_name {
			color: var(--cs2s-wear-ww-color);

			&::before {
				border-top-color: color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%);
				border-right-color: color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 65%);
			}

			&::after {
				background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%), transparent);
			}
		}
	}
	&.cs2s_asset_wear_bs {
		color: color-mix(in srgb, var(--cs2s-wear-bs-color), #cdcdcd 66%);
		text-shadow: -3px -1px 10px var(--cs2s-wear-bs-color);
		background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 85%) 2px);

		&::after {
			background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%), transparent);
		}

		.cs2s_asset_wear_name {
			color: var(--cs2s-wear-bs-color);

			&::before {
				border-top-color: color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%);
				border-right-color: color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 65%);
			}

			&::after {
				background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%), transparent);
			}
		}
	}
}
.cs2s_asset_seed {
	position: absolute;
	top: 0px;
	right: 0px;
	padding-right: 4px;
	font-size: 8pt;
	max-width: 100%;
}

.cs2s_asset_rarity {
	position: absolute;
	top: 0px;
	left: 0px;
	bottom: 11px;
	right: 6px;

	&::before {
		content: '';
		position: absolute;
		top: 0;
		width: 0;
		height: 0;
		border-style: solid;
		border-width: 15px 20px 0 0;
		border-color: transparent;
	}

	&::after {
		position: absolute;
		left: 1px;
		top: 0;
		padding: 0px 0px 1px 3px;
		font-size: 8pt;
		font-weight: 500;
		text-shadow: 0px 2px 4px #000000bf;
	}

	&.cs2s_asset_stattrak {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-stattrak-color), transparent 65%) !important;
		}

		&::after {
			color: var(--cs2s-stattrak-color) !important;
		}
	}

	&.cs2s_asset_quality_3 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-quality-3-color), transparent 65%) !important;
		}

		&::after {
			content: '\u2605' !important;
			color: var(--cs2s-quality-3-color) !important;
		}
	}

	&.cs2s_asset_quality_12 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-quality-12-color), transparent 65%) !important;
		}

		&::after {
			color: var(--cs2s-quality-12-color) !important;
		}
	}

	&.cs2s_asset_rarity_7 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-7-color), transparent 65%);
		}

		&::after {
			content: '7';
			color: var(--cs2s-rarity-7-color);
		}
	}

	&.cs2s_asset_rarity_6 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-6-color), transparent 65%);
		}

		&::after {
			content: '6';
			color: var(--cs2s-rarity-6-color);
		}
	}

	&.cs2s_asset_rarity_5 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-5-color), transparent 65%);
		}

		&::after {
			content: '5';
			color: var(--cs2s-rarity-5-color);
		}
	}

	&.cs2s_asset_rarity_4 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-4-color), transparent 65%);
		}

		&::after {
			content: '4';
			color: var(--cs2s-rarity-4-color);
		}
	}

	&.cs2s_asset_rarity_3 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-3-color), transparent 65%);
		}

		&::after {
			content: '3';
			color: var(--cs2s-rarity-3-color);
		}
	}

	&.cs2s_asset_rarity_2 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-2-color), transparent 65%);
		}

		&::after {
			content: '2';
			color: var(--cs2s-rarity-2-color);
		}
	}

	&.cs2s_asset_rarity_1 {
		&::before {
			border-top-color: color-mix(in srgb, var(--cs2s-rarity-1-color), transparent 65%);
		}

		&::after {
			content: '1';
			color: var(--cs2s-rarity-1-color);
		}
	}
}

.cs2s_asset_quantity {
	position: absolute;
	top: 0px;
	left: 0px;
	padding-left: 4px;
	font-size: 8pt;
	max-width: 100%;
}

.cs2s_asset_name {
	position: absolute;
	bottom: 0px;
	left: 0px;
	right: 0px;
	padding: 1px 4px 0px 4px;
	overflow: hidden;
	margin: 4px;
	border-radius: 2px;
	border-bottom: 2px solid #5f6a76;
	font-size: 9pt;
	max-width: 100%;
	color: #b7becd;
	text-shadow: 0px 2px 4px #000000bf;
	text-overflow: ellipsis;
	text-align: center;
	background: #505050bf;
	background-image: radial-gradient( #b7becd0d 1px, transparent 0);
	background-size: 4px 4px;
	background-position: -4px -3px;
}

.cs2s_asset_cosmetics {
	position: absolute;
	bottom: 14px;
	left: 0px;

	img {
		height: 19px;
		width: 25px !important;
		filter: drop-shadow(0px 0px 0px #1c1c23);
	}
	
	&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
		margin-left: -8px;
	}

	&:has(> :nth-child(6)) img:nth-child(n+2) {
		margin-left: -12px;
	}
}

.cs2s_asset_sticker_wear, .cs2s_asset_charm_template {
	position: relative;
	display: inline-block;
	padding-bottom: 16px;

	&::before {
		position: absolute;
		bottom: 0px;
		left: 0px;
		right: 0px;
	}

	&.cs2s_asset_cosmetic_small {
		padding-bottom: 0px;
		top: -6px;

		&::before {
			bottom: -12px;
			font-size: 11px;
			text-align: center;
		}
	}
}

.cs2s_asset_sticker_wear::before {
	content: attr(wear) '%';
}

.cs2s_asset_charm_template::before {
	content: attr(template);
}

.cs2s_asset_wear_range {
	margin: 0px 0px 8px 4px;

	& > div {
		width: 50px;
		height: 4px;
		display: inline-block;
		position: relative;
		background: linear-gradient(360deg, rgb(50 50 50 / 40%), transparent);

		&:not(:last-child) {
			border-right: 1px solid #1d1d1dbf;
		}

		&.cs2s_asset_wear_range_left, &.cs2s_asset_wear_range_right, &.cs2s_asset_wear_range_empty  {
			background-color: #91919180 !important;
		}

		&.cs2s_asset_wear_range_left::before, &.cs2s_asset_wear_range_right::before {
			content: "";
			width: var(--wear-percentage);
			height: 100%;
			display: block;
			position: absolute;
			background: linear-gradient(360deg, rgb(50 50 50 / 40%), transparent);
		}

		&.cs2s_asset_wear_range_left::before {
			left: 0px;
		}
		&.cs2s_asset_wear_range_right::before {
			right: 0px;
		}

		&.cs2s_asset_wear_range_fn {
			border-radius: 4px 0px 0px 4px;
			background-color: var(--cs2s-wear-fn-color);

			&::before {
				background-color: var(--cs2s-wear-fn-color);
			}

			& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
				background-color: var(--cs2s-wear-fn-color);
			}
		}

		&.cs2s_asset_wear_range_mw {
			background-color: var(--cs2s-wear-mw-color);

			&::before {
				background-color: var(--cs2s-wear-mw-color);
			}

			& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
				background-color: var(--cs2s-wear-mw-color);
			}
		}

		&.cs2s_asset_wear_range_ft {
			background-color: var(--cs2s-wear-ft-color);

			&::before {
				background-color: var(--cs2s-wear-ft-color);
			}

			& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
				background-color: var(--cs2s-wear-ft-color);
			}
		}

		&.cs2s_asset_wear_range_ww {
			background-color: var(--cs2s-wear-ww-color);

			&::before {
				background-color: var(--cs2s-wear-ww-color);
			}

			& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
				background-color: var(--cs2s-wear-ww-color);
			}
		}

		&.cs2s_asset_wear_range_bs {
			border-radius: 0px 4px 4px 0px;
			background-color: var(--cs2s-wear-bs-color);

			&::before {
				background-color: var(--cs2s-wear-bs-color);
			}

			& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
				background-color: var(--cs2s-wear-bs-color);
			}
		}
	}

	& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
		position: absolute;
		top: -2px;
		bottom: -2px;
		width: 2px;

		&::before {
			content: attr(wear_value);
			position: absolute;
			bottom: 6px;
			left: -2px;
			font-size: 8pt;
		}
	}

	& .cs2s_asset_wear_range_low {
		right: var(--wear-percentage);
		transform: translate(50%, 0%);
	}

	& .cs2s_asset_wear_range_high {
		left: var(--wear-percentage);
		transform: translate(-50%, 0%);
	}

	& .cs2s_asset_wear_range_marker {
		position: absolute;
		top: 3px;
		left: var(--wear-percentage);
		transform: translate(-50%, 0%);
		width: 0;
		height: 0;
		border-style: solid;
		border-width: 0px 5px 5px 5px;
		border-color: transparent;
		border-bottom-color: white;
	}
}

.cs2s_asset_rank_gold {
	background: linear-gradient( #ffe34b 50%, #ff8f00);
	background-clip: text;
	-webkit-text-fill-color: transparent;
	text-shadow: 1px 1px 10px #ffe34b40, 1px 1px 10px #ff8f0040;
	border-color: #ffe34b;
}

.cs2s_asset_rank_silver {
	background: linear-gradient( #ffffff 50%, #fdfdfd40);
	background-clip: text;
	-webkit-text-fill-color: transparent;
	text-shadow: 1px 1px 10px #ffffff40, 1px 1px 10px #fdfdfd40;
	border-color: #ffffff;
}

.cs2s_asset_rank_bronze {
	background: linear-gradient( #e7913d 50%, #bb2f0f);
	background-clip: text;
	-webkit-text-fill-color: transparent;
	text-shadow: 1px 1px 10px #e7913d40, 1px 1px 10px #bb2f0f40;
	border-color: #e7913d;
}

.cs2s_asset_rank_rust {
	background: linear-gradient( #ff5716 50%, #daddb2);
	background-clip: text;
	-webkit-text-fill-color: transparent;
	text-shadow: 1px 1px 10px #ff57161a, 1px 1px 10px #daddb21a, #9d242480 -1px -1px 0px;
	border-color: #ff5716;
}

.cs2s_listing_info {
	width: 250px;
	padding: 10px 8px 0px 0px;
	font-size: 14px;

	& + br + div {
		border-left: 1px solid #404040;
		padding-left: 16px !important;
	}
}

.cs2s_has_tooltip {
	border-bottom-width: 1px;
	border-bottom-style: dashed;
}

.cs2s_tooltip {
	position: absolute;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.2s;
	z-index: 9999;
	background: #c2c2c2;
	color: #3d3d3f;
	font-size: 11px;
	border-radius: 3px;
	padding: 5px;
	max-width: 300px;
	white-space: normal;
	box-shadow: 0 0 3px #000000;
}

.cs2s_popup_opened {
	overflow: hidden;
}

.cs2s_popup_background {
	position: fixed;
	top: 0px;
	right: 0px;
	bottom: 0px;
	left: 0px;
	background: #000000;
	opacity: 80%;
}

.cs2s_popup_container {
	position: fixed;
	top: 0px;
	right: 0px;
	bottom: 0px;
	left: 0px;
	display: flex;
	justify-content: center;
	align-items: center;
}

.cs2s_popup_body {
	position: fixed;
	background: radial-gradient(circle at top left, rgba(74, 81, 92, 0.4) 0%, rgba(75, 81, 92, 0) 60%), #25282e;
	
	&:not(.cs2s_popup_body_simple) {
		padding-top: 3px;
		
		&::after {
			content: "";
			position: absolute;
			top: 0px;
			left: 0px;
			right: 0px;
			height: 1px;
			background: linear-gradient(to right, #00ccff, #3366ff);
		}
		
		.cs2s_popup_title {
			padding: 24px;
			font-size: 22px;
			font-weight: 700;
			color: #ffffff;
		}
	}
	
	&.cs2s_popup_body_simple .cs2s_popup_title {
		min-width: 400px;
		padding: 16px;
		font-size: 20px;
		font-weight: 500;
		text-align: center;
		color: #fff;
		background: #1b1b2280;
	}

	&.cs2s_popup_body_popover {
		box-shadow: 0px 0px 16px 8px #00000060;
	}
	
	&:has(.cs2s_popup_footer) {
		border-radius: 0px 0px 10px 10px;
		margin-bottom: 64px;
	}
}

.cs2s_popup_close_button {
	float: right;
	height: 16px;
	width: 16px;
	margin-top: 9px;
	margin-right: 9px;			
	cursor: pointer;
	opacity: 70%;
	background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVBREZBRDlBNzdCNzExRTI5ODAzRUE3MDU0Mzk5MjM5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVBREZBRDlCNzdCNzExRTI5ODAzRUE3MDU0Mzk5MjM5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NUFERkFEOTg3N0I3MTFFMjk4MDNFQTcwNTQzOTkyMzkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NUFERkFEOTk3N0I3MTFFMjk4MDNFQTcwNTQzOTkyMzkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4iulRzAAABPElEQVR42mI8cuQIAyWABUqbAXEylH0fiDtwqI8FYhsoewEQH4cZcBaI64DYG8p/AVWADDyAeD4QMwPxJiA+BRJkgkr+BeJoIL4D5U8DYi0kzepAvAKq+TJU7V9kA0DgIxD7Q2lOIF4NpfmBeAuUfg3EPkD8BaaJCc2Z14A4EcoGuWAC1NkqQPwLqvkRsgYmLAG1HoiboOw0IA6EshNh/iZkAAjUA/FBJP5KIF6GTSEuAwygUQsDflAxogwQAuJ10AAExcpNKHsjEIsSMoAZGl2K0EALBeIIKFsOKSpxGtACxK5Qdi4QX4DiAqiYExB34TIgBIgrkAJtFpLcdKgYCBQBcRRMghGamUBxfhKIeaB+NkFOLFAAkjsDTZXfgdgK5DpYXvBGiqYpWDQzQMVAYZKDlDcuMFKanQECDAAqw0LA+GRiqAAAAABJRU5ErkJggg==);
	
	&:hover {
		opacity: 100%;
	}
}

.cs2s_table_title_casket {
	color: #919191;
	&::before {
		content: "";
		background: url(https://community.fastly.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxqAhWSVieFOX71szWCgwsdlZRsuz0L1M1iqrOIGUauNiyzdmKxKWsMrnXkjlQsIthhO5eh9dfdg/66x45);
		width: 66px;
		height: 45px;
		display: inline-block;
		vertical-align: middle;
		filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
	}
	&.cs2s_table_title_casket_multiple {
		position: relative;
		margin-left: 16px;
		&::before {
			margin-right: 12px;
		}
		&::after {
			content: "";
			background: url(https://community.fastly.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxqAhWSVieFOX71szWCgwsdlZRsuz0L1M1iqrOIGUauNiyzdmKxKWsMrnXkjlQsIthhO5eh9dfdg/45x31);
			width: 82px;
			height: 31px;
			display: inline-block;
			vertical-align: middle;
			filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
			position: absolute;
			left: -14px;
			top: -1px;
			z-index: -1;
			opacity: 85%;
		}
	}
}

.cs2s_table_container {
	outline: 0;
	overflow-y: scroll;
	border-radius: 0px 0px 10px 10px;
}

.cs2s_table {
	user-select: none;
	width: 100%;
	border-spacing: 0px;

	.cs2s_table_image_column {
		width: 93px;
	}

	.cs2s_table_name_column {
		width: 350px;
	}

	.cs2s_table_collection_column {
		width: 250px;
	}

	.cs2s_table_float_column {
		width: 275px;
	}

	.cs2s_table_seed_column {
		width: 150px;
	}

	.cs2s_table_crate_column {
		width: 230px;
		padding-right: 20px;
		white-space: nowrap;
	}

	td {
		border-bottom: 1px solid #1c1c23;

		&:nth-child(n+2) {
			padding-left: 8px;
		}
	}

	thead {
		tr {
			height: 30px;
		}

		th {
			position: sticky;
			top: 1px;
			background: #1c1c23;
			z-index: 2;
			text-align: left;

			&:nth-child(n+2) {
				padding-left: 8px;
				border-left: 1px solid #3d3d3d;
			}

			&:before {
				content: "";
				position: absolute;
				top: -1px;
				left: -1px;
				right: 0px;
				height: 1px;
				background: #1c1c23;
				border-left: 1px solid #3d3d3d;
			}
		}
	}

	tbody {
  		will-change: transform;
	}

	tbody tr {
		height: 69px;
		color: #bdbdbd;
		user-select: none;

		&.cs2s_table_row_selected {
			background: #a3cbe3;
			color: #3c3f44;

			td {
				border-color: #badbdb
			}
		}

		.cs2s_table_image_column {
			position: relative;
			padding-left: 4px;

			img {
				height: 62px;
				width: 93px;
				display: block;
			}

			.cs2s_table_image_column_cosmetics {
				position: absolute;
				bottom: -2px;
				left: 2px;
				white-space: nowrap;

				img {
					width: 25px;
					height: 19px;
					display: inline-block;
				}

				&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
					margin-left: -8px;
				}

				&:has(> :nth-child(6)) img:nth-child(n+2) {
					margin-left: -12px;
				}
			}
		}

		&:not(.cs2s_table_row_selected) .cs2s_table_image_column {
			& > img {
				filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
				clip-path: rect(0px 100px 66px 0px);
			}

			.cs2s_table_image_column_cosmetics img {
				filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(4px 0px 4px #1c1c23);
			}
		}

		.cs2s_table_name_column {
			a {
				position: relative;
				top: 1px;
				left: 2px;
				opacity: 75%;
				color: #ffffff;

				svg {
					height: 12px;
					width: 12px;
				}
			}
		}

		&.cs2s_table_row_selected .cs2s_table_name_column a {
			color: #000000;
		}
		
		.cs2s_table_collection_column {
			padding-left: 30px !important;

			&.cs2s_table_collection_column_has_rarity {
				position: relative;

				&::after{
					position: absolute;
					font-size: 8pt;
					font-weight: 800;
					left: 5px;
					top: 50%;
					width: 21px;
					text-align: center;
					transform: translate(0%, -50%);
				}

				&.cs2s_table_collection_column_rarity_7::after {
					content: "7";
					color: var(--cs2s-rarity-7-color);
				}

				&.cs2s_table_collection_column_rarity_6::after {
					content: "6";
					color: var(--cs2s-rarity-6-color);
				}

				&.cs2s_table_collection_column_rarity_5::after {
					content: "5";
					color: var(--cs2s-rarity-5-color);
				}

				&.cs2s_table_collection_column_rarity_4::after {
					content: "4";
					color: var(--cs2s-rarity-4-color);
				}

				&.cs2s_table_collection_column_rarity_3::after {
					content: "3";
					color: var(--cs2s-rarity-3-color);
				}

				&.cs2s_table_collection_column_rarity_2::after {
					content: "2";
					color: var(--cs2s-rarity-2-color);
				}

				&.cs2s_table_collection_column_rarity_1::after {
					content: "1";
					color: var(--cs2s-rarity-1-color);
				}

				&.cs2s_table_collection_column_stattrak::after {
					color: var(--cs2s-stattrak-color);
				}

				&.cs2s_table_collection_column_quality_3::after {
					content: "\u2605";
					color: var(--cs2s-quality-3-color);
				}

				&.cs2s_table_collection_column_quality_12::after {
					color: var(--cs2s-quality-12-color);
				}
			}
		}

		&.cs2s_table_row_selected .cs2s_table_collection_column_has_rarity::after {
			color: #3c3f44 !important;
		}

		&:not(.cs2s_table_row_selected) .cs2s_table_collection_column_has_rarity::after {
			text-shadow: 2px 4px 6px #1c1c23;
		}

		.cs2s_table_float_column {
			padding-left: 36px !important;
			font-variant-numeric: tabular-nums;
			
			&.cs2s_table_float_column_has_float {
				position: relative;

				&::after{
					position: absolute;
					font-size: 8pt;
					font-weight: 800;
					top: 50%;
					left: 8px;
					width: 22px;
					text-align: center;
					transform: translate(0%, -50%);
				}

				&.cs2s_table_float_column_float_fn::after {
					content: "FN";
					color: var(--cs2s-wear-fn-color);
				}

				&.cs2s_table_float_column_float_mw::after {
					content: "MW";
					color: var(--cs2s-wear-mw-color);
				}

				&.cs2s_table_float_column_float_ft::after {
					content: "FT";
					color: var(--cs2s-wear-ft-color);
				}

				&.cs2s_table_float_column_float_ww::after {
					content: "WW";
					color: var(--cs2s-wear-ww-color);
				}

				&.cs2s_table_float_column_float_bs::after {
					content: "BS";
					color: var(--cs2s-wear-bs-color);
				}
			}
		}

		&.cs2s_table_row_selected .cs2s_table_float_column_has_float::after {
			color: #3c3f44 !important;
		}

		&:not(.cs2s_table_row_selected) .cs2s_table_float_column_has_float::after {
			text-shadow: 2px 4px 6px #1c1c23;
		}

		.cs2s_table_empty {
			height: 150px;
			font-size: 20px;
			font-weight: 500;
			text-align: center;
			border-bottom-width: 0px;
		}
	}

	.cs2s_table_column {
		cursor: pointer;
		user-select: none;

		&:hover {
			color: #ffffff;
		}

		&:has(.cs2s_table_column_sort_asc), &:has(.cs2s_table_column_sort_desc) {
			color: #3a8dde;

			&:hover {
				color: #4aa6ff;
			}
		}
	}

	.cs2s_table_column_sort {
		position: relative;
		display: inline-block;
		height: 15px;
		width: 15px;
		vertical-align: text-bottom;
		background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23595959' width='800px' height='800px' viewBox='0 0 36.678 36.678' %3E%3Cg%3E%3Cpath d='M29.696,20.076c0.088,0.16,0.08,0.354-0.021,0.51L19.395,36.449c-0.091,0.139-0.241,0.224-0.407,0.229 c-0.004,0-0.008,0-0.015,0c-0.157,0-0.31-0.076-0.403-0.205L6.998,20.609c-0.11-0.15-0.127-0.354-0.041-0.521 c0.085-0.168,0.257-0.272,0.444-0.272h21.855C29.443,19.814,29.609,19.914,29.696,20.076z M7.401,16.865h21.855 c0.008,0,0.017,0,0.021,0c0.275,0,0.5-0.225,0.5-0.5c0-0.156-0.07-0.295-0.184-0.388L18.086,0.205 C17.989,0.072,17.821,0.002,17.668,0c-0.165,0.005-0.315,0.09-0.406,0.229L6.982,16.094c-0.101,0.152-0.105,0.35-0.021,0.512 C7.05,16.765,7.218,16.865,7.401,16.865z'/%3E%3C/g%3E%3C/svg%3E");
		background-size: 15px 15px;
		margin: 0px 4px;
		pointer-events: none;

		&.cs2s_table_column_sort_asc::before, &.cs2s_table_column_sort_desc::before {
			content: "";
			position: absolute;
			inset: 0;
			display: block;
			height: 7px;
			width: 15px;
			background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%233a8dde' width='800px' height='800px' viewBox='0 0 36.678 36.678' %3E%3Cg%3E%3Cpath d='M29.696,20.076c0.088,0.16,0.08,0.354-0.021,0.51L19.395,36.449c-0.091,0.139-0.241,0.224-0.407,0.229 c-0.004,0-0.008,0-0.015,0c-0.157,0-0.31-0.076-0.403-0.205L6.998,20.609c-0.11-0.15-0.127-0.354-0.041-0.521 c0.085-0.168,0.257-0.272,0.444-0.272h21.855C29.443,19.814,29.609,19.914,29.696,20.076z M7.401,16.865h21.855 c0.008,0,0.017,0,0.021,0c0.275,0,0.5-0.225,0.5-0.5c0-0.156-0.07-0.295-0.184-0.388L18.086,0.205 C17.989,0.072,17.821,0.002,17.668,0c-0.165,0.005-0.315,0.09-0.406,0.229L6.982,16.094c-0.101,0.152-0.105,0.35-0.021,0.512 C7.05,16.765,7.218,16.865,7.401,16.865z'/%3E%3C/g%3E%3C/svg%3E");
			background-size: 15px 15px;
		}

		&.cs2s_table_column_sort_desc::before {
			top: 8px;
			background-position-y: 7px;
		}
	}

	.cs2s_table_column_search {
		position: relative;
		margin-left: 2px;
		font-weight: normal;
		font-size: 13px;
		max-width: 275px;

		&::before {
			content: "";
			display: inline-block;
			position: absolute;
			top: 4px;
			left: 4px;
			height: 13px;
			width: 13px;
			background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%2396969696' width='800px' height='800px' viewBox='0 0 24 24'%3E%3Cpath d='M23.46,20.38l-5.73-5.73a9.52,9.52,0,1,0-2.83,2.83l5.73,5.73a1,1,0,0,0,1.41,0l1.41-1.41A1,1,0,0,0,23.46,20.38ZM9.75,15a5.5,5.5,0,1,1,5.5-5.5A5.51,5.51,0,0,1,9.75,15Z'/%3E%3C/svg%3E");
			background-size: 13px;
			pointer-events: none;
		}

		&::after {
			padding-left: 42px;
		}

		input {
			background: transparent;
			border: none;
			outline: none;
			color: #969696;
			border-bottom: 1px dashed #96969696;
			padding-left: 22px;
			font-family: inherit;
			width: 100px;
			min-width: 100px;

			&::-webkit-search-cancel-button {
				-webkit-appearance: none;
				position: relative;
				top: 1px;
				height: 8px;
				width: 8px;
				background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M1 1L11 11M11 1L1 11' stroke='%233a8dde' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
				cursor: pointer;
			}
		}

		&:has(input:not(:placeholder-shown)) {
			&::before {
				background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%233a8dde' width='800px' height='800px' viewBox='0 0 24 24'%3E%3Cpath d='M23.46,20.38l-5.73-5.73a9.52,9.52,0,1,0-2.83,2.83l5.73,5.73a1,1,0,0,0,1.41,0l1.41-1.41A1,1,0,0,0,23.46,20.38ZM9.75,15a5.5,5.5,0,1,1,5.5-5.5A5.51,5.51,0,0,1,9.75,15Z'/%3E%3C/svg%3E");
			}

			input {
				color: #3a8dde;
				border-color: #3a8dde;
			}
		}
	}
}

.cs2s_table_footer {
	height: 64px;
	position: absolute;
	top: 100%;
	left: 0px;
	right: 0px;
	color: #bdbdbd;
	display: flex;
	justify-content: space-between;
	align-items: center;

	&::before {
		content: "";
		position: absolute;
		left: 0px;
		top: 0px;
		right: 0px;
		bottom: 0px;
		background: radial-gradient(ellipse at 68% 40%, #1c1c2380 -24%, #05080b80 66%);
		backdrop-filter: blur(10px);
		z-index: -1;
		mask: linear-gradient(180deg, rgba(0, 0, 0, 0.9) 40%, transparent);
	}

	a, button {
		border-radius: 20px;

		& > span {
			border-radius: 20px;
		}
	}
}

.cs2s_table_footer_element_left > * {
	margin-right: 16px;
}

.cs2s_table_footer_element_right > * {
	margin-left: 16px;
}

.cs2s_table_footer_selection_count {
	font-weight: bold;
}

.cs2s_table_footer_action_link {
	display: inline-block;
	padding: 0px 18px 0px 12px;
	margin-right: 8px;
	border: 0px;
	line-height: 28px;
	background: #d7d7d7;
	color: #272727;
	font-size: 14px;
	font-weight: bold;
	text-shadow: none;
	opacity: 95%;
	cursor: pointer;
	user-select: none;

	&.cs2s_table_footer_action_link_active {
		background: #3a8dde;
		color: #fff;

		&:hover {
			background: #43a2ff;
		}
	}

	&:hover {
		background: #fff;
	}

	span {
		display: inline-block;

		svg {
			height: 21px;
			width: 21px;
			display: inline-block;
			vertical-align: top;
			margin-right: 2px;
			margin-top: 3px;
		}
	}
}

.cs2s_table_footer_input {
	font-weight: bold;

	input {
		outline: none;
		padding: 0px;
		border-bottom: 1px dashed !important;
		color: inherit !important;

		&::-webkit-outer-spin-button, &::-webkit-inner-spin-button {
			-webkit-appearance: none;
			margin: 0;
		}
	}
}

.cs2s_resizable_input {
	display: inline-grid;

	input {
		font-size: inherit;
		font-weight: inherit;
		font-family: inherit;
		grid-area: 1 / 2;
		appearance: textfield;
	}

	&:after {
		content: attr(data-value);
		visibility: hidden;
		grid-area: 1 / 2;
		white-space: nowrap;
	}
}

.cs2s_error_table_container {
	max-height: 80vh;
	width: 1250px;
	user-select: auto;

	table, tbody, tr, th, td {
		user-select: auto !important;
	}

	th:first-child, td:first-child {
		width: 250px;
		padding-left: 16px;
		white-space: nowrap;
	}

	th:nth-child(2), td:nth-child(2) {
		width: 150px;
	}
}

.cs2s_action_body {
	padding: 16px;
	display: flex;
	flex-direction: column;
	gap: 16px;

	& > div {
		margin: 0px auto;
	}
}

.cs2s_action_item_window {
	height: 120px;
	width: 120px;
	margin: 0 auto;
	display: flex;
	justify-content: center;
	align-items: center;
	position: relative;
	border-radius: 100%;
	overflow: hidden;
	background: #1b1b2280;
}

.cs2s_action_item_window_image {
	display: inline-flex;
	position: absolute;
	left: 0px;
	transform: translate(13px, 0px);

	& > img {
		filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
	}

	.cs2s_table_image_column_cosmetics {
		position: absolute;
		bottom: -5px;
		left: -2px;
		white-space: nowrap;

		img {
			width: 25px;
			height: 19px;
			display: inline-block;
		}

		&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
			margin-left: -8px;
		}

		&:has(> :nth-child(6)) img:nth-child(n+2) {
			margin-left: -12px;
		}
	}

	
}

.cs2s_action_message {
	color: #969696;
	font-size: 16px;
}

.cs2s_action_message_tall {
	padding-top: 8px;
	padding-bottom:12px;
}

.cs2s_action_multi_message {
	max-width: 500px;
	padding-left: 16px;
	padding-right: 16px;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.cs2s_action_buttons {
	div:not(:first-child) {
		margin-left: 16px;
	}
}

.cs2s_action_progress_bar {
	background: #1b1b2280;
	padding: 6px;
	border-radius: 12px;
	width: 300px;
	height: 25px;

	&::before {
		content: "";
		display: block;
		height: 100%;
		width: var(--percentage);
		min-width: 1px;
		border-radius: 6px;
		background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
		background-position: 25%;
		background-size: 330% 100%;
		transition: width 0.3s ease-in-out;
	}
}

.cs2s_action_spinner {
	width: 50px;
	height: 50px;
	border: 5px solid #a6a6ad80;
	border-top-color: transparent;
	border-radius: 50%;
	animation: spin 1s linear infinite;
}

@keyframes spin {
	to { transform: rotate(360deg); }
}

.cs2s_settings_form {
	overflow: scroll;
	padding: 0px 24px 24px 24px;
	width: 900px;
	max-height: 85vh;
}

.cs2s_settings_filter {
	input::placeholder {
		opacity: .75;
	}

	input[type=text]:not(:placeholder-shown), input[type=number]:not(:placeholder-shown), select:has(option:checked:not([value=""]):not([value="custom"])) {
		outline: 1px solid #3a8dde;
	}
}

.cs2s_settings_form_group_title {
	padding: 0px 0px 6px 10px;
	border-bottom: 2px solid rgba(228, 228, 228, .1);
	font-size: 16px;
	line-height: 28px;
	text-transform: uppercase;
	letter-spacing: 0;
	color: #e4e4e4;
}

.cs2s_settings_form_group {
	flex: 1;
	padding: 24px 20px;
	align-items: center;
}

.cs2s_settings_form_group_row {
	display: flex;
	justify-content: space-between;
	flex-direction: row;
	gap: 32px;

	.cs2s_settings_form_group_item {
		flex: 1;
	}
}

.cs2s_settings_form_group_half_row {
	display: flex;
	justify-content: flex-start;
	flex-direction: row;
	gap: 32px;
}

.cs2s_settings_form_group_collection {
	flex: 1;
	position: relative;
	margin: 8px 0px 10px;

	&::before {
		content: "";
		position: absolute;
		z-index: -1;
		top: -4px;
		bottom: 12px;
		left: -12px;
		right: -12px;
		background-color: #2e3137;
	}
}

.cs2s_settings_form_submit_group {
	display: flex;
	flex-direction: row-reverse;

	button {
		margin: 2px 0 2px 12px;
	}
}

.cs2s_settings_form_group_item {
	display: flex;
	flex-direction: column;
	margin-bottom: 22px;

	label {
		display: block;
		margin-bottom: 4px;
		font-size: 13px;
		font-weight: 300;
		line-height: 19px;
		color: #acb2b8;
		text-transform: uppercase;
		letter-spacing: initial;
		user-select: none;
	}

	&.cs2s_settings_form_group_item_checkbox {
		flex-direction: row;

		label {
			flex: 1;
			margin: 0;
			padding: 4px 0px;
			cursor: pointer;
			white-space: nowrap;
		}
	}

	input[type=text], input[type=number] {
		display: block;
		padding: 10px;
		font-size: 14px;
		line-height: 22px;
		color: #909090;
		background-color: rgba(0, 0, 0, .25);
		border: none;
		box-shadow: inset 1px 1px 0px #000a;
		outline: 0;

		&:disabled {
			appearance: textfield;
		}
	}

	input[type=checkbox] {
		float: left;
		width: 22px;
		height: 22px;
		margin-right: 8px;
		padding: 0;
		border-radius: 2px;
		appearance: none;
		background-color: #0004;
		box-shadow: inset 1px .5px 3px rgba(1, 1, 1, .4);
		cursor: pointer;

		&:not(:disabled):hover {
			background-color: #090909;
		}

		&:checked {
			background-image: url('data:image/svg+xml,<svg version="1.1" id="base" xmlns="http://www.w3.org/2000/svg" class="SVGIcon_Button SVGIcon_DialogCheck" x="0px" y="0px" width="18px" height="18px" viewBox="0 0 256 256"><defs><linearGradient id="svgid_0" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="%2300ccff"></stop><stop offset="100%" stop-color="%232d73ff"></stop></linearGradient><filter id="svgid_1" x="0" y="0" width="200%" height="200%"><feOffset result="offOut" in="SourceAlpha" dx="20" dy="20"></feOffset><feGaussianBlur result="blurOut" in="offOut" stdDeviation="10"></feGaussianBlur><feBlend in="SourceGraphic" in2="blurOut" mode="normal"></feBlend></filter></defs><path fill="none" stroke="url(%23svgid_0)" stroke-width="24" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="10" d="M206.5,45.25L95,210.75l-45.5-63" stroke-dasharray="365.19 365.19" stroke-dashoffset="0.00"></path><path fill="none" opacity=".2" filter="url(%23svgid_1)" stroke="url(%23svgid_0)" stroke-width="24" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="10" d="M206.5,45.25L95,210.75l-45.5-63" stroke-dasharray="365.19 365.19" stroke-dashoffset="0.00"></path></svg>');
			background-repeat: no-repeat;
			background-position: 50% 50%;
		}
	}

	select {
		display: block;
		padding: 10px;
		font-size: 14px;
		height: 42px;
		color: #909090;
		background-color: rgba(0, 0, 0, .25);
		border: none;
		border-right: 4px solid transparent;
		box-shadow: inset 1px 1px 0px #000a;
		outline: 0;

		option, optgroup {
			color: #909090;
			background-color: #262931;
		}
	}
}

.cs2s_settings_form_message {
	font-style: italic;
	color: #909090;
}

.cs2s_settings_form_separator {
	align-content: center;
	font-weight: 800;
	opacity: 0.5;
	user-select: none;
}

.cs2s_settings_form_disabled {
	opacity: 0.5;

	input, select, label {
		cursor: default !important;
		outline: 0 !important;
	}
}

.popup_menu_item {
	display: block;
}

.cs2s_navigation_icon {
	display: inline-block;
	vertical-align: text-top;
	height: 16px;
	width: 47px;

	svg {
		height: 11px;
		width: 50px;
	}
}

.cs2s_navigation_status_error_glow {
	animation: cs2s_glow 2s infinite ease-in-out;
}

@keyframes cs2s_glow {
	0%, 100% {
		box-shadow: 0 0 5px rgba(102, 192, 244, 0.4);
	}
	20% {
		box-shadow: 0 0 10px rgba(102, 192, 244, 0.6);
	}
	40% {
		box-shadow: 0 0 20px rgba(102, 192, 244, 0.9);
	}
	60% {
		box-shadow: 0 0 5px rgba(102, 192, 244, 0.3);
	}
	80% {
		box-shadow: 0 0 15px rgba(102, 192, 244, 0.8);
	}
}

.cs2s_navigation_status_error_pulse {
	animation: cs2s_pulse 2s infinite ease-in-out;
}

@keyframes cs2s_pulse {
	0% {
		transform: scale(1);
		opacity: 0.75;
		box-shadow: 0 0 0 0 rgba(102, 192, 244, 0.75);
	}
	50% {
		transform: scale(1.1);
		opacity: 1;
		box-shadow: 0 0 10px 10px rgba(102, 192, 244, 0.3);
		color: #66c0f4
	}
	100% {
		transform: scale(1);
		opacity: 0.75;
		box-shadow: 0 0 0 0 rgba(102, 192, 244, 0);
	}
}

.cs2s_grey_long_button {
	display: inline-block;
	width: 200px;
	padding: 0;
	line-height: 32px;
	text-align: center;
	font-size: 14px;
	color: #dfe3e6;
	background-color: #3d4450;
	border: 0;
	border-radius: 2px;
	cursor: pointer;

	&:hover {
		color: #ffffff;
		background-color: #464d58;
	}
}

.cs2s_blue_long_button {
	display: inline-block;
	width: 200px;
	padding: 0;
	line-height: 32px;
	text-align: center;
	font-size: 14px;
	color: #dfe3e6;
	background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
	background-position: 25%;
	background-size: 330% 100%;
	border: 0;
	border-radius: 2px;
	cursor: pointer;

	&:hover {
		background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
		background-position: 0%;
		background-size: 330% 100%;
	}
}

.cs2s_green_button {
	padding: 1px;
	display: inline-block;
	cursor: pointer;
	color: #D2E885;
	background: linear-gradient(to bottom, #07d03f 5%, #04692f 95%);
	border-bottom-width: 0px;

	span {
		display: block;
		padding: 0 24px;
		font-size: 15px;
		line-height: 30px;
		background: linear-gradient(to bottom, #059917 5%, #04693b 95%);
	}

	&:not(.cs2s_button_disabled) {
		&:hover {
			color: #ffffff;
			background: linear-gradient(to bottom, #08d92b 5%, #06a030 95%);

			span {
				background: linear-gradient(to bottom, #07bf2b 5%, #06a05e 95%);
			}
		}
	}

	&.cs2s_button_disabled {
		opacity: 45%;
		cursor: default;
	}
}
`;

  // src/main.js
  {
    const HAS_GM = typeof GM !== "undefined";
    const NEW_GM = ((scope, GM2) => {
      if (GM_info.scriptHandler !== "Tampermonkey" || compareVersions(GM_info.version, "5.3.2") < 0) return;
      const GM_xmlhttpRequestOrig = GM_xmlhttpRequest;
      const GM_xmlHttpRequestOrig = GM2.xmlHttpRequest;
      function compareVersions(v1, v2) {
        const parts1 = v1.split(".").map(Number);
        const parts2 = v2.split(".").map(Number);
        const length = Math.max(parts1.length, parts2.length);
        for (let i = 0; i < length; i++) {
          const num1 = parts1[i] || 0;
          const num2 = parts2[i] || 0;
          if (num1 > num2) return 1;
          if (num1 < num2) return -1;
        }
        return 0;
      }
      function GM_xmlhttpRequestWrapper(odetails) {
        if (odetails.redirect !== void 0) {
          return GM_xmlhttpRequestOrig(odetails);
        }
        if (odetails.onprogress || odetails.fetch === false) {
          console.warn("Fetch mode does not support onprogress in the background.");
        }
        const {
          onload,
          onloadend,
          onerror,
          onabort,
          ontimeout,
          ...details
        } = odetails;
        const handleRedirects = (initialDetails) => {
          const request = GM_xmlhttpRequestOrig({
            ...initialDetails,
            redirect: "manual",
            onload: function(response) {
              if (response.status >= 300 && response.status < 400) {
                const m = response.responseHeaders.match(/Location:\s*(\S+)/i);
                const redirectUrl = m && m[1];
                if (redirectUrl) {
                  const absoluteUrl = new URL(redirectUrl, initialDetails.url).href;
                  handleRedirects({ ...initialDetails, url: absoluteUrl });
                  return;
                }
              }
              if (onload) onload.call(this, response);
              if (onloadend) onloadend.call(this, response);
            },
            onerror: function(response) {
              if (onerror) onerror.call(this, response);
              if (onloadend) onloadend.call(this, response);
            },
            onabort: function(response) {
              if (onabort) onabort.call(this, response);
              if (onloadend) onloadend.call(this, response);
            },
            ontimeout: function(response) {
              if (ontimeout) ontimeout.call(this, response);
              if (onloadend) onloadend.call(this, response);
            }
          });
          return request;
        };
        return handleRedirects(details);
      }
      function GM_xmlHttpRequestWrapper(odetails) {
        let abort;
        const p = new Promise((resolve, reject) => {
          const { onload, ontimeout, onerror, ...send } = odetails;
          send.onerror = function(r) {
            if (onerror) {
              resolve(r);
              onerror.call(this, r);
            } else {
              reject(r);
            }
          };
          send.ontimeout = function(r) {
            if (ontimeout) {
              resolve(r);
              ontimeout.call(this, r);
            } else {
              reject(r);
            }
          };
          send.onload = function(r) {
            resolve(r);
            if (onload) onload.call(this, r);
          };
          const a = GM_xmlhttpRequestWrapper(send).abort;
          if (abort === true) {
            a();
          } else {
            abort = a;
          }
        });
        p.abort = () => {
          if (typeof abort === "function") {
            abort();
          } else {
            abort = true;
          }
        };
        return p;
      }
      GM_xmlhttpRequest = GM_xmlhttpRequestWrapper;
      scope.GM_xmlhttpRequestOrig = GM_xmlhttpRequestOrig;
      const gopd = Object.getOwnPropertyDescriptor(GM2, "xmlHttpRequest");
      if (gopd && gopd.configurable === false) {
        return {
          __proto__: GM2,
          xmlHttpRequest: GM_xmlHttpRequestWrapper,
          xmlHttpRequestOrig: GM_xmlHttpRequestOrig
        };
      } else {
        GM2.xmlHttpRequest = GM_xmlHttpRequestWrapper;
        GM2.xmlHttpRequestOrig = GM_xmlHttpRequestOrig;
      }
    })(window, HAS_GM ? GM : {});
    if (HAS_GM && NEW_GM) GM = NEW_GM;
  }
  (async function() {
    GM_addStyle(style_default);
    await script_default.VerifyConnection();
    const PAGE_INVENTORY = 0;
    const PAGE_MARKET_LISTING = 1;
    let currentPage = null;
    if (window.location.href.includes("/market/listings")) {
      currentPage = PAGE_MARKET_LISTING;
    } else if (window.location.href.includes("/inventory")) {
      currentPage = PAGE_INVENTORY;
    }
    if (currentPage == PAGE_INVENTORY) {
      const IS_OWN_INVENTORY = unsafeWindow.g_ActiveUser.strSteamId == unsafeWindow.g_steamID;
      if (IS_OWN_INVENTORY) {
        const initInventory = () => {
          if (initInventory.initialized) {
            return;
          }
          initInventory.initialized = true;
          script_default.GetInventory();
        };
        const allCratesButton = CreateElement("a", {
          class: "btn_darkblue_white_innerfade btn_medium",
          style: {
            marginRight: "12px"
          },
          html: "<span>Retrieve All Stored Items</span>",
          onclick: async () => {
            const inventory = await script_default.GetInventory({ showProgress: true });
            if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
              script_default.ShowStartInterfacePrompt({
                message: "Interface must be running to fetch stored items",
                fade: false
              });
              return;
            }
            if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
              script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
              return;
            }
            if (!(inventory instanceof Inventory)) {
              return;
            }
            const table = new Table(inventory.storedItems.slice(), inventory, {
              mode: Table.MODE.RETRIEVE,
              casketName: "All Storage Units",
              multiCasket: true
            });
            table.Show();
          }
        });
        const originalShowItemInventory = unsafeWindow.ShowItemInventory;
        unsafeWindow.ShowItemInventory = function(appid) {
          const result = originalShowItemInventory.call(this, ...arguments);
          if (appid == CS2_APPID) {
            initInventory();
            !allCratesButton.isConnected && unsafeWindow.document.getElementsByClassName("inventory_rightnav")[0].prepend(allCratesButton);
          } else {
            allCratesButton.isConnected && allCratesButton.remove();
          }
          return result;
        };
        if (unsafeWindow.g_ActiveInventory.appid == CS2_APPID) {
          initInventory();
          unsafeWindow.document.getElementsByClassName("inventory_rightnav")[0].prepend(allCratesButton);
        }
      }
      {
        const handleInventoryAssets = () => {
          if (!handleInventoryAssets.handledAssetIDs) {
            handleInventoryAssets.handledAssetIDs = /* @__PURE__ */ new Set();
          }
          if (!unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory?.m_rgAssets) {
            return;
          }
          for (const element of unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory.m_rgItemElements) {
            const asset = element?.[0]?.rgItem;
            if (!asset) {
              continue;
            }
            const assetid = asset.assetid;
            if (handleInventoryAssets.handledAssetIDs.has(assetid)) {
              continue;
            }
            handleInventoryAssets.handledAssetIDs.add(assetid);
            const inventoryAsset = new InventoryAsset(asset);
            inventoryAsset.BuildInventoryUI();
          }
        };
        const originalAddInventoryData = unsafeWindow.CInventory.prototype.AddInventoryData;
        unsafeWindow.CInventory.prototype.AddInventoryData = function(data) {
          const result = originalAddInventoryData.call(this, ...arguments);
          if (data?.assets?.[0]?.appid == CS2_APPID) {
            handleInventoryAssets();
          }
          return result;
        };
        handleInventoryAssets();
      }
      {
        const handleSelectedAsset = (asset) => {
          const inventoryAsset = new InventoryAsset(asset);
          inventoryAsset.BuildSelectedUI();
        };
        const originalSelectItem = unsafeWindow.CInventory.prototype.SelectItem;
        unsafeWindow.CInventory.prototype.SelectItem = function(a, b, asset) {
          const result = originalSelectItem.call(this, ...arguments);
          if (asset.appid == CS2_APPID) {
            handleSelectedAsset(asset);
          }
          return result;
        };
        if (unsafeWindow.g_ActiveInventory.selectedItem?.appid == CS2_APPID) {
          handleSelectedAsset(unsafeWindow.g_ActiveInventory.selectedItem);
        }
      }
    } else if (currentPage == PAGE_MARKET_LISTING) {
      const IS_CS2_ITEM = !!unsafeWindow.g_rgAppContextData?.[CS2_APPID];
      const HAS_INDIVIDUAL_LISTINGS = Object.values(unsafeWindow.g_rgAssets?.[CS2_APPID]?.[2])[0]?.commodity == 0;
      if (!IS_CS2_ITEM || !HAS_INDIVIDUAL_LISTINGS) {
        return;
      }
      {
        const handleMarketAssets = () => {
          if (!unsafeWindow.g_rgAssets?.[CS2_APPID]?.[2] || !unsafeWindow.g_rgListingInfo) {
            return;
          }
          for (const listing of Object.values(unsafeWindow.g_rgListingInfo)) {
            const asset = unsafeWindow.g_rgAssets[CS2_APPID][2][listing.asset?.id];
            if (!asset) {
              continue;
            }
            const marketAsset = new MarketAsset(asset, listing);
            marketAsset.BuildListingUI();
          }
        };
        const originalOnResponseRenderResults = unsafeWindow.CAjaxPagingControls.prototype.OnResponseRenderResults;
        unsafeWindow.CAjaxPagingControls.prototype.OnResponseRenderResults = function() {
          const result = originalOnResponseRenderResults.call(this, ...arguments);
          handleMarketAssets();
          return result;
        };
        handleMarketAssets();
      }
    }
  })();
})();