FF Scouter Target Finder

Quick target finder using FF Scouter API

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         FF Scouter Target Finder
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Quick target finder using FF Scouter API
// @author       FFScouter
// @match        https://www.torn.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @connect      ffscouter.com
// @connect      api.torn.com
// ==/UserScript==

(function() {
    'use strict';

    // PDA API Key placeholder - Torn PDA replaces this at runtime when making requests
    const PDA_API_KEY = "###PDA-APIKEY###";

    // Detect mobile/touch device
    const isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);

    // Default configuration
    const defaultConfig = {
        apiKey: '',
        easy: {
            minFF: 1.50,
            maxFF: 2.0,
            minLevel: 1,
            maxLevel: 100
        },
        good: {
            minFF: 2.50,
            maxFF: 3.00,
            minLevel: 1,
            maxLevel: 100
        },
        factionlessOnly: false,
        inactiveOnly: true,
        openInNewTab: true,
        verifyStatus: false,
        hasUsedTap: false,
        hasUsedHold: false,
        buttonPosition: {
            right: 12,
            top: 50,
            isPercent: true
        },
        buttonVisible: true
    };

    // Load or initialize configuration
    function getConfig() {
        const saved = GM_getValue('ffscouter_config');
        if (saved) {
            try {
                const config = JSON.parse(saved);
                if (config.normal && !config.good) {
                    config.good = config.normal;
                    delete config.normal;
                }
                if (config.openInNewTab === undefined) config.openInNewTab = true;
                if (config.verifyStatus === undefined) config.verifyStatus = false;
                if (config.hasUsedTap === undefined) config.hasUsedTap = false;
                if (config.hasUsedHold === undefined) config.hasUsedHold = false;
                if (config.hasSeenHint) {
                    config.hasUsedTap = true;
                    config.hasUsedHold = true;
                    delete config.hasSeenHint;
                }
                if (!config.buttonPosition) {
                    config.buttonPosition = defaultConfig.buttonPosition;
                }
                if (config.buttonVisible === undefined) config.buttonVisible = true;
                return config;
            } catch (e) {
                return defaultConfig;
            }
        }
        return defaultConfig;
    }

    function saveConfig(config) {
        GM_setValue('ffscouter_config', JSON.stringify(config));
    }

    function getApiKey() {
        const config = getConfig();
        if (config.apiKey && /^[a-zA-Z0-9]{16}$/.test(config.apiKey)) {
            return { key: config.apiKey, source: 'manual' };
        }
        return { key: PDA_API_KEY, source: 'pda' };
    }

    // Torn-style CSS
    GM_addStyle(`
        /* ===== SETTINGS POPUP ===== */
        .ffs-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.85);
            z-index: 999999;
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: Arial, Helvetica, sans-serif;
            backdrop-filter: blur(3px);
        }

        .ffs-popup {
            background: linear-gradient(180deg, #2d2d2d 0%, #1a1a1a 100%);
            border-radius: 8px;
            width: 380px;
            max-width: 95vw;
            max-height: 90vh;
            overflow-y: auto;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.1);
            color: #ddd;
        }

        .ffs-popup::-webkit-scrollbar {
            width: 8px;
        }

        .ffs-popup::-webkit-scrollbar-track {
            background: #1a1a1a;
        }

        .ffs-popup::-webkit-scrollbar-thumb {
            background: #444;
            border-radius: 4px;
        }

        .ffs-header {
            background: linear-gradient(180deg, #3d3d3d 0%, #2a2a2a 100%);
            padding: 16px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #444;
            position: sticky;
            top: 0;
            z-index: 10;
        }

        .ffs-header-title {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .ffs-header-title svg {
            width: 22px;
            height: 22px;
            fill: #6ac46a;
        }

        .ffs-header h2 {
            margin: 0!important;
            color: #fff;
            font-size: 15px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }

        .ffs-close {
            background: rgba(255,255,255,0.1);
            border: none;
            color: #888;
            font-size: 18px;
            cursor: pointer;
            padding: 0;
            width: 28px;
            height: 28px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s;
        }

        .ffs-close:hover {
            background: rgba(255,100,100,0.2);
            color: #f66;
        }

        .ffs-content {
            padding: 16px;
        }

        /* API Status Banner */
        .ffs-api-banner {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 12px 14px;
            border-radius: 6px;
            margin-bottom: 16px;
            cursor: pointer;
            transition: all 0.2s;
        }

        .ffs-api-banner svg {
            width: 20px;
            height: 20px;
            flex-shrink: 0;
        }

        .ffs-api-banner-text {
            flex: 1;
        }

        .ffs-api-banner-title {
            font-size: 12px;
            font-weight: 600;
            margin-bottom: 2px;
        }

        .ffs-api-banner-sub {
            font-size: 10px;
            opacity: 0.7;
        }

        .ffs-api-banner.manual {
            background: linear-gradient(135deg, rgba(106, 196, 106, 0.15) 0%, rgba(80, 150, 80, 0.1) 100%);
            border: 1px solid rgba(106, 196, 106, 0.3);
        }

        .ffs-api-banner.manual svg {
            fill: #6c6;
        }

        .ffs-api-banner.manual:hover {
            background: linear-gradient(135deg, rgba(106, 196, 106, 0.25) 0%, rgba(80, 150, 80, 0.15) 100%);
        }

        .ffs-api-banner.auto {
            background: linear-gradient(135deg, rgba(106, 150, 196, 0.15) 0%, rgba(80, 120, 150, 0.1) 100%);
            border: 1px solid rgba(106, 150, 196, 0.3);
        }

        .ffs-api-banner.auto svg {
            fill: #6af;
        }

        .ffs-api-banner.auto:hover {
            background: linear-gradient(135deg, rgba(106, 150, 196, 0.25) 0%, rgba(80, 120, 150, 0.15) 100%);
        }

        .ffs-api-badge {
            background: rgba(255,255,255,0.1);
            padding: 3px 8px;
            border-radius: 10px;
            font-size: 9px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .ffs-api-banner.auto .ffs-api-badge {
            background: rgba(106, 170, 255, 0.2);
            color: #6af;
        }

        .ffs-api-banner.manual .ffs-api-badge {
            background: rgba(106, 196, 106, 0.2);
            color: #6c6;
        }

        /* Target Cards */
        .ffs-target-card {
            background: rgba(0,0,0,0.2);
            border: 1px solid #333;
            border-radius: 6px;
            margin-bottom: 12px;
            overflow: hidden;
        }

        .ffs-card-header {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 10px 14px;
            background: rgba(255,255,255,0.03);
            border-bottom: 1px solid #333;
        }

        .ffs-card-icon {
            width: 32px;
            height: 32px;
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
        }

        .ffs-card-icon.easy {
            background: linear-gradient(135deg, #4a7c4a 0%, #3a5c3a 100%);
        }

        .ffs-card-icon.good {
            background: linear-gradient(135deg, #7c6a4a 0%, #5c4a3a 100%);
        }

        .ffs-card-title {
            flex: 1;
        }

        .ffs-card-title h3 {
            margin: 0!important;
            font-size: 13px;
            font-weight: 600;
            color: #eee;
        }

        .ffs-card-title span {
            font-size: 10px;
            color: #777;
        }

        .ffs-card-body {
            padding: 12px 14px;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .ffs-input-row {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .ffs-input-label {
            font-size: 11px;
            color: #999;
            width: 55px;
            flex-shrink: 0;
        }

        .ffs-input-group {
            display: flex;
            align-items: center;
            gap: 6px;
            flex: 1;
        }

        .ffs-input {
            flex: 1;
            padding: 8px 10px;
            border: 1px solid #444;
            border-radius: 4px;
            background: #252525;
            color: #fff;
            font-size: 13px;
            text-align: center;
            transition: all 0.2s;
        }

        .ffs-input:focus {
            outline: none;
            border-color: #6ac46a;
            background: #2a2a2a;
            box-shadow: 0 0 0 2px rgba(106, 196, 106, 0.1);
        }

        .ffs-input-sep {
            color: #555;
            font-size: 11px;
        }

        /* Target Count Badge */
        .ffs-card-count {
            padding: 6px 14px;
            background: rgba(0,0,0,0.2);
            border-top: 1px solid #333;
            font-size: 11px;
            color: #888;
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .ffs-card-count.loading {
            color: #666;
        }

        .ffs-card-count.error {
            color: #c66;
        }

        .ffs-card-count.warning {
            color: #c96;
        }

        .ffs-card-count.good {
            color: #6a6;
        }

        .ffs-count-num {
            font-weight: 600;
            color: #aaa;
        }

        .ffs-card-count.warning .ffs-count-num {
            color: #fc6;
        }

        .ffs-card-count.good .ffs-count-num {
            color: #6c6;
        }

        .ffs-card-count.error .ffs-count-num {
            color: #c66;
        }

        .ffs-count-spinner {
            width: 12px;
            height: 12px;
            border: 2px solid #444;
            border-top-color: #888;
            border-radius: 50%;
            animation: ffs-spin 0.8s linear infinite;
        }

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

        /* Options Section */
        .ffs-options {
            background: rgba(0,0,0,0.2);
            border: 1px solid #333;
            border-radius: 6px;
            overflow: hidden;
            margin-bottom: 16px;
        }

        .ffs-options-header {
            padding: 10px 14px;
            background: rgba(255,255,255,0.03);
            border-bottom: 1px solid #333;
            font-size: 11px;
            font-weight: 600;
            color: #888;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .ffs-option {
            display: flex;
            align-items: center;
            padding: 12px 14px;
            border-bottom: 1px solid #2a2a2a;
            cursor: pointer;
            transition: background 0.15s;
        }

        .ffs-option:last-child {
            border-bottom: none;
        }

        .ffs-option:hover {
            background: rgba(255,255,255,0.02);
        }

        .ffs-option-text {
            flex: 1;
            margin-left: 12px;
        }

        .ffs-option-title {
            font-size: 12px;
            color: #ddd;
        }

        .ffs-option-desc {
            font-size: 10px;
            color: #666;
            margin-top: 2px;
        }

        .ffs-option-warn {
            color: #c96;
        }

        /* Custom Toggle Switch */
        .ffs-toggle {
            position: relative;
            width: 40px;
            height: 22px;
            flex-shrink: 0;
        }

        .ffs-toggle input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .ffs-toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: #3a3a3a;
            border-radius: 22px;
            transition: 0.2s;
            border: 1px solid #444;
        }

        .ffs-toggle-slider:before {
            position: absolute;
            content: "";
            height: 16px;
            width: 16px;
            left: 2px;
            bottom: 2px;
            background: #888;
            border-radius: 50%;
            transition: 0.2s;
        }

        .ffs-toggle input:checked + .ffs-toggle-slider {
            background: #4a7c4a;
            border-color: #5a5;
        }

        .ffs-toggle input:checked + .ffs-toggle-slider:before {
            transform: translateX(18px);
            background: #fff;
        }

        /* Footer */
        .ffs-footer {
            display: flex;
            gap: 10px;
            padding: 16px;
            background: rgba(0,0,0,0.2);
            border-top: 1px solid #333;
        }

        .ffs-btn {
            flex: 1;
            padding: 12px 20px;
            border: none;
            border-radius: 6px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }

        .ffs-btn-primary {
            background: linear-gradient(180deg, #5a9 0%, #4a8 100%);
            color: #fff;
            box-shadow: 0 2px 8px rgba(90, 170, 150, 0.3);
        }

        .ffs-btn-primary:hover {
            background: linear-gradient(180deg, #6ba 0%, #5a9 100%);
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(90, 170, 150, 0.4);
        }

        .ffs-btn-secondary {
            background: #333;
            color: #aaa;
            border: 1px solid #444;
        }

        .ffs-btn-secondary:hover {
            background: #3a3a3a;
            color: #ddd;
        }

        /* Keyboard hints */
        .ffs-kbd-hints {
            display: ${isMobile ? 'none' : 'flex'};
            justify-content: center;
            gap: 16px;
            padding: 12px;
            background: rgba(0,0,0,0.3);
            border-top: 1px solid #333;
        }

        .ffs-kbd-hint {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 10px;
            color: #666;
        }

        .ffs-kbd {
            background: #333;
            padding: 3px 6px;
            border-radius: 3px;
            font-family: monospace;
            font-size: 10px;
            color: #999;
            border: 1px solid #444;
        }

        /* ===== TOAST ===== */
        .ffs-toast {
            position: fixed;
            bottom: ${isMobile ? '80px' : '20px'};
            right: 20px;
            left: ${isMobile ? '20px' : 'auto'};
            padding: 14px 18px;
            border-radius: 8px;
            color: #fff;
            font-size: 13px;
            font-weight: 500;
            z-index: 9999999;
            animation: ffs-slide-in 0.3s ease;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
            max-width: ${isMobile ? 'none' : '320px'};
        }

        .ffs-toast-success {
            background: linear-gradient(135deg, #4a7c4a 0%, #3a5c3a 100%);
        }

        .ffs-toast-error {
            background: linear-gradient(135deg, #7c4a4a 0%, #5c3a3a 100%);
        }

        .ffs-toast-info {
            background: linear-gradient(135deg, #4a5c7c 0%, #3a4a5c 100%);
        }

        .ffs-toast-warning {
            background: linear-gradient(135deg, #7c6a4a 0%, #5c4a3a 100%);
        }

        @keyframes ffs-slide-in {
            from { transform: translateY(20px); opacity: 0; }
            to { transform: translateY(0); opacity: 1; }
        }

        /* ===== FLOATING BUTTON ===== */
        .ffs-fab-container {
            position: fixed;
            z-index: 999998;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
        }

        .ffs-fab-container.hidden {
            display: none !important;
        }

        .ffs-fab {
            width: ${isMobile ? '48px' : '42px'};
            height: ${isMobile ? '48px' : '42px'};
            border-radius: 50%;
            background: linear-gradient(135deg, #4a7c4a 0%, #3a5c3a 100%);
            border: 2px solid #5a5;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
            transition: all 0.2s;
            position: relative;
            user-select: none;
            -webkit-tap-highlight-color: transparent;
        }

        .ffs-fab:hover {
            transform: scale(1.08);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
        }

        .ffs-fab:active {
            transform: scale(0.95);
        }

        .ffs-fab svg {
            width: 22px;
            height: 22px;
            fill: #fff;
            z-index: 2;
        }

        .ffs-fab-label {
            background: rgba(0,0,0,0.7);
            color: #fc6;
            font-size: 9px;
            font-weight: 600;
            padding: 3px 8px;
            border-radius: 10px;
            white-space: nowrap;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            pointer-events: none;
        }

        .ffs-fab-progress {
            position: absolute;
            top: -4px;
            left: -4px;
            width: calc(100% + 8px);
            height: calc(100% + 8px);
            transform: rotate(-90deg);
            opacity: 0;
            transition: opacity 0.1s;
        }

        .ffs-fab-progress circle {
            fill: none;
            stroke: #fff;
            stroke-width: 3;
            stroke-dasharray: 160;
            stroke-dashoffset: 160;
            stroke-linecap: round;
        }

        .ffs-fab.pressing .ffs-fab-progress {
            opacity: 1;
        }

        .ffs-fab.pressing .ffs-fab-progress circle {
            animation: ffs-progress-fill 0.5s ease-out forwards;
        }

        @keyframes ffs-progress-fill {
            to { stroke-dashoffset: 0; }
        }

        .ffs-fab-hint {
            position: absolute;
            right: calc(100% + 12px);
            top: 50%;
            transform: translateY(-50%);
            background: #222;
            color: #ddd;
            padding: 10px 14px;
            border-radius: 8px;
            font-size: 12px;
            white-space: nowrap;
            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s;
            border: 1px solid #444;
        }

        .ffs-fab-hint::after {
            content: '';
            position: absolute;
            right: -6px;
            top: 50%;
            transform: translateY(-50%);
            border: 6px solid transparent;
            border-left-color: #444;
        }

        .ffs-fab-hint.show {
            opacity: 1;
        }

        .ffs-fab-hint.animate {
            animation: ffs-hint-bounce 0.5s ease;
        }

        @keyframes ffs-hint-bounce {
            0%, 100% { transform: translateY(-50%) translateX(0); }
            50% { transform: translateY(-50%) translateX(-5px); }
        }

        .ffs-hint-row {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 4px 0;
        }

        .ffs-hint-action {
            background: #333;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 10px;
            color: #999;
            min-width: 40px;
            text-align: center;
        }

        .ffs-hint-result {
            color: #ddd;
        }

        .ffs-hint-result.good {
            color: #fc6;
        }

        .ffs-hint-result.menu {
            color: #aaa;
        }

        /* ===== FLOATING MENU ===== */
        .ffs-menu {
            position: fixed;
            z-index: 999997;
            background: #1c1c1c;
            border: 1px solid #444;
            border-radius: 10px;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
            overflow: hidden;
            opacity: 0;
            pointer-events: none;
            transition: all 0.2s ease;
            min-width: 180px;
        }

        .ffs-menu.active {
            opacity: 1;
            pointer-events: auto;
            transform: scale(1);
        }

        .ffs-menu-header {
            padding: 12px 16px;
            background: linear-gradient(135deg, #4a7c4a 0%, #3a5c3a 100%);
            color: #fff;
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }

        .ffs-menu-item {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 14px 16px;
            color: #ccc;
            font-size: 13px;
            cursor: pointer;
            border-bottom: 1px solid #2a2a2a;
            transition: all 0.15s;
        }

        .ffs-menu-item:last-child {
            border-bottom: none;
        }

        .ffs-menu-item:hover {
            background: rgba(255,255,255,0.05);
            color: #fff;
        }

        .ffs-menu-item:active {
            background: rgba(255,255,255,0.08);
        }

        .ffs-menu-icon {
            font-size: 16px;
            width: 20px;
            text-align: center;
        }

        .ffs-menu-text {
            flex: 1;
        }

        .ffs-menu-kbd {
            background: #333;
            padding: 3px 7px;
            border-radius: 4px;
            font-family: monospace;
            font-size: 10px;
            color: #777;
            border: 1px solid #444;
            display: ${isMobile ? 'none' : 'block'};
        }

        .ffs-menu-item.easy { color: #7c7; }
        .ffs-menu-item.easy:hover { background: rgba(106, 196, 106, 0.1); color: #9f9; }

        .ffs-menu-item.good { color: #fc6; }
        .ffs-menu-item.good:hover { background: rgba(255, 204, 102, 0.1); color: #fd8; }

        .ffs-menu-item.move { color: #6af; }
        .ffs-menu-item.move:hover { background: rgba(102, 170, 255, 0.1); color: #8cf; }

        /* ===== REPOSITION MODE ===== */
        .ffs-fab-container.repositioning {
            cursor: grab;
            z-index: 9999999;
        }

        .ffs-fab-container.repositioning.dragging {
            cursor: grabbing;
        }

        .ffs-fab-container.repositioning .ffs-fab {
            animation: ffs-pulse 1.5s ease-in-out infinite;
            border-color: #6af;
            background: linear-gradient(135deg, #4a6c9c 0%, #3a4c6c 100%);
        }

        .ffs-fab-container.repositioning .ffs-fab:hover {
            transform: none;
        }

        @keyframes ffs-pulse {
            0%, 100% { box-shadow: 0 0 0 0 rgba(102, 170, 255, 0.5), 0 4px 15px rgba(0, 0, 0, 0.4); }
            50% { box-shadow: 0 0 0 10px rgba(102, 170, 255, 0), 0 4px 15px rgba(0, 0, 0, 0.4); }
        }

        .ffs-reposition-bar {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: #1c1c1c;
            border: 1px solid #444;
            border-radius: 12px;
            padding: 12px 20px;
            display: flex;
            align-items: center;
            gap: 16px;
            z-index: 99999999;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6);
            font-family: Arial, Helvetica, sans-serif;
        }

        .ffs-reposition-text {
            color: #ddd;
            font-size: 13px;
        }

        .ffs-reposition-text span {
            color: #6af;
            font-weight: 600;
        }

        .ffs-reposition-btns {
            display: flex;
            gap: 8px;
        }

        .ffs-reposition-btn {
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            font-size: 12px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }

        .ffs-reposition-btn.confirm {
            background: linear-gradient(180deg, #5a9 0%, #4a8 100%);
            color: #fff;
        }

        .ffs-reposition-btn.confirm:hover {
            background: linear-gradient(180deg, #6ba 0%, #5a9 100%);
        }

        .ffs-reposition-btn.cancel {
            background: #333;
            color: #aaa;
            border: 1px solid #444;
        }

        .ffs-reposition-btn.cancel:hover {
            background: #3a3a3a;
            color: #ddd;
        }

        .ffs-reposition-btn.reset {
            background: transparent;
            color: #888;
            padding: 8px 12px;
        }

        .ffs-reposition-btn.reset:hover {
            color: #c66;
        }

        /* ===== TORN SETTINGS MENU TOGGLE ===== */
        .ffs-torn-toggle .icon-wrapper svg {
            fill: #6ac46a;
        }
    `);

    // Toast notification
    function showToast(message, type = 'info', duration = 3000) {
        const existing = document.querySelector('.ffs-toast');
        if (existing) existing.remove();

        const toast = document.createElement('div');
        toast.className = `ffs-toast ffs-toast-${type}`;
        toast.textContent = message;
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.style.animation = 'ffs-slide-in 0.3s ease reverse';
            setTimeout(() => toast.remove(), 300);
        }, duration);
    }

    // API Key prompt
    function promptApiKey() {
        const config = getConfig();
        const currentKey = config.apiKey || '';

        const newKey = prompt(
            "Enter your FF Scouter API Key (16 characters):\n\nIf you don't have one: \n    Get an api key from: \n        https://www.torn.com/preferences.php#tab=api \n    then register it in: ffscouter.com\n\nTorn PDA users: Leave empty to use automatic key",
            currentKey
        );

        if (newKey === null) return;

        const trimmedKey = newKey.trim();

        if (trimmedKey === '') {
            config.apiKey = '';
            saveConfig(config);
            showToast('Using automatic API key', 'success');
            return;
        }

        if (!/^[a-zA-Z0-9]{16}$/.test(trimmedKey)) {
            showToast('Invalid key format (must be 16 characters)', 'error');
            return;
        }

        config.apiKey = trimmedKey;
        saveConfig(config);
        showToast('API key saved!', 'success');
    }

    function getRandomElement(arr) {
        return arr[Math.floor(Math.random() * arr.length)];
    }

    function shuffleArray(arr) {
        const shuffled = [...arr];
        for (let i = shuffled.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
        }
        return shuffled;
    }

    // Check target status via Torn API
    function checkTargetStatus(playerId, apiKey) {
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://api.torn.com/v2/user/${playerId}/basic?striptags=true&key=${apiKey}`,
                timeout: 5000,
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.error) {
                            resolve({ success: false, error: data.error.error || 'API error' });
                            return;
                        }
                        const state = data.profile?.status?.state;
                        const isOkay = state === 'Okay';
                        resolve({
                            success: true,
                            isOkay,
                            state,
                            status: data.profile?.status
                        });
                    } catch (e) {
                        resolve({ success: false, error: 'Parse error' });
                    }
                },
                onerror: function() {
                    resolve({ success: false, error: 'Request failed' });
                },
                ontimeout: function() {
                    resolve({ success: false, error: 'Timeout' });
                }
            });
        });
    }

    // Fetch target count for preview
    function fetchTargetCount(settings, inactiveOnly, factionlessOnly) {
        return new Promise((resolve) => {
            const { key } = getApiKey();

            const params = new URLSearchParams({
                key: key,
                minff: settings.minFF,
                maxff: settings.maxFF,
                minlevel: settings.minLevel,
                maxlevel: settings.maxLevel,
                inactiveonly: inactiveOnly ? 1 : 0,
                factionless: factionlessOnly ? 1 : 0,
                limit: 50
            });

            const url = `https://ffscouter.com/api/v1/get-targets?${params.toString()}`;

            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                timeout: 10000,
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.error) {
                            resolve({ success: false, error: data.error });
                            return;
                        }
                        const count = data.targets?.length || 0;
                        resolve({ success: true, count });
                    } catch (e) {
                        resolve({ success: false, error: 'Parse error' });
                    }
                },
                onerror: function() {
                    resolve({ success: false, error: 'Request failed' });
                },
                ontimeout: function() {
                    resolve({ success: false, error: 'Timeout' });
                }
            });
        });
    }

    // Find a valid target (with optional status verification)
    async function findValidTarget(targets, apiKey, verifyStatus) {
        if (!verifyStatus) {
            return { target: getRandomElement(targets), checked: 0 };
        }

        const shuffled = shuffleArray(targets);
        let checked = 0;

        for (const target of shuffled) {
            checked++;
            const status = await checkTargetStatus(target.player_id, apiKey);

            if (!status.success) {
                console.warn('FFS: Status check failed:', status.error);
                return { target, checked, verifyFailed: true };
            }

            if (status.isOkay) {
                return { target, checked };
            }

            console.log(`FFS: Target ${target.name} is ${status.state}, trying next...`);
        }

        return { target: null, checked };
    }

    // API call function
    async function fetchTarget(targetType) {
        const { key, source } = getApiKey();
        const config = getConfig();
        const settings = targetType === 'easy' ? config.easy : config.good;

        const params = new URLSearchParams({
            key: key,
            minff: settings.minFF,
            maxff: settings.maxFF,
            minlevel: settings.minLevel,
            maxlevel: settings.maxLevel,
            inactiveonly: config.inactiveOnly ? 1 : 0,
            factionless: config.factionlessOnly ? 1 : 0,
            limit: 50
        });

        const url = `https://ffscouter.com/api/v1/get-targets?${params.toString()}`;

        showToast(`Finding ${targetType} target...`, 'info');

        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            onload: async function(response) {
                try {
                    const data = JSON.parse(response.responseText);

                    if (data.error) {
                        if (source === 'pda' && (data.error.includes('key') || data.error.includes('API') || data.error.includes('auth'))) {
                            showToast('API key required - not using Torn PDA?', 'error');
                            setTimeout(() => promptApiKey(), 1000);
                        } else {
                            showToast(`Error: ${data.error}`, 'error');
                        }
                        return;
                    }

                    if (!data.targets || data.targets.length === 0) {
                        showToast('No targets found with current filters', 'error');
                        return;
                    }

                    const targetCount = data.targets.length;

                    if (targetCount < 10) {
                        showToast(`Warning: Only ${targetCount} target${targetCount === 1 ? '' : 's'} available. Consider adjusting filters.`, 'warning');
                        await new Promise(r => setTimeout(r, 1500));
                    }

                    const verifyStatus = config.verifyStatus;
                    if (verifyStatus) {
                        showToast('Verifying target status...', 'info');
                    }

                    const result = await findValidTarget(data.targets, key, verifyStatus);

                    if (!result.target) {
                        showToast(`No available targets found (checked ${result.checked})`, 'error');
                        return;
                    }

                    if (result.verifyFailed) {
                        showToast('Status check failed, using unverified target', 'warning');
                        await new Promise(r => setTimeout(r, 1000));
                    }

                    const target = result.target;
                    const attackUrl = `https://www.torn.com/loader.php?sid=attack&user2ID=${target.player_id}`;

                    let message = `${target.name} [${target.player_id}] • Lvl ${target.level} • FF ${target.fair_fight.toFixed(2)}`;
                    if (verifyStatus && result.checked > 1) {
                        message += ` (${result.checked} checked)`;
                    }
                    showToast(message, 'success');

                    if (config.openInNewTab) {
                        window.open(attackUrl, '_blank');
                    } else {
                        window.location.href = attackUrl;
                    }
                } catch (e) {
                    showToast('Failed to parse response', 'error');
                    console.error('FFS Error:', e);
                }
            },
            onerror: function(error) {
                showToast('Request failed - check connection', 'error');
                console.error('FFS Error:', error);
            }
        });
    }

    // Reposition mode
    let isRepositioning = false;
    let originalPosition = null;

    function enterRepositionMode() {
        if (isRepositioning) return;
        isRepositioning = true;

        const container = document.querySelector('.ffs-fab-container');
        const floatingMenu = document.querySelector('.ffs-menu');
        if (floatingMenu) floatingMenu.classList.remove('active');

        const config = getConfig();
        originalPosition = { ...config.buttonPosition };

        container.classList.add('repositioning');

        // Create instruction bar
        const bar = document.createElement('div');
        bar.className = 'ffs-reposition-bar';
        bar.innerHTML = `
            <div class="ffs-reposition-text"><span>Drag</span> the button to move it</div>
            <div class="ffs-reposition-btns">
                <button class="ffs-reposition-btn reset">Reset</button>
                <button class="ffs-reposition-btn cancel">Cancel</button>
                <button class="ffs-reposition-btn confirm">Save</button>
            </div>
        `;
        document.body.appendChild(bar);

        // Dragging state
        let isDragging = false;
        let startX, startY;
        let startLeft, startTop;

        const getContainerPosition = () => {
            const rect = container.getBoundingClientRect();
            return {
                left: rect.left,
                top: rect.top
            };
        };

        const onDragStart = (e) => {
            e.preventDefault();
            isDragging = true;
            container.classList.add('dragging');

            const pos = getContainerPosition();
            startLeft = pos.left;
            startTop = pos.top;

            if (e.type === 'touchstart') {
                startX = e.touches[0].clientX;
                startY = e.touches[0].clientY;
            } else {
                startX = e.clientX;
                startY = e.clientY;
            }
        };

        const onDragMove = (e) => {
            if (!isDragging) return;
            e.preventDefault();

            let clientX, clientY;
            if (e.type === 'touchmove') {
                clientX = e.touches[0].clientX;
                clientY = e.touches[0].clientY;
            } else {
                clientX = e.clientX;
                clientY = e.clientY;
            }

            const deltaX = clientX - startX;
            const deltaY = clientY - startY;

            let newLeft = startLeft + deltaX;
            let newTop = startTop + deltaY;

            // Constrain to viewport
            const fabSize = isMobile ? 48 : 42;
            const padding = 8;
            newLeft = Math.max(padding, Math.min(window.innerWidth - fabSize - padding, newLeft));
            newTop = Math.max(padding, Math.min(window.innerHeight - fabSize - padding, newTop));

            // Apply position
            container.style.left = newLeft + 'px';
            container.style.top = newTop + 'px';
            container.style.right = 'auto';
            container.style.transform = 'none';
        };

        const onDragEnd = () => {
            if (!isDragging) return;
            isDragging = false;
            container.classList.remove('dragging');
        };

        // Add drag listeners
        container.addEventListener('mousedown', onDragStart);
        document.addEventListener('mousemove', onDragMove);
        document.addEventListener('mouseup', onDragEnd);

        container.addEventListener('touchstart', onDragStart, { passive: false });
        document.addEventListener('touchmove', onDragMove, { passive: false });
        document.addEventListener('touchend', onDragEnd);

        const cleanup = () => {
            container.removeEventListener('mousedown', onDragStart);
            document.removeEventListener('mousemove', onDragMove);
            document.removeEventListener('mouseup', onDragEnd);
            container.removeEventListener('touchstart', onDragStart);
            document.removeEventListener('touchmove', onDragMove);
            document.removeEventListener('touchend', onDragEnd);
            document.removeEventListener('keydown', escHandler);
            bar.remove();
            container.classList.remove('repositioning', 'dragging');
            isRepositioning = false;
        };

        const savePosition = () => {
            const rect = container.getBoundingClientRect();
            const config = getConfig();

            // Calculate position from right and top percentage for responsiveness
            config.buttonPosition = {
                right: window.innerWidth - rect.right,
                top: (rect.top / window.innerHeight) * 100,
                isPercent: true
            };

            saveConfig(config);
            applyButtonPosition();
            cleanup();
            showToast('Button position saved!', 'success');
        };

        const cancelReposition = () => {
            applyButtonPosition(originalPosition);
            cleanup();
        };

        const resetPosition = () => {
            const config = getConfig();
            config.buttonPosition = { ...defaultConfig.buttonPosition };
            saveConfig(config);
            applyButtonPosition();
            cleanup();
            showToast('Button position reset!', 'info');
        };

        bar.querySelector('.confirm').addEventListener('click', savePosition);
        bar.querySelector('.cancel').addEventListener('click', cancelReposition);
        bar.querySelector('.reset').addEventListener('click', resetPosition);

        const escHandler = (e) => {
            if (e.key === 'Escape') {
                cancelReposition();
            }
        };
        document.addEventListener('keydown', escHandler);
    }

    function applyButtonPosition(customPosition = null) {
        const container = document.querySelector('.ffs-fab-container');
        if (!container) return;

        const config = getConfig();
        const pos = customPosition || config.buttonPosition;

        container.style.right = pos.right + 'px';
        container.style.left = 'auto';

        if (pos.isPercent) {
            container.style.top = pos.top + '%';
            container.style.transform = 'translateY(-50%)';
        } else {
            container.style.top = pos.top + 'px';
            container.style.transform = 'none';
        }
    }

    function updateMenuPosition() {
        const container = document.querySelector('.ffs-fab-container');
        const menu = document.querySelector('.ffs-menu');
        if (!container || !menu) return;

        const rect = container.getBoundingClientRect();
        const menuWidth = 180;
        const menuHeight = menu.offsetHeight || 250;

        // Decide whether to show menu on left or right of button
        let menuLeft;
        if (rect.left > menuWidth + 20) {
            // Show on left
            menuLeft = rect.left - menuWidth - 10;
        } else {
            // Show on right
            menuLeft = rect.right + 10;
        }

        // Vertical positioning
        let menuTop = rect.top + (rect.height / 2) - (menuHeight / 2);
        menuTop = Math.max(10, Math.min(window.innerHeight - menuHeight - 10, menuTop));

        menu.style.left = menuLeft + 'px';
        menu.style.top = menuTop + 'px';
        menu.style.right = 'auto';
        menu.style.transform = 'scale(1)';
    }

    // Button visibility
    function updateButtonVisibility() {
        const container = document.querySelector('.ffs-fab-container');
        const menu = document.querySelector('.ffs-menu');
        if (!container) return;

        const config = getConfig();
        if (config.buttonVisible) {
            container.classList.remove('hidden');
        } else {
            container.classList.add('hidden');
            if (menu) menu.classList.remove('active');
        }
    }

    // Inject toggle into Torn's settings menu
    function injectSettingsToggle() {
        const settingsMenu = document.querySelector('ul.settings-menu');
        if (!settingsMenu || document.getElementById('ffs-button-state')) return;

        const config = getConfig();

        const li = document.createElement('li');
        li.className = 'setting ffs-torn-toggle';
        li.innerHTML = `
            <label for="ffs-button-state" class="setting-container">
                <div class="icon-wrapper">
                    <svg viewBox="0 0 24 24" width="22" height="22"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
                </div>
                <span class="setting-name">FF Scouter</span>
                <div class="choice-container">
                    <input id="ffs-button-state" class="checkbox-css dark-bg" type="checkbox" ${config.buttonVisible ? 'checked' : ''}>
                    <label class="marker-css" for="ffs-button-state"></label>
                </div>
            </label>
        `;

        // Insert before the Settings link
        const settingsLink = settingsMenu.querySelector('li.link a[href="/preferences.php"]');
        if (settingsLink && settingsLink.parentElement) {
            settingsMenu.insertBefore(li, settingsLink.parentElement);
        } else {
            // Fallback: insert before logout
            const logoutLink = settingsMenu.querySelector('li.link a[href^="/logout.php"]');
            if (logoutLink && logoutLink.parentElement) {
                settingsMenu.insertBefore(li, logoutLink.parentElement);
            } else {
                settingsMenu.appendChild(li);
            }
        }

        // Add event listener
        document.getElementById('ffs-button-state').addEventListener('change', (e) => {
            const cfg = getConfig();
            cfg.buttonVisible = e.target.checked;
            saveConfig(cfg);
            updateButtonVisibility();

            if (!e.target.checked) {
                showToast('FF Scouter button hidden. Re-enable from profile menu.', 'info', 4000);
            } else {
                showToast('FF Scouter button visible', 'success');
            }
        });
    }

    // Configuration popup
    function showConfigPopup() {
        const existing = document.querySelector('.ffs-overlay');
        if (existing) existing.remove();

        const floatingMenu = document.querySelector('.ffs-menu');
        if (floatingMenu) floatingMenu.classList.remove('active');

        const config = getConfig();
        const { source } = getApiKey();
        const isManual = source === 'manual';

        const overlay = document.createElement('div');
        overlay.className = 'ffs-overlay';
        overlay.innerHTML = `
            <div class="ffs-popup">
                <div class="ffs-header">
                    <div class="ffs-header-title">
                        <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
                        <h2>FF Scouter</h2>
                    </div>
                    <button class="ffs-close" id="ffs-close">✕</button>
                </div>

                <div class="ffs-content">
                    <div class="ffs-api-banner ${isManual ? 'manual' : 'auto'}" id="ffs-api-btn">
                        <svg viewBox="0 0 24 24"><path d="M12.65 10C11.83 7.67 9.61 6 7 6c-3.31 0-6 2.69-6 6s2.69 6 6 6c2.61 0 4.83-1.67 5.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
                        <div class="ffs-api-banner-text">
                            <div class="ffs-api-banner-title">${isManual ? 'Manual API Key' : 'Automatic (Torn PDA)'}</div>
                            <div class="ffs-api-banner-sub">${isManual ? 'Click to change or use automatic' : 'Click to set manual key instead'}</div>
                        </div>
                        <span class="ffs-api-badge">${isManual ? 'Manual' : 'Auto'}</span>
                    </div>

                    <div class="ffs-target-card" id="ffs-easy-card">
                        <div class="ffs-card-header">
                            <div class="ffs-card-icon easy">⚡</div>
                            <div class="ffs-card-title">
                                <h3>Easy Targets</h3>
                                <span>${isMobile ? 'Via menu' : 'Press F1'}</span>
                            </div>
                        </div>
                        <div class="ffs-card-body">
                            <div class="ffs-input-row">
                                <span class="ffs-input-label">Fair Fight</span>
                                <div class="ffs-input-group">
                                    <input type="number" class="ffs-input ffs-easy-input" id="ffs-easy-minff" value="${config.easy.minFF}" step="0.1" min="1" max="3">
                                    <span class="ffs-input-sep">→</span>
                                    <input type="number" class="ffs-input ffs-easy-input" id="ffs-easy-maxff" value="${config.easy.maxFF}" step="0.1" min="1" max="3">
                                </div>
                            </div>
                            <div class="ffs-input-row">
                                <span class="ffs-input-label">Level</span>
                                <div class="ffs-input-group">
                                    <input type="number" class="ffs-input ffs-easy-input" id="ffs-easy-minlvl" value="${config.easy.minLevel}" min="1" max="100">
                                    <span class="ffs-input-sep">→</span>
                                    <input type="number" class="ffs-input ffs-easy-input" id="ffs-easy-maxlvl" value="${config.easy.maxLevel}" min="1" max="100">
                                </div>
                            </div>
                        </div>
                        <div class="ffs-card-count loading" id="ffs-easy-count">
                            <div class="ffs-count-spinner"></div>
                            <span>Checking available targets...</span>
                        </div>
                    </div>

                    <div class="ffs-target-card" id="ffs-good-card">
                        <div class="ffs-card-header">
                            <div class="ffs-card-icon good">🔥</div>
                            <div class="ffs-card-title">
                                <h3>Good Targets</h3>
                                <span>${isMobile ? 'Tap button' : 'Press F2'}</span>
                            </div>
                        </div>
                        <div class="ffs-card-body">
                            <div class="ffs-input-row">
                                <span class="ffs-input-label">Fair Fight</span>
                                <div class="ffs-input-group">
                                    <input type="number" class="ffs-input ffs-good-input" id="ffs-good-minff" value="${config.good.minFF}" step="0.1" min="1" max="3">
                                    <span class="ffs-input-sep">→</span>
                                    <input type="number" class="ffs-input ffs-good-input" id="ffs-good-maxff" value="${config.good.maxFF}" step="0.1" min="1" max="3">
                                </div>
                            </div>
                            <div class="ffs-input-row">
                                <span class="ffs-input-label">Level</span>
                                <div class="ffs-input-group">
                                    <input type="number" class="ffs-input ffs-good-input" id="ffs-good-minlvl" value="${config.good.minLevel}" min="1" max="100">
                                    <span class="ffs-input-sep">→</span>
                                    <input type="number" class="ffs-input ffs-good-input" id="ffs-good-maxlvl" value="${config.good.maxLevel}" min="1" max="100">
                                </div>
                            </div>
                        </div>
                        <div class="ffs-card-count loading" id="ffs-good-count">
                            <div class="ffs-count-spinner"></div>
                            <span>Checking available targets...</span>
                        </div>
                    </div>

                    <div class="ffs-options">
                        <div class="ffs-options-header">Filters</div>
                        <label class="ffs-option">
                            <div class="ffs-toggle">
                                <input type="checkbox" id="ffs-inactive" class="ffs-filter-toggle" ${config.inactiveOnly ? 'checked' : ''}>
                                <span class="ffs-toggle-slider"></span>
                            </div>
                            <div class="ffs-option-text">
                                <div class="ffs-option-title">Inactive Only</div>
                                <div class="ffs-option-desc">Target players inactive 14+ days</div>
                            </div>
                        </label>
                        <label class="ffs-option">
                            <div class="ffs-toggle">
                                <input type="checkbox" id="ffs-factionless" class="ffs-filter-toggle" ${config.factionlessOnly ? 'checked' : ''}>
                                <span class="ffs-toggle-slider"></span>
                            </div>
                            <div class="ffs-option-text">
                                <div class="ffs-option-title">Factionless Only</div>
                                <div class="ffs-option-desc">Target players without a faction</div>
                            </div>
                        </label>
                        <label class="ffs-option">
                            <div class="ffs-toggle">
                                <input type="checkbox" id="ffs-verify" ${config.verifyStatus ? 'checked' : ''}>
                                <span class="ffs-toggle-slider"></span>
                            </div>
                            <div class="ffs-option-text">
                                <div class="ffs-option-title">Verify Status</div>
                                <div class="ffs-option-desc">Check target is okay <span class="ffs-option-warn">(slower)</span></div>
                            </div>
                        </label>
                    </div>

                    <div class="ffs-options">
                        <div class="ffs-options-header">Behavior</div>
                        <label class="ffs-option">
                            <div class="ffs-toggle">
                                <input type="checkbox" id="ffs-newtab" ${config.openInNewTab ? 'checked' : ''}>
                                <span class="ffs-toggle-slider"></span>
                            </div>
                            <div class="ffs-option-text">
                                <div class="ffs-option-title">Open in New Tab</div>
                                <div class="ffs-option-desc">Open attack page in a new browser tab</div>
                            </div>
                        </label>
                        <div class="ffs-option" id="ffs-move-btn" style="cursor: pointer;">
                            <div style="width: 40px; height: 22px; display: flex; align-items: center; justify-content: center;">
                                <span style="font-size: 18px;">📍</span>
                            </div>
                            <div class="ffs-option-text">
                                <div class="ffs-option-title">Move Button</div>
                                <div class="ffs-option-desc">Drag the floating button to a new position</div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="ffs-footer">
                    <button class="ffs-btn ffs-btn-secondary" id="ffs-cancel">Cancel</button>
                    <button class="ffs-btn ffs-btn-primary" id="ffs-save">Save Settings</button>
                </div>

                <div class="ffs-kbd-hints">
                    <div class="ffs-kbd-hint"><span class="ffs-kbd">F1</span> Easy</div>
                    <div class="ffs-kbd-hint"><span class="ffs-kbd">F2</span> Good</div>
                    <div class="ffs-kbd-hint"><span class="ffs-kbd">F3</span> API Key</div>
                    <div class="ffs-kbd-hint"><span class="ffs-kbd">F4</span> Settings</div>
                </div>
            </div>
        `;

        document.body.appendChild(overlay);

        // Target count update functions
        let easyDebounce = null;
        let goodDebounce = null;

        function updateCountDisplay(elementId, result) {
            const el = document.getElementById(elementId);
            if (!el) return;

            if (!result.success) {
                el.className = 'ffs-card-count error';
                el.innerHTML = `<span class="ffs-count-num">!</span> <span>${result.error}</span>`;
                return;
            }

            const count = result.count;
            let statusClass = 'good';
            let statusText = 'targets available';

            if (count === 0) {
                statusClass = 'error';
                statusText = 'No targets found';
            } else if (count < 10) {
                statusClass = 'warning';
                statusText = count === 1 ? 'target available (very low!)' : 'targets available (low!)';
            } else if (count == 50) {
                statusText = 'targets available (max)';
            }

            el.className = `ffs-card-count ${statusClass}`;
            el.innerHTML = `<span class="ffs-count-num">${count}</span> <span>${statusText}</span>`;
        }

        function setCountLoading(elementId) {
            const el = document.getElementById(elementId);
            if (!el) return;
            el.className = 'ffs-card-count loading';
            el.innerHTML = '<div class="ffs-count-spinner"></div> <span>Checking...</span>';
        }

        function getFormSettings(type) {
            const prefix = type === 'easy' ? 'ffs-easy' : 'ffs-good';
            return {
                minFF: parseFloat(document.getElementById(`${prefix}-minff`).value) || 1,
                maxFF: parseFloat(document.getElementById(`${prefix}-maxff`).value) || 3,
                minLevel: parseInt(document.getElementById(`${prefix}-minlvl`).value) || 1,
                maxLevel: parseInt(document.getElementById(`${prefix}-maxlvl`).value) || 100
            };
        }

        function getFormFilters() {
            return {
                inactiveOnly: document.getElementById('ffs-inactive').checked,
                factionlessOnly: document.getElementById('ffs-factionless').checked
            };
        }

        async function refreshEasyCount() {
            setCountLoading('ffs-easy-count');
            const settings = getFormSettings('easy');
            const filters = getFormFilters();
            const result = await fetchTargetCount(settings, filters.inactiveOnly, filters.factionlessOnly);
            updateCountDisplay('ffs-easy-count', result);
        }

        async function refreshGoodCount() {
            setCountLoading('ffs-good-count');
            const settings = getFormSettings('good');
            const filters = getFormFilters();
            const result = await fetchTargetCount(settings, filters.inactiveOnly, filters.factionlessOnly);
            updateCountDisplay('ffs-good-count', result);
        }

        async function refreshBothCounts() {
            await Promise.all([refreshEasyCount(), refreshGoodCount()]);
        }

        // Debounced refresh for easy inputs
        function debouncedRefreshEasy() {
            clearTimeout(easyDebounce);
            easyDebounce = setTimeout(refreshEasyCount, 300);
        }

        // Debounced refresh for good inputs
        function debouncedRefreshGood() {
            clearTimeout(goodDebounce);
            goodDebounce = setTimeout(refreshGoodCount, 300);
        }

        // Add blur listeners to easy inputs
        document.querySelectorAll('.ffs-easy-input').forEach(input => {
            input.addEventListener('blur', debouncedRefreshEasy);
            input.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') {
                    e.target.blur();
                }
            });
        });

        // Add blur listeners to good inputs
        document.querySelectorAll('.ffs-good-input').forEach(input => {
            input.addEventListener('blur', debouncedRefreshGood);
            input.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') {
                    e.target.blur();
                }
            });
        });

        // Add change listeners to filter toggles
        document.querySelectorAll('.ffs-filter-toggle').forEach(toggle => {
            toggle.addEventListener('change', refreshBothCounts);
        });

        // Initial count fetch
        refreshBothCounts();

        const closePopup = () => {
            clearTimeout(easyDebounce);
            clearTimeout(goodDebounce);
            overlay.remove();
        };

        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) closePopup();
        });

        document.getElementById('ffs-close').addEventListener('click', closePopup);
        document.getElementById('ffs-cancel').addEventListener('click', closePopup);
        document.getElementById('ffs-api-btn').addEventListener('click', () => {
            closePopup();
            promptApiKey();
        });

        document.getElementById('ffs-move-btn').addEventListener('click', () => {
            closePopup();
            setTimeout(() => enterRepositionMode(), 100);
        });

        document.getElementById('ffs-save').addEventListener('click', () => {
            const currentConfig = getConfig();

            const newConfig = {
                apiKey: currentConfig.apiKey,
                easy: {
                    minFF: parseFloat(document.getElementById('ffs-easy-minff').value) || 1.50,
                    maxFF: parseFloat(document.getElementById('ffs-easy-maxff').value) || 2.00,
                    minLevel: parseInt(document.getElementById('ffs-easy-minlvl').value) || 1,
                    maxLevel: parseInt(document.getElementById('ffs-easy-maxlvl').value) || 100
                },
                good: {
                    minFF: parseFloat(document.getElementById('ffs-good-minff').value) || 2.50,
                    maxFF: parseFloat(document.getElementById('ffs-good-maxff').value) || 3.00,
                    minLevel: parseInt(document.getElementById('ffs-good-minlvl').value) || 1,
                    maxLevel: parseInt(document.getElementById('ffs-good-maxlvl').value) || 100
                },
                inactiveOnly: document.getElementById('ffs-inactive').checked,
                factionlessOnly: document.getElementById('ffs-factionless').checked,
                verifyStatus: document.getElementById('ffs-verify').checked,
                openInNewTab: document.getElementById('ffs-newtab').checked,
                hasUsedTap: currentConfig.hasUsedTap,
                hasUsedHold: currentConfig.hasUsedHold,
                buttonPosition: currentConfig.buttonPosition,
                buttonVisible: currentConfig.buttonVisible
            };

            if (newConfig.easy.minFF > newConfig.easy.maxFF) {
                showToast('Easy: Min FF cannot exceed Max', 'error');
                return;
            }
            if (newConfig.good.minFF > newConfig.good.maxFF) {
                showToast('Good: Min FF cannot exceed Max', 'error');
                return;
            }
            if (newConfig.easy.minLevel > newConfig.easy.maxLevel) {
                showToast('Easy: Min Level cannot exceed Max', 'error');
                return;
            }
            if (newConfig.good.minLevel > newConfig.good.maxLevel) {
                showToast('Good: Min Level cannot exceed Max', 'error');
                return;
            }

            saveConfig(newConfig);
            showToast('Settings saved!', 'success');
            closePopup();
        });

        const escHandler = (e) => {
            if (e.key === 'Escape') {
                closePopup();
                document.removeEventListener('keydown', escHandler);
            }
        };
        document.addEventListener('keydown', escHandler);
    }

    // Create floating button
    function createFloatingButton() {
        const container = document.createElement('div');
        container.className = 'ffs-fab-container';

        const config = getConfig();
        const showInitialHint = !config.hasUsedTap || !config.hasUsedHold;

        container.innerHTML = `
            <div class="ffs-fab" title="Tap: Good Target • Hold: Menu">
                <svg class="ffs-fab-progress" viewBox="0 0 52 52">
                    <circle cx="26" cy="26" r="24"/>
                </svg>
                <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
                <div class="ffs-fab-hint ${showInitialHint ? 'show animate' : ''}" id="ffs-hint">
                    <div class="ffs-hint-row">
                        <span class="ffs-hint-action">Tap</span>
                        <span class="ffs-hint-result good">🔥 Good Target</span>
                    </div>
                    <div class="ffs-hint-row">
                        <span class="ffs-hint-action">Hold</span>
                        <span class="ffs-hint-result menu">☰ More Options</span>
                    </div>
                </div>
            </div>
        `;

        const floatingMenu = document.createElement('div');
        floatingMenu.className = 'ffs-menu';
        floatingMenu.innerHTML = `
            <div class="ffs-menu-header">FF Scouter</div>
            <div class="ffs-menu-item easy" data-action="easy">
                <span class="ffs-menu-icon">⚡</span>
                <span class="ffs-menu-text">Easy Target</span>
                <span class="ffs-menu-kbd">F1</span>
            </div>
            <div class="ffs-menu-item good" data-action="good">
                <span class="ffs-menu-icon">🔥</span>
                <span class="ffs-menu-text">Good Target</span>
                <span class="ffs-menu-kbd">F2</span>
            </div>
            <div class="ffs-menu-item" data-action="apikey">
                <span class="ffs-menu-icon">🔑</span>
                <span class="ffs-menu-text">API Key</span>
                <span class="ffs-menu-kbd">F3</span>
            </div>
            <div class="ffs-menu-item" data-action="settings">
                <span class="ffs-menu-icon">⚙️</span>
                <span class="ffs-menu-text">Settings</span>
                <span class="ffs-menu-kbd">F4</span>
            </div>
            <div class="ffs-menu-item move" data-action="move">
                <span class="ffs-menu-icon">📍</span>
                <span class="ffs-menu-text">Move Button</span>
                <span class="ffs-menu-kbd"></span>
            </div>
        `;

        document.body.appendChild(container);
        document.body.appendChild(floatingMenu);

        // Apply saved position and visibility
        applyButtonPosition();
        updateButtonVisibility();

        const fab = container.querySelector('.ffs-fab');
        const hint = container.querySelector('#ffs-hint');
        let hintTimeout = null;

        function shouldShowHints() {
            const cfg = getConfig();
            return !cfg.hasUsedTap || !cfg.hasUsedHold;
        }

        const hideHint = () => {
            hint.classList.remove('show', 'animate');
        };

        const showHint = (animate = false) => {
            if (shouldShowHints()) {
                hint.classList.add('show');
                if (animate) hint.classList.add('animate');
            }
        };

        if (showInitialHint) {
            hintTimeout = setTimeout(() => {
                hideHint();
            }, isMobile ? 8000 : 6000);
        }

        if (!isMobile) {
            fab.addEventListener('mouseenter', () => {
                if (shouldShowHints()) {
                    clearTimeout(hintTimeout);
                    showHint(false);
                }
            });
            fab.addEventListener('mouseleave', () => {
                if (!fab.classList.contains('pressing')) {
                    hideHint();
                }
            });
        }

        let pressTimer = null;
        let isLongPress = false;
        const LONG_PRESS_DURATION = 500;

        const startPress = (e) => {
            if (isRepositioning) return;
            e.preventDefault();
            clearTimeout(hintTimeout);
            hideHint();
            isLongPress = false;
            fab.classList.add('pressing');

            pressTimer = setTimeout(() => {
                isLongPress = true;
                fab.classList.remove('pressing');
                updateMenuPosition();
                floatingMenu.classList.add('active');

                const cfg = getConfig();
                if (!cfg.hasUsedHold) {
                    cfg.hasUsedHold = true;
                    saveConfig(cfg);
                }
            }, LONG_PRESS_DURATION);
        };

        const endPress = (e) => {
            if (isRepositioning) return;
            e.preventDefault();
            fab.classList.remove('pressing');

            if (pressTimer) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }

            if (!isLongPress) {
                const cfg = getConfig();
                if (!cfg.hasUsedTap) {
                    cfg.hasUsedTap = true;
                    saveConfig(cfg);
                }
                fetchTarget('good');
            }
        };

        const cancelPress = () => {
            if (isRepositioning) return;
            fab.classList.remove('pressing');
            if (pressTimer) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        };

        fab.addEventListener('mousedown', startPress);
        fab.addEventListener('mouseup', endPress);
        fab.addEventListener('mouseleave', cancelPress);

        fab.addEventListener('touchstart', startPress, { passive: false });
        fab.addEventListener('touchend', endPress, { passive: false });
        fab.addEventListener('touchcancel', cancelPress);

        fab.addEventListener('contextmenu', (e) => e.preventDefault());

        floatingMenu.addEventListener('click', (e) => {
            const item = e.target.closest('.ffs-menu-item');
            if (!item) return;

            const action = item.dataset.action;
            floatingMenu.classList.remove('active');

            switch (action) {
                case 'easy': fetchTarget('easy'); break;
                case 'good': fetchTarget('good'); break;
                case 'apikey': promptApiKey(); break;
                case 'settings': showConfigPopup(); break;
                case 'move': enterRepositionMode(); break;
            }
        });

        document.addEventListener('click', (e) => {
            if (!floatingMenu.contains(e.target) && !fab.contains(e.target)) {
                floatingMenu.classList.remove('active');
            }
        });
    }

    // Keyboard shortcuts
    document.addEventListener('keydown', (e) => {
        if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) {
            return;
        }

        if (isRepositioning) return;

        switch (e.key) {
            case 'F1':
                e.preventDefault();
                fetchTarget('easy');
                break;
            case 'F2':
                e.preventDefault();
                fetchTarget('good');
                break;
            case 'F3':
                e.preventDefault();
                promptApiKey();
                break;
            case 'F4':
                e.preventDefault();
                showConfigPopup();
                break;
        }
    });

    // Watch for settings menu to appear
    const observer = new MutationObserver(() => {
        injectSettingsToggle();
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // Initialize
    createFloatingButton();
    injectSettingsToggle();
    console.log('FF Scouter loaded');
})();