// ==UserScript== // @name SakaLuX Elimination Assistant // @namespace sakalux.elimination.assistant // @version 1.3.66 // @description Torn Eliminations advisor with rotating 500-player batches, persistent SAFE targets, TornPDA export, FF/BS calibration and PC-safe attack links. // @author SakaLuX [2380374] // @copyright 2026 SakaLuX [2380374] // @license All Rights Reserved // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @connect api.torn.com // @connect ffscouter.com // @downloadURL https://update.greasyfork.org/scripts/594921/SakaLuX%20Elimination%20Assistant.user.js // @updateURL https://update.greasyfork.org/scripts/594921/SakaLuX%20Elimination%20Assistant.meta.js // @homepage https://github.com/SakaLuX/SakaLuX-Script-HUB // @supportURL https://github.com/SakaLuX/SakaLuX-Script-HUB/issues // ==/UserScript== /* SakaLuX Shared Core — BEGIN */ /* SakaLuX Shared Core v1 - test foundation * Source-only module. Not installed directly by users. * Intended to be embedded into standalone userscripts at build/release time. */ (() => { 'use strict'; const g = globalThis; const CORE_VERSION = '1.2.8'; const NS = 'SakaLuXCore'; const SETTINGS_CATALOG = Object.freeze([ { match: /Account Auditor/i, id: 'account-auditor', version: 1, keys: ['SakaLuX_AUDITOR_SETTINGS_V3'] }, { match: /Bazaar Smart Pricer/i, id: 'bazaar-smart-pricer', version: 1, keys: ['SakaLuX_BAZAAR_SMART_PRICER_SETTINGS'] }, { match: /Bazaar Thanker/i, id: 'bazaar', version: 1, keys: ['sakalux_bazaar_thanker_v5'] }, { match: /Bounty Hunter/i, id: 'bounty-hunter', version: 1, keys: ['SLX_BOUNTY_SETTINGS_V3','SLX_BOUNTY_WATCH_V1','SLX_BOUNTY_BLACK_V1','SLX_BOUNTY_CACHE_V2','SLX_BOUNTY_USER_CACHE_V1','SLX_BOUNTY_FF_CACHE_V1','SLX_BOUNTY_SCAN_STATE_V1'] }, { match: /Chat Intelligence/i, id: 'chat-intelligence', version: 1, keys: ['SLX_CHAT_CFG4'] }, { match: /Company Intelligence/i, id: 'company-intelligence', version: 1, keys: ['sak_ci:mode', 'sak_ci:tab', 'sak_ci:compact', 'sak_ci:enabled'] }, { match: /Elimination Assistant/i, id: 'elimination-assistant', version: 1, keys: ['slx_elim_ui_v1'] }, { match: /Enhancer Guard/i, id: 'enhancer', version: 1, keys: ['SakaLuX_EG_FAVORITES'] }, { match: /Market Intelligence/i, id: 'market-intelligence', version: 1, keys: ['SakaLuX_MI_SETTINGS_V2'] }, { match: /Mission Rewards/i, id: 'mission-rewards', version: 1, keys: ['SakaLuX_MR_SETTINGS_V1'] }, { match: /Script Hub/i, id: 'script-hub', version: 1, keys: ['SakaLuX_HUB_SETTINGS_V16'] }, { match: /Stock Manager/i, id: 'stock-manager-advisor', version: 1, keys: ['SLX_STOCK_PRESETS', 'SLX_STOCK_BENEFIT_VALUES'] }, { match: /SakaLuX Suite/i, id: 'suite', version: 1, keys: ['sakalux_master_suite_settings_v1'] } ]); function currentScriptSettingsDefinition() { let name = ''; try { name = String(g.GM_info?.script?.name || ''); } catch {} return SETTINGS_CATALOG.find(entry => entry.match.test(name)) || null; } function currentTransportEnvironment() { let gm = null; try { if (typeof GM_xmlhttpRequest === 'function') gm = GM_xmlhttpRequest; } catch {} return { pda: typeof g.PDA_httpGet === 'function' ? g.PDA_httpGet.bind(g) : null, gm, fetch: typeof g.fetch === 'function' ? g.fetch.bind(g) : null }; } if (g[NS]?.version === CORE_VERSION) { g[NS].api?.registerEnvironment?.(currentTransportEnvironment()); g[NS].settings?.autoGuardCurrentScript?.(); if (!g.SakaLuXPerf && g[NS].perf) g.SakaLuXPerf = g[NS].perf; return; } const timers = new Map(); const listeners = new Set(); let routeKey = ''; let routeEpoch = 0; let routerBound = false; let routeAbortHook = null; const perf = { debounce(key, fn, wait = 220) { const old = timers.get(key); if (old) clearTimeout(old); const id = setTimeout(() => { timers.delete(key); fn(); }, Math.max(120, Number(wait) || 220)); timers.set(key, id); return id; }, idle(fn, timeout = 700) { if (typeof requestIdleCallback === 'function') return requestIdleCallback(fn, { timeout }); return setTimeout(fn, 32); }, unrelated(records) { return Array.isArray(records) && records.length > 0 && records.every(record => { const node = record?.target; const target = node?.nodeType === 1 ? node : node?.parentElement; return !!target?.closest?.('#chat-box,[id^="chat-box"],[class*="chat-box"],[class*="chatBox"],#sakalux-standalone-dock,[id^="sakalux-inline-footer-"]'); }); } }; const hub = { installed() { if (typeof document === 'undefined') return false; const html = document.documentElement; const body = document.body; return !!( g.SakaLuXScriptHub || document.getElementById('sakalux-hub-button') || document.getElementById('sakalux-hub-top-skull') || document.getElementById('sakalux-hub-nav-skull') || document.getElementById('sakalux-hub-panel') || document.getElementById('sakalux-hub-style') || html?.getAttribute('data-sakalux-hub-installed') === '1' || body?.getAttribute('data-sakalux-hub-installed') === '1' || html?.getAttribute('data-sakalux-hub-active') === '1' || body?.getAttribute('data-sakalux-hub-active') === '1' ); } }; const storage = { get(key, fallback = null) { try { const raw = localStorage.getItem(key); return raw == null ? fallback : JSON.parse(raw); } catch { return fallback; } }, set(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); return true; } catch { return false; } }, remove(key) { try { localStorage.removeItem(key); return true; } catch { return false; } } }; const settings = (() => { const statuses = new Map(); const prefix = 'SakaLuX_SettingsSchema::'; const backupPrefix = 'SakaLuX_SettingsBackup::'; function normalizeDefinition(definition = {}) { const id = String(definition.id || '').trim(); const version = Math.max(1, Math.floor(Number(definition.version) || 1)); const keys = [...new Set((definition.keys || []).map(String).filter(Boolean))]; if (!id) throw new Error('Settings schema id is required'); if (!keys.length) throw new Error(`Settings schema ${id} has no storage keys`); return { ...definition, id, version, keys }; } function readJson(key, fallback) { try { const raw = localStorage.getItem(key); return raw == null ? fallback : JSON.parse(raw); } catch { return fallback; } } function writeJson(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); return true; } catch { return false; } } function snapshot(keys) { const values = {}; for (const key of keys) { try { const raw = localStorage.getItem(key); if (raw != null) values[key] = raw; } catch {} } return values; } function validateAndRecover(def, backup) { const recovered = []; const reset = []; const valid = []; for (const key of def.keys) { let raw = null; try { raw = localStorage.getItem(key); } catch {} if (raw == null) continue; try { JSON.parse(raw); valid.push(key); continue; } catch {} const previous = backup?.values?.[key]; if (typeof previous === 'string') { try { JSON.parse(previous); localStorage.setItem(key, previous); recovered.push(key); continue; } catch {} } try { localStorage.removeItem(key); } catch {} reset.push(key); } return { recovered, reset, valid }; } function register(definition = {}) { const def = normalizeDefinition(definition); const metaKey = prefix + def.id; const backupKey = backupPrefix + def.id; const previousMeta = readJson(metaKey, {}) || {}; const previousVersion = Math.max(0, Math.floor(Number(previousMeta.version) || 0)); const existingBackup = readJson(backupKey, null); const before = snapshot(def.keys); if (Object.keys(before).length) writeJson(backupKey, { version: previousVersion, at: Date.now(), values: before }); const recovery = validateAndRecover(def, existingBackup); let migrated = false; let fallback = recovery.reset.length > 0; let error = ''; if (previousVersion < def.version) { try { for (let target = previousVersion + 1; target <= def.version; target++) { const migrate = def.migrations?.[target]; if (typeof migrate !== 'function') continue; for (const key of def.keys) { let raw = null; try { raw = localStorage.getItem(key); } catch {} if (raw == null) continue; const current = JSON.parse(raw); const next = migrate(current, { id: def.id, key, from: target - 1, to: target }); if (next !== undefined) localStorage.setItem(key, JSON.stringify(next)); } } migrated = previousVersion > 0 || Object.keys(before).length > 0; } catch (err) { error = String(err?.message || err); fallback = true; for (const key of def.keys) { const raw = before[key]; try { if (raw == null) localStorage.removeItem(key); else localStorage.setItem(key, raw); } catch {} } } } const nextMeta = { schema: 'sakalux-settings-schema-v1', id: def.id, version: error ? previousVersion : Math.max(previousVersion, def.version), updatedAt: Date.now(), migrated, fallback, recovered: recovery.recovered, reset: recovery.reset, error: error || null }; writeJson(metaKey, nextMeta); statuses.set(def.id, Object.freeze({ ...nextMeta })); return statuses.get(def.id); } function status(id) { return statuses.get(String(id)) || readJson(prefix + String(id), null); } function diagnostics() { return Object.freeze(Object.fromEntries([...statuses.entries()])); } function autoGuardCurrentScript() { const def = currentScriptSettingsDefinition(); if (!def) return null; try { return register(def); } catch (err) { const failed = Object.freeze({ schema: 'sakalux-settings-schema-v1', id: def.id, version: 0, fallback: true, error: String(err?.message || err) }); statuses.set(def.id, failed); return failed; } } return Object.freeze({ register, status, diagnostics, autoGuardCurrentScript, catalog: SETTINGS_CATALOG }); })(); const router = { key(loc = g.location) { if (!loc) return ''; return `${loc.pathname || ''}${loc.search || ''}${loc.hash || ''}`; }, epoch() { return routeEpoch; }, onChange(fn) { listeners.add(fn); return () => listeners.delete(fn); }, check(loc = g.location) { const next = this.key(loc); if (next === routeKey) return false; const prev = routeKey; routeKey = next; routeEpoch++; try { routeAbortHook?.({ previous: prev, current: next, epoch: routeEpoch }); } catch (err) { console.error('[SakaLuXCore router abort]', err); } for (const fn of [...listeners]) { try { fn({ previous: prev, current: next, epoch: routeEpoch }); } catch (err) { console.error('[SakaLuXCore router]', err); } } return true; }, bind() { if (routerBound || typeof g.addEventListener !== 'function') return false; const signal = () => this.check(); g.addEventListener('hashchange', signal, { passive: true }); g.addEventListener('popstate', signal, { passive: true }); routerBound = true; return true; } }; const dock = { ORDER: Object.freeze([ 'enhancer','bazaar','bazaar-smart-pricer','bounty-hunter','mission-rewards','market-intelligence', 'elimination-assistant','company-intelligence','chat-intelligence','stock-manager-advisor','account-auditor' ]), dedupe(registrations = []) { return [...new Map(registrations.filter(Boolean).map(r => [r.id, r])).values()]; }, sort(registrations = []) { const order = this.ORDER; return this.dedupe(registrations).sort((a, b) => { const ai = order.indexOf(a.id), bi = order.indexOf(b.id); const ar = ai < 0 ? Number.MAX_SAFE_INTEGER : ai; const br = bi < 0 ? Number.MAX_SAFE_INTEGER : bi; return ar - br || String(a.name || a.id).localeCompare(String(b.name || b.id)); }); } }; const api = (() => { const inflight = new Map(); const responseCache = new Map(); const queue = []; const routeControllers = new Set(); const env = { pda: null, gm: null, fetch: null }; const stats = { requests: 0, networkRequests: 0, cacheHits: 0, deduped: 0, retries: 0, failures: 0, aborted: 0, timeouts: 0, rateLimited: 0 }; let active = 0; let maxConcurrent = 4; let sequence = 0; function registerEnvironment(next = {}) { if (typeof next.pda === 'function') env.pda = next.pda; if (typeof next.gm === 'function') env.gm = next.gm; if (typeof next.fetch === 'function') env.fetch = next.fetch; if (typeof g.PDA_httpGet === 'function') env.pda = g.PDA_httpGet.bind(g); if (!env.fetch && typeof g.fetch === 'function') env.fetch = g.fetch.bind(g); return { pda: !!env.pda, gm: !!env.gm, fetch: !!env.fetch }; } function makeError(message, code, extra = {}) { const err = new Error(message); err.code = code; Object.assign(err, extra); return err; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, Math.max(0, ms))); } function canonicalUrl(value) { const raw = String(value || ''); try { const u = new URL(raw, g.location?.origin || 'https://www.torn.com'); for (const key of ['ts', '_', 'cacheBust', 'cache_bust']) u.searchParams.delete(key); u.searchParams.sort(); return u.toString(); } catch { return raw; } } function requestKey(opts) { if (opts.key) return String(opts.key); return `${opts.method}|${canonicalUrl(opts.url)}|${opts.parse || 'text'}|${opts.credentials || ''}`; } function cacheRead(key) { const row = responseCache.get(key); if (!row) return null; if (row.expiresAt <= Date.now()) { responseCache.delete(key); return null; } return row.value; } function cacheWrite(key, value, ttl) { const ms = Math.max(0, Number(ttl) || 0); if (ms > 0) responseCache.set(key, { value, expiresAt: Date.now() + ms }); } function enqueue(run, priority = 0) { return new Promise((resolve, reject) => { queue.push({ run, priority: Number(priority) || 0, sequence: sequence++, resolve, reject }); queue.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence); pump(); }); } function pump() { while (active < maxConcurrent && queue.length) { const job = queue.shift(); active++; Promise.resolve().then(job.run).then(job.resolve, job.reject).finally(() => { active--; pump(); }); } } function normalizePdaResponse(raw) { if (typeof raw === 'string') return { status: 200, text: raw }; const status = Number(raw?.status || raw?.statusCode || 200) || 200; const value = raw?.responseText ?? raw?.body ?? raw?.data ?? raw; return { status, text: typeof value === 'string' ? value : JSON.stringify(value ?? null) }; } function requestViaPda(opts) { return Promise.resolve(env.pda(opts.url, opts.headers || {})).then(normalizePdaResponse); } function requestViaGm(opts, controller) { return new Promise((resolve, reject) => { let settled = false; let handle = null; const finish = fn => value => { if (settled) return; settled = true; fn(value); }; const onResolve = finish(resolve); const onReject = finish(reject); try { handle = env.gm({ method: opts.method, url: opts.url, headers: opts.headers || {}, data: opts.body == null ? undefined : opts.body, timeout: opts.timeout, onload: r => onResolve({ status: Number(r?.status || 200) || 200, text: String(r?.responseText ?? '') }), onerror: () => onReject(makeError('Network error', 'NETWORK')), ontimeout: () => onReject(makeError('Request timeout', 'TIMEOUT')), onabort: () => onReject(makeError('Request aborted', 'ABORTED')) }); } catch (err) { onReject(err); return; } if (controller?.signal) { const abort = () => { try { handle?.abort?.(); } catch {} onReject(makeError('Request aborted', 'ABORTED')); }; if (controller.signal.aborted) abort(); else controller.signal.addEventListener('abort', abort, { once: true }); } }); } async function requestViaFetch(opts, controller) { if (!env.fetch) throw makeError('No HTTP transport available', 'NO_TRANSPORT'); let timeoutId = null; let timeoutController = controller; if (!timeoutController && typeof AbortController === 'function') timeoutController = new AbortController(); if (opts.timeout > 0 && timeoutController) timeoutId = setTimeout(() => timeoutController.abort('timeout'), opts.timeout); try { const res = await env.fetch(opts.url, { method: opts.method, headers: opts.headers || {}, body: opts.body == null ? undefined : opts.body, credentials: opts.credentials || 'omit', cache: opts.cacheMode || 'no-store', signal: timeoutController?.signal }); return { status: Number(res?.status || 0), text: await res.text() }; } catch (err) { if (timeoutController?.signal?.aborted) { const timedOut = timeoutController.signal.reason === 'timeout'; throw makeError(timedOut ? 'Request timeout' : 'Request aborted', timedOut ? 'TIMEOUT' : 'ABORTED'); } throw makeError(err?.message || 'Network error', 'NETWORK', { cause: err }); } finally { if (timeoutId) clearTimeout(timeoutId); } } async function transport(opts, controller) { registerEnvironment(currentTransportEnvironment()); if (opts.method === 'GET' && env.pda) return requestViaPda(opts); if (env.gm) return requestViaGm(opts, controller); return requestViaFetch(opts, controller); } function retryableStatus(status) { return status === 429 || status === 408 || status >= 500; } function retryableError(err) { return ['NETWORK', 'TIMEOUT'].includes(err?.code); } function tornError(data) { const raw = data?.error; if (!raw) return null; const message = String(raw?.error ?? raw?.message ?? raw ?? 'Torn API error'); const apiCode = Number(raw?.code); const lower = message.toLowerCase(); const isRateLimit = apiCode === 5 || /too many|rate.?limit|requests per/i.test(lower); const isInvalidKey = [2, 12, 13, 16].includes(apiCode) || /invalid.*key|key.*invalid|incorrect.*key/i.test(lower); return { message, apiCode: Number.isFinite(apiCode) ? apiCode : null, isRateLimit, isInvalidKey }; } async function networkRequest(opts, startEpoch) { let attempt = 0; const retries = Math.max(0, Number(opts.retries) || 0); while (true) { if (opts.routeScoped && router.epoch() !== startEpoch) throw makeError('Stale route request', 'STALE_ROUTE'); const controller = opts.routeScoped && typeof AbortController === 'function' ? new AbortController() : null; if (controller) routeControllers.add(controller); try { stats.networkRequests++; const result = await transport(opts, controller); if (opts.routeScoped && router.epoch() !== startEpoch) throw makeError('Stale route request', 'STALE_ROUTE'); const status = Number(result?.status || 0); if (status >= 200 && status < 300) return String(result?.text ?? ''); if (status === 429) stats.rateLimited++; if (attempt < retries && retryableStatus(status)) { stats.retries++; await sleep((Number(opts.retryBase) || 400) * (2 ** attempt)); attempt++; continue; } throw makeError(`HTTP ${status || 0}`, 'HTTP', { status, retryable: retryableStatus(status) }); } catch (err) { if (err?.code === 'ABORTED' || err?.code === 'STALE_ROUTE') { stats.aborted++; throw err; } if (err?.code === 'TIMEOUT') stats.timeouts++; if (attempt < retries && retryableError(err)) { stats.retries++; await sleep((Number(opts.retryBase) || 400) * (2 ** attempt)); attempt++; continue; } throw err; } finally { if (controller) routeControllers.delete(controller); } } } function requestText(input = {}) { const opts = typeof input === 'string' ? { url: input } : { ...input }; opts.url = String(opts.url || ''); opts.method = String(opts.method || 'GET').toUpperCase(); opts.timeout = Math.max(0, Number(opts.timeout ?? 15000)); opts.retries = Math.max(0, Number(opts.retries ?? 2)); opts.retryBase = Math.max(0, Number(opts.retryBase ?? 400)); opts.parse = 'text'; if (!opts.url) return Promise.reject(makeError('Request URL is required', 'INVALID_REQUEST')); stats.requests++; const key = requestKey(opts); const cacheable = opts.method === 'GET' && opts.body == null; if (cacheable && !opts.force) { const cached = cacheRead(key); if (cached != null) { stats.cacheHits++; return Promise.resolve(cached); } } if (cacheable && inflight.has(key)) { stats.deduped++; return inflight.get(key); } const startEpoch = router.epoch(); const promise = enqueue(() => networkRequest(opts, startEpoch), opts.priority) .then(text => { if (cacheable) cacheWrite(key, text, opts.ttl); return text; }) .catch(err => { stats.failures++; throw err; }) .finally(() => { if (inflight.get(key) === promise) inflight.delete(key); }); if (cacheable) inflight.set(key, promise); return promise; } async function requestJson(urlOrOptions, options = {}) { const opts = typeof urlOrOptions === 'string' ? { ...options, url: urlOrOptions } : { ...(urlOrOptions || {}) }; const text = await requestText(opts); let data; try { data = text ? JSON.parse(text) : null; } catch (err) { throw makeError('Invalid JSON response', 'INVALID_JSON', { cause: err }); } if (opts.throwApiError) { const info = tornError(data); if (info) { if (info.isRateLimit) stats.rateLimited++; throw makeError(info.message, 'TORN_API_ERROR', info); } } return data; } function clearCache(match = null) { if (match == null) { const size = responseCache.size; responseCache.clear(); return size; } const needle = String(match); let removed = 0; for (const key of [...responseCache.keys()]) if (key.includes(needle)) { responseCache.delete(key); removed++; } return removed; } function cancelRouteScoped() { let count = 0; for (const controller of [...routeControllers]) { try { controller.abort('route-change'); count++; } catch {} } return count; } function configure(options = {}) { if (Number.isFinite(Number(options.maxConcurrent))) maxConcurrent = Math.max(1, Math.min(12, Math.floor(Number(options.maxConcurrent)))); pump(); return diagnostics(); } function diagnostics() { return Object.freeze({ ...stats, active, queued: queue.length, inflight: inflight.size, cacheEntries: responseCache.size, maxConcurrent, transports: { pda: !!env.pda, gm: !!env.gm, fetch: !!env.fetch } }); } routeAbortHook = cancelRouteScoped; registerEnvironment(currentTransportEnvironment()); return Object.freeze({ request: requestText, requestText, requestJson, clearCache, cancelRouteScoped, configure, diagnostics, registerEnvironment }); })(); const ui = { makeDraggable(element, options = {}) { if (!element || typeof window === 'undefined' || typeof element.addEventListener !== 'function') return null; if (element.dataset.slxDraggable === '1') return element._slxDragCleanup || null; const storageKey = String(options.storageKey || ('SLX_DRAG_POSITION_' + (element.id || 'BUTTON'))); const padding = Math.max(0, Number(options.padding ?? 6)); let drag = null; let suppressClick = false; let releaseClickTimer = 0; const viewport = () => ({ width: Math.max(0, Number(window.visualViewport?.width || window.innerWidth || 0)), height: Math.max(0, Number(window.visualViewport?.height || window.innerHeight || 0)) }); const place = (x, y) => { const view = viewport(); const width = Math.max(1, element.offsetWidth || 48); const height = Math.max(1, element.offsetHeight || 48); const left = Math.min(Math.max(padding, Number(x) || padding), Math.max(padding, view.width - width - padding)); const top = Math.min(Math.max(padding, Number(y) || padding), Math.max(padding, view.height - height - padding)); Object.assign(element.style, { left: left + 'px', top: top + 'px', right: 'auto', bottom: 'auto', touchAction: 'none', userSelect: 'none' }); return { x: left, y: top }; }; try { const saved = JSON.parse(localStorage.getItem(storageKey) || 'null'); if (Number.isFinite(saved?.x) && Number.isFinite(saved?.y)) place(saved.x, saved.y); } catch {} const onPointerDown = event => { if (event.button != null && event.button !== 0) return; const rect = element.getBoundingClientRect(); drag = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, offsetX: event.clientX - rect.left, offsetY: event.clientY - rect.top, moved: false }; element.setPointerCapture?.(event.pointerId); }; const onPointerMove = event => { if (!drag || event.pointerId !== drag.pointerId) return; if (!drag.moved && Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) < 5) return; drag.moved = true; event.preventDefault(); place(event.clientX - drag.offsetX, event.clientY - drag.offsetY); }; const onPointerUp = event => { if (!drag || event.pointerId !== drag.pointerId) return; element.releasePointerCapture?.(event.pointerId); if (drag.moved) { const rect = element.getBoundingClientRect(); const position = place(rect.left, rect.top); try { localStorage.setItem(storageKey, JSON.stringify(position)); } catch {} suppressClick = true; clearTimeout(releaseClickTimer); releaseClickTimer = setTimeout(() => { suppressClick = false; }, 0); } drag = null; }; const onClick = event => { if (!suppressClick) return; event.preventDefault(); event.stopImmediatePropagation(); }; const onResize = () => { if (element.style.left && element.style.top) place(parseFloat(element.style.left), parseFloat(element.style.top)); }; element.dataset.slxDraggable = '1'; element.addEventListener('pointerdown', onPointerDown); element.addEventListener('pointermove', onPointerMove); element.addEventListener('pointerup', onPointerUp); element.addEventListener('pointercancel', onPointerUp); element.addEventListener('click', onClick, true); window.addEventListener('resize', onResize); const cleanup = () => { clearTimeout(releaseClickTimer); element.removeEventListener('pointerdown', onPointerDown); element.removeEventListener('pointermove', onPointerMove); element.removeEventListener('pointerup', onPointerUp); element.removeEventListener('pointercancel', onPointerUp); element.removeEventListener('click', onClick, true); window.removeEventListener('resize', onResize); delete element.dataset.slxDraggable; delete element._slxDragCleanup; }; element._slxDragCleanup = cleanup; return cleanup; }, ensureDonationFooter(rootOrSelector, options = {}) { if (typeof document === 'undefined' || typeof document.createElement !== 'function') return null; const root = typeof rootOrSelector === 'string' ? document.querySelector(rootOrSelector) : rootOrSelector; if (!root) return null; const moduleId = String(options.id || 'module').replace(/[^a-z0-9_-]/gi, '-').toLowerCase(); const id = 'sakalux-inline-footer-' + moduleId; const existing = root.querySelector?.('#' + id) || document.getElementById(id); if (existing) { if (existing.parentElement !== root) root.appendChild(existing); return existing; } const profile = String(options.profile || 'https://www.torn.com/profiles.php?XID=2380374'); const author = String(options.author || 'SakaLuX [2380374]'); const showMoney = options.showMoney !== false; const showItems = options.showItems !== false; const moneyLabel = String(options.moneyLabel || '💸 SEND MONEY'); const itemsLabel = String(options.itemsLabel || '🎁 SEND ITEMS'); const inlineLayout = options.layout === 'inline'; if (!document.getElementById('sakalux-shared-donation-footer-style')) { const style = document.createElement('style'); style.id = 'sakalux-shared-donation-footer-style'; style.textContent = `.slx-shared-donation{display:block!important;flex:0 0 50px!important;width:100%!important;height:50px!important;min-height:50px!important;margin:0!important;padding:0!important;box-sizing:border-box!important;overflow:hidden!important;border-top:1px solid rgba(255,255,255,.08)!important;background:#080d13!important;font-family:Inter,Arial,sans-serif!important}.slx-shared-donation *{box-sizing:border-box!important}.slx-shared-donation-actions{display:grid!important;grid-template-columns:1fr 1fr!important;gap:7px!important;height:28px!important;padding:4px 10px!important}.slx-shared-donation button{display:block!important;width:100%!important;height:20px!important;min-height:20px!important;margin:0!important;padding:0 4px!important;border:1px solid #2d3d50!important;border-radius:8px!important;background:#151f2a!important;color:#c5d2df!important;font:900 8px/1.2 Inter,Arial,sans-serif!important;letter-spacing:.04em!important;white-space:nowrap!important;box-shadow:none!important}.slx-shared-donation-made{height:22px!important;display:flex!important;align-items:center!important;justify-content:center!important;gap:3px!important;padding:0 6px!important;border-top:1px solid rgba(223,154,55,.52)!important;color:#df9a37!important;font:500 9px/20px Inter,Arial,sans-serif!important;white-space:nowrap!important}.slx-shared-donation-made a{color:#78aef2!important;font-weight:900!important;text-decoration:none!important}.slx-shared-donation.slx-shared-donation-inline{display:grid!important;grid-template-columns:minmax(0,1fr) auto!important;align-items:center!important;flex:0 0 29px!important;height:29px!important;min-height:29px!important}.slx-shared-donation-inline .slx-shared-donation-actions{height:29px!important;padding:4px 6px 4px 10px!important}.slx-shared-donation-inline .slx-shared-donation-made{height:29px!important;border-top:0!important;padding:0 10px 0 6px!important}`; (document.head || document.documentElement).appendChild(style); } const footer = document.createElement('div'); footer.id = id; footer.className = 'slx-shared-donation' + (inlineLayout ? ' slx-shared-donation-inline' : ''); const actions = document.createElement('div'); actions.className = 'slx-shared-donation-actions'; const actionDefinitions = []; if (showMoney) actionDefinitions.push(['money', moneyLabel]); if (showItems) actionDefinitions.push(['items', itemsLabel]); actions.style.gridTemplateColumns = `repeat(${Math.max(1, actionDefinitions.length)}, minmax(0, 1fr))`; for (const [actionName, actionLabel] of actionDefinitions) { const button = document.createElement('button'); button.type = 'button'; button.dataset.slxDonate = actionName; button.textContent = actionLabel; actions.appendChild(button); } const made = document.createElement('div'); made.className = 'slx-shared-donation-made'; made.appendChild(document.createTextNode('Made with ❤️ by ')); const authorLink = document.createElement('a'); authorLink.href = profile; authorLink.textContent = author; made.appendChild(authorLink); footer.append(actions, made); footer.addEventListener('click', event => { const action = event.target?.closest?.('[data-slx-donate]'); const link = event.target?.closest?.('a'); if (!action && !link) return; event.preventDefault(); if (action && typeof options.onDonate === 'function') { try { options.onDonate(action.dataset.slxDonate, profile); return; } catch {} } if (typeof location !== 'undefined') location.href = profile; }); root.appendChild(footer); return footer; }, applyWorkspaceLayout(overlay, panel, options = {}) { if (!overlay || !panel || typeof window === 'undefined') return null; const top = Math.max(0, Number(options.top ?? 0)); const bottom = Math.max(0, Number(options.bottom ?? 8)); const side = Math.max(0, Number(options.side ?? 4)); const maxWidth = Math.max(240, Number(options.maxWidth ?? 760)); const radius = Math.max(0, Number(options.radius ?? 16)); if (typeof document !== 'undefined' && !document.getElementById('sakalux-shared-workspace-layout-style')) { const style = document.createElement('style'); style.id = 'sakalux-shared-workspace-layout-style'; style.textContent = `[data-slx-workspace-layout="1"],[data-slx-workspace-layout="1"] *,[data-slx-workspace-panel="1"],[data-slx-workspace-panel="1"] *{-webkit-backdrop-filter:none!important;backdrop-filter:none!important;filter:none!important}[data-slx-workspace-layout="1"]{background:transparent!important;background-image:none!important;box-shadow:none!important}`; (document.head || document.documentElement).appendChild(style); } overlay.dataset.slxWorkspaceLayout = '1'; panel.dataset.slxWorkspacePanel = '1'; const apply = () => { const vv = window.visualViewport; const width = Math.max(0, Number(vv?.width || window.innerWidth || 0)); const height = Math.max(0, Number(vv?.height || window.innerHeight || 0)); const offsetTop = Math.max(0, Number(vv?.offsetTop || 0)); const offsetLeft = Math.max(0, Number(vv?.offsetLeft || 0)); Object.assign(overlay.style, { position: 'fixed', inset: `0px 0px ${bottom}px 0px`, width: 'auto', height: 'auto', maxHeight: 'none', display: 'block', background: 'transparent', backdropFilter: 'none', WebkitBackdropFilter: 'none', boxShadow: 'none' }); const usable = Math.max(240, height - top - bottom); const panelWidth = Math.min(maxWidth, Math.max(240, width - side * 2)); Object.assign(panel.style, { position: 'fixed', top: (offsetTop + top) + 'px', bottom: 'auto', left: (offsetLeft + Math.max(side, (width - panelWidth) / 2)) + 'px', width: panelWidth + 'px', height: usable + 'px', maxHeight: usable + 'px', margin: '0', boxSizing: 'border-box', borderRadius: radius + 'px', overflow: 'hidden', boxShadow: 'none', backdropFilter: 'none', WebkitBackdropFilter: 'none' }); }; apply(); const vv = window.visualViewport; vv?.addEventListener?.('resize', apply); vv?.addEventListener?.('scroll', apply); window.addEventListener?.('resize', apply); return () => { vv?.removeEventListener?.('resize', apply); vv?.removeEventListener?.('scroll', apply); window.removeEventListener?.('resize', apply); delete overlay.dataset.slxWorkspaceLayout; delete panel.dataset.slxWorkspacePanel; }; }, ensureSharedSkin() { if (typeof document === 'undefined' || typeof document.createElement !== 'function' || document.getElementById('sakalux-shared-hub-skin')) return; const st = document.createElement('style'); st.id = 'sakalux-shared-hub-skin'; st.textContent = ` :root{--slx-bg:#0b1118;--slx-card:#111a24;--slx-card2:#172331;--slx-border:#34465b;--slx-border-soft:rgba(255,255,255,.09);--slx-text:#edf3fa;--slx-muted:#93a4b7;--slx-blue:#4f8fe8;--slx-gold:#dfbd61;--slx-green:#55d98a;--slx-red:#ff6b78;--slx-shadow:0 16px 40px rgba(0,0,0,.46)} body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) button,body [id^="slx-"] button,body [class^="sakalux-"] button,body [class*=" sakalux-"] button{border-radius:10px;box-shadow:inset 0 1px 0 rgba(255,255,255,.04);font-family:Inter,Arial,sans-serif;transition:border-color .15s ease,background .15s ease,transform .08s ease,opacity .15s ease} body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) button:active,body [id^="slx-"] button:active{transform:scale(.985)} body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) input,body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) select,body [id^="slx-"] input,body [id^="slx-"] select{border-radius:10px;border-color:#3a4d63;background:#151f2b;color:var(--slx-text);font-family:Inter,Arial,sans-serif} body [id*="sakalux"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="panel"],body [id*="sakalux"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="modal"],body [id*="slx"][id*="panel"],body [id*="slx"][id*="modal"],body #slx-stock-inline{font-family:Inter,Arial,sans-serif;color:var(--slx-text);border-color:var(--slx-border);box-shadow:var(--slx-shadow)} body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) .header,body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) .head,body [id^="slx-"] .header,body [id^="slx-"] .head{background:radial-gradient(circle at 12% -20%,rgba(79,143,232,.18),transparent 42%),linear-gradient(155deg,#18212d 0%,#101720 72%);border-color:var(--slx-border-soft)} body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) .card,body [id^="slx-"] .card{border-color:var(--slx-border-soft);background:linear-gradient(180deg,rgba(19,28,39,.98),rgba(11,17,24,.98))} @media(max-width:700px){body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) button,body [id^="slx-"] button{min-height:36px}body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) input,body [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) select,body [id^="slx-"] input,body [id^="slx-"] select{min-height:36px}} `; (document.head || document.documentElement).appendChild(st); } }; const logger = { debug(...args) { if (storage.get('SakaLuX_DEBUG', false)) console.debug('[SakaLuX]', ...args); }, warn(...args) { console.warn('[SakaLuX]', ...args); }, error(...args) { console.error('[SakaLuX]', ...args); } }; const core = Object.freeze({ version: CORE_VERSION, perf, hub, storage, settings, router, dock, api, ui, logger }); g[NS] = core; g.SakaLuXPerf = perf; settings.autoGuardCurrentScript(); routeKey = router.key(); ui.ensureSharedSkin(); })(); /* SakaLuX Shared Core — END */ /* SakaLuX Premium Badges v2 — BEGIN */ (()=>{ 'use strict'; const MATCH=new RegExp("smart target|smart score|calibrat|ffscouter|target learning|record win|record loss|advanced target|load ff|tactical",'i'); const ROOT=new RegExp("slx-elim|slx-ea|elimination",'i'); const STYLE_ID='slx-premium-badge-style'; function decorate(){ if(!document.body)return; if(!document.getElementById(STYLE_ID)){ const style=document.createElement('style');style.id=STYLE_ID; style.textContent='.slx-premium-badge{display:inline-flex!important;align-items:center!important;margin-inline-start:5px!important;padding:1px 5px!important;border:1px solid #bd9a4c!important;border-radius:5px!important;background:#372b14!important;color:#f9dc8d!important;font:800 10px/1.5 system-ui,sans-serif!important;letter-spacing:.035em!important;white-space:nowrap!important;vertical-align:middle!important;pointer-events:none!important}'; (document.head||document.documentElement).appendChild(style); } const selector='button,[role="button"],[role="tab"],label,select'; for(const el of document.querySelectorAll(selector)){ if(el.closest('#sakalux-unified-dialog,#sakalux-hub,#sakalux-script-hub,.slx-dialog-shade'))continue; let node=el, inModule=false; for(let i=0;node&&i<6;i++,node=node.parentElement){ const identity=String(node.id||'')+' '+String(typeof node.className==='string'?node.className:''); if(ROOT.test(identity)){inModule=true;break} } if(!inModule)continue; if(el.tagName==='SELECT'){ for(const option of el.options){ if(option.dataset.slxProOption==='1')continue; const title=String(option.textContent||'').trim(); if(MATCH.test(title)&&!(/(?:✦\s*)?PRO\s*$/i).test(title)){ option.textContent=title+' · ✦ PRO';option.dataset.slxProOption='1'; } } continue; } if(el.querySelector(':scope > .slx-premium-badge'))continue; const label=String(el.getAttribute('aria-label')||el.getAttribute('title')||el.textContent||'').trim(); if(!MATCH.test(label)||/^(?:OPEN PREMIUM|PRO|✦ PRO)$/i.test(label)||/(?:\bPRO\b|✦\s*PRO)/i.test(label))continue; const tag=document.createElement('span');tag.className='slx-premium-badge';tag.textContent='✦ PRO';tag.setAttribute('aria-hidden','true'); if(el.tagName==='LABEL'&&el.querySelector('button'))continue; el.append(tag); if(!el.title)el.title='SakaLuX PRO feature'; } } let timer=0; const schedule=()=>{if(timer)return;timer=setTimeout(()=>{timer=0;decorate()},180)}; const start=()=>{decorate();new MutationObserver(schedule).observe(document.body,{subtree:true,childList:true})}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',start,{once:true});else start(); })(); /* SakaLuX Premium Badges v2 — END */ /* SakaLuX Signed License Verifier — BEGIN */ /* SakaLuX signed license grant verifier — independent userscript realms. * Shared storage is a transport only, never an authorization decision. */ (function(root) { 'use strict'; const PUBLIC_KEY_B64='Hw+1h/0NZwOLEmJ+sbwgcKBIpJrgE/5kmjGnA7hnrhM='; const STORAGE_KEY='SakaLuX_SIGNED_PRO_GRANT_V1'; const decode=s=>Uint8Array.from(atob(String(s).replace(/-/g,'+').replace(/_/g,'/')+'='.repeat((4-String(s).length%4)%4)),c=>c.charCodeAt(0)); const validKey=k=>/^[A-Za-z0-9]{16}$/.test(String(k)); const hash=async k=>Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256',new TextEncoder().encode(k)))).map(n=>n.toString(16).padStart(2,'0')).join(''); async function verify(data,{apiKey,entitlement,userId,now=Date.now()}={}){ if(!validKey(apiKey)||typeof entitlement!=='string'||!entitlement||!Number.isSafeInteger(userId)||userId<=0)return false; const cert=data?.signed_certificate; if(data?.status!=='ok'||data.premium_active!==true||cert?.format!=='slx-ed25519-v1')return false; if(!Array.isArray(data.entitlements)||!data.entitlements.includes(entitlement))return false; if(!Number.isSafeInteger(Number(data.user?.id))||Number(data.user.id)<=0)return false; const keyBytes=decode(PUBLIC_KEY_B64),signature=decode(cert.signature),payload=decode(cert.payload); if(keyBytes.length!==32||signature.length!==64)return false; const publicKey=await crypto.subtle.importKey('raw',keyBytes,{name:'Ed25519'},false,['verify']); if(!await crypto.subtle.verify('Ed25519',publicKey,signature,payload))return false; const claim=JSON.parse(new TextDecoder().decode(payload)); const t=Math.floor(now/1000); if(claim.issuer!=='sakalux.ro'||claim.v!==1||claim.subject!==Number(data.user.id)||claim.subject!==userId)return false; if(!Number.isInteger(claim.iat)||!Number.isInteger(claim.exp)||claim.exp<=t||claim.iat>t+30||claim.exp>claim.iat+300)return false; if(JSON.stringify(claim.entitlements)!==JSON.stringify(data.entitlements))return false; // The signed claim expires within five minutes; other clients must independently verify it. return true; } async function store(storage,apiKey,data,userId){ if(!validKey(apiKey)||!data?.signed_certificate)return false; const entitlements=Array.isArray(data.entitlements)?data.entitlements:[]; if(!entitlements.length||!await verify(data,{apiKey,entitlement:entitlements[0],userId}))return false; storage.setItem(STORAGE_KEY,JSON.stringify({keyHash:await hash(apiKey),data})); return true; } async function load(storage,apiKey,entitlement,userId){ if(!validKey(apiKey))return null; try{ const saved=JSON.parse(storage.getItem(STORAGE_KEY)||'null'); if(saved?.keyHash!==await hash(apiKey))return null; if(!await verify(saved.data,{apiKey,entitlement,userId}))return null; const claim=JSON.parse(new TextDecoder().decode(decode(saved.data.signed_certificate.payload))); return {...saved.data,verifiedGrantExpiresAt:claim.exp*1000}; }catch{return null} } root.SakaLuXSignedGrant=Object.freeze({verify,store,load,STORAGE_KEY}); })(typeof globalThis!=='undefined'?globalThis:this); /* SakaLuX Signed License Verifier — END */ /* SakaLuX Freemium Control — BEGIN */ (()=>{ 'use strict'; const ENT='elimination_assistant_pro', MATCH=/smart target|calibrat|ffscouter|target learning|record win|record loss/i, ROOT=/slx-elim|slx-ea|elimination/i; let verifiedUntil=0,verifiedKey='',pending=null; let verificationState='checking'; const key=()=>{try{return String(globalThis.SakaLuXScriptHub?.getApiKey?.()||localStorage.getItem('SakaLuX_HUB_TORN_API_KEY')||'').trim()}catch{return ''}}; const accepts=(data,k)=>{ const expiry=Date.parse(String(data?.expires_at||'').replace(' ','T')+'Z'); return !!(data?.premium_active===true&&data?.entitlements?.includes(ENT)&&Number.isFinite(expiry)&&expiry>Date.now()&&k===key()); }; async function isPro(){ const k=key(); // Cross-world authorization requires signed certificate AND authenticated Torn identity. // Online SakaLuX verification remains the fallback if either validation fails. if(typeof GM_xmlhttpRequest==='function'&&globalThis.SakaLuXSignedGrant?.load){ try{ const grantKey=globalThis.SakaLuXSignedGrant.STORAGE_KEY; if(localStorage.getItem(grantKey)&&/^[A-Za-z0-9]{16}$/.test(k)){ const ownId=await new Promise((resolve,reject)=>GM_xmlhttpRequest({ method:'GET',url:'https://api.torn.com/v2/user/basic?key='+encodeURIComponent(k), timeout:10000, onload:r=>{try{ const d=JSON.parse(r.responseText||'{}'),id=Number(d.id); if(r.status!==200||d.error||!Number.isSafeInteger(id)||id<=0)throw Error('identity_invalid'); resolve(id); }catch(e){reject(e)}}, onerror:()=>reject(Error('identity_network')),ontimeout:()=>reject(Error('identity_timeout')) })); if(k===key()){ const grant=await globalThis.SakaLuXSignedGrant.load(localStorage,k,ENT,ownId); if(grant&&k===key()){ verifiedKey=k; verifiedUntil=Math.min(grant.verifiedGrantExpiresAt,Date.now()+300000,Date.parse(String(grant.expires_at||'').replace(' ','T').replace(/Z$/i,'')+'Z')); verificationState='pro'; return true; } } } }catch{} // Never grant PRO if cache or Torn identity verification is unavailable. } if(!/^[A-Za-z0-9]{16}$/.test(k)){verificationState='unavailable';return false;} if(k===verifiedKey&&verifiedUntil>Date.now()){verificationState='pro';return true;} const hub=globalThis.__SakaLuXPremiumVerified; if(hub?.key===k&&Date.now()-hub.at<300000&&accepts(hub.data,k)){verifiedKey=k;verifiedUntil=Math.min(Date.now()+300000,Date.parse(String(hub.data.expires_at).replace(' ','T')+'Z'));verificationState='pro';return true} // Prefer the Hub's shared broker: one in-flight request for all modules. // A server outage is unknown, never proof that the account is FREE. const broker=globalThis.SakaLuXLicenseBroker; if(broker?.check){ try{ const d=await broker.check(k); const ok=d?.status==='ok'&&accepts(d,k); if(ok){verifiedKey=k;verifiedUntil=Math.min(Date.now()+300000,Date.parse(String(d.expires_at).replace(' ','T')+'Z'));} else {verifiedKey='';verifiedUntil=0;} verificationState=ok?'pro':(d?.status==='ok'?'free':'unavailable'); return ok; }catch{verificationState='unavailable';return false;} } if(pending)return pending; if(typeof GM_xmlhttpRequest!=='function'){verificationState='unavailable';return false;} pending=new Promise(resolve=>{ GM_xmlhttpRequest({method:'POST',url:'https://sakalux.ro/api/hub-premium-check.php',headers:{'Content-Type':'application/json','Accept':'application/json'},data:JSON.stringify({api_key:k}),timeout:12000, onload:r=>{try{const d=JSON.parse(r.responseText||'{}');const ok=r.status===200&&d.status==='ok'&&accepts(d,k);verificationState=r.status===200&&d.status==='ok'?(ok?'pro':'free'):'unavailable';if(ok){verifiedKey=k;verifiedUntil=Math.min(Date.now()+300000,Date.parse(String(d.expires_at).replace(' ','T')+'Z'))}resolve(ok)}catch{verificationState='unavailable';resolve(false)}}, onerror:()=>{verificationState='unavailable';resolve(false)},ontimeout:()=>{verificationState='unavailable';resolve(false)} }) });try{return await pending}finally{pending=null} } function locked(){ if(verificationState==='unavailable'||verificationState==='checking'){ globalThis.SakaLuXDialog?.notice?.('PRO verification temporarily unavailable. Please retry shortly.','warning'); return; } if(globalThis.SakaLuXDialog?.show)globalThis.SakaLuXDialog.show({title:'SakaLuX PRO',type:'pro',message:'This advanced feature requires active SakaLuX PRO. Basic features remain FREE. Send 1 Xanax for 7 days PRO.',actions:[{label:'CLOSE'},{label:'OPEN PREMIUM',primary:true,onClick:()=>location.assign('https://sakalux.ro/premium.html')}]}); else globalThis.SakaLuXDialog?.notice?.('This feature requires SakaLuX PRO.','pro'); } window.addEventListener('SakaLuX:PremiumStatus',event=>{ const data=event.detail||{}; const expiry=Date.parse(String(data.expires_at||'').replace(' ','T')+'Z'); const active=data.premium_active===true&&Array.isArray(data.entitlements)&&data.entitlements.includes(ENT)&&Number.isFinite(expiry)&&expiry>Date.now(); verifiedKey=active?key():''; verifiedUntil=active?Math.min(Date.now()+5*60*1000,expiry):0; verificationState=active?'pro':(data.verification_state==='unavailable'?'unavailable':'free'); }); globalThis.SakaLuXFreemium=globalThis.SakaLuXFreemium||{}; globalThis.SakaLuXFreemium['elimination-assistant']={isPro,locked,isActive:()=>verifiedKey===key()&&verifiedUntil>Date.now()};void isPro(); const bypass=new WeakSet(); document.addEventListener('click',async e=>{ const button=e.target?.closest?.('button,[role="button"],a');if(!button||bypass.has(button))return; const owner=button.closest?.('[id],[class]');const scope=(button.closest?.('[id*="slx"],[id*="sakalux"],[id*="qp"],[id*="mission"],[class*="slx"],[class*="sakalux"]')?.id||button.closest?.('[id*="slx"],[id*="sakalux"],[id*="qp"],[id*="mission"]')?.className||''); if(!ROOT.test(String(scope))&&!ROOT.test(String(owner?.id||'')))return; const label=String(button.textContent||button.title||button.getAttribute('aria-label')||'').trim(); if(!MATCH.test(label))return; e.preventDefault();e.stopImmediatePropagation(); if(await isPro()){bypass.add(button);try{button.click()}finally{bypass.delete(button)}}else locked(); },true); })(); /* SakaLuX Freemium Control — END */ /* SakaLuX Unified Dialogs v1.0 — BEGIN */ (() => { 'use strict'; if (globalThis.SakaLuXDialog?.version === '1.0') return; const STYLE='sakalux-unified-dialog-style'; const esc=v=>String(v??''); function ensure(){ if(!document.getElementById(STYLE)){ const style=document.createElement('style');style.id=STYLE; style.textContent=`.slx-dialog-shade{position:fixed!important;inset:0!important;z-index:2147483647!important;background:rgba(2,8,19,.78)!important;backdrop-filter:blur(5px)!important;display:flex!important;align-items:center!important;justify-content:center!important;padding:18px!important;box-sizing:border-box!important}.slx-dialog-panel{box-sizing:border-box!important;width:min(100%,420px)!important;max-height:90dvh!important;overflow:auto!important;background:linear-gradient(155deg,#172638,#0b1421)!important;border:1px solid #405874!important;border-radius:20px!important;color:#edf4ff!important;box-shadow:0 24px 65px #000a!important;font:14px/1.55 system-ui,Arial,sans-serif!important}.slx-dialog-head{display:flex!important;align-items:center!important;gap:12px!important;padding:20px 20px 6px!important}.slx-dialog-icon{display:grid!important;place-items:center!important;flex:none!important;width:43px!important;height:43px!important;background:#26394e!important;color:#e8c577!important;border:1px solid #56617a!important;border-radius:13px!important;font-size:21px!important}.slx-dialog-title{font-size:20px!important;font-weight:800!important;line-height:1.2!important}.slx-dialog-tag{font-size:10px!important;font-weight:800!important;letter-spacing:.1em!important;color:#e9c779!important}.slx-dialog-x{margin-left:auto!important;border:0!important;border-radius:10px!important;background:#233348!important;color:#fff!important;padding:7px 12px!important;font-size:16px!important}.slx-dialog-message{white-space:pre-wrap!important;overflow-wrap:anywhere!important;color:#d8e5f7!important;padding:14px 20px 4px!important;font-size:15px!important}.slx-dialog-actions{display:flex!important;gap:10px!important;padding:18px 20px 20px!important}.slx-dialog-btn{min-height:43px!important;flex:1!important;border:1px solid #536a84!important;border-radius:12px!important;color:white!important;background:#26394e!important;font-weight:800!important}.slx-dialog-btn.primary{background:linear-gradient(#3d93e9,#2769b5)!important;border-color:#60a6ef!important}`; (document.head||document.documentElement).appendChild(style); } } function show({title='SakaLuX',message='',type='info',actions}={}){ ensure();const old=document.getElementById('sakalux-unified-dialog');old?.remove(); const shade=document.createElement('div');shade.id='sakalux-unified-dialog';shade.className='slx-dialog-shade'; const panel=document.createElement('section');panel.className='slx-dialog-panel';panel.setAttribute('role','dialog');panel.setAttribute('aria-modal','true'); const head=document.createElement('div');head.className='slx-dialog-head'; const icon=document.createElement('div');icon.className='slx-dialog-icon';icon.textContent=type==='error'?'!':type==='success'?'✓':type==='pro'?'✦':type==='update'?'↻':'i'; const group=document.createElement('div'),heading=document.createElement('div'),tag=document.createElement('div'); heading.className='slx-dialog-title';heading.textContent=title;tag.className='slx-dialog-tag';tag.textContent=type.toUpperCase();group.append(heading,tag); const x=document.createElement('button');x.type='button';x.className='slx-dialog-x';x.textContent='×';x.setAttribute('aria-label','Close');x.onclick=()=>shade.remove();head.append(icon,group,x); const body=document.createElement('div');body.className='slx-dialog-message';body.textContent=esc(message); const foot=document.createElement('div');foot.className='slx-dialog-actions'; for(const action of actions||[{label:'CLOSE',primary:true}]){const b=document.createElement('button');b.type='button';b.className='slx-dialog-btn'+(action.primary?' primary':'');b.textContent=action.label||'OK';b.onclick=()=>{shade.remove();action.onClick?.()};foot.append(b)} if(type==='pro'){const link=document.createElement('a');link.href='https://www.torn.com/profiles.php?XID=2380374';link.target='_blank';link.rel='noopener noreferrer';link.textContent='Send 1 Xanax for 7 days PRO → SakaLuX [2380374] ↗';link.style.cssText='display:block;margin:10px 20px;color:#e9c779;font-weight:700;text-decoration:underline';panel.append(head,body,link,foot)}else panel.append(head,body,foot);shade.append(panel);(document.body||document.documentElement).append(shade); shade.addEventListener('click',e=>{if(e.target===shade)shade.remove()});return shade; } function notice(message,type){const m=esc(message);return show({title:/error|failed|unavailable/i.test(m)?'Action failed':/pro|premium|license/i.test(m)?'SakaLuX PRO':'SakaLuX',message:m,type:type||(/error|failed|unavailable/i.test(m)?'error':/pro|premium|license/i.test(m)?'pro':'info')})} function confirmAsync(message){return new Promise(resolve=>show({title:'Please confirm',message,type:'info',actions:[{label:'CANCEL',onClick:()=>resolve(false)},{label:'CONFIRM',primary:true,onClick:()=>resolve(true)}]}))} globalThis.SakaLuXDialog={version:'1.0',show,notice,confirmAsync}; })(); /* SakaLuX Unified Dialogs v1.0 — END */ /* SakaLuX Canonical Installed Version — BEGIN */ (() => { 'use strict'; const v = '1.3.66'; // This script's own @version; global GM_info can belong to another TornPDA userscript. const g = globalThis; g.__SakaLuXInstalledVersions = g.__SakaLuXInstalledVersions || Object.create(null); g.__SakaLuXInstalledVersions['elimination-assistant'] = v; try { document.documentElement?.setAttribute('data-sakalux-installed-elimination-assistant', v); } catch {} })(); /* SakaLuX Canonical Installed Version — END */ /* SakaLuX Shared Dock Runtime — BEGIN */ /* SakaLuX Shared Dock Runtime v1 - Priority 6 foundation * Source-only module. Not installed directly by users. * Intended to be embedded with Shared Core into standalone userscripts. */ (() => { 'use strict'; const g = globalThis; const NS = 'SakaLuXDockRuntime'; const VERSION = '1.1.10'; const HUB_URL = 'https://update.greasyfork.org/scripts/592699/SakaLuX%20Script%20Hub.user.js'; const OPEN_KEY = 'SakaLuX_STANDALONE_DOCK_OPEN'; const PROMPT_KEY = 'SakaLuX_HUB_INSTALL_PROMPT_LAST'; const PROMPT_INTERVAL = 12 * 60 * 60 * 1000; const IDS = Object.freeze({ dock: 'sakalux-standalone-dock', prompt: 'sakalux-hub-install-prompt', native: 'sakalux-standalone-native-s', fallback: 'sakalux-standalone-fallback-s', style: 'sakalux-standalone-dock-runtime-style' }); function versionParts(v){return String(v||'0').match(/\d+/g)?.map(Number)||[0]} function compareVersion(a,b){const x=versionParts(a),y=versionParts(b);for(let i=0;i0?1:-1}return 0} const currentRuntime=g.__SakaLuXDockRuntimeCurrent||g[NS]; if(currentRuntime?.version&&compareVersion(currentRuntime.version,VERSION)>=0)return; try { currentRuntime?.removeUi?.(); } catch {} const modules = g.__SakaLuXDockRuntimeModules instanceof Map ? g.__SakaLuXDockRuntimeModules : new Map(); g.__SakaLuXDockRuntimeModules = modules; let observer = null; let observerQueued = false; let runtimeSignalsBound = false; let promptScheduled = false; function core() { return g.SakaLuXCore || null; } function doc() { return typeof document === 'undefined' ? null : document; } function hubInstalled() { return Boolean(core()?.hub?.installed?.()); } let openState = false; let autoCloseTimer = 0; let userOpened = false; function readOpen() { return false; } function writeOpen(value) { openState = Boolean(value); try { localStorage.removeItem(OPEN_KEY); } catch {} } function forceCloseDock() { userOpened = false; openState = false; clearTimeout(autoCloseTimer); const p = doc()?.getElementById(IDS.dock); if (p) { p.dataset.open = '0'; p.hidden = true; } try { localStorage.removeItem(OPEN_KEY); } catch {} return false; } function armAutoClose() { clearTimeout(autoCloseTimer); if (!openState) return; autoCloseTimer = setTimeout(() => forceCloseDock(), 6000); } function normalize(entry = {}) { const id = String(entry.id || '').trim(); if (!id) throw new Error('Dock module id is required'); return Object.freeze({ id, name: String(entry.name || id), icon: String(entry.icon || '🧩'), version: String(entry.version || ''), open: typeof entry.open === 'function' ? entry.open : null, enabled: typeof entry.enabled === 'function' ? entry.enabled : () => true }); } function sorted() { const values = [...modules.values()]; const sorter = core()?.dock?.sort; return typeof sorter === 'function' ? sorter.call(core().dock, values) : values; } function removeNode(id) { try { doc()?.getElementById(id)?.remove(); } catch {} } function removeUi() { removeNode(IDS.dock); removeNode(IDS.prompt); removeNode(IDS.native); removeNode(IDS.fallback); } function addStyle() { const d = doc(); if (!d || d.getElementById(IDS.style)) return; const style = d.createElement('style'); style.id = IDS.style; style.textContent = ` #${IDS.dock}{position:fixed;right:10px;bottom:calc(92px + env(safe-area-inset-bottom,0px));z-index:2147483000;width:min(220px,calc(100vw - 20px));max-height:calc(100dvh - 190px);overflow:hidden;padding:10px;background:linear-gradient(180deg,rgba(10,14,20,.992),rgba(7,10,15,.992));border:1px solid rgba(255,255,255,.09);border-radius:18px;box-shadow:0 16px 40px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.04);font-family:Inter,Arial,sans-serif;display:none;flex-direction:column;box-sizing:border-box} #${IDS.dock}[data-open="1"]{display:flex} #${IDS.dock} .slx-dock-head{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:4px;padding:4px 6px 10px;margin-bottom:7px;border-bottom:1px solid rgba(255,255,255,.055)} #${IDS.dock} .slx-dock-mark{width:30px;height:30px;display:grid;place-items:center;padding:0;margin:0;border-radius:10px;background:linear-gradient(180deg,#293545,#1a2430);border:1px solid rgba(223,189,97,.38);color:#dfbd61;font:900 16px/30px Arial,sans-serif;box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 4px 10px rgba(0,0,0,.2);cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent} #${IDS.dock} .slx-dock-title{color:#f4f7fb;font-size:11px;font-weight:900;line-height:1.15;letter-spacing:.01em;text-align:center} #${IDS.dock} .slx-dock-items{overflow:auto;min-height:0} #${IDS.dock} .sl-dock-row{display:flex;align-items:center;gap:8px;width:100%;min-height:34px;margin:0 0 6px;padding:7px 9px;border:1px solid rgba(255,255,255,.09);border-radius:9px;background:#111b26;color:#eaf0f6;text-align:left;font:700 11px/1.2 Arial,sans-serif} #${IDS.dock} .sl-dock-row:last-child{margin-bottom:0}#${IDS.dock} .sl-dock-row[disabled]{opacity:.45} #${IDS.dock} .slx-dock-install{display:block;margin-top:8px;padding-top:7px;border-top:1px solid rgba(255,255,255,.08);color:#d8a45c;text-align:center;text-decoration:none;font-size:10px;font-weight:800} #${IDS.fallback}{position:fixed;right:10px;bottom:calc(44px + env(safe-area-inset-bottom,0px));z-index:2147482900;width:38px;height:38px;border:1px solid rgba(255,255,255,.18);border-radius:10px;background:#0b1118;color:#e9a84d;font:800 15px/1 Arial,sans-serif;box-shadow:0 8px 24px rgba(0,0,0,.35)} #${IDS.native}{all:unset!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;align-self:center!important;vertical-align:middle!important;box-sizing:border-box!important;flex:0 0 24px!important;width:24px!important;min-width:24px!important;max-width:24px!important;height:24px!important;min-height:24px!important;max-height:24px!important;margin:0 3px 0 0!important;padding:0!important;border:0!important;border-radius:0!important;list-style:none!important;background:transparent!important;background-image:none!important;box-shadow:none!important;filter:none!important;transform:none!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;overflow:visible!important}#${IDS.native}::before,#${IDS.native}::after,#${IDS.native} .slx-s-link::before,#${IDS.native} .slx-s-link::after{content:none!important;display:none!important;background:none!important;background-image:none!important}#${IDS.native} .slx-s-link{all:unset!important;display:flex!important;align-items:center!important;justify-content:center!important;box-sizing:border-box!important;width:24px!important;height:24px!important;min-width:24px!important;min-height:24px!important;margin:0!important;padding:0!important;border:0!important;border-radius:0!important;background:transparent!important;background-image:none!important;box-shadow:none!important;filter:none!important;transform:translateY(2px)!important;color:#dfbd61!important;font:900 17px/24px Arial,sans-serif!important;line-height:24px!important;text-align:center!important;text-decoration:none!important;text-shadow:0 1px 1px rgba(0,0,0,.75),0 0 4px rgba(223,189,97,.2)!important;cursor:pointer!important;touch-action:manipulation!important;-webkit-tap-highlight-color:transparent!important}#${IDS.native} .slx-s-link:active{transform:translateY(2px) scale(.92)!important} #${IDS.prompt}{position:fixed;left:50%;bottom:calc(18px + env(safe-area-inset-bottom,0px));transform:translateX(-50%);z-index:2147483600;width:min(360px,calc(100vw - 20px));padding:10px;border:1px solid rgba(255,255,255,.12);border-radius:12px;background:#0b1118;color:#eef3f8;font:600 11px/1.35 Arial,sans-serif;box-shadow:0 16px 42px rgba(0,0,0,.45)} #${IDS.prompt} .slx-prompt-actions{display:flex;gap:7px;margin-top:8px}#${IDS.prompt} button{flex:1;min-height:30px;border:1px solid rgba(255,255,255,.12);border-radius:8px;background:#17212d;color:#eef3f8;font-weight:800} `; (d.head || d.documentElement).appendChild(style); } function findStatusIconList() { const d=doc(); if(!d)return null; const selectors=['ul[class*="statusIcons"][class*="big"]','ul[class*="status-icons"][class*="big"]','ul[class*="statusIcons"]','ul[class*="status-icons"]']; const lists=selectors.flatMap(q=>[...d.querySelectorAll(q)]); return lists.find(list=>list.isConnected&&[...list.children].some(item=>item.querySelector?.('a')))||null; } function ensureLauncher(){ const d=doc(); if(!d||hubInstalled()){removeNode(IDS.native);removeNode(IDS.fallback);return null;} const list=findStatusIconList(); let item=d.getElementById(IDS.native); if(!list){item?.remove();return null;} if(!item){ item=d.createElement('li'); item.id=IDS.native; } item.className='slx-standalone-native'; item.removeAttribute?.('style'); let link=item.querySelector('a.slx-s-link'); if(!link){ item.replaceChildren(); link=d.createElement('a'); link.href='#';link.className='slx-s-link';link.textContent='S'; link.title='SakaLuX Scripts';link.setAttribute('aria-label','SakaLuX Scripts'); item.appendChild(link); }else{ link.textContent='S';link.href='#';link.className='slx-s-link'; } link.onclick=e=>{ e.preventDefault();e.stopPropagation();e.stopImmediatePropagation?.(); const p=d.getElementById(IDS.dock); const open=p?.dataset.open==='1'&&!p.hidden; if(open)forceCloseDock();else{userOpened=true;toggleDock(true);} }; const first=[...list.children].find(x=>x!==item)||null; if(first){ if(list.firstElementChild!==item) list.insertBefore(item,first); }else if(item.parentElement!==list){ list.appendChild(item); } removeNode(IDS.fallback); return item; } function ensureDock() { const d = doc(); if (!d || hubInstalled()) { removeUi(); return null; } let panel = d.getElementById(IDS.dock); if (!panel) { panel = d.createElement('div'); panel.id = IDS.dock; panel.dataset.open = '0'; panel.hidden = true; writeOpen(false); const head = d.createElement('div'); head.className = 'slx-dock-head'; const close = d.createElement('button'); close.type = 'button'; close.className = 'slx-dock-mark'; close.textContent = 'S'; close.title = 'Close SakaLuX Scripts'; close.addEventListener?.('click', e => { e?.preventDefault?.(); e?.stopPropagation?.(); forceCloseDock(); }); const title = d.createElement('div'); title.className = 'slx-dock-title'; title.textContent = 'SakaLuX Scripts'; const sub = d.createElement('div'); sub.className = 'slx-dock-sub'; sub.textContent = 'Standalone'; head.appendChild(close); head.appendChild(title); head.appendChild(sub); const items = d.createElement('div'); items.className = 'slx-dock-items'; const install = d.createElement('a'); install.className = 'slx-dock-install'; install.href = HUB_URL; install.textContent = 'Install SakaLuX Hub'; panel.appendChild(head); panel.appendChild(items); panel.appendChild(install); (d.body || d.documentElement).appendChild(panel); } return panel; } function toggleDock(force) { if (hubInstalled()) { removeUi(); return false; } render(); const panel = doc()?.getElementById(IDS.dock); if (!panel) return false; const next = typeof force === 'boolean' ? force : panel.dataset.open !== '1'; if (next) { userOpened = true; openState = true; panel.dataset.open = '1'; panel.hidden = false; writeOpen(true); armAutoClose(); } else forceCloseDock(); return next; } function render() { const d = doc(); if (!d) return null; if (hubInstalled()) { try { d.documentElement?.setAttribute('data-sakalux-hub-active', '1'); } catch {} try { d.body?.setAttribute('data-sakalux-hub-active', '1'); } catch {} removeUi(); return null; } try { d.body?.removeAttribute('data-sakalux-hub-active'); } catch {} addStyle(); ensureLauncher(); const panel = ensureDock(); if (!panel) return null; const box = typeof panel.querySelector === 'function' ? panel.querySelector('.slx-dock-items') : panel.children?.[1]; if (!box) return panel; box.replaceChildren?.(); for (const entry of sorted()) { const button = d.createElement('button'); button.type = 'button'; button.className = 'sl-dock-row'; button.dataset.moduleId = entry.id; button.textContent = `${entry.icon} ${entry.name}`; let enabled = true; try { enabled = entry.enabled() !== false; } catch { enabled = false; } button.disabled = !enabled || !entry.open; button.addEventListener?.('click', () => { try { entry.open?.(); } finally { toggleDock(false); } }); box.appendChild(button); } if(!userOpened) forceCloseDock(); else panel.hidden = panel.dataset.open !== '1'; return panel; } function maybePrompt() { const d = doc(); if (!d || hubInstalled() || !d.body) return false; let last = 0; try { last = Number(localStorage.getItem(PROMPT_KEY) || 0); } catch {} if (Date.now() - last < PROMPT_INTERVAL || d.getElementById(IDS.prompt)) return false; try { localStorage.setItem(PROMPT_KEY, String(Date.now())); } catch {} const prompt = d.createElement('div'); prompt.id = IDS.prompt; const text = d.createElement('div'); text.textContent = 'Install SakaLuX Script Hub for one control center, health checks and module management.'; const actions = d.createElement('div'); actions.className = 'slx-prompt-actions'; const later = d.createElement('button'); later.type = 'button'; later.textContent = 'LATER'; later.addEventListener?.('click', () => prompt.remove()); const install = d.createElement('button'); install.type = 'button'; install.textContent = 'INSTALL HUB'; install.addEventListener?.('click', () => { location.href = HUB_URL; }); actions.appendChild(later); actions.appendChild(install); prompt.appendChild(text); prompt.appendChild(actions); d.body.appendChild(prompt); return true; } function scheduleRefresh(delay = 180) { if (observerQueued) return; observerQueued = true; const run = () => { observerQueued = false; render(); }; const perf = core()?.perf; if (typeof perf?.debounce === 'function') perf.debounce('shared-dock-runtime', run, delay); else setTimeout(run, delay); } function bindRuntimeSignals() { if (runtimeSignalsBound) return; runtimeSignalsBound = true; try { core()?.router?.onChange?.(() => { forceCloseDock(); scheduleRefresh(180); }); core()?.router?.bind?.(); } catch {} try { g.addEventListener?.('SakaLuX:ScriptHubReady', () => removeUi(), { passive: true }); } catch {} try { const outside = e => { const panel = doc()?.getElementById(IDS.dock); if (!panel || panel.dataset.open !== '1' || panel.hidden) return; const t=e?.target; if (t?.closest?.('#'+IDS.dock) || t?.closest?.('#'+IDS.native) || t?.closest?.('#'+IDS.fallback)) return; forceCloseDock(); }; for (const ev of ['pointerdown','touchstart','mousedown','click']) doc()?.addEventListener?.(ev,outside,true); } catch {} try { g.addEventListener?.('keydown', e => { if(e?.key==='Escape') forceCloseDock(); }, {passive:true}); } catch {} try { if (!observer && typeof MutationObserver === 'function' && doc()?.body) { observer = new MutationObserver(records => { if (core()?.perf?.unrelated?.(records)) return; scheduleRefresh(240); }); observer.observe(doc().body, { childList:true, subtree:true }); } } catch {} } function register(entry) { const normalized = normalize(entry); modules.set(normalized.id, normalized); // latest registration wins render(); bindRuntimeSignals(); if (!promptScheduled) { promptScheduled = true; Promise.resolve().then(() => maybePrompt()); } return normalized; } function unregister(id) { const removed = modules.delete(String(id || '')); render(); return removed; } function list() { return Object.freeze(sorted().map(item => Object.freeze({ ...item }))); } const api = Object.freeze({ version: VERSION, ids: IDS, register, unregister, list, render, toggleDock, removeUi, hubInstalled, maybePrompt }); g.__SakaLuXDockRuntimeCurrent = api; try { const desc=Object.getOwnPropertyDescriptor(g,NS); if(!desc||desc.configurable){ Object.defineProperty(g,NS,{configurable:true,enumerable:true,get(){return g.__SakaLuXDockRuntimeCurrent},set(v){if(v?.version&&compareVersion(v.version,g.__SakaLuXDockRuntimeCurrent?.version)>=0)g.__SakaLuXDockRuntimeCurrent=v}}); } else g[NS]=api; } catch { try { g[NS]=api; } catch {} } })(); /* SakaLuX Shared Dock Runtime — END */ /* SakaLuX Shared Dock Registration — BEGIN */ (() => { 'use strict'; const SELF = Object.freeze(Object.assign({"id":"elimination-assistant","name":"Elimination","icon":"⚔️","selector":"","fallback":"https://www.torn.com/page.php?sid=elimination"}, { version: "1.3.66" })); const API_GLOBAL = "SakaLuXEliminationAssistant"; function openSelf() { if (SELF.id === 'bazaar-smart-pricer' && location.pathname !== '/bazaar.php') { location.href = SELF.fallback || 'https://www.torn.com/bazaar.php'; return; } try { const api = API_GLOBAL ? window[API_GLOBAL] : null; if (api && typeof api.open === 'function') { api.open(); return; } } catch {} const el = SELF.selector ? document.querySelector(SELF.selector) : null; if (el) { el.click(); return; } const bridge = document.getElementById('sakalux-module-bridge-' + SELF.id); if (bridge) { bridge.dataset.action = 'open'; bridge.click(); return; } if (SELF.fallback) location.href = SELF.fallback; } function register() { const dock = globalThis.SakaLuXDockRuntime; if (!dock || typeof dock.register !== 'function') throw new Error('SakaLuX Shared Dock Runtime is unavailable'); dock.register({ ...SELF, open: openSelf }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', register, { once: true }); else register(); })(); /* SakaLuX Shared Dock Registration — END */ (() => { const id='sakalux-standalone-layer-style'; if(!document.getElementById(id)){ const style=document.createElement('style'); style.id=id; style.textContent=`/* Keep managed add-on panels above the shared standalone dock. */ :where( [id^="sl-eg-"][id*="panel" i], [id^="sakalux-bt-"][id*="settings" i], [id^="sl-mr-"][id*="panel" i], [id^="sl-mri-"][id*="panel" i], [id^="sl-mi-"][id*="panel" i], #slx-elim, [id^="slx-elim-"][id*="panel" i] ){z-index:2147483646!important;} #sakalux-standalone-dock{z-index:2147483500!important;}`; (document.head||document.documentElement).appendChild(style); } })(); /* * Copyright © 2026 SakaLuX [2380374] * All Rights Reserved. * * Personal use and private modification are permitted. * Redistribution, republication, rebranding, or publication of * modified versions requires prior written permission from * SakaLuX [2380374]. * * Original author attribution must be retained in all authorized * derivative works. */ (() => { 'use strict'; const VERSION = '1.3.66'; const HUB_INSTALL_URL='https://update.greasyfork.org/scripts/592699/SakaLuX%20Script%20Hub.user.js'; const HUB_PROMPT_STORAGE='SakaLuX_HUB_INSTALL_PROMPT_LAST'; const HUB_PROMPT_ID='sakalux-hub-install-prompt'; const HUB_PROMPT_INTERVAL=43200000; const TORN_KEY_CREATE_URL='https://www.torn.com/preferences.php#tab=api?step=addNewKey&title=SakaLuX_Elimination_Assistant&user=battlestats&torn=elimination,eliminationteam'; const IDS={panel:'slx-elim',style:'slx-elim-style'}; const K={torn:'slx_elim_torn_key',ff:'slx_elim_ff_key',team:'slx_elim_team',teams:'slx_elim_teams_v1',enabled:'slx_elim_enabled',hist:'slx_elim_history_v4',learn:'slx_elim_learning_v1',cache:'slx_elim_ff_cache_v2',my:'slx_elim_my_stats_v1',batches:'slx_elim_batches_v1',safe:'slx_elim_safe_targets_v1',ui:'slx_elim_ui_v1'}; const load=(k,f)=>{try{return JSON.parse(localStorage.getItem(k)||'null')??f}catch{return f}}; const save=(k,v)=>{try{localStorage.setItem(k,JSON.stringify(v))}catch{}}; const $=(q,r=document)=>r.querySelector(q), $$=(q,r=document)=>[...r.querySelectorAll(q)]; const esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const state={enabled:localStorage.getItem(K.enabled)!=='0',tornKey:localStorage.getItem(K.torn)||'',ffKey:localStorage.getItem(K.ff)||'',teamId:Number(localStorage.getItem(K.team)||0),teams:load(K.teams,[]),players:[],view:[],history:load(K.hist,[]),learning:load(K.learn,{}),cache:load(K.cache,{}),my:load(K.my,{total:null,at:0,source:''}),batchOffsets:load(K.batches,{}),safeTargets:load(K.safe,[]),ui:Object.assign({filters:[],query:'',panelOpen:false},load(K.ui,{})),batchRawCount:0,busy:false,keyBusy:false,lastRefresh:0,tornKeySource:'None',tornAccessStatus:'unknown',tornAccessMessage:'Not checked yet',tornAccessCheckedAt:0,ffAccessStatus:'unknown',ffAccessMessage:'Optional · not checked'}; function getTornKey(){try{const k=window.SakaLuXScriptHub?.getApiKey?.()||'';if(k){state.tornKeySource='SakaLuX Hub';return k}if(window.SakaLuXScriptHub||document.getElementById('sakalux-hub-button')){const stored=localStorage.getItem('SakaLuX_HUB_TORN_API_KEY')||'';if(stored){state.tornKeySource='SakaLuX Hub';return stored}}}catch{}if(state.tornKey){state.tornKeySource='Local standalone';return state.tornKey}state.tornKeySource='None';return''} const fmtBS=n=>{n=Number(n||0);if(!n)return'—';if(n>=1e12)return(n/1e12).toFixed(2)+'T';if(n>=1e9)return(n/1e9).toFixed(2)+'B';if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return(n/1e3).toFixed(1)+'K';return String(Math.round(n))}; const age=ts=>{if(!ts)return'—';const s=Math.max(0,Math.floor(Date.now()/1000)-Number(ts));return s<60?s+'s':s<3600?Math.floor(s/60)+'m':s<86400?Math.floor(s/3600)+'h':Math.floor(s/86400)+'d'}; function requestJSON(url){ const decode=raw=>{ let v=raw; if(v&&typeof v==='object'){ if(v.responseText!==undefined)v=v.responseText; else if(v.body!==undefined)v=v.body; else if(v.data!==undefined)v=v.data; else if(v.response!==undefined)v=v.response; else return v; } if(typeof v!=='string')v=String(v??''); v=v.trim(); if(!v)throw new Error('Empty API response'); try{return JSON.parse(v)}catch(e){ const a=v.indexOf('{'),b=v.lastIndexOf('}'); if(a>=0&&b>a){try{return JSON.parse(v.slice(a,b+1))}catch(_){}} throw new Error('Invalid API response: '+e.message); } }; const checked=raw=>{const j=decode(raw);if(j?.error){const e=new Error(j.error.error||j.error.message||'API error');e.code=Number(j.error.code||0);throw e}return j}; const viaGM=()=>new Promise((resolve,reject)=>{ if(typeof GM_xmlhttpRequest!=='function'){reject(new Error('GM request unavailable'));return} GM_xmlhttpRequest({method:'GET',url,timeout:15000,onload:r=>{try{if(r.status<200||r.status>=400)throw new Error('HTTP '+r.status);resolve(checked(r))}catch(e){reject(e)}},onerror:()=>reject(new Error('Network error')),ontimeout:()=>reject(new Error('Timeout'))}); }); const viaFetch=()=>fetch(url,{headers:{Accept:'application/json'}}).then(async r=>{if(!r.ok)throw new Error('HTTP '+r.status);return checked(await r.text())}); return (async()=>{ let last=null; if(typeof window.PDA_httpGet==='function')try{return checked(await window.PDA_httpGet(url,{Accept:'application/json'}))}catch(e){last=e} if(window.flutter_inappwebview?.callHandler)try{return checked(await window.flutter_inappwebview.callHandler('PDA_httpGet',url,{Accept:'application/json'}))}catch(e){last=e} if(typeof GM_xmlhttpRequest==='function')try{return await viaGM()}catch(e){last=e} try{return await viaFetch()}catch(e){last=e} throw last||new Error('API request failed'); })(); } function torn(path,params={},keyOverride=''){const key=String(keyOverride||getTornKey()||'').trim();if(!key)return Promise.reject(new Error('Set Torn API key in API Access or SakaLuX Hub'));const u=new URL('https://api.torn.com/v2/'+path.replace(/^\/+/,''));u.searchParams.set('key',key);u.searchParams.set('striptags','true');Object.entries(params).forEach(([k,v])=>u.searchParams.set(k,String(v)));return requestJSON(u.href)} function ffReq(ids,keyOverride=''){const key=String(keyOverride||state.ffKey||'').trim();if(!key)return Promise.reject(new Error('Set FFScouter API key in API Access'));const u=new URL('https://ffscouter.com/api/v1/get-stats');u.searchParams.set('key',key);u.searchParams.set('targets',ids.join(','));return requestJSON(u.href)} function normTeams(raw){const root=raw?.elimination??raw?.eliminations??raw?.teams??raw?.data??raw;const nested=root?.teams??root?.elimination_teams??root?.participants??root;const a=Array.isArray(nested)?nested:(nested&&typeof nested==='object'?Object.entries(nested).map(([id,x])=>x&&typeof x==='object'?{id:Number(x.id??x.team_id??id),...x}:{id:Number(id),name:String(x||'')}):[]);return a.map((t,i)=>({id:Number(t.id??t.team_id??t.teamId??i),name:t.name??t.team_name??t.teamName??('Team '+(t.id??t.team_id??i)),score:Number(t.score??t.points??0)})).filter(x=>Number.isFinite(x.id)&&x.id>0)} function normPlayers(raw){const r=raw?.eliminationteam||raw?.players||raw?.members||raw?.data||raw;const a=Array.isArray(r)?r:(r&&typeof r==='object'?(Array.isArray(r.players)?r.players:Array.isArray(r.members)?r.members:Object.entries(r).map(([id,x])=>({id:Number(id),...(x||{})}))):[]);return a.map((p,i)=>{const st=p.status&&typeof p.status==='object'?p.status:{};const tr=p.travel&&typeof p.travel==='object'?p.travel:{};return{id:Number(p.id??p.user_id??p.player_id??i),name:p.name??p.player_name??p.username??('Player '+i),level:Number(p.level??0),score:Number(p.score??p.points??p.contribution??0),last:Number(p.last_action?.timestamp??p.last_action_timestamp??0),statusState:String(st.state??p.status_state??(typeof p.status==='string'?p.status:'')),statusDescription:String(st.description??p.status_description??''),statusDetails:String(st.details??p.status_details??''),travelStatus:String(tr.status??tr.state??p.travel_status??''),destination:String(tr.destination??tr.country??p.destination??p.country??''),ff:null,bs:null}}).filter(p=>p.id>0)} function normFF(raw){const a=Array.isArray(raw)?raw:Array.isArray(raw?.players)?raw.players:Array.isArray(raw?.data)?raw.data:[];return a.map(x=>({id:Number(x.player_id??x.id??0),ff:Number(x.fair_fight??x.ff??0)||null,bs:Number(x.bs_estimate??x.battle_stats??x.bss??0)||null})).filter(x=>x.id>0)} function presence(p){const raw=[p.statusState,p.statusDescription,p.statusDetails,p.travelStatus,p.destination].filter(Boolean).join(' ').trim();if(/hospital/i.test(raw))return{key:'hospital',icon:'🏥',label:'Hospital',detail:raw};if(/jail/i.test(raw))return{key:'jail',icon:'🔒',label:'Jail',detail:raw};if(/federal/i.test(raw))return{key:'federal',icon:'⛔',label:'Federal',detail:raw};if(/fallen/i.test(raw))return{key:'fallen',icon:'💀',label:'Fallen',detail:raw};if(/dormant/i.test(raw))return{key:'dormant',icon:'💤',label:'Dormant',detail:raw};if(/awoken/i.test(raw))return{key:'awoken',icon:'👁️',label:'Awoken',detail:raw};if(/travel(?:ing|ling)|flying|returning/i.test(raw))return{key:'flying',icon:'✈️',label:'Flying',detail:raw};if(/abroad|south africa|switzerland|united kingdom|cayman|canada|china|hawaii|japan|mexico|uae|argentina/i.test(raw))return{key:'abroad',icon:'🌍',label:'Abroad',detail:raw};if(/okay|torn|online|offline|idle/i.test(raw))return{key:'torn',icon:'🟢',label:'Torn',detail:raw};return{key:'unknown',icon:'⚪',label:'Unknown',detail:raw||'No location status returned'}} function attackable(p){return presence(p).key==='torn'} function unavailable(p){return/^(hospital|jail|federal|fallen|dormant|awoken|flying|abroad)$/.test(presence(p).key)} function learn(id){const x=state.learning[String(id)]||{};return{wins:Number(x.wins||0),losses:Number(x.losses||0)}} function risk(p){let n=50;const l=learn(p.id);const edge=state.my.total&&p.bs?state.my.total/Math.max(1,p.bs):null;if(edge!==null){if(edge>=5)n-=38;else if(edge>=2)n-=27;else if(edge>=1.25)n-=14;else if(edge<.8)n+=34;else n+=8}else if(p.ff){if(p.ff>=5)n-=34;else if(p.ff>=3)n-=25;else if(p.ff>=1.5)n-=7;else n+=27}else{if(p.level&&p.level<=10)n-=22;else if(p.level<=25)n-=13;else if(p.level<=50)n+=4;else if(p.level<=75)n+=15;else if(p.level>75)n+=26}if(p.last){const h=(Date.now()/1000-p.last)/3600;if(h>=168)n-=16;else if(h>=24)n-=10;else if(h<4)n+=8}if(l.wins+l.losses){const wr=l.wins/(l.wins+l.losses);if(l.wins+l.losses>=2&&wr>=.75)n-=14;else if(l.wins+l.losses>=2&&wr<=.4)n+=22}if(unavailable(p))n=100;n=Math.max(0,Math.min(100,Math.round(n)));return{score:n,label:n<=34?'SAFE':n<=64?'RISKY':'SKIP',edge}} function smart(p){if(!globalThis.SakaLuXFreemium['elimination-assistant'].isActive())return 0;const r=risk(p);let s=100-r.score;if(p.ff)s+=Math.max(-8,Math.min(16,(p.ff-1)*4));if(r.edge!==null)s+=Math.max(-18,Math.min(20,Math.log2(Math.max(.1,r.edge))*8));if(unavailable(p))s=0;return Math.max(0,Math.min(100,Math.round(s)))} function signal(p){if(!globalThis.SakaLuXFreemium['elimination-assistant'].isActive())return 'Advanced target analysis · PRO';const r=risk(p);const top=`${p.ff?'FF '+p.ff.toFixed(2):'FF —'} · ${p.bs?'BS '+fmtBS(p.bs):'BS —'}`;const bottom=`${r.edge!==null?r.edge.toFixed(1)+'× · ':''}${r.label} · ${smart(p)}/100`;return top+'\n'+bottom} function syncHubPower(){ for(const b of $$('[data-script="elimination-assistant"][data-action="toggle"]')){ const txt=state.enabled?'⏻ ON':'⏻ OFF'; if(b.textContent!==txt)b.textContent=txt; b.style.setProperty('display','inline-block','important'); b.style.setProperty('background',state.enabled?'#166534':'#991b1b','important'); b.style.setProperty('border-color',state.enabled?'#22c55e':'#ef4444','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('font-weight','900','important'); const actions=b.closest('.slh-actions'); if(actions){ for(const x of $$('.slh-action',actions)){ if(x===b)x.style.setProperty('display','inline-block','important'); else if(state.enabled)x.style.removeProperty('display'); else x.style.setProperty('display','none','important'); } } } } function isHubInstalled(){return!!(window.SakaLuXScriptHub||$('#sakalux-hub-button'))} function showHubPrompt(){if(!state.enabled||isHubInstalled()||$('#'+HUB_PROMPT_ID))return;const last=Number(localStorage.getItem(HUB_PROMPT_STORAGE)||0);if(last&&Date.now()-lastInstall SakaLuX Script Hub?
';document.body.appendChild(d);$('#slx-later',d).onclick=()=>{localStorage.setItem(HUB_PROMPT_STORAGE,String(Date.now()));d.remove()};$('#slx-install',d).onclick=()=>{localStorage.setItem(HUB_PROMPT_STORAGE,String(Date.now()));location.href=HUB_INSTALL_URL}} function css(){if($('#'+IDS.style))return;const s=document.createElement('style');s.id=IDS.style;s.textContent=`#${IDS.panel}{display:none;position:fixed;right:6px;bottom:125px;z-index:999998;width:min(920px,calc(100vw - 12px));height:80vh;background:#0d1117;color:#f8fafc;border:1px solid #3c4652;border-radius:14px;overflow:hidden;font:14px Arial,sans-serif}#${IDS.panel}.open{display:flex;flex-direction:column}.slx-h,.slx-t,.slx-s{display:flex;gap:8px;align-items:center;padding:10px;border-bottom:1px solid #2d3742;flex-wrap:wrap}.slx-h{background:#111821}.slx-h b{font-size:16px;color:#f8fafc}.slx-h b,.slx-s span{flex:1}.slx-s{background:#121a23;font-size:14px;line-height:1.35}.slx-s span{color:#e5e7eb}.slx-s b{color:#facc15}.slx-t input,.slx-t select,.slx-t button,.slx-a,.slx-h button{background:#18212c;color:#f8fafc;border:1px solid #475569;border-radius:8px;padding:9px 10px;font-size:14px}.slx-t button{font-weight:800}.slx-t input{min-width:180px;flex:1}.slx-body{overflow:auto;flex:1;background:#0d1117}.slx-body table{width:100%;border-collapse:collapse;table-layout:auto}.slx-body td,.slx-body th{padding:9px 8px;border-bottom:1px solid #26313c;text-align:left;vertical-align:top;font-size:14px;line-height:1.35}.slx-body th{position:sticky;top:0;background:#121a23;color:#f1f5f9;z-index:2}.slx-body td:first-child{min-width:190px}.slx-body td:nth-child(2){min-width:130px}.slx-a{display:inline-block;text-decoration:none;margin:2px}.safe{color:#4ade80!important;font-weight:900}.risky{color:#fbbf24!important;font-weight:900}.skip{color:#fb7185!important;font-weight:900}.slx-presence{display:block;margin-top:3px;font-size:11px;font-weight:900;white-space:nowrap}.slx-presence.torn{color:#4ade80}.slx-presence.flying{color:#7dd3fc}.slx-presence.abroad{color:#c4b5fd}.slx-presence.hospital,.slx-presence.jail,.slx-presence.federal,.slx-presence.fallen{color:#fda4af}.slx-presence.unknown{color:#94a3b8}.slx-wait{display:inline-block;color:#94a3b8;font-size:10px;font-weight:900;padding:3px}.slx-modal{display:none;position:absolute;inset:0;z-index:20;background:#0c1015f5;padding:16px;overflow:auto;font-size:14px}.slx-modal.open{display:block}.slx-modal input{width:100%;padding:10px;margin:4px 0 10px;background:#11161c;color:#fff;border:1px solid #475569;border-radius:8px;font-size:14px}@media(max-width:640px){#${IDS.panel}{right:4px;width:calc(100vw - 8px);height:82vh;font-size:14px}.slx-h,.slx-t,.slx-s{padding:9px}.slx-t input,.slx-t select,.slx-t button{min-height:42px;font-size:14px}.slx-body td,.slx-body th{font-size:13px;padding:8px 6px}.slx-body td:first-child{min-width:170px}.slx-a{padding:8px 9px}}`;document.head.appendChild(s)} function safeCss(){if($('#slx-elim-safe-style'))return;const x=document.createElement('style');x.id='slx-elim-safe-style';x.textContent=`#slx-safe-open{border-color:#237a4b!important;background:#123523!important;color:#86efac!important;white-space:nowrap!important}#slx-safe-count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;margin-left:3px;padding:0 4px;border-radius:999px;background:#22c55e;color:#07150d;font-size:9px;font-weight:900}.slx-safe-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.slx-safe-head h3{margin:0;color:#86efac}.slx-safe-note{margin:8px 0;color:#a7b2c0;font-size:11px;line-height:1.45}.slx-safe-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin:12px 0}.slx-safe-actions button{min-height:40px;margin:0!important;font-weight:900}.slx-safe-list{border:1px solid #2d3742;border-radius:10px;overflow:hidden}.slx-safe-empty{padding:18px;color:#94a3b8;text-align:center}.slx-safe-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;padding:9px;border-bottom:1px solid #26313c;background:#111821}.slx-safe-row:last-child{border-bottom:0}.slx-safe-player{min-width:0}.slx-safe-player a{color:#86efac;text-decoration:none;font-weight:900}.slx-safe-player small{display:block;margin-top:3px;color:#94a3b8}.slx-safe-remove{min-width:34px!important;margin:0!important;color:#fda4af!important}.slx-safe-danger{grid-column:1/3;background:#54232f!important;border-color:#864354!important;color:#ffd7df!important}`;(document.head||document.documentElement).appendChild(x)} let safeUiObserver=null; function installSafeTargetsUi(){const p=$('#'+IDS.panel);if(!p||$('#slx-safe-open',p))return;safeCss();const header=$('.slx-h',p);if(!header)return;const openButton=document.createElement('button');openButton.id='slx-safe-open';openButton.type='button';openButton.innerHTML='SAFE 0';const settings=$('#slx-set',header);header.insertBefore(openButton,settings||header.lastElementChild);const modal=document.createElement('div');modal.className='slx-modal';modal.id='slx-safe-list-modal';modal.innerHTML='

