SHAYA UI

All-in-One Faction HUD – v25.0: Age in Tagen, Enemy Bounty, Bank raus, Bounty-Filter bereinigt, Code aufgeräumt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         SHAYA UI
// @namespace    https://www.torn.com/
// @version      25.0
// @description  All-in-One Faction HUD – v25.0: Age in Tagen, Enemy Bounty, Bank raus, Bounty-Filter bereinigt, Code aufgeräumt
// @author       xShaYaKaZ
// @match        https://www.torn.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      api.torn.com
// ==/UserScript==
 
(function () {
    'use strict';
 
    const VERSION = '25.0';
    const SCRIPT_TITLE = "SHAYA UI";
    const API_BASE = 'https://api.torn.com';
 
    const REFRESH = {
        PERSONAL:  15000,
        FACTION:   30000,
        CHAIN:     8000,
        TICK:      1000,
        NETWORTH:  60000,
        COMPANY:   60000,
        ENEMY:     30000,
    };
 
    const TRAVEL_WARN_SEC  = 420;
    const TRAVEL_CRIT_SEC  = 120;
    const CHAIN_WARN_SEC   = 60;
    const CHAIN_START_HIT  = 10;
    const INACTIVE_LIMIT   = 3;
    const SHOPPING_TIME_SEC = 15;
    const HAPPY_JUMP_THRESHOLD = 151;
 
    const DESTINATIONS = {
        'Mexico':         { flag: '🇲🇽' },
        'Cayman Islands': { flag: '🇰🇾' },
        'Canada':         { flag: '🇨🇦' },
        'Hawaii':         { flag: '🇺🇸' },
        'United Kingdom': { flag: '🇬🇧' },
        'Argentina':      { flag: '🇦🇷' },
        'Switzerland':    { flag: '🇨🇭' },
        'Japan':          { flag: '🇯🇵' },
        'China':          { flag: '🇨🇳' },
        'UAE':            { flag: '🇦🇪' },
        'South Africa':   { flag: '🇿🇦' },
        'Torn':           { flag: '🏠'  },
        'Torn City':      { flag: '🏠'  },
    };
 
    const DEST_TOP_ITEMS = {
        'Mexico':         ['Jaguar Plushie', 'Dahlia'],
        'United Kingdom': ['Xanax', 'Red Fox Plushie'],
        'Japan':          ['Xanax', 'Cherry Blossom'],
        'South Africa':   ['Lion Plushie', 'African Violet'],
        'Cayman Islands': ['Beer', 'Flower'],
        'Canada':         ['Wine', 'Beer'],
        'Hawaii':         ['Flower', 'Cannabis'],
        'Argentina':      ['Cocaine', 'Cannabis'],
        'Switzerland':    ['Ecstasy', 'Wine'],
        'China':          ['Opium', 'Heroin'],
        'UAE':            ['Cannabis', 'Laptop'],
    };
 
    const THEMES = {
        obsidian: { name:'⬛ Obsidian', bg:'#0a0a0b', bgCard:'#111114', bgEl:'#18181c', border:'#2a2a30', accent:'#6366f1', accent2:'#818cf8', text:'#f1f5f9', textMuted:'#64748b', textDim:'#94a3b8', green:'#10b981', red:'#ef4444', amber:'#f59e0b', blue:'#3b82f6', chain:'#ef4444', travel:'#6366f1', online:'#10b981' },
        slate:    { name:'🔵 Slate',    bg:'#0f172a', bgCard:'#1e293b', bgEl:'#293548', border:'#334155', accent:'#38bdf8', accent2:'#7dd3fc', text:'#f8fafc', textMuted:'#64748b', textDim:'#94a3b8', green:'#22c55e', red:'#f87171', amber:'#fbbf24', blue:'#38bdf8', chain:'#f87171', travel:'#38bdf8', online:'#22c55e' },
        emerald:  { name:'🟢 Emerald',  bg:'#030a06', bgCard:'#071210', bgEl:'#0d1e17', border:'#1a3a28', accent:'#10b981', accent2:'#34d399', text:'#ecfdf5', textMuted:'#4b7a60', textDim:'#6ee7b7', green:'#10b981', red:'#ef4444', amber:'#f59e0b', blue:'#3b82f6', chain:'#ef4444', travel:'#10b981', online:'#10b981' },
        crimson:  { name:'🔴 Crimson',  bg:'#0a0305', bgCard:'#150509', bgEl:'#1f070c', border:'#3a0d14', accent:'#f43f5e', accent2:'#fb7185', text:'#fff1f2', textMuted:'#7a3040', textDim:'#fca5a5', green:'#22c55e', red:'#f43f5e', amber:'#fb923c', blue:'#60a5fa', chain:'#f43f5e', travel:'#fb923c', online:'#22c55e' },
    };
 
    // ═══════════════════════════════════════════════════════════════
    // CSS
    // ═══════════════════════════════════════════════════════════════
    const buildCSS = () => `
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=DM+Sans:wght@400;500;600;700&display=swap');
:root { --bg:#0a0a0b; --bg-card:#111114; --bg-el:#18181c; --border:#2a2a30; --accent:#6366f1; --accent2:#818cf8; --text:#f1f5f9; --muted:#64748b; --dim:#94a3b8; --green:#10b981; --red:#ef4444; --amber:#f59e0b; --blue:#3b82f6; --chain:#ef4444; --travel:#6366f1; --online:#10b981; --r:12px; --r-sm:8px; --r-lg:16px; --font:'DM Sans',sans-serif; --mono:'JetBrains Mono',monospace; }
* { box-sizing:border-box; margin:0; padding:0; }
#thud-overlay { position:fixed; z-index:99999; font-family:var(--font); font-size:13px; color:var(--text); background:var(--bg); border:1px solid var(--border); border-radius:20px; box-shadow:0 32px 80px rgba(0,0,0,.95),0 0 0 1px rgba(255,255,255,.03); display:flex; flex-direction:column; overflow:hidden; min-width:300px; min-height:200px; user-select:none; }
#thud-overlay.minimized { min-height:0 !important; height:auto !important; border-radius:12px; }
#thud-overlay.minimized .thud-tabs, #thud-overlay.minimized .thud-body, #thud-overlay.minimized .thud-resize-se, #thud-overlay.minimized .thud-resize-e, #thud-overlay.minimized .thud-resize-s { display:none !important; }
#thud-overlay.minimized .thud-mini { display:flex !important; }
#thud-overlay:not(.minimized) .thud-mini { display:none !important; }
.thud-header { display:flex; align-items:center; gap:8px; padding:10px 14px; background:linear-gradient(180deg,rgba(255,255,255,.025) 0%,transparent 100%); border-bottom:1px solid var(--border); cursor:grab; flex-shrink:0; }
.thud-header:active { cursor:grabbing; }
.thud-header-logo { width:32px; height:32px; flex-shrink:0; display:flex; align-items:center; justify-content:center; filter:drop-shadow(0 2px 8px rgba(239,68,68,.5)); }
.thud-header-logo svg { width:32px; height:32px; }
.thud-header-info { flex:1; min-width:0; }
.thud-header-title { font-size:13px; font-weight:800; color:var(--text); letter-spacing:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-transform:uppercase; }
.thud-header-sub { font-size:9px; color:var(--muted); font-family:var(--mono); margin-top:1px; }
.thud-header-actions { display:flex; gap:4px; flex-shrink:0; align-items:center; }
.thud-btn { background:var(--bg-el); border:1px solid var(--border); color:var(--dim); border-radius:7px; padding:5px 8px; cursor:pointer; font-size:11px; font-family:var(--font); font-weight:600; transition:all .15s; display:flex; align-items:center; gap:4px; white-space:nowrap; }
.thud-btn:hover { border-color:var(--accent); color:var(--text); background:rgba(99,102,241,.1); }
.thud-btn.active { border-color:var(--green); color:var(--green); background:rgba(16,185,129,.08); }
.thud-btn-close { background:rgba(239,68,68,.12); border:1px solid rgba(239,68,68,.25); color:var(--red); border-radius:7px; padding:5px 8px; cursor:pointer; font-size:12px; font-weight:700; transition:all .15s; display:flex; align-items:center; line-height:1; }
.thud-btn-close:hover { background:rgba(239,68,68,.3); border-color:var(--red); }
.pip { width:6px; height:6px; border-radius:50%; background:var(--green); box-shadow:0 0 6px var(--green); animation:pipPulse 2s ease-in-out infinite; }
@keyframes pipPulse { 0%,100%{opacity:1} 50%{opacity:.3} }
.thud-tabs { display:flex; background:var(--bg); border-bottom:1px solid var(--border); flex-shrink:0; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; gap:2px; padding:5px 6px 0; cursor:default; }
.thud-tabs::-webkit-scrollbar { display:none; }
.thud-tab { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; padding:6px 8px 8px; cursor:pointer; color:var(--muted); border-bottom:2px solid transparent; border-radius:7px 7px 0 0; transition:all .15s; white-space:nowrap; min-width:40px; flex-shrink:0; }
.thud-tab .ti { font-size:13px; line-height:1; }
.thud-tab .tl { font-size:7.5px; font-weight:700; letter-spacing:.7px; text-transform:uppercase; }
.thud-tab:hover { color:var(--dim); background:rgba(255,255,255,.04); }
.thud-tab.active { color:var(--accent2); border-bottom-color:var(--accent); background:rgba(99,102,241,.06); }
.thud-mini { display:none; flex-direction:column; align-items:stretch; }
.thud-mini-bar { display:flex; align-items:center; gap:6px; padding:5px 10px; flex-wrap:nowrap; overflow:hidden; border-top:1px solid var(--border); }
.thud-mini-chip { display:flex; align-items:center; gap:3px; font-size:10px; font-weight:700; flex-shrink:0; background:var(--bg-el); border:1px solid var(--border); border-radius:6px; padding:2px 6px; }
.thud-mini-val { color:var(--text); font-family:var(--mono); font-size:10px; }
.thud-mini-lbl { color:var(--muted); font-size:9px; }
.thud-mini-tabs { display:flex; border-top:1px solid rgba(255,255,255,.04); width:100%; }
.thud-mini-tab { flex:1; padding:4px 2px; text-align:center; font-size:9px; font-weight:700; color:var(--muted); cursor:pointer; border-right:1px solid rgba(255,255,255,.04); letter-spacing:.3px; text-transform:uppercase; transition:all .15s; }
.thud-mini-tab:last-child { border-right:none; }
.thud-mini-tab:hover { color:var(--accent2); background:rgba(99,102,241,.06); }
.thud-body { flex:1 1 0; overflow-y:scroll !important; min-height:0; display:flex; flex-direction:column; gap:10px; padding:12px 14px 14px; pointer-events:auto; scrollbar-width:thin; scrollbar-color:var(--border) transparent; }
.thud-body::-webkit-scrollbar { width:4px; }
.thud-body::-webkit-scrollbar-thumb { background:var(--border); border-radius:2px; }
.card { background:var(--bg-card); border:1px solid var(--border); border-radius:var(--r); overflow:hidden; flex-shrink:0; }
.card-header { display:flex; align-items:center; justify-content:space-between; padding:10px 14px; border-bottom:1px solid rgba(255,255,255,.05); }
.card-title { font-size:10px; font-weight:700; letter-spacing:.8px; text-transform:uppercase; color:var(--dim); }
.card-title.accent { color:var(--accent2); } .card-title.green { color:var(--green); } .card-title.red { color:var(--red); } .card-title.amber { color:var(--amber); } .card-title.blue { color:var(--blue); }
.card-body { padding:12px 14px; display:flex; flex-direction:column; gap:8px; }
.card-body.p0 { padding:0; }
.badge { padding:2px 7px; border-radius:20px; font-size:9px; font-weight:700; letter-spacing:.5px; }
.badge-green { background:rgba(16,185,129,.12); color:var(--green); border:1px solid rgba(16,185,129,.2); }
.badge-red   { background:rgba(239,68,68,.12);  color:var(--red);   border:1px solid rgba(239,68,68,.2); }
.badge-amber { background:rgba(245,158,11,.12); color:var(--amber); border:1px solid rgba(245,158,11,.2); }
.badge-blue  { background:rgba(59,130,246,.12); color:var(--blue);  border:1px solid rgba(59,130,246,.2); }
.badge-muted { background:rgba(255,255,255,.06); color:var(--muted); border:1px solid rgba(255,255,255,.08); }
.row { display:flex; align-items:center; justify-content:space-between; padding:6px 0; border-bottom:1px solid rgba(255,255,255,.04); }
.row:last-child { border-bottom:none; }
.row-label { font-size:12px; color:var(--dim); font-weight:500; }
.row-value { font-size:12px; font-family:var(--mono); font-weight:600; color:var(--text); }
.bar { height:4px; background:rgba(255,255,255,.06); border-radius:3px; overflow:hidden; }
.bar-lg { height:6px; }
.bar-fill { height:100%; border-radius:3px; transition:width .4s; }
.bar-block { display:flex; flex-direction:column; gap:5px; }
.bar-block-head { display:flex; justify-content:space-between; align-items:center; }
.bar-block-lbl { font-size:12px; color:var(--muted); font-weight:600; }
.bar-block-val { font-size:13px; font-family:var(--mono); font-weight:700; }
.bar-block-sub { font-size:10px; color:var(--muted); }
.stat-grid { display:grid; gap:8px; }
.stat-grid-3 { grid-template-columns:repeat(3,1fr); }
.stat-grid-4 { grid-template-columns:repeat(4,1fr); }
.stat-card { background:var(--bg-el); border:1px solid var(--border); border-radius:var(--r-sm); padding:10px 6px; text-align:center; }
.sv { font-size:17px; font-weight:700; font-family:var(--mono); line-height:1; }
.sv-green { color:var(--green); } .sv-red { color:var(--red); } .sv-amber { color:var(--amber); } .sv-blue { color:var(--blue); }
.sl { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.5px; margin-top:4px; }
.stat-chip { text-align:center; }
.sn { font-size:15px; font-weight:700; font-family:var(--mono); }
.status-summary { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; padding:10px 0 4px; border-top:1px solid rgba(255,255,255,.05); margin-top:6px; }
.ql-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:6px; padding:2px 0 4px; }
.ql-card { background:var(--bg-el); border:1px solid var(--border); border-radius:10px; padding:10px 4px 8px; cursor:pointer; text-align:center; display:flex; flex-direction:column; align-items:center; gap:4px; transition:all .18s; text-decoration:none; }
.ql-card:hover { border-color:var(--accent); background:rgba(99,102,241,.1); transform:translateY(-2px); box-shadow:0 6px 20px rgba(99,102,241,.15); }
.ql-icon { font-size:20px; line-height:1; }
.ql-name { font-size:9px; font-weight:800; color:var(--dim); text-align:center; line-height:1.2; }
.travel-card { border:1px solid rgba(99,102,241,.15); border-radius:var(--r); overflow:hidden; flex-shrink:0; }
.travel-card.home { border-color:rgba(16,185,129,.15); }
.travel-card.warn { border-color:rgba(245,158,11,.3); }
.travel-card.crit { border-color:rgba(239,68,68,.4); animation:travelCritPulse 1s ease-in-out infinite alternate; }
.travel-card.ok   { border-color:rgba(99,102,241,.3); }
@keyframes travelCritPulse { from{box-shadow:none} to{box-shadow:0 0 20px rgba(239,68,68,.3)} }
.travel-card-top { display:flex; align-items:center; justify-content:space-between; padding:8px 14px; font-size:10px; font-weight:700; letter-spacing:.8px; text-transform:uppercase; background:rgba(0,0,0,.15); border-bottom:1px solid rgba(255,255,255,.05); }
.travel-card-body { padding:12px 14px; }
.travel-dest { font-size:18px; font-weight:800; letter-spacing:-.3px; }
.travel-clock { font-size:28px; font-weight:800; font-family:var(--mono); line-height:1; }
.travel-prog { height:3px; background:rgba(255,255,255,.06); border-radius:2px; overflow:hidden; margin-top:10px; }
.travel-prog-fill { height:100%; border-radius:2px; background:var(--travel); transition:width .5s; }
.travel-prog-fill.warn { background:var(--amber); }
.travel-prog-fill.crit { background:var(--red); }
.smart-tipp { background:linear-gradient(135deg,rgba(99,102,241,.09),rgba(129,140,248,.03)); border:1px solid rgba(99,102,241,.25); border-left:3px solid var(--accent); border-radius:var(--r); padding:9px 12px; font-size:12px; color:var(--dim); line-height:1.6; flex-shrink:0; display:flex; align-items:center; gap:8px; }
.smart-tipp-icon { font-size:15px; flex-shrink:0; }
.smart-tipp-text { flex:1; }
.member-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:2px 8px; }
.member-row { display:flex; align-items:center; gap:5px; padding:4px 0; border-bottom:1px solid rgba(255,255,255,.04); }
.member-row:last-child { border-bottom:none; }
.member-name { flex:1; font-size:11px; font-weight:600; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.member-status { font-size:9px; color:var(--muted); font-weight:600; white-space:nowrap; }
.status-dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
.sd-online { background:var(--online); box-shadow:0 0 5px var(--online); }
.sd-idle { background:var(--amber); }
.sd-traveling { background:var(--travel); }
.sd-hospital { background:var(--red); }
.sd-jail { background:#f97316; }
.sd-offline { background:rgba(255,255,255,.12); }
.offline-row { display:flex; align-items:center; gap:8px; padding:6px 14px; border-bottom:1px solid rgba(255,255,255,.04); }
.offline-row:last-child { border-bottom:none; }
.offline-name { flex:1; font-size:11px; color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.offline-ago { font-size:10px; font-family:var(--mono); font-weight:700; }
.ago-m { color:var(--amber); } .ago-h { color:var(--red); } .ago-d { color:var(--muted); }
.bounty-row { display:flex; align-items:flex-start; gap:10px; padding:10px 14px; border-bottom:1px solid rgba(255,255,255,.04); }
.bounty-row:last-child { border-bottom:none; }
.bounty-row.is-hospital { background:rgba(239,68,68,.06); border-left:3px solid var(--red); }
.bounty-reward { font-family:var(--mono); font-size:12px; font-weight:700; color:var(--amber); white-space:nowrap; }
.bounty-link { display:inline-flex; align-items:center; padding:5px 10px; border-radius:6px; background:rgba(239,68,68,.15); border:1px solid rgba(239,68,68,.25); color:var(--red); font-size:11px; font-weight:700; text-decoration:none; white-space:nowrap; transition:all .15s; }
.bounty-link:hover { background:rgba(239,68,68,.3); }
.bounty-difficulty { padding:2px 6px; border-radius:4px; font-size:9px; font-weight:800; }
.diff-easy   { background:rgba(16,185,129,.15); color:var(--green); }
.diff-medium { background:rgba(245,158,11,.15);  color:var(--amber); }
.diff-hard   { background:rgba(239,68,68,.15);   color:var(--red); }
.sort-bar { display:flex; align-items:center; gap:5px; flex-wrap:wrap; }
.bounty-info-row { display:flex; gap:5px; flex-wrap:wrap; align-items:center; margin-top:4px; }
.bounty-tag { font-size:9px; font-weight:700; padding:1px 5px; border-radius:4px; white-space:nowrap; }
.tag-hosp { background:rgba(239,68,68,.25); color:var(--red); border:1px solid rgba(239,68,68,.5); font-size:10px; padding:2px 7px; border-radius:5px; animation:hospTagPulse 1.5s ease-in-out infinite; }
@keyframes hospTagPulse { 0%,100%{box-shadow:none} 50%{box-shadow:0 0 6px rgba(239,68,68,.5)} }
.tag-jail   { background:rgba(245,158,11,.15); color:var(--amber);  border:1px solid rgba(245,158,11,.2); }
.tag-travel { background:rgba(99,102,241,.15);  color:var(--accent2); border:1px solid rgba(99,102,241,.2); }
.tag-ok     { background:rgba(16,185,129,.10);  color:var(--green);  border:1px solid rgba(16,185,129,.15); }
.bounty-search { width:100%; background:var(--bg); border:1px solid var(--border); border-radius:var(--r-sm); padding:7px 11px; color:var(--text); font-family:var(--font); font-size:12px; outline:none; transition:border-color .15s; }
.bounty-search:focus { border-color:var(--accent); }
.level-filter-row { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.level-input { background:var(--bg); border:1px solid var(--border); border-radius:6px; padding:4px 7px; color:var(--accent2); font-family:var(--mono); font-size:11px; width:55px; text-align:center; outline:none; }
.level-input:focus { border-color:var(--accent); }
.reward-input { background:var(--bg); border:1px solid var(--border); border-radius:6px; padding:4px 7px; color:var(--amber); font-family:var(--mono); font-size:11px; width:70px; text-align:center; outline:none; }
.bounty-load-more-inline { display:inline-flex; align-items:center; gap:4px; padding:3px 9px; border-radius:6px; background:rgba(99,102,241,.15); border:1px solid rgba(99,102,241,.3); color:var(--accent2); font-size:10px; font-weight:700; cursor:pointer; font-family:var(--font); transition:all .15s; }
.bounty-load-more-inline:hover { background:rgba(99,102,241,.28); }
.company-kpi-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:7px; margin-bottom:8px; }
.company-kpi { background:var(--bg-el); border:1px solid var(--border); border-radius:var(--r-sm); padding:9px 7px; text-align:center; }
.kv { font-size:13px; font-weight:700; font-family:var(--mono); line-height:1; }
.kl { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.5px; margin-top:4px; }
.company-emp-row { display:flex; align-items:center; gap:8px; padding:7px 14px; border-bottom:1px solid rgba(255,255,255,.04); }
.company-emp-row:last-child { border-bottom:none; }
.company-emp-name { flex:1; font-size:12px; font-weight:600; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.company-emp-pos { font-size:10px; color:var(--muted); white-space:nowrap; min-width:60px; }
.company-emp-eff { font-size:11px; font-family:var(--mono); font-weight:700; white-space:nowrap; text-align:right; min-width:36px; }
.nw-ticker { background:linear-gradient(135deg,rgba(245,158,11,.07),rgba(251,191,36,.02)); border:1px solid rgba(245,158,11,.15); border-radius:var(--r); padding:16px 18px; flex-shrink:0; }
.nw-main-val { font-size:26px; font-weight:800; font-family:var(--mono); color:var(--amber); }
.nw-change { font-size:11px; font-family:var(--mono); font-weight:700; }
.nw-change.pos { color:var(--green); } .nw-change.neg { color:var(--red); }
.settings-section { display:flex; flex-direction:column; gap:0; }
.settings-section-title { font-size:9px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.8px; padding:12px 14px 7px; border-top:1px solid rgba(255,255,255,.05); }
.settings-section:first-child .settings-section-title { border-top:none; padding-top:4px; }
.alarm-row-item { display:flex; align-items:center; gap:10px; padding:9px 14px; border-bottom:1px solid rgba(255,255,255,.04); }
.alarm-lbl { font-size:12px; font-weight:600; color:var(--text); }
.alarm-desc { font-size:10px; color:var(--muted); margin-top:1px; }
.toggle { position:relative; display:inline-block; width:34px; height:19px; flex-shrink:0; }
.toggle input { opacity:0; width:0; height:0; }
.toggle-slider { position:absolute; inset:0; background:rgba(255,255,255,.1); border-radius:19px; transition:.2s; }
.toggle-slider::before { content:''; position:absolute; height:13px; width:13px; left:3px; bottom:3px; background:var(--dim); border-radius:50%; transition:.2s; }
.toggle input:checked + .toggle-slider { background:var(--accent); }
.toggle input:checked + .toggle-slider::before { transform:translateX(15px); background:white; }
.theme-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:5px; }
.theme-btn { padding:9px 5px; border-radius:var(--r-sm); border:1px solid var(--border); background:var(--bg-el); font-size:10px; font-weight:600; color:var(--muted); cursor:pointer; font-family:var(--font); transition:all .15s; text-align:center; }
.theme-btn.active,.theme-btn:hover { border-color:var(--accent); color:var(--accent2); background:rgba(99,102,241,.08); }
.vis-grid { display:flex; flex-direction:column; gap:0; }
.vis-row { display:flex; align-items:center; justify-content:space-between; padding:8px 10px; background:rgba(0,0,0,.15); border-radius:var(--r-sm); border:1px solid rgba(255,255,255,.04); }
.vis-lbl { font-size:11px; color:var(--dim); font-weight:500; }
.api-key-row { display:flex; align-items:center; gap:10px; padding:10px 12px; background:rgba(0,0,0,.2); border-radius:var(--r-sm); border:1px solid rgba(255,255,255,.04); }
.api-key-status { flex:1; font-size:12px; font-weight:600; }
.api-key-status.set { color:var(--green); } .api-key-status.unset { color:var(--red); }
.sound-profile-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:5px; }
.sp-btn { padding:9px 5px; border-radius:var(--r-sm); border:1px solid var(--border); background:var(--bg-el); font-size:10px; font-weight:600; color:var(--muted); cursor:pointer; font-family:var(--font); transition:all .15s; text-align:center; }
.sp-btn:hover,.sp-btn.active { border-color:var(--accent); color:var(--accent2); background:rgba(99,102,241,.08); }
.section-header { font-size:9px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.8px; padding:3px 0 7px; display:flex; align-items:center; gap:7px; }
.section-header::after { content:''; flex:1; height:1px; background:rgba(255,255,255,.06); }
#thud-toasts { position:fixed; bottom:20px; left:20px; z-index:999998; display:flex; flex-direction:column-reverse; gap:10px; pointer-events:none; width:340px; }
.toast { display:flex; align-items:flex-start; gap:14px; background:var(--bg-card); border-radius:var(--r); padding:16px; pointer-events:all; border:1px solid var(--border); border-left:4px solid var(--green); box-shadow:0 16px 60px rgba(0,0,0,.95); animation:toastIn .25s cubic-bezier(.34,1.56,.64,1); }
.toast.warn   { border-left-color:var(--amber); }
.toast.crit   { border-left-color:var(--red); }
.toast.info   { border-left-color:var(--blue); }
.toast.travel { border-left-color:var(--travel); }
.toast.landed { border-left-color:var(--red); background:rgba(239,68,68,.08); }
.toast.enemy-alert { border-left-color:#ff4400; background:rgba(255,68,0,.12); box-shadow:0 16px 60px rgba(0,0,0,.95),0 0 50px rgba(255,68,0,.5),0 0 0 2px #ff4400; animation:toastIn .25s cubic-bezier(.34,1.56,.64,1), enemyPulse .6s ease-in-out infinite alternate; }
@keyframes enemyPulse { from{box-shadow:0 16px 60px rgba(0,0,0,.95),0 0 30px rgba(255,68,0,.4)} to{box-shadow:0 16px 60px rgba(0,0,0,.95),0 0 70px rgba(255,68,0,.8),0 0 0 2px #ff4400} }
@keyframes toastIn  { from{opacity:0;transform:translateX(-20px) scale(.95)} to{opacity:1;transform:translateX(0) scale(1)} }
@keyframes toastOut { from{opacity:1;transform:translateX(0) scale(1)} to{opacity:0;transform:translateX(-16px) scale(.95)} }
.toast.leaving { animation:toastOut .2s ease forwards; }
.toast-icon { font-size:22px; flex-shrink:0; margin-top:1px; }
.toast-body { flex:1; min-width:0; }
.toast-title { font-size:14px; font-weight:800; color:var(--text); letter-spacing:.3px; }
.toast-msg   { font-size:12px; color:var(--dim); margin-top:4px; line-height:1.5; }
.toast-x { background:transparent; border:1px solid var(--border); color:var(--muted); border-radius:5px; width:20px; height:20px; cursor:pointer; font-size:10px; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.thud-modal-bg { position:fixed; inset:0; background:rgba(0,0,0,.85); z-index:999999; display:flex; align-items:center; justify-content:center; }
.thud-modal { background:var(--bg-card); border:1px solid var(--border); border-radius:var(--r-lg); padding:26px; width:340px; box-shadow:0 32px 80px rgba(0,0,0,.9); }
.thud-modal h3 { font-size:15px; font-weight:700; color:var(--text); margin-bottom:7px; }
.thud-modal p  { font-size:12px; color:var(--muted); margin-bottom:16px; line-height:1.7; }
.thud-modal input { width:100%; background:var(--bg); border:1px solid var(--border); border-radius:var(--r-sm); padding:10px 12px; color:var(--text); font-family:var(--mono); font-size:12px; outline:none; margin-bottom:11px; }
.thud-modal input:focus { border-color:var(--accent); }
.thud-modal textarea { width:100%; background:var(--bg); border:1px solid var(--border); border-radius:var(--r-sm); padding:10px 12px; color:var(--text); font-family:var(--font); font-size:12px; outline:none; margin-bottom:11px; min-height:70px; resize:vertical; }
.modal-btns { display:flex; gap:8px; justify-content:flex-end; }
.modal-save   { background:var(--green); color:#000; border:none; border-radius:var(--r-sm); padding:9px 18px; font-size:12px; font-weight:700; cursor:pointer; font-family:var(--font); }
.modal-cancel { background:var(--bg-el); color:var(--muted); border:1px solid var(--border); border-radius:var(--r-sm); padding:9px 14px; font-size:12px; font-weight:600; cursor:pointer; font-family:var(--font); }
.thud-resize-se { position:absolute; right:0; bottom:0; width:18px; height:18px; cursor:se-resize; z-index:10; }
.thud-resize-se::after { content:''; position:absolute; right:4px; bottom:4px; width:7px; height:7px; border-right:2px solid var(--muted); border-bottom:2px solid var(--muted); opacity:.2; }
.thud-resize-e { position:absolute; right:-3px; top:20px; bottom:20px; width:8px; cursor:ew-resize; z-index:9; }
.thud-resize-s { position:absolute; left:20px; right:20px; bottom:-3px; height:8px; cursor:ns-resize; z-index:9; }
#thud-fab { position:fixed; z-index:99998; width:36px; height:36px; border-radius:10px; background:linear-gradient(135deg,#1a0505,#2a0a0a); border:1px solid rgba(239,68,68,.3); box-shadow:0 4px 16px rgba(0,0,0,.85); cursor:grab; display:flex; align-items:center; justify-content:center; transition:all .2s; overflow:hidden; }
#thud-fab:active { cursor:grabbing; transform:scale(.93); }
#thud-fab:hover { border-color:rgba(239,68,68,.7); box-shadow:0 4px 20px rgba(239,68,68,.4); }
#thud-fab.on { border-color:rgba(239,68,68,.5); box-shadow:0 4px 20px rgba(239,68,68,.35); }
#thud-fab svg { width:24px; height:24px; filter:drop-shadow(0 0 4px rgba(239,68,68,.8)); }
.chain-block { padding:8px 14px; border-bottom:1px solid var(--border); flex-shrink:0; }
.chain-idle { display:flex; align-items:center; }
.chain-active-row { display:flex; align-items:center; }
.chain-hits { font-family:var(--mono); font-size:18px; font-weight:800; color:var(--chain); }
.chain-hits-unit { font-size:9px; color:var(--muted); font-weight:600; text-transform:uppercase; align-self:flex-end; margin-bottom:2px; }
.chain-divider { width:1px; height:24px; background:rgba(255,255,255,.1); }
.chain-timer { font-family:var(--mono); font-size:16px; font-weight:800; color:var(--green); }
.chain-timer.warn { color:var(--chain); }
.chain-mult { font-family:var(--mono); font-size:15px; font-weight:800; color:var(--amber); }
.chain-prog { height:3px; background:rgba(255,255,255,.06); border-radius:2px; overflow:hidden; margin-top:6px; }
.chain-prog-fill { height:100%; border-radius:2px; background:var(--chain); transition:width .5s; }
.pulse-dot { width:7px; height:7px; border-radius:50%; background:var(--chain); box-shadow:0 0 8px var(--chain); animation:pipPulse 1s ease-in-out infinite; flex-shrink:0; }
.war-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:7px; }
.war-cell { background:var(--bg-el); border:1px solid var(--border); border-radius:var(--r-sm); padding:12px 5px; text-align:center; }
.war-cell .wv { font-weight:700; font-size:20px; line-height:1; font-family:var(--mono); }
.war-cell .wl { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.5px; margin-top:5px; }
.enemy-row { padding:12px 14px; border-bottom:1px solid rgba(255,255,255,.05); display:flex; flex-direction:column; gap:6px; }
.enemy-row:last-child { border-bottom:none; }
.enemy-row:hover { background:rgba(255,255,255,.02); }
.enemy-row.in-hospital { background:rgba(239,68,68,.06); border-left:3px solid var(--red); }
.enemy-row.traveling   { background:rgba(99,102,241,.05); border-left:3px solid var(--travel); }
.enemy-top { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.enemy-name-link { font-size:13px; font-weight:800; color:var(--text); text-decoration:none; }
.enemy-name-link:hover { color:var(--red); }
.enemy-level { font-size:10px; font-family:var(--mono); font-weight:700; color:var(--amber); }
.enemy-meta { display:flex; gap:6px; flex-wrap:wrap; align-items:center; }
.enemy-tag { font-size:9px; font-weight:700; padding:2px 6px; border-radius:4px; white-space:nowrap; }
.etag-hosp   { background:rgba(239,68,68,.2);  color:var(--red);    border:1px solid rgba(239,68,68,.4); }
.etag-travel { background:rgba(99,102,241,.15); color:var(--accent2); border:1px solid rgba(99,102,241,.3); }
.etag-ok     { background:rgba(16,185,129,.1);  color:var(--green);  border:1px solid rgba(16,185,129,.2); }
.etag-jail   { background:rgba(245,158,11,.1);  color:var(--amber);  border:1px solid rgba(245,158,11,.2); }
.etag-job    { background:rgba(59,130,246,.08); color:var(--blue);   border:1px solid rgba(59,130,246,.15); }
.enemy-note { font-size:10px; color:var(--muted); font-style:italic; padding:4px 8px; background:rgba(0,0,0,.2); border-radius:4px; border-left:2px solid var(--amber); }
.enemy-actions { display:flex; gap:5px; flex-wrap:wrap; }
.enemy-action-btn { display:inline-flex; align-items:center; gap:3px; padding:4px 10px; border-radius:6px; font-size:10px; font-weight:700; text-decoration:none; cursor:pointer; border:none; font-family:var(--font); transition:all .15s; }
.eab-attack  { background:rgba(239,68,68,.15);  border:1px solid rgba(239,68,68,.25);  color:var(--red); }
.eab-attack:hover { background:rgba(239,68,68,.3); }
.eab-profile { background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.1); color:var(--dim); }
.eab-profile:hover { border-color:var(--accent); color:var(--accent2); }
.eab-note    { background:rgba(245,158,11,.1);  border:1px solid rgba(245,158,11,.2);  color:var(--amber); }
.eab-note:hover { background:rgba(245,158,11,.2); }
.eab-remove  { background:rgba(255,255,255,.04); border:1px solid rgba(255,255,255,.08); color:var(--muted); }
.eab-remove:hover { background:rgba(239,68,68,.15); border-color:var(--red); color:var(--red); }
.enemy-add-row { display:flex; gap:6px; align-items:center; }
.enemy-id-input { flex:1; background:var(--bg); border:1px solid var(--border); border-radius:var(--r-sm); padding:7px 11px; color:var(--text); font-family:var(--mono); font-size:12px; outline:none; }
.enemy-id-input:focus { border-color:var(--red); }
.loading-state { display:flex; align-items:center; justify-content:center; padding:40px; color:var(--muted); font-size:12px; letter-spacing:1px; animation:opPulse 1.5s ease-in-out infinite; }
@keyframes opPulse { 0%,100%{opacity:1} 50%{opacity:.3} }
.empty-state { display:flex; flex-direction:column; align-items:center; justify-content:center; padding:36px 18px; color:var(--muted); gap:10px; text-align:center; }
.empty-state .es-icon { font-size:32px; opacity:.2; }
.empty-state .es-text { font-size:12px; letter-spacing:.5px; font-weight:600; }
.empty-state .es-sub  { font-size:11px; opacity:.6; }
.toggle-more { display:inline-flex; align-items:center; gap:5px; padding:5px 11px; border-radius:20px; border:1px solid var(--border); color:var(--muted); cursor:pointer; font-size:10px; font-weight:600; transition:all .15s; margin-top:7px; }
.toggle-more:hover { border-color:var(--accent); color:var(--accent2); }
.ts { font-family:var(--mono); font-size:10px; color:var(--muted); }
.fullscreen-alert { position:fixed; inset:0; background:rgba(2,4,8,.97); display:none; flex-direction:column; align-items:center; justify-content:center; z-index:9999999; }
.fullscreen-alert.active { display:flex; animation:fadeIn .4s ease; }
@keyframes fadeIn { from{opacity:0} to{opacity:1} }
.fs-box { text-align:center; padding:48px; border-radius:20px; max-width:420px; background:rgba(99,102,241,.06); border:2px solid var(--accent); box-shadow:0 0 80px rgba(99,102,241,.3); }
.fs-title { font-size:20px; font-weight:700; letter-spacing:2px; text-transform:uppercase; margin:16px 0; }
.fs-msg   { font-size:15px; color:var(--dim); line-height:1.6; }
.fs-close { margin-top:24px; background:rgba(99,102,241,.2); border:1px solid var(--accent); color:var(--accent2); border-radius:var(--r-sm); padding:12px 28px; font-size:12px; font-weight:700; cursor:pointer; font-family:var(--font); }
.scan-btn { display:inline-flex; align-items:center; gap:5px; padding:7px 14px; border-radius:var(--r-sm); background:rgba(99,102,241,.15); border:1px solid rgba(99,102,241,.3); color:var(--accent2); font-size:11px; font-weight:700; cursor:pointer; font-family:var(--font); transition:all .15s; }
.scan-btn:hover { background:rgba(99,102,241,.3); }
.scan-btn:disabled { opacity:.4; cursor:not-allowed; }
.spinning { animation:spin 1s linear infinite; }
@keyframes spin { to { transform:rotate(360deg); } }
.sort-btn { padding:4px 9px; border-radius:6px; border:1px solid var(--border); background:var(--bg-el); color:var(--muted); font-size:10px; font-weight:700; cursor:pointer; font-family:var(--font); transition:all .15s; }
.sort-btn.active { border-color:var(--accent); color:var(--accent2); background:rgba(99,102,241,.1); }
.threshold-input { background:var(--bg); border:1px solid var(--border); border-radius:5px; padding:3px 7px; color:var(--accent2); font-family:var(--mono); font-size:11px; width:50px; text-align:center; outline:none; }
.threshold-input:focus { border-color:var(--accent); }
.fab-pin-row { display:flex; align-items:center; justify-content:space-between; padding:9px 14px; border-bottom:1px solid rgba(255,255,255,.04); }
.fab-pin-lbl { font-size:12px; font-weight:600; color:var(--text); }
.fab-pin-desc { font-size:10px; color:var(--muted); margin-top:1px; }
`;
 
    const SHAYA_LOGO_SVG = `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="sg" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#ff2222"/><stop offset="50%" style="stop-color:#cc0000"/><stop offset="100%" style="stop-color:#880000"/></linearGradient></defs><polygon points="62,10 38,10 28,28 52,28 40,48 58,48 30,90 72,90 80,70 56,70 68,50 50,50" fill="url(#sg)"/><polygon points="68,8 74,14 66,18" fill="#ff4444" opacity="0.8"/><polygon points="30,8 24,16 34,14" fill="#dd2222" opacity="0.7"/><polygon points="26,88 20,82 30,80" fill="#ff3333" opacity="0.75"/><polygon points="74,92 80,84 70,86" fill="#cc1111" opacity="0.7"/></svg>`;
    const FAB_LOGO_SVG   = `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="fg" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#ff3333"/><stop offset="100%" style="stop-color:#aa0000"/></linearGradient></defs><polygon points="62,10 38,10 28,28 52,28 40,48 58,48 30,90 72,90 80,70 56,70 68,50 50,50" fill="url(#fg)"/><polygon points="68,8 74,14 66,18" fill="#ff5555" opacity="0.9"/><polygon points="30,8 24,16 34,14" fill="#ee2222" opacity="0.8"/><polygon points="26,88 20,82 30,80" fill="#ff4444" opacity="0.8"/><polygon points="74,92 80,84 70,86" fill="#cc1111" opacity="0.75"/></svg>`;
 
    // ═══════════════════════════════════════════════════════════════
    // UTILITY
    // ═══════════════════════════════════════════════════════════════
    class Utils {
        static fmtMoney(n) {
            if (!n && n !== 0) return '—';
            const abs = Math.abs(n), sign = n < 0 ? '-' : '';
            if (abs >= 1e9) return sign + '$' + (abs / 1e9).toFixed(2) + 'B';
            if (abs >= 1e6) return sign + '$' + (abs / 1e6).toFixed(2) + 'M';
            if (abs >= 1e3) return sign + '$' + (abs / 1e3).toFixed(1) + 'K';
            return sign + '$' + abs.toLocaleString('de-DE');
        }
        static fmtStat(n) {
            if (!n && n !== 0) return '—';
            if (n >= 1e9) return (n / 1e9).toFixed(2) + 'B';
            if (n >= 1e6) return (n / 1e6).toFixed(2) + 'M';
            if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
            return n.toLocaleString('de-DE');
        }
        static fmtTravel(sec) { if (sec <= 0) return '—'; const h = Math.floor(sec/3600), m = Math.ceil((sec%3600)/60); return h > 0 ? `${h}h ${m}m` : (m <= 0 ? '< 1m' : `${m}m`); }
        static fmtHM(sec) { if (!sec || sec <= 0) return '—'; const h = Math.floor(sec/3600), m = Math.floor((sec%3600)/60); if (h > 0) return `${h}h ${m}m`; if (m > 0) return `${m}m`; return '< 1m'; }
        static fmtDhm(sec) { if (!sec || sec <= 0) return 'Fertig'; const d=Math.floor(sec/86400),h=Math.floor((sec%86400)/3600),m=Math.floor((sec%3600)/60); if(d>0)return`${d}T ${h}h`; if(h>0)return`${h}h ${m}m`; return`${m}m`; }
        static fmtSec(sec) { if (!sec || sec <= 0) return '0s'; const h=Math.floor(sec/3600),m=Math.floor((sec%3600)/60),s=sec%60; if(h>0)return`${h}h ${m}m`; if(m>0)return`${m}m ${s}s`; return`${s}s`; }
        static arrTime(secLeft) { if (!secLeft || secLeft <= 0) return '—'; return new Date(Date.now() + secLeft*1000).toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'}); }
        static tctTime() { return new Date().toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit',timeZone:'UTC'}); }
        static pctBar(pct, color, size = '') { const w = Math.min(100,Math.max(0,pct||0)); return `<div class="bar ${size}"><div class="bar-fill" style="width:${w}%;background:${color};"></div></div>`; }
        static escHtml(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
        static inactiveAgo(ts) {
            if (!ts) return { text:'?', cls:'ago-d' };
            const s=Math.floor(Date.now()/1000-ts), m=Math.floor(s/60), h=Math.floor(s/3600), d=Math.floor(s/86400);
            if (s < 3600) return { text:m+'m', cls:'ago-m' };
            if (h < 24)   return { text:h+'h', cls:'ago-h' };
            return { text:d+'d', cls:'ago-d' };
        }
        static now() { return Math.floor(Date.now()/1000); }
        static buildDonut(data, total) {
            const r=28,cx=32,cy=32,circ=2*Math.PI*r; let off=0;
            const segs = data.map(({count,color}) => {
                if (!count||!total) return '';
                const dash=(count/total)*circ;
                const seg=`<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${color}" stroke-width="5" stroke-dasharray="${dash} ${circ-dash}" stroke-dashoffset="${-off}" stroke-linecap="butt"/>`;
                off+=dash; return seg;
            }).filter(Boolean);
            if (!segs.length) segs.push(`<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="#2a2a30" stroke-width="5"/>`);
            return `<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" style="width:52px;height:52px;transform:rotate(-90deg)"><circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="#18181c" stroke-width="5"/>${segs.join('')}</svg>`;
        }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // AUDIO
    // ═══════════════════════════════════════════════════════════════
    class AudioManager {
        constructor(store) { this.store = store; this._ctx = null; }
        get ctx() { if (!this._ctx) { try { this._ctx = new (window.AudioContext||window.webkitAudioContext)(); } catch(e){} } return this._ctx; }
        play(type) {
            if (!this.store.get('sound') && type !== 'enemy') return;
            if (!this.ctx) return;
            const c=this.ctx, now=c.currentTime, p=this.store.get('soundProfile')||'classic';
            const note=(freq,start,dur,vol,wave='sine')=>{const osc=c.createOscillator(),g=c.createGain();osc.connect(g);g.connect(c.destination);osc.type=wave;osc.frequency.value=freq;g.gain.setValueAtTime(0,now+start);g.gain.linearRampToValueAtTime(vol,now+start+0.03);g.gain.exponentialRampToValueAtTime(0.001,now+start+dur);osc.start(now+start);osc.stop(now+start+dur+0.05);};
            if (type==='enemy') { [0,.1,.2,.3].forEach(o=>note(880,o,.08,.25,'sawtooth')); note(440,.05,.3,.15,'square'); return; }
            if (p==='subtle')   { if(type==='travel_warn'){note(440,0,.2,.08);note(550,.25,.2,.08);}else if(type==='travel_crit'){[0,.15,.3].forEach(o=>note(660,o,.12,.1));}else if(type==='full'){note(330,0,.3,.08);}else note(400,0,.25,.06); return; }
            if (p==='military') { if(type==='travel_crit'){[0,.12,.24,.36].forEach(o=>note(1400,o,.07,.2,'sawtooth'));}else{note(1000,0,.05,.15,'square');note(800,.08,.05,.1,'square');} return; }
            if (type==='travel_warn')   { [0,.22].forEach(o=>note(660,o,.2,.25)); }
            else if (type==='travel_crit')  { [0,.16,.32].forEach(o=>note(880,o,.13,.18,'square')); }
            else if (type==='landing')  { [0,.15,.3].forEach(o=>note(520,o,.15,.2)); }
            else if (type==='full')     { const osc=c.createOscillator(),g=c.createGain();osc.connect(g);g.connect(c.destination);osc.type='sine';osc.frequency.setValueAtTime(440,now);osc.frequency.linearRampToValueAtTime(880,now+.4);g.gain.setValueAtTime(0,now);g.gain.linearRampToValueAtTime(.25,now+.08);g.gain.linearRampToValueAtTime(0,now+.5);osc.start(now);osc.stop(now+.55); }
            else { note(520,0,.4,.18); }
        }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // STORE / TOAST / API
    // ═══════════════════════════════════════════════════════════════
    class Store {
        get(key, def) { const v = GM_getValue('thud_'+key, undefined); return v !== undefined ? v : def; }
        set(key, val) { GM_setValue('thud_'+key, val); return val; }
    }
 
    class ToastManager {
        constructor() { this._fired = {}; }
        show(icon, title, msg, style='', duration=10000) {
            let c = document.getElementById('thud-toasts');
            if (!c) { c = document.createElement('div'); c.id='thud-toasts'; document.body.appendChild(c); }
            const t = document.createElement('div');
            t.className = `toast ${style}`;
            t.innerHTML = `<div class="toast-icon">${icon}</div><div class="toast-body"><div class="toast-title">${title}</div><div class="toast-msg">${msg}</div></div><button class="toast-x">✕</button>`;
            t.querySelector('.toast-x').addEventListener('click', () => { t.classList.add('leaving'); setTimeout(()=>t.remove(),220); });
            c.appendChild(t);
            setTimeout(() => { if (t.parentNode) { t.classList.add('leaving'); setTimeout(()=>t.remove(),220); } }, duration);
        }
        showLandingTimer(destName) {
            let c = document.getElementById('thud-toasts');
            if (!c) { c = document.createElement('div'); c.id='thud-toasts'; document.body.appendChild(c); }
            const t = document.createElement('div'); t.className='toast landed';
            const topItems = (DEST_TOP_ITEMS[destName]||[]).slice(0,2).join(' · ');
            t.innerHTML = `<div class="toast-icon">🛬</div><div class="toast-body"><div class="toast-title">GELANDET: ${Utils.escHtml(destName)}</div><div class="toast-msg">⏱ <span id="thud-land-timer">15</span>s Einkaufszeit${topItems?`<br>🎯 ${topItems}`:''}</div></div><button class="toast-x">✕</button>`;
            t.querySelector('.toast-x').addEventListener('click', ()=>{ t.classList.add('leaving'); setTimeout(()=>t.remove(),220); });
            c.appendChild(t);
            let rem = SHOPPING_TIME_SEC;
            const iv = setInterval(()=>{ rem--; const el=t.querySelector('#thud-land-timer'); if(el)el.textContent=rem; if(rem<=0){clearInterval(iv);if(t.parentNode){t.classList.add('leaving');setTimeout(()=>t.remove(),220);}} },1000);
            hud.audio.play('landing');
        }
        fire(key, icon, title, msg, style, audio) { if(this._fired[key])return; this._fired[key]=true; hud.audio.play(audio||'notify'); this.show(icon,title,msg,style); }
        reset(key) { delete this._fired[key]; }
    }
 
    class TornAPI {
        constructor(store) { this.store = store; }
        get key() { return this.store.get('apiKey',''); }
        call(url, cb) {
            if (!this.key) { cb(null,'NO_KEY'); return; }
            GM_xmlhttpRequest({ method:'GET', url,
                onload: r => { try { const d=JSON.parse(r.responseText); if(d.error)cb(null,d.error.code); else cb(d,null); } catch(e){ cb(null,'PARSE'); } },
                onerror: () => cb(null,'NET'),
            });
        }
        v2(path, cb) { this.call(`${API_BASE}/v2/${path}&key=${this.key}`, cb); }
        userBasicAndProfile(cb) { this.v2('user?selections=basic,profile', cb); }
        userTravel(cb)           { this.v2('user?selections=travel', cb); }
        userBars(cb)             { this.v2('user?selections=bars', cb); }
        userCooldowns(cb)        { this.v2('user?selections=cooldowns', cb); }
        userEducation(cb)        { this.v2('user?selections=education', cb); }
        userBattleStats(cb)      { this.v2('user?selections=battlestats', cb); }
        userWorkStats(cb)        { this.v2('user?selections=workstats', cb); }
        userNetworth(cb)         { this.v2('user?selections=networth', cb); }
        factionBasicMembers(cb)  { this.v2('faction?selections=basic,members', cb); }
        factionChain(cb)         { this.v2('faction?selections=chain', cb); }
        companyProfile(cb)       { this.v2('company?selections=profile', cb); }
        companyEmployees(cb)     { this.v2('company?selections=employees', cb); }
        tornBountiesPage(offset, cb) { this.v2(`torn?selections=bounties&offset=${offset}`, cb); }
        playerProfile(playerId, cb) { this.call(`${API_BASE}/v2/user/${playerId}?selections=basic,profile&key=${this.key}`, cb); }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // STATE
    // ═══════════════════════════════════════════════════════════════
    class StateManager {
        constructor(store) {
            this.store = store;
            this.userBasic=null; this.userProfile=null; this.userTravel=null;
            this.bars=null; this.cooldowns=null; this.education=null;
            this.battleStats=null; this.workStats=null;
            this.faction={}; this.members={}; this.chain=null; this.chainEndTime=null;
            this.companyProfile=null; this.companyEmployees=[];
            this.networthData=null; this.networthHistory=store.get('nwHistory',[]);
            // Bounty
            this.bountyData=null; this.bountyAllData=null; this.bountyLastFetch=0;
            this.bountySort=store.get('bountySort','reward');
            this.bountySearch='';
            this.bountyFilterHosp=store.get('bountyFilterHosp',false);
            this.bountyLevelMin=store.get('bountyLevelMin',1);
            this.bountyLevelMax=store.get('bountyLevelMax',100);
            this.bountyRewardMin=store.get('bountyRewardMin',0);
            this.bountyRewardMax=store.get('bountyRewardMax',0);
            this.bountyDisplayCount=80; this.bountyLoadedPages=0;
            this.bountyLoading=false; this.bountyScanningAll=false;
            // Enemy
            this.enemies=store.get('enemies',[]);
            this.enemyData={};
            this.enemyFetchRunning=false;
            this._enemyTravelAlerted=store.get('_enemyTravelAlerted',{});
            // Misc
            this.lastUpdate=null; this.uptimeSec=0;
            this.showAllOnline=false; this.showAllOffline=false;
            this._fsAlertFired=false; this._landingFired=false;
            this._lastTravelSec=0; this._prevTravelDest='';
            this.energyThresholds=store.get('energyThresholds',[50,75,100]);
            this.nerveThresholds=store.get('nerveThresholds',[50,100]);
            this._energyAlerted=store.get('_energyAlerted',{});
            this._nerveAlerted=store.get('_nerveAlerted',{});
        }
        setBountySort(v)       { this.bountySort=v; this.store.set('bountySort',v); }
        setBountyFilterHosp(v) { this.bountyFilterHosp=v; this.store.set('bountyFilterHosp',v); }
        setBountyLevelMin(v)   { this.bountyLevelMin=Number(v)||1;   this.store.set('bountyLevelMin',this.bountyLevelMin); }
        setBountyLevelMax(v)   { this.bountyLevelMax=Number(v)||100; this.store.set('bountyLevelMax',this.bountyLevelMax); }
        setBountyRewardMin(v)  { this.bountyRewardMin=Number(v)||0;  this.store.set('bountyRewardMin',this.bountyRewardMin); }
        setBountyRewardMax(v)  { this.bountyRewardMax=Number(v)||0;  this.store.set('bountyRewardMax',this.bountyRewardMax); }
        addEnemy(id, name, note) { if(this.enemies.find(e=>String(e.id)===String(id)))return false; this.enemies.push({id:String(id),name:name||`#${id}`,note:note||'',addedAt:Utils.now()}); this.store.set('enemies',this.enemies); return true; }
        removeEnemy(id) { this.enemies=this.enemies.filter(e=>String(e.id)!==String(id)); delete this.enemyData[id]; this.store.set('enemies',this.enemies); }
        updateEnemyNote(id, note) { const e=this.enemies.find(e=>String(e.id)===String(id)); if(e){e.note=note;this.store.set('enemies',this.enemies);} }
        updateEnemyData(id, data) { this.enemyData[String(id)]=data; }
        get alarms() { return this.store.get('alarms',{}); }
        setAlarm(k,v) { const a=this.alarms; a[k]=v; this.store.set('alarms',a); }
        isAlarm(k) { const d=ALARM_DEFAULTS[k]; return this.alarms[k]!==undefined?this.alarms[k]:(d?d.enabled:false); }
        get visibility() { return this.store.get('visibility',{}); }
        isVisible(k) { const v=this.visibility; return v[k]!==undefined?v[k]:(VISIBILITY_DEFAULTS[k]?VISIBILITY_DEFAULTS[k].enabled:true); }
        setVisible(k,v) { const vis=this.visibility; vis[k]=v; this.store.set('visibility',vis); }
        get travelAlerts() { return this.store.get('travelAlerts',{}); }
        isTravelAlert(k) { const t=this.travelAlerts; return t[k]!==undefined?t[k]:true; }
        setTravelAlert(k,v) { const t=this.travelAlerts; t[k]=v; this.store.set('travelAlerts',t); }
        setEnergyThresholds(arr) { this.energyThresholds=arr; this.store.set('energyThresholds',arr); }
        setNerveThresholds(arr)  { this.nerveThresholds=arr;  this.store.set('nerveThresholds',arr); }
    }
 
    const ALARM_DEFAULTS = {
        travel_warn:    { enabled:true,  label:'✈ Travel Warnung',      desc:'Alarm wenn Ankunft < 7 Min' },
        travel_crit:    { enabled:true,  label:'✈ Travel Kritisch',      desc:'Alarm wenn Ankunft < 2 Min' },
        landing_timer:  { enabled:true,  label:'🛬 Landing Timer',       desc:'15s Countdown bei Landung' },
        energy_full:    { enabled:true,  label:'⚡ Energie Voll',         desc:'Alarm wenn Energie 100%' },
        energy_thresh:  { enabled:true,  label:'⚡ Energie Schwellwert',  desc:'Alarm bei konfigurierten Werten' },
        energy_over151: { enabled:false, label:'⚡ Energie über 151',     desc:'Alarm wenn Energie > 151 (Happy Jump)' },
        nerve_full:     { enabled:true,  label:'🧠 Nerve Voll',           desc:'Alarm wenn Nerve 100%' },
        nerve_thresh:   { enabled:true,  label:'🧠 Nerve Schwellwert',    desc:'Alarm bei konfigurierten Werten' },
        hp_crit:        { enabled:true,  label:'❤ HP unter 50%',         desc:'Toast-Alarm' },
        hospital_free:  { enabled:true,  label:'🏥 Krankenhaus Frei',     desc:'Alarm letzte 60 Sek' },
        jail_free:      { enabled:true,  label:'🚔 Gefängnis Frei',       desc:'Alarm letzte 60 Sek' },
        drug_ready:     { enabled:false, label:'💊 Drogen Bereit',        desc:'Alarm wenn Drug-CD weg' },
        booster_ready:  { enabled:false, label:'🧪 Booster Bereit',       desc:'Alarm wenn Booster-CD weg' },
        medical_ready:  { enabled:false, label:'💉 Medical Bereit',       desc:'Alarm wenn Medical-CD weg' },
        chain_warn:     { enabled:true,  label:'⛓ Chain Warnung',        desc:'Alarm wenn Chain < 1 Min' },
        enemy_travel:   { enabled:true,  label:'🎯 Enemy reist ab',       desc:'Alarm wenn Enemy-Target abreist' },
    };
 
    const VISIBILITY_DEFAULTS = {
        show_happy:       { enabled:true,  label:'😊 Happy Bar'          },
        show_jail:        { enabled:true,  label:'🚔 Gefängnis'          },
        show_hospital:    { enabled:true,  label:'🏥 Krankenhaus'        },
        show_drug_cd:     { enabled:true,  label:'💊 Drug CD'            },
        show_booster_cd:  { enabled:true,  label:'🧪 Booster CD'         },
        show_medical_cd:  { enabled:true,  label:'💉 Medical CD'         },
        show_education:   { enabled:true,  label:'📚 Lehrgang'           },
        show_tip:         { enabled:true,  label:'💡 Smart Tipp'         },
        show_quick_links: { enabled:true,  label:'🔗 Quick Links'        },
        show_tct_time:    { enabled:true,  label:'🕒 TCT Zeit'           },
        show_battle_stats:{ enabled:true,  label:'⚔ Battle Stats (Ich)' },
    };
 
    const TABS_DEF = [
        { id:'personal',      icon:'👤', label:'Ich'      },
        { id:'faction',       icon:'⚔',  label:'Fraktion' },
        { id:'bounty',        icon:'🎯',  label:'Bounty'   },
        { id:'enemy',         icon:'💀',  label:'Enemy'    },
        { id:'company',       icon:'🏢',  label:'Firma'    },
        { id:'networth',      icon:'💰',  label:'Vermögen' },
        { id:'notifications', icon:'🔔',  label:'Alarme'   },
        { id:'settings',      icon:'⚙',   label:'Settings' },
    ];
 
    // ═══════════════════════════════════════════════════════════════
    // ALARM CHECKER
    // ═══════════════════════════════════════════════════════════════
    class AlarmChecker {
        constructor(state, toast) { this.state=state; this.toast=toast; }
        run() {
            const s=this.state, now=Utils.now(), t=this.toast;
            if (!s.userBasic && !s.userProfile) return;
            const travel=s.userTravel?.travel||{};
            const tSec=Math.max(0,Number(travel.time_left)||0), dest=travel.destination||'';
            // Landing timer
            if (s._lastTravelSec>5 && tSec<=5 && s._prevTravelDest && s._prevTravelDest!=='Torn' && s._prevTravelDest!=='Torn City') {
                if (!s._landingFired && s.isAlarm('landing_timer')) { s._landingFired=true; t.showLandingTimer(s._prevTravelDest); }
            }
            if (tSec>5) { s._landingFired=false; if(dest) s._prevTravelDest=dest; }
            s._lastTravelSec=tSec;
            const flying=tSec>0;
            if (!flying) { t.reset('travel_warn'); t.reset('travel_crit'); s._fsAlertFired=false; }
            else {
                if (tSec>TRAVEL_WARN_SEC) t.reset('travel_warn');
                if (tSec>TRAVEL_CRIT_SEC) t.reset('travel_crit');
                if (s.isAlarm('travel_warn') && tSec<=TRAVEL_WARN_SEC && tSec>TRAVEL_CRIT_SEC && s.isTravelAlert('toast'))
                    t.fire('travel_warn','✈','ANKUNFT BALD',`${dest} — noch ${Utils.fmtHM(tSec)}`,'travel','travel_warn');
                if (s.isAlarm('travel_crit') && tSec<=TRAVEL_CRIT_SEC) {
                    if (s.isTravelAlert('toast')) t.fire('travel_crit','⚠','KRITISCH – KURZ VOR ANKUNFT',`${dest} landet in ${Utils.fmtTravel(tSec)}!`,'crit','travel_crit');
                    if (s.isTravelAlert('fullscreen') && !s._fsAlertFired) {
                        s._fsAlertFired=true;
                        const fs=document.getElementById('thud-fs-alert');
                        if (fs) { document.getElementById('thud-fs-msg').innerHTML=`${dest} — Ankunft in ca. 1 Minute!`; fs.classList.add('active'); setTimeout(()=>fs.classList.remove('active'),12000); }
                    }
                }
            }
            const energy=s.bars?.energy;
            if (energy) {
                const pct=Math.round((energy.current/energy.maximum)*100);
                if (pct<100) t.reset('energy_full');
                if (s.isAlarm('energy_full') && pct>=100 && energy.current<=HAPPY_JUMP_THRESHOLD) t.fire('energy_full','⚡','ENERGIE VOLL!',`${energy.current}/${energy.maximum} — Gym oder Chains!`,'warn','full');
                if (energy.current>HAPPY_JUMP_THRESHOLD) { if(s.isAlarm('energy_over151')) t.fire('energy_over151','⚡',`ENERGIE ÜBER ${HAPPY_JUMP_THRESHOLD}!`,`${energy.current} Energie — Happy Jump Zone!`,'crit','notify'); }
                else { t.reset('energy_over151'); }
                if (s.isAlarm('energy_thresh')) {
                    for (const thresh of (s.energyThresholds||[])) {
                        if (thresh>=100) continue;
                        if (pct>=thresh && !s._energyAlerted[thresh]) { s._energyAlerted[thresh]=true; t.show('⚡',`ENERGIE ${thresh}%`,`${energy.current}/${energy.maximum} Energie erreicht!`,'warn',8000); hud.audio.play('notify'); }
                        else if (pct<thresh-10) { delete s._energyAlerted[thresh]; }
                    }
                }
            }
            const nerve=s.bars?.nerve;
            if (nerve) {
                const pct=Math.round((nerve.current/nerve.maximum)*100);
                if (pct<100) t.reset('nerve_full');
                if (s.isAlarm('nerve_full') && pct>=100) t.fire('nerve_full','🧠','NERVE VOLL!',`${nerve.current}/${nerve.maximum} — Crimes abarbeiten!`,'warn','full');
                if (s.isAlarm('nerve_thresh')) {
                    for (const thresh of (s.nerveThresholds||[])) {
                        if (thresh>=100) continue;
                        if (pct>=thresh && !s._nerveAlerted[thresh]) { s._nerveAlerted[thresh]=true; t.show('🧠',`NERVE ${thresh}%`,`${nerve.current}/${nerve.maximum} Nerve erreicht!`,'info',8000); hud.audio.play('notify'); }
                        else if (pct<thresh-10) { delete s._nerveAlerted[thresh]; }
                    }
                }
            }
            const life=s.bars?.life||s.userProfile?.life||{};
            if (life.maximum) { const p=(life.current/life.maximum)*100; if(p>=50)t.reset('hp_crit'); if(s.isAlarm('hp_crit')&&p<50)t.fire('hp_crit','❤','HP KRITISCH!',`Nur noch ${Math.round(p)}% HP! Medical nutzen!`,'crit','notify'); }
            const statusObj=s.userProfile?.status||{};
            const hospState=(statusObj.state||'').toLowerCase();
            const hospUntil=Number(statusObj.until??0);
            const hospSec=hospState==='hospital'&&hospUntil>now?hospUntil-now:0;
            if (hospSec>60) t.reset('hospital_free');
            if (s.isAlarm('hospital_free')&&hospSec>0&&hospSec<=60) t.fire('hospital_free','🏥','KRANKENHAUS FREI','Du wirst gleich entlassen!','','notify');
            const jailUntil=(statusObj.state||'').toLowerCase()==='jail'?Number(statusObj.until??0):0;
            const jailSec=jailUntil>now?jailUntil-now:0;
            if (jailSec>60) t.reset('jail_free');
            if (s.isAlarm('jail_free')&&jailSec>0&&jailSec<=60) t.fire('jail_free','🚔','GEFÄNGNIS FREI','Du wirst gleich entlassen!','crit','notify');
            const cd=s.cooldowns?.cooldowns||{};
            const _cdVal=(v)=>Number(typeof v==='object'?(v?.cooldown_until??0):(v??0));
            const drugSec=Math.max(0,_cdVal(cd.drug)-now), boostSec=Math.max(0,_cdVal(cd.booster)-now), medSec=Math.max(0,_cdVal(cd.medical)-now);
            if (drugSec>120)  t.reset('drug_ready');
            if (boostSec>120) t.reset('booster_ready');
            if (medSec>120)   t.reset('medical_ready');
            if (s.isAlarm('drug_ready')    && _cdVal(cd.drug)>0    && drugSec<=0)  t.fire('drug_ready',   '💊','DROGEN BEREIT',  'Drug-Cooldown abgelaufen!',   'info','notify');
            if (s.isAlarm('booster_ready') && _cdVal(cd.booster)>0 && boostSec<=0) t.fire('booster_ready','🧪','BOOSTER BEREIT', 'Booster-Cooldown abgelaufen!','info','notify');
            if (s.isAlarm('medical_ready') && _cdVal(cd.medical)>0 && medSec<=0)   t.fire('medical_ready','💉','MEDICAL BEREIT', 'Cooldown abgelaufen!',        'info','notify');
            if (s.isAlarm('enemy_travel')) {
                for (const enemy of s.enemies) {
                    const ed=s.enemyData[enemy.id]; if(!ed) continue;
                    const eStat=(ed.status?.state||'').toLowerCase(), eDest=ed.status?.description||'';
                    const travelKey=`${enemy.id}_${eDest}`;
                    if (eStat==='traveling' && !s._enemyTravelAlerted[travelKey]) {
                        s._enemyTravelAlerted[travelKey]=true; hud.store.set('_enemyTravelAlerted',s._enemyTravelAlerted);
                        hud.audio.play('enemy'); t.show('⚔',`⚠ ENEMY REIST AB!`,`${enemy.name} fliegt: ${eDest}`,'enemy-alert',20000);
                    }
                    if (eStat!=='traveling') { Object.keys(s._enemyTravelAlerted).forEach(k=>{ if(k.startsWith(enemy.id+'_'))delete s._enemyTravelAlerted[k]; }); }
                }
            }
        }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // CHAIN MANAGER
    // ═══════════════════════════════════════════════════════════════
    class ChainManager {
        constructor(state) { this.state=state; this._tick=null; }
        process(chain) {
            const s=this.state;
            if (chain&&chain.current>0) { s.chain=chain; s.chainEndTime=Date.now()+Number(chain.timeout)*1000; this.startTick(); }
            else { s.chain=null; s.chainEndTime=null; this.stopTick(); }
            this.renderSection();
            if (hud.store.get('minimized',false)) hud.renderer.renderMini();
        }
        startTick() { if(!this._tick) this._tick=setInterval(()=>this.tick(),1000); }
        stopTick()  { if(this._tick){clearInterval(this._tick);this._tick=null;} }
        tick() {
            const s=this.state; if(!s.chainEndTime){this.stopTick();return;}
            const rem=Math.max(0,s.chainEndTime-Date.now()), m=Math.floor(rem/60000), warn=rem<=CHAIN_WARN_SEC*1000;
            const el=document.getElementById('thud-chain-timer');
            if(el){el.textContent=`${m}m`;warn?el.classList.add('warn'):el.classList.remove('warn');}
            if(warn&&s.isAlarm('chain_warn'))hud.toasts.fire('chain_warn','⛓','CHAIN LÄUFT AB!',`Nur noch ${m}m!`,'crit','travel_crit');
            if(!warn)hud.toasts.reset('chain_warn');
            if(rem===0){s.chain=null;s.chainEndTime=null;this.stopTick();this.renderSection();}
        }
        renderSection() {
            const el=document.getElementById('thud-chain-block'); if(!el)return;
            const c=this.state.chain;
            if(!c||c.current===0){el.className='chain-block';el.innerHTML=`<div class="chain-idle"><div class="pulse-dot" style="opacity:.2;animation:none;background:var(--muted)"></div><span style="letter-spacing:.5px;font-size:10px;font-weight:600;margin-left:8px;">Keine aktive Chain</span></div>`;return;}
            const ms=[10,25,50,100,250,500,1000,2500,5000,10000,25000,50000,100000];
            const nM=ms.find(x=>x>c.current)||c.current, pM=ms[ms.indexOf(nM)-1]||0;
            const prog=((c.current-pM)/(nM-pM))*100;
            const mt=[[10,1],[25,1.5],[50,2],[100,2.5],[250,3],[500,3.5],[1000,4]];
            let mul=1; for(const[thresh,v]of mt)if(c.current>=thresh)mul=v;
            const rem=Math.max(0,this.state.chainEndTime-Date.now()), m=Math.floor(rem/60000), warn=rem<=CHAIN_WARN_SEC*1000;
            const isWU=c.current<CHAIN_START_HIT, hits=isWU?c.current:c.current-CHAIN_START_HIT;
            el.className='chain-block active';
            el.innerHTML=`<div class="chain-active-row"><div class="pulse-dot"></div><span style="font-size:9px;font-weight:700;letter-spacing:1px;color:var(--chain);margin-left:5px;">${isWU?'WARMUP':'CHAIN'}</span><div class="chain-hits" style="margin-left:7px;">${hits.toLocaleString()}</div><div class="chain-hits-unit" style="margin-left:2px;">hits</div><div class="chain-divider" style="margin:0 10px;"></div><div style="display:flex;flex-direction:column;align-items:center;"><div class="chain-timer ${warn?'warn':''}" id="thud-chain-timer">${m}m</div><div style="font-size:7px;color:var(--muted);text-transform:uppercase;margin-top:1px;">timeout</div></div><div style="display:flex;flex-direction:column;align-items:center;margin-left:10px;"><div class="chain-mult">×${mul}</div><div style="font-size:7px;color:var(--muted);text-transform:uppercase;margin-top:1px;">mult</div></div></div><div class="chain-prog"><div class="chain-prog-fill" style="width:${Math.max(1,Math.min(100,prog))}%"></div></div>`;
        }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // FACTION HELPER
    // ═══════════════════════════════════════════════════════════════
    class FactionHelper {
        static getStatus(member) {
            const state=(typeof member.status==='object'?member.status?.state:member.status||'').toLowerCase();
            const lastStatus=(member.last_action?.status||'').toLowerCase();
            if(state.includes('hospital'))return'hospital';
            if(state.includes('travel')||state.includes('abroad'))return'traveling';
            if(state.includes('jail'))return'jail';
            if(lastStatus==='idle')return'idle';
            if(lastStatus==='online')return'online';
            const a=Date.now()/1000-(member.last_action?.timestamp||0);
            if(a<120)return'online'; if(a<600)return'idle'; return'offline';
        }
        static statusOrder(s) { return{online:0,traveling:1,idle:2,hospital:3,jail:4,offline:5}[s]??6; }
        static statusLabel(s) { return{online:'Online',idle:'AFK',traveling:'Travel',hospital:'Hosp.',jail:'Jail',offline:'Offline'}[s]||s; }
        static parseTravelRoute(member) {
            const s=typeof member.status==='object'?member.status:{};
            const desc=(s.description||s.state||'').trim();
            const toM=desc.match(/to\s+([A-Za-z\s]+?)(?:\s*(?:from|$)|\.|,)/i);
            const frM=desc.match(/from\s+([A-Za-z\s]+?)(?:\s*(?:to|$)|\.|,)/i);
            let to='Abroad',fr='Torn City';
            const norm=(str)=>{const l=str.trim().replace(/[.,;:!?]+$/,''); return l.toLowerCase().includes('torn')?'Torn City':l.length>2?l:'Abroad';};
            if(toM?.[1]) to=norm(toM[1]);
            if(frM?.[1]) fr=frM[1].trim().toLowerCase().includes('torn')?'Torn City':frM[1].trim();
            return{from:fr,to,dir:to==='Torn City'&&fr!=='Torn City'?'home':'abroad'};
        }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // DATA FETCHER
    // ═══════════════════════════════════════════════════════════════
    class DataFetcher {
        constructor(api, state, toast, renderer) { this.api=api; this.state=state; this.toast=toast; this.renderer=renderer; }
        _opt(fetchFn, cb) { fetchFn((d,err)=>{ if(err===7||err===16)return; if(d)cb(d); }); }
        _afterPersonal() { setTimeout(()=>{ this.state.lastUpdate=new Date(); hud.alarmChecker.run(); if(hud.activeTab==='personal')this.renderer.render(); },600); }
 
        fetchPersonal() {
            if (!this.api.key) { this.renderer.render(); return; }
            this.api.userBasicAndProfile(d=>{ if(d&&(d.profile||d.basic)){this.state.userBasic=d.profile||d.basic||d;this.state.userProfile=d.profile||d;this._afterPersonal();} });
            this.api.userTravel(d=>{ if(d)this.state.userTravel=d; });
            this._opt(cb=>this.api.userBars(cb), d=>{ this.state.bars=d?.bars||d||null; });
            this._opt(cb=>this.api.userCooldowns(cb), d=>{ this.state.cooldowns=d||null; });
            this._opt(cb=>this.api.userEducation(cb), d=>{
                const edu=d?.education||d||null;
                if(edu&&typeof edu==='object'){const until=edu.current?.until??edu.until??edu.ends??0;this.state.education={until,raw:edu};}
                else this.state.education=edu;
            });
            this.api.userBattleStats((d,err)=>{
                if(err||!d)return;
                const _bv=(v)=>{if(!v&&v!==0)return 0;if(typeof v==='number')return v;if(typeof v==='object')return Number(v.modifier_value??v.value??v.current??0);return Number(v)||0;};
                let raw=null;
                if(d.battlestats&&typeof d.battlestats==='object')raw=d.battlestats;
                else if(d.battle_stats&&typeof d.battle_stats==='object')raw=d.battle_stats;
                else if('strength'in d||'defense'in d)raw=d;
                if(raw)this.state.battleStats={strength:_bv(raw.strength),defense:_bv(raw.defense),speed:_bv(raw.speed),dexterity:_bv(raw.dexterity)};
            });
            this._opt(cb=>this.api.userWorkStats(cb), d=>{
                if(d)this.state.workStats={manual:d.manual_labor??d.workstats?.manual_labor??0,intelligence:d.intelligence??d.workstats?.intelligence??0,endurance:d.endurance??d.workstats?.endurance??0};
            });
        }
 
        fetchFaction() {
            if(!this.api.key)return;
            this.api.factionBasicMembers(data=>{
                if(!data)return;
                const members=data.members||[];
                if(Array.isArray(members)){this.state.members={};members.forEach(m=>{this.state.members[m.id]=m;});}
                else this.state.members=members;
                this.state.faction={...this.state.faction,...(data.faction||data)};
                const el=document.getElementById('thud-faction-name');
                const n=this.state.faction.name||this.state.faction.faction?.name;
                if(el&&n)el.textContent=`${SCRIPT_TITLE} — ${n.toUpperCase()}`;
                if(hud.activeTab==='faction')this.renderer.render();
                if(hud.store.get('minimized',false))this.renderer.renderMini();
            });
        }
        fetchChain() { if(!this.api.key)return; this.api.factionChain(data=>{ if(data)hud.chainManager.process(data.chain||null); }); }
        fetchCompany() {
            if(!this.api.key)return;
            this.api.companyProfile((data,err)=>{ if(err===7||err===16)return; if(data)this.state.companyProfile=data.profile||data.company||data; });
            this.api.companyEmployees((data,err)=>{
                if(err===7||err===16)return;
                if(data){const empl=data.employees||[];this.state.companyEmployees=Array.isArray(empl)?empl:Object.values(empl);}
                if(hud.activeTab==='company')this.renderer.render();
            });
        }
        fetchNetworth() {
            if(!this.api.key)return;
            this.api.userNetworth((data,err)=>{
                if(err===7||err===16||!data)return;
                const nw=data.networth||null; if(!nw)return;
                const total=nw.total||0, now=Utils.now(), hist=this.state.networthHistory;
                hist.push({ts:now,val:total}); if(hist.length>120)hist.shift();
                this.state.networthHistory=hist; hud.store.set('nwHistory',hist);
                this.state.networthData=nw;
                if(hud.activeTab==='networth')this.renderer.render();
            });
        }
        fetchBountiesPage(offset, onDone) { this.api.tornBountiesPage(offset,data=>{ const list=data?.bounties; const arr=Array.isArray(list)?list:(list?Object.values(list):[]); onDone(arr); }); }
        fetchBountiesInitial(onDone) {
            const s=this.state; s.bountyLoading=true; s.bountyAllData=[]; s.bountyLoadedPages=0;
            this.fetchBountiesPage(0,arr=>{ s.bountyAllData=this._dedup(arr); s.bountyLoadedPages=1; s.bountyData=s.bountyAllData; s.bountyLastFetch=Utils.now(); s.bountyLoading=false; onDone(s.bountyAllData); });
        }
        fetchBountiesNextPage(onDone) {
            const s=this.state; if(s.bountyLoading)return; s.bountyLoading=true;
            this.fetchBountiesPage(s.bountyLoadedPages*100,arr=>{ s.bountyLoading=false; if(!arr.length){onDone(false);return;} s.bountyAllData=this._dedup([...(s.bountyAllData||[]),...arr]); s.bountyLoadedPages++; s.bountyData=s.bountyAllData; onDone(true); });
        }
        fetchBountiesAllPages(onProgress, onDone) {
            const s=this.state; if(s.bountyScanningAll)return; s.bountyScanningAll=true; s.bountyLoading=true; s.bountyAllData=[]; s.bountyLoadedPages=0;
            const MAX=20;
            const go=(offset)=>{
                if(s.bountyLoadedPages>=MAX){s.bountyScanningAll=false;s.bountyLoading=false;s.bountyData=s.bountyAllData;onDone(s.bountyAllData);return;}
                this.fetchBountiesPage(offset,arr=>{ if(!arr.length){s.bountyScanningAll=false;s.bountyLoading=false;s.bountyData=s.bountyAllData;onDone(s.bountyAllData);return;} s.bountyAllData=this._dedup([...s.bountyAllData,...arr]);s.bountyLoadedPages++;s.bountyLastFetch=Utils.now();if(onProgress)onProgress(s.bountyAllData.length,s.bountyLoadedPages);go(s.bountyLoadedPages*100); });
            };
            go(0);
        }
        _dedup(arr) { const seen=new Map(); for(const b of arr){const id=b.target_id??b.id??Math.random();if(!seen.has(id))seen.set(id,b);} return Array.from(seen.values()); }
 
        fetchEnemyData() {
            const s=this.state;
            if(s.enemyFetchRunning||!s.enemies.length||!this.api.key)return;
            s.enemyFetchRunning=true;
            let pending=s.enemies.length;
            const done=()=>{ pending--; if(pending<=0){s.enemyFetchRunning=false;if(hud.activeTab==='enemy')hud.renderer.render();} };
            s.enemies.forEach(enemy=>{
                this.api.playerProfile(enemy.id,(data,err)=>{
                    if(data){
                        const basic=data.basic||{}, profile=data.profile||{};
                        const merged=Object.assign({},data,basic,profile);
                        if(!merged.age&&merged.registration_timestamp) merged.age=Math.floor((Utils.now()-merged.registration_timestamp)/86400);
                        if(!merged.age&&profile.age) merged.age=profile.age;
                        if(!merged.age&&basic.age)   merged.age=basic.age;
                        const fac=merged.faction||profile.faction||basic.faction||null;
                        if(fac){const facId=Number(fac.faction_id??fac.id??0);merged._factionId=facId>0?facId:null;merged._factionName=facId>0?(fac.faction_name??fac.name??''):null;}
                        else{merged._factionId=null;merged._factionName=null;}
                        // Fetch open bounty on this enemy from bounty data
                        merged._bountyReward=s._getEnemyBountyReward(enemy.id);
                        s.updateEnemyData(enemy.id,merged);
                        const liveName=merged.name??merged.player_name;
                        if(liveName&&enemy.name!==liveName){enemy.name=liveName;hud.store.set('enemies',s.enemies);}
                    }
                    done();
                });
            });
        }
 
        fetchAll() { this.fetchPersonal(); this.fetchFaction(); this.fetchChain(); this.fetchCompany(); this.fetchNetworth(); this.fetchEnemyData(); }
    }
 
    // Helper: get bounty reward for enemy id from loaded bounty data
    StateManager.prototype._getEnemyBountyReward = function(id) {
        const data = this.bountyData || this.bountyAllData || [];
        for (const b of data) {
            const tid = String(b.target_id ?? b.id ?? '');
            if (tid === String(id)) return Number(b.reward ?? b.amount ?? 0);
        }
        return 0;
    };
 
    // ═══════════════════════════════════════════════════════════════
    // RENDERER
    // ═══════════════════════════════════════════════════════════════
    class Renderer {
        constructor(state) { this.state=state; }
        get body() { return document.getElementById('thud-body'); }
        render() {
            switch(hud.activeTab){
                case 'personal':      return this.renderPersonal();
                case 'faction':       return this.renderFaction();
                case 'bounty':        return this.renderBounty();
                case 'enemy':         return this.renderEnemy();
                case 'company':       return this.renderCompany();
                case 'networth':      return this.renderNetworth();
                case 'notifications': return this.renderNotifications();
                case 'settings':      return this.renderSettings();
                default:              return this.renderPersonal();
            }
        }
 
        renderMini() {
            const b=document.getElementById('thud-mini'); if(!b)return;
            const m=Object.values(this.state.members);
            const online=m.filter(x=>FactionHelper.getStatus(x)!=='offline').length;
            const c=this.state.chain, energy=this.state.bars?.energy, nerve=this.state.bars?.nerve;
            const tSec=Math.max(0,Number(this.state.userTravel?.travel?.time_left)||0);
            const tDest=this.state.userTravel?.travel?.destination||'';
            let chips='';
            chips+=`<div class="thud-mini-chip"><span style="width:5px;height:5px;border-radius:50%;background:var(--online);box-shadow:0 0 4px var(--online);display:inline-block;"></span><span class="thud-mini-val">${online}</span><span class="thud-mini-lbl">/${m.length}</span></div>`;
            if(energy){const ep=Math.round((energy.current/energy.maximum)*100);const ec=ep>=100?'var(--red)':ep>=75?'var(--amber)':'var(--blue)';chips+=`<div class="thud-mini-chip"><span style="font-size:9px;">⚡</span><span class="thud-mini-val" style="color:${ec};">${energy.current}</span></div>`;}
            if(nerve){const np=Math.round((nerve.current/nerve.maximum)*100);const nc=np>=100?'var(--red)':'var(--dim)';chips+=`<div class="thud-mini-chip"><span style="font-size:9px;">🧠</span><span class="thud-mini-val" style="color:${nc};">${nerve.current}</span></div>`;}
            if(c&&c.current>0){const rem=Math.max(0,this.state.chainEndTime-Date.now());const mc=Math.floor(rem/60000);const warn=rem<=CHAIN_WARN_SEC*1000;chips+=`<div class="thud-mini-chip"><span style="font-size:9px;">⛓</span><span class="thud-mini-val" style="color:${warn?'var(--red)':'var(--chain)'};">${c.current}</span><span class="thud-mini-lbl">${mc}m</span></div>`;}
            if(tSec>0){const dInfo=DESTINATIONS[tDest]||{flag:'✈'};const tw=tSec<=TRAVEL_WARN_SEC;chips+=`<div class="thud-mini-chip"><span style="font-size:11px;">${dInfo.flag}</span><span class="thud-mini-val" style="color:${tw?'var(--amber)':'var(--travel)'};">${Utils.fmtHM(tSec)}</span></div>`;}
            b.innerHTML=`<div class="thud-mini-bar">${chips}</div><div class="thud-mini-tabs"><div class="thud-mini-tab" data-mini-tab="personal">👤 Ich</div><div class="thud-mini-tab" data-mini-tab="faction">⚔ Frak</div><div class="thud-mini-tab" data-mini-tab="bounty">🎯 BNT</div><div class="thud-mini-tab" data-mini-tab="enemy">💀 ENM</div><div class="thud-mini-tab" data-mini-tab="networth">💰 NW</div></div>`;
            b.querySelectorAll('[data-mini-tab]').forEach(btn=>btn.addEventListener('click',()=>{hud.store.set('minimized',false);document.getElementById('thud-overlay')?.classList.remove('minimized');hud.switchTab(btn.dataset.miniTab);}));
        }
 
        // ─── PERSONAL TAB ───
        renderPersonal() {
            const body=this.body; if(!body)return;
            const s=this.state;
            if(!s.userBasic&&!s.userProfile){body.innerHTML=!hud.store.get('apiKey')?this._noKeyState():this._loadingState();return;}
            const now=Utils.now(), basic=s.userBasic||{}, profile=s.userProfile||{};
            const travel=s.userTravel?.travel||{};
            const life=s.bars?.life||profile.life||basic.life||{};
            const hpC=Number(life.current??0), hpM=Number(life.maximum??0), hp=hpM>0?(hpC/hpM)*100:0;
            // Hospital fix: v2 status.state + status.until
            const statusObj=profile.status||basic.status||{};
            const statusState=typeof statusObj==='string'?statusObj:(statusObj.state||'Okay');
            const hospState=statusState.toLowerCase()==='hospital', jailState=statusState.toLowerCase()==='jail';
            const hospUntil=hospState?Number(statusObj.until??0):0, jailUntil=jailState?Number(statusObj.until??0):0;
            const hospSec=hospUntil>now?hospUntil-now:0, jailSec=jailUntil>now?jailUntil-now:0;
            const energy=s.bars?.energy, nerve=s.bars?.nerve, happy=s.bars?.happy;
            const ePct=energy?(energy.current/energy.maximum)*100:0;
            const nPct=nerve?(nerve.current/nerve.maximum)*100:0;
            const haPct=happy?(happy.current/happy.maximum)*100:0;
            const tSec=Math.max(0,Number(travel.time_left)||0), flying=tSec>0;
            const destInfo=DESTINATIONS[travel.destination]||{flag:'✈'};
            const tDest=travel.destination||'';
            let tvCls='home',tvBadge='🏠 TORN CITY – BEREIT',tvBadgeColor='var(--green)';
            if(flying){if(tSec<=TRAVEL_CRIT_SEC){tvCls='crit';tvBadge='⚠ KURZ VOR ANKUNFT';tvBadgeColor='var(--red)';}else if(tSec<=TRAVEL_WARN_SEC){tvCls='warn';tvBadge='✈ ANKUNFT BALD';tvBadgeColor='var(--amber)';}else{tvCls='ok';tvBadge='✈ UNTERWEGS';tvBadgeColor='var(--travel)';}}
            const tClockColor=tSec<=TRAVEL_CRIT_SEC?'var(--red)':tSec<=TRAVEL_WARN_SEC?'var(--amber)':'var(--travel)';
            const tProgCls=tSec<=TRAVEL_CRIT_SEC?'crit':tSec<=TRAVEL_WARN_SEC?'warn':'';
            const hpColor=hp<50?'var(--red)':hp<70?'var(--amber)':'var(--green)';
            const eColor=ePct>=100?'var(--red)':ePct>=75?'var(--amber)':'var(--travel)';
            const nColor=nPct>=100?'var(--red)':nPct>=75?'var(--amber)':'#9333ea';
            const eMin=energy?.fulltime?Math.max(0,Math.ceil((energy.fulltime-now)/60)):null;
            const nMin=nerve?.fulltime?Math.max(0,Math.ceil((nerve.fulltime-now)/60)):null;
            const cd=s.cooldowns?.cooldowns||{};
            const _cd=(v)=>Number(typeof v==='object'?(v?.cooldown_until??0):(v??0));
            const drugSec=Math.max(0,_cd(cd.drug)-now), medSec=Math.max(0,_cd(cd.medical)-now), boostSec=Math.max(0,_cd(cd.booster)-now);
            const edu=s.education, eduLeft=edu?Math.max(0,Number(edu.until??0)-now):0;
            // Cash only (bank removed)
            const nwObj=s.networthData||{};
            const wallet=Number(nwObj.wallet??nwObj.cash??0);
            const stocks=Number(nwObj.stockmarket??nwObj.stocks??0);
            const totalMoney=wallet+stocks;
            const level=basic.level||profile.level||'?', name=basic.name||profile.name||'—';
            const tip=this._smartTip(hp,energy,nerve,tSec,hospSec,jailSec);
            const smartTippHtml=(tip&&s.isVisible('show_tip'))?`<div class="smart-tipp"><span class="smart-tipp-icon">${tip.icon}</span><span class="smart-tipp-text">${tip.text}</span></div>`:'';
            const DEFAULT_QL=[{label:'Stock\nMarket',icon:'📈',url:'https://www.torn.com/page.php?sid=stocks'},{label:'Casino',icon:'🎰',url:'https://www.torn.com/page.php?sid=slots'},{label:'Bazaar',icon:'🏪',url:'https://www.torn.com/bazaar.php?userId=0'},{label:'Forum',icon:'💬',url:'https://www.torn.com/forums.php'}];
            const quickLinks=hud.store.get('customQuickLinks',null)||DEFAULT_QL;
            const qlHtml=s.isVisible('show_quick_links')?`<div><div class="section-header">🔗 QUICK LINKS</div><div class="ql-grid">${quickLinks.map(({label,icon,url})=>`<a class="ql-card" href="${url}" target="_blank"><span class="ql-icon">${icon}</span><span class="ql-name">${label.replace('\n','<br>')}</span></a>`).join('')}</div></div>`:'';
            const bs=s.battleStats;
            const bsT=bs?(Number(bs.strength||0)+Number(bs.defense||0)+Number(bs.speed||0)+Number(bs.dexterity||0)):0;
            const bsHtml=(s.isVisible('show_battle_stats')&&bs)?`<div class="card"><div class="card-header"><span class="card-title red">⚔ BATTLE STATS</span><span class="badge badge-amber">${Utils.fmtStat(bsT)} total</span></div><div class="card-body"><div class="stat-grid stat-grid-4"><div class="stat-card"><div class="sv sv-red">${Utils.fmtStat(bs.strength||0)}</div><div class="sl">STR</div></div><div class="stat-card"><div class="sv sv-blue">${Utils.fmtStat(bs.defense||0)}</div><div class="sl">DEF</div></div><div class="stat-card"><div class="sv sv-green">${Utils.fmtStat(bs.speed||0)}</div><div class="sl">SPD</div></div><div class="stat-card"><div class="sv sv-amber">${Utils.fmtStat(bs.dexterity||0)}</div><div class="sl">DEX</div></div></div></div></div>`:'';
            const tctHtml=s.isVisible('show_tct_time')?`<span style="color:var(--accent2);font-family:var(--mono);">TCT ${Utils.tctTime()}</span>`:'';
            body.innerHTML=`
            ${smartTippHtml}
            <div style="display:flex;align-items:center;justify-content:space-between;padding:2px 2px 0;">
                <div><div style="font-size:14px;font-weight:700;color:var(--text);">${Utils.escHtml(name)}</div><div style="font-size:10px;color:var(--muted);margin-top:2px;">Level ${level} · ${Utils.escHtml(statusState)}</div></div>
                <div style="text-align:right;"><div style="font-family:var(--mono);font-size:15px;font-weight:700;color:var(--amber);">${Utils.fmtMoney(totalMoney)}</div><div style="font-size:9px;color:var(--muted);margin-top:1px;">💵 ${Utils.fmtMoney(wallet)}${stocks?` · 📈 ${Utils.fmtMoney(stocks)}`:''}</div></div>
            </div>
            <div class="travel-card ${tvCls}">
                <div class="travel-card-top" style="color:${tvBadgeColor};"><span>${tvBadge}</span>${flying?`<span style="font-size:18px;">${destInfo.flag}</span>`:''}</div>
                <div class="travel-card-body">
                ${!flying?`<div style="display:flex;align-items:center;gap:12px;"><span style="font-size:24px;opacity:.2;">🏠</span><div><div style="font-size:14px;font-weight:700;color:var(--green);">TORN CITY</div><div style="font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:1.5px;margin-top:2px;">BEREIT ZUM ABFLUG</div></div></div>`
                :`<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px;"><span style="font-size:22px;">${destInfo.flag}</span><div class="travel-dest" style="color:${tClockColor};">${Utils.escHtml(tDest||'Unbekannt')}</div></div><div style="display:flex;justify-content:space-between;align-items:flex-end;"><div class="travel-clock" style="color:${tClockColor};">${Utils.fmtHM(tSec)}</div><div style="text-align:right;"><div style="font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;">ANKUNFT</div><div style="font-family:var(--mono);font-size:15px;font-weight:700;color:var(--dim);margin-top:1px;">${Utils.arrTime(tSec)}</div></div></div><div class="travel-prog"><div class="travel-prog-fill ${tProgCls}" style="width:0%;"></div></div>`}
                </div>
            </div>
            <div class="card">
                <div class="card-header"><span class="card-title accent">◈ BARS &amp; STATUS</span><span class="badge badge-${statusState==='Okay'?'green':statusState==='Hospital'?'red':statusState==='Jail'?'amber':'muted'}">${Utils.escHtml(statusState)}</span></div>
                <div class="card-body">
                    <div class="stat-grid stat-grid-3" style="margin-bottom:12px;">
                        <div class="stat-card"><div class="sv ${hp>=70?'sv-green':hp>=50?'sv-amber':'sv-red'}">${hpM>0?Math.round(hp)+'%':'—'}</div><div class="sl">HP</div></div>
                        <div class="stat-card"><div class="sv ${ePct>=100?'sv-red':ePct>=75?'sv-amber':'sv-blue'}">${energy?energy.current:'—'}</div><div class="sl">Energie</div></div>
                        <div class="stat-card"><div class="sv ${nPct>=100?'sv-red':nPct>=75?'sv-amber':'sv-blue'}">${nerve?nerve.current:'—'}</div><div class="sl">Nerve</div></div>
                    </div>
                    <div class="bar-block"><div class="bar-block-head"><span class="bar-block-lbl">❤ HP</span><span class="bar-block-val" style="color:${hpColor}">${hpC} / ${hpM||'?'}</span></div>${Utils.pctBar(hp,hpColor,'bar-lg')}</div>
                    <div class="bar-block"><div class="bar-block-head"><span class="bar-block-lbl">⚡ Energie</span><span class="bar-block-val" style="color:${eColor}">${energy?`${energy.current} / ${energy.maximum}`:'—'}</span></div>${Utils.pctBar(ePct,eColor)}${eMin!==null&&eMin>0?`<div class="bar-block-sub">Voll in ${eMin} Min</div>`:''}</div>
                    <div class="bar-block"><div class="bar-block-head"><span class="bar-block-lbl">🧠 Nerve</span><span class="bar-block-val" style="color:${nColor}">${nerve?`${nerve.current} / ${nerve.maximum}`:'—'}</span></div>${Utils.pctBar(nPct,nColor)}${nMin!==null&&nMin>0?`<div class="bar-block-sub">Voll in ${nMin} Min</div>`:''}</div>
                    ${happy&&s.isVisible('show_happy')?`<div class="bar-block"><div class="bar-block-head"><span class="bar-block-lbl">😊 Happy</span><span class="bar-block-val" style="color:var(--amber)">${happy.current} / ${happy.maximum}</span></div>${Utils.pctBar(haPct,'var(--amber)')}</div>`:''}
                </div>
            </div>
            ${bsHtml}
            ${qlHtml}
            <div class="card">
                <div class="card-header"><span class="card-title">⏱ COOLDOWNS &amp; STATUS</span></div>
                <div class="card-body">
                    ${s.isVisible('show_hospital')?`<div class="row"><span class="row-label">🏥 Krankenhaus</span><span class="row-value" style="color:${hospSec>0?'var(--red)':'var(--green)'}">${hospSec>0?Utils.fmtSec(hospSec):'FREI'}</span></div>`:''}
                    ${s.isVisible('show_jail')?`<div class="row"><span class="row-label">🚔 Gefängnis</span><span class="row-value" style="color:${jailSec>0?'var(--amber)':'var(--green)'}">${jailSec>0?Utils.fmtSec(jailSec):'FREI'}</span></div>`:''}
                    ${s.isVisible('show_drug_cd')?`<div class="row"><span class="row-label">💊 Drogen CD</span><span class="row-value" style="color:${drugSec>0?'var(--amber)':'var(--green)'}">${drugSec>0?Utils.fmtSec(drugSec):'BEREIT'}</span></div>`:''}
                    ${s.isVisible('show_medical_cd')?`<div class="row"><span class="row-label">💉 Medical CD</span><span class="row-value" style="color:${medSec>0?'var(--amber)':'var(--green)'}">${medSec>0?Utils.fmtSec(medSec):'BEREIT'}</span></div>`:''}
                    ${s.isVisible('show_booster_cd')?`<div class="row"><span class="row-label">🧪 Booster CD</span><span class="row-value" style="color:${boostSec>0?'var(--amber)':'var(--green)'}">${boostSec>0?Utils.fmtSec(boostSec):'BEREIT'}</span></div>`:''}
                    ${s.isVisible('show_education')&&edu?(eduLeft>0?`<div class="row"><span class="row-label">📚 Kurs</span><span class="row-value">${Utils.fmtDhm(eduLeft)}</span></div>`:`<div class="row"><span class="row-label">📚 Lehrgang</span><span class="row-value" style="color:var(--green);">ABGESCHLOSSEN ✓</span></div>`):''}
                </div>
            </div>
            <div style="display:flex;justify-content:space-between;align-items:center;padding:2px 0;flex-shrink:0;" class="ts">
                <span style="display:flex;align-items:center;gap:5px;"><div class="pip"></div>${s.lastUpdate?.toLocaleTimeString('de-DE')||'—'}</span>
                ${tctHtml}
                <span>⬆ ${this._uptimeStr()}</span>
            </div>`;
        }
 
        _smartTip(hp, energy, nerve, tSec, hospSec, jailSec) {
            if(jailSec>0)return{icon:'🚔',text:`Du sitzt noch ${Utils.fmtSec(jailSec)} im Knast.`};
            if(hospSec>0&&hospSec<300)return{icon:'🏥',text:`Nur noch ${Utils.fmtSec(hospSec)} im Krankenhaus.`};
            if(hp<50&&hp>0)return{icon:'❤',text:`HP sehr niedrig (${Math.round(hp)}%). Medical Items nutzen!`};
            if(energy?.current>=energy?.maximum)return{icon:'⚡',text:'Energie voll! Chains oder Gym nutzen!'};
            if(nerve?.current>=nerve?.maximum)return{icon:'🧠',text:'Nerve voll! Crimes abarbeiten!'};
            if(tSec>0&&tSec<300)return{icon:'✈',text:`Fast da! Ankunft in ${Utils.fmtHM(tSec)}.`};
            if(energy&&(energy.current/energy.maximum)>0.85)return{icon:'💡',text:'Energie fast voll – nächste Chain planen?'};
            return null;
        }
        _uptimeStr() { const s=this.state.uptimeSec,h=Math.floor(s/3600),m=Math.floor((s%3600)/60); return h>0?`${h}h ${m}m`:`${m}m`; }
 
        // ─── FACTION TAB ───
        renderFaction() {
            const body=this.body; if(!body)return;
            const m=Object.values(this.state.members), t=m.length;
            const cap=this.state.faction.max_members||this.state.faction.capacity||t||50;
            const groups={online:[],idle:[],traveling:[],hospital:[],jail:[],offline:[]};
            m.forEach(x=>groups[FactionHelper.getStatus(x)].push(x));
            const active=[...groups.online,...groups.traveling,...groups.idle,...groups.hospital,...groups.jail];
            const sa=active.sort((a,b)=>FactionHelper.statusOrder(FactionHelper.getStatus(a))-FactionHelper.statusOrder(FactionHelper.getStatus(b)));
            const so=[...groups.offline].sort((a,b)=>(a.last_action?.timestamp||0)-(b.last_action?.timestamp||0));
            const sl=20,ol=INACTIVE_LIMIT;
            const sOn=this.state.showAllOnline?sa:sa.slice(0,sl);
            const sOf=this.state.showAllOffline?so:so.slice(0,ol);
            const eOn=sa.length-sl,eOf=so.length-ol;
            const rd=groups.online.length+groups.idle.length,oc=active.length;
            const donutSVG=Utils.buildDonut([{count:groups.online.length,color:'var(--green)'},{count:groups.idle.length,color:'var(--amber)'},{count:groups.traveling.length,color:'var(--travel)'},{count:groups.hospital.length,color:'var(--red)'},{count:groups.jail.length,color:'#f97316'},{count:groups.offline.length,color:'var(--bg-el)'}],t);
            body.innerHTML=`
            <div class="chain-block" id="thud-chain-block"><div class="chain-idle"><div class="pulse-dot" style="opacity:.2;animation:none;background:var(--muted);"></div><span style="font-size:10px;font-weight:600;margin-left:7px;letter-spacing:.5px;">Keine aktive Chain</span></div></div>
            <div class="card"><div class="card-header"><div style="display:flex;align-items:center;gap:8px;"><span class="card-title green">● ONLINE</span><span class="badge badge-green">${oc}</span></div><div style="position:relative;display:flex;align-items:center;justify-content:center;">${donutSVG}<div style="position:absolute;text-align:center;pointer-events:none;"><div style="font-size:13px;font-weight:700;color:var(--text);">${oc}</div><div style="font-size:8px;color:var(--muted);">/${cap}</div></div></div></div>
            <div class="card-body"><div class="member-grid">${sOn.map(x=>{const st=FactionHelper.getStatus(x);return`<div class="member-row"><span class="status-dot sd-${st}"></span><span class="member-name">${Utils.escHtml(x.name)}</span><span class="member-status">${FactionHelper.statusLabel(st)}</span></div>`;}).join('')}</div>${eOn>0&&!this.state.showAllOnline?`<span class="toggle-more" id="thud-more-online">▾ ${eOn} mehr</span>`:this.state.showAllOnline&&sa.length>sl?`<span class="toggle-more" id="thud-less-online">▴ Weniger</span>`:''}<div class="status-summary"><div class="stat-chip"><div class="sn" style="color:var(--green);">${groups.online.length}</div><div class="sl">Online</div></div><div class="stat-chip"><div class="sn" style="color:var(--amber);">${groups.idle.length}</div><div class="sl">AFK</div></div><div class="stat-chip"><div class="sn" style="color:var(--travel);">${groups.traveling.length}</div><div class="sl">Travel</div></div><div class="stat-chip"><div class="sn" style="color:var(--red);">${groups.hospital.length}</div><div class="sl">Hosp.</div></div><div class="stat-chip"><div class="sn" style="color:#f97316;">${groups.jail.length}</div><div class="sl">Jail</div></div><div class="stat-chip"><div class="sn" style="color:var(--muted);">${groups.offline.length}</div><div class="sl">Offline</div></div></div></div></div>
            <div class="card"><div class="card-header"><span class="card-title red">⚔ WAR READY</span></div><div class="card-body"><div class="war-grid"><div class="war-cell"><div class="wv" style="color:var(--green);">${rd}</div><div class="wl">Ready</div></div><div class="war-cell"><div class="wv" style="color:var(--red);">${groups.hospital.length}</div><div class="wl">Hosp.</div></div><div class="war-cell"><div class="wv" style="color:var(--travel);">${groups.traveling.length}</div><div class="wl">Travel</div></div><div class="war-cell"><div class="wv" style="color:var(--amber);">${t>0?Math.round(rd/t*100):0}%</div><div class="wl">Bereit</div></div></div></div></div>
            ${groups.traveling.length>0?`<div class="card"><div class="card-header"><span class="card-title blue">✈ UNTERWEGS (${groups.traveling.length})</span></div><div class="card-body p0">${groups.traveling.map(x=>{const{from,to,dir}=FactionHelper.parseTravelRoute(x);const fC=from.toLowerCase().includes('torn')?'var(--green)':'var(--travel)';const tC=to.toLowerCase().includes('torn')?'var(--green)':'var(--travel)';return`<div style="display:flex;align-items:center;gap:10px;padding:9px 14px;border-bottom:1px solid rgba(255,255,255,.04);"><span style="font-size:18px;">${dir==='home'?'🏠':'✈'}</span><div style="flex:1;min-width:0;"><div style="font-size:12px;font-weight:600;color:var(--text);">${Utils.escHtml(x.name)}</div><div style="font-size:10px;margin-top:2px;display:flex;align-items:center;gap:5px;"><span style="color:${fC};">${Utils.escHtml(from)}</span><span style="color:var(--muted);">→</span><span style="color:${tC};">${Utils.escHtml(to)}</span></div></div></div>`;}).join('')}</div></div>`:''}
            <div class="card"><div class="card-header"><span class="card-title">💤 OFFLINE (${groups.offline.length})</span></div><div class="card-body p0">${sOf.map(x=>{const a=Utils.inactiveAgo(x.last_action?.timestamp||0);return`<div class="offline-row"><span class="status-dot sd-offline"></span><span class="offline-name">${Utils.escHtml(x.name)}</span><span class="offline-ago ${a.cls}">${a.text}</span></div>`;}).join('')}${eOf>0&&!this.state.showAllOffline?`<span class="toggle-more" style="margin:7px 14px 12px;" id="thud-more-offline">▾ ${eOf} weitere</span>`:this.state.showAllOffline&&so.length>ol?`<span class="toggle-more" style="margin:7px 14px 12px;" id="thud-less-offline">▴ Weniger</span>`:''}</div></div>`;
            hud.chainManager.renderSection();
            if(this.state.chain?.current>0)hud.chainManager.startTick();
            document.getElementById('thud-more-online')?.addEventListener('click',()=>{this.state.showAllOnline=true;this.renderFaction();});
            document.getElementById('thud-less-online')?.addEventListener('click',()=>{this.state.showAllOnline=false;this.renderFaction();});
            document.getElementById('thud-more-offline')?.addEventListener('click',()=>{this.state.showAllOffline=true;this.renderFaction();});
            document.getElementById('thud-less-offline')?.addEventListener('click',()=>{this.state.showAllOffline=false;this.renderFaction();});
        }
 
        // ─── BOUNTY TAB ───
        renderBounty() {
            const body=this.body; if(!body)return;
            const s=this.state, data=s.bountyData, sort=s.bountySort, now=Utils.now();
            const doScan=()=>{ hud.fetcher.fetchBountiesInitial(()=>{s.bountySearch='';s.bountyDisplayCount=80;this.renderBounty();}); };
            if(!data){
                body.innerHTML=`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title red">🎯 BOUNTY RADAR</span></div></div><div class="empty-state"><div class="es-icon">🎯</div><div class="es-text">Keine Bounties geladen</div><div class="es-sub">Klick "Laden" um die Torn Bounty-Liste zu holen</div></div><button class="scan-btn" id="thud-bounty-scan" style="align-self:center;">🔍 Bounty-Liste laden</button>`;
                document.getElementById('thud-bounty-scan')?.addEventListener('click',doScan); return;
            }
            const lvMin=Number(s.bountyLevelMin)||1, lvMax=Number(s.bountyLevelMax)||100;
            const rwMin=Number(s.bountyRewardMin)||0, rwMax=Number(s.bountyRewardMax)||0;
            const q=(s.bountySearch||'').toLowerCase().trim();
            let filtered=data.slice();
            if(q)filtered=filtered.filter(b=>{const name=(b.target_name??b.name??'').toLowerCase(),reason=(b.reason??'').toLowerCase();return name.includes(q)||reason.includes(q);});
            filtered=filtered.filter(b=>{const lvl=Number(b.target_level??b.level??0);return lvl>=lvMin&&lvl<=lvMax;});
            if(rwMin>0||rwMax>0){filtered=filtered.filter(b=>{const r=Number(b.reward??b.amount??0);if(rwMin>0&&r<rwMin)return false;if(rwMax>0&&r>rwMax)return false;return true;});}
            if(s.bountyFilterHosp)filtered=filtered.filter(b=>!this._isHospital(b));
            if(sort==='reward')filtered.sort((a,b)=>(b.reward??b.amount??0)-(a.reward??a.amount??0));
            if(sort==='level') filtered.sort((a,b)=>(a.target_level??a.level??0)-(b.target_level??b.level??0));
            if(sort==='time')  filtered.sort((a,b)=>(a.valid_until??a.expires??0)-(b.valid_until??b.expires??0));
            if(!s.bountyFilterHosp)filtered.sort((a,b)=>(this._isHospital(a)?0:1)-(this._isHospital(b)?0:1));
            const displayCount=s.bountyDisplayCount||80, visible=filtered.slice(0,displayCount), hasMoreVisible=filtered.length>displayCount;
            const hospCount=data.filter(b=>this._isHospital(b)).length, isFiltered=filtered.length!==data.length;
            const searchHadFocus=document.activeElement?.id==='thud-bounty-search';
            const searchCursorPos=searchHadFocus?(document.activeElement.selectionStart??0):0;
            const rwMinD=rwMin>0?(rwMin>=1e6?(rwMin/1e6).toFixed(1)+'M':rwMin>=1e3?(rwMin/1e3).toFixed(0)+'K':rwMin):'';
            const rwMaxD=rwMax>0?(rwMax>=1e6?(rwMax/1e6).toFixed(1)+'M':rwMax>=1e3?(rwMax/1e3).toFixed(0)+'K':rwMax):'';
            body.innerHTML=`
            <div class="card" style="flex-shrink:0;">
                <div class="card-header" style="flex-wrap:wrap;gap:6px;">
                    <span class="card-title red">🎯 BOUNTY RADAR</span>
                    <div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;">
                        <span class="badge badge-red">${data.length} total</span>
                        ${hospCount>0?`<span class="badge badge-red">🏥 ${hospCount}</span>`:''}
                        ${isFiltered?`<span class="badge badge-amber">${filtered.length} gefiltert</span>`:''}
                        ${!s.bountyLoading?`<button class="bounty-load-more-inline" id="thud-bounty-more">▾ +Mehr (S.${s.bountyLoadedPages})</button>`:`<span class="bounty-load-more-inline" style="opacity:.5;cursor:default;"><span class="spinning">↺</span>${s.bountyScanningAll?' Scan...':''}</span>`}
                        <button class="scan-btn" id="thud-bounty-scan-all" style="padding:4px 10px;font-size:10px;background:rgba(245,158,11,.15);border-color:rgba(245,158,11,.3);color:var(--amber);" ${s.bountyLoading?'disabled':''} title="Alle Seiten laden">⚡ Alle</button>
                        <button class="scan-btn" id="thud-bounty-scan" style="padding:4px 10px;font-size:10px;" ${s.bountyLoading?'disabled':''}>${s.bountyLoading?'<span class="spinning">↺</span>':'↺'}</button>
                    </div>
                </div>
                <div class="card-body" style="padding:9px 14px 10px;gap:7px;">
                    <input type="text" class="bounty-search" id="thud-bounty-search" placeholder="🔍 Name oder Grund..." value="${Utils.escHtml(s.bountySearch||'')}">
                    <div class="level-filter-row">
                        <span style="font-size:10px;color:var(--muted);font-weight:700;">LV:</span>
                        <input type="number" class="level-input" id="thud-lvl-min" min="1" max="100" value="${lvMin}">
                        <span style="color:var(--muted);font-size:10px;">–</span>
                        <input type="number" class="level-input" id="thud-lvl-max" min="1" max="100" value="${lvMax}">
                        <button class="sort-btn" id="thud-lvl-apply">✓</button>
                    </div>
                    <div class="level-filter-row">
                        <span style="font-size:10px;color:var(--amber);font-weight:700;">💰:</span>
                        <input type="text" class="reward-input" id="thud-rw-min" placeholder="Min" value="${rwMinD}">
                        <span style="color:var(--muted);font-size:10px;">–</span>
                        <input type="text" class="reward-input" id="thud-rw-max" placeholder="Max" value="${rwMaxD}">
                        <button class="sort-btn" id="thud-rw-apply" style="border-color:rgba(245,158,11,.3);color:var(--amber);">✓</button>
                        ${(rwMin>0||rwMax>0)?`<button class="sort-btn" id="thud-rw-clear" style="color:var(--muted);">✕</button>`:''}
                    </div>
                    <div class="sort-bar">
                        <span style="font-size:9px;color:var(--muted);font-weight:700;">SORT:</span>
                        <button class="sort-btn ${sort==='reward'?'active':''}" data-sort="reward">💰 Reward</button>
                        <button class="sort-btn ${sort==='level'?'active':''}"  data-sort="level">⚔ Level</button>
                        <button class="sort-btn ${sort==='time'?'active':''}"   data-sort="time">⏱ Zeit</button>
                    </div>
                    <div class="sort-bar">
                        <span style="font-size:9px;color:var(--muted);font-weight:700;">FILTER:</span>
                        <button class="sort-btn ${s.bountyFilterHosp?'active':''}" data-filter="hosp">🏥 ${s.bountyFilterHosp?'Hosp. ausgebl.':'Hosp. anzeigen'}</button>
                    </div>
                </div>
            </div>
            <div class="card" style="flex-shrink:0;"><div class="card-body p0" id="thud-bounty-list">${this._buildBountyRows(visible,now)}</div></div>
            <div class="ts" style="text-align:center;flex-shrink:0;">${data.length} Bounties · Seite ${s.bountyLoadedPages} · ${s.bountyLastFetch?new Date(s.bountyLastFetch*1000).toLocaleTimeString('de-DE'):'—'}</div>`;
            if(searchHadFocus){const inp=document.getElementById('thud-bounty-search');if(inp){inp.focus();try{inp.setSelectionRange(searchCursorPos,searchCursorPos);}catch(e){}}}
            document.getElementById('thud-bounty-scan')?.addEventListener('click',doScan);
            document.getElementById('thud-bounty-scan-all')?.addEventListener('click',()=>{if(s.bountyScanningAll||s.bountyLoading)return;hud.fetcher.fetchBountiesAllPages(()=>this.renderBounty(),(all)=>{s.bountySearch='';s.bountyDisplayCount=80;hud.toasts.show('✅','Alle Bounties geladen',`${all.length} Bounties`,'info',5000);this.renderBounty();});this.renderBounty();});
            document.getElementById('thud-bounty-search')?.addEventListener('input',e=>{s.bountySearch=e.target.value;s.bountyDisplayCount=80;this._renderBountyListOnly(s,now);});
            document.getElementById('thud-lvl-apply')?.addEventListener('click',()=>{s.setBountyLevelMin(Number(document.getElementById('thud-lvl-min')?.value)||1);s.setBountyLevelMax(Number(document.getElementById('thud-lvl-max')?.value)||100);s.bountyDisplayCount=80;this.renderBounty();});
            const parseR=(str)=>{if(!str||!str.trim())return 0;str=str.trim().toUpperCase().replace(/\s/g,'').replace(',','.');const m=str.match(/^([\d.]+)([KMB]?)$/);if(!m)return 0;return Math.round(parseFloat(m[1])*({K:1e3,M:1e6,B:1e9,'':1}[m[2]]||1));};
            document.getElementById('thud-rw-apply')?.addEventListener('click',()=>{s.setBountyRewardMin(parseR(document.getElementById('thud-rw-min')?.value));s.setBountyRewardMax(parseR(document.getElementById('thud-rw-max')?.value));s.bountyDisplayCount=80;this.renderBounty();});
            document.getElementById('thud-rw-clear')?.addEventListener('click',()=>{s.setBountyRewardMin(0);s.setBountyRewardMax(0);s.bountyDisplayCount=80;this.renderBounty();});
            body.querySelectorAll('[data-sort]').forEach(btn=>btn.addEventListener('click',()=>{s.setBountySort(btn.dataset.sort);s.bountyDisplayCount=80;this.renderBounty();}));
            body.querySelectorAll('[data-filter]').forEach(btn=>btn.addEventListener('click',()=>{if(btn.dataset.filter==='hosp')s.setBountyFilterHosp(!s.bountyFilterHosp);s.bountyDisplayCount=80;this.renderBounty();}));
            document.getElementById('thud-bounty-more')?.addEventListener('click',()=>{if(hasMoreVisible){s.bountyDisplayCount+=80;this._renderBountyListOnly(s,now);}else{hud.fetcher.fetchBountiesNextPage(has=>{if(!has)hud.toasts.show('ℹ','Alle geladen',`${s.bountyData.length} Bounties`,'info',4000);else s.bountyDisplayCount+=80;this.renderBounty();});}});
            body.querySelectorAll('[data-bounty-add-enemy]').forEach(btn=>btn.addEventListener('click',()=>{const id=btn.dataset.bountyAddEnemy,name=btn.dataset.bountyName||`#${id}`;if(!s.enemies.find(e=>String(e.id)===String(id))){s.addEnemy(String(id),name,'');hud.toasts.show('💀','Enemy hinzugefügt',`${name} aus Bounty-Liste`,'crit',3000);hud.fetcher.fetchEnemyData();}else{hud.toasts.show('⚠','Bereits in Enemy-Liste',name,'warn',2000);}}));
        }
 
        _isHospital(b) {
            const so=(typeof b.target?.status==='object'&&b.target.status)||(typeof b.status==='object'&&b.status)||{};
            const raw=so.state??so.description??b.target_state??b.state??'';
            return raw.toLowerCase().includes('hospital');
        }
 
        _buildBountyRows(visible, now) {
            if(!visible||!visible.length)return`<div class="empty-state"><div class="es-icon">🔍</div><div class="es-text">Keine Ergebnisse</div><div class="es-sub">Filter anpassen oder Bounties neu laden</div></div>`;
            return visible.map(b=>{
                const tid=b.target_id??b.id, tname=b.target_name??b.name??`#${tid}`;
                const lvl=b.target_level??b.level??0, reward=b.reward??b.amount??0;
                const validUntil=b.valid_until??b.expires??0, timeLeft=validUntil>0?Math.max(0,validUntil-now):0;
                const reason=b.reason?Utils.escHtml(b.reason.substring(0,80)):'';
                const so=(typeof b.target?.status==='object'&&b.target.status)||(typeof b.status==='object'&&b.status)||{};
                const rawState=so.state??so.description??b.target_state??b.state??'';
                const ss=rawState.toLowerCase(), isH=ss.includes('hospital');
                const hospUntil=Number(so.until??so.hospital_timestamp??0);
                const hospLeft=isH&&hospUntil>now?hospUntil-now:0;
                let statusTag='';
                if(isH)statusTag=`<span class="bounty-tag tag-hosp">🏥 HOSPITAL${hospLeft>0?` · ${Utils.fmtSec(hospLeft)}`:''}</span>`;
                else if(ss.includes('travel')||ss.includes('abroad'))statusTag=`<span class="bounty-tag tag-travel">✈ TRAVEL</span>`;
                else if(ss.includes('jail'))statusTag=`<span class="bounty-tag tag-jail">🚔 JAIL</span>`;
                else if(ss&&ss!=='okay')statusTag=`<span class="bounty-tag tag-ok">✓ ${Utils.escHtml(rawState)}</span>`;
                let diff,dCls;
                if(lvl<=15){diff='EASY';dCls='diff-easy';}else if(lvl<=50){diff='MID';dCls='diff-medium';}else{diff='HARD';dCls='diff-hard';}
                return`<div class="bounty-row${isH?' is-hospital':''}">
                    <div style="flex:1;min-width:0;">
                        <div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;">
                            <a href="https://www.torn.com/profiles.php?XID=${tid}" target="_blank" style="color:var(--text);text-decoration:none;font-weight:700;font-size:13px;">${Utils.escHtml(tname)}</a>
                            <span class="${dCls} bounty-difficulty">${diff}</span>
                            <span style="font-size:10px;font-family:var(--mono);color:var(--muted);">Lv ${lvl}</span>
                        </div>
                        <div class="bounty-info-row">${statusTag}</div>
                        ${reason?`<div style="font-size:10px;color:var(--muted);margin-top:2px;font-style:italic;">"${reason}"</div>`:''}
                        ${timeLeft>0?`<div style="font-size:9px;color:var(--amber);font-family:var(--mono);margin-top:1px;">⏱ ${Utils.fmtSec(timeLeft)}</div>`:''}
                    </div>
                    <div style="display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0;">
                        <span class="bounty-reward">${Utils.fmtMoney(reward)}</span>
                        <a class="bounty-link" href="https://www.torn.com/page.php?sid=attack&user2ID=${tid}" target="_blank">⚔ Angriff</a>
                        <button class="bounty-link" style="background:rgba(239,68,68,.12);border:1px solid rgba(239,68,68,.25);color:var(--red);cursor:pointer;font-family:var(--font);" data-bounty-add-enemy="${tid}" data-bounty-name="${Utils.escHtml(tname)}">💀 Enemy</button>
                    </div>
                </div>`;
            }).join('');
        }
 
        _renderBountyListOnly(s, now) {
            const listEl=document.getElementById('thud-bounty-list'); if(!listEl){this.renderBounty();return;}
            const q=(s.bountySearch||'').toLowerCase().trim();
            const lvMin=Number(s.bountyLevelMin)||1,lvMax=Number(s.bountyLevelMax)||100;
            const rwMin=Number(s.bountyRewardMin)||0,rwMax=Number(s.bountyRewardMax)||0;
            let filtered=(s.bountyData||[]).slice();
            if(q)filtered=filtered.filter(b=>{const n=(b.target_name??b.name??'').toLowerCase(),r=(b.reason??'').toLowerCase();return n.includes(q)||r.includes(q);});
            filtered=filtered.filter(b=>{const l=Number(b.target_level??b.level??0);return l>=lvMin&&l<=lvMax;});
            if(rwMin>0||rwMax>0)filtered=filtered.filter(b=>{const r=Number(b.reward??b.amount??0);if(rwMin>0&&r<rwMin)return false;if(rwMax>0&&r>rwMax)return false;return true;});
            if(s.bountyFilterHosp)filtered=filtered.filter(b=>!this._isHospital(b));
            const sort=s.bountySort;
            if(sort==='reward')filtered.sort((a,b)=>(b.reward??b.amount??0)-(a.reward??a.amount??0));
            if(sort==='level') filtered.sort((a,b)=>(a.target_level??a.level??0)-(b.target_level??b.level??0));
            if(sort==='time')  filtered.sort((a,b)=>(a.valid_until??a.expires??0)-(b.valid_until??b.expires??0));
            if(!s.bountyFilterHosp)filtered.sort((a,b)=>(this._isHospital(a)?0:1)-(this._isHospital(b)?0:1));
            listEl.innerHTML=this._buildBountyRows(filtered.slice(0,s.bountyDisplayCount||80),now);
        }
 
        // ─── ENEMY TAB ───
        renderEnemy() {
            const body=this.body; if(!body)return;
            const s=this.state, now=Utils.now(), enemies=s.enemies||[];
            const addEnemy=(id,note)=>{
                if(!id||isNaN(parseInt(id))){hud.toasts.show('⚠','Ungültige ID','Bitte gültige Spieler-ID eingeben','warn',3000);return;}
                hud.fetcher.api.playerProfile(id,(data)=>{
                    const p=data?.profile??data;
                    const name=p?.name??p?.player_name??`#${id}`;
                    if(s.addEnemy(String(id),name,note)){hud.toasts.show('💀',`Enemy hinzugefügt`,`${name} (ID: ${id})`,'crit',4000);hud.fetcher.fetchEnemyData();this.renderEnemy();}
                    else hud.toasts.show('⚠','Bereits vorhanden',`ID ${id} ist bereits in der Liste`,'warn',3000);
                });
            };
            const renderRow=(enemy)=>{
                const ed=s.enemyData[enemy.id]||{};
                const statusObj=ed.status||{}, ss=(statusObj.state||'').toLowerCase();
                const isH=ss==='hospital', isTr=ss==='traveling'||ss==='abroad', isJ=ss==='jail';
                const hospUntil=isH?Number(statusObj.until??0):0, hospSec=hospUntil>now?hospUntil-now:0;
                const level=ed.level??'?';
                // Age in TAGEN (kein y/m Format)
                const ageDays=Number(ed.age??0);
                const facId=ed._factionId??null, facName=ed._factionName??null;
                const jobCo=ed.job?.company_name??ed.job?.name??null, jobPos=ed.job?.position??null;
                const travelDesc=statusObj.description||'';
                const lastTs=ed.last_action?.timestamp??0;
                const isOnline=(ed.last_action?.status||'').toLowerCase()==='online'||(lastTs>0&&(now-lastTs)<120);
                const lastAgo=lastTs>0?Utils.inactiveAgo(lastTs):null;
                // Bounty reward on this enemy
                const bountyR=s._getEnemyBountyReward(enemy.id);
                let statusTag='',rowClass='enemy-row';
                if(isH){statusTag=`<span class="enemy-tag etag-hosp">🏥 HOSPITAL${hospSec>0?` · ${Utils.fmtSec(hospSec)}`:''}</span>`;rowClass+=' in-hospital';}
                else if(isTr){statusTag=`<span class="enemy-tag etag-travel">✈ ${Utils.escHtml(travelDesc)||'Reist'}</span>`;rowClass+=' traveling';}
                else if(isJ)statusTag=`<span class="enemy-tag etag-jail">🚔 JAIL</span>`;
                else if(ss)statusTag=`<span class="enemy-tag etag-ok">✓ OKAY</span>`;
                const lastHtml=lastAgo?`<span class="enemy-tag" style="background:rgba(255,255,255,.04);color:${isOnline?'var(--green)':'var(--muted)'};border:1px solid rgba(255,255,255,.08);">⏱ ${isOnline?'Online':lastAgo.text+' ago'}</span>`:'';
                const facTag=facId?`<span class="enemy-tag" style="background:rgba(255,255,255,.05);color:var(--muted);border:1px solid rgba(255,255,255,.08);">⚔ ${Utils.escHtml(facName||'Faction')}</span>`:
                                   `<span class="enemy-tag" style="background:rgba(16,185,129,.08);color:var(--green);border:1px solid rgba(16,185,129,.2);">✓ No Faction</span>`;
                // Age: "Age 1569" in grün, gleicher Style wie Lv
                const ageHtml=ageDays>0?`<span class="enemy-level" style="color:var(--green);">Age ${ageDays}</span>`:'';
                // Bounty: zeige wenn vorhanden
                const bountyHtml=bountyR>0?`<span class="enemy-level" style="color:var(--amber);">🎯 ${Utils.fmtMoney(bountyR)}</span>`:'';
                return`<div class="${rowClass}" data-enemy-id="${enemy.id}">
                    <div class="enemy-top">
                        <a class="enemy-name-link" href="https://www.torn.com/profiles.php?XID=${enemy.id}" target="_blank">${Utils.escHtml(enemy.name)}</a>
                        <span class="enemy-level">Lv ${level}</span>
                        ${ageHtml}
                        ${bountyHtml}
                    </div>
                    <div class="enemy-meta">
                        ${statusTag}${lastHtml}${facTag}
                        ${jobCo?`<span class="enemy-tag etag-job">🏢 ${Utils.escHtml(jobCo)}${jobPos?` · ${Utils.escHtml(jobPos)}`:''}</span>`:''}
                    </div>
                    ${enemy.note?`<div class="enemy-note">📝 ${Utils.escHtml(enemy.note)}</div>`:''}
                    <div class="enemy-actions">
                        <a class="enemy-action-btn eab-attack"  href="https://www.torn.com/page.php?sid=attack&user2ID=${enemy.id}" target="_blank">⚔ Angriff</a>
                        <a class="enemy-action-btn eab-profile" href="https://www.torn.com/profiles.php?XID=${enemy.id}" target="_blank">👤 Profil</a>
                        <button class="enemy-action-btn eab-note"   data-note-enemy="${enemy.id}">📝 Notiz</button>
                        <button class="enemy-action-btn eab-remove" data-remove-enemy="${enemy.id}">✕ Entfernen</button>
                    </div>
                </div>`;
            };
            body.innerHTML=`
            <div class="card" style="flex-shrink:0;">
                <div class="card-header"><span class="card-title red">💀 ENEMY TRACKER</span><div style="display:flex;gap:5px;align-items:center;"><span class="badge badge-red">${enemies.length} Enemies</span><button class="scan-btn" id="thud-enemy-refresh" style="padding:4px 10px;font-size:10px;">${s.enemyFetchRunning?'<span class="spinning">↺</span>':'↺ Refresh'}</button></div></div>
                <div class="card-body" style="padding:10px 14px;gap:7px;"><div style="font-size:10px;color:var(--muted);margin-bottom:2px;">Spieler-ID eingeben:</div><div class="enemy-add-row"><input type="number" class="enemy-id-input" id="thud-enemy-id" placeholder="Spieler ID (z.B. 123456)" min="1"><button class="scan-btn" id="thud-enemy-add" style="white-space:nowrap;">+ Hinzufügen</button></div></div>
            </div>
            ${enemies.length===0?`<div class="empty-state"><div class="es-icon">💀</div><div class="es-text">Keine Enemies</div><div class="es-sub">Füge Spieler-IDs hinzu um sie zu tracken</div></div>`:`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title amber">⚠ ENEMY LIST (${enemies.length})</span><span style="font-size:9px;color:var(--muted);">Auto-Refresh 30s</span></div><div class="card-body p0">${enemies.map(e=>renderRow(e)).join('')}</div></div>`}
            <div style="background:rgba(239,68,68,.06);border:1px solid rgba(239,68,68,.15);border-radius:var(--r);padding:9px 12px;font-size:10px;color:var(--muted);flex-shrink:0;">⚠ Enemy-Reise-Alarm → <b style="color:var(--text);">Alarme → Enemy reist ab</b></div>`;
            document.getElementById('thud-enemy-refresh')?.addEventListener('click',()=>{hud.fetcher.fetchEnemyData();this.renderEnemy();});
            document.getElementById('thud-enemy-add')?.addEventListener('click',()=>{const id=document.getElementById('thud-enemy-id')?.value?.trim();addEnemy(id,'');});
            document.getElementById('thud-enemy-id')?.addEventListener('keydown',e=>{if(e.key==='Enter'){addEnemy(e.target.value?.trim(),'');}});
            body.querySelectorAll('[data-remove-enemy]').forEach(btn=>btn.addEventListener('click',()=>{const id=btn.dataset.removeEnemy;const en=s.enemies.find(e=>String(e.id)===String(id));if(confirm(`Enemy "${en?.name||id}" wirklich entfernen?`)){s.removeEnemy(id);this.renderEnemy();}}));
            body.querySelectorAll('[data-note-enemy]').forEach(btn=>btn.addEventListener('click',()=>{const id=btn.dataset.noteEnemy;const en=s.enemies.find(e=>String(e.id)===String(id));const modal=document.createElement('div');modal.className='thud-modal-bg';modal.innerHTML=`<div class="thud-modal"><h3>📝 Notiz für ${Utils.escHtml(en?.name||id)}</h3><p>Füge eine persönliche Notiz hinzu:</p><textarea id="thud-note-input" placeholder="Deine Notiz...">${Utils.escHtml(en?.note||'')}</textarea><div class="modal-btns"><button class="modal-cancel" id="thud-note-cancel">Abbrechen</button><button class="modal-save" id="thud-note-save">Speichern</button></div></div>`;document.body.appendChild(modal);document.getElementById('thud-note-save').onclick=()=>{s.updateEnemyNote(id,document.getElementById('thud-note-input').value);modal.remove();this.renderEnemy();};document.getElementById('thud-note-cancel').onclick=()=>modal.remove();modal.addEventListener('click',e=>{if(e.target===modal)modal.remove();});}));
        }
 
        // ─── COMPANY TAB ───
        renderCompany() {
            const body=this.body; if(!body)return;
            const cp=this.state.companyProfile, employees=this.state.companyEmployees||[], ws=this.state.workStats;
            const wsHtml=ws?`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title blue">💼 DEINE WORKING STATS</span></div><div class="card-body"><div class="stat-grid stat-grid-3"><div class="stat-card"><div class="sv sv-amber">${Utils.fmtStat(ws.manual)}</div><div class="sl">🛠 Manual</div></div><div class="stat-card"><div class="sv sv-blue">${Utils.fmtStat(ws.intelligence)}</div><div class="sl">🧠 Intel</div></div><div class="stat-card"><div class="sv sv-green">${Utils.fmtStat(ws.endurance)}</div><div class="sl">🏃 Endure</div></div></div></div></div>`:'';
            if(!cp){body.innerHTML=`${wsHtml}<div class="empty-state"><div class="es-icon">🏢</div><div class="es-text">Keine Firmendaten</div><div class="es-sub">Du musst Inhaber oder Direktor sein.</div></div>`;return;}
            const name=cp.name||'—', type=cp.type?.name||(typeof cp.type==='string'?cp.type:'')||cp.company_type||'—', rating=cp.rating??'—';
            const _s=(v)=>{if(v===null||v===undefined)return null;if(typeof v==='number')return v;if(typeof v==='object')return v.value??v.current??v.amount??null;return null;};
            const dailyIncome=Number(cp.income?.daily??cp.daily_income??cp.daily_revenue??0);
            const weeklyProfit=Number(cp.income?.weekly??cp.weekly_profit??0);
            const empHired=cp.employees?.hired??cp.employees_hired??employees.length??0;
            const empCap=cp.employees?.capacity??cp.employees_capacity??'—';
            const effs=employees.map(e=>Number(e.effectiveness?.working_stats?.total??e.effectiveness?.total??e.working_stats?.total??0)).filter(v=>v>0);
            const avgEff=effs.length?Math.round(effs.reduce((a,v)=>a+v,0)/effs.length):(Number(_s(cp.efficiency))||0);
            body.innerHTML=`${wsHtml}
            <div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title amber">🏢 ${Utils.escHtml(name)}</span><span class="badge badge-amber">${Utils.escHtml(String(type))}</span></div>
            <div class="card-body"><div class="company-kpi-grid"><div class="company-kpi"><div class="kv" style="color:var(--green);">${Utils.fmtMoney(dailyIncome)}</div><div class="kl">Täglich</div></div><div class="company-kpi"><div class="kv" style="color:var(--amber);">${Utils.fmtMoney(weeklyProfit)}</div><div class="kl">Wöchentlich</div></div><div class="company-kpi"><div class="kv" style="color:var(--blue);">${empHired}/${empCap}</div><div class="kl">Mitarbeiter</div></div><div class="company-kpi"><div class="kv" style="color:${avgEff>=60?'var(--green)':avgEff>=30?'var(--amber)':'var(--muted)'};">${avgEff>0?avgEff+'%':'—'}</div><div class="kl">Effizienz Ø</div></div></div>${rating!=='—'?`<div class="row"><span class="row-label">⭐ Rating</span><span class="row-value" style="color:var(--amber);">${rating} / 10</span></div>`:''}</div></div>
            ${employees.length>0?`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title green">👷 MITARBEITER</span><span class="badge badge-green">${avgEff>0?avgEff+'%':'—'} Ø</span></div><div class="card-body p0">${employees.slice(0,40).map(e=>{const eff=Number(e.effectiveness?.working_stats?.total??e.effectiveness?.total??e.working_stats?.total??0);const pos=(()=>{const p=e.position??e.role??null;if(!p)return'—';if(typeof p==='string')return p;if(typeof p==='object')return p.name??p.title??'—';return'—';})();const online=((Date.now()/1000-(e.last_action?.timestamp||0))<120);const ec=eff>=60?'var(--green)':eff>=30?'var(--amber)':eff>0?'var(--red)':'var(--muted)';return`<div class="company-emp-row"><span class="status-dot sd-${online?'online':'offline'}" style="flex-shrink:0;"></span><span class="company-emp-name">${Utils.escHtml(e.name||`#${e.id}`)}</span><span class="company-emp-pos">${Utils.escHtml(pos)}</span><span class="company-emp-eff" style="color:${ec};">${eff>0?eff+'%':'—'}</span></div>`;}).join('')}</div></div>`:''}`;
        }
 
        // ─── NETWORTH TAB ───
        renderNetworth() {
            const body=this.body; if(!body)return;
            const nw=this.state.networthData, hist=this.state.networthHistory;
            if(!nw){body.innerHTML=`<div class="empty-state"><div class="es-icon">💰</div><div class="es-text">Lade Vermögensdaten...</div><div class="es-sub">Benötigt Full Access API Key</div></div>`;return;}
            const now=Utils.now(), oh=hist.filter(h=>h.ts>=now-3600);
            const change=oh.length>=2?hist[hist.length-1].val-oh[0].val:0;
            const wallet=Number(nw.wallet??nw.cash??0), bank=Number(nw.bank??0), stocks=Number(nw.stockmarket??nw.stocks??0);
            const totalLiquid=wallet+bank+stocks;
            const bazaar=Number(nw.bazaar??0), props=Number(nw.properties??0), piggy=Number(nw.piggybank??0), fvault=Number(nw.factionvault??0);
            body.innerHTML=`
            <div class="nw-ticker"><div style="font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:4px;">LIQUIDES VERMÖGEN</div><div style="display:flex;align-items:baseline;gap:10px;"><div class="nw-main-val">${Utils.fmtMoney(totalLiquid)}</div>${change!==0?`<div class="nw-change ${change>0?'pos':'neg'}">${change>0?'▲':'▼'} ${Utils.fmtMoney(Math.abs(change))} / 1h</div>`:'<div class="nw-change" style="color:var(--muted);">± —</div>'}</div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title green">💵 LIQUIDITÄT</span></div><div class="card-body"><div class="row"><span class="row-label">💵 Cash</span><span class="row-value" style="color:var(--green);">${Utils.fmtMoney(wallet)}</span></div><div class="row"><span class="row-label">🏦 Bank</span><span class="row-value" style="color:var(--blue);">${Utils.fmtMoney(bank)}</span></div><div class="row"><span class="row-label">📈 Aktien</span><span class="row-value" style="color:var(--amber);">${Utils.fmtMoney(stocks)}</span></div></div></div>
            ${(bazaar||props||piggy||fvault)?`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title">📦 WEITERE ASSETS</span></div><div class="card-body">${bazaar?`<div class="row"><span class="row-label">🏪 Bazaar</span><span class="row-value">${Utils.fmtMoney(bazaar)}</span></div>`:''}${props?`<div class="row"><span class="row-label">🏠 Immobilien</span><span class="row-value">${Utils.fmtMoney(props)}</span></div>`:''}${piggy?`<div class="row"><span class="row-label">🐷 Sparschwein</span><span class="row-value">${Utils.fmtMoney(piggy)}</span></div>`:''}${fvault?`<div class="row"><span class="row-label">🏛 Faction Vault</span><span class="row-value">${Utils.fmtMoney(fvault)}</span></div>`:''}</div></div>`:''} 
            ${hist.length>=2?`<div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title green">📈 VERLAUF</span></div><div class="card-body">${this._simpleChart(hist)}</div></div>`:''}`;
        }
        _simpleChart(hist) {
            if(hist.length<2)return'';
            const vals=hist.map(h=>h.val), mn=Math.min(...vals), mx=Math.max(...vals), range=mx-mn||1;
            const W=280,H=60;
            const pts=hist.map((h,i)=>`${((i/(hist.length-1))*W).toFixed(1)},${(H-((h.val-mn)/range)*H).toFixed(1)}`).join(' ');
            return`<svg viewBox="0 0 ${W} ${H}" style="width:100%;height:56px;overflow:visible;"><polyline points="${pts}" fill="none" stroke="${vals[vals.length-1]>=vals[0]?'var(--green)':'var(--red)'}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
        }
 
        // ─── NOTIFICATIONS TAB ───
        renderNotifications() {
            const body=this.body; if(!body)return;
            const s=this.state;
            const ag=(title,keys)=>{const rows=keys.filter(k=>ALARM_DEFAULTS[k]).map(key=>{const def=ALARM_DEFAULTS[key],on=s.isAlarm(key);return`<div class="alarm-row-item"><div style="flex:1;min-width:0;"><div class="alarm-lbl">${def.label}</div><div class="alarm-desc">${def.desc}</div></div><label class="toggle"><input type="checkbox" data-alarm="${key}" ${on?'checked':''}><span class="toggle-slider"></span></label></div>`;}).join('');return`<div class="settings-section"><div class="settings-section-title">${title}</div>${rows}</div>`;};
            const eT=(s.energyThresholds||[50,75,100]).join(', '), nT=(s.nerveThresholds||[50,100]).join(', ');
            body.innerHTML=`
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div style="display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap;"><button class="thud-btn ${s.store.get('sound',true)?'active':''}" id="thud-toggle-sound">${s.store.get('sound',true)?'🔊 Sound AN':'🔇 Sound AUS'}</button><button class="thud-btn ${s.store.get('notif',true)?'active':''}" id="thud-toggle-notif">${s.store.get('notif',true)?'🔔 Toasts AN':'🔕 Toasts AUS'}</button></div><div class="settings-section-title">SOUND-PROFIL</div><div class="sound-profile-grid">${['classic','military','subtle'].map(p=>`<button class="sp-btn ${s.store.get('soundProfile','classic')===p?'active':''}" data-sp="${p}">${{classic:'🎵 Classic',military:'🪖 Military',subtle:'🔉 Subtle'}[p]}</button>`).join('')}</div></div></div>
            <div class="card" style="flex-shrink:0;">${ag('✈ TRAVEL',['travel_warn','travel_crit','landing_timer'])}${ag('⚡ ENERGIE',['energy_full','energy_thresh','energy_over151'])}${ag('🧠 NERVE',['nerve_full','nerve_thresh'])}${ag('❤ HP',['hp_crit'])}${ag('⏱ COOLDOWNS',['hospital_free','jail_free','drug_ready','booster_ready','medical_ready'])}${ag('⛓ CHAIN',['chain_warn'])}${ag('💀 ENEMY',['enemy_travel'])}</div>
            <div class="card" style="flex-shrink:0;"><div class="card-body" style="padding:12px 14px;gap:10px;"><div class="settings-section-title" style="border:none;padding:0 0 8px;">⚡ ENERGIE SCHWELLWERTE</div><div style="font-size:11px;color:var(--muted);margin-bottom:4px;">Alarme bei diesen % Werten · kein Alarm über ${HAPPY_JUMP_THRESHOLD}</div><div style="display:flex;gap:8px;align-items:center;"><input type="text" class="threshold-input" id="thud-e-thresh" style="width:130px;" value="${eT}" placeholder="50,75,100"><button class="sort-btn" id="thud-e-thresh-save">✓ Speichern</button></div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body" style="padding:12px 14px;gap:10px;"><div class="settings-section-title" style="border:none;padding:0 0 8px;">🧠 NERVE SCHWELLWERTE</div><div style="display:flex;gap:8px;align-items:center;"><input type="text" class="threshold-input" id="thud-n-thresh" style="width:130px;" value="${nT}" placeholder="50,100"><button class="sort-btn" id="thud-n-thresh-save">✓ Speichern</button></div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div class="settings-section-title">TRAVEL ALERT TYP</div>${[['toast','🔔 Toast'],['fullscreen','🖥 Vollbild']].map(([k,lbl])=>`<div class="alarm-row-item"><div class="alarm-lbl">${lbl}</div><label class="toggle"><input type="checkbox" data-ta="${k}" ${s.isTravelAlert(k)?'checked':''}><span class="toggle-slider"></span></label></div>`).join('')}</div></div>`;
            body.querySelectorAll('[data-alarm]').forEach(el=>el.addEventListener('change',e=>s.setAlarm(e.target.dataset.alarm,e.target.checked)));
            body.querySelectorAll('[data-ta]').forEach(el=>el.addEventListener('change',e=>s.setTravelAlert(e.target.dataset.ta,e.target.checked)));
            body.querySelectorAll('[data-sp]').forEach(btn=>btn.addEventListener('click',()=>{hud.store.set('soundProfile',btn.dataset.sp);hud.audio.play('notify');this.renderNotifications();}));
            document.getElementById('thud-toggle-sound')?.addEventListener('click',()=>{hud.store.set('sound',!hud.store.get('sound',true));this.renderNotifications();});
            document.getElementById('thud-toggle-notif')?.addEventListener('click',()=>{hud.store.set('notif',!hud.store.get('notif',true));this.renderNotifications();});
            document.getElementById('thud-e-thresh-save')?.addEventListener('click',()=>{const raw=document.getElementById('thud-e-thresh')?.value||'';const arr=raw.split(',').map(x=>parseInt(x.trim())).filter(x=>!isNaN(x)&&x>0&&x<=100);s.setEnergyThresholds([...new Set(arr)].sort((a,b)=>a-b));hud.toasts.show('✅','Energie-Schwellwerte gespeichert',arr.join(', ')+'%','info',3000);});
            document.getElementById('thud-n-thresh-save')?.addEventListener('click',()=>{const raw=document.getElementById('thud-n-thresh')?.value||'';const arr=raw.split(',').map(x=>parseInt(x.trim())).filter(x=>!isNaN(x)&&x>0&&x<=100);s.setNerveThresholds([...new Set(arr)].sort((a,b)=>a-b));hud.toasts.show('✅','Nerve-Schwellwerte gespeichert',arr.join(', ')+'%','info',3000);});
        }
 
        // ─── SETTINGS TAB ───
        renderSettings() {
            const body=this.body; if(!body)return;
            const s=this.state, fabPinned=hud.store.get('fabPinned',false);
            const visRows=Object.entries(VISIBILITY_DEFAULTS).map(([k,v])=>`<div class="vis-row" style="margin-bottom:3px;"><span class="vis-lbl">${v.label}</span><label class="toggle"><input type="checkbox" data-vis="${k}" ${s.isVisible(k)?'checked':''}><span class="toggle-slider"></span></label></div>`).join('');
            const curLinks=hud.store.get('customQuickLinks',null)||[{label:'Stock\nMarket',icon:'📈',url:'https://www.torn.com/page.php?sid=stocks'},{label:'Casino',icon:'🎰',url:'https://www.torn.com/page.php?sid=slots'},{label:'Bazaar',icon:'🏪',url:'https://www.torn.com/bazaar.php?userId=0'},{label:'Forum',icon:'💬',url:'https://www.torn.com/forums.php'}];
            body.innerHTML=`
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div class="settings-section-title">THEME</div><div class="theme-grid">${Object.entries(THEMES).map(([k,t])=>`<button class="theme-btn ${hud.store.get('theme','obsidian')===k?'active':''}" data-theme="${k}">${t.name}</button>`).join('')}</div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-header"><span class="card-title">🔴 FAB BUTTON</span></div><div class="card-body" style="padding:4px 0 8px;gap:0;"><div class="fab-pin-row"><div><div class="fab-pin-lbl">📌 Position fixieren</div><div class="fab-pin-desc">Button lässt sich nicht mehr verschieben</div></div><label class="toggle"><input type="checkbox" id="thud-fab-pin" ${fabPinned?'checked':''}><span class="toggle-slider"></span></label></div><div style="padding:7px 14px;display:flex;gap:6px;align-items:center;"><button class="sort-btn" id="thud-fab-reset">↺ Position zurücksetzen</button></div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div class="settings-section-title">SICHTBARE ELEMENTE</div><div class="vis-grid">${visRows}</div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body" style="gap:8px;"><div class="settings-section-title">🔗 QUICK LINKS KONFIGURIEREN</div><div style="font-size:10px;color:var(--muted);margin-bottom:4px;">JSON-Array mit label, icon, url.</div><textarea id="thud-ql-json" style="width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--r-sm);padding:8px;color:var(--text);font-family:var(--mono);font-size:10px;min-height:120px;resize:vertical;">${Utils.escHtml(JSON.stringify(curLinks,null,2))}</textarea><div style="display:flex;gap:6px;"><button class="sort-btn" id="thud-ql-save" style="border-color:rgba(16,185,129,.3);color:var(--green);">✓ Speichern</button><button class="sort-btn" id="thud-ql-reset" style="color:var(--muted);">↺ Standard</button></div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div class="settings-section-title">API KEY</div><div class="api-key-row"><span class="api-key-status ${hud.store.get('apiKey')?'set':'unset'}">${hud.store.get('apiKey')?'✓ API Key gesetzt':'⚠ Kein API Key'}</span><button class="thud-btn" id="thud-api-key-btn">🔑 Ändern</button></div></div></div>
            <div class="card" style="flex-shrink:0;"><div class="card-body"><div class="settings-section-title">TASTENKÜRZEL</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;font-size:11px;color:var(--dim);"><span><kbd style="background:var(--bg-el);border:1px solid var(--border);border-radius:3px;padding:1px 5px;font-family:var(--mono);font-size:9px;">M</kbd> Minimieren</span><span><kbd style="background:var(--bg-el);border:1px solid var(--border);border-radius:3px;padding:1px 5px;font-family:var(--mono);font-size:9px;">H</kbd> Ausblenden</span><span><kbd style="background:var(--bg-el);border:1px solid var(--border);border-radius:3px;padding:1px 5px;font-family:var(--mono);font-size:9px;">R</kbd> Refresh</span><span><kbd style="background:var(--bg-el);border:1px solid var(--border);border-radius:3px;padding:1px 5px;font-family:var(--mono);font-size:9px;">S</kbd> Settings</span></div></div></div>
            <div class="ts" style="text-align:center;flex-shrink:0;">${SCRIPT_TITLE} v${VERSION} · by xShaYaKaZ</div>`;
            body.querySelectorAll('[data-theme]').forEach(btn=>btn.addEventListener('click',()=>{hud.store.set('theme',btn.dataset.theme);applyTheme(btn.dataset.theme);this.renderSettings();}));
            body.querySelectorAll('[data-vis]').forEach(el=>el.addEventListener('change',e=>s.setVisible(e.target.dataset.vis,e.target.checked)));
            document.getElementById('thud-api-key-btn')?.addEventListener('click',openApiModal);
            document.getElementById('thud-fab-pin')?.addEventListener('change',e=>hud.store.set('fabPinned',e.target.checked));
            document.getElementById('thud-fab-reset')?.addEventListener('click',()=>{const fab=document.getElementById('thud-fab');if(fab){fab.style.left='10px';fab.style.top='10px';}hud.store.set('fabPos',{l:10,t:10});hud.toasts.show('✅','FAB zurückgesetzt','Links oben','info',2000);});
            document.getElementById('thud-ql-save')?.addEventListener('click',()=>{try{const raw=document.getElementById('thud-ql-json')?.value||'[]';const parsed=JSON.parse(raw);if(!Array.isArray(parsed))throw new Error('Kein Array');hud.store.set('customQuickLinks',parsed);hud.toasts.show('✅','Quick Links gespeichert',`${parsed.length} Links`,'info',3000);this.renderSettings();}catch(e){hud.toasts.show('⚠','JSON Fehler',e.message,'warn',4000);}});
            document.getElementById('thud-ql-reset')?.addEventListener('click',()=>{hud.store.set('customQuickLinks',null);hud.toasts.show('✅','Quick Links zurückgesetzt','Standard wiederhergestellt','info',3000);this.renderSettings();});
        }
 
        _noKeyState() { return`<div class="empty-state" style="padding:48px 24px;"><div class="es-icon">🔑</div><div class="es-text">KEIN API KEY</div><div class="es-sub">Klick um deinen Torn API Key einzugeben</div><button class="scan-btn" style="margin-top:14px;" onclick="document.getElementById('thud-api-key-btn-header').click()">🔑 API Key eingeben</button></div>`; }
        _loadingState() { return`<div class="loading-state">LADE DATEN…</div>`; }
    }
 
    // ═══════════════════════════════════════════════════════════════
    // THEME / MODAL
    // ═══════════════════════════════════════════════════════════════
    function applyTheme(key) {
        const t=THEMES[key]||THEMES.obsidian, r=document.documentElement.style;
        r.setProperty('--bg',t.bg); r.setProperty('--bg-card',t.bgCard); r.setProperty('--bg-el',t.bgEl);
        r.setProperty('--border',t.border); r.setProperty('--accent',t.accent); r.setProperty('--accent2',t.accent2);
        r.setProperty('--text',t.text); r.setProperty('--muted',t.textMuted); r.setProperty('--dim',t.textDim);
        r.setProperty('--green',t.green); r.setProperty('--red',t.red); r.setProperty('--amber',t.amber);
        r.setProperty('--blue',t.blue); r.setProperty('--chain',t.chain); r.setProperty('--travel',t.travel); r.setProperty('--online',t.online);
    }
    function openApiModal() {
        const m=document.createElement('div'); m.className='thud-modal-bg';
        m.innerHTML=`<div class="thud-modal"><h3>⚙ API Key</h3><p>Torn → Settings → API Key</p><input id="thud-api-input" type="text" placeholder="dein_api_key" value="${hud.store.get('apiKey','')}"><div class="modal-btns"><button class="modal-cancel" id="thud-modal-cancel">Abbrechen</button><button class="modal-save" id="thud-modal-save">Speichern</button></div></div>`;
        document.body.appendChild(m);
        document.getElementById('thud-modal-save').onclick=()=>{const k=document.getElementById('thud-api-input').value.trim();if(k){hud.store.set('apiKey',k);m.remove();hud.fetcher.fetchAll();hud.renderer.render();}};
        document.getElementById('thud-modal-cancel').onclick=()=>m.remove();
        m.addEventListener('click',e=>{if(e.target===m)m.remove();});
    }
 
    // ═══════════════════════════════════════════════════════════════
    // HUD CONTROLLER
    // ═══════════════════════════════════════════════════════════════
    const hud = {
        store: new Store(),
        state:null, api:null, audio:null, toasts:null,
        chainManager:null, alarmChecker:null, fetcher:null, renderer:null,
        activeTab:null,
 
        init() {
            this.state        = new StateManager(this.store);
            this.api          = new TornAPI(this.store);
            this.audio        = new AudioManager(this.store);
            this.toasts       = new ToastManager();
            this.chainManager = new ChainManager(this.state);
            this.alarmChecker = new AlarmChecker(this.state, this.toasts);
            this.renderer     = new Renderer(this.state);
            this.activeTab    = this.store.get('activeTab','personal');
            this._injectCSS(); this._buildUI();
            applyTheme(this.store.get('theme','obsidian'));
            this._setupIntervals(); this._setupHotkeys();
            if(!this.api.key) setTimeout(openApiModal,600);
            else this.fetcher.fetchAll();
        },
        _injectCSS() { const st=document.createElement('style'); st.textContent=buildCSS(); document.head.appendChild(st); },
        _buildUI() {
            if(!document.getElementById('thud-toasts')){ const tc=document.createElement('div'); tc.id='thud-toasts'; document.body.appendChild(tc); }
            const fs=document.createElement('div'); fs.id='thud-fs-alert'; fs.className='fullscreen-alert';
            fs.innerHTML=`<div class="fs-box"><div style="font-size:52px;">✈️</div><div class="fs-title">ANKUNFT IN KÜRZE</div><div class="fs-msg" id="thud-fs-msg"></div><button class="fs-close">OK</button></div>`;
            document.body.appendChild(fs); fs.querySelector('.fs-close').addEventListener('click',()=>fs.classList.remove('active'));
            const overlay=document.createElement('div'); overlay.id='thud-overlay';
            const tabsHtml=TABS_DEF.map(t=>`<div class="thud-tab ${this.activeTab===t.id?'active':''}" data-tab="${t.id}"><span class="ti">${t.icon}</span><span class="tl">${t.label}</span></div>`).join('');
            overlay.innerHTML=`
                <div class="thud-header" id="thud-header">
                    <div class="thud-header-logo">${SHAYA_LOGO_SVG}</div>
                    <div class="thud-header-info"><div class="thud-header-title" id="thud-faction-name">${SCRIPT_TITLE}</div><div class="thud-header-sub">v${VERSION} · xShaYaKaZ</div></div>
                    <div class="thud-header-actions"><div class="pip"></div><button class="thud-btn" id="thud-btn-refresh" title="Refresh [R]">↺</button><button class="thud-btn" id="thud-api-key-btn-header" title="API Key">🔑</button><button class="thud-btn" id="thud-btn-minimize" title="[M]">—</button><button class="thud-btn-close" id="thud-btn-close" title="[H]">✕</button></div>
                </div>
                <div class="thud-tabs" id="thud-tabs">${tabsHtml}</div>
                <div class="thud-mini" id="thud-mini"></div>
                <div class="thud-body" id="thud-body"><div class="loading-state">LADE…</div></div>
                <div class="thud-resize-se" id="thud-rse"></div>
                <div class="thud-resize-e"  id="thud-re"></div>
                <div class="thud-resize-s"  id="thud-rs"></div>`;
            document.body.appendChild(overlay);
            const pos=this.store.get('pos',null);
            if(pos){overlay.style.left=pos.l+'px';overlay.style.top=pos.t+'px';}else{overlay.style.right='20px';overlay.style.top='60px';}
            overlay.style.width=this.store.get('width',400)+'px';
            overlay.style.height=(this.store.get('height',null)||560)+'px';
            if(!this.store.get('visible',true))overlay.style.display='none';
            if(this.store.get('minimized',false))overlay.classList.add('minimized');
            const fab=document.createElement('div'); fab.id='thud-fab'; fab.title=`${SCRIPT_TITLE} [H]`; fab.innerHTML=FAB_LOGO_SVG;
            document.body.appendChild(fab);
            const fPos=this.store.get('fabPos',null);
            if(fPos){fab.style.left=fPos.l+'px';fab.style.top=fPos.t+'px';}else{fab.style.left='10px';fab.style.top='10px';}
            if(this.store.get('visible',true))fab.classList.add('on');
            this._setupDrag(overlay); this._setupResize(overlay); this._setupFab(fab);
            this._setupTabWheelScroll(); this._setupScrollFix(overlay);
            document.getElementById('thud-tabs').addEventListener('click',e=>{const t=e.target.closest('.thud-tab');if(!t)return;this.switchTab(t.dataset.tab);});
            document.getElementById('thud-btn-refresh').addEventListener('click',()=>this.fetcher.fetchAll());
            document.getElementById('thud-btn-minimize').addEventListener('click',()=>this.toggleMinimize());
            document.getElementById('thud-btn-close').addEventListener('click',()=>this.toggleVisible());
            document.getElementById('thud-api-key-btn-header').addEventListener('click',openApiModal);
            this.fetcher=new DataFetcher(this.api,this.state,this.toasts,this.renderer);
            this.renderer.render();
        },
        _setupTabWheelScroll() { const tabs=document.getElementById('thud-tabs');if(!tabs)return;tabs.addEventListener('wheel',e=>{e.preventDefault();tabs.scrollLeft+=e.deltaY!==0?e.deltaY:e.deltaX;},{passive:false}); },
        _setupScrollFix(overlay) {
            const getBody=()=>document.getElementById('thud-body');
            overlay.addEventListener('wheel',e=>{const t=e.target.closest('#thud-tabs');if(t)return;const b=getBody();if(!b)return;b.scrollTop+=e.deltaY;e.preventDefault();e.stopPropagation();},{passive:false});
            let ty=0;
            overlay.addEventListener('touchstart',e=>{ty=e.touches[0].clientY;},{passive:true});
            overlay.addEventListener('touchmove',e=>{const b=getBody();if(!b)return;b.scrollTop+=ty-e.touches[0].clientY;ty=e.touches[0].clientY;e.preventDefault();},{passive:false});
        },
        switchTab(tabId) { this.activeTab=tabId; this.store.set('activeTab',tabId); document.querySelectorAll('.thud-tab').forEach(el=>el.classList.toggle('active',el.dataset.tab===tabId)); this.renderer.render(); setTimeout(()=>{const b=document.getElementById('thud-body');if(b)b.scrollTop=0;},50); },
        toggleMinimize() { const v=!this.store.get('minimized',false); this.store.set('minimized',v); const o=document.getElementById('thud-overlay');if(o)o.classList.toggle('minimized',v); if(v)this.renderer.renderMini(); },
        toggleVisible() { const v=!this.store.get('visible',true); this.store.set('visible',v); const o=document.getElementById('thud-overlay');if(o)o.style.display=v?'':'none'; const fab=document.getElementById('thud-fab');if(fab)v?fab.classList.add('on'):fab.classList.remove('on'); },
        _setupDrag(el) {
            let drag=false,ox=0,oy=0;
            document.getElementById('thud-header').addEventListener('mousedown',e=>{if(e.target.tagName==='BUTTON'||e.target.closest('button'))return;e.preventDefault();const r=el.getBoundingClientRect();ox=e.clientX-r.left;oy=e.clientY-r.top;drag=true;});
            document.addEventListener('mousemove',e=>{if(!drag)return;el.style.left=Math.max(0,Math.min(e.clientX-ox,window.innerWidth-el.offsetWidth))+'px';el.style.top=Math.max(0,Math.min(e.clientY-oy,window.innerHeight-40))+'px';el.style.right='auto';});
            document.addEventListener('mouseup',()=>{if(!drag)return;drag=false;this.store.set('pos',{l:parseInt(el.style.left),t:parseInt(el.style.top)});});
        },
        _setupResize(el) {
            let rSE=false,rE=false,rS=false,sx=0,sy=0,sw=0,sh=0;
            document.getElementById('thud-rse').addEventListener('mousedown',e=>{rSE=true;sx=e.clientX;sy=e.clientY;sw=el.offsetWidth;sh=el.offsetHeight;e.preventDefault();e.stopPropagation();});
            document.getElementById('thud-re').addEventListener('mousedown',e=>{rE=true;sx=e.clientX;sw=el.offsetWidth;e.preventDefault();e.stopPropagation();});
            document.getElementById('thud-rs').addEventListener('mousedown',e=>{rS=true;sy=e.clientY;sh=el.offsetHeight;e.preventDefault();e.stopPropagation();});
            document.addEventListener('mousemove',e=>{if(rSE){el.style.width=Math.max(300,Math.min(720,sw+(e.clientX-sx)))+'px';el.style.height=Math.max(250,sh+(e.clientY-sy))+'px';}else if(rE){el.style.width=Math.max(300,Math.min(720,sw+(e.clientX-sx)))+'px';}else if(rS){el.style.height=Math.max(250,sh+(e.clientY-sy))+'px';}});
            document.addEventListener('mouseup',()=>{if(rSE||rE||rS){this.store.set('width',parseInt(el.style.width));if(el.style.height)this.store.set('height',parseInt(el.style.height));}rSE=rE=rS=false;});
        },
        _setupFab(fab) {
            let drag=false,ox=0,oy=0,moved=false,sx=0,sy=0;
            fab.addEventListener('mousedown',e=>{e.preventDefault();drag=true;moved=false;const r=fab.getBoundingClientRect();ox=e.clientX-r.left;oy=e.clientY-r.top;sx=e.clientX;sy=e.clientY;});
            document.addEventListener('mousemove',e=>{if(!drag)return;if(hud.store.get('fabPinned',false)){drag=false;return;}if(Math.abs(e.clientX-sx)>4||Math.abs(e.clientY-sy)>4)moved=true;fab.style.left=Math.max(0,Math.min(window.innerWidth-40,e.clientX-ox))+'px';fab.style.top=Math.max(0,Math.min(window.innerHeight-40,e.clientY-oy))+'px';});
            document.addEventListener('mouseup',()=>{if(!drag)return;drag=false;if(!moved){this.toggleVisible();return;}this.store.set('fabPos',{l:parseInt(fab.style.left),t:parseInt(fab.style.top)});});
        },
        _setupIntervals() {
            setInterval(()=>hud.fetcher.fetchPersonal(),REFRESH.PERSONAL);
            setInterval(()=>hud.fetcher.fetchFaction(), REFRESH.FACTION);
            setInterval(()=>hud.fetcher.fetchChain(),   REFRESH.CHAIN);
            setInterval(()=>hud.fetcher.fetchNetworth(),REFRESH.NETWORTH);
            setInterval(()=>hud.fetcher.fetchCompany(), REFRESH.COMPANY);
            setInterval(()=>hud.fetcher.fetchEnemyData(),REFRESH.ENEMY);
            setInterval(()=>this._tick(),               REFRESH.TICK);
        },
        _setupHotkeys() {
            document.addEventListener('keydown',e=>{ if(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA')return; if(e.key==='m'||e.key==='M')this.toggleMinimize(); if(e.key==='h'||e.key==='H')this.toggleVisible(); if(e.key==='r'||e.key==='R')this.fetcher.fetchAll(); if(e.key==='s'||e.key==='S')this.switchTab('settings'); });
        },
        _tick() {
            this.state.uptimeSec++;
            const td=this.state.userTravel?.travel;
            if(td?.time_left>0)td.time_left=Math.max(0,Number(td.time_left)-1);
            this.alarmChecker.run();
            const min=this.store.get('minimized',false);
            if(!min&&this.activeTab==='personal')this.renderer.renderPersonal();
            if(min)this.renderer.renderMini();
        },
    };
 
    if(document.readyState==='loading'){ document.addEventListener('DOMContentLoaded',()=>hud.init()); }
    else { hud.init(); }
 
})();