Smart Panic

Navbar panic button — deposit all cash into your vault target stock. Works with Smart Stock Vault or standalone.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Smart Panic
// @namespace    Noobler.torn.panicNavbar
// @version      2.1.2
// @description  Navbar panic button — deposit all cash into your vault target stock. Works with Smart Stock Vault or standalone.
// @author       Noobler
// @match        https://www.torn.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @connect      api.torn.com
// @license      MIT
// ==/UserScript==


(() => {
  // src/shared/theme.js
  var tokens = {
    accent: "#caa14a",
    accentMuted: "rgba(202, 161, 74, 0.35)",
    accentSubtle: "rgba(202, 161, 74, 0.12)",
    accentText: "#f0e3c0",
    panelBg: "linear-gradient(180deg, #23252b, #1b1d22)",
    panelHeaderBg: "linear-gradient(180deg, #2c2f37, #23252b)",
    panelBorder: "#34373f",
    surface: "#15161a",
    text: "#d7d9de",
    textMuted: "#8a8d96",
    textDim: "#71747d",
    success: "#6fcf86",
    successBg: "#16341f",
    successBorder: "#2c6b3c",
    warning: "#ffd966",
    warningBg: "#332b13",
    warningBorder: "#6b5a1f",
    danger: "#ff6b6b",
    dangerBg: "#341818",
    dangerBorder: "#6b2c2c",
    info: "#8dbdf0",
    infoBg: "#15263d",
    infoBorder: "#2c4f7b",
    hover: "#d8b25c",
    font: "'Trebuchet MS', Verdana, sans-serif",
    radius: "8px",
    shadow: "0 2px 10px rgba(0, 0, 0, 0.35)",
    statDex: "#8a7ff0",
    statDef: "#e07a4f",
    statStr: "#3fae84",
    statSpd: "#4a97e6"
  };
  var STYLE_ID = "hf-torn-theme";
  function injectStyles(scopeClass = "hf-torn") {
    if (document.getElementById(STYLE_ID)) {
      return;
    }
    const css = `
    .${scopeClass} {
      --hf-accent: ${tokens.accent};
      --hf-accent-muted: ${tokens.accentMuted};
      --hf-accent-subtle: ${tokens.accentSubtle};
      --hf-accent-text: ${tokens.accentText};
      --hf-panel-bg: ${tokens.panelBg};
      --hf-panel-header-bg: ${tokens.panelHeaderBg};
      --hf-panel-border: ${tokens.panelBorder};
      --hf-surface: ${tokens.surface};
      --hf-text: ${tokens.text};
      --hf-text-muted: ${tokens.textMuted};
      --hf-text-dim: ${tokens.textDim};
      --hf-success: ${tokens.success};
      --hf-success-bg: ${tokens.successBg};
      --hf-success-border: ${tokens.successBorder};
      --hf-warning: ${tokens.warning};
      --hf-warning-bg: ${tokens.warningBg};
      --hf-warning-border: ${tokens.warningBorder};
      --hf-danger: ${tokens.danger};
      --hf-danger-bg: ${tokens.dangerBg};
      --hf-danger-border: ${tokens.dangerBorder};
      --hf-info: ${tokens.info};
      --hf-info-bg: ${tokens.infoBg};
      --hf-info-border: ${tokens.infoBorder};
      --hf-hover: ${tokens.hover};
      --hf-radius: ${tokens.radius};
      --hf-shadow: ${tokens.shadow};
      --hf-font: ${tokens.font};
      --hf-stat-dex: ${tokens.statDex};
      --hf-stat-def: ${tokens.statDef};
      --hf-stat-str: ${tokens.statStr};
      --hf-stat-spd: ${tokens.statSpd};
      color: var(--hf-text);
      font-family: var(--hf-font);
      font-size: 12px;
      line-height: 1.4;
      box-sizing: border-box;
    }

    .${scopeClass} *, .${scopeClass} *::before, .${scopeClass} *::after {
      box-sizing: border-box;
    }

    .${scopeClass} .hf-btn {
      appearance: none;
      border: 1px solid var(--hf-panel-border);
      border-radius: 5px;
      background: var(--hf-surface);
      color: var(--hf-accent-text);
      cursor: pointer;
      padding: 6px 10px;
      font: inherit;
      transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
    }

    .${scopeClass} .hf-btn:hover {
      background: var(--hf-accent-subtle);
      border-color: var(--hf-accent);
      color: #fff;
    }

    .${scopeClass} .hf-btn.is-active,
    .${scopeClass} .hf-btn--primary {
      background: var(--hf-accent);
      border-color: var(--hf-accent);
      color: #1b1d22;
      font-weight: 700;
    }

    .${scopeClass} .hf-btn.is-active:hover,
    .${scopeClass} .hf-btn--primary:hover {
      background: var(--hf-hover);
      border-color: var(--hf-hover);
    }

    .${scopeClass} .hf-muted {
      color: var(--hf-text-muted);
    }

    .${scopeClass} .hf-dim {
      color: var(--hf-text-dim);
    }

    .${scopeClass} .hf-badge {
      display: inline-block;
      padding: 2px 8px;
      border-radius: 4px;
      background: var(--hf-accent);
      color: #1b1d22;
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }

    .${scopeClass} .hf-input,
    .${scopeClass} .hf-select {
      width: 100%;
      box-sizing: border-box;
      padding: 6px 8px;
      background: var(--hf-surface);
      border: 1px solid var(--hf-panel-border);
      color: var(--hf-accent-text);
      border-radius: 5px;
      font: inherit;
      font-size: 12px;
    }

    .${scopeClass} .hf-label {
      display: block;
      font-size: 11px;
      color: var(--hf-text-muted);
      margin: 12px 0 4px;
    }

    .${scopeClass} .hf-table {
      width: 100%;
      border-collapse: collapse;
    }

    .${scopeClass} .hf-table th,
    .${scopeClass} .hf-table td {
      padding: 4px 6px;
      text-align: left;
      border-bottom: 1px solid var(--hf-panel-border);
    }

    .${scopeClass} .hf-table th {
      font-weight: bold;
      color: var(--hf-accent-text);
    }

    .${scopeClass}.hf-panel {
      margin: 0 0 12px;
      border-radius: var(--hf-radius);
      background: var(--hf-panel-bg);
      border: 1px solid var(--hf-panel-border);
      box-shadow: var(--hf-shadow);
      overflow: hidden;
    }

    .${scopeClass}.hf-panel--page {
      width: 100%;
    }

    .${scopeClass}.hf-panel--fixed {
      position: fixed;
      z-index: 9999;
    }

    .${scopeClass} .hf-panel-header {
      background: var(--hf-panel-header-bg);
      border-bottom: 1px solid var(--hf-panel-border);
      border-radius: var(--hf-radius) var(--hf-radius) 0 0;
    }

    .${scopeClass} .hf-panel-tabs {
      border-bottom: 1px solid var(--hf-panel-border);
    }

    .${scopeClass} .hf-panel-body {
      padding: 12px 13px;
    }

    .${scopeClass}.hf-panel--page .hf-panel-body {
      max-height: min(70vh, 640px);
      overflow-y: auto;
    }

    .${scopeClass}.hf-panel--page.hf-panel--grow .hf-panel-body {
      max-height: none;
      overflow: visible;
    }

    .${scopeClass}.hf-overlay,
    .${scopeClass} .hf-overlay {
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.6);
      z-index: 99999;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .${scopeClass}.hf-modal,
    .${scopeClass} .hf-modal {
      background: #1f2127;
      border: 1px solid var(--hf-panel-border);
      border-radius: var(--hf-radius);
      width: min(440px, 92vw);
      max-height: 84vh;
      overflow-y: auto;
      padding: 18px;
      color: var(--hf-text);
    }

    .${scopeClass}.hf-modal h2,
    .${scopeClass} .hf-modal h2 {
      margin: 0 0 14px;
      font-size: 15px;
      color: var(--hf-accent-text);
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .${scopeClass} .hf-mini {
      font-size: 10px;
      color: var(--hf-text-dim);
      margin-top: 3px;
      line-height: 1.4;
    }
  `;
    const style = document.createElement("style");
    style.id = STYLE_ID;
    style.textContent = css;
    document.head.appendChild(style);
  }
  var theme = {
    tokens,
    injectStyles
  };

  // src/shared/storage.js
  var PREFIX = "hf.torn";
  function namespaced(key) {
    return `${PREFIX}.${key}`;
  }
  function getLocal(key, fallback = null) {
    try {
      const raw = localStorage.getItem(namespaced(key));
      if (raw === null) {
        return fallback;
      }
      return JSON.parse(raw);
    } catch {
      return fallback;
    }
  }
  function setLocal(key, value) {
    localStorage.setItem(namespaced(key), JSON.stringify(value));
  }
  function removeLocal(key) {
    localStorage.removeItem(namespaced(key));
  }
  var DB_NAME = "heartflower-torn";
  var DB_VERSION = 1;
  var dbPromise = null;
  function openDb() {
    if (dbPromise) {
      return dbPromise;
    }
    dbPromise = new Promise((resolve, reject) => {
      const request = indexedDB.open(DB_NAME, DB_VERSION);
      request.onupgradeneeded = () => {
        const db = request.result;
        if (!db.objectStoreNames.contains("races")) {
          const store = db.createObjectStore("races", { keyPath: "id" });
          store.createIndex("timestamp", "timestamp", { unique: false });
          store.createIndex("track", "track", { unique: false });
          store.createIndex("carKey", "carKey", { unique: false });
        }
      };
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error ?? new Error("IndexedDB open failed"));
    });
    return dbPromise;
  }
  async function withStore(storeName, mode, run) {
    const db = await openDb();
    return new Promise((resolve, reject) => {
      const tx = db.transaction(storeName, mode);
      const store = tx.objectStore(storeName);
      const request = run(store);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
    });
  }
  async function putRecord(storeName, record) {
    await withStore(storeName, "readwrite", (store) => store.put(record));
  }
  async function deleteRecord(storeName, key) {
    await withStore(storeName, "readwrite", (store) => store.delete(key));
  }
  async function getRecord(storeName, key) {
    return withStore(storeName, "readonly", (store) => store.get(key));
  }
  async function getAllRecords(storeName, query, limit) {
    const db = await openDb();
    return new Promise((resolve, reject) => {
      const tx = db.transaction(storeName, "readonly");
      const store = tx.objectStore(storeName);
      const request = store.getAll(query, limit);
      request.onsuccess = () => resolve(
        /** @type {Record<string, unknown>[]} */
        request.result ?? []
      );
      request.onerror = () => reject(request.error ?? new Error("IndexedDB getAll failed"));
    });
  }
  async function getByIndex(storeName, indexName, key) {
    return withStore(storeName, "readonly", (store) => store.index(indexName).getAll(key));
  }
  var storage = {
    PREFIX,
    getLocal,
    setLocal,
    removeLocal,
    putRecord,
    deleteRecord,
    getRecord,
    getAllRecords,
    getByIndex
  };

  // src/shared/dom.js
  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
  async function waitFor(selector, options = {}) {
    const { timeout = 1e4, interval = 100, root = document } = options;
    const start = Date.now();
    while (Date.now() - start < timeout) {
      const el = root.querySelector(selector);
      if (el) {
        return el;
      }
      await sleep(interval);
    }
    throw new Error(`waitFor timeout: ${selector}`);
  }
  async function waitForOptional(selector, options = {}) {
    try {
      return await waitFor(selector, options);
    } catch {
      return null;
    }
  }
  function observeMutations(root, callback, options = {}) {
    const { debounce = 50 } = options;
    let timer = null;
    const observer = new MutationObserver(() => {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(callback, debounce);
    });
    observer.observe(root, { childList: true, subtree: true });
    callback();
    return () => {
      if (timer) {
        clearTimeout(timer);
      }
      observer.disconnect();
    };
  }
  function onAnchorClick(callback) {
    const handler = (event) => {
      const target = (
        /** @type {Element} */
        event.target
      );
      if (target.tagName === "A" || target.closest("a")) {
        setTimeout(callback, 150);
      }
    };
    document.body.addEventListener("click", handler);
    return () => document.body.removeEventListener("click", handler);
  }
  function normalizeText(text) {
    return text.replace(/\s+/g, " ").trim();
  }
  var dom = {
    sleep,
    waitFor,
    waitForOptional,
    observeMutations,
    onAnchorClick,
    normalizeText
  };

  // src/shared/mount.js
  var MOUNT_PRESETS = {
    racing: {
      waitFor: ["#racingMainContainer"],
      target: "#racingMainContainer",
      position: "before"
    },
    gym: {
      waitFor: ["#gymroot"],
      target: "#gymroot",
      position: "prepend"
    },
    gymBar: {
      waitFor: ["#gymroot"],
      target: "#gymroot",
      position: "before"
    },
    stocksBar: {
      waitFor: ["#stockmarketroot"],
      target: "#stockmarketroot",
      position: "before"
    },
    disposalBar: {
      waitFor: ['[class*="disposal-root"]'],
      target: '[class*="disposal-root"]',
      position: "before"
    },
    contentTitle: {
      waitFor: [".content-title", ".body > .content-title", "div.content-title"],
      target: ".content-title",
      position: "after"
    }
  };
  function resolveMountConfig(mount2) {
    if (!mount2) {
      return MOUNT_PRESETS.contentTitle;
    }
    if (typeof mount2 === "string") {
      if (mount2 === "page") {
        return MOUNT_PRESETS.contentTitle;
      }
      return MOUNT_PRESETS[mount2] ?? MOUNT_PRESETS.contentTitle;
    }
    return mount2;
  }
  function findMountTarget(config) {
    const pageReady = config.waitFor.some((selector) => document.querySelector(selector));
    if (!pageReady) {
      return null;
    }
    return document.querySelector(config.target);
  }
  function insertAt(target, element, position) {
    switch (position) {
      case "before":
        target.insertAdjacentElement("beforebegin", element);
        break;
      case "after":
        target.insertAdjacentElement("afterend", element);
        break;
      case "prepend":
        target.prepend(element);
        break;
      case "append":
        target.append(element);
        break;
    }
  }
  function isMountedAt(element, target, position) {
    if (!element.isConnected) {
      return false;
    }
    switch (position) {
      case "before":
        return element.nextElementSibling === target;
      case "after":
        return element.previousElementSibling === target;
      case "prepend":
        return target.firstElementChild === element;
      case "append":
        return target.lastElementChild === element;
      default:
        return false;
    }
  }
  function mountElement(config, element) {
    const target = findMountTarget(config);
    if (!target) {
      return false;
    }
    if (isMountedAt(element, target, config.position)) {
      return true;
    }
    insertAt(target, element, config.position);
    return true;
  }
  function watchMount(config, getElement) {
    let stopped = false;
    const start = Date.now();
    const timeoutMs = 15e3;
    const tryMount = () => {
      if (stopped) {
        return;
      }
      const element = getElement();
      mountElement(config, element);
    };
    const poll = window.setInterval(() => {
      tryMount();
      if (findMountTarget(config) || Date.now() - start > timeoutMs) {
        window.clearInterval(poll);
      }
    }, 250);
    const observer = new MutationObserver((mutations) => {
      const onlyOwnChanges = mutations.every((mutation) => {
        const node = mutation.target;
        return node instanceof HTMLElement && node.closest(".hf-torn");
      });
      if (!onlyOwnChanges) {
        tryMount();
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });
    tryMount();
    return () => {
      stopped = true;
      window.clearInterval(poll);
      observer.disconnect();
    };
  }
  var mount = {
    MOUNT_PRESETS,
    resolveMountConfig,
    findMountTarget,
    insertAt,
    isMountedAt,
    mountElement,
    watchMount
  };

  // src/shared/api.js
  var API_BASE = "https://api.torn.com/v2";
  var SETTINGS_KEY = "hf.torn.settings";
  function loadSettings() {
    try {
      const raw = GM_getValue(SETTINGS_KEY, "{}");
      const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
      return {
        apiKey: String(parsed?.apiKey ?? "").trim()
      };
    } catch {
      return { apiKey: "" };
    }
  }
  function saveSettings(patch) {
    const current = loadSettings();
    GM_setValue(SETTINGS_KEY, JSON.stringify({ ...current, ...patch }));
  }
  function parseTornError(json) {
    if (!json || typeof json !== "object" || !("error" in json)) {
      return null;
    }
    const err = (
      /** @type {{ error?: unknown }} */
      json.error
    );
    if (typeof err === "string") {
      return new Error(err);
    }
    if (err && typeof err === "object") {
      const detail = (
        /** @type {{ error?: string, message?: string, code?: number }} */
        err
      );
      return new Error(detail.error || detail.message || `Torn API error (${detail.code ?? "unknown"})`);
    }
    return new Error("Torn API error");
  }
  function tornGet(path, params, apiKey) {
    const url = new URL(`${API_BASE}/${path.replace(/^\//, "")}`);
    url.searchParams.set("key", apiKey);
    for (const [key, value] of Object.entries(params ?? {})) {
      if (value !== void 0 && value !== "") {
        url.searchParams.set(key, String(value));
      }
    }
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        url: url.toString(),
        timeout: 2e4,
        onload: (response) => {
          try {
            const json = JSON.parse(response.responseText || "{}");
            const apiError = parseTornError(json);
            if (apiError) {
              reject(apiError);
              return;
            }
            resolve(json);
          } catch (error) {
            reject(error instanceof Error ? error : new Error("Invalid API response"));
          }
        },
        onerror: () => reject(new Error("Network error")),
        ontimeout: () => reject(new Error("API request timed out"))
      });
    });
  }
  var api = {
    loadSettings,
    saveSettings,
    parseTornError,
    tornGet,
    SETTINGS_KEY
  };

  // src/shared/ui.js
  function panelCollapsedKey(panelId) {
    return `panel.${panelId}.collapsed`;
  }
  function readPanelCollapsed(panelId, legacyKeys = []) {
    const stored = getLocal(panelCollapsedKey(panelId), void 0);
    if (stored === true || stored === "true") {
      return true;
    }
    if (stored === false || stored === "false") {
      return false;
    }
    for (const key of legacyKeys) {
      const raw = localStorage.getItem(key);
      if (raw === "true") {
        setLocal(panelCollapsedKey(panelId), true);
        return true;
      }
      if (raw === "false") {
        setLocal(panelCollapsedKey(panelId), false);
        return false;
      }
    }
    return false;
  }
  var PANELS = /* @__PURE__ */ new Map();
  function createPanel(options) {
    const existing = PANELS.get(options.id);
    if (existing?.element.isConnected) {
      return existing;
    }
    if (existing) {
      PANELS.delete(options.id);
    }
    injectStyles();
    const mountOption = options.mount ?? "racing";
    const isFixed = mountOption === "fixed";
    const mountConfig = isFixed ? null : resolveMountConfig(mountOption);
    const pageBody = options.pageBody ?? "cap";
    const growPageBody = !isFixed && pageBody === "grow";
    const root = document.createElement("section");
    root.id = options.id;
    root.className = isFixed ? "hf-torn hf-panel hf-panel--fixed" : `hf-torn hf-panel hf-panel--page${growPageBody ? " hf-panel--grow" : ""}`;
    applyPanelLayout(root, isFixed, options.position ?? "bottom-right");
    const header = document.createElement("div");
    header.className = "hf-panel-header";
    header.style.cssText = `
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 13px;
    cursor: pointer;
    user-select: none;
  `;
    const titleWrap = document.createElement("div");
    titleWrap.style.display = "flex";
    titleWrap.style.alignItems = "center";
    titleWrap.style.gap = "10px";
    titleWrap.style.flex = "1";
    titleWrap.style.minWidth = "0";
    if (options.badge) {
      const badge = document.createElement("span");
      badge.className = "hf-badge";
      badge.textContent = options.badge;
      titleWrap.appendChild(badge);
    } else if (options.title) {
      const title = document.createElement("div");
      title.textContent = options.title;
      title.style.fontWeight = "700";
      title.style.fontSize = "13px";
      title.style.color = "var(--hf-accent-text)";
      titleWrap.appendChild(title);
    }
    const right = document.createElement("div");
    right.className = "hf-panel-right";
    right.style.cssText = `
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    flex-shrink: 0;
  `;
    const subtitle = document.createElement("div");
    subtitle.className = "hf-muted hf-panel-subtitle";
    subtitle.style.cssText = `
    font-size: 11px;
    max-width: min(280px, 40vw);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: none;
  `;
    const gear = document.createElement("button");
    gear.type = "button";
    gear.className = "hf-panel-gear";
    gear.title = "Settings";
    gear.innerHTML = "&#9881;";
    gear.style.cssText = `
    font-size: 15px;
    color: var(--hf-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
    flex-shrink: 0;
    position: relative;
    z-index: 2;
  `;
    const openSettings2 = (event) => {
      event.preventDefault();
      event.stopPropagation();
      options.onSettings?.();
    };
    gear.addEventListener("mousedown", openSettings2);
    gear.addEventListener("click", openSettings2);
    const toggle = document.createElement("span");
    toggle.className = "hf-panel-chev";
    toggle.textContent = "\u25BC";
    toggle.style.cssText = "font-size:12px;color:var(--hf-text-muted);transition:transform .2s;flex-shrink:0;";
    right.appendChild(subtitle);
    if (options.onSettings) {
      right.appendChild(gear);
    }
    right.appendChild(toggle);
    header.appendChild(titleWrap);
    header.appendChild(right);
    const tabBar = document.createElement("div");
    tabBar.className = "hf-panel-tabs";
    tabBar.style.cssText = `
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 6px 8px;
  `;
    const body = document.createElement("div");
    body.className = "hf-panel-body";
    if (growPageBody) {
      body.style.maxHeight = "none";
      body.style.overflow = "visible";
    }
    root.appendChild(header);
    if (options.tabs.length > 1) {
      root.appendChild(tabBar);
    }
    root.appendChild(body);
    let collapsed = readPanelCollapsed(options.id, options.collapsedLegacyKeys);
    let activeTabId = options.tabs[0]?.id ?? "";
    const tabButtons = /* @__PURE__ */ new Map();
    const setCollapsed = (value) => {
      collapsed = value;
      const hideBody = collapsed;
      if (options.tabs.length > 1) {
        tabBar.style.display = collapsed ? "none" : "flex";
      }
      body.style.display = hideBody ? "none" : "block";
      toggle.style.transform = collapsed ? "rotate(-90deg)" : "";
      root.classList.toggle("is-collapsed", collapsed);
      setLocal(panelCollapsedKey(options.id), value);
    };
    const renderActiveTab = async () => {
      const tab = options.tabs.find((item) => item.id === activeTabId);
      body.replaceChildren();
      if (!tab) {
        body.textContent = "No tab selected.";
        return;
      }
      const content = await tab.render();
      body.appendChild(content);
    };
    const setTab = (id) => {
      activeTabId = id;
      tabButtons.forEach((btn, tabId) => {
        btn.classList.toggle("is-active", tabId === id);
      });
      renderActiveTab();
    };
    if (options.tabs.length > 1) {
      for (const tab of options.tabs) {
        const btn = document.createElement("button");
        btn.type = "button";
        btn.className = "hf-btn";
        btn.textContent = tab.label;
        btn.addEventListener("click", (event) => {
          event.stopPropagation();
          setTab(tab.id);
        });
        tabButtons.set(tab.id, btn);
        tabBar.appendChild(btn);
      }
    }
    header.addEventListener("click", (event) => {
      if (
        /** @type {Element} */
        event.target.closest(".hf-panel-gear")
      ) {
        return;
      }
      if (
        /** @type {Element} */
        event.target.closest("button")
      ) {
        return;
      }
      setCollapsed(!collapsed);
    });
    gear.addEventListener("mouseenter", () => {
      gear.style.color = "#fff";
    });
    gear.addEventListener("mouseleave", () => {
      gear.style.color = "var(--hf-text-muted)";
    });
    setTab(activeTabId);
    setCollapsed(collapsed);
    let stopWatching = null;
    const ensureMounted = () => {
      if (isFixed) {
        if (root.parentElement !== document.body) {
          document.body.appendChild(root);
        }
        return;
      }
      if (mountConfig) {
        mountElement(mountConfig, root);
      }
    };
    if (isFixed) {
      ensureMounted();
    } else if (mountConfig) {
      stopWatching = watchMount(mountConfig, () => root);
    }
    const panel = {
      element: root,
      setTab,
      refresh: () => {
        if (options.getSubtitle) {
          subtitle.textContent = options.getSubtitle() ?? "";
        }
        renderActiveTab();
      },
      setSubtitle: (text) => {
        subtitle.textContent = text;
      },
      ensureMounted,
      destroy: () => {
        stopWatching?.();
        root.remove();
        PANELS.delete(options.id);
      }
    };
    if (options.getSubtitle) {
      subtitle.textContent = options.getSubtitle() ?? "";
    }
    PANELS.set(options.id, panel);
    return panel;
  }
  function applyPanelLayout(el, isFixed, position) {
    if (!isFixed) {
      el.style.cssText = `
      position: static;
      width: 100%;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    `;
      return;
    }
    el.style.cssText = `
    position: fixed;
    z-index: 9999;
    width: min(420px, calc(100vw - 24px));
    max-height: min(70vh, 560px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  `;
    applyFixedPosition(el, position);
  }
  function applyFixedPosition(el, position) {
    el.style.top = "";
    el.style.right = "";
    el.style.bottom = "";
    el.style.left = "";
    switch (position) {
      case "top-right":
        el.style.top = "12px";
        el.style.right = "12px";
        break;
      case "bottom-left":
        el.style.bottom = "12px";
        el.style.left = "12px";
        break;
      case "bottom-right":
      default:
        el.style.bottom = "12px";
        el.style.right = "12px";
        break;
    }
  }
  function emptyState(message) {
    const div = document.createElement("div");
    div.className = "hf-muted";
    div.textContent = message;
    return div;
  }
  var ui = {
    createPanel,
    emptyState
  };

  // src/shared/percent.js
  function parsePercent(raw, fallback = 0) {
    if (raw === null || raw === void 0 || raw === "") {
      return fallback;
    }
    if (typeof raw === "number") {
      return Number.isFinite(raw) ? raw : fallback;
    }
    const cleaned = String(raw).trim().replace("%", "").replace(",", ".");
    const value = parseFloat(cleaned);
    return Number.isFinite(value) ? value : fallback;
  }
  function weightToPercent(weight) {
    return Math.round(weight * 1e3) / 10;
  }
  function weightSharePercent(weight, weights) {
    const sum = Object.values(weights).reduce((total, w) => total + (w > 0 ? w : 0), 0);
    if (sum <= 0 || weight <= 0) {
      return 0;
    }
    return weight / sum * 100;
  }
  function percentToWeight(raw, fallback = 0) {
    const pct = parsePercent(raw, fallback * 100);
    return pct / 100;
  }
  function weightsToShares(weights) {
    const sum = Object.values(weights).reduce((total, w) => total + (w > 0 ? w : 0), 0);
    if (sum <= 0) {
      return {};
    }
    const out = {};
    for (const [stat, w] of Object.entries(weights)) {
      out[stat] = w > 0 ? w / sum * 100 : 0;
    }
    return out;
  }
  function normalizeWeightsToShares(weights) {
    const sum = Object.values(weights).reduce((total, w) => total + (w > 0 ? w : 0), 0);
    if (sum <= 0) {
      return weights;
    }
    const out = {};
    for (const [stat, w] of Object.entries(weights)) {
      out[stat] = w > 0 ? w / sum * 100 : 0;
    }
    return out;
  }
  function parseShareInputs(inputsByStat) {
    const raw = {};
    let sum = 0;
    for (const [stat, value] of Object.entries(inputsByStat)) {
      const pct = Math.max(0, parsePercent(value, 0));
      raw[stat] = pct;
      sum += pct;
    }
    if (sum <= 0) {
      return raw;
    }
    const out = {};
    for (const [stat, pct] of Object.entries(raw)) {
      out[stat] = pct > 0 ? pct / sum * 100 : 0;
    }
    return out;
  }
  function bonusesToMultiplier(bonuses) {
    const f = parsePercent(bonuses?.faction, 0);
    const e = parsePercent(bonuses?.education, 0);
    const p = parsePercent(bonuses?.property, 0);
    return (1 + f / 100) * (1 + e / 100) * (1 + p / 100);
  }
  function multiplierToTotalPercent(multiplier) {
    if (!Number.isFinite(multiplier) || multiplier <= 1) {
      return 0;
    }
    return Math.round((multiplier - 1) * 1e3) / 10;
  }
  function formatPercent(pct, digits = 1) {
    const rounded = Math.round(pct * Math.pow(10, digits)) / Math.pow(10, digits);
    const text = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(digits);
    return `${text}%`;
  }
  function formatWeightSummary(weights, shortLabels) {
    const parts = Object.entries(weights).filter(([, w]) => w > 0).sort((a, b) => b[1] - a[1]).map(([stat, w]) => `${shortLabels[stat] ?? stat} ${formatPercent(weightSharePercent(w, weights), 0)}`);
    return parts.join(" \xB7 ");
  }
  var percent = {
    parsePercent,
    weightToPercent,
    weightSharePercent,
    percentToWeight,
    weightsToShares,
    normalizeWeightsToShares,
    parseShareInputs,
    bonusesToMultiplier,
    multiplierToTotalPercent,
    formatPercent,
    formatWeightSummary
  };

  // src/shared/index.js
  var HF = {
    version: "0.4.0",
    theme,
    storage,
    dom,
    mount,
    api,
    ui,
    percent
  };

  // src/panic/config.js
  var LS_PANIC = "alfa_panic_navbar_config";
  var SS_PENDING = "alfa_panic_nav_pending";
  var STOCKS_PATH = "/page.php?sid=stocks";
  var DEFAULT_CONFIG = {
    preferSmartStockVault: true,
    targetStock: "",
    vaultStocks: [],
    lockedStocks: []
  };
  var DEFAULT_VAULT_FALLBACK = { stocks: [], lockedStocks: [] };
  function loadJson(key, fallback) {
    try {
      const raw = localStorage.getItem(key);
      if (!raw) return { ...fallback };
      const o = JSON.parse(raw);
      return { ...fallback, ...o };
    } catch {
      return { ...fallback };
    }
  }
  function savePanicConfig(cfg) {
    try {
      localStorage.setItem(LS_PANIC, JSON.stringify(cfg));
    } catch (e) {
      console.error("[Smart Panic] save config failed", e);
    }
  }
  function getPanicConfig() {
    return loadJson(LS_PANIC, DEFAULT_CONFIG);
  }
  function getSsvVault() {
    return loadJson("alfa_vault_config", DEFAULT_VAULT_FALLBACK);
  }
  function getSsvGamble() {
    return loadJson("alfa_gamble_config", { targetStock: "" });
  }
  function resolveTargetSymbol(gambleTarget, vaultStocks) {
    const list = (Array.isArray(vaultStocks) ? vaultStocks : []).map((s) => String(s).toUpperCase());
    const gt = String(gambleTarget || "").toUpperCase();
    if (gt && list.includes(gt)) return gt;
    return String(list[0] || "").toUpperCase();
  }
  function getEffectiveVaultAndTarget() {
    const panic = getPanicConfig();
    if (panic.preferSmartStockVault) {
      const v = getSsvVault();
      const g = getSsvGamble();
      const stocks2 = (Array.isArray(v.stocks) ? v.stocks : []).map((s) => String(s).toUpperCase());
      const lockedStocks2 = (Array.isArray(v.lockedStocks) ? v.lockedStocks : []).map((s) => String(s).toUpperCase());
      const target2 = resolveTargetSymbol(g.targetStock || "", stocks2);
      return { vaultStocks: stocks2, lockedStocks: lockedStocks2, targetStock: target2, source: "ssv" };
    }
    const stocks = (Array.isArray(panic.vaultStocks) ? panic.vaultStocks : []).map((s) => String(s).toUpperCase());
    const lockedStocks = (Array.isArray(panic.lockedStocks) ? panic.lockedStocks : []).map((s) => String(s).toUpperCase());
    const target = resolveTargetSymbol(panic.targetStock || "", stocks);
    return { vaultStocks: stocks, lockedStocks, targetStock: target, source: "local" };
  }
  function isStocksPage() {
    return /[?&]sid=stocks\b/.test(location.search || "");
  }
  function stocksUrl() {
    return `https://www.torn.com${STOCKS_PATH}`;
  }
  function parseSymbolsInput(str) {
    if (!str || typeof str !== "string") return [];
    return str.split(/[\s,]+/).map((s) => s.trim().toUpperCase()).filter(Boolean);
  }

  // src/panic/money.js
  function parseTornNumber(val) {
    if (typeof val !== "string") return 0;
    val = val.trim().toLowerCase();
    if (!val) return 0;
    if (val.endsWith("k")) return parseFloat(val.replace("k", "")) * 1e3;
    if (val.endsWith("m")) return parseFloat(val.replace("m", "")) * 1e6;
    if (val.endsWith("b")) return parseFloat(val.replace("b", "")) * 1e9;
    return parseFloat(val.replace(/,/g, "")) || 0;
  }
  function getMoneyFromNavbar() {
    const el = document.getElementById("user-money");
    if (!el) return null;
    const dm = el.getAttribute("data-money");
    if (dm !== null && dm !== "") {
      const n = parseFloat(dm);
      if (!Number.isNaN(n)) return n;
    }
    const t = el.textContent || "";
    if (t) {
      const n = parseTornNumber(t.replace(/^\$/, ""));
      if (!Number.isNaN(n) && n >= 0) return n;
    }
    return null;
  }
  async function getMoneyApiFallback() {
    const key = localStorage.getItem("alfa_vault_apikey");
    if (!key) return null;
    try {
      const res = await fetch(`https://api.torn.com/v2/user/money?key=${encodeURIComponent(key)}&ts=${Date.now()}`);
      const data = await res.json();
      if (data.error) return null;
      if (data.money && typeof data.money.wallet === "number") return data.money.wallet;
    } catch (e) {
      console.warn("[Smart Panic] API money fallback failed", e);
    }
    return null;
  }
  async function getCashForPanic() {
    const dom2 = getMoneyFromNavbar();
    if (dom2 !== null && dom2 !== void 0 && !Number.isNaN(dom2)) return dom2;
    const api2 = await getMoneyApiFallback();
    return api2 !== null && api2 !== void 0 ? api2 : 0;
  }
  function formatMoneyWhole(amount) {
    return `$${Math.round(Number(amount) || 0).toLocaleString("en-US", {
      maximumFractionDigits: 0,
      minimumFractionDigits: 0
    })}`;
  }
  function tryUpdateGambleCashFromNavbar() {
    const el = document.getElementById("gamble-cash-value");
    if (!el || !document.getElementById("user-money")) return false;
    const domCash = getMoneyFromNavbar();
    if (domCash === null || domCash === void 0 || Number.isNaN(domCash)) return false;
    el.textContent = formatMoneyWhole(domCash);
    return true;
  }
  async function tryUpdateGambleCashWithApiFallback() {
    const el = document.getElementById("gamble-cash-value");
    if (!el) return;
    const w = await getMoneyApiFallback();
    if (w !== null && w !== void 0 && !Number.isNaN(w)) el.textContent = formatMoneyWhole(w);
  }
  function refreshGambleCashAfterPanicTrade() {
    tryUpdateGambleCashFromNavbar();
    setTimeout(() => tryUpdateGambleCashFromNavbar(), 400);
    setTimeout(() => tryUpdateGambleCashFromNavbar(), 800);
    setTimeout(() => {
      if (!tryUpdateGambleCashFromNavbar()) void tryUpdateGambleCashWithApiFallback();
    }, 1400);
  }

  // src/panic/stocks-page.js
  function scanStocksFromDom() {
    const map = /* @__PURE__ */ new Map();
    document.querySelectorAll('ul[class^="stock_"]').forEach((ul) => {
      const img = ul.querySelector('img[src*="logos/"]');
      if (!img) return;
      const src = img.getAttribute("src") || "";
      const m = src.match(/logos\/([^/.]+)\.svg/i);
      if (!m) return;
      const sym = m[1].toUpperCase();
      const stockId = ul.getAttribute("id");
      const priceEl = ul.querySelector('div[class^="price_"]');
      const priceTxt = priceEl ? priceEl.textContent : "";
      const price = parseFloat(String(priceTxt).replace(/,/g, "")) || 0;
      if (stockId && sym) map.set(sym, { stockId, price });
    });
    return map;
  }
  function waitForStockRow(symbol, maxMs = 12e3) {
    const sym = String(symbol || "").toUpperCase();
    return new Promise((resolve, reject) => {
      const t0 = Date.now();
      const tick = () => {
        const row = scanStocksFromDom().get(sym);
        if (row && row.price > 0 && row.stockId) {
          resolve(row);
          return;
        }
        if (Date.now() - t0 > maxMs) {
          reject(new Error("Stock list not ready or symbol not found"));
          return;
        }
        setTimeout(tick, 200);
      };
      tick();
    });
  }

  // src/panic/trade.js
  function getRFC() {
    const c = document.cookie.match(/rfc_v=([^;]+)/);
    return c ? c[1] : "";
  }
  async function postBuyShares(stockId, amount) {
    const rfc = getRFC();
    const url = `https://www.torn.com/page.php?sid=StockMarket&step=buyShares&rfcv=${encodeURIComponent(rfc)}`;
    const body = new URLSearchParams();
    body.set("stockId", stockId);
    body.set("amount", String(amount));
    const res = await fetch(url, {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest"
      },
      body: body.toString()
    });
    const text = await res.text();
    let data;
    try {
      data = JSON.parse(text);
    } catch {
      throw new Error("Invalid response from Torn");
    }
    if (!data.success) throw new Error(data.message || "Trade failed");
    return data;
  }
  async function runPanic(btn, setStatus, openSettings2) {
    const { vaultStocks, lockedStocks, targetStock: sym } = getEffectiveVaultAndTarget();
    if (!sym || !vaultStocks.includes(sym)) {
      setStatus("Configure target stock (Settings)", true);
      openSettings2();
      return;
    }
    if (lockedStocks.includes(sym)) {
      setStatus("Target stock is locked", true);
      return;
    }
    if (!isStocksPage()) {
      try {
        sessionStorage.setItem(SS_PENDING, "1");
      } catch {
      }
      setStatus("Opening stocks\u2026 tap Panic again", false);
      window.location.href = stocksUrl();
      return;
    }
    if (btn) {
      btn.disabled = true;
      btn.classList.add("is-busy");
    }
    setStatus("Working\u2026", false);
    try {
      const cash = await getCashForPanic();
      const row = await waitForStockRow(sym);
      const shares = Math.floor(cash / row.price);
      if (shares <= 0) {
        setStatus("No cash to deposit", true);
        return;
      }
      await postBuyShares(row.stockId, shares);
      setStatus(`Deposited ${shares.toLocaleString()} shares`, false);
      refreshGambleCashAfterPanicTrade();
      try {
        sessionStorage.removeItem(SS_PENDING);
      } catch {
      }
    } catch (e) {
      console.error("[Smart Panic]", e);
      setStatus(e instanceof Error ? e.message : "Failed", true);
    } finally {
      if (btn) {
        btn.disabled = false;
        btn.classList.remove("is-busy");
      }
    }
  }

  // src/panic/settings.js
  function openSettings(setStatus) {
    const existing = document.querySelector(".hf-panic-settings-overlay");
    if (existing?.isConnected) return;
    existing?.remove();
    HF.theme.injectStyles();
    const panic = getPanicConfig();
    const overlay = document.createElement("div");
    overlay.className = "hf-torn hf-overlay hf-panic-settings-overlay";
    overlay.style.cssText = `
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.62);
    backdrop-filter: blur(2px);
  `;
    const modal = document.createElement("div");
    modal.className = "hf-modal hf-torn hf-panic-settings-modal";
    modal.style.cssText = "width: min(420px, 94vw); max-height: 90vh; overflow-y: auto; padding: 18px;";
    modal.innerHTML = `
    <h2>
      Smart Panic settings
      <button type="button" class="hf-btn hf-panic-close" title="Close">\xD7</button>
    </h2>
    <div class="hf-panic-field hf-panic-check">
      <input type="checkbox" id="hf-panic-prefer-ssv" ${panic.preferSmartStockVault ? "checked" : ""}>
      <label for="hf-panic-prefer-ssv">
        Use Smart Stock Vault settings when available (vault list, locks, gamble target)
      </label>
    </div>
    <div class="hf-panic-field" id="hf-panic-standalone-fields">
      <label class="hf-label" for="hf-panic-vault-symbols">Vault symbols (standalone)</label>
      <input class="hf-input" type="text" id="hf-panic-vault-symbols" placeholder="e.g. MUN, SYM, TCI" autocomplete="off">
      <label class="hf-label" for="hf-panic-target" style="margin-top:12px">Target stock</label>
      <select class="hf-select" id="hf-panic-target"></select>
    </div>
    <div class="hf-panic-field hf-panic-hint" id="hf-panic-ssv-hint" hidden>
      Target and vault come from Smart Stock Vault. Configure there, or turn off the checkbox above.
    </div>
    <div class="hf-panic-actions">
      <button type="button" class="hf-btn hf-btn--save" id="hf-panic-save">Save</button>
      <button type="button" class="hf-btn" id="hf-panic-cancel">Cancel</button>
    </div>
  `;
    overlay.appendChild(modal);
    document.body.appendChild(overlay);
    overlay.addEventListener("click", (e) => {
      if (e.target === overlay) overlay.remove();
    });
    modal.addEventListener("click", (e) => e.stopPropagation());
    const preferEl = modal.querySelector("#hf-panic-prefer-ssv");
    const standaloneFields = modal.querySelector("#hf-panic-standalone-fields");
    const ssvHint = modal.querySelector("#hf-panic-ssv-hint");
    const vaultInput = modal.querySelector("#hf-panic-vault-symbols");
    const targetSel = modal.querySelector("#hf-panic-target");
    vaultInput.value = (panic.vaultStocks || []).join(", ");
    function refreshStandaloneVisibility() {
      const useSsv = preferEl.checked;
      standaloneFields.hidden = useSsv;
      ssvHint.hidden = !useSsv;
    }
    function fillTargetOptions() {
      const useSsv = preferEl.checked;
      const stocks = useSsv ? (getSsvVault().stocks || []).map((s) => String(s).toUpperCase()) : parseSymbolsInput(vaultInput.value);
      targetSel.innerHTML = "";
      const cur = useSsv ? resolveTargetSymbol(getSsvGamble().targetStock || "", stocks) : String(panic.targetStock || "").toUpperCase();
      stocks.forEach((sym) => {
        const opt = document.createElement("option");
        opt.value = sym;
        opt.textContent = sym;
        if (sym === cur) opt.selected = true;
        targetSel.appendChild(opt);
      });
      if (stocks.length === 0) {
        const opt = document.createElement("option");
        opt.value = "";
        opt.textContent = "Add symbols first";
        targetSel.appendChild(opt);
      }
    }
    preferEl.addEventListener("change", () => {
      refreshStandaloneVisibility();
      fillTargetOptions();
    });
    vaultInput.addEventListener("input", () => {
      if (!preferEl.checked) fillTargetOptions();
    });
    refreshStandaloneVisibility();
    fillTargetOptions();
    modal.querySelector(".hf-panic-close")?.addEventListener("click", () => overlay.remove());
    modal.querySelector("#hf-panic-cancel")?.addEventListener("click", () => overlay.remove());
    modal.querySelector("#hf-panic-save")?.addEventListener("click", () => {
      const vaultParsed = parseSymbolsInput(vaultInput.value);
      const next = {
        preferSmartStockVault: preferEl.checked,
        vaultStocks: preferEl.checked ? panic.vaultStocks || [] : vaultParsed,
        lockedStocks: panic.lockedStocks || []
      };
      if (preferEl.checked) {
        next.targetStock = panic.targetStock || "";
      } else {
        if (!vaultParsed.length) {
          alert("Add at least one vault symbol for standalone mode.");
          return;
        }
        const t = targetSel.value || "";
        next.targetStock = t && vaultParsed.includes(t) ? t : resolveTargetSymbol("", vaultParsed);
        next.vaultStocks = vaultParsed;
      }
      savePanicConfig({ ...DEFAULT_CONFIG, ...panic, ...next });
      overlay.remove();
      setStatus("Settings saved", false);
    });
  }

  // src/panic/navbar.js
  var ROOT_ID = "hf-panic-root";
  function isMobileLayout() {
    return window.matchMedia("(max-width: 784px)").matches;
  }
  function findEnergyBarLink() {
    const selectors = [
      'a.bar-link[class*="energy"]',
      'a[class*="bar-link"][class*="energy"]',
      'a[href*="sid=energy"]',
      'a[href*="/energy"]'
    ];
    for (const sel of selectors) {
      const el = document.querySelector(sel);
      if (el?.parentNode) return el;
    }
    return null;
  }
  function findInsertBeforeEnergy() {
    const energy = findEnergyBarLink();
    if (energy?.parentNode) return { parent: energy.parentNode, before: energy };
    const money = document.getElementById("user-money");
    if (money) {
      let p = money.parentElement;
      for (let i = 0; i < 6 && p; i++) {
        const g = p.querySelector('a.bar-link[class*="energy"], a[class*="energy"][class*="bar-link"]');
        if (g?.parentNode) return { parent: g.parentNode, before: g };
        p = p.parentElement;
      }
      if (money.parentNode) return { parent: money.parentNode, before: money.nextElementSibling };
    }
    return null;
  }
  function findMobileHeaderRow() {
    const money = document.getElementById("user-money");
    if (!money?.parentNode) return null;
    let p = money;
    for (let i = 0; i < 8 && p; i++) {
      const rect = p.getBoundingClientRect();
      if (p.tagName === "UL" || p.tagName === "DIV" || p.tagName === "NAV") {
        if (rect.width > 200) return p;
      }
      p = p.parentElement;
    }
    return money.parentElement;
  }
  function mountNavbar(setStatus, openSettingsFn) {
    if (document.getElementById(ROOT_ID)) return true;
    const root = document.createElement("div");
    root.id = ROOT_ID;
    root.className = "hf-torn hf-panic-root";
    root.dataset.hfPanic = "1";
    const stack = document.createElement("div");
    stack.className = "hf-panic-stack";
    const wrap = document.createElement("div");
    wrap.className = "hf-panic-btn-wrap";
    const btn = document.createElement("button");
    btn.type = "button";
    btn.className = "hf-panic-btn";
    btn.textContent = "Panic";
    const gear = document.createElement("button");
    gear.type = "button";
    gear.className = "hf-panic-gear";
    gear.setAttribute("aria-label", "Smart Panic settings");
    gear.innerHTML = "&#9881;";
    const status = document.createElement("div");
    status.className = "hf-panic-status";
    status.id = "hf-panic-status";
    btn.addEventListener("click", () => runPanic(btn, setStatus, openSettingsFn));
    gear.addEventListener("click", (e) => {
      e.preventDefault();
      e.stopPropagation();
      openSettingsFn();
    });
    wrap.appendChild(btn);
    wrap.appendChild(gear);
    stack.appendChild(wrap);
    stack.appendChild(status);
    root.appendChild(stack);
    if (isMobileLayout()) root.classList.add("hf-panic-root--mobile");
    const anchor = findInsertBeforeEnergy();
    if (anchor) {
      anchor.parent.insertBefore(root, anchor.before);
      return true;
    }
    if (isMobileLayout()) {
      const rowHost = findMobileHeaderRow();
      if (rowHost) {
        if (getComputedStyle(rowHost).display === "flex" || rowHost.querySelector(".bar-link")) {
          rowHost.appendChild(root);
        } else {
          const outer = document.createElement("div");
          outer.style.cssText = "display:flex;width:100%;justify-content:center;padding:4px 0;";
          outer.appendChild(root);
          rowHost.parentNode?.insertBefore(outer, rowHost.nextSibling);
        }
        return true;
      }
    }
    return false;
  }
  function createStatusSetter() {
    let timer = null;
    return function setStatus(msg, isError = false) {
      const el = document.getElementById("hf-panic-status");
      if (!el) return;
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      el.textContent = msg || "";
      el.classList.toggle("is-error", !!isError);
      el.classList.toggle("is-ok", !!msg && !isError);
      if (msg && !isError) {
        timer = window.setTimeout(() => {
          el.textContent = "";
          el.classList.remove("is-error", "is-ok");
          timer = null;
        }, 4e3);
      }
    };
  }

  // src/panic/styles.js
  var STYLE_ID2 = "hf-panic-styles";
  function injectPanicStyles() {
    if (document.getElementById(STYLE_ID2)) return;
    const style = document.createElement("style");
    style.id = STYLE_ID2;
    style.textContent = `
    .hf-panic-root {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      vertical-align: middle;
      box-sizing: border-box;
      flex: 1 1 0%;
      min-width: 0;
      width: 100%;
      max-width: none;
      margin: 0 4px;
      font-family: var(--hf-font);
    }

    .hf-panic-root.hf-panic-root--mobile {
      margin: 2px 6px;
    }

    .hf-panic-stack {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      width: 100%;
      box-sizing: border-box;
    }

    .hf-panic-btn-wrap {
      position: relative;
      width: 100%;
      box-sizing: border-box;
      flex-shrink: 0;
    }

    .hf-panic-btn {
      display: block;
      width: 100%;
      box-sizing: border-box;
      height: 33px;
      min-height: 33px;
      max-height: 33px;
      padding: 0 24px 0 10px;
      margin: 0;
      font: inherit;
      font-size: 12px;
      font-weight: 700;
      line-height: 31px;
      border-radius: 5px;
      border: 1px solid var(--hf-danger-border);
      background: var(--hf-danger-bg);
      color: var(--hf-danger);
      cursor: pointer;
      text-align: center;
      transition: transform 0.1s ease, background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
      transform: scale(1);
      transform-origin: center center;
    }

    .hf-panic-btn:hover,
    .hf-panic-btn:focus-visible {
      background: var(--hf-danger);
      border-color: var(--hf-danger);
      color: #fff;
      outline: none;
    }

    .hf-panic-btn:active:not(:disabled),
    .hf-panic-btn.is-busy {
      transform: scale(0.96);
    }

    .hf-panic-btn:disabled {
      opacity: 0.85;
      cursor: wait;
    }

    .hf-panic-gear {
      appearance: none;
      position: absolute;
      top: 50%;
      right: 7px;
      width: 16px;
      height: 16px;
      min-width: 16px;
      min-height: 16px;
      padding: 0;
      margin: 0;
      border: 0;
      border-radius: 50%;
      background: transparent;
      color: var(--hf-text-muted);
      cursor: pointer;
      font: inherit;
      font-size: 11px;
      line-height: 16px;
      text-align: center;
      z-index: 2;
      opacity: 0.8;
      transform: translateY(-50%);
      transition: color 0.15s ease, opacity 0.15s ease, transform 0.1s ease;
    }

    .hf-panic-gear:hover,
    .hf-panic-gear:focus-visible {
      color: var(--hf-accent-text);
      opacity: 1;
      outline: none;
    }

    .hf-panic-gear:active {
      transform: translateY(-50%) scale(0.9);
    }

    .hf-panic-status {
      font-size: 10px;
      line-height: 1.25;
      margin-top: 3px;
      height: 2.5em;
      min-height: 2.5em;
      max-height: 2.5em;
      overflow: hidden;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      word-break: break-word;
      box-sizing: border-box;
      color: var(--hf-text-muted);
    }

    .hf-panic-status.is-error {
      color: var(--hf-danger);
    }

    .hf-panic-status.is-ok {
      color: var(--hf-success);
    }

    .hf-panic-settings-overlay {
      z-index: 2147483640;
    }

    .hf-panic-settings-modal h2 {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      margin: 0 0 14px;
      font-size: 15px;
      color: var(--hf-accent-text);
    }

    .hf-panic-settings-modal .hf-panic-close {
      padding: 2px 8px;
      line-height: 1.2;
    }

    .hf-panic-field {
      margin-bottom: 14px;
    }

    .hf-panic-check {
      display: flex;
      align-items: flex-start;
      gap: 10px;
      min-height: 44px;
      font-size: 12px;
      line-height: 1.45;
      color: var(--hf-text);
    }

    .hf-panic-check input {
      width: 18px;
      height: 18px;
      margin-top: 2px;
      flex-shrink: 0;
      accent-color: var(--hf-accent);
    }

    .hf-panic-hint {
      font-size: 11px;
      color: var(--hf-text-muted);
      line-height: 1.45;
    }

    .hf-panic-actions {
      display: flex;
      gap: 8px;
      margin-top: 16px;
    }

    .hf-panic-actions .hf-btn {
      flex: 1;
      min-height: 40px;
      font-weight: 700;
    }

    .hf-panic-actions .hf-btn--save {
      background: var(--hf-success-bg);
      border-color: var(--hf-success-border);
      color: var(--hf-success);
    }

    .hf-panic-actions .hf-btn--save:hover {
      filter: brightness(1.12);
      color: var(--hf-success);
    }
  `;
    document.head.appendChild(style);
  }

  // src/panic/main.js
  function maybeShowPendingToast(setStatus) {
    if (!isStocksPage()) return;
    try {
      if (sessionStorage.getItem(SS_PENDING) === "1") {
        setStatus("Tap Panic to deposit all cash", false);
      }
    } catch {
    }
  }
  function init() {
    HF.theme.injectStyles();
    injectPanicStyles();
    const setStatus = createStatusSetter();
    const openSettingsModal = () => openSettings(setStatus);
    let tries = 0;
    const maxTries = 80;
    const timer = window.setInterval(() => {
      tries += 1;
      if (mountNavbar(setStatus, openSettingsModal) || tries >= maxTries) {
        clearInterval(timer);
        if (tries >= maxTries && !document.getElementById("hf-panic-root")) {
          console.warn("[Smart Panic] Could not find header anchor; retrying on DOM mutations");
          const obs = new MutationObserver(() => {
            if (mountNavbar(setStatus, openSettingsModal)) obs.disconnect();
          });
          obs.observe(document.body, { childList: true, subtree: true });
        }
      }
    }, 250);
    maybeShowPendingToast(setStatus);
    window.addEventListener("pageshow", () => {
      setTimeout(() => maybeShowPendingToast(setStatus), 300);
    });
    let resizeT;
    window.addEventListener("resize", () => {
      clearTimeout(resizeT);
      resizeT = window.setTimeout(() => {
        if (!document.getElementById("hf-panic-root")) {
          mountNavbar(setStatus, openSettingsModal);
        }
      }, 300);
    });
  }
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();