Remembered SAFE Targets

Every target detected as SAFE and currently in Torn is saved automatically across LOAD NEXT batches and future sessions.
';p.appendChild(modal);openButton.onclick=openSafeTargets;$('#slx-safe-close',modal).onclick=()=>modal.classList.remove('open');$('#slx-safe-copy',modal).onclick=()=>busy(copyAllSafe);$('#slx-safe-export',modal).onclick=()=>busy(exportSafeTargets);$('#slx-safe-clear',modal).onclick=clearSafeTargets;renderSafeTargets()} function watchSafeTargetsUi(){if(safeUiObserver)return;safeCss();installSafeTargetsUi();safeUiObserver=new MutationObserver(installSafeTargetsUi);safeUiObserver.observe(document.body,{childList:true})} function apiCss(){if($('#slx-elim-api-style'))return;const x=document.createElement('style');x.id='slx-elim-api-style';x.textContent=`.slx-key-button{border-color:#7c681e!important;background:#2a2512!important;color:#f5d85f!important}.slx-api-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.slx-api-head h3{margin:0;color:#fff;font-size:17px}.slx-api-sub{margin-top:3px;color:#8e96a3;font-size:10px}.slx-api-required{padding:10px;border:1px solid #66591d;border-radius:9px;background:#211d10;color:#e4c95d;font-size:11px;line-height:1.5}.slx-api-create{display:block!important;width:100%;box-sizing:border-box;margin:9px 0!important;text-align:center;background:#2a2512!important;color:#f5d85f!important;border-color:#7c681e!important;font-weight:900}.slx-api-box{margin:9px 0;padding:9px;border:1px solid #2f3945;border-radius:9px;background:#121820}.slx-api-status{display:flex;justify-content:space-between;gap:8px;padding:8px;border-radius:7px;background:#181d24;font-size:10px;line-height:1.35}.slx-api-status b{color:#d7b94c}.slx-api-status.ok span{color:#78d98b}.slx-api-status.error span,.slx-api-status.missing span,.slx-api-status.missing-permission span{color:#f08b8b}.slx-api-source,.slx-api-note{margin:8px 0;color:#9ca3af;font-size:9px;line-height:1.45}.slx-api-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}.slx-api-actions button,.slx-api-clear{min-height:36px;border:0;border-radius:8px;background:#374151;color:#fff;font-weight:900;font-size:10px}.slx-api-actions button:first-child{background:#2563eb}.slx-api-clear{width:100%;margin-top:7px}.slx-ff-box{border-color:#43385a;background:#171321}.slx-ff-title{color:#c4b5fd;font-size:12px;font-weight:900;margin-bottom:4px}.slx-manual-box{margin-top:9px;padding-top:9px;border-top:1px solid #2f3945}.slx-manual-save{width:100%}`;document.head.appendChild(x)} function syncApiButton(){apiCss();const b=$('#slx-set');if(!b)return;b.textContent='🔑';b.title='API Access';b.setAttribute('aria-label','API Access');b.classList.add('slx-key-button');const status=$('#slx-status');if(status&&status.textContent.includes('Settings'))status.textContent=status.textContent.replace('Settings','API Access')} function compactCss(){if($('#slx-elim-compact-style'))return;const x=document.createElement('style');x.id='slx-elim-compact-style';x.textContent=`#${IDS.panel}{right:4px!important;bottom:72px!important;width:min(920px,calc(100vw - 8px))!important;height:88vh!important;max-height:calc(100vh - 88px)!important;font-size:13px!important}.slx-h{padding:6px 8px!important;gap:6px!important}.slx-h b{font-size:14px!important}.slx-t{padding:5px 7px!important;gap:5px!important;flex-wrap:nowrap!important}.slx-top #slx-team{flex:1!important;min-width:0!important}.slx-search{align-items:center!important;flex-wrap:nowrap!important;position:relative!important}.slx-target-wrap{position:relative!important;flex:0 0 auto!important}.slx-search #slx-targets-btn{min-width:118px!important;min-height:34px!important;display:flex!important;align-items:center!important;justify-content:center!important;gap:5px!important;font-weight:900!important}.slx-search #slx-targets-count{display:none!important;min-width:17px!important;height:17px!important;align-items:center!important;justify-content:center!important;border-radius:999px!important;background:#2563eb!important;color:#fff!important;font-size:9px!important}.slx-search #slx-targets-count.on{display:inline-flex!important}.slx-targets-menu{display:none!important;position:absolute!important;left:0!important;top:calc(100% + 6px)!important;z-index:50!important;width:184px!important;padding:8px!important;border:1px solid #334155!important;border-radius:12px!important;background:linear-gradient(160deg,#17202b,#10161e)!important;box-shadow:0 14px 30px rgba(0,0,0,.48)!important}.slx-targets-menu.open{display:block!important}.slx-targets-title{padding:2px 3px 7px!important;color:#8fa0b5!important;font-size:9px!important;font-weight:900!important;letter-spacing:.35px!important;text-transform:uppercase!important}.slx-target-option{display:flex!important;align-items:center!important;justify-content:space-between!important;gap:10px!important;min-height:35px!important;margin:3px 0!important;padding:7px 9px!important;box-sizing:border-box!important;border:1px solid #263545!important;border-radius:9px!important;background:#121a23!important;color:#d6dee8!important;font-size:10px!important;font-weight:850!important;cursor:pointer!important;transition:background .16s ease,border-color .16s ease!important}.slx-target-option:hover{background:#151f2a!important}.slx-target-option span{order:1!important;flex:1!important;white-space:nowrap!important;letter-spacing:.1px!important}.slx-target-option input{order:2!important;appearance:none!important;-webkit-appearance:none!important;position:relative!important;width:40px!important;height:22px!important;min-width:40px!important;max-width:40px!important;min-height:22px!important;max-height:22px!important;margin:0!important;padding:0!important;border:1px solid #46576b!important;border-radius:999px!important;background:#25303d!important;box-shadow:inset 0 1px 2px rgba(0,0,0,.35)!important;outline:none!important;transition:background .18s ease,border-color .18s ease!important;cursor:pointer!important}.slx-target-option input:before{content:''!important;position:absolute!important;top:2px!important;left:2px!important;width:16px!important;height:16px!important;border-radius:50%!important;background:#b9c4d0!important;box-shadow:0 1px 2px rgba(0,0,0,.45)!important;transition:transform .18s ease,background .18s ease!important}.slx-target-option input:checked{background:#2563eb!important;border-color:#3b82f6!important}.slx-target-option input:checked:before{transform:translateX(18px)!important;background:#fff!important}.slx-target-option:has(input:checked){border-color:#334a62!important;background:#14202c!important;color:#eef4fb!important}.slx-target-option.safe-opt:has(input:checked){border-color:#315b43!important;color:#93e6ad!important}.slx-target-option.safe-opt input:checked{background:#198754!important;border-color:#2aa66a!important}.slx-target-option.risky-opt:has(input:checked){border-color:#625225!important;color:#f1d56b!important}.slx-target-option.risky-opt input:checked{background:#8a6f16!important;border-color:#b69428!important}.slx-targets-menu #slx-targets-clear{width:100%!important;margin-top:7px!important;min-height:30px!important;border:1px solid #344357!important;border-radius:8px!important;background:#1a2430!important;color:#aeb9c7!important;font-size:9px!important;font-weight:900!important}.slx-search #slx-q{flex:1 1 auto!important;min-width:0!important}.slx-t input,.slx-t select,.slx-t button{min-height:34px!important;padding:6px 7px!important;font-size:12px!important}.slx-s{padding:4px 7px!important;gap:5px!important;flex-wrap:nowrap!important;min-height:32px!important}.slx-s span{min-width:0!important;white-space:nowrap!important;overflow:hidden!important;text-overflow:ellipsis!important;font-size:11px!important}.slx-s b{font-size:11px!important;white-space:nowrap!important;color:#facc15!important}.slx-cal-mini{background:#2a220b!important;color:#fde68a!important;border:1px solid #7c5f11!important;border-radius:7px!important;padding:4px 6px!important;min-height:26px!important;font-size:10px!important;font-weight:900!important;white-space:nowrap!important}.slx-body table{table-layout:fixed!important}.slx-body col.signal{width:32%}.slx-body col.player{width:28%}.slx-body col.lvl{width:7%}.slx-body col.last{width:9%}.slx-body col.actions{width:24%}.slx-body th,.slx-body td{font-size:11px!important;padding:5px 3px!important;line-height:1.12!important;vertical-align:middle!important;overflow:hidden!important}.slx-body td:first-child{min-width:0!important;white-space:pre-line!important}.slx-body td:nth-child(2){min-width:0!important;white-space:nowrap!important;text-overflow:ellipsis!important}.slx-body td:nth-child(2) small{display:block;font-size:8px;color:#94a3b8}.slx-body td:nth-child(2) .slx-presence{font-size:9px!important;overflow:hidden;text-overflow:ellipsis}.slx-body td:nth-child(3),.slx-body td:nth-child(4){text-align:center;white-space:nowrap}.slx-body td:nth-child(3){color:#fde047!important;font-weight:900!important;text-shadow:0 1px 1px #000}.slx-body td:nth-child(4){color:#bae6fd!important;font-weight:900!important;text-shadow:0 1px 1px #000}.slx-player{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slx-actions{white-space:nowrap!important;text-align:right!important}.slx-action-grid{display:grid!important;grid-template-columns:minmax(34px,1fr) 24px!important;grid-template-rows:repeat(2,22px)!important;gap:2px!important;align-items:stretch!important}.slx-action-grid>.atk,.slx-action-grid>.slx-wait{grid-column:1!important;grid-row:1/3!important;align-self:center!important}.slx-action-grid>.win{grid-column:2!important;grid-row:1!important}.slx-action-grid>.loss{grid-column:2!important;grid-row:2!important}.slx-action-grid>.win,.slx-action-grid>.loss{min-height:22px!important;min-width:24px!important;padding:1px 3px!important;margin:0!important}.slx-actions .slx-a{display:inline-flex!important;align-items:center!important;justify-content:center!important;font-size:9px!important;padding:3px 4px!important;min-height:24px!important;min-width:22px!important;margin:1px!important}.slx-actions .atk{min-width:34px!important;font-weight:900!important}.slx-actions .win{color:#86efac!important}.slx-actions .loss{color:#fda4af!important}.safe{color:#4ade80!important}.risky{color:#fbbf24!important}.skip{color:#fb7185!important}@media(max-width:640px){#${IDS.panel}{height:90vh!important;max-height:calc(100vh - 72px)!important}}`;document.head.appendChild(x)} function removeTouchingGrassWidget(){ const panel=$('#'+IDS.panel);if(!panel)return false; const leaves=[...panel.querySelectorAll('*')].filter(el=>/touching\s+grass\s+targets/i.test((el.textContent||'').trim())); for(const leaf of leaves){ let node=leaf; for(let depth=0;node&&node!==panel&&depth<7;depth++,node=node.parentElement){ const txt=(node.textContent||'').replace(/\s+/g,' ').trim(); if(/touching\s+grass\s+targets/i.test(txt)&&/target\s*list/i.test(txt)&&/show\s*all/i.test(txt)&&/apply/i.test(txt)){ node.remove(); return true; } } } return false; } function guardAgainstForeignTargetWidgets(){ const panel=$('#'+IDS.panel);if(!panel)return; removeTouchingGrassWidget(); if(panel.__slxForeignWidgetObserver)return; const observer=new MutationObserver(()=>removeTouchingGrassWidget()); observer.observe(panel,{childList:true,subtree:true}); panel.__slxForeignWidgetObserver=observer; setTimeout(removeTouchingGrassWidget,100); setTimeout(removeTouchingGrassWidget,800); } function inject(){if(!state.enabled||$('#'+IDS.panel))return;css();compactCss();const p=document.createElement('div');p.id=IDS.panel;p.innerHTML=`
SakaLuX Elimination Assistant v${VERSION}
${getTornKey()?'API key ready.':'Set a Torn API key in Settings or Hub.'}
SignalPlayer / StatusLvlLastActions

Settings

${window.SakaLuXScriptHub?.getApiKey?.()?'Using the shared SakaLuX Hub Torn API key. ':''}TEST TORN KEY checks battlestats and Eliminations separately. API 32 on eliminationteam means that Torn is not currently exposing that event endpoint; it is not treated as a bad API key.

`;document.body.append(p);guardAgainstForeignTargetWidgets();$('#slx-close',p).onclick=()=>p.classList.remove('open');$('#slx-set',p).onclick=openSettings;$('#slx-cancel',p).onclick=()=>$('#slx-settings',p).classList.remove('open');$('#slx-save',p).onclick=saveSettings;$('#slx-create',p).onclick=createKey;$('#slx-test',p).onclick=()=>busy(testKey);$('#slx-load',p).onclick=()=>busy(loadNextTeamBatch);$('#slx-ff',p).onclick=()=>busy(()=>loadFF(true));$('#slx-export',p).onclick=()=>busy(exportTargets);$('#slx-cal',p).onclick=()=>busy(()=>calibrate(true));$('#slx-q',p).oninput=apply;$$('#slx-targets-menu input[data-filter]',p).forEach(x=>x.onchange=apply);$('#slx-targets-btn',p).onclick=e=>{e.stopPropagation();$('#slx-targets-menu',p).classList.toggle('open')};$('#slx-targets-menu',p).onclick=e=>e.stopPropagation();$('#slx-targets-clear',p).onclick=()=>{$$('#slx-targets-menu input[data-filter]',p).forEach(x=>x.checked=false);apply()};p.__slxDocumentClick=()=>$('#slx-targets-menu',p)?.classList.remove('open');document.addEventListener('click',p.__slxDocumentClick);$('#slx-team',p).onchange=e=>{state.teamId=Number(e.target.value||0);localStorage.setItem(K.team,String(state.teamId||''));state.players=[];state.view=[];state.batchRawCount=0;render();setStatus('Team selected · press LOAD NEXT')};if(getTornKey())busy(refresh)} function removeUI(){const panel=$('#'+IDS.panel);panel?.__slxForeignWidgetObserver?.disconnect();if(panel?.__slxDocumentClick)document.removeEventListener('click',panel.__slxDocumentClick);panel?.remove();$('#'+HUB_PROMPT_ID)?.remove()} function setEnabled(v){state.enabled=!!v;localStorage.setItem(K.enabled,state.enabled?'1':'0');state.enabled?inject():removeUI();syncApiButton();syncHubPower();setTimeout(syncHubPower,180);window.dispatchEvent(new CustomEvent('SakaLuXEliminationAssistantStateChanged',{detail:{enabled:state.enabled,version:VERSION}}));syncHubBridge('elimination-assistant',state.enabled);return state.enabled} function toggleEnabled(){return setEnabled(!state.enabled)} function syncHubBridge(id,value){const bridge=document.getElementById('sakalux-module-bridge-'+id);if(bridge)bridge.dataset.enabled=String(Boolean(value))} function installHubBridge(id,openHandler){let bridge=document.getElementById('sakalux-module-bridge-'+id);if(!bridge){bridge=document.createElement('button');bridge.type='button';bridge.id='sakalux-module-bridge-'+id;bridge.hidden=true;(document.body||document.documentElement).appendChild(bridge)}bridge.dataset.version=VERSION;bridge.dataset.enabled=String(Boolean(state.enabled));bridge.onclick=()=>{const action=bridge.dataset.action;if(action==='open')openHandler();else if(action==='toggle')toggleEnabled();else if(action==='on'||action==='off')setEnabled(action==='on');bridge.dataset.action='';syncHubBridge(id,state.enabled)}} function setStatus(t){const e=$('#slx-status');if(e)e.textContent=t} function createKey(){if(state.keyBusy)return false;state.keyBusy=true;setTimeout(()=>state.keyBusy=false,2500);state.tornAccessStatus='setup';state.tornAccessMessage='Create the named key in Torn, then return and paste it below.';try{sessionStorage.setItem('SakaLuX_ELIM_KEY_SETUP_PENDING','1')}catch{}location.href=TORN_KEY_CREATE_URL;return true} function apiSetupPending(){try{return sessionStorage.getItem('SakaLuX_ELIM_KEY_SETUP_PENDING')==='1'}catch{return false}} function updateAccessPanel(){ const m=$('#slx-settings');if(!m)return;getTornKey(); const ts=$('#slx-torn-status',m),fs=$('#slx-ff-status',m),source=$('#slx-torn-source',m); if(ts){ts.className='slx-api-status '+state.tornAccessStatus;$('span',ts).textContent=state.tornAccessMessage} if(fs){fs.className='slx-api-status '+state.ffAccessStatus;$('span',fs).textContent=state.ffAccessMessage} if(source)source.innerHTML='Active source: '+esc(state.tornKeySource)+''; } function openSettings(){ apiCss();syncApiButton();const m=$('#slx-settings');if(!m)return false;getTornKey(); m.innerHTML=`

🔑 Elimination API Access

SakaLuX Elimination Assistant v${VERSION}
Exact Torn permissions required
User: Battlestats
Torn: Elimination + Elimination Team
No write permission is requested.
TORN API ACCESS${esc(state.tornAccessMessage)}
Active source: ${esc(state.tornKeySource)}
The Hub general key is used first when available. The local key remains the standalone fallback.
📊 FFSCOUTER — OPTIONAL, SEPARATE SERVICE
FFSCOUTER ACCESS${esc(state.ffAccessMessage)}
FFScouter supplies optional Fair Fight and estimated battle-stat data. It is not part of Torn API and is never stored in the Hub key.
`; m.classList.add('open'); $('#slx-cancel',m).onclick=()=>m.classList.remove('open'); $('#slx-create',m).onclick=createKey; $('#slx-save-torn',m).onclick=async()=>{const key=$('#slx-torn',m).value.trim();if(!key){$('#slx-torn',m).focus();return}state.tornKey=key;localStorage.setItem(K.torn,key);try{sessionStorage.removeItem('SakaLuX_ELIM_KEY_SETUP_PENDING')}catch{}const b=$('#slx-save-torn',m);b.textContent='CHECKING…';const ok=await testKey(key);b.textContent=ok?'TORN KEY OK ✓':'SAVED · CHECK FAILED';updateAccessPanel();if(ok)busy(refresh)}; $('#slx-test',m).onclick=async()=>{const b=$('#slx-test',m);b.textContent='CHECKING…';const ok=await testKey($('#slx-torn',m).value.trim());b.textContent=ok?'ACCESS OK ✓':'CHECK FAILED';updateAccessPanel()}; $('#slx-clear-torn',m).onclick=()=>{state.tornKey='';localStorage.removeItem(K.torn);const remaining=getTornKey();state.tornAccessStatus=remaining?'unknown':'missing';state.tornAccessMessage=remaining?'Local key cleared · Hub key remains active':'No Torn API key configured';$('#slx-torn',m).value='';updateAccessPanel()}; $('#slx-save-ff',m).onclick=async()=>{const key=$('#slx-ffkey',m).value.trim();if(!key){$('#slx-ffkey',m).focus();return}state.ffKey=key;localStorage.setItem(K.ff,key);const b=$('#slx-save-ff',m);b.textContent='CHECKING…';const ok=await testFFKey(key);b.textContent=ok?'FF KEY OK ✓':'SAVED · CHECK FAILED';updateAccessPanel()}; $('#slx-open-ff',m).onclick=()=>window.open('https://ffscouter.com/','_blank','noopener'); $('#slx-clear-ff',m).onclick=()=>{state.ffKey='';localStorage.removeItem(K.ff);state.ffAccessStatus='missing';state.ffAccessMessage='No FFScouter key configured';$('#slx-ffkey',m).value='';updateAccessPanel()}; $('#slx-save-manual',m).onclick=()=>{const n=Number($('#slx-manual',m).value||0);if(n>0){state.my={total:n,at:Date.now(),source:'manual'};save(K.my,state.my);apply();$('#slx-save-manual',m).textContent='SAVED ✓'}}; return true; } function saveSettings(){const m=$('#slx-settings');const newTorn=$('#slx-torn',m).value.trim(),newFF=$('#slx-ffkey',m).value.trim();if(newTorn)state.tornKey=newTorn;if(newFF)state.ffKey=newFF;const n=Number($('#slx-manual',m).value||0);if(n>0){state.my={total:n,at:Date.now(),source:'manual'};save(K.my,state.my)}if(state.tornKey)localStorage.setItem(K.torn,state.tornKey);if(state.ffKey)localStorage.setItem(K.ff,state.ffKey);m.classList.remove('open');busy(refresh)} async function testKey(keyOverride=''){ const typed=String(keyOverride||$('#slx-torn')?.value||'').trim(); if(typed){state.tornKey=typed;localStorage.setItem(K.torn,typed)} const key=typed||getTornKey(); if(!key){state.tornAccessStatus='missing';state.tornAccessMessage='No Torn API key configured';updateAccessPanel();return false} const out=[];let failed=false,testTeam=state.teamId; try{await torn('user/battlestats',{},key);out.push('battlestats: OK')}catch(e){out.push('battlestats: FAIL'+(e.code?' API '+e.code:''));failed=true} try{const elimination=await torn('torn/elimination',{},key);out.push('elimination: OK');if(!testTeam)testTeam=normTeams(elimination)[0]?.id||0} catch(e){if(Number(e.code)===32)out.push('elimination: UNAVAILABLE API 32');else{out.push('elimination: FAIL'+(e.code?' API '+e.code:''));failed=true}} if(testTeam){ try{await torn(`torn/${testTeam}/eliminationteam`,{limit:1,offset:0},key);out.push('eliminationteam: OK')} catch(e){if(Number(e.code)===32)out.push('eliminationteam: UNAVAILABLE API 32');else{out.push('eliminationteam: FAIL'+(e.code?' API '+e.code:''));failed=true}} }else out.push('eliminationteam: no active team available'); state.tornAccessStatus=failed?'missing-permission':'ok'; state.tornAccessMessage=failed?'TORN KEY MISSING REQUIRED ACCESS':out.join(' · '); state.tornAccessCheckedAt=Date.now();setStatus(out.join(' | '));updateAccessPanel();return!failed; } async function testFFKey(keyOverride=''){ const key=String(keyOverride||state.ffKey||'').trim(); if(!key){state.ffAccessStatus='missing';state.ffAccessMessage='No FFScouter key configured';updateAccessPanel();return false} try{const target=state.players[0]?.id||2380374;await ffReq([target],key);state.ffAccessStatus='ok';state.ffAccessMessage='FFScouter access OK';updateAccessPanel();return true} catch(e){state.ffAccessStatus='error';state.ffAccessMessage=String(e?.message||e||'FFScouter request failed');updateAccessPanel();return false} } async function calibrate(force=false){ if(!(await globalThis.SakaLuXFreemium['elimination-assistant'].isPro())){globalThis.SakaLuXFreemium['elimination-assistant'].locked();return state.my.total||0;}if(state.my.source==='manual'&&!force)return state.my.total;if(!force&&state.my.total&&Date.now()-Number(state.my.at||0)<900000)return state.my.total;const raw=await torn('user/battlestats');const x=raw?.battlestats??raw?.data?.battlestats??raw?.data??raw??{};const statVal=k=>{const v=x?.[k]??x?.battle_stats?.[k]??0;if(v&&typeof v==='object')return Number(v.value??v.amount??v.total??v.base??0)||0;return Number(v)||0};const apiTotal=Number(x?.total??x?.total_battlestats??0)||0;const total=apiTotal||['strength','defense','speed','dexterity'].reduce((sum,k)=>sum+statVal(k),0);if(!total)throw new Error('Battle stats endpoint replied, but no stat values were found. Check Torn API key access.');state.my={total,at:Date.now(),source:'Torn API'};save(K.my,state.my);apply();setStatus('Battle stats calibrated: '+fmtBS(total));return total} function renderTeamOptions(){const e=$('#slx-team');if(!e)return;e.innerHTML=''+state.teams.map(t=>``).join('')} async function loadTeams(){const fresh=normTeams(await torn('torn/elimination'));if(fresh.length){state.teams=fresh;save(K.teams,state.teams)}else if(!state.teams.length){state.teamId=0;localStorage.removeItem(K.team);renderTeamOptions();throw new Error('Torn returned no Elimination teams. The saved team was cleared so an old team cannot be loaded silently. Refresh and try again.')}if(!state.teams.some(t=>t.id===state.teamId))state.teamId=state.teams[0]?.id||0;if(state.teamId)localStorage.setItem(K.team,String(state.teamId));renderTeamOptions()} async function loadTeam(startOffset=Number(state.batchOffsets[String(state.teamId)]||0)){if(!state.teamId)throw new Error('Choose a team');startOffset=Math.max(0,Math.floor(Number(startOffset)||0));setStatus(`Loading targets ${startOffset+1}–${startOffset+500}…`);const a=[];for(let off=startOffset,i=0;i<5;i++,off+=100){let raw;try{raw=await torn(`torn/${state.teamId}/eliminationteam`,{limit:100,offset:off})}catch(e){if(Number(e.code)===32)throw new Error('Elimination team data is currently unavailable from Torn (API 32). Your API key was not rejected; try again when Torn enables the Eliminations team endpoint.');throw e}const batch=normPlayers(raw);a.push(...batch);if(batch.length<100)break}if(!a.length&&startOffset>0){setStatus('End reached · returning to the first 500 targets…');return loadTeam(0)}state.players=[...new Map(a.map(p=>[p.id,p])).values()];state.batchRawCount=a.length;state.batchOffsets[String(state.teamId)]=startOffset;save(K.batches,state.batchOffsets);applyCache();apply();const end=startOffset+a.length;let note=a.length?`Batch ${startOffset+1}–${end} · ${state.players.length} players`:'No players returned';if(a.length<500)note+=' · end reached, next LOAD wraps to 1';if(state.ffKey){try{await loadFF(false);note+=' · FF ready'}catch(e){apply();note+=' · FFScouter unavailable: '+e.message}}setStatus(note);return state.players.length} async function loadNextTeamBatch(){if(!state.teamId)throw new Error('Choose a team');const current=Number(state.batchOffsets[String(state.teamId)]||0);const next=state.players.length?(state.batchRawCount>=500?current+500:0):current;return loadTeam(next)} function applyCache(){for(const p of state.players){const c=state.cache[String(p.id)];if(c&&Date.now()-Number(c.at||0)<1800000){p.ff=c.ff||null;p.bs=c.bs||null}}} async function copyText(text){if(navigator.clipboard?.writeText){try{await navigator.clipboard.writeText(text);return}catch{}}const area=document.createElement('textarea');area.value=text;area.style.cssText='position:fixed;left:-9999px;top:0';document.body.appendChild(area);area.focus();area.select();const ok=document.execCommand('copy');area.remove();if(!ok)throw new Error('Clipboard access was blocked')} function cleanSafeTargets(){const map=new Map;for(const x of Array.isArray(state.safeTargets)?state.safeTargets:[]){const id=Number(x?.id||0);if(id>0)map.set(id,{id,name:String(x.name||('Player '+id)),level:Number(x.level||0),score:Number(x.score||0),teamId:Number(x.teamId||0),addedAt:Number(x.addedAt||Date.now()),seenAt:Number(x.seenAt||x.addedAt||Date.now())})}state.safeTargets=[...map.values()].slice(-5000)} function rememberSafeTargets(){cleanSafeTargets();const map=new Map(state.safeTargets.map(x=>[x.id,x]));let changed=false;for(const p of state.players){if(!attackable(p)||risk(p).label!=='SAFE')continue;const old=map.get(p.id),next={id:p.id,name:p.name,level:p.level||0,score:smart(p),teamId:state.teamId||0,addedAt:old?.addedAt||Date.now(),seenAt:Date.now()};if(!old||old.name!==next.name||old.level!==next.level||old.score!==next.score||old.teamId!==next.teamId){map.set(p.id,next);changed=true}}if(changed){state.safeTargets=[...map.values()].sort((a,b)=>a.addedAt-b.addedAt).slice(-5000);save(K.safe,state.safeTargets)}renderSafeTargets()} function renderSafeTargets(){cleanSafeTargets();const count=state.safeTargets.length,badge=$('#slx-safe-count');if(badge)badge.textContent=String(count);const total=$('#slx-safe-total');if(total)total.textContent=`${count} remembered SAFE target${count===1?'':'s'}`;const list=$('#slx-safe-list');if(!list)return;const rows=[...state.safeTargets].sort((a,b)=>b.addedAt-a.addedAt);list.innerHTML=rows.length?rows.map(x=>`
${esc(x.name)} [${x.id}]Score ${x.score}/100${x.level?' · Level '+x.level:''} · saved ${age(Math.floor(x.addedAt/1000))} ago
`).join(''):'
SAFE targets will be remembered automatically while loading and scanning batches.
';$$('.slx-safe-remove',list).forEach(b=>b.onclick=()=>removeSafeTarget(Number(b.dataset.id)))} function openSafeTargets(){renderSafeTargets();$('#slx-safe-list-modal')?.classList.add('open')} function removeSafeTarget(id){state.safeTargets=state.safeTargets.filter(x=>Number(x.id)!==Number(id));save(K.safe,state.safeTargets);renderSafeTargets();setStatus(`Removed target ${id} from SAFE list`)} async function clearSafeTargets(){if(!state.safeTargets.length)return;if(!(await globalThis.SakaLuXDialog.confirmAsync(`Clear all ${state.safeTargets.length} remembered SAFE targets?`)))return;state.safeTargets=[];save(K.safe,state.safeTargets);renderSafeTargets();setStatus('Remembered SAFE targets cleared')} async function copyAllSafe(){cleanSafeTargets();if(!state.safeTargets.length)throw new Error('No remembered SAFE targets yet');await copyText(state.safeTargets.map(x=>`https://www.torn.com/profiles.php?XID=${x.id}`).join('\n'));setStatus(`Copied ${state.safeTargets.length} remembered SAFE profile links`);return state.safeTargets.length} async function exportSafeTargets(){cleanSafeTargets();if(!state.safeTargets.length)throw new Error('No remembered SAFE targets yet');const payload={target_backup:state.safeTargets.map(x=>({id:x.id,notes:`SakaLuX SAFE · Score ${x.score}/100`,notes_color:'green'}))};await copyText(JSON.stringify(payload));setStatus(`Copied ${state.safeTargets.length} remembered SAFE targets · TornPDA: Chaining → Targets → Import / Export → paste → Add`);return state.safeTargets.length} async function exportTargets(){if(!state.view.length)throw new Error('Load and filter targets first');const list=state.view.filter(p=>attackable(p)&&risk(p).label!=='SKIP');if(!list.length)throw new Error('No attackable SAFE/RISKY targets in the current filtered list');const payload={target_backup:list.map(p=>{const r=risk(p);return{id:p.id,notes:`SakaLuX ${r.label} · Score ${smart(p)}/100 · ${presence(p).label}`,notes_color:r.label==='SAFE'?'green':'red'}})};await copyText(JSON.stringify(payload));setStatus(`Copied ${list.length} targets · TornPDA: Chaining → Targets → Import / Export → paste → Add`);return list.length} async function loadFF(force=false){ if(!(await globalThis.SakaLuXFreemium['elimination-assistant'].isPro())){globalThis.SakaLuXFreemium['elimination-assistant'].locked();return;}if(!state.players.length)throw new Error('Load a team first');if(!state.ffKey)throw new Error('Set FFScouter API key');const ids=state.players.filter(p=>force||!state.cache[String(p.id)]||Date.now()-Number(state.cache[String(p.id)].at||0)>=1800000).map(p=>p.id),all=[];for(let i=0;i0)}} function apply(){const q=($('#slx-q')?.value||'').toLowerCase();const filters=new Set($$('#slx-targets-menu input[data-filter]:checked').map(x=>x.dataset.filter));let a=state.players.filter(p=>!q||p.name.toLowerCase().includes(q)||String(p.id).includes(q));a=a.filter(p=>{const r=risk(p);if(filters.has('attackable')&&!attackable(p))return false;if(filters.has('unopened')&&state.history.some(h=>Number(h.id)===p.id))return false;const riskFilters=['safe','risky'].filter(x=>filters.has(x));if(riskFilters.length){const key=String(r.label||'').toLowerCase();if(!riskFilters.includes(key))return false}return true});a.sort((x,y)=>smart(y)-smart(x));state.view=a;updateTargetFilterCount();rememberSafeTargets();render()} function render(){const e=$('#slx-rows');if(!e)return;e.innerHTML=state.view.map(p=>{const r=risk(p),c=r.label==='SAFE'?'safe':r.label==='RISKY'?'risky':'skip',l=learn(p.id),st=presence(p),action=unavailable(p)?`WAIT`:`ATK`;return`${esc(signal(p))}${esc(p.name)} ${l.wins}W/${l.losses}L${st.icon} ${esc(st.label)}${p.level||'—'}${age(p.last)}
${action}
`}).join('');$$('.atk',e).forEach(a=>a.onclick=()=>{const p=state.players.find(x=>x.id===Number(a.dataset.id));if(p){state.history.unshift({id:p.id,name:p.name,action:'opened',at:Date.now()});save(K.hist,state.history.slice(0,1000))}});$$('.win',e).forEach(b=>b.onclick=()=>record(state.players.find(x=>x.id===Number(b.dataset.id)),'win'));$$('.loss',e).forEach(b=>b.onclick=()=>record(state.players.find(x=>x.id===Number(b.dataset.id)),'loss'));const safe=state.players.filter(p=>!unavailable(p)&&risk(p).label==='SAFE').length,tornCount=state.players.filter(attackable).length;$('#slx-summary').textContent=`TORN ${tornCount} · SAFE ${safe}`} async function record(p,res){if(!p)return;if(!(await globalThis.SakaLuXFreemium['elimination-assistant'].isPro())){globalThis.SakaLuXFreemium['elimination-assistant'].locked();return;}const l=learn(p.id);res==='win'?l.wins++:l.losses++;state.learning[String(p.id)]=l;save(K.learn,state.learning);apply()} async function refresh(){if(!state.enabled)return false;await loadTeams();if(state.teamId)await loadTeam();state.lastRefresh=Date.now();return true} async function busy(fn){if(!state.enabled||state.busy)return false;state.busy=true;try{await fn();return true}catch(e){console.error('[SakaLuX Elimination]',e);setStatus('Error: '+e.message);return false}finally{state.busy=false}} function open(){if(!state.enabled)setEnabled(true);inject();syncApiButton();$('#'+IDS.panel)?.classList.add('open');return true} function close(){$('#'+IDS.panel)?.classList.remove('open')} function health(){const batchStart=Number(state.batchOffsets[String(state.teamId)]||0);return{version:VERSION,enabled:state.enabled,ready:state.enabled&&!!$('#'+IDS.panel),hasApiKey:Boolean(getTornKey()),apiMode:state.tornKeySource,tornAccessStatus:state.tornAccessStatus,tornAccessMessage:state.tornAccessMessage,hasFFScouterKey:Boolean(state.ffKey),ffAccessStatus:state.ffAccessStatus,targets:state.players.length,rememberedSafeTargets:state.safeTargets.length,batchStart:batchStart+1,batchEnd:batchStart+state.batchRawCount,myBattleStats:state.my.total||null,lastRefresh:state.lastRefresh}} function goToEliminations(){location.href='https://www.torn.com/page.php?sid=elimination'} window.SakaLuXEliminationAssistant={version:VERSION,open,close,openApiSettings:openSettings,openSafeTargets,refresh:()=>busy(refresh),scanFF:()=>busy(()=>loadFF(true)),exportTargets:()=>busy(exportTargets),copyAllSafe:()=>busy(copyAllSafe),exportSafeTargets:()=>busy(exportSafeTargets),calibrate:()=>busy(()=>calibrate(true)),testTornKey:()=>busy(testKey),testFFScouterKey:()=>busy(testFFKey),createRequiredTornKey:createKey,setEnabled,toggleEnabled,isEnabled:()=>state.enabled,goToEliminations,health}; window.dispatchEvent(new CustomEvent('SakaLuXEliminationAssistantReady',{detail:{version:VERSION,enabled:state.enabled}})); watchSafeTargetsUi(); function persistTargetUI(){const panel=$('#'+IDS.panel);if(!panel)return;state.ui.query=$('#slx-q',panel)?.value||'';state.ui.filters=$$('#slx-targets-menu input[data-filter]:checked',panel).map(x=>x.dataset.filter);state.ui.panelOpen=panel.classList.contains('open');save(K.ui,state.ui)} function restoreTargetUI(){const panel=$('#'+IDS.panel);if(!panel||panel.dataset.slxUiRestored==='1')return;panel.dataset.slxUiRestored='1';renderTeamOptions();const q=$('#slx-q',panel);if(q)q.value=String(state.ui.query||'');const selected=new Set(Array.isArray(state.ui.filters)?state.ui.filters:[]);$$('#slx-targets-menu input[data-filter]',panel).forEach(x=>x.checked=selected.has(x.dataset.filter));panel.classList.toggle('open',!!state.ui.panelOpen);apply()} function installUIPersistence(){document.addEventListener('input',e=>{if(e.target?.id==='slx-q')persistTargetUI()});document.addEventListener('change',e=>{if(e.target?.matches?.('#slx-targets-menu input[data-filter]'))persistTargetUI()});document.addEventListener('click',e=>{if(e.target?.id==='slx-targets-clear')setTimeout(persistTargetUI,0);if(e.target?.id==='slx-close')setTimeout(persistTargetUI,0)});new MutationObserver(restoreTargetUI).observe(document.body,{childList:true});restoreTargetUI()} function start(){installUIPersistence();try{localStorage.setItem('SakaLuX_Installed_elimination-assistant',VERSION);localStorage.setItem('SakaLuX_Installed_elimination',VERSION)}catch{}installHubBridge('elimination-assistant',open);syncHubPower();setInterval(syncHubPower,900);if(state.enabled){inject();syncApiButton();setTimeout(showHubPrompt,1200);if(apiSetupPending()&&!/preferences\.php/i.test(location.pathname+location.href))setTimeout(()=>{open();openSettings()},900)}} if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',start,{once:true});else start(); /* SakaLuX Unified Control Center UI — visual layer only. */ function installSakaLuXUnifiedTheme_elimination_assistant() { if (document.getElementById('sakalux-unified-theme-elimination-assistant')) return; const style = document.createElement('style'); style.id = 'sakalux-unified-theme-elimination-assistant'; style.textContent = ` :where([id^="slx-elim-"],[class*="slx-elim-"]){font-family:Inter,Arial,sans-serif!important;box-sizing:border-box} :where([id^="slx-elim-"][id*="panel" i],[id^="slx-elim-"][id*="settings" i],[id^="slx-elim-"][id*="modal" i],[id^="slx-elim-"][id*="details" i]){background:radial-gradient(circle at 12% -20%,rgba(79,143,232,.15),transparent 38%),linear-gradient(155deg,#18212d 0%,#101720 72%)!important;color:#e7edf5!important;border:1px solid #314154!important;border-radius:16px!important;box-shadow:0 18px 52px rgba(0,0,0,.55),inset 0 1px rgba(255,255,255,.025)!important} :where([class*="slx-elim-"][class*="header" i],[id^="slx-elim-"][id*="header" i]){background:linear-gradient(155deg,#1b2634,#111923)!important;border-color:#314154!important;color:#f8fafc!important} :where([class*="slx-elim-"][class*="card" i],[class*="slx-elim-"][class*="row" i],[class*="slx-elim-"][class*="section" i],[class*="slx-elim-"][class*="note" i]){background:linear-gradient(145deg,#18212d,#131b25)!important;border-color:#2d3c4e!important;border-radius:12px!important;color:#dce6f0!important;box-shadow:0 6px 18px rgba(0,0,0,.14)!important} :where(button[id^="slx-elim-"],button[class*="slx-elim-"]){border:1px solid #3d78bf!important;border-radius:10px!important;background:linear-gradient(180deg,#377fcf,#275f9f)!important;color:#fff!important;font-weight:900!important;box-shadow:none!important;transition:transform .12s ease,filter .12s ease!important} :where(button[id^="slx-elim-"],button[class*="slx-elim-"]):active{transform:translateY(1px)!important} :where(input[id^="slx-elim-"],select[id^="slx-elim-"],textarea[id^="slx-elim-"],[id^="slx-elim-"] input,[id^="slx-elim-"] select,[id^="slx-elim-"] textarea){background:#0d141d!important;border:1px solid #3a4b61!important;border-radius:9px!important;color:#f4f7fb!important;outline:none!important} :where(input[type="checkbox"][id^="slx-elim-"]){appearance:none!important;-webkit-appearance:none!important;width:38px!important;height:21px!important;min-width:38px!important;margin:0 8px 0 0!important;vertical-align:middle!important;border:1px solid #546276!important;border-radius:999px!important;background:radial-gradient(circle at 10px 50%,#e7edf5 0 6px,transparent 6.5px),#465365!important;cursor:pointer!important;transition:.18s ease!important;box-shadow:inset 0 1px 3px rgba(0,0,0,.4)!important} :where(input[type="checkbox"][id^="slx-elim-"]):checked{border-color:#24754f!important;background:radial-gradient(circle at 27px 50%,#fff 0 6px,transparent 6.5px),#1eb36a!important} :where(button[id^="slx-elim-"],button[class*="slx-elim-"])[id*="close" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[class*="close" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[id*="back" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[class*="gray" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[class*="secondary" i]{background:linear-gradient(180deg,#253243,#1a2431)!important;border-color:#3a4a5d!important;color:#d7e1eb!important} :where(button[id^="slx-elim-"],button[class*="slx-elim-"])[id*="clear" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[id*="reset" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[id*="delete" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[class*="danger" i],:where(button[id^="slx-elim-"],button[class*="slx-elim-"])[class*="red" i]{background:linear-gradient(180deg,#733344,#54232f)!important;border-color:#864354!important;color:#ffd7df!important} @media(max-width:520px){:where([id^="slx-elim-"][id*="panel" i],[id^="slx-elim-"][id*="settings" i],[id^="slx-elim-"][id*="modal" i],[id^="slx-elim-"][id*="details" i]){border-radius:15px!important}:where(button[id^="slx-elim-"],button[class*="slx-elim-"]){min-height:34px!important}} `; (document.head || document.documentElement).appendChild(style); } installSakaLuXUnifiedTheme_elimination_assistant(); })(); /* slx-host-scroll-contract-v3 */ (()=>{if(document.getElementById('slx-host-scroll-contract-v3'))return;const s=document.createElement('style');s.id='slx-host-scroll-contract-v3';s.textContent=`@media(max-width:820px){ [data-slx-fullsheet-v2="1"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)){position:relative!important;inset:auto!important;width:100%!important;max-width:100%!important;height:100%!important;min-height:0!important;max-height:100%!important;margin:0!important;overflow-y:auto!important;overflow-x:hidden!important;overscroll-behavior:contain!important;touch-action:pan-y!important;-webkit-overflow-scrolling:touch!important;background:rgba(9,15,22,.94)!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important;} }`;(document.head||document.documentElement).appendChild(s)})(); /* SakaLuX Mobile Full-Screen Performance Contract */ (()=>{ if(document.getElementById('sakalux-fullscreen-performance-contract')) return; const s=document.createElement('style'); s.id='sakalux-fullscreen-performance-contract'; s.textContent=`@media(max-width:820px){ [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="overlay"], [id^="slx-"][id*="overlay"], [id^="sl-"][id*="overlay"]{ position:fixed!important;inset:0!important;top:0!important;right:0!important;bottom:0!important;left:0!important; width:100vw!important;height:100dvh!important;max-width:none!important;max-height:none!important; margin:0!important;padding:0!important;border-radius:0!important;overflow:hidden!important; -webkit-backdrop-filter:none!important;backdrop-filter:none!important;background:#0b1118!important;box-shadow:none!important } [data-slx-fullsheet-v2="1"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)), [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="panel"],[id^="slx-"][id*="panel"],[id^="sl-"][id*="panel"], [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="modal"],[id^="slx-"][id*="modal"],[id^="sl-"][id*="modal"]{ position:fixed!important;inset:0!important;top:0!important;right:0!important;bottom:0!important;left:0!important; width:100vw!important;height:100dvh!important;min-height:100dvh!important;max-width:none!important;max-height:none!important; margin:0!important;border-radius:0!important;box-sizing:border-box!important;overflow:auto!important; touch-action:pan-y!important;overscroll-behavior:contain!important;-webkit-overflow-scrolling:touch!important; -webkit-backdrop-filter:none!important;backdrop-filter:none!important;box-shadow:none!important } [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *)) *,[id^="slx-"] *,[id^="sl-"] *{ -webkit-backdrop-filter:none!important;backdrop-filter:none!important } [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="panel"] *,[id^="slx-"][id*="panel"] *,[id^="sl-"][id*="panel"] *, [id^="sakalux-"]:where(:not(#sakalux-hub-overlay, #sakalux-hub-panel, #sakalux-hub-overlay *, #sakalux-hub-panel *))[id*="modal"] *,[id^="slx-"][id*="modal"] *,[id^="sl-"][id*="modal"] *{ animation:none!important;transition:none!important } }`; (document.head||document.documentElement).appendChild(s); })(); /* Elimination v1.3.39: scoped target controls and taller mobile panel. */ (()=>{ const s=document.createElement('style'); s.id='slx-elim-ui-1339'; s.textContent=` #slx-elim #slx-targets-menu{box-sizing:border-box!important;width:206px!important;max-width:calc(100vw - 24px)!important;padding:8px!important} #slx-elim #slx-targets-menu .slx-target-option{min-height:42px!important;padding:7px 9px!important;gap:12px!important} #slx-elim #slx-targets-menu .slx-target-option span{font-size:11px!important;line-height:1.2!important} #slx-elim #slx-targets-menu input[type="checkbox"]{ appearance:none!important;-webkit-appearance:none!important;display:block!important; flex:0 0 40px!important;width:40px!important;min-width:40px!important;max-width:40px!important; height:22px!important;min-height:22px!important;max-height:22px!important; box-sizing:border-box!important;margin:0!important;padding:0!important;border:1px solid #46576b!important;border-radius:999px!important; background:radial-gradient(circle at 10px 50%,#cbd5e1 0 7px,transparent 7.5px),#25303d!important; box-shadow:inset 0 1px 2px #0004!important;transform:none!important;cursor:pointer!important; } #slx-elim #slx-targets-menu input[type="checkbox"]::before, #slx-elim #slx-targets-menu input[type="checkbox"]::after{content:none!important;display:none!important} #slx-elim #slx-targets-menu input[type="checkbox"]:checked{background:radial-gradient(circle at 28px 50%,#fff 0 7px,transparent 7.5px),#2563eb!important;border-color:#3b82f6!important} #slx-elim #slx-targets-menu .safe-opt input:checked{background:radial-gradient(circle at 28px 50%,#fff 0 7px,transparent 7.5px),#198754!important;border-color:#2aa66a!important} #slx-elim #slx-targets-menu .risky-opt input:checked{background:radial-gradient(circle at 28px 50%,#fff 0 7px,transparent 7.5px),#8a6f16!important;border-color:#b69428!important} #slx-elim #slx-targets-clear{height:32px!important;min-height:32px!important;padding:6px 8px!important;line-height:1.2!important} @media(max-width:820px){ #slx-elim#slx-elim{top:0!important;bottom:36px!important;left:4px!important;right:4px!important;width:auto!important;height:auto!important;min-height:0!important;max-height:none!important;box-sizing:border-box!important} #slx-elim>.slx-h,#slx-elim>.slx-t,#slx-elim>.slx-s{flex-shrink:0!important} #slx-elim>.slx-body{flex:1 1 0!important;min-height:0!important;overflow:auto!important;overscroll-behavior:contain!important} #slx-elim>#sakalux-inline-footer-elimination-assistant{flex:0 0 auto!important;margin-top:0!important} } `; (document.head||document.documentElement).appendChild(s); })(); /* Elimination v1.3.39: SAFE sheet stays inside its parent panel. */ (()=>{ const s=document.createElement('style');s.id='slx-elim-safe-layout-1339'; s.textContent=` #slx-elim #slx-safe-list-modal#slx-safe-list-modal{ position:absolute!important;inset:0 0 50px!important;width:auto!important;height:auto!important; min-height:0!important;max-height:none!important;max-width:none!important; margin:0!important;padding:12px!important;box-sizing:border-box!important; background:#0d1117!important;border-radius:0!important;overflow:hidden!important; z-index:60!important;color:#e2e8f0!important;font:13px/1.4 Arial,sans-serif!important; } #slx-elim #slx-safe-list-modal.open{display:flex!important;flex-direction:column!important} #slx-elim #slx-safe-list-modal .slx-safe-head{flex:0 0 auto!important;align-items:center!important;gap:10px!important;padding:0 0 10px!important;border-bottom:1px solid #2d3742!important} #slx-elim #slx-safe-list-modal .slx-safe-head h3{flex:1!important;min-width:0!important;margin:0!important;padding:0!important;font:800 17px/1.25 Arial,sans-serif!important;color:#86efac!important} #slx-elim #slx-safe-list-modal .slx-a{box-sizing:border-box!important;margin:0!important;padding:8px 10px!important;min-height:36px!important;font:800 12px/1.2 Arial,sans-serif!important;border-radius:9px!important;text-align:center!important} #slx-elim #slx-safe-close{flex:0 0 auto!important;white-space:nowrap!important} #slx-elim #slx-safe-list-modal .slx-safe-note{flex:0 0 auto!important;margin:8px 0 0!important;font:12px/1.45 Arial,sans-serif!important;color:#a7b2c0!important} #slx-elim #slx-safe-total{font-weight:700!important;color:#cbd5e1!important} #slx-elim #slx-safe-list-modal .slx-safe-actions{flex:0 0 auto!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:8px!important;margin:12px 0!important} #slx-elim #slx-safe-list-modal .slx-safe-list{flex:1 1 auto!important;min-height:0!important;overflow:auto!important;overscroll-behavior:contain!important;background:#111821!important} #slx-elim #slx-safe-list-modal .slx-safe-empty{padding:20px 14px!important;font:13px/1.45 Arial,sans-serif!important} #slx-elim #slx-safe-list-modal .slx-safe-row{gap:10px!important;padding:10px!important} #slx-elim #slx-safe-list-modal .slx-safe-player a{font-size:13px!important;overflow-wrap:anywhere!important} #slx-elim #slx-safe-list-modal .slx-safe-player small{font:11px/1.4 Arial,sans-serif!important} `;(document.head||document.documentElement).appendChild(s); })(); /* Elimination v1.3.39: API form fits within the panel and scrolls to manual save. */ (()=>{ const s=document.createElement('style');s.id='slx-elim-api-layout-1339'; s.textContent=` #slx-elim #slx-settings#slx-settings{ position:absolute!important;inset:0 0 50px!important;width:auto!important;height:auto!important; min-height:0!important;max-height:none!important;max-width:none!important; margin:0!important;padding:12px 12px 18px!important;box-sizing:border-box!important; background:#0d1117!important;border-radius:0!important;overflow-y:auto!important;overflow-x:hidden!important; overscroll-behavior:contain!important;-webkit-overflow-scrolling:touch!important; z-index:60!important;color:#e2e8f0!important;font:13px/1.4 Arial,sans-serif!important; } #slx-elim #slx-settings *,#slx-elim #slx-settings *::before,#slx-elim #slx-settings *::after{box-sizing:border-box!important} #slx-elim #slx-settings .slx-api-head{align-items:center!important;gap:10px!important} #slx-elim #slx-settings .slx-api-head>div{min-width:0!important;flex:1!important} #slx-elim #slx-settings .slx-api-head h3{margin:0!important;font:800 17px/1.25 Arial,sans-serif!important} #slx-elim #slx-settings .slx-api-box,#slx-elim #slx-settings .slx-manual-box{min-width:0!important;max-width:100%!important} #slx-elim #slx-settings label{display:block!important;margin:8px 0 4px!important;font:12px/1.4 Arial,sans-serif!important} #slx-elim #slx-settings input{ display:block!important;width:100%!important;min-width:0!important;max-width:100%!important; height:40px!important;min-height:40px!important;margin:0 0 10px!important;padding:9px 10px!important; font:13px/1.4 Arial,sans-serif!important;border-radius:8px!important; } #slx-elim #slx-settings button{ min-width:0!important;max-width:100%!important;min-height:38px!important; margin:0!important;padding:9px 10px!important;font:800 12px/1.25 Arial,sans-serif!important; white-space:normal!important;overflow-wrap:anywhere!important;border-radius:8px!important; } #slx-elim #slx-settings #slx-cancel{flex:0 0 36px!important} #slx-elim #slx-settings .slx-api-actions{grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:8px!important} #slx-elim #slx-settings .slx-api-clear{margin-top:8px!important} #slx-elim #slx-settings .slx-api-create{margin:10px 0!important} #slx-elim #slx-settings .slx-api-status{flex-wrap:wrap!important} #slx-elim #slx-settings .slx-api-status span{min-width:0!important;overflow-wrap:anywhere!important} #slx-elim #slx-settings #slx-save-manual{ display:flex!important;align-items:center!important;justify-content:center!important; width:100%!important;min-height:42px!important;height:auto!important;margin:0!important; padding:10px!important;line-height:1.3!important; } `;(document.head||document.documentElement).appendChild(s); })(); /* SakaLuX Hub footer v3: native module root only; compact donation controls. */ (()=>{ const selector="#slx-elim",id="sakalux-inline-footer-elimination-assistant",profile='https://www.torn.com/profiles.php?XID=2380374'; const st=document.createElement('style');st.textContent=` #${id}#${id}{position:sticky!important;bottom:0!important;inset-inline:auto!important;display:block!important;flex:0 0 50px!important;width:100%!important;height:50px!important;min-height:50px!important;max-height:50px!important;margin:0!important;padding:0!important;box-sizing:border-box!important;z-index:5!important;font-family:Arial,sans-serif!important;overflow:hidden!important;border-radius:10px!important} #${id}#${id} *{box-sizing:border-box!important} #${id}#${id} .slh-bottom{height:28px!important;margin:0!important;padding:4px 14px!important;background:#0b1118!important;border-top:1px solid rgba(255,255,255,.08)!important;border-radius:10px 10px 0 0!important;overflow:hidden!important} #${id}#${id} .slh-bottom-grid{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:7px!important;height:20px!important} #${id}#${id} .slh-bottom-btn{display:block!important;width:100%!important;min-width:0!important;height:20px!important;min-height:20px!important;max-height:20px!important;margin:0!important;padding:0 4px!important;border:1px solid #2d3d50!important;border-radius:10px!important;background:#151f2a!important;color:#b9c7d6!important;font:900 8px/1.2 Arial,sans-serif!important;letter-spacing:.04em!important;white-space:nowrap!important;box-shadow:none!important;cursor:pointer!important} #${id}#${id} .slh-footer{height:22px!important;min-height:22px!important;max-height:22px!important;margin:0!important;padding:0 6px!important;display:flex!important;align-items:center!important;justify-content:center!important;gap:3px!important;border-top:1px solid rgba(223,154,55,.52)!important;border-radius:0 0 10px 10px!important;background:#080d13!important;color:#df9a37!important;font:400 9px/20px Arial,sans-serif!important;white-space:nowrap!important;overflow:hidden!important} #${id}#${id} .slh-author{color:#78aef2!important;font-weight:900!important;text-decoration:none!important} `;(document.head||document.documentElement).appendChild(st); function ensure(){ const panel=document.querySelector(selector);if(!panel||panel.closest('#sakalux-hub-overlay, #sakalux-hub-panel'))return; if(panel.querySelector('#'+id))return; const f=document.createElement('div');f.id=id; f.innerHTML='
'; f.querySelectorAll('[data-slx-donate]').forEach(b=>b.onclick=()=>{location.href=profile});panel.appendChild(f); } function start(){ensure();let scheduled=false;new MutationObserver(records=>{ const nativeRoot=selector.split(/[ >]/)[0]; const relevant=records.some(r=>{ if(r.target?.closest?.('[id^="sakalux-inline-footer-"]'))return false; return r.target?.closest?.(nativeRoot)||[...r.addedNodes].some(n=>n.nodeType===1&&n.matches?.(nativeRoot)); }); if(scheduled||!relevant)return; scheduled=true;requestAnimationFrame(()=>{scheduled=false;ensure()}); }).observe(document.body,{childList:true,subtree:true});} if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',start,{once:true});else start(); })(); /* Compact donation controls and Elimination mobile panel geometry 1.3.41 */ (()=>{const s=document.createElement('style');s.textContent="@media(max-width:820px){\n#slx-elim#slx-elim#slx-elim{position:fixed!important;inset:0 4px 36px!important;top:0!important;bottom:36px!important;left:4px!important;right:4px!important;width:auto!important;height:auto!important;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;margin:0!important;transform:none!important;box-sizing:border-box!important;border-radius:14px!important;}\n\n}";(document.head||document.documentElement).appendChild(s)})();