☰

🌐 Social

O script social mais completo do Popmundo — O lendário Speed Calling e recursos exclusivos: Radar, Prateleira, Cartão de Personagem, Guia de Interação e muito mais.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como Tampermonkey para instalar este script.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como Tampermonkey ou Violentmonkey para instalar este script.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como Tampermonkey ou Userscripts para instalar este script.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como o Tampermonkey para instalar este script.

VocĂȘ precisarĂĄ instalar um gerenciador de scripts de usuĂĄrio para instalar este script.

(Eu jĂĄ tenho um gerenciador de scripts de usuĂĄrio, me deixe instalĂĄ-lo!)

VocĂȘ precisarĂĄ instalar uma extensĂŁo como o Stylus para instalar este estilo.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como o Stylus para instalar este estilo.

VocĂȘ precisarĂĄ instalar uma extensĂŁo como o Stylus para instalar este estilo.

VocĂȘ precisarĂĄ instalar um gerenciador de estilos de usuĂĄrio para instalar este estilo.

VocĂȘ precisarĂĄ instalar um gerenciador de estilos de usuĂĄrio para instalar este estilo.

VocĂȘ precisarĂĄ instalar um gerenciador de estilos de usuĂĄrio para instalar este estilo.

(Eu jå possuo um gerenciador de estilos de usuårio, me deixar fazer a instalação!)

// ==UserScript==
// @name         🌐 Social
// @name:en      🌐 Social
// @name:pt-BR   🌐 Social
// @namespace    popmundo.social
// @version      3.1
// @description  Popmundo'nun en kapsamlı sosyal scripti — Efsane Speed Calling ve yalnızca burada bulabileceğin Radar Takibi, Raf, Karakter Kartı, İlgilenme Rehberi ve daha fazlası.
// @description:en  The most comprehensive social script for Popmundo — Legendary Speed Calling and features you won't find anywhere else: Radar Tracking, Shelf, Character Card, Interaction Guide and more.
// @description:pt-BR O script social mais completo do Popmundo — O lendário Speed Calling e recursos exclusivos: Radar, Prateleira, Cartão de Personagem, Guia de Interação e muito mais.
// @author       luke-james-gibson
// @license      MIT
// @id           9g1a6x
// @match        https://*.popmundo.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        unsafeWindow
// @run-at       document-end
// ==/UserScript==

(function () {
try {
'use strict';

// POPCONTROL DISABLE CHECK
try { const _ppc = JSON.parse(localStorage.getItem('ppc_enabled')||'{}'); if (_ppc['social'] === false) return; } catch {}

// DEVICE BLOCK — Mobilde çalıßmaz; override için ppsm_soc_mob_ack=1 set et
(function() {
    const _isMob = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(navigator.userAgent);
    if (!_isMob) return; // Desktop — devam
    if (localStorage.getItem('ppsm_soc_mob_ack')) return; // Kullanıcı bypass seçti
    const ov = document.createElement('div');
    ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:99999;display:flex;align-items:center;justify-content:center;font-family:sans-serif;padding:16px';
    ov.innerHTML = '<div style="background:#fff;border-radius:12px;padding:24px;max-width:340px;width:100%;text-align:center">'
        + '<div style="font-size:36px;margin-bottom:8px">đŸ“±</div>'
        + '<div style="font-weight:bold;font-size:15px;margin-bottom:8px">Mobil Cihaz Tespit Edildi</div>'
        + '<div style="font-size:13px;color:#555;margin-bottom:16px">Bu script masaĂŒstĂŒ cihazlar için tasarlanmıßtır. Mobil kullanım için <b>Social Mobile</b> scriptini kullanmanız önerilir.</div>'
        + '<a href="https://greasyfork.org/tr/scripts/568918-social-mobile" target="_blank" style="display:inline-block;margin-bottom:16px;color:#6f42c1;font-weight:bold;font-size:13px;text-decoration:none">đŸ“„ Social Mobile — İndir / Install</a>'
        + '<div style="display:flex;gap:8px;justify-content:center">'
        + '<button id="_ppsm_ack" style="background:#6f42c1;color:#fff;border:none;border-radius:6px;padding:8px 18px;cursor:pointer;font-size:13px;font-family:inherit">Yine de Kullan</button>'
        + '<button id="_ppsm_close" style="background:#eee;border:none;border-radius:6px;padding:8px 18px;cursor:pointer;font-size:13px;font-family:inherit">Kapat</button>'
        + '</div></div>';
    document.body ? document.body.appendChild(ov) : document.addEventListener('DOMContentLoaded', () => document.body.appendChild(ov));
    document.addEventListener('click', function _h(e) {
        if (e.target.id === '_ppsm_ack') { localStorage.setItem('ppsm_soc_mob_ack','1'); location.reload(); }
        if (e.target.id === '_ppsm_ack' || e.target.id === '_ppsm_close') { ov.remove(); document.removeEventListener('click', _h); }
    });
    throw new Error('__ppsm_device_block__');
})();

// CSS
document.head.appendChild(Object.assign(document.createElement('style'), { textContent: `
.tvis-bar{position:fixed;top:0;z-index:9986;background:#f5f0ff;border:1px solid #c9b8f0;border-radius:0 0 0 6px;padding:3px 10px;font-size:11px;display:flex;gap:8px;align-items:center;box-shadow:0 1px 6px rgba(0,0,0,.15)}
.tvis-bar a,.tvis-bar button.tvis-lnk{font-weight:bold;text-decoration:none;color:#6f42c1;cursor:pointer;background:none;border:none;font-size:11px;padding:0}
.tvis-hpanel{display:none;position:fixed;top:26px;z-index:9985;background:#fff;border:1px solid #c9b8f0;border-radius:0 0 0 6px;padding:12px;min-width:240px;max-width:300px;box-shadow:0 4px 12px rgba(0,0,0,.15);max-height:82vh;overflow-y:auto}
.tvis-ov{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:99999;display:flex;align-items:flex-start;padding:40px 10px 10px;justify-content:center;overflow-y:auto}
.tvis-box{background:#fff;border-radius:8px;padding:18px;min-width:320px;max-width:min(95vw,1500px);width:95%;box-shadow:0 4px 24px rgba(0,0,0,.35)}
.tvis-title{font-weight:bold;font-size:14px;margin-bottom:12px}
.tvis-chk{display:flex;align-items:flex-start;gap:6px;margin-bottom:8px;cursor:pointer;font-size:12px;line-height:1.4}
.tvis-chk input{margin-top:2px;flex-shrink:0;cursor:pointer}
.tvis-hr{border:none;border-top:1px solid #e0e0e0;margin:6px 0}
.tvis-sec{font-size:10px;font-weight:bold;color:#888;margin:8px 0 3px;text-transform:uppercase;letter-spacing:.5px}
.tvis-lang-row{display:flex;gap:4px;margin:6px 0}
.tvis-lang-btn{flex:1;padding:3px 4px;border:1px solid #ccc;border-radius:4px;cursor:pointer;font-size:11px;background:#f8f9fa;text-align:center}
.tvis-lang-btn.active{background:#6f42c1;color:#fff;border-color:#6f42c1;font-weight:bold}
.tvis-prow{display:flex;align-items:center;gap:4px;padding:4px 6px;background:#f8f9fa;border-radius:4px;margin-bottom:3px;border:1px solid #e8e8e8;font-size:12px}
.tvis-prow[draggable]{cursor:grab}
.tvis-prow[draggable]:active{opacity:.7}
.tvis-prow.drag-over{border-top:2px solid #6f42c1}
.tvis-plink{flex:1;text-decoration:none;color:#6f42c1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tvis-pnote{font-size:10px;color:#aaa;font-style:italic;max-width:70px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}
.tvis-pedit{background:#f5f0ff;border:1px solid #c9b8f0;border-radius:4px;padding:6px;margin-bottom:3px;font-size:11px}
.tvis-pin-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:8px}
.tvis-ia{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;font-size:12px;text-decoration:none!important;cursor:pointer;background:transparent;border:none;padding:0;margin-left:2px;opacity:.55;vertical-align:middle;line-height:1}
.tvis-ia:hover{opacity:1}
.tvis-ia-wrap{display:inline;white-space:nowrap}
.tvis-iarow{display:flex;align-items:center;gap:4px;padding:4px 6px;background:#f8f9fa;border-radius:4px;margin-bottom:3px;border:1px solid #e8e8e8;font-size:12px}
.tvis-iarow[draggable]{cursor:grab}
.tvis-iarow[draggable]:active{opacity:.7}
.tvis-iarow.drag-over{border-top:2px solid #6f42c1}
.tvis-icon-pick{display:flex;flex-wrap:wrap;gap:3px;margin:4px 0 6px;max-height:120px;overflow-y:auto}
.tvis-icon-pick button{width:26px;height:26px;font-size:13px;cursor:pointer;border-radius:3px;border:1px solid #ddd;background:#fff;padding:0;line-height:1}
.tvis-icon-pick button.sel{border:2px solid #6f42c1;background:#f0ebff}
.tvis-custom-icons{display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px;min-height:8px}
.tvis-custom-chip{background:#f0ebff;border:1px solid #c9b8f0;border-radius:3px;padding:1px 5px;font-size:13px;display:inline-flex;align-items:center;gap:3px}
.tvis-custom-chip button{background:none;border:none;color:#e74c3c;cursor:pointer;font-size:11px;padding:0;line-height:1}
.tvis-notebar{background:#fff9e6;border:1px solid #f0c040;border-radius:4px;padding:5px 8px;margin-top:6px;display:flex;align-items:center;gap:6px}
.tvis-notebar textarea{flex:1;font-size:11px;padding:3px;border:1px solid #ddd;border-radius:3px;resize:none;height:26px;font-family:inherit}
/* CHAR HOVER POPUP */
.tvis-chpop{position:fixed;z-index:99997;background:#fff;border:1px solid #bbb;border-radius:8px;width:380px;display:none;padding:0;overflow:hidden;box-shadow:0 4px 18px rgba(0,0,0,.22);pointer-events:auto}
.tvis-pop-img{width:114px;min-width:114px;height:156px;flex-shrink:0;background:linear-gradient(160deg,#ddd5ff,#9b72f0);display:flex;align-items:center;justify-content:center;font-size:44px}
.tvis-pop-img img{width:114px;height:156px;object-fit:cover}
.tvis-pop-right{flex:1;display:flex;flex-direction:column;border-left:1px solid #ede9ff;min-width:0}
.tvis-pop-head{background:#f5f0ff;padding:7px 9px 5px;border-bottom:1px solid #ede9ff}
.tvis-pop-nameline{display:flex;align-items:center;gap:5px}
.tvis-pop-name{font-weight:700;font-size:12px;color:#2d1e6b;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tvis-pop-copyid{background:#ede9ff;border:1px solid #c9b8f0;color:#6f42c1;border-radius:3px;font-size:9px;padding:1px 5px;cursor:pointer}
.tvis-pop-body{flex:1;padding:5px 9px 4px;display:flex;flex-direction:column;gap:3px;overflow:hidden}
.tvis-pop-links{padding:5px 9px;border-top:1px solid #f0f0f0;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.tvis-pop-link{font-size:17px;opacity:.6;text-decoration:none}
.tvis-pop-link:hover{opacity:1}
.tvis-trackbtn{background:none;border:1px solid #c9b8f0;color:#6f42c1;border-radius:3px;font-size:9px;padding:1px 6px;cursor:pointer;flex-shrink:0}
.tvis-trackbtn.tracked{background:#fff8e6;border-color:#e0a800;color:#c8900a}
.tvis-updatebtn{background:#ede9ff;border:1px solid #c9b8f0;color:#6f42c1;border-radius:3px;font-size:9px;padding:1px 5px;cursor:pointer;display:inline-flex;align-items:center;gap:2px}
.tvis-updatebtn:hover{background:#d4c5f9;border-color:#9b72f0}
/* RADAR BULK PROGRESS */
.tvis-rprog{position:fixed;bottom:20px;left:20px;z-index:999998;background:#2d1e6b;color:#fff;font-size:12px;padding:9px 14px;border-radius:7px;box-shadow:0 4px 16px rgba(0,0,0,.35);display:flex;align-items:center;gap:10px;min-width:220px;max-width:calc(100vw - 40px)}
.tvis-rprog-txt{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tvis-rprog-cancel{background:#e74c3c;border:none;color:#fff;border-radius:4px;font-size:11px;padding:2px 8px;cursor:pointer;flex-shrink:0;min-width:60px}
.tvis-rprog-cancel:hover{background:#c0392b}
.tvis-rprog.done{background:#218838}
.tvis-rprog.stopped{background:#6c757d}
.tvis-toast{position:fixed;bottom:20px;right:20px;background:#2d1e6b;color:#fff;font-size:12px;padding:10px 16px;border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,.35);z-index:999999;opacity:0;transition:opacity .3s;pointer-events:none;max-width:calc(100vw - 40px)}
.tvis-toast.show{opacity:1}

/* Mobile-specific improvements */
@media (max-width: 768px) {
    .tvis-rprog {
        bottom: 10px;
        left: 10px;
        right: 10px;
        min-width: auto;
        padding: 8px 12px;
        font-size: 11px;
    }
    
    .tvis-rprog-cancel {
        padding: 4px 6px;
        font-size: 10px;
        min-width: 50px;
    }
    
    .tvis-toast {
        bottom: 70px;
        left: 10px;
        right: 10px;
        font-size: 11px;
        padding: 8px 12px;
        text-align: center;
    }
    
    #tvis-global-stop {
        padding: 8px;
        font-size: 12px;
    }
}
/* RADAR GRID — no inner scrollbar; outer modal box scrolls */
.tvis-tgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr));gap:6px;overflow-x:hidden}
.tvis-tcard{width:100%;height:156px;min-width:0;border:1px solid #e0e0e0;border-radius:7px;overflow:hidden;background:#fafafa;display:flex;cursor:grab;position:relative;transition:box-shadow .15s,border-color .15s}
.tvis-tcard:hover{box-shadow:0 3px 12px rgba(111,66,193,.15);border-color:#c9b8f0}
.tvis-tcard.tc-online{border-left:3px solid #28a745}
.tvis-tcard.tc-moved{border:2px solid #e74c3c;background:#fff8f8;animation:tvis-pulse 2s infinite}
.tvis-tcard.tc-updated{border-left:3px solid #f0c040;background:#fffef5}
@keyframes tvis-pulse{0%,100%{border-color:#e74c3c}50%{border-color:#ff8080}}
.tvis-tc-img{width:114px;min-width:114px;height:156px;flex-shrink:0;position:relative;overflow:hidden}
.tvis-tc-imgbg{width:114px;height:156px;background:linear-gradient(160deg,#ddd5ff,#9b72f0);display:flex;align-items:center;justify-content:center;font-size:44px}
.tvis-tc-imgbg img{width:114px;height:156px;object-fit:cover;display:block}
.tvis-tc-drag{position:absolute;top:3px;left:3px;color:rgba(255,255,255,.9);font-size:10px;background:rgba(0,0,0,.3);border-radius:2px;padding:0 3px;line-height:1.6;cursor:grab}
.tvis-tc-badge{position:absolute;bottom:4px;left:0;right:0;display:flex;justify-content:center}
.tvis-tc-badge span{font-size:8px;padding:1px 7px;border-radius:10px;color:#fff}
.badge-on{background:rgba(40,167,69,.85)}
.badge-off{background:rgba(100,100,100,.75)}
.badge-mv{background:rgba(231,76,60,.9);font-weight:700}
.badge-upd{background:rgba(240,192,64,.9);color:#333!important}
.tvis-tc-body{flex:1;min-width:0;padding:7px 7px 5px;display:flex;flex-direction:column;gap:2px;border-left:1px solid #ede9ff;overflow:hidden}
.tvis-tc-name{font-weight:700;font-size:10px;color:#6f42c1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-decoration:none;display:block}
.tvis-tc-row{font-size:9px;color:#666;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.35}
.tvis-tc-row a{color:#17a2b8;text-decoration:none}
.tvis-tc-warn{font-size:9px;color:#e74c3c;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tvis-tc-warn.upd{color:#c8900a}
/* Note textarea — 2 lines tall */
.tvis-tc-note{font-size:9px;border:1px solid #e0e0e0;border-radius:3px;padding:2px 4px;width:100%;box-sizing:border-box;resize:none;font-family:inherit;color:#555;height:34px;margin-top:1px}
.tvis-tc-actions{display:flex;gap:3px;align-items:center;margin-top:auto}
.tvis-tc-time{font-size:9px;color:#bbb;white-space:nowrap}
.tvis-tc-ref{background:#ede9ff;border:1px solid #c9b8f0;color:#6f42c1;border-radius:3px;font-size:8px;padding:1px 4px;cursor:pointer}
.tvis-tc-ref:hover{background:#d4c5f9}
.tvis-tc-ok{background:#218838;color:#fff;border:none;border-radius:3px;font-size:8px;padding:1px 4px;cursor:pointer}
.tvis-tc-x{background:#e74c3c;color:#fff;border:none;border-radius:3px;font-size:8px;padding:1px 4px;cursor:pointer}
.tvis-tc-empty{width:100%;height:156px;border:1px dashed #e8e8e8;border-radius:7px;background:#fafafa}
.tvis-page-tab{background:#f8f9fa;border:1px solid #e0e0e0;color:#555;border-radius:4px;font-size:10px;padding:3px 8px;cursor:pointer;white-space:nowrap;transition:background .15s,color .15s}
.tvis-page-tab.active{color:#fff;font-weight:700}
/* RENK SEÇİCİ */
.tvis-cpick{display:flex;flex-wrap:wrap;gap:3px;margin:4px 0 6px;align-items:center}
.tvis-cpick-sw{width:20px;height:20px;border-radius:3px;border:2px solid transparent;cursor:pointer;padding:0;flex-shrink:0}
.tvis-cpick-sw.sel{border-color:#333;transform:scale(1.2)}
.tvis-cpick-sw:hover{transform:scale(1.15)}
.tvis-cpick-custom{width:26px;height:22px;padding:1px;border:1px solid #ccc;border-radius:3px;cursor:pointer;margin-left:2px}
/* RAF */
.tvis-raf-tabs{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:10px}
.tvis-raf-tab{padding:4px 10px;border-radius:4px;border:2px solid #ccc;font-size:11px;cursor:pointer;font-weight:600;background:#fff;white-space:nowrap;transition:.15s;user-select:none}
.tvis-raf-tab.active{color:#fff}
.tvis-raf-tab.drag-over-tab{outline:2px dashed #6f42c1;outline-offset:2px}
.tvis-raf-tab-badge{display:inline-block;background:rgba(0,0,0,.18);color:inherit;font-size:9px;font-weight:700;border-radius:8px;padding:0 4px;margin-left:4px;vertical-align:middle;min-width:14px;text-align:center}
.tvis-raf-tab.active .tvis-raf-tab-badge{background:rgba(255,255,255,.3)}
.tvis-raf-tab-edit{background:none;border:none;font-size:10px;cursor:pointer;opacity:.5;padding:0 2px}
.tvis-raf-tab-edit:hover{opacity:1}
.tvis-raf-recent-tab{padding:4px 10px;border-radius:4px;border:2px dashed #c9b8f0;font-size:11px;cursor:pointer;font-weight:600;background:#fdf8ff;color:#6f42c1;white-space:nowrap;transition:.15s}
.tvis-raf-recent-tab.active{background:#6f42c1;color:#fff;border-color:#6f42c1}
.tvis-raf-colcount{display:flex;align-items:center;gap:4px;margin-bottom:6px;font-size:10px;color:#aaa}
.tvis-raf-colcount button{padding:1px 6px;border:1px solid #ccc;border-radius:3px;background:#fff;font-size:10px;cursor:pointer;color:#666}
.tvis-raf-colcount button.sel{background:#6f42c1;color:#fff;border-color:#6f42c1}
.tvis-raf-grid{display:grid;gap:6px;min-width:600px}
.tvis-raf-col{background:#f8f9fa;border:1px solid #e0e0e0;border-radius:6px;padding:5px;min-height:60px}
.tvis-raf-col.drag-target{outline:2px dashed #6f42c1;background:#f5f0ff}
.tvis-raf-col-head{display:flex;gap:3px;align-items:center;margin-bottom:5px}
.tvis-raf-col-name{flex:1;padding:2px 4px;border:1px solid #ddd;border-radius:3px;font-size:11px;font-weight:600;background:#fff}
.tvis-raf-card{display:flex;align-items:center;gap:3px;padding:3px 5px;background:#fff;border:1px solid #e8e8e8;border-radius:3px;margin-bottom:2px;font-size:11px;cursor:grab}
.tvis-raf-card:active{opacity:.6}
.tvis-raf-card.drag-over{border-top:2px solid #6f42c1}
.tvis-raf-card.colored{border-color:transparent}
.tvis-raf-card-color{width:4px;min-width:4px;border-radius:2px;flex-shrink:0;align-self:stretch}
.tvis-raf-card-ico{flex-shrink:0;font-size:13px}
.tvis-raf-card-lbl{flex:1;text-decoration:none;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tvis-raf-card-lbl:hover{color:#6f42c1}
.tvis-raf-card.colored .tvis-raf-card-lbl{color:inherit}
.tvis-raf-card.colored .tvis-raf-card-lbl:hover{opacity:.85;color:inherit}
.tvis-raf-card-note{font-size:9px;color:#888;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:80px;flex-shrink:0;font-style:italic}
.tvis-raf-card.colored .tvis-raf-card-note{color:inherit;opacity:.75}
.tvis-raf-edit{background:#f8f9fa;border:1px solid #ddd;border-radius:4px;padding:6px;margin-bottom:4px;font-size:11px}
/* WATCH INDICATOR */

.tvis-tab-edit-btn{background:none;border:none;font-size:10px;cursor:pointer;opacity:.5;padding:0 2px;vertical-align:middle}
.tvis-tab-edit-btn:hover{opacity:1}
.tvis-tab-edit-pop{position:fixed;z-index:999999;background:#fff;border:1px solid #c9b8f0;border-radius:6px;padding:8px;box-shadow:0 4px 14px rgba(0,0,0,.2);min-width:220px}
/* Page picker popup */
.tvis-page-picker{position:fixed;z-index:999999;background:#fff;border:1px solid #c9b8f0;border-radius:6px;padding:8px;box-shadow:0 4px 14px rgba(0,0,0,.2);min-width:190px}
/* INTERACT HELPER */
.tvis-ih-bar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:6px;padding:5px 8px;background:#f5f0ff;border:1px solid #c9b8f0;border-radius:5px}
.tvis-ih-typebtn{padding:2px 8px;border-radius:4px;border:1px solid #c9b8f0;background:#fff;color:#6f42c1;font-size:11px;cursor:pointer;font-weight:400;transition:all .12s}
.tvis-ih-typebtn.active{background:#6f42c1;color:#fff;font-weight:700}
.tvis-ih-typebtn.t-arkadaß{border-color:#2196f3;color:#2196f3}
.tvis-ih-typebtn.t-arkadaß.active{background:#2196f3;color:#fff}
.tvis-ih-typebtn.t-romantik{border-color:#e91e63;color:#e91e63}
.tvis-ih-typebtn.t-romantik.active{background:#e91e63;color:#fff}
.tvis-ih-typebtn.t-nefret{border-color:#f44336;color:#f44336}
.tvis-ih-typebtn.t-nefret.active{background:#f44336;color:#fff}
.tvis-ih-warn{background:#fff3cd;border:1px solid #ffc107;border-radius:4px;padding:4px 8px;font-size:11px;color:#856404;margin-bottom:4px}
.tvis-ih-guide-tbl{border-collapse:collapse;font-size:11px;width:100%;min-width:580px}
.tvis-ih-guide-tbl th{background:#f5f0ff;color:#6f42c1;font-size:10px;padding:2px 4px;text-align:left;border-bottom:1px solid #c9b8f0;white-space:nowrap}
.tvis-ih-guide-tbl td{padding:2px 4px;border-bottom:1px solid #f0f0f0;vertical-align:middle}
.tvis-ih-guide-tbl td:first-child{white-space:nowrap}
.tvis-ih-guide-tbl td:nth-child(2){max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tvis-ih-guide-tbl tr:hover td{background:#fdf8ff}.tvis-ih-joy{color:#28a745;font-size:10px;font-weight:600}
.tvis-ih-love{color:#e91e63;font-size:10px;font-weight:600}
.tvis-ih-hate{color:#dc3545;font-size:10px;font-weight:600}
.tvis-ih-note{color:#999;font-size:9px;font-style:italic}
.tvis-ih-badge{display:inline-block;font-size:9px;padding:1px 4px;border-radius:3px;margin-left:3px;font-weight:700}
.tvis-ih-badge-a{background:#e3f2fd;color:#1565c0}
.tvis-ih-badge-r{background:#fce4ec;color:#b71c1c}
.tvis-ih-badge-n{background:#ffebee;color:#b71c1c}
.tvis-ih-jlabel{display:inline-flex;align-items:center;gap:3px;font-size:11px;cursor:pointer;padding:2px 6px;border-radius:3px;border:1px solid #ddd;background:#fff}
.tvis-ih-jlabel.active-no{border-color:#28a745;color:#28a745;background:#f0fff4}
.tvis-ih-jlabel.active-yes{border-color:#e91e63;color:#e91e63;background:#fff0f5}
.frl-addbtn{display:inline-block;margin-left:5px;padding:1px 6px;border-radius:3px;border:1px solid #c9b8f0;background:#f5f0ff;color:#6f42c1;font-size:12px;cursor:pointer;vertical-align:middle;transition:all .15s;line-height:1.5}
.frl-addbtn:hover{background:#e0d0ff;border-color:#9b72f0}
.frl-addbtn.on{background:#6f42c1;color:#fff;border-color:#6f42c1}
.frl-addbtn.on:hover{background:#5a32a3;border-color:#5a32a3}
/* GENRE POPUP */
.tvis-gpop-iframe{width:100%;height:68vh;min-height:480px;border:none;border-radius:4px;display:block}
/* SERENADE HELPER */
.tvis-sh-row{display:flex;gap:6px;align-items:baseline;padding:4px 4px;border-bottom:1px solid #f0f0f0;font-size:11px}
.tvis-sh-row:last-child{border-bottom:none}
.tvis-sh-prefix{font-weight:700;color:#6f42c1;min-width:54px;flex-shrink:0;font-size:10px}
.tvis-sh-track{flex:1;color:#444;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tvis-sh-empty{font-size:11px;color:#999;padding:10px 4px;font-style:italic}
.tvis-sh-list{max-height:52vh;overflow-y:auto;margin-bottom:2px;border:1px solid #ede9ff;border-radius:4px;padding:2px 0}
.tvis-sh-footer{font-size:10px;color:#888;padding:6px 0 2px;border-top:1px solid #e0e0e0;margin-top:6px;display:flex;flex-direction:column;gap:4px}
.tvis-sh-prog{font-size:11px;color:#6f42c1;padding:3px 0;font-weight:600;min-height:16px}
.tvis-sh-warn{font-size:11px;color:#c8900a;padding:2px 0;min-height:14px}
/* SPEED CALLING BAR */
.tvis-sc-bar{position:fixed;top:0;left:0;right:0;z-index:999999;background:#1a1035;color:#fff;font-size:12px;padding:5px 12px;display:flex;align-items:center;gap:10px;box-shadow:0 2px 8px rgba(0,0,0,.4);font-family:inherit}
.tvis-sc-bar a,.tvis-sc-bar button{font-family:inherit}
.tvis-sc-stat{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tvis-sc-name{color:#c9b8f0;font-weight:600}
.tvis-sc-timer{color:#ffd700;font-weight:700;min-width:28px;text-align:center}
.tvis-sc-btn{background:#6f42c1;border:none;color:#fff;border-radius:4px;font-size:11px;padding:3px 10px;cursor:pointer;flex-shrink:0}
.tvis-sc-btn:hover{background:#5a32a3}
.tvis-sc-btn.stop{background:#e74c3c}
.tvis-sc-btn.stop:hover{background:#c0392b}
.tvis-sc-btn.resume{background:#218838}
.tvis-sc-btn.resume:hover{background:#1a6e2e}
.tvis-sc-warn{background:#fff3cd;color:#856404;border:1px solid #ffc107;border-radius:4px;padding:2px 8px;font-size:11px;flex-shrink:0}
/* SPEED CALLING MODAL */
.tvis-sc-phonerow{display:flex;align-items:center;gap:6px;margin-bottom:5px;font-size:12px}
.tvis-sc-phoneinp{flex:1;padding:3px 6px;border:1px solid #c9b8f0;border-radius:4px;font-size:11px;font-family:monospace}
.tvis-sc-charlist{max-height:180px;overflow-y:auto;border:1px solid #e0e0e0;border-radius:4px;margin:4px 0 8px;font-size:11px}
.tvis-sc-charrow{display:flex;align-items:center;gap:6px;padding:3px 7px;border-bottom:1px solid #f0f0f0}
.tvis-sc-charrow:last-child{border-bottom:none}
.tvis-sc-charrow input[type=checkbox]{flex-shrink:0;cursor:pointer}
.tvis-sc-badge{font-size:9px;padding:1px 5px;border-radius:8px;font-weight:700}
.tvis-sc-badge.r{background:#fce4ec;color:#b71c1c}
.tvis-sc-badge.a{background:#e3f2fd;color:#1565c0}
` }));

// UTILS
const CK = {
    get: k => { const m = document.cookie.match(new RegExp('(?:^|; )' + k + '=([^;]*)')); return m ? decodeURIComponent(m[1]) : null; },
    set: (k, v) => { document.cookie = `${k}=${encodeURIComponent(v)};domain=.popmundo.com;path=/;max-age=31536000`; }
};
const gmGet    = (k, def = null) => { try { const v = GM_getValue(k, null); return v !== null ? (typeof v === 'string' && (v[0] === '[' || v[0] === '{') ? JSON.parse(v) : v) : def; } catch { return def; } };
const gmSet    = (k, v)          => GM_setValue(k, typeof v === 'object' ? JSON.stringify(v) : v);
const gmDel    = k               => GM_deleteValue(k);
const mk       = (tag, cls, txt) => { const e = document.createElement(tag); if (cls) e.className = cls; if (txt !== undefined) e.textContent = txt; return e; };
const mkB      = (txt, cls, fn)  => Object.assign(mk('button', cls, txt), { onclick: fn, type: 'button' });
const isOn     = k               => CK.get(k) === '1';
const isOnDef  = (k, def=false)  => { const v = CK.get(k); return v !== null ? v === '1' : def; };
const guard    = (key, ...urls)  => isOnDef(key, true) && (!urls.length || urls.some(u => location.href.includes(u)));
const PM       = '/World/Popmundo.aspx';
const normUrl  = href => { try { const u = new URL(href, location.href); return u.pathname + u.search; } catch { return href; } };

// LANG
const LANG       = CK.get('ppm_lang') || 'TR';
const _D         = (tr, en, pt) => ({ TR: tr, EN: en, PT: pt });
const dateLocale = { TR: 'tr-TR', EN: 'en-GB', PT: 'pt-BR' }[LANG];

const STR = {
    menuTitle:        _D('🌐 Social',                      '🌐 Social',                        '🌐 Social'),
    menuClip:         _D('📋 Pano',                        '📋 Clipboard',                     '📋 Painel'),
    menuRadar:        _D('📍 Radar',                       '📍 Radar',                         '📍 Radar'),
    save:             _D('✔ Tamam',                        '✔ Save',                           '✔ Salvar'),
    close:            _D('Kapat',                          'Close',                            'Fechar'),
    langLabel:        _D('Dil',                            'Language',                         'Idioma'),
    backup:           _D('đŸ“€ Yedekle',                     'đŸ“€ Backup',                        'đŸ“€ Exportar'),
    restore:          _D('đŸ“„ Geri YĂŒkle',                  'đŸ“„ Restore',                       'đŸ“„ Importar'),
    restoreErr:       _D('Geçersiz dosya.',                'Invalid file.',                    'Arquivo invålido.'),
    restoreQ:         _D('Mevcut veriler ne olsun?',       'What to do with current data?',    'O que fazer com os dados atuais?'),
    mergeLbl:         _D('Birleßtir',                      'Merge',                            'Mesclar'),
    replaceLbl:       _D('Üzerine Yaz',                    'Replace',                          'Substituir'),
    cancelLbl:        _D('İptal',                          'Cancel',                           'Cancelar'),
    // features — SOSYAL
    pins:             _D('📌 Rafım — Sanatçı, mekan, ßehir, forum ve favori bağlantıları klasörlĂŒ raflarda sakla',
                         '📌 Shelf — Store artist, locale, city, forum & favourite links in organized shelves',
                         '📌 Prateleira — Salve artistas, locais, cidades, fórum e favoritos em prateleiras'),
    charCard:         _D('⭐ Karakter Kartı — İsme hover\'da anlık bilgi: konum, tavır, online durumu',
                         '⭐ Character Card — Hover for instant info: location, attitude, online status',
                         '⭐ Cartão de Personagem — Hover para info: localização, atitude, status online'),
    radar:            _D('📍 Radar — 10 sekmede 200 karakter takibi',
                         '📍 Radar — Track 200 characters on 10 tabs',
                         '📍 Radar — Rastreie 200 personagens em 10 abas'),
    interactfilter:   _D('👋 İlgilenme Rehberi — Seçeneklere keyif/romantizm/nefret değerlerini göster, filtrele',
                         '👋 Interaction Guide — Show joy/romance/hatred values, filter by type',
                         '👋 Guia de Interação — Mostre valores de alegria/romance/ódio, filtre'),
    quickLinks:       _D('🔗 Hızlı Bağlantılar — Karakter ve mekan sayfalarına mesaj/git/para ver butonları ekle',
                         '🔗 Quick Links — Add message/go/send money buttons to character & locale pages',
                         '🔗 Links RĂĄpidos — BotĂ”es de mensagem/ir/dinheiro em personagens e locais'),
    note:             _D('📝 Karakter Notu — Her profilde kalıcı kißisel not alanı',
                         '📝 Character Note — Persistent personal note field on every profile',
                         '📝 Nota de Personagem — Campo de nota pessoal em cada perfil'),
    // features — ARAÇLAR
    diary:            _D('🔍 GĂŒnlĂŒk Filtresi — GĂŒnlĂŒk girißlerini gerçek zamanlı ara ve filtrele',
                         '🔍 Diary Filter — Real-time search and filter for diary entries',
                         '🔍 Filtro de Diário — Busca em tempo real nas entradas do diário'),
    moneyFmt:         _D('💰 Para Biçimlendirici — BĂŒyĂŒk sayıları otomatik noktalı yaz: 1.500.000',
                         '💰 Money Formatter — Automatically format large amounts: 1,500,000',
                         '💰 Formatador de Dinheiro — Formate valores grandes: 1.500.000'),
    addIcon:          _D('+ Simge Ekle',                   '+ Add Icon',                       '+ Adicionar Ícone'),
    customIconPlh:    _D('Emoji yapıßtır...',              'Paste emoji...',                   'Cole emoji...'),
    customIconTitle:  _D('Özel Simgeler',                  'Custom Icons',                     'Ícones Personalizados'),
    delAllIcons:      _D('🗑 Hepsini Sil',                 '🗑 Delete All',                    '🗑 Excluir Todos'),
    delAllIconsConfirm:_D('TĂŒm özel simgeler silinsin mi?','Delete all custom icons?',         'Excluir todos os Ă­cones?'),
    exportIcons:      _D('đŸ“€ Dıßa Aktar',                  'đŸ“€ Export',                        'đŸ“€ Exportar'),
    emojiRef:         _D('🔗 Simge bul: getemoji.com',     '🔗 Find icons: getemoji.com',      '🔗 Encontrar ícones: getemoji.com'),
    // pins
    pinBtn:           _D('📌 Rafım',                         '📌 Shelf',                        '📌 Prateleira'),
    rafForum:         _D('Forum',              'Forum',              'FĂłrum'),
    rafArtists:       _D('Sanatçılar',         'Artists',            'Artistas'),
    rafLocales:       _D('Mekanlar',           'Locales',            'Locais'),
    rafCities:        _D('ƞehirler',           'Cities',             'Cidades'),
    rafFav:           _D('Favoriler',          'Favorites',          'Favoritos'),
    rafChars:         _D('Karakterler',        'Characters',         'Personagens'),
    rafWork:          _D('İß & StĂŒdyo',        'Work & Studio',      'Trabalho & EstĂșdio'),
    rafGoals:         _D('Hedefler',           'Goals',              'Objetivos'),
    rafColDefault:    _D('Sıra',                              'Lane',                            'Faixa'),
    rafEmpty:         _D('Klasör boß.',                       'Folder is empty.',                'Pasta vazia.'),
    rafEditFolder:    _D('KlasörĂŒ DĂŒzenle',                   'Edit Folder',                     'Editar Pasta'),
    rafEditCol:       _D('SĂŒtunu DĂŒzenle',                   'Edit Column',                     'Editar Coluna'),
    rafItemNote:      _D('Not...',                            'Note...',                         'Nota...'),
    rafDup:           _D('Bu URL zaten eklendi!',             'This URL already added!',         'Este URL jĂĄ foi adicionado!'),
    colorPicker:      _D('Renk Seçici',                       'Color Picker',                    'Seletor de Cor'),
    scAskSC:          _D('Speed Calling listesine de eklensin mi?','Add to Speed Calling list?','Adicionar Ă  lista Speed Calling?'),
    yes:              _D('Evet',                              'Yes',                             'Sim'),
    ppEmpty:          _D('HenĂŒz pin yok.',                 'No pins yet.',                     'Nenhum pin ainda.'),
    ppDup:            _D('Bu sayfa zaten pinli!',          'This page is already pinned!',     'Esta pĂĄgina jĂĄ estĂĄ fixada!'),
    pinAdd:           _D('📌 Yeni Pin Ekle',               '📌 Add New Pin',                   '📌 Adicionar Novo Pin'),
    pinSave:          _D('📌 Pinle',                       '📌 Pin',                           '📌 Fixar'),
    pinName:          _D('Ad:',                            'Name:',                            'Nome:'),
    pinNote:          _D('Not:',                           'Note:',                            'Nota:'),
    pinIcon:          _D('Simge',                          'Icon',                             'Ícone'),
    // clipboard
    chTitle:          _D('📋 Pano Geçmißi',                '📋 Clipboard History',             '📋 HistĂłrico de Área de TransferĂȘncia'),
    chEmpty:          _D('HenĂŒz kopyalanan ID yok.',       'No IDs copied yet.',               'Nenhum ID copiado ainda.'),
    chClear:          _D('TĂŒmĂŒnĂŒ Temizle',                 'Clear All',                        'Limpar Tudo'),
    chCopy:           _D('Kopyala',                        'Copy',                             'Copiar'),
    // quick links (inline actions)
    iaEdit:           _D('🔗 Hızlı Bağlantıları DĂŒzenle', '🔗 Edit Quick Links',              '🔗 Editar Links RĂĄpidos'),
    iaDefaults:       _D('↩ Varsayılana Dön',              '↩ Reset to Defaults',              '↩ Restaurar PadrĂ”es'),
    iaAddSec:         _D('+ Yeni Link',                    '+ New Link',                       '+ Novo Link'),
    iaUrlPlh:         _D('URL yapıßtır...',                'Paste URL...',                     'Cole a URL...'),
    iaUrlInfo:        _D('Kaydedilecek yol:',              'Path to save:',                    'Caminho a salvar:'),
    iaLblPlh:         _D('Buton adı...',                   'Button name...',                   'Nome do botão...'),
    iaSave:           _D('Kaydet',                         'Save',                             'Salvar'),
    // diary
    dfTitle:          _D('🔍 GĂŒnlĂŒk Filtresi',             '🔍 Diary Filter',                  '🔍 Filtro de DiĂĄrio'),
    dfPlh:            _D('Ara...',                         'Search...',                        'Buscar...'),
    dfClear:          _D('Temizle',                        'Clear',                            'Limpar'),
    dfCount:          _D('eßleßme',                        'matches',                          'correspondĂȘncias'),
    dfTotal:          _D('kayıt',                          'entries',                          'entradas'),
    // note
    notePlh:          _D('Bu karakter için not...',        'Note for this character...',       'Nota para este personagem...'),
    // char card popup
    cpLoading:        _D('⏳ YĂŒkleniyor...',               '⏳ Loading...',                    '⏳ Carregando...'),
    cpTrack:          _D('☆ Radar\'a Ekle',                '☆ Add to Radar',                  '☆ Adicionar ao Radar'),
    cpTracked:        _D('⭐ Radarda',                     '⭐ On Radar',                      '⭐ No Radar'),
    cpOffline:        _D('Çevrimdıßı',                     'Offline',                          'Desconectado'),
    cpAttitude:       _D('Tavır',                          'Attitude',                         'Atitude'),
    cpState:          _D('Durum',                          'State',                            'Estado'),
    cpRefresh:        _D('🔄 Manuel GĂŒncelle',             '🔄 Update Manually',               '🔄 Atualizar Manualmente'),
    // radar
    tkTitle:          _D('📍 Takip İstasyonu',             '📍 Tracking Station',              '📍 Estação de Rastreamento'),
    tkEmpty:          _D('Radar boƟ.',                     'Radar is empty.',                  'Radar está vazio.'),
    tkConfirmRm:      _D('Radardan çıkarılsın mı?',        'Remove from radar?',               'Remover do radar?'),
    tkLastSeen:       _D('Son GiriƟ:',                     'Last Seen:',                       'Último Acesso:'),
    tkLastUpd:        _D('','',''),
    tkConfirmOk:      _D('✔ Onayla',                       '✔ Confirm',                        '✔ Confirmar'),
    tkNote:           _D('Not...','Note...','Nota...'),
    tkBgDone:         _D('📍 Radar gĂŒncellendi',           '📍 Radar updated',                 '📍 Radar atualizado'),
    tkBgStopped:      _D('⛔ GĂŒncelleme durduruldu',       '⛔ Update stopped',                 '⛔ Atualização interrompida'),
    tkBgRunning:      _D('📍 Radar gĂŒncelleniyor...',      '📍 Updating radar...',              '📍 Atualizando radar...'),
    tkBgCancel:       _D('Durdur',                         'Stop',                              'Parar'),
    tkUpdate:         _D('🔄 Sayfayı GĂŒncelle',            '🔄 Update Page',                   '🔄 Atualizar PĂĄgina'),
    tkTabEdit:        _D('Sekmeyi DĂŒzenle',                'Edit Tab',                         'Editar Aba'),
    tkGoTo:           _D('Yanına Git',                     'Go To',                            'Ir Para'),
    tkPageSelect:     _D('Hangi sayfaya eklensin?',        'Which page to add to?',            'Em qual pĂĄgina adicionar?'),
    tkPageMove:       _D('Hangi sayfaya taßınsın?',        'Which page to move to?',           'Para qual pĂĄgina mover?'),
    tkPageFull:       _D('Bu sayfa dolu!',                 'This page is full!',               'Esta pĂĄgina estĂĄ cheia!'),
    tkRemove:         _D('⭐ Radardan Çıkar',              '⭐ Remove from Radar',              '⭐ Remover do Radar'),
    tkMove:           _D('↕ Sayfayı Değißtir',            '↕ Move to Page',                   '↕ Mover para PĂĄgina'),
    // planner
    plDesc:           _D('Ne yapılacak?',                  'What to do?',                      'O que fazer?'),
    plDescPlh:        _D('Görev gir...',                   'Enter task...',                    'Digite a tarefa...'),
    plSchedule:       _D('PROGRAM',                        'SCHEDULE',                         'CRONOGRAMA'),
    plTabDef:         _D('Sekme',                          'Tab',                              'Aba'),
    plNoTasks:        _D('Görev yok.',                     'No tasks.',                        'Sem tarefas.'),

    // custom icons
    interactFilter:     _D('İliƟki Tipi:',                    'Relationship Type:',              'Tipo de Relação:'),
    interactAll:        _D('🌐 Standart',                     '🌐 Standard',                     '🌐 Padrão'),
    interactFriend:     _D('đŸ‘„ Arkadaßlık',                   'đŸ‘„ Friendship',                   'đŸ‘„ Amizade'),
    interactRomantic:   _D('💕 Romantizm',                    '💕 Romance',                      '💕 Romance'),
    interactHate:       _D('😡 Nefret',                       '😡 Hatred',                       '😡 Ódio'),
    interactGuide:      _D('â„č Rehber',                       'â„č Guide',                        'â„č Guia'),
    interactGuideTitle: _D('İlgilen Seçenekleri Rehberi',     'Interaction Options Guide',       'Guia de OpçÔes de Interação'),
    interactJealous:    _D('💘 Kıskançlık:',                  '💘 Jealousy:',                    '💘 CiĂșme:'),
    interactJealousNo:  _D('Kıskanmam',                       "Won't be jealous",                'NĂŁo vou ciĂșmar'),
    interactJealousYes: _D('Kıskanırım',                      'Will be jealous',                 'Vou ciĂșmar'),
    interactWarn:       _D('⚠ Romantizm 70+ — Kıskançlık riski yĂŒksek!', '⚠ Romance 70+ — High jealousy risk!', '⚠ Romance 70+ — Alto risco de ciĂșme!'),
    interactColJoy:     _D('Keyif',                           'Joy',                             'Alegria'),
    interactColLove:    _D('Romantizm',                       'Romance',                         'Romance'),
    interactColHate:    _D('Nefret',                          'Hatred',                          'Ódio'),
    interactColNote:    _D('KoƟul',                           'Condition',                       'Condição'),
    interactSave:       _D('Kaydet',                          'Save',                            'Salvar'),
    interactType:       _D('Tip',                             'Type',                            'Tipo'),
    interactName:       _D('Seçenek',                         'Option',                          'Opção'),
    interactDataEdit:   _D('📊 İlgilen Verilerini DĂŒzenle',   '📊 Edit Interact Data',           '📊 Editar Dados de Interação'),
    interactDataId:     _D('Seçenek ID',                      'Option ID',                       'ID da Opção'),
    interactDataAdd:    _D('+ Ekle',                          '+ Add',                           '+ Adicionar'),
    interactDataEmpty:  _D('Özel veri yok.',                  'No custom data.',                 'Nenhum dado personalizado.'),
    interactDataDup:    _D('Bu ID zaten var!',                'This ID already exists!',         'Este ID jĂĄ existe!'),
    interactDataReset:  _D('🗑 TĂŒmĂŒnĂŒ Sil',                  '🗑 Delete All',                   '🗑 Excluir Todos'),
    interactDataResetQ: _D('TĂŒm özel veriler silinsin mi?',   'Delete all custom data?',         'Excluir todos os dados personalizados?'),
    // radar badges
    badgeMoved:         _D('📍 TAƞINDI',                      '📍 MOVED',                        '📍 MUDOU'),
    badgeUpdated:       _D('✎ GĂŒncellendi',                   '✎ Updated',                       '✎ Atualizado'),
    badgeOnline:        _D('● Çevrimiçi',                     '● Online',                        '● Online'),
    // radar card warnings
    tcWarnMoved:        _D('⚠ Önceki:',                      '⚠ Previous:',                    '⚠ Anterior:'),
    tcWarnUpdated:      _D('✎ Tavır/durum değißti',           '✎ Attitude/status changed',       '✎ Atitude/estado mudou'),
    // radar footer
    tcFooterHint:       _D('â ż SĂŒrĂŒkle & sırala · ✏ Sekme dĂŒzenle', 'â ż Drag & sort · ✏ Edit tab', 'â ż Arrastar & ordenar · ✏ Editar aba'),
    tcPage:             _D('Sayfa',                           'Page',                            'PĂĄgina'),
    tcTotal:            _D('Toplam',                          'Total',                           'Total'),
    // misc
    cash:               _D('Nakit',                           'Cash',                            'Dinheiro'),
    // custom icons
    ciNoIcons:          _D('Simge yok!',                      'No icons!',                       'Nenhum Ă­cone!'),
    ciCopied:           _D('📋 Simgeler kopyalandı!',         '📋 Icons copied!',                '📋 Ícones copiados!'),
    // ia reset confirm
    iaResetConfirm:     _D('Varsayılana dön?',                'Reset to defaults?',              'Restaurar padrÔes?'),
    // ia exclusion list
    iaExcl:             _D('đŸš« Dıßlama Listesi',              'đŸš« Exclusion List',               'đŸš« Lista de ExclusĂŁo'),
    iaExclTitle:        _D('đŸš« Hızlı Bağlantı Dıßlama Listesi', 'đŸš« Quick Links Exclusion List', 'đŸš« Lista de ExclusĂŁo de Links RĂĄpidos'),
    iaExclEmpty:        _D('Dıßlama listesi boß.',             'Exclusion list is empty.',        'Lista de exclusĂŁo vazia.'),
    iaExclAddMe:        _D('➕ Kendimi Ekle',                  '➕ Add Myself',                   '➕ Adicionar-me'),
    iaExclAdd:          _D('+ Ekle',                           '+ Add',                           '+ Adicionar'),
    iaExclIdPlh:        _D('Karakter ID...',                   'Character ID...',                 'ID do Personagem...'),
    iaExclNamePlh:      _D('İsim (opsiyonel)...',              'Name (optional)...',              'Nome (opcional)...'),
    iaExclType:         _D('TĂŒr:',                             'Type:',                           'Tipo:'),
    iaExclDel:          _D('Sil',                              'Delete',                          'Excluir'),
    iaExclNoId:         _D('ID bulunamadı — karakter sayfasında dene.', 'ID not found — try on a character page.', 'ID nĂŁo encontrado — tente em uma pĂĄgina de personagem.'),
    // genre popup
    genrePopupBtn:      _D('đŸŽŒ TĂŒr PopĂŒlerliğini Gör',       'đŸŽŒ View Genre Popularity',        'đŸŽŒ Ver Popularidade do GĂȘnero'),
    genrePopupTitle:    _D('đŸŽŒ MĂŒzik TĂŒrĂŒ PopĂŒlerliği',      'đŸŽŒ Genre Popularity',             'đŸŽŒ Popularidade do GĂȘnero'),
    // serenade helper
    shBtn:              _D('đŸŽ” Serenat Helper',               'đŸŽ” Serenade Helper',              'đŸŽ” Ajudante de Serenata'),
    shTitle:            _D('đŸŽ” Serenat Helper',               'đŸŽ” Serenade Helper',              'đŸŽ” Ajudante de Serenata'),
    shNoCache:          _D('Cache yok — gĂŒncelle butonuna bas.',  'No cache — press update.',    'Sem cache — pressione atualizar.'),
    shLastUpd:          _D('Son gĂŒncelleme:',                 'Last update:',                    'Última atualização:'),
    shNextUpd:          _D('Sonraki gĂŒncelleme:',             'Next update:',                    'PrĂłxima atualização:'),
    shUpdateBtn:        _D('🔄 GĂŒncelle',                    '🔄 Update',                       '🔄 Atualizar'),
    shRadioLink:        _D('đŸ“» Radyo Sıralamaları',          'đŸ“» Radio Charts',                 'đŸ“» Paradas de RĂĄdio'),
    shWarn1:            _D('Son gĂŒncelleme: {date} — Çarßamba 10:00 CET\'e kadar gĂŒncellemeye gerek yok.',
                            'Last update: {date} — No update needed until Wednesday 10:00 CET.',
                            'Última atualização: {date} — Sem necessidade atĂ© quarta 10:00 CET.'),
    shWarn2:            _D('GĂŒncelleme gerçekten gerekli mi? Tekrar bas.',
                            'Is an update really necessary? Press again.',
                            'A atualização é realmente necessåria? Pressione novamente.'),
    shFetching:         _D('đŸ“» İstasyon yĂŒkleniyor: {n}/17', 'đŸ“» Fetching station: {n}/17',     'đŸ“» Buscando estação: {n}/17'),
    shDone:             _D('✅ GĂŒncelleme tamamlandı!',      '✅ Update complete!',              '✅ Atualização concluĂ­da!'),
    shErr:              _D('❌ Bir hata oluƟtu.',            '❌ An error occurred.',            '❌ Erro ao atualizar.'),
    shNoneMatched:      _D('Bu restoranda radyo listesiyle eßleßen ßarkı bulunamadı.',
                            'No songs matched the radio list at this restaurant.',
                            'Nenhuma mĂșsica correspondeu Ă  lista de rĂĄdio neste restaurante.'),
    // feature toggles
    genrePopup:         _D('đŸŽŒ TĂŒr PopĂŒlerliği — ƞarkı eklerken tĂŒr popĂŒlerliği popup\'ı',
                            'đŸŽŒ Genre Popularity — Popup when adding songs to repertoire',
                            'đŸŽŒ Popularidade do GĂȘnero — Popup ao adicionar mĂșsicas'),
    serenadeHelper:     _D('đŸŽ” Serenat Helper — Serenat sayfasında radyo önekleri ve gĂŒncelleme',
                            'đŸŽ” Serenade Helper — Radio prefixes & cache on serenade page',
                            'đŸŽ” Ajudante de Serenata — Prefixos de rĂĄdio na serenata'),
    speedcall:      _D('📞 Hızlı Arama — Arkadaß ve romantik karakterleri sırayla otomatik ara; aralık ve telefon seçenekleri ayarlanabilir',
                        '📞 Speed Calling — Auto-call friends & romantics in sequence; adjustable interval and call options',
                        '📞 Ligação RĂĄpida — Ligue automaticamente para amigos e romĂąnticos em sequĂȘncia; intervalo e opçÔes ajustĂĄveis'),
    // hardcoded strings
    folderTitle:        _D('Baßlık',                          'Title',                           'TĂ­tulo'),
    recentTab:          _D('🕐 Son Eklenenler',               '🕐 Recently Added',               '🕐 Adicionados Recentemente'),
    recentEmpty:        _D('HenĂŒz kayıtlı Ă¶ÄŸe yok.',         'No saved items yet.',             'Nenhum item salvo ainda.'),
    recentCount:        _D('Son {n} eklenen',                 'Last {n} added',                  'Últimos {n} adicionados'),
    goToFolder:         _D('Klasöre git',                     'Go to folder',                    'Ir para pasta'),
    colLabel:           _D('SĂŒtun:',                          'Column:',                         'Coluna:'),
    addWhere:           _D('Nereye ekleyelim?',               'Where to add?',                   'Onde adicionar?'),
    deleteEntry:        _D('Bu kaydı sil?',                   'Delete this entry?',              'Excluir este registro?'),
    interactDataWip:    _D('⚠ Bu bölĂŒm çalıßma aßamasındadır — eklenen veriler rehbere ve dropdown\'a anında yansır.',
                            '⚠ This section is a work in progress — added data reflects immediately.',
                            '⚠ Esta seção estĂĄ em desenvolvimento — os dados adicionados refletem imediatamente.'),
    interactDataLegend: _D('✓ = Bu sayfada mevcut · Soluk = Sadece rehberde · 🟱 Arka plan = Kullanıcı ekledi',
                            '✓ = On this page · Faded = Guide only · 🟱 Background = User added',
                            '✓ = Nesta pĂĄgina · Esmaecido = Apenas guia · 🟱 Fundo = Adicionado pelo usuĂĄrio'),
    // speed calling
    scBtn:          _D('📞 Ara',                        '📞 Call',                          '📞 Ligar'),
    scTitle:        _D('📞 Speed Calling',              '📞 Speed Calling',                 '📞 Speed Calling'),
    scInterval:     _D('Arama arası (sn):',             'Interval (sec):',                  'Intervalo (seg):'),
    scIntervalNote: _D('+ 0-2sn rastgele eklenir',      '+ 0-2s random added',              '+ 0-2s aleatĂłrio'),
    scPhoneIds:     _D('Telefon Seçenek ID\'leri',      'Phone Option IDs',                 'IDs de Opção de Telefone'),
    scPhoneNote:    _D('VirgĂŒlle ayır · Soldan denenecek · GĂŒncel ID bilinmiyorsa boß bırak',
                        'Comma separated · Tried left to right · Leave empty if unknown',
                        'Separado por vírgula · Da esquerda para direita · Deixe vazio se desconhecido'),
    scFriendIds:    _D('Arkadaß aramaları:',            'Friendship calls:',                'LigaçÔes de amizade:'),
    scRomIds:       _D('Romantik aramalar:',            'Romantic calls:',                  'LigaçÔes romùnticas:'),
    scWho:          _D('Kimler aransın?',               'Who to call?',                     'Quem ligar?'),
    scWhoFriend:    _D('Arkadaßlar',                    'Friends',                          'Amigos'),
    scWhoRom:       _D('Romantikler',                   'Romantics',                        'RomĂąnticos'),
    scStart:        _D('▶ Baßlat',                      '▶ Start',                          '▶ Iniciar'),
    scResume:       _D('▶ Kaldığı Yerden Devam',        '▶ Resume',                         '▶ Retomar'),
    scReset:        _D('â†ș Sıfırla',                     'â†ș Reset',                          'â†ș Reiniciar'),
    scNoChars:      _D('Aramak için kayıtlı arkadaß/romantik karakter bulunamadı.',
                        'No saved friend/romantic characters found.',
                        'Nenhum personagem amigo/romĂąntico encontrado.'),
    scBarCalling:   _D('📞 Aranıyor:',                  '📞 Calling:',                      '📞 Ligando:'),
    scBarDone:      _D('✅ TĂŒm aramalar tamamlandı!',   '✅ All calls done!',               '✅ Todas as ligaçÔes concluĂ­das!'),
    scBarStop:      _D('Durdur',                        'Stop',                             'Parar'),
    scBarResume:    _D('Devam Et',                      'Resume',                           'Continuar'),
    scBarSkip:      _D('Geç',                           'Skip',                             'Pular'),
    scBarFail:      _D('⚠ 2 ardıßık hata — Script arama yapamıyor!', '⚠ 2 consecutive errors — Script cannot call!', '⚠ 2 erros consecutivos — Script nĂŁo consegue ligar!'),
    scBarFailNote:  _D('Denemeye devam et?',            'Continue trying?',                 'Continuar tentando?'),
    scBarOf:        _D('/',                             '/',                                '/'),
    scBarNext:      _D('Sonraki:',                      'Next:',                            'PrĂłximo:'),
    scBarNoId:      _D('ID bulunamadı — atlandı',       'No ID found — skipped',            'ID nĂŁo encontrado — pulado'),
};

const _clSocial = (() => { try { const v = localStorage.getItem('ppc_lc_social'); return v ? JSON.parse(v) : null; } catch { return null; } })();
const s  = k => { if (_clSocial && _clSocial[k]) return _clSocial[k]; const v = STR[k]; if (!v) return k; return v[LANG] ?? v['TR'] ?? k; };

    // SETTINGS KEYS (cookies)
const K = {
    pins:          'tvis_feat_pins',
    charPopup:     'tvis_feat_chpopup',
    tracking:      'tvis_feat_tracking',
    ia:            'tvis_feat_ia',
    note:          'tvis_feat_cnote',
    diary:         'tvis_feat_dfl',
};

// DATA KEYS (GM_setValue)
const DK = {
    PINS:        'tvis_pins',
    CLIP:        'tvis_clip',
    IA:          'tvis_ia_',
    CACHE:       'tvis_char_cache',
    TRACK:       'tvis_track',      // legacy — kept for backup compat
    TRACK_V2:    'tvis_track_v2_',  // prefix; append page index 0-9
    TRACK_PAGE:  'tvis_track_page',
    NOTES:       'tvis_notes',
    LAST_NOTIF:  'ayu_last_notif_date',
    RADAR_TABS:  'tvis_radar_tabs',
    RAF:         'tvis_raf',
    WATCH:       'tvis_watch_state',
    WATCH_NOTIF: 'tvis_watch_notified',
    CUSTOM_ICONS:'tvis_custom_icons',
    INTERACT_TYPE: 'tvis_interact_type_',
    INTERACT_CUSTOM: 'tvis_interact_custom',
    RADIO_CACHE: 'tvis_radio_cache',
    SPEEDCALL_Q:     'tvis_sc_queue',
    SPEEDCALL_STATE: 'tvis_sc_state',
    SPEEDCALL_CFG:   'tvis_sc_cfg',
    SC_CHARS:        'tvis_sc_chars',
    IA_EXCL:         'tvis_ia_excl',
};

// RADAR TABS
const RADAR_PAGE_SIZE = 20;
const RADAR_PAGES     = 10;

// Radar V2 helpers (per-page independent arrays, no sentinels)
const getRadarPage  = idx => gmGet(DK.TRACK_V2 + idx, []) || [];
const setRadarPage  = (idx, arr) => gmSet(DK.TRACK_V2 + idx, arr);
const getTrackedPage = charId => {
    for (let i = 0; i < RADAR_PAGES; i++) {
        if (getRadarPage(i).some(e => String(e.charId) === String(charId))) return i;
    }
    return -1;
};
const isTrackedV2 = charId => getTrackedPage(charId) >= 0;
const removeFromRadar = charId => {
    for (let i = 0; i < RADAR_PAGES; i++) {
        const p = getRadarPage(i);
        const idx = p.findIndex(e => String(e.charId) === String(charId));
        if (idx >= 0) { p.splice(idx, 1); setRadarPage(i, p); return true; }
    }
    return false;
};
const addToRadar = (pageIdx, entry) => {
    if (getRadarPage(pageIdx).length >= RADAR_PAGE_SIZE) return false;
    if (isTrackedV2(entry.charId)) return false;
    const p = getRadarPage(pageIdx);
    p.push(entry);
    setRadarPage(pageIdx, p);
    return true;
};
const moveInRadar = (charId, newPageIdx) => {
    const oldPage = getTrackedPage(charId);
    if (oldPage < 0) return false;
    const oldArr = getRadarPage(oldPage);
    const idx = oldArr.findIndex(e => String(e.charId) === String(charId));
    if (idx < 0) return false;
    const [entry] = oldArr.splice(idx, 1);
    setRadarPage(oldPage, oldArr);
    const newArr = getRadarPage(newPageIdx);
    newArr.push(entry);
    setRadarPage(newPageIdx, newArr);
    return true;
};
const updateInRadar = (charId, data) => {
    const pageIdx = getTrackedPage(charId);
    if (pageIdx < 0) return;
    const p = getRadarPage(pageIdx);
    const idx = p.findIndex(e => String(e.charId) === String(charId));
    if (idx >= 0) { p[idx] = { ...p[idx], ...data, savedAt: Date.now() }; setRadarPage(pageIdx, p); }
};
const getAllTracked = () => {
    const all = [];
    for (let i = 0; i < RADAR_PAGES; i++) getRadarPage(i).forEach(e => all.push(e));
    return all;
};

const DEFAULT_RADAR_TABS = [
    { icon:'⭐', name:'YAKIN TAKİP', color:'#ffd700' },
    { icon:'đŸ‘Ș', name:'AİLE',        color:'#28a745' },
    { icon:'đŸ€', name:'ARKADAƞ',     color:'#007bff' },
    { icon:'🎯', name:'TAKİP',       color:'#fd7e14' },
    { icon:'⚔', name:'RAKİP',       color:'#dc3545' },
    { icon:'🎾', name:'BAND',        color:'#6f42c1' },
    { icon:'đŸ’Œ', name:'İƞ',          color:'#17a2b8' },
    { icon:'🌐', name:'DÜNYA',       color:'#20c997' },
    { icon:'📌', name:'ÖZEL',        color:'#e83e8c' },
    { icon:'📡', name:'DİĞER',       color:'#6c757d' },
];

const getRadarTabs = () => {
    const saved = gmGet(DK.RADAR_TABS, null);
    if (saved && Array.isArray(saved) && saved.length >= RADAR_PAGES) return saved;
    // Migrate if shorter
    if (saved && Array.isArray(saved) && saved.length > 0) {
        const merged = DEFAULT_RADAR_TABS.map((def, i) =>
            saved[i] ? { ...def, ...saved[i] } : def
        );
        return merged;
    }
    return DEFAULT_RADAR_TABS.map(t => ({ ...t }));
};

// CUSTOM ICONS
const getCustomIcons = () => gmGet(DK.CUSTOM_ICONS, []) || [];

// BACKUP & RESTORE
const dbExport = () => {
    const data = { v: 2, script: 'social', cookies: {}, gm: {} };
    Object.values(K).forEach(k => { const v = CK.get(k); if (v !== null) data.cookies[k] = v; });
    data.cookies['ppm_lang'] = CK.get('ppm_lang') || 'TR';
    [DK.PINS, DK.RAF, DK.CLIP, DK.CACHE, DK.NOTES, DK.RADAR_TABS, DK.CUSTOM_ICONS, DK.INTERACT_CUSTOM, DK.SPEEDCALL_CFG].forEach(k => {
        const v = gmGet(k, null); if (v !== null) data.gm[k] = v;
    });
    // Radar V2 pages
    for (let i = 0; i < RADAR_PAGES; i++) {
        const k = DK.TRACK_V2 + i; const v = gmGet(k, null); if (v !== null) data.gm[k] = v;
    }
   ['character','locale','artist','city'].forEach(sec => {
        const k = DK.IA + sec, v = gmGet(k, null); if (v !== null) data.gm[k] = v;
    });
    const d = new Date(), p = n => String(n).padStart(2,'0');
    const a = document.createElement('a');
    a.href = URL.createObjectURL(new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }));
    a.download = `ppm-social-${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}.json`;
    a.click();
};

const dbImport = () => {
    const inp = Object.assign(document.createElement('input'), { type: 'file', accept: '.json' });
    inp.onchange = () => {
        const f = inp.files[0]; if (!f) return;
        const reader = new FileReader();
        reader.onload = ev => {
            let data; try { data = JSON.parse(ev.target.result); } catch { alert(s('restoreErr')); return; }
            mkModal(s('restore'), (cont, close) => {
                cont.appendChild(mk('div','',s('restoreQ'))).style.cssText='font-size:13px;margin-bottom:12px';
                const apply = (mode) => {
                    close();
                    if (mode === 'merge') {
                        if (data.cookies) Object.entries(data.cookies).forEach(([k,v]) => { if (CK.get(k) === null) CK.set(k,v); });
                        if (data.gm)      Object.entries(data.gm).forEach(([k,v])      => { if (gmGet(k, null) === null) gmSet(k,v); });
                    } else {
                        if (data.cookies) Object.entries(data.cookies).forEach(([k,v]) => CK.set(k,v));
                        if (data.gm)      Object.entries(data.gm).forEach(([k,v])      => gmSet(k,v));
                    }
                    location.reload();
                };
                const row = mk('div'); row.style.cssText='display:flex;gap:8px';
                row.append(mkB(s('mergeLbl'),'btn-b',()=>apply('merge')), mkB(s('replaceLbl'),'btn-r',()=>apply('replace')), mkB(s('cancelLbl'),'btn-grey',close));
                cont.appendChild(row);
            });
        };
        reader.readAsText(f);
    };
    inp.click();
};

// DRAG & DROP
const mkDraggable = (container, onReorder) => {
    let drag = null;
    container.addEventListener('dragstart', e => { drag = e.target.closest('[draggable]'); drag?.classList.add('dragging'); });
    container.addEventListener('dragend', () => {
        drag?.classList.remove('dragging');
        container.querySelectorAll('.drag-over').forEach(el => el.classList.remove('drag-over'));
        if (drag) onReorder([...container.querySelectorAll('[draggable]')].map(el => el.dataset.did));
        drag = null;
    });
    container.addEventListener('dragover', e => {
        e.preventDefault();
        if (!drag) return; // Obje tutulmadan tetiklenmeyi engelle
        const tgt = e.target.closest('[draggable]'); if (!tgt || tgt === drag) return;
        container.querySelectorAll('.drag-over').forEach(el => el.classList.remove('drag-over'));
        tgt.classList.add('drag-over');
        const r = tgt.getBoundingClientRect();
        container.insertBefore(drag, e.clientY > r.top + r.height / 2 ? tgt.nextSibling : tgt);
    });
    container.addEventListener('drop', e => e.preventDefault());
};

// ICON PICKER (includes custom icons at top)
const ICONS = [
    '🧑','đŸ‘€','👑','🎭','đŸ•”ïž','🧙','🩾','💃','đŸ•ș','đŸŽ€','🧛','🧟','🧝','🧜','đŸ€Ž','👾','đŸ€”','đŸ‘©â€đŸŽ€','đŸ‘šâ€đŸŽ€','đŸ€©','😎',
    '😀','😃','😄','😁','😆','😅','😂','🙂','🙃','😉','😊','😇','đŸ„°','😍','đŸ€—','đŸ€­','đŸ€«','đŸ€”','đŸ«Ą','đŸ€ ','đŸ„ł',
    'đŸ˜ș','😾','đŸ˜č','đŸ˜»','đŸ˜Œ','đŸ˜œ','🙀','😿','đŸ˜Ÿ','👋','đŸ€š','✋','đŸ–ïž','🖖','👌','đŸ€Œ','đŸ€','✌','đŸ€ž','đŸ€Ÿ','đŸ€˜','đŸ€™',
    '👈','👉','👆','👇','☝','👍','👎','✊','👊','đŸ€›','đŸ€œ','👏','🙌','👐','đŸ€Č','đŸ€','đŸŽ”','đŸŽ¶','🎾','đŸŽč','đŸŽș','đŸŽ»',
    'đŸ„','đŸŽ·','đŸŽŒ','đŸŽ™ïž','đŸŽšïž','đŸŽ›ïž','🔊','📱','📣','🎧','đŸȘ•','🏠','🏡','🏱','đŸ€','đŸ„','🏩','🏹','đŸ©','đŸȘ','đŸ«','🏬',
    '🏭','🏯','🏰','đŸ—Œ','đŸ—œ','â›Ș','🕌','đŸŽȘ','🎠','🎡','đŸŸïž','đŸšȘ','đŸ›‹ïž','đŸ›ïž','🌆','🌇','🌃','🌉','🌁','🌍','đŸ—ș','📍',
    '⛰','đŸ•ïž','đŸïž','đŸ–ïž','🚀','🚒','✈','🍳','đŸŒŸ','đŸ«','⚖','🔧','🏭','🎓','🎬','✈','đŸ›©ïž','🚀','🛾','đŸ›°ïž','🚁','đŸ›¶',
    'â›”','đŸš€','🚱','🚗','🚕','🚙','🚌','đŸŽïž','🚓','🚑','🧭','🧳','☀','đŸŒ€ïž','đŸŒ„ïž','đŸŒŠïž','đŸŒ©ïž','đŸŒšïž','❄','⛄','đŸŒŹïž','💹',
    'đŸŒȘ','đŸŒ«ïž','🌈','☂','☔','🌙','⚡','🌊','đŸŒ±','🌿','🍀','đŸŒ”','🌮','🌳','đŸŒČ','đŸȘ”','đŸŒŸ','đŸŒș','🌾','đŸŒŒ','đŸŒ»','đŸŒč','đŸ„€',
    'đŸŒ·','🍁','🍂','🍃','🩁','🐯','🩊','đŸș','🩝','đŸ»','🐗','🐮','🐐','🐑','🐄','🩒','🐘','🩛','🐁','🐀','🩄','đŸČ','🐉',
    '🐊','🐱','🩎','🐍','🩅','🩉','🩋','🩆','🩱','đŸŠ©','🩚','🩜','🩇','🐩','🐧','🐟','🐠','🐬','🐳','🩈','🩂','đŸ•·ïž','đŸ•žïž',
    '🐞','🐜','🐝','đŸŸ','đŸș','đŸ»','đŸ„‚','đŸ·','🍾','đŸč','đŸ„ƒ','đŸŸ','☕','🧃','đŸ”','🧋','đŸ„€','đŸŒ','đŸ„›','🍕','🍔','🌼','🍜','🍣',
    'đŸ±','🎂','🍰','đŸ«','🍬','🌭','đŸ„—','đŸ„˜','đŸČ','🍛','🍝','đŸ„Ÿ','đŸ€','🍚','🍱','🍡','🍧','🍹','🍩','đŸ„§','🧁','🍼','🧊',
    '🍏','🍎','🍊','🍋','🍌','🍉','🍇','🍓','🍒','🍑','🍍','đŸ„„','đŸ„','🍅','đŸ„‘','đŸ„•','đŸŒœ','đŸŒ¶ïž','đŸ„’','đŸ„Š','🧄','🍄','đŸ„”',
    '🍞','đŸ„','đŸ„–','🧀','đŸ„š','🍳','đŸ„ž','🧇','đŸ„“','🍗','🍖','⭐','🌟','đŸ’«','✹','đŸ”„','❀','🧡','💛','💚','💙','💜','đŸ–€',
    'đŸ€','đŸ€Ž','💎','💰','🏆','đŸ„‡','đŸ„ˆ','đŸ„‰','đŸŽ–ïž','🏅','đŸ’Œ','📋','📊','📈','📉','📂','đŸ—ƒïž','📌','🔖','đŸ·ïž','✂','đŸ–Šïž','đŸ–‹ïž',
    '✒','📝','⌚','⏰','⌛','⏳','🎉','🎊','🧾','đŸȘ…','🧹','đŸȘ“','🔔','⏱','âČ','đŸ•°ïž','⌚','đŸ–±ïž','📀','📾','đŸ•Żïž','đŸȘ”','📃',
    '📜','📄','đŸ–‡ïž','đŸ§·','đŸ§Ÿ','đŸ—‚ïž','đŸ—„ïž','đŸ—‘ïž','đŸȘŁ','⛓','🛌','🚿','🛁','đŸšœ','đŸ§»','đŸ…°ïž','đŸ…±ïž','🆒','🆓','🆔','🆕','🆗','‎',
    '—','🔙','🔚','🔛','🔜','🔝','đŸ„Ž','🏉','đŸ„','🏒','🏑','đŸ„','🏏','đŸ›č','đŸ›·','⛞','đŸ„Œ','🎼','đŸ•č','đŸŽČ','🎯','🎬','đŸŽžïž',
    'đŸ“œïž','đŸŽ„','đŸ“ș','đŸŽœ','✅','❌','⚠','🚹','❔','❕','❓','❗','🛑','⛔','đŸš«','💯','🔮','🟠','🟡','🟱','đŸ””','🟣','đŸŸ€','âšȘ',
    '⚫','đŸŸ„','🟧','🟹','đŸŸ©','🟩','đŸŸȘ','đŸŸ«','⬜','⬛','🚾','🚩','🚧','đŸ”¶','🔾','đŸ”·','đŸ”č','đŸ”ș','đŸ”»','🔼','💀','đŸ‘ïž','đŸ—Ąïž','đŸ›Ąïž',
];

const mkIconPicker = (container, initial) => {
    let sel = initial || ICONS[0];
    const pick = mk('div', 'tvis-icon-pick');
    const custom = getCustomIcons();
    const all = custom.length ? [...custom, '|', ...ICONS] : ICONS;
    all.forEach(ico => {
        if (ico === '|') {
            const sep = mk('div'); sep.style.cssText='width:100%;height:1px;background:#eee;margin:2px 0';
            pick.appendChild(sep); return;
        }
        const b = mk('button', ico === sel ? 'sel' : '', ico); b.type = 'button';
        b.onclick = () => { sel = ico; pick.querySelectorAll('button').forEach(x => x.className = ''); b.className = 'sel'; };
        pick.appendChild(b);
    });
    container.appendChild(pick);
    return () => sel;
};

// MODAL
const mkModal = (title, renderFn) => {
    document.getElementById('tvis-modal')?.remove();
    const ov  = mk('div', 'tvis-ov'); ov.id = 'tvis-modal';
    const box = mk('div', 'tvis-box');
    box.appendChild(mk('div', 'tvis-title', title));
    const cont = mk('div'); box.appendChild(cont);
    const close = () => {
        ov.remove();
        window.removeEventListener('resize', onResize);
    };
    // Close if box goes off screen on resize
    const onResize = () => {
        const r = box.getBoundingClientRect();
        if (r.left < 0 || r.right > innerWidth + 2) close();
    };
    window.addEventListener('resize', onResize);
    renderFn(cont, close);
    const cb = mkB('✕ ' + s('close'), 'btn-grey', close); cb.style.marginTop = '12px';
    box.appendChild(cb);
    ov.onclick = e => { if (e.target === ov) close(); };
    ov.appendChild(box); document.body.appendChild(ov);
    return cont;
};

// TOAST
const showToast = msg => {
    document.getElementById('tvis-toast')?.remove();
    const t = mk('div','tvis-toast',msg); t.id='tvis-toast';
    document.body.appendChild(t);
    requestAnimationFrame(()=>t.classList.add('show'));
    setTimeout(()=>{ t.classList.remove('show'); setTimeout(()=>t.remove(),400); },3500);
};

// RENK SEÇİCİ
// Returns true if hex color is dark enough to warrant white text
const isColorDark = hex => {
    const h = hex.replace('#','');
    if (h.length < 6) return false;
    const r=parseInt(h.slice(0,2),16), g=parseInt(h.slice(2,4),16), b=parseInt(h.slice(4,6),16);
    return (0.299*r + 0.587*g + 0.114*b) < 155;
};

const PRESET_COLORS = [
    // Temel mor / mavi ailesi
    '#6f42c1','#9b59b6','#8e44ad','#5a32a3','#4a235a',
    // Maviler
    '#007bff','#2980b9','#17a2b8','#0d6efd','#1abc9c',
    // Yeßiller
    '#28a745','#27ae60','#20c997','#2ecc71','#16a085',
    // Kırmızı / turuncu / sarı
    '#dc3545','#c0392b','#e74c3c','#fd7e14','#f39c12',
    '#ffc107','#ffd700','#f1c40f',
    // Pembe / mor tonları
    '#e83e8c','#e91e63','#c2185b',
    // Koyu / nötr
    '#343a40','#6c757d','#495057','#2c3e50','#34495e',
    // Açık ve özel
    '#3498db','#00b894','#e17055','#a29bfe','#74b9ff',
];

const mkColorPicker = (container, initial) => {
    let sel = initial || '#6f42c1';
    const wrap = mk('div','tvis-cpick');
    const label = mk('div','tvis-sec',s('colorPicker')); container.appendChild(label);
    PRESET_COLORS.forEach(c => {
        const sw = mk('button','tvis-cpick-sw'+(c===sel?' sel':'')); sw.type='button';
        sw.style.background=c; sw.title=c;
        sw.onclick=()=>{ sel=c; wrap.querySelectorAll('.tvis-cpick-sw').forEach(x=>x.classList.remove('sel')); sw.classList.add('sel'); };
        wrap.appendChild(sw);
    });
    const ci = mk('input'); ci.type='color'; ci.value=sel; ci.className='tvis-cpick-custom'; ci.title='Özel renk';
    ci.oninput=()=>{ sel=ci.value; wrap.querySelectorAll('.tvis-cpick-sw').forEach(x=>x.classList.remove('sel')); };
    wrap.appendChild(ci);
    container.appendChild(wrap);
    return () => sel;
};

// RAF SİSTEMİ
const RAF_FOLDER_DEFS = [
    { id:'chars',   icon:'đŸ‘€', nameKey:'rafChars',   color:'#e83e8c', type:'character' },
    { id:'cities',  icon:'đŸ™ïž', nameKey:'rafCities',  color:'#fd7e14', type:'city'      },
    { id:'locales', icon:'📍', nameKey:'rafLocales', color:'#28a745', type:'locale'    },
    { id:'artists', icon:'🎾', nameKey:'rafArtists', color:'#6f42c1', type:'artist'    },
    { id:'forum',   icon:'📋', nameKey:'rafForum',   color:'#17a2b8', type:'forum'     },
    { id:'fav',     icon:'⭐', nameKey:'rafFav',     color:'#ffc107', type:'any'       },
    { id:'work',    icon:'đŸ’Œ', nameKey:'rafWork',    color:'#343a40', type:'any'       },
    { id:'goals',   icon:'🎯', nameKey:'rafGoals',   color:'#dc3545', type:'any'       },
];
const SHELF_COLS = 5;

const getShelf = () => {
    const saved = gmGet(DK.RAF, null);
    // Existing v1 save: patch missing folders + fields
    if (saved?.v && saved?.folders) {
        let dirty = false;
        // Add missing folders
        RAF_FOLDER_DEFS.forEach(f => {
            if (!saved.folders[f.id]) {
                saved.folders[f.id] = {
                    icon:f.icon, name:s(f.nameKey), color:f.color, colCount:5,
                    columns: Array.from({length:5},(_,i)=>({name:`${s('rafColDefault')} ${i+1}`,items:[]}))
                };
                dirty = true;
            }
            // Patch missing colCount
            if (!saved.folders[f.id].colCount) { saved.folders[f.id].colCount=5; dirty=true; }
        });
        // Add folderOrder if missing
        if (!saved.folderOrder) {
            saved.folderOrder = RAF_FOLDER_DEFS.map(f=>f.id);
            dirty = true;
        }
        // Pre-populate cities if empty
        if (!saved.folders.cities.columns.some(c=>c.items.length)) {
            saved.folders.cities.columns = buildCityCols();
            dirty = true;
        }
        if (dirty) gmSet(DK.RAF, saved);
        return saved;
    }
    // Fresh init
    const folders = {};
    RAF_FOLDER_DEFS.forEach(f => {
        const existing = saved?.[f.id];
        const cols = f.id==='cities' ? buildCityCols() :
            (existing?.columns || Array.from({length:5},(_,i)=>({name:`${s('rafColDefault')} ${i+1}`,items:[]})));
        folders[f.id] = { icon:f.icon, name:s(f.nameKey), color:f.color, colCount:5, columns:cols };
    });
    // Migrate old PIN data
    const oldPins = gmGet(DK.PINS,[]);
    if (oldPins?.length && !saved?.v) {
        oldPins.forEach(p=>{
            const fid=p.type==='artist'?'artists':p.type==='locale'?'locales':p.type==='city'?'cities':'fav';
            folders[fid]?.columns[0].items.push({id:'p'+Date.now()+Math.random(),label:p.label,url:p.url,icon:p.icon||'📌',note:p.note||'',color:null,type:p.type||'page',savedAt:Date.now()});
        });
    }
    // Migrate old forum list data
    const oldFl = gmGet('tvis_forum_list',null);
    if (oldFl?.lanes) {
        oldFl.lanes.forEach((lane,li)=>{
            if(li>=5)return;
            folders['forum'].columns[li].name=lane.name;
            lane.threads?.forEach(t=>folders['forum'].columns[li].items.push({id:'f'+Date.now()+Math.random(),label:t.name,url:t.url,icon:'📋',note:'',color:null,type:'forum',savedAt:Date.now()}));
        });
    }
    return {v:1, folderOrder:RAF_FOLDER_DEFS.map(f=>f.id), folders};
};
const saveShelf = d => gmSet(DK.RAF, d);

// Build pre-sorted city columns (alphabetical, 5 cols)
const buildCityCols = () => {
    const PM_BASE = '/World/Popmundo.aspx/City/';
    const cities = [
        {n:'Amsterdam',id:8},{n:'Ankara',id:35},{n:'Antalya',id:61},
        {n:'BakĂŒ',id:58},{n:'Barselona',id:9},{n:'Belgrad',id:36},
        {n:'Berlin',id:7},{n:'BrĂŒksel',id:33},{n:'Budapeßte',id:42},
        {n:'Buenos Aires',id:17},{n:'BĂŒkreß',id:46},{n:'Cakarta',id:55},
        {n:'Dubrovnik',id:29},{n:'Glasgow',id:27},{n:'Helsinki',id:19},
        {n:'İstanbul',id:30},{n:'İzmir',id:47},{n:'Johannesburg',id:51},
        {n:'Kopenhag',id:22},{n:'Kyiv',id:56},{n:'Londra',id:5},
        {n:'Los Angeles',id:14},{n:'Madrid',id:24},{n:'Manila',id:54},
        {n:'Melbourne',id:10},{n:'Mexico City',id:32},{n:'Milano',id:52},
        {n:'Montreal',id:38},{n:'Moskova',id:18},{n:'Nashville',id:11},
        {n:'New York',id:6},{n:'Paris',id:20},{n:'Porto',id:31},
        {n:'Rio de Janeiro',id:25},{n:'Roma',id:23},{n:'Sao Paulo',id:21},
        {n:'Saraybosna',id:49},{n:'Seattle',id:50},{n:'Singapur',id:39},
        {n:'Sofya',id:53},{n:'Stokholm',id:1},{n:'ƞangay',id:45},
        {n:'ƞikago',id:60},{n:'Tallinn',id:34},{n:'Tokyo',id:62},
        {n:'Toronto',id:16},{n:'Tromsþ',id:26},{n:'VarƟova',id:48},
        {n:'Vilnius',id:28},
    ];
    // Already alphabetically sorted (TR locale). Distribute into 5 cols.
    const colCount=5, perCol=Math.ceil(cities.length/colCount);
    const colRanges=[{s:'A–B',e:9},{s:'B–C',e:19},{s:'L–N',e:29},{s:'N–S',e:39},{s:'S–V',e:49}];
    return Array.from({length:colCount},(_,ci)=>{
        const slice=cities.slice(ci*perCol,ci*perCol+perCol);
        return {
            name:colRanges[ci].s,
            items:slice.map(c=>({
                id:'city'+c.id, label:c.n, url:PM_BASE+c.id,
                icon:'đŸ™ïž', note:'', color:null, type:'city', savedAt:0
            }))
        };
    });
};

const detectPage = () => {
    const url = location.href; let m;
    if ((m = url.match(/\/Character\/(\d+)(?:[/?#]|$)/)))
        return { type:'character', id:m[1], icon:'🧑', label: document.querySelector('.charPresBox h2,.charPresBox h3')?.textContent.trim() || `Karakter #${m[1]}` };
    if ((m = url.match(/\/Locale\/(\d+)(?:[/?#]|$)/)))
        return { type:'locale', id:m[1], icon:'📍', label: document.querySelector('h1,h2')?.textContent.trim() || `Mekan #${m[1]}` };
    if ((m = url.match(/\/Artist\/(\d+)(?:[/?#]|$)/)))
        return { type:'artist', id:m[1], icon:'🎾', label: document.querySelector('h1,h2')?.textContent.trim() || `Sanatçı #${m[1]}` };
    if ((m = url.match(/\/City\/(\d+)(?:[/?#]|$)/)))
        return { type:'city', id:m[1], icon:'đŸ™ïž', label: document.querySelector('h1,h2')?.textContent.trim() || `ƞehir #${m[1]}` };
    if (url.includes('/Forum/')||url.includes('/Thread/'))
        return { type:'forum', id:'', icon:'📋', label:(document.title||'').replace(/^Popmundo\s*[-–]\s*/i,'').trim()||location.pathname };
    return { type:'page', id:'', icon:'📌', label:(document.title||'').replace(/^\(\d+\)\s*/,'').replace(/^Popmundo\s*[-–]\s*/i,'').trim()||location.pathname };
};

const openMetaEdit = (anchorEl, current, onSave) => {
    document.getElementById('tvis-meta-edit-pop')?.remove();
    const pop=mk('div','tvis-tab-edit-pop'); pop.id='tvis-meta-edit-pop';
    const rect=anchorEl.getBoundingClientRect();
    pop.style.left=Math.min(rect.left,innerWidth-260)+'px'; pop.style.top=(rect.bottom+4)+'px'; pop.style.minWidth='240px';
    const nameI=mk('input'); nameI.value=current.name||''; nameI.maxLength=20;
    nameI.style.cssText='width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin:4px 0';
    pop.appendChild(mk('div','tvis-sec',s('folderTitle'))); pop.appendChild(nameI);
    let selIcon=current.icon||'📌';
    const iconPick=mk('div','tvis-icon-pick'); iconPick.style.maxHeight='80px';
    const allIcos=[...getCustomIcons(),'|',...ICONS];
    allIcos.forEach(ico=>{
        if(ico==='|'){const sep=mk('div');sep.style.cssText='width:100%;height:1px;background:#eee;margin:2px 0';iconPick.appendChild(sep);return;}
        const b=mk('button',ico===selIcon?'sel':'',ico);b.type='button';
        b.onclick=()=>{selIcon=ico;iconPick.querySelectorAll('button').forEach(x=>x.className='');b.className='sel';};
        iconPick.appendChild(b);
    });
    pop.appendChild(mk('div','tvis-sec',s('pinIcon'))); pop.appendChild(iconPick);
    const getColor=mkColorPicker(pop,current.color||'#6f42c1');
    pop.appendChild(mkB('✔ '+s('iaSave'),'btn-sm btn-g',()=>{pop.remove();onSave({name:nameI.value.trim()||current.name,icon:selIcon,color:getColor()});}));
    const cb=mkB(s('cancelLbl'),'btn-sm btn-grey',()=>pop.remove()); cb.style.marginLeft='4px'; pop.lastChild.insertAdjacentElement('afterend',cb);
    document.body.appendChild(pop);
    setTimeout(()=>{const close=e=>{if(!pop.contains(e.target)){pop.remove();document.removeEventListener('mousedown',close);}};document.addEventListener('mousedown',close);},10);
};

const openRaf = () => mkModal(s('pinBtn'), cont => {
    cont.style.minWidth='720px';
    const shelf0=getShelf();
    const order0=shelf0.folderOrder||RAF_FOLDER_DEFS.map(f=>f.id);
    // Start on first folder that has items, else first folder
    let activeFolder=(()=>{ for(const fid of order0){ if(shelf0.folders[fid]?.columns.some(c=>c.items.length)) return fid; } return order0[0]||RAF_FOLDER_DEFS[0].id; })();
    let editItemKey=null;
    let drag=null;
    let tabDrag=null;
    let rafSearchQ='';

    // Shared card renderer
    const renderRafCard=(item,itemKey,onEdit,fid,ci,ii,grid,getDrag,setDrag)=>{
        const card=mk('div','tvis-raf-card');
        if(item.color){
            card.classList.add('colored');
            card.style.background=item.color;
            card.style.borderColor=item.color;
            card.style.color=isColorDark(item.color)?'#fff':'#222';
        }
        const cbar=mk('div','tvis-raf-card-color');
        if(item.color) cbar.style.background=isColorDark(item.color)?'rgba(255,255,255,.25)':'rgba(0,0,0,.15)';
        const ico=mk('span','tvis-raf-card-ico',item.icon||'📌');
        const lbl=mk('a','tvis-raf-card-lbl',item.label); lbl.href=item.url; lbl.target='_blank'; lbl.title=item.label+(item.note?'\n'+item.note:'');
        card.append(mk('span','frl-drag','â ż'),cbar,ico,lbl);
        if(item.note){ const noteEl=mk('span','tvis-raf-card-note',item.note); if(item.color) noteEl.style.color=isColorDark(item.color)?'rgba(255,255,255,.75)':'rgba(0,0,0,.55)'; card.appendChild(noteEl); }
        if(itemKey!=null && onEdit){
            const eB=mkB('✏','btn-sm btn-grey',()=>onEdit(itemKey));
            const dB=mkB('✕','btn-sm btn-r',()=>{const sh=getShelf();sh.folders[fid].columns[ci].items.splice(ii,1);saveShelf(sh);render();});
            eB.style.cssText=dB.style.cssText='font-size:9px;padding:1px 3px;flex-shrink:0';
            card.append(eB,dB);
            card.draggable=true; card.dataset.itemkey=`${fid}-${ci}`;
            card.addEventListener('dragstart',()=>setDrag({type:'card',fid,ci,ii}));
            card.addEventListener('dragover',e=>{
                e.preventDefault();
                if(getDrag()?.type==='card'){ grid?.querySelectorAll('.drag-over').forEach(x=>x.classList.remove('drag-over')); card.classList.add('drag-over'); }
            });
            card.addEventListener('drop',e=>{
                e.preventDefault();e.stopPropagation();
                const d=getDrag(); if(!d||d.type!=='card') return;
                const sh=getShelf();
                const [itm]=sh.folders[d.fid].columns[d.ci].items.splice(d.ii,1);
                const to=e.clientY>card.getBoundingClientRect().top+card.offsetHeight/2?ii+1:ii;
                sh.folders[fid].columns[ci].items.splice(to,0,itm);
                setDrag(null);saveShelf(sh);render();
            });
        }
        return card;
    };

    // Inline item editor
    const buildItemEditor=(item,ci,ii)=>{
        const ed=mk('div','tvis-raf-edit');
        const r1=mk('div');r1.style.cssText='display:flex;gap:4px;flex-wrap:wrap;margin-bottom:4px';
        const nI=mk('input');nI.value=item.label;nI.style.cssText='flex:1;min-width:100px;padding:3px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        const ntI=mk('input');ntI.value=item.note||'';ntI.placeholder=s('rafItemNote');ntI.style.cssText='flex:1;min-width:80px;padding:3px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        r1.append(nI,ntI); ed.appendChild(r1);
        ed.appendChild(mk('div','tvis-sec',s('pinIcon')));
        let edIcon=item.icon||'📌';
        const edIp=mk('div','tvis-icon-pick');edIp.style.maxHeight='60px';
        [...getCustomIcons(),'|',...ICONS].forEach(ico2=>{
            if(ico2==='|'){const sep=mk('div');sep.style.cssText='width:100%;height:1px;background:#eee;margin:2px 0';edIp.appendChild(sep);return;}
            const b=mk('button',ico2===edIcon?'sel':'',ico2);b.type='button';
            b.onclick=()=>{edIcon=ico2;edIp.querySelectorAll('button').forEach(x=>x.className='');b.className='sel';};
            edIp.appendChild(b);
        });
        ed.appendChild(edIp);
        const getEdColor=mkColorPicker(ed,item.color||null);
        const sv=mkB('✔ '+s('iaSave'),'btn-sm btn-g',()=>{
            const sh=getShelf();const it=sh.folders[activeFolder].columns[ci].items[ii];
            it.label=nI.value.trim()||it.label;it.note=ntI.value.trim();it.icon=edIcon;it.color=getEdColor()||null;
            saveShelf(sh);editItemKey=null;render();
        });
        sv.style.marginTop='4px';ed.appendChild(sv);
        return ed;
    };

    const render=()=>{
        cont.innerHTML='';
        const shelf=getShelf();
        const order=shelf.folderOrder||RAF_FOLDER_DEFS.map(f=>f.id);

        // SEARCH BAR
        const searchRow=mk('div'); searchRow.style.cssText='display:flex;gap:6px;align-items:center;margin-bottom:10px';
        const searchI=mk('input'); searchI.id='tvis-raf-search';
        searchI.placeholder='🔍 Raflarda ara... (isim, not)';
        searchI.style.cssText='flex:1;padding:4px 8px;border:1px solid #c9b8f0;border-radius:4px;font-size:12px';
        searchI.value=rafSearchQ;
        const clrBtn=mkB('✕','btn-sm btn-grey',()=>{ rafSearchQ=''; render(); });
        clrBtn.style.display=rafSearchQ?'':'none';
        searchI.addEventListener('input',()=>{ rafSearchQ=searchI.value; clrBtn.style.display=rafSearchQ?'':'none'; renderContent(); });
        searchRow.append(searchI,clrBtn);
        cont.appendChild(searchRow);

        // FOLDER TABS (draggable)
        const tabRow=mk('div','tvis-raf-tabs');
        if(rafSearchQ) tabRow.style.opacity='0.5';

        order.forEach(fid=>{
            const def=RAF_FOLDER_DEFS.find(d=>d.id===fid); if(!def) return;
            const fd=shelf.folders[fid]; if(!fd) return;
            const totalItems=fd.columns.flatMap(c=>c.items).length;
            const isActive=activeFolder===fid&&!rafSearchQ;
            const tw=mk('span'); tw.style.cssText='display:inline-flex;align-items:center;gap:1px';
            tw.draggable=true; tw.dataset.fid=fid;
            tw.addEventListener('dragstart',e=>{ tabDrag=fid; tw.style.opacity='.4'; e.dataTransfer.effectAllowed='move'; });
            tw.addEventListener('dragend',()=>{ tw.style.opacity=''; tabRow.querySelectorAll('.drag-over-tab').forEach(x=>x.classList.remove('drag-over-tab')); });
            tw.addEventListener('dragover',e=>{ if(tabDrag&&tabDrag!==fid){e.preventDefault();tw.querySelector('button')?.classList.add('drag-over-tab');} });
            tw.addEventListener('dragleave',()=>tw.querySelector('button')?.classList.remove('drag-over-tab'));
            tw.addEventListener('drop',e=>{
                e.preventDefault();e.stopPropagation();
                if(!tabDrag||tabDrag===fid) return;
                const sh=getShelf(); const ord=sh.folderOrder||RAF_FOLDER_DEFS.map(f=>f.id);
                const from=ord.indexOf(tabDrag),to=ord.indexOf(fid);
                if(from>=0&&to>=0){ord.splice(from,1);ord.splice(to,0,tabDrag);sh.folderOrder=ord;saveShelf(sh);}
                tabDrag=null;render();
            });
            const tab=mk('button','tvis-raf-tab'+(isActive?' active':''), `${fd.icon} ${fd.name}`);
            tab.style.borderColor=fd.color;
            if(isActive){tab.style.background=fd.color;tab.style.color='#fff';}
            if(totalItems>0){ const badge=mk('span','tvis-raf-tab-badge',String(totalItems)); tab.appendChild(badge); }
            // Trailing icon
            const trailIco=mk('span',''); trailIco.textContent=' '+fd.icon; trailIco.style.cssText='font-size:11px;opacity:.7';
            tab.appendChild(trailIco);
            tab.onclick=()=>{rafSearchQ='';activeFolder=fid;editItemKey=null;render();};
            const eb=mk('button','tvis-raf-tab-edit','✏');
            eb.onclick=e=>{e.stopPropagation();openMetaEdit(eb,fd,(meta)=>{const sh=getShelf();sh.folders[fid]={...sh.folders[fid],...meta};saveShelf(sh);render();});};
            tw.append(tab,eb); tabRow.appendChild(tw);
        });

        // Son Eklenenler pseudo-tab
        const recTab=mk('button','tvis-raf-recent-tab'+(activeFolder==='__recent__'&&!rafSearchQ?' active':''),s('recentTab'));
        recTab.onclick=()=>{rafSearchQ='';activeFolder='__recent__';editItemKey=null;render();};
        tabRow.appendChild(recTab);
        cont.appendChild(tabRow);

        const contentArea=mk('div'); cont.appendChild(contentArea);

        const renderContent=()=>{
            contentArea.innerHTML='';
            const shelf2=getShelf();
            const order2=shelf2.folderOrder||RAF_FOLDER_DEFS.map(f=>f.id);

            if(rafSearchQ.trim()){
                // SEARCH
                const q=rafSearchQ.trim().toLowerCase();
                const results=[];
                order2.forEach(fid=>{ const fd2=shelf2.folders[fid]; if(!fd2) return;
                    fd2.columns.forEach((col,ci)=>{ col.items.forEach((item,ii)=>{
                        if((item.label||'').toLowerCase().includes(q)||(item.note||'').toLowerCase().includes(q))
                            results.push({item,fid,ficon:fd2.icon,fname:fd2.name,ci,ii,colname:col.name});
                    });});
                });
                if(!results.length){
                    const em=mk('div',''); em.style.cssText='color:#999;font-size:12px;padding:16px 0;text-align:center';
                    em.textContent=`"${rafSearchQ}" için sonuç bulunamadı.`; contentArea.appendChild(em);
                } else {
                    const info=mk('div',''); info.style.cssText='font-size:10px;color:#aaa;margin-bottom:8px';
                    info.textContent=`${results.length} sonuç`; contentArea.appendChild(info);
                    const list=mk('div'); list.style.cssText='display:flex;flex-direction:column;gap:3px';
                    results.forEach(({item,fid,ficon,fname,ci,colname})=>{
                        const row=renderRafCard(item,null,null,fid,ci,0,null,()=>null,()=>{});
                        row.style.cursor='default';
                        const bc=mk('span',''); bc.style.cssText='font-size:9px;white-space:nowrap;flex-shrink:0';
                        bc.style.color=item.color?(isColorDark(item.color)?'rgba(255,255,255,.6)':'rgba(0,0,0,.45)'):'#aaa';
                        bc.textContent=`${ficon} ${fname} â€ș ${colname}`;
                        const goBtn=mkB('→','btn-sm btn-grey',()=>{rafSearchQ='';activeFolder=fid;render();});
                        goBtn.title='Bu klasöre git';goBtn.style.flexShrink='0';
                        row.append(bc,goBtn); list.appendChild(row);
                    });
                    contentArea.appendChild(list);
                }
                setTimeout(()=>{ const si=document.getElementById('tvis-raf-search'); if(si){si.focus();si.setSelectionRange(si.value.length,si.value.length);} },10);

            } else if(activeFolder==='__recent__'){
                // SON EKLENENLER
                const allItems=[];
                order2.forEach(fid=>{ const fd2=shelf2.folders[fid]; if(!fd2) return;
                    fd2.columns.forEach((col,ci)=>{ col.items.forEach((item,ii)=>{
                        const ts=item.savedAt||parseInt(String(item.id).replace(/\D/g,'').slice(0,13))||0;
                        if(ts>0) allItems.push({item,fid,ficon:fd2.icon,fname:fd2.name,ci,ii,colname:col.name,ts});
                    });});
                });
                allItems.sort((a,b)=>b.ts-a.ts);
                const recent=allItems.slice(0,20);
                if(!recent.length){
                    const em=mk('div',''); em.style.cssText='color:#999;font-size:12px;padding:16px 0;text-align:center';
                    em.textContent=s('recentEmpty'); contentArea.appendChild(em);
                } else {
                    const info=mk('div',''); info.style.cssText='font-size:10px;color:#aaa;margin-bottom:8px';
                    info.textContent=s('recentCount').replace('{n}',recent.length); contentArea.appendChild(info);
                    const list=mk('div'); list.style.cssText='display:flex;flex-direction:column;gap:3px';
                    recent.forEach(({item,fid,ficon,fname,ci,colname,ts})=>{
                        const row=renderRafCard(item,null,null,fid,ci,0,null,()=>null,()=>{});
                        row.style.cursor='default';
                        const dateStr=ts>0?new Date(ts).toLocaleDateString('tr-TR',{day:'2-digit',month:'2-digit',year:'2-digit'}):'';
                        const meta=mk('span',''); meta.style.cssText='font-size:9px;color:#aaa;white-space:nowrap;flex-shrink:0';
                        if(item.color) meta.style.color=isColorDark(item.color)?'rgba(255,255,255,.6)':'rgba(0,0,0,.45)';
                        meta.textContent=`${ficon} ${fname} â€ș ${colname}${dateStr?' · '+dateStr:''}`;
                        const goBtn=mkB('→','btn-sm btn-grey',()=>{activeFolder=fid;render();});
                        goBtn.title=s('goToFolder');goBtn.style.flexShrink='0';
                        row.append(meta,goBtn); list.appendChild(row);
                    });
                    contentArea.appendChild(list);
                }

            } else {
                // NORMAL GRID
                const fd=shelf2.folders[activeFolder]; if(!fd) return;
                const colCount=fd.colCount||5;

                // Column count selector
                const ccRow=mk('div','tvis-raf-colcount');
                ccRow.appendChild(mk('span','',s('colLabel')));
                [3,4,5,6].forEach(n=>{
                    const b=mkB(String(n),'',()=>{
                        if(n===colCount) return;
                        const sh=getShelf(); const fdr=sh.folders[activeFolder];
                        if(n>colCount){ for(let i=colCount;i<n;i++) fdr.columns.push({name:`${s('rafColDefault')} ${i+1}`,items:[]}); }
                        else { const overflow=fdr.columns.splice(n).flatMap(c=>c.items); fdr.columns[n-1].items.push(...overflow); }
                        fdr.colCount=n; saveShelf(sh); render();
                    });
                    b.style.cssText=n===colCount
                        ? 'padding:1px 7px;border:1px solid #6f42c1;border-radius:3px;background:#6f42c1;font-size:10px;cursor:pointer;color:#fff'
                        : 'padding:1px 7px;border:1px solid #ccc;border-radius:3px;background:#fff;font-size:10px;cursor:pointer;color:#666';
                    ccRow.appendChild(b);
                });
                contentArea.appendChild(ccRow);

                const grid=mk('div','tvis-raf-grid');
                grid.style.gridTemplateColumns=`repeat(${colCount},1fr)`;
                contentArea.appendChild(grid);

                fd.columns.forEach((col,ci)=>{
                    const colEl=mk('div','tvis-raf-col');
                    const head=mk('div','tvis-raf-col-head');
                    const nameI=mk('input','tvis-raf-col-name'); nameI.value=col.name; nameI.maxLength=20;
                    nameI.onchange=()=>{const sh=getShelf();sh.folders[activeFolder].columns[ci].name=nameI.value.trim()||col.name;saveShelf(sh);};
                    const cnt=mk('span',''); cnt.style.cssText='font-size:9px;color:#aaa;flex-shrink:0;padding:0 2px';
                    cnt.textContent=col.items.length?`(${col.items.length})`:'';
                    head.append(nameI,cnt); colEl.appendChild(head);
                    col.items.forEach((item,ii)=>{
                        const itemKey=`${ci}-${ii}`;
                        const card=renderRafCard(item,itemKey,(key)=>{editItemKey=editItemKey===key?null:key;render();},
                            activeFolder,ci,ii,grid,()=>drag,(d)=>{drag=d;});
                        colEl.appendChild(card);
                        if(editItemKey===itemKey) colEl.appendChild(buildItemEditor(item,ci,ii));
                    });
                    colEl.addEventListener('dragover',e=>e.preventDefault());
                    colEl.addEventListener('dragenter',()=>colEl.classList.add('drag-target'));
                    colEl.addEventListener('dragleave',e=>{if(!colEl.contains(e.relatedTarget))colEl.classList.remove('drag-target');});
                    colEl.addEventListener('drop',e=>{
                        e.preventDefault();colEl.classList.remove('drag-target');
                        if(!drag||drag.type!=='card') return;
                        const sh=getShelf();
                        const [itm]=sh.folders[drag.fid].columns[drag.ci].items.splice(drag.ii,1);
                        sh.folders[activeFolder].columns[ci].items.push(itm);
                        drag=null;saveShelf(sh);render();
                    });
                    if(!col.items.length){const em=mk('div','',s('rafEmpty'));em.style.cssText='color:#bbb;font-size:10px;text-align:center;padding:8px 0';colEl.appendChild(em);}
                    grid.appendChild(colEl);
                });
            }
        };
        renderContent();
    };
    render();
})

// "Serbest" klasörler — sayfa tipine göre otomatik yönlendirilemeyen klasörler
const FREE_FOLDER_IDS = ['fav','work','goals'];

const quickRaf = () => {
    const pg = detectPage();
    // Bilinen tipe sahip sayfalar → direkt klasör
    const autoFid = pg.type==='artist'?'artists' : pg.type==='locale'?'locales' : pg.type==='city'?'cities'
                  : pg.type==='forum'?'forum' : pg.type==='character'?'chars' : null;

    const shelf = getShelf();

    // Zaten eklenmiß mi kontrol et (tĂŒm klasörlerde)
    const allItems = Object.values(shelf.folders).flatMap(fd=>fd.columns.flatMap(c=>c.items));
    if(allItems.find(it=>normUrl(it.url)===normUrl(location.href))){ showToast(s('rafDup')); return; }

    const openForm = (targetFid) => {
        const fd = shelf.folders[targetFid];
        mkModal(s('pinAdd'),(cont,close)=>{
            const fld=(lbl,val,plh)=>{
                const l=mk('div','',lbl); l.style.cssText='font-size:11px;color:#666;margin-bottom:2px';
                const i=mk('input'); i.style.cssText='width:100%;box-sizing:border-box;padding:4px 6px;border:1px solid #ccc;border-radius:3px;font-size:12px;margin-bottom:6px';
                if(val!==undefined) i.value=val; if(plh) i.placeholder=plh;
                cont.append(l,i); return i;
            };
            const nI=fld(s('pinName'),pg.label);
            const ntI=fld(s('pinNote'),'','...');
            cont.appendChild(mk('div','tvis-sec',s('pinIcon')));
            let selIcon=pg.icon;
            const ip=mk('div','tvis-icon-pick'); ip.style.maxHeight='80px';
            [...getCustomIcons(),'|',...ICONS].forEach(ico=>{
                if(ico==='|'){const sep=mk('div');sep.style.cssText='width:100%;height:1px;background:#eee;margin:2px 0';ip.appendChild(sep);return;}
                const b=mk('button',ico===selIcon?'sel':'',ico); b.type='button';
                b.onclick=()=>{selIcon=ico;ip.querySelectorAll('button').forEach(x=>x.className='');b.className='sel';};
                ip.appendChild(b);
            });
            cont.appendChild(ip);
            const getColor=mkColorPicker(cont,null);
            cont.appendChild(mk('div','tvis-sec',s('rafColDefault')));
            const colSel=mk('select'); colSel.style.cssText='width:100%;padding:3px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin-bottom:6px';
            fd.columns.forEach((c,i)=>{const o=mk('option','',`${c.name} (${c.items.length})`);o.value=i;colSel.appendChild(o);});
            cont.appendChild(colSel);
            cont.appendChild(mkB(s('pinSave'),'btn-v',()=>{
                const sh=getShelf();
                sh.folders[targetFid].columns[parseInt(colSel.value)].items.push({
                    id:'i'+Date.now(), label:nI.value.trim()||pg.label, url:normUrl(location.href),
                    icon:selIcon, note:ntI.value.trim(), color:getColor()||null, type:pg.type, savedAt:Date.now()
                });
                saveShelf(sh); close(); showToast('📌 '+s('pinSave'));
            }));
        });
    };

    if(autoFid){
        // Bilinen tip → direkt forma git
        openForm(autoFid);
    } else {
        // Serbest tip → Hangi klasöre? seçici
        const freeFolders = FREE_FOLDER_IDS.map(fid=>({ fid, fd:shelf.folders[fid] })).filter(x=>x.fd);
        const order = shelf.folderOrder || RAF_FOLDER_DEFS.map(f=>f.id);
        freeFolders.sort((a,b)=>order.indexOf(a.fid)-order.indexOf(b.fid));

        // Mini popup — add button'un yakınında göster
        const addBtn = document.querySelector('#tvis-bar .tvis-bar a') || document.body;
        const pop = mk('div');
        pop.style.cssText='position:fixed;z-index:999999;background:#fff;border:1px solid #c9b8f0;border-radius:8px;padding:8px;box-shadow:0 4px 16px rgba(0,0,0,.2);min-width:180px';
        pop.style.top='36px'; pop.style.right='4px';

        const title=mk('div','tvis-sec',s('addWhere')); title.style.marginBottom='6px';
        pop.appendChild(title);

        freeFolders.forEach(({fid,fd})=>{
            const btn=mk('button'); btn.type='button';
            btn.style.cssText='display:flex;align-items:center;gap:8px;width:100%;padding:6px 10px;margin-bottom:4px;border:2px solid;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;background:#fff;text-align:left';
            btn.style.borderColor=fd.color;
            btn.style.color=fd.color;
            const totalItems=fd.columns.flatMap(c=>c.items).length;
            btn.innerHTML=`<span style="font-size:16px">${fd.icon}</span><span>${fd.name}</span><span style="margin-left:auto;font-size:10px;opacity:.6">${totalItems}</span>`;
            btn.onmouseover=()=>{ btn.style.background=fd.color; btn.style.color=isColorDark(fd.color)?'#fff':'#222'; };
            btn.onmouseout=()=>{ btn.style.background='#fff'; btn.style.color=fd.color; };
            btn.onclick=()=>{ pop.remove(); openForm(fid); };
            pop.appendChild(btn);
        });

        document.body.appendChild(pop);
        setTimeout(()=>{
            const close=e=>{ if(!pop.contains(e.target)){pop.remove();document.removeEventListener('mousedown',close);} };
            document.addEventListener('mousedown',close);
        },50);
    }
};

const addForumToRaf=(id,name,url,targetCol=-1)=>{
    const sh=getShelf(); const fd=sh.folders['forum'];
    const nUrl=normUrl(url);
    if(fd.columns.flatMap(c=>c.items).find(it=>normUrl(it.url)===nUrl))return false;
    let tc = targetCol >= 0 && targetCol < fd.columns.length ? targetCol
           : fd.columns.findIndex(c=>c.items.length<20);
    if(tc<0)tc=SHELF_COLS-1;
    fd.columns[tc].items.push({id:'f'+Date.now(),label:name,url:nUrl,icon:'📋',note:'',color:null,type:'forum',savedAt:Date.now()});
    saveShelf(sh); return true;
};
const isForumInRaf=url=>getShelf().folders['forum'].columns.flatMap(c=>c.items).some(it=>normUrl(it.url)===normUrl(url));

// CLIPBOARD HISTORY
const addClip = (id, name, type) => {
    const log = gmGet(DK.CLIP, []);
    log.unshift({ id, name, type, ts: Date.now() });
    if (log.length > 25) log.length = 25;
    gmSet(DK.CLIP, log);
};

const openClip = () => mkModal(s('chTitle'), cont => {
    const render = () => {
        cont.innerHTML = '';
        const log = gmGet(DK.CLIP, []);
        if (!log.length) { const d=mk('div','',s('chEmpty')); d.style.cssText='color:#999;font-size:12px'; cont.appendChild(d); return; }
        const clr = mkB(s('chClear'), 'btn-sm btn-r', () => { gmSet(DK.CLIP,[]); render(); });
        clr.style.marginBottom = '8px'; cont.appendChild(clr);
        log.forEach(e => {
            const row = mk('div'); row.style.cssText='display:flex;align-items:center;gap:6px;margin-bottom:4px;padding:4px 6px;background:#f8f9fa;border-radius:3px';
            const ico = e.type==='character'?'🧑':e.type==='locale'?'📍':'🎾';
            const lbl = mk('span','',`${ico} ${e.name||'?'} — ID: ${e.id}`); lbl.style.cssText='flex:1;font-size:12px';
            const ts  = mk('span','',new Date(e.ts).toLocaleTimeString(dateLocale,{hour:'2-digit',minute:'2-digit'})); ts.style.cssText='font-size:10px;color:#999';
            const cp  = mkB(s('chCopy'), 'btn-sm btn-b', () => { navigator.clipboard?.writeText(e.id); });
            row.append(lbl,ts,cp); cont.appendChild(row);
        });
    };
    render();
});

// CHARACTER CACHE
const CACHE_TTL = 86400000, CACHE_MAX = 200;
const CC = {
    _s: () => gmGet(DK.CACHE, {}),
    get(id) {
        const s = this._s(), e = s[String(id)]; if (!e) return null;
        if (Date.now() - e.t > CACHE_TTL) { delete s[id]; gmSet(DK.CACHE,s); return null; }
        return e;
    },
    set(id, data) {
        const s = this._s();
        const tracked = new Set(getAllTracked().map(t => String(t.charId)));
        const keys = Object.keys(s);
        if (keys.length >= CACHE_MAX) {
            const evict = keys.filter(k=>!tracked.has(k)).sort((a,b)=>s[a].t-s[b].t)[0] || keys.sort((a,b)=>s[a].t-s[b].t)[0];
            if (evict) delete s[evict];
        }
        s[String(id)] = { ...data, t: Date.now() };
        gmSet(DK.CACHE,s);
    },
    del(id) { const s=this._s(); delete s[String(id)]; gmSet(DK.CACHE,s); }
};

let lastFetch = 0;
const FETCH_GAP = 3000;
const waitGap = () => { const g = FETCH_GAP-(Date.now()-lastFetch); return g>0?new Promise(r=>setTimeout(r,g)):Promise.resolve(); };

// GLOBAL STOP FUNCTIONALITY
const showGlobalStop = (onStop) => {
    if (document.getElementById('tvis-global-stop')) return;
    const bar = mk('div'); bar.id = 'tvis-global-stop';
    bar.style.cssText = 'position:fixed;top:0;left:0;width:100%;background:#dc3545;color:#fff;text-align:center;padding:12px;z-index:999999;font-weight:bold;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,0.3);font-size:14px;';
    bar.textContent = 'âč ' + s('tkBgCancel');
    bar.onclick = () => { bar.remove(); if(onStop) onStop(); };
    document.body.appendChild(bar);
};

// NOTIFICATION SYSTEM
const showNotification = (message, type = 'info') => {
    const notification = mk('div', 'tvis-toast');
    notification.textContent = message;
    
    // Set color based on type
    const colors = {
        success: '#218838',
        error: '#dc3545',
        warning: '#ffc107',
        info: '#17a2b8'
    };
    notification.style.background = colors[type] || colors.info;
    
    document.body.appendChild(notification);
    
    // Show animation
    requestAnimationFrame(() => notification.classList.add('show'));
    
    // Auto-hide after 4 seconds
    setTimeout(() => {
        notification.classList.remove('show');
        setTimeout(() => notification.remove(), 300);
    }, 4000);
};

// Enhanced hideProgress with notifications
const hideProgressWithNotification = (taskType, stopped, task) => {
    const progressId = `tvis-${taskType}-prog`;
    const el = document.getElementById(progressId);
    if (!el) return;
    
    el.classList.remove('done','stopped');
    el.classList.add(stopped ? 'stopped' : 'done');
    
    let msg, notificationMsg, notificationType;
    
    if (stopped) {
        msg = `${s('tkBgStopped')} ${task.current}/${task.total}`;
        notificationMsg = `⛔ ${taskType} iƟlemi durduruldu: ${task.current}/${task.total}`;
        notificationType = 'warning';
    } else {
        switch(taskType) {
            case 'radar':
                msg = `${s('tkBgDone')} ${task.total}/${task.total}`;
                notificationMsg = `✅ Radar gĂŒncellendi: ${task.total} karakter`;
                notificationType = 'success';
                break;
            case 'radio':
                msg = 'đŸ“» Radyo listesi gĂŒncellendi!';
                notificationMsg = 'đŸ“» Radyo sıralamaları gĂŒncellendi';
                notificationType = 'success';
                break;
            case 'speedcall':
                msg = '✅ TĂŒm aramalar tamamlandı!';
                notificationMsg = `📞 Speed Calling tamamlandı: ${task.total} arama`;
                notificationType = 'success';
                break;
            default:
                msg = `✅ ${taskType} tamamlandı`;
                notificationMsg = `✅ ${taskType} ißlemi tamamlandı`;
                notificationType = 'success';
        }
    }
    
    document.getElementById(`${progressId}-txt`).textContent = msg;
    const stopBtn = el.querySelector('.tvis-rprog-cancel');
    if (stopBtn) stopBtn.remove();
    
    // Show notification
    showNotification(notificationMsg, notificationType);
    
    setTimeout(() => el.remove(), 3500);
};

// BACKGROUND TASK MANAGER
const BGTASKS = {
    radar: { running: false, cancelled: false, current: 0, total: 0 },
    radio: { running: false, cancelled: false, current: 0, total: 0 },
    speedcall: { running: false, cancelled: false, current: 0, total: 0 }
};

// Page-independent task persistence
const BG_TASK_KEY = 'tvis_bg_tasks';
const saveBgTasks = () => localStorage.setItem(BG_TASK_KEY, JSON.stringify(BGTASKS));
const loadBgTasks = () => {
    try {
        const saved = localStorage.getItem(BG_TASK_KEY);
        if (saved) {
            const parsed = JSON.parse(saved);
            Object.assign(BGTASKS, parsed);
        }
    } catch (e) {
        console.warn('Failed to load background tasks:', e);
    }
};

// Initialize on page load
loadBgTasks();

// Auto-save when tasks change
const saveTaskState = (taskType) => {
    setTimeout(() => saveBgTasks(), 100);
};

const startBackgroundTask = (taskType, total, processFn) => {
    if (BGTASKS[taskType].running) return;
    
    BGTASKS[taskType] = { running: true, cancelled: false, current: 0, total };
    saveTaskState(taskType);
    
    const showProgress = () => {
        const task = BGTASKS[taskType];
        const progressId = `tvis-${taskType}-prog`;
        let el = document.getElementById(progressId);
        
        if (!el) {
            el = mk('div', 'tvis-rprog'); el.id = progressId;
            const txt = mk('span', 'tvis-rprog-txt'); txt.id = `${progressId}-txt`;
            const stop = mk('button', 'tvis-rprog-cancel', s('tkBgCancel'));
            stop.onclick = () => { 
                BGTASKS[taskType].cancelled = true; 
                saveTaskState(taskType);
                stop.disabled = true; 
                stop.textContent = '...'; 
            };
            el.append(txt, stop);
            document.body.appendChild(el);
        }
        
        document.getElementById(`${progressId}-txt`).textContent = 
            taskType === 'radar' ? `${s('tkBgRunning')} ${task.current}/${task.total}` :
            taskType === 'radio' ? `đŸ“» ${s('shFetching').replace('{n}', task.current).replace('/17', `/${task.total}`)}` :
            `📞 ${s('scBarCalling')} ${task.current}/${task.total}`;
    };
    
    const hideProgress = (stopped) => {
        const task = BGTASKS[taskType];
        const progressId = `tvis-${taskType}-prog`;
        const el = document.getElementById(progressId);
        if (!el) return;
        
        el.classList.remove('done','stopped');
        el.classList.add(stopped ? 'stopped' : 'done');
        
        const msg = stopped ? 
            `${s('tkBgStopped')} ${task.current}/${task.total}` : 
            taskType === 'radar' ? `${s('tkBgDone')} ${task.total}/${task.total}` :
            taskType === 'radio' ? 'đŸ“» Radyo listesi gĂŒncellendi!' :
            '✅ TĂŒm aramalar tamamlandı!';
            
        document.getElementById(`${progressId}-txt`).textContent = msg;
        const stopBtn = el.querySelector('.tvis-rprog-cancel');
        if (stopBtn) stopBtn.remove();
        setTimeout(() => el.remove(), 3500);
    };
    
    // Global stop integration
    showGlobalStop(() => {
        BGTASKS[taskType].cancelled = true;
        saveTaskState(taskType);
        const stopBtn = document.querySelector(`#tvis-${taskType}-prog .tvis-rprog-cancel`);
        if (stopBtn) {
            stopBtn.disabled = true;
            stopBtn.textContent = '...';
        }
    });
    
    const runTask = async () => {
        const task = BGTASKS[taskType];
        showProgress();
        
        try {
            await processFn(task);
        } catch (error) {
            console.error(`Background task ${taskType} error:`, error);
        }
        
        task.running = false;
        saveTaskState(taskType);
        hideProgressWithNotification(taskType, task.cancelled, task);
    };
    
    runTask();
};

// PARSE CHAR PAGE
const parseCharPage = html => {
    const doc  = new DOMParser().parseFromString(html,'text/html');
    const name = doc.querySelector('.charPresBox h2')?.textContent.trim(); if (!name) return null;
    const pres = doc.querySelector('.characterPresentation');
    const bandLink   = pres?.querySelector('a[href*="/Artist/"]');
    const cityLink   = pres?.querySelector('a[href*="/City/"]');
    const localeLink = [...(pres?.querySelectorAll('a[href*="/Locale/"]')||[])].find(a=>!a.href.includes('CharactersPresent')&&!a.href.includes('MoveToLocale'));
    const onlineTxt  = doc.getElementById('ctl00_cphLeftColumn_ctl00_lnkOnlineStatus')?.textContent.trim()
        || doc.getElementById('ctl00_cphLeftColumn_ctl00_trOnlineStatus')?.querySelector('td')?.textContent.replace(/Durum[u]?\s*:/,'').trim() || '';
    const attitude   = doc.getElementById('ctl00_cphLeftColumn_ctl00_lnkAttitude')?.textContent.trim() || '';
    const stateImg   = doc.getElementById('ctl00_cphLeftColumn_ctl00_imgState');
    const state      = stateImg ? [...stateImg.closest('tr').querySelectorAll('td')].pop()?.textContent.trim()||'' : '';
    const avatarDiv  = doc.querySelector('.avatar.idTrigger');
    const avatarUrl  = avatarDiv?.style.backgroundImage?.match(/url\(['"]?([^'"]+)['"]?\)/)?.[1] || '';
    const cashRow    = doc.getElementById('ctl00_cphLeftColumn_ctl00_imgCash');
    const cash       = cashRow ? [...cashRow.closest('tr').querySelectorAll('td')].pop()?.textContent.trim()||'' : '';
    return {
        name, band: bandLink?.textContent.trim()||'', bandHref: bandLink?.getAttribute('href')||'',
        city: cityLink?.textContent.trim()||'', cityHref: cityLink?.getAttribute('href')||'',
        locale: localeLink?.textContent.trim()||'', localeHref: localeLink?.getAttribute('href')||'',
        localeId: localeLink?.href.match(/\/Locale\/(\d+)/)?.[1]||'',
        online: onlineTxt, attitude, state, avatarUrl, cash
    };
};

// ONLINE DOT — extracts just the date part to avoid prefix duplication
const onlineDot = (online, small) => {
    const dateMatch = (online||'').match(/(\d{1,2}\.\d{2}\.\d{4})/);
    const isDate    = !!dateMatch;
    const dateStr   = dateMatch?.[1] || '';
    const off       = !online || online === s('cpOffline') || online === 'Offline' || online === 'Çevrimdıßı' || online === 'Desconectado' || isDate;
    const sz        = small ? '6px' : '7px';
    const dot       = `<span style="background:${off?'#aaa':'#28a745'};width:${sz};height:${sz};border-radius:50%;display:inline-block;margin-right:3px;vertical-align:middle;flex-shrink:0"></span>`;
    if (off) return dot + (isDate ? `${s('cpOffline')} · ${s('tkLastSeen')} ${dateStr}` : s('cpOffline'));
    return dot + online;
};

// SC CHARS (Speed Calling listesi)
const getSCChars = () => gmGet(DK.SC_CHARS, []) || [];
const setSCChars = a => gmSet(DK.SC_CHARS, a);
const addSCChar = (charId, name, type) => { const a=getSCChars(); if(a.some(c=>String(c.charId)===String(charId)))return false; a.push({charId:String(charId),name,type}); setSCChars(a); return true; };
const removeSCChar = charId => setSCChars(getSCChars().filter(c=>String(c.charId)!==String(charId)));

// CHARACTER HOVER POPUP (Karakter Kartı)
let popEl, hideT, fetchT, fetchSeq = 0;

const getPopEl = () => {
    if (!popEl) {
        popEl = mk('div','tvis-chpop');
        popEl.addEventListener('mouseenter', () => clearTimeout(hideT));
        popEl.addEventListener('mouseleave', () => { hideT = setTimeout(()=>{ popEl.style.display='none'; },1000); });
        document.body.appendChild(popEl);
    }
    return popEl;
};

const posPopup = (x,y) => {
    const el=getPopEl(), w=388, h=180;
    let l=x+14, t=y-10;
    if (l+w>innerWidth-8) l=x-w-14;
    if (t+h>innerHeight-8) t=innerHeight-h-8;
    el.style.left=Math.max(4,l)+'px'; el.style.top=Math.max(4,t)+'px';
};

const renderPopup = (id, data) => {
    const el      = getPopEl();
    const timeStr = new Date(data.t||Date.now()).toLocaleTimeString(dateLocale,{hour:'2-digit',minute:'2-digit'});
    const radarOn = isOnDef(K.tracking, true);
    const tracked = radarOn && isTrackedV2(id);
    const imgHtml = data.avatarUrl
        ? `<img src="${data.avatarUrl}" onerror="this.parentElement.innerHTML='🧑'" alt="">`
        : '🧑';
    el.innerHTML = `
<div class="tvis-pop-img">${imgHtml}</div>
<div class="tvis-pop-right">
  <div class="tvis-pop-head">
    <div class="tvis-pop-nameline">
      ${radarOn ? `<button class="tvis-trackbtn${tracked?' tracked':''}">${tracked?s('cpTracked'):s('cpTrack')}</button>` : ''}
      <span class="tvis-pop-name">${data.name}</span>
      <button class="tvis-pop-copyid">📋 ID</button>
    </div>
    <div style="font-size:10px;margin-top:2px">${onlineDot(data.online)}</div>
  </div>
  <div class="tvis-pop-body">
    ${data.band?`<div style="font-size:10px"><a href="${data.bandHref}" target="_blank" style="color:#6f42c1;text-decoration:none">🎾 ${data.band}</a></div>`:''}
    ${(data.city||data.locale)?`<div style="font-size:10px">${data.city?`<a href="${data.cityHref}" target="_blank" style="color:#17a2b8;text-decoration:none">đŸ™ïž ${data.city}</a>`:''}${data.locale?` <a href="${data.localeHref}" target="_blank" style="color:#17a2b8;text-decoration:none">📍 ${data.locale}</a>`:''}</div>`:''}
    ${data.attitude?`<div style="font-size:10px;color:#555"><span style="color:#aaa;min-width:38px;display:inline-block">${s('cpAttitude')}</span>${data.attitude}</div>`:''}
    ${data.state?`<div style="font-size:10px;color:#555"><span style="color:#aaa;min-width:38px;display:inline-block">${s('cpState')}</span>${data.state}</div>`:''}
    ${data.cash?`<div style="font-size:10px;color:#555"><span style="color:#aaa;min-width:38px;display:inline-block">${s('cash')}</span><span style="color:#218838;font-weight:600">${data.cash}</span></div>`:''}
  </div>
  <div class="tvis-pop-links">
    <a href="${PM}/Interact/Phone/${id}" class="tvis-pop-link" target="_blank" title="Telefon">📞</a>
    <a href="${PM}/Conversations/Conversation/${id}" class="tvis-pop-link" target="_blank" title="Mesaj">✉</a>
    <a href="${PM}/Interact/${id}" class="tvis-pop-link" target="_blank" title="İlgilen">👋</a>
    <a href="${PM}/Character/OfferItem/${id}" class="tvis-pop-link" target="_blank" title="EƟya Ver">🎁</a>
    <a href="${PM}/Character/GiveMoney/${id}" class="tvis-pop-link" target="_blank" title="Para Ver">💰</a>
    <a href="${PM}/Character/Blog/${id}" class="tvis-pop-link" target="_blank" title="Blog">📖</a>
    <div style="margin-left:auto;display:flex;align-items:center;gap:4px;flex-shrink:0">
      <button class="tvis-updatebtn" title="${s('cpRefresh')}">🔄 ${s('cpRefresh').replace('🔄 ','')}</button>
      <span style="font-size:10px;color:#bbb">${timeStr}</span>
    </div>
  </div>
</div>`;

    if (radarOn) {
        el.querySelector('.tvis-trackbtn')?.addEventListener('click', () => {
            const trackBtn = el.querySelector('.tvis-trackbtn');
            const alreadyTracked = isTrackedV2(id);
            if (alreadyTracked) {
                // Show mini menu: Remove or Move
                document.getElementById('tvis-track-menu')?.remove();
                const menu = mk('div','tvis-tab-edit-pop'); menu.id='tvis-track-menu';
                const rect = trackBtn.getBoundingClientRect();
                menu.style.left = Math.min(rect.left, innerWidth-200)+'px';
                menu.style.top  = (rect.bottom+4)+'px';
                const rmBtn = mkB(s('tkRemove'),'btn-sm btn-r',()=>{
                    removeFromRadar(id);
                    menu.remove(); renderPopup(id,data);
                });
                const mvBtn = mkB(s('tkMove'),'btn-sm btn-v',()=>{
                    menu.remove();
                    showPagePicker(trackBtn, pageIdx => {
                        moveInRadar(id, pageIdx);
                        renderPopup(id,data);
                    }, true);
                });
                rmBtn.style.cssText='width:100%;margin-bottom:3px;display:block;text-align:left';
                mvBtn.style.cssText='width:100%;display:block;text-align:left';
                menu.append(rmBtn,mvBtn);
                document.body.appendChild(menu);
                setTimeout(()=>{
                    const close=e=>{if(!menu.contains(e.target)){menu.remove();document.removeEventListener('click',close);}};
                    document.addEventListener('click',close);
                },50);
            } else {
                showPagePicker(trackBtn, pageIdx => {
                    const newEntry = { charId:String(id), charName:data.name, band:data.band, city:data.city, cityHref:data.cityHref, locale:data.locale, localeHref:data.localeHref, localeId:data.localeId, online:data.online, attitude:data.attitude, state:data.state, cash:data.cash||'', avatarUrl:data.avatarUrl||'', savedAt:Date.now() };
                    addToRadar(pageIdx, newEntry);
                    renderPopup(id,data);
                });
            }
        });
    }
    el.querySelector('.tvis-pop-copyid').onclick = () => {
        navigator.clipboard?.writeText(id);
        addClip(id,data.name,'character');
    };
    el.querySelector('.tvis-updatebtn').onclick = ev => {
        ev.stopPropagation(); CC.del(id);
        const rect=el.getBoundingClientRect(); loadAndShow(id,rect.left+10,rect.top+10);
    };

    // Speed Calling — Friend / Romantic toggle (no confirm)
    const updateWrap = el.querySelector('.tvis-pop-links > div:last-child');
    if (updateWrap) {
        let fBtn, rBtn;
        const refreshFR = () => {
            const cur = getSCChars().find(c=>String(c.charId)===String(id));
            fBtn.textContent = cur?.type==='arkadaß' ? 'đŸ‘„ ✓' : 'đŸ‘„';
            rBtn.textContent = cur?.type==='romantik' ? '💕 ✓' : '💕';
            fBtn.className = 'tvis-trackbtn' + (cur?.type==='arkadaß'?' tracked':'');
            rBtn.className = 'tvis-trackbtn' + (cur?.type==='romantik'?' tracked':'');
        };
        fBtn = mk('button'); rBtn = mk('button');
        fBtn.title = 'Arkadaß'; rBtn.title = 'Romantik';
        fBtn.onclick = () => {
            const cur = getSCChars().find(c=>String(c.charId)===String(id));
            if (cur?.type==='arkadaß') removeSCChar(id);
            else { if (cur) removeSCChar(id); addSCChar(id, data.name||id, 'arkadaß'); }
            refreshFR();
        };
        rBtn.onclick = () => {
            const cur = getSCChars().find(c=>String(c.charId)===String(id));
            if (cur?.type==='romantik') removeSCChar(id);
            else { if (cur) removeSCChar(id); addSCChar(id, data.name||id, 'romantik'); }
            refreshFR();
        };
        refreshFR();

        // Butonları sağdaki div'in içerisine (GĂŒncelleme butonunun yanına) yerleßtiriyoruz
        updateWrap.insertBefore(rBtn, updateWrap.firstChild);
        updateWrap.insertBefore(fBtn, updateWrap.firstChild);
        const scLbl = Object.assign(mk('span','','SC:'), {style:'font-size:9px;color:#888;white-space:nowrap;margin-right:2px'});
        updateWrap.insertBefore(scLbl, updateWrap.firstChild);
    }

    el.style.display='flex';
};

// PAGE PICKER — choose radar page when adding a character
const showPagePicker = (anchorEl, onSelect, moveMode=false) => {
    document.getElementById('tvis-page-picker')?.remove();
    const tabs = getRadarTabs();
    const pop = mk('div','tvis-page-picker'); pop.id='tvis-page-picker';
    const rect = anchorEl ? anchorEl.getBoundingClientRect() : { left: innerWidth/2-100, bottom: innerHeight/2 };
    pop.style.left = Math.min(Math.max(10, rect.left), innerWidth-210)+'px';
    pop.style.top  = (rect.bottom+6)+'px';
    pop.appendChild(mk('div','tvis-sec', moveMode ? s('tkPageMove') : s('tkPageSelect')));
    tabs.forEach((tab, i) => {
        const pageArr = getRadarPage(i);
        const count   = pageArr.length;
        const full    = count >= RADAR_PAGE_SIZE;
        const label   = `${tab.icon} ${tab.name}`;
        const btn = mkB(`${label}  (${count}/${RADAR_PAGE_SIZE})`, 'btn-sm '+(full?'btn-grey':'btn-v'), () => {
            if (full) { showToast(s('tkPageFull')); return; }
            pop.remove(); onSelect(i);
        });
        btn.style.cssText='width:100%;margin-bottom:3px;text-align:left;display:block';
        pop.appendChild(btn);
    });
    document.body.appendChild(pop);
    setTimeout(() => {
        const close = e => { if (!pop.contains(e.target)) { pop.remove(); document.removeEventListener('click', close); } };
        document.addEventListener('click', close);
    }, 50);
};

const loadAndShow = async (id,x,y) => {
    const seq = ++fetchSeq;
    const cached = CC.get(id);
    if (cached) { if (fetchSeq===seq) { renderPopup(id,cached); posPopup(x,y); } return; }
    const el = getPopEl();
    el.innerHTML = `<div style="color:#999;font-size:11px;padding:12px">${s('cpLoading')}</div>`;
    el.style.display='flex'; posPopup(x,y);
    await waitGap(); if (fetchSeq!==seq) return;
    lastFetch = Date.now();
    const html = await fetch(`${PM}/Character/${id}`).then(r=>r.ok?r.text():null).catch(()=>null);
    if (fetchSeq!==seq) return;
    if (!html) { el.style.display='none'; return; }
    const data = parseCharPage(html);
    if (!data) { el.style.display='none'; return; }
    CC.set(id,data); renderPopup(id,data); posPopup(x,y);
};

const applyCharPopup = () => {
    if (!isOnDef(K.charPopup, true)) return;
    let activeLink = null;
    document.addEventListener('mouseover', e => {
        const link = e.target.closest('a[href*="/Character/"]');
        if (link===activeLink) return;
        if (!link||link.closest('#tvis-bar,#tvip-bar,.tvis-ov,.tvis-chpop')) return;
        const m = link.href?.match(/\/Character\/(\d+)(?:[/?#]|$)/); if (!m) return;
        activeLink = link; const id=m[1];
        clearTimeout(fetchT); clearTimeout(hideT);
        const onMove = ev => posPopup(ev.clientX,ev.clientY);
        link.addEventListener('mousemove',onMove);
        fetchT = setTimeout(()=>loadAndShow(id,e.clientX,e.clientY),300);
        link.addEventListener('mouseleave',()=>{ activeLink=null; clearTimeout(fetchT); link.removeEventListener('mousemove',onMove); hideT=setTimeout(()=>{ if(popEl)popEl.style.display='none'; },1000); },{once:true});
    });
};

// RADAR (Takip İstasyonu)
const openTrackModal = () => mkModal(s('tkTitle'), box => {
    let trackPage = Math.max(0, Math.min(RADAR_PAGES-1, parseInt(gmGet(DK.TRACK_PAGE, 0)) || 0));
    let radarSearchQ = '';

    const getBadge = (cls, txt) => `<div class="tvis-tc-badge"><span class="${cls}">${txt}</span></div>`;

    const renderCard = entry => {
        const cached  = CC.get(entry.charId);
        const d       = cached || entry;
        const moved   = cached?.localeId && entry.localeId && cached.localeId !== entry.localeId;
        const isOff   = !d.online || /Çevrimdıßı|Offline|Desconectado/.test(d.online) || /\d{1,2}\.\d{2}\.\d{4}/.test(d.online);
        const updated = !moved && cached && (cached.online !== entry.online || cached.attitude !== entry.attitude || cached.state !== entry.state);
        const online  = !isOff;

        const card = mk('div','tvis-tcard');
        card.dataset.did = entry.charId;
        card.draggable   = true; // FIX: enable drag on radar cards
        if (moved)        card.classList.add('tc-moved');
        else if (updated) card.classList.add('tc-updated');
        else if (online)  card.classList.add('tc-online');

        const imgWrap = mk('div','tvis-tc-img');
        const imgBg   = mk('div','tvis-tc-imgbg');
        if (d.avatarUrl||entry.avatarUrl) {
            const img=mk('img'); img.src=d.avatarUrl||entry.avatarUrl;
            img.onerror=()=>{imgBg.innerHTML='🧑';}; imgBg.appendChild(img);
        } else { imgBg.textContent='🧑'; }
        const dragH = mk('span','tvis-tc-drag','â ż');
        let badgeHtml = '';
        if (moved)        badgeHtml = getBadge('badge-mv', s('badgeMoved'));
        else if (updated) badgeHtml = getBadge('badge-upd', s('badgeUpdated'));
        else if (online)  badgeHtml = getBadge('badge-on', s('badgeOnline'));
        else              badgeHtml = getBadge('badge-off', s('cpOffline'));
        imgBg.insertAdjacentHTML('beforeend', badgeHtml);
        imgWrap.append(imgBg, dragH);

        const body      = mk('div','tvis-tc-body');
        const nameA     = mk('a','tvis-tc-name', entry.charName);
        nameA.href      = `${PM}/Character/${entry.charId}`;
        const onlineRow = mk('div','tvis-tc-row');
        onlineRow.innerHTML = onlineDot(d.online||'', true);
        const locRow = mk('div','tvis-tc-row');
        locRow.innerHTML = [
            d.city  ? `<a href="${d.cityHref||'#'}">${d.city}</a>` : '',
            d.locale? `<a href="${d.localeHref||'#'}">📍 ${d.locale}</a>` : ''
        ].filter(Boolean).join(' â€ș ');

        const allNotes = gmGet(DK.NOTES,{})||{};
        const noteTA   = mk('textarea','tvis-tc-note'); noteTA.placeholder=s('tkNote'); noteTA.value=allNotes[entry.charId]||'';
        const saveBtn  = mk('button','tvis-tc-ok','đŸ’Ÿ'); saveBtn.style.cssText='font-size:8px;padding:1px 3px;flex-shrink:0';
        saveBtn.onclick = () => { const n=gmGet(DK.NOTES,{})||{}; n[entry.charId]=noteTA.value; gmSet(DK.NOTES,n); };

        const updTime  = entry.savedAt ? new Date(entry.savedAt).toLocaleTimeString(dateLocale,{hour:'2-digit',minute:'2-digit'}) : '--:--';
        const actions  = mk('div','tvis-tc-actions');

        // Mesaj butonu
        const msgA = mk('a','','✉');
        msgA.style.cssText='font-size:13px;opacity:.6;text-decoration:none;flex-shrink:0';
        msgA.href  = `${PM}/Conversations/Conversation/${entry.charId}`;
        msgA.title = 'Mesaj';
        msgA.target= '_blank';
        // Para ver butonu
        const moneyA = mk('a','','💰');
        moneyA.style.cssText='font-size:13px;opacity:.6;text-decoration:none;flex-shrink:0';
        moneyA.href  = `${PM}/Character/GiveMoney/${entry.charId}`;
        moneyA.title = 'Para Ver';
        moneyA.target= '_blank';
        // Yanına Git butonu
        const locId = d.localeId || entry.localeId;
        const gotoA = mk('a','','đŸ—ș');
        gotoA.style.cssText='font-size:13px;opacity:.6;text-decoration:none;flex-shrink:0';
        gotoA.title = s('tkGoTo');
        gotoA.target= '_blank';
        if (locId) {
            gotoA.href = `${PM}/Locale/MoveToLocale/${locId}/${entry.charId}`;
        } else {
            gotoA.style.opacity = '0.2';
            gotoA.style.cursor  = 'default';
            gotoA.href = '#';
            gotoA.onclick = e => e.preventDefault();
        }

        const timeSpan = mk('span','tvis-tc-time',updTime);
        const refBtn   = mk('button','tvis-tc-ref','🔄'); refBtn.title=s('cpRefresh');
        refBtn.style.marginLeft = 'auto'; // push right group to end
        const xBtn     = mk('button','tvis-tc-x','✕');

        refBtn.onclick = async () => {
            refBtn.disabled=true; refBtn.textContent='⏳';
            await waitGap(); lastFetch=Date.now();
            const html=await fetch(`${PM}/Character/${entry.charId}`).then(r=>r.ok?r.text():null).catch(()=>null);
            if (html){const data=parseCharPage(html);if(data){CC.set(entry.charId,data);updateInRadar(entry.charId,data);}}
            render();
        };
        const mvBtn = mk('button','tvis-tc-x','↕'); mvBtn.title=s('tkMove');
        mvBtn.onclick = () => {
            showPagePicker(mvBtn, pageIdx => { moveInRadar(entry.charId, pageIdx); render(); }, true);
        };
        xBtn.onclick = () => {
            if(!confirm(s('tkConfirmRm')))return;
            removeFromRadar(entry.charId);
            render();
        };

        // Build body
        body.appendChild(nameA);
        body.appendChild(onlineRow);
        body.appendChild(locRow);

        if (moved) {
            const warnRow=mk('div','tvis-tc-warn',`${s('tcWarnMoved')} ${entry.locale}`);
            body.appendChild(warnRow);
        } else if (updated) {
            const warnRow=mk('div','tvis-tc-warn upd', s('tcWarnUpdated'));
            body.appendChild(warnRow);
        } else {
            // Show state + cash compactly
            const infoParts = [];
            if (d.state) infoParts.push(d.state);
            if (d.cash)  infoParts.push(`<span style="color:#218838;font-weight:600">💰 ${d.cash}</span>`);
            if (infoParts.length) {
                const infoRow = mk('div','tvis-tc-row');
                infoRow.innerHTML = infoParts.join(' · ');
                body.appendChild(infoRow);
            } else if (d.band) {
                body.appendChild(mk('div','tvis-tc-row','🎾 '+d.band));
            }
        }

        const noteRow = mk('div'); noteRow.style.cssText='display:flex;gap:2px;margin-top:auto';
        noteRow.append(noteTA, saveBtn);
        body.appendChild(noteRow);

        if (moved) {
            const okBtn=mk('button','tvis-tc-ok','✔'); okBtn.title=s('tkConfirmOk'); okBtn.style.flexShrink='0';
            okBtn.onclick=()=>{ updateInRadar(entry.charId,{locale:cached.locale,localeId:cached.localeId,city:cached.city,cityHref:cached.cityHref}); render(); };
            actions.append(msgA, moneyA, gotoA, okBtn, refBtn, mvBtn, timeSpan, xBtn);
        } else {
            actions.append(msgA, moneyA, gotoA, refBtn, mvBtn, timeSpan, xBtn);
        }
        body.appendChild(actions);

        card.append(imgWrap,body);
        return card;
    };

    const bulkFetch = entries => {
        if (BGTASKS.radar.running) return;

        startBackgroundTask('radar', entries.length, async (task) => {
            for(let i = 0; i < entries.length; i++){
                if (task.cancelled) break;
                if(i > 0) await new Promise(r => setTimeout(r, 2000 + Math.random() * 4000));
                if (task.cancelled) break;
                await waitGap(); lastFetch = Date.now();

                const html = await fetch(`${PM}/Character/${entries[i].charId}`)
                    .then(r => r.ok ? r.text() : null)
                    .catch(() => null);

                if(html) {
                    const data = parseCharPage(html);
                    if(data) {
                        CC.set(entries[i].charId, data);
                        updateInRadar(entries[i].charId, data);
                    }
                }

                task.current = i + 1;
                saveTaskState('radar');

                const txtEl = document.getElementById('tvis-radar-prog-txt');
                if (txtEl) txtEl.textContent = `${s('tkBgRunning')} ${task.current}/${task.total}`;
            }
            if(document.getElementById('tvis-modal')) render();
        });
    };

    // TAB EDIT POPUP — opens via ✏ button next to each tab
    const openTabEdit = (tabIdx, anchorEl) => {
        document.getElementById('tvis-tab-edit-pop')?.remove();
        const pop = mk('div','tvis-tab-edit-pop'); pop.id='tvis-tab-edit-pop';
        const rect = anchorEl.getBoundingClientRect();
        pop.style.left = Math.min(rect.left, innerWidth-240)+'px';
        pop.style.top  = (rect.bottom+4)+'px';

        const tabs = getRadarTabs();
        const cur  = tabs[tabIdx];
        let selIcon = cur.icon;

        pop.appendChild(mk('div','tvis-sec',s('tkTabEdit')));
        const iconPick = mk('div','tvis-icon-pick'); iconPick.style.maxHeight='80px';
        const custom = getCustomIcons();
        const allIcos = custom.length ? [...custom, '|', ...ICONS] : ICONS;
        allIcos.forEach(ico => {
            if (ico === '|') {
                const sep = mk('div'); sep.style.cssText='width:100%;height:1px;background:#eee;margin:2px 0';
                iconPick.appendChild(sep); return;
            }
            const b = mk('button', ico===selIcon?'sel':'', ico); b.type='button';
            b.onclick = () => { selIcon=ico; iconPick.querySelectorAll('button').forEach(x=>x.className=''); b.className='sel'; };
            iconPick.appendChild(b);
        });
        pop.appendChild(iconPick);

        const nameI = mk('input'); nameI.value=cur.name; nameI.maxLength=12;
        nameI.style.cssText='width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin:4px 0';
        pop.appendChild(nameI);

        const getTabColor = mkColorPicker(pop, cur.color||'#6f42c1');

        pop.appendChild(mkB('✔ ' + s('iaSave'), 'btn-sm btn-g', () => {
            const t = getRadarTabs();
            t[tabIdx] = { icon: selIcon, name: (nameI.value.trim().toUpperCase().substring(0,12)) || String(tabIdx+1), color: getTabColor() };
            gmSet(DK.RADAR_TABS, t);
            pop.remove();
            render();
        }));

        const cancelBtn = mkB(s('cancelLbl'), 'btn-sm btn-grey', () => pop.remove());
        cancelBtn.style.marginLeft='4px';
        pop.lastChild.insertAdjacentElement('afterend', cancelBtn);

        document.body.appendChild(pop);
        setTimeout(() => {
            const close = e => { if (!pop.contains(e.target)) { pop.remove(); document.removeEventListener('mousedown', close); } };
            document.addEventListener('mousedown', close);
        }, 10);
    };

    const render = () => {
        box.querySelectorAll('.tvis-tl').forEach(e=>e.remove());
        const pageEntries = getRadarPage(trackPage);
        const tabs        = getRadarTabs();
        const realEntries = pageEntries;

        if (!pageEntries.length && trackPage === 0) {
            const anyTracked = getAllTracked().length > 0;
            if (!anyTracked) {
                const w=mk('div','tvis-tl'); const d=mk('div','',s('tkEmpty')); d.style.cssText='color:#999;font-size:12px;margin-bottom:10px';
                w.appendChild(d); box.appendChild(w); return;
            }
        }

        const wrap = mk('div','tvis-tl');

        // SEARCH BAR
        const searchRow = mk('div'); searchRow.style.cssText='display:flex;gap:6px;align-items:center;margin-bottom:8px';
        const searchI = mk('input'); searchI.id='tvis-radar-search';
        searchI.placeholder='🔍 Karakterleri ara...';
        searchI.style.cssText='flex:1;padding:4px 8px;border:1px solid #c9b8f0;border-radius:4px;font-size:12px';
        searchI.value = radarSearchQ;
        const clearBtn = mkB('✕','btn-sm btn-grey',()=>{ radarSearchQ=''; render(); });
        clearBtn.style.display = radarSearchQ ? '' : 'none';
        searchI.addEventListener('input',()=>{ radarSearchQ=searchI.value; clearBtn.style.display=radarSearchQ?'':'none'; renderSearchOrNormal(); });
        searchRow.append(searchI, clearBtn);
        wrap.appendChild(searchRow);

        const renderSearchOrNormal = () => {
            // Remove previous content below search bar
            wrap.querySelectorAll('.tvis-tl-body').forEach(e=>e.remove());
            const body = mk('div','tvis-tl-body');
            wrap.appendChild(body);

            if (radarSearchQ.trim()) {
                // Search mode
                const q = radarSearchQ.trim().toLowerCase();
                const results = [];
                for (let i=0; i<RADAR_PAGES; i++) {
                    getRadarPage(i).forEach(entry => {
                        if ((entry.charName||'').toLowerCase().includes(q)) results.push({entry,pageIdx:i});
                    });
                }
                if (!results.length) {
                    const em=mk('div','',`"${radarSearchQ}" için sonuç bulunamadı.`); em.style.cssText='color:#999;font-size:12px;padding:16px 0;text-align:center';
                    body.appendChild(em);
                } else {
                    const infoRow=mk('div',''); infoRow.style.cssText='font-size:10px;color:#aaa;margin-bottom:6px';
                    infoRow.textContent=`${results.length} sonuç`;
                    body.appendChild(infoRow);
                    const grid=mk('div','tvis-tgrid');
                    results.forEach(({entry,pageIdx})=>{
                        const card=renderCard(entry);
                        // Tab badge overlay
                        const tab=tabs[pageIdx];
                        const badge=mk('div',''); badge.style.cssText='position:absolute;top:3px;right:3px;font-size:8px;padding:1px 5px;border-radius:8px;color:#fff;font-weight:700;z-index:2;pointer-events:none';
                        badge.style.background=tab.color||'#6f42c1';
                        badge.textContent=`${tab.icon} ${tab.name}`;
                        card.style.position='relative';
                        card.appendChild(badge);
                        grid.appendChild(card);
                    });
                    body.appendChild(grid);
                }
                // Tab row — dimmed in search mode
                const tabRow2 = buildTabRow(tabs, true);
                body.insertAdjacentElement('afterbegin', tabRow2);
            } else {
                // Normal mode
                const tabRow2 = buildTabRow(tabs, false);
                body.appendChild(tabRow2);
                buildNormalContent(body, tabs, realEntries);
            }
        };

        const buildTabRow = (tabs, dimmed) => {
            const tabRow = mk('div'); tabRow.style.cssText='display:flex;gap:4px;align-items:center;margin-bottom:10px;flex-wrap:wrap';
            if(dimmed) tabRow.style.opacity='0.55';
            tabs.forEach((tab, i) => {
                const tabWrap = mk('span'); tabWrap.style.cssText='display:inline-flex;align-items:center;gap:1px';
                const isWT = false;
                const lbl  = `${tab.icon} ${tab.name}`;
                const btn  = mk('button', 'tvis-page-tab'+(trackPage===i&&!dimmed?' active':''), lbl);
                const tc = tab.color||'#6f42c1';
                btn.style.borderColor = tc;
                if(trackPage===i&&!dimmed){ btn.style.background=tc; btn.style.color='#fff'; }
                else { btn.style.color=tc; }
                btn.onclick = () => { radarSearchQ=''; trackPage=i; gmSet(DK.TRACK_PAGE,i); render(); };
                btn.title   = tab.icon+' '+tab.name;
                const editBtn = mk('button','tvis-tab-edit-btn','✏');
                editBtn.title = s('tkTabEdit');
                editBtn.onclick = e => { e.stopPropagation(); openTabEdit(i, editBtn); };
                tabWrap.append(btn, editBtn);
                tabRow.appendChild(tabWrap);
            });
            const bulkBtn = mk('button','btn-b',s('tkUpdate')); bulkBtn.style.cssText='font-size:10px;padding:3px 10px;margin-left:auto;white-space:nowrap;flex-shrink:0';
            bulkBtn.onclick = () => { if (BGTASKS.radar.running) return; bulkFetch(pageEntries.filter(e=>!e._empty)); };
            if (BGTASKS.radar.running) { bulkBtn.disabled=true; bulkBtn.style.opacity='.5'; }
            tabRow.appendChild(bulkBtn);
            return tabRow;
        };

        const buildNormalContent = (body, tabs, realEntries) => {
            const grid = mk('div','tvis-tgrid');
            mkDraggable(grid, ids => {
                const pageArr = getRadarPage(trackPage);
                const map = {}; pageArr.forEach(e => { map[e.charId] = e; });
                const reordered = ids.map(id => map[id]).filter(Boolean);
                setRadarPage(trackPage, reordered); render();
            });
            pageEntries.forEach(entry => { grid.appendChild(renderCard(entry)); });
            const totalTracked = getAllTracked().length;
            body.appendChild(grid);
            const footer = mk('div'); footer.style.cssText='margin-top:8px;font-size:10px;color:#bbb;display:flex;justify-content:space-between;flex-wrap:wrap;gap:4px';
            footer.innerHTML=`<span>${s('tcFooterHint')}</span><span>${s('tcPage')} ${trackPage+1}: ${realEntries.length}/${RADAR_PAGE_SIZE} · ${s('tcTotal')}: ${totalTracked}</span>`;
            body.appendChild(footer);
        };

        renderSearchOrNormal();
        box.appendChild(wrap);
        // Restore focus to search box after re-render
        if (radarSearchQ) setTimeout(()=>{ const si=document.getElementById('tvis-radar-search'); if(si){si.focus();si.setSelectionRange(si.value.length,si.value.length);} },10);
    };
    render();
});

// INTERACT HELPER DATA
const INTERACT_DATA = {
    1:{sub:'temel',joy:'+2-3%',love:null,hate:'-1%',note:null},
    3:{sub:'sözlĂŒ',joy:'+2-3%',love:null,hate:'-2%',note:null},
    4:{sub:'özel',joy:'+1%',love:null,hate:'-1%',note:'🎭 ⭐ Komedi'},
    5:{sub:'sözlĂŒ',joy:'+2-3%',love:null,hate:'-2%',note:null},
    6:{sub:'fiziksel',joy:'+5%',love:null,hate:null,note:'đŸ‘¶ Bebeklere'},
    7:{sub:'fiziksel',joy:null,love:'+2%',hate:null,note:'đŸ» Bar/Rest'},
    8:{sub:'fiziksel',joy:'+2-3%',love:null,hate:null,note:null},
    9:{sub:'yakın temas',joy:null,love:'+5%',hate:null,note:null},
    10:{sub:'yakın temas',joy:null,love:'+5%',hate:null,note:null},
    11:{sub:'cinsel',joy:'-1%',love:'+5%',hate:null,note:'🔞 ⭐ Seks | 🏠 Ev/Otel/Park'},
    12:{sub:'fiziksel',joy:null,love:'+2-3%',hate:'-1%',note:null},
    13:{sub:'cinsel',joy:null,love:'+2-3%',hate:null,note:'🔞 ⭐ Seks | 🏠 Ev/Otel/Park'},
    14:{sub:'sözlĂŒ',joy:null,love:'+2-3%',hate:null,note:null},
    15:{sub:'temel',joy:'-1%',love:null,hate:'+5%',note:null},
    16:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:null},
    17:{sub:'yakın temas',joy:null,love:null,hate:'+10%',note:'👊 Karßılıklı vuruß: Kalıcı sağlık kaybı đŸ©č'},
    18:{sub:'fiziksel',joy:'+5%',love:null,hate:'-4%',note:null},
    19:{sub:'cinsel',joy:'-1%',love:'+5%',hate:null,note:'🔞 ⭐ Tantrik | 🏠 Ev/Otel'},
    20:{sub:'cinsel',joy:null,love:'+5%',hate:null,note:'🏠 Ev/Otel'},
    21:{sub:'özel',joy:'+2-3%',love:null,hate:'-2%',note:'đŸŽ€ ⭐ ƞarkı'},
    22:{sub:'özel',joy:null,love:null,hate:null,note:'📔 Sadece gĂŒnlĂŒk yazısı'},
    24:{sub:'telefon',joy:'+2-3%',love:null,hate:'-2%',note:null},
    25:{sub:'telefon',joy:null,love:'+5%',hate:null,note:null},
    26:{sub:'telefon',joy:'+2-3%',love:null,hate:'-2%',note:null},
    29:{sub:'özel',joy:'+2%',love:null,hate:null,note:null},
    30:{sub:'fiziksel',joy:null,love:'+5%',hate:null,note:null},
    32:{sub:'tıbbi',joy:'+5%',love:null,hate:'-5%',note:'đŸ©ș ⭐ Tıp'},
    33:{sub:'özel',joy:'+2-8%',love:null,hate:'-6%',note:'đŸȘ„ ⭐ İllĂŒzyon | DĂŒĆŸĂŒk Yetenek arkadaßlığı dĂŒĆŸĂŒrĂŒr'},
    34:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-4%',note:null},
    35:{sub:'fiziksel',joy:null,love:'+3-7%',hate:null,note:'💃 ⭐ Dans | đŸ» Bar/Rest/StĂŒdyo/Lahit'},
    36:{sub:'fiziksel',joy:'-4-6%',love:null,hate:'+5-7%',note:null},
    37:{sub:'ölĂŒmcĂŒl',joy:'-10%',love:null,hate:'+10%',note:null},
    38:{sub:'ölĂŒmcĂŒl',joy:'-5%',love:null,hate:'+10%',note:null},
    39:{sub:'ruhani',joy:'+1-2%',love:null,hate:null,note:'â›Ș ⭐ Din | İbadet evi'},
    41:{sub:'yakın temas',joy:'-2%',love:null,hate:'+2%',note:null},
    42:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:null},
    44:{sub:'tıbbi',joy:'+5%',love:null,hate:'-5%',note:null},
    45:{sub:'ölĂŒmcĂŒl',joy:null,love:null,hate:'+10%',note:'đŸ”« ⭐ Silah'},
    46:{sub:'telefon',joy:'-5%',love:'-5%',hate:'+10%',note:null},
    47:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-4%',note:null},
    48:{sub:'yakın temas',joy:'-2%',love:null,hate:'+3%',note:null},
    49:{sub:'fiziksel',joy:'-2-4%',love:'-2-3%',hate:'+3-5%',note:null},
    51:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-5%',note:null},
    52:{sub:'sözlĂŒ',joy:'+2%',love:null,hate:null,note:'đŸ€« đŸ‘¶ Bebeklere'},
    54:{sub:'temel',joy:'+0-1%',love:null,hate:'-1%',note:null},
    55:{sub:'fiziksel',joy:'+2-3%',love:null,hate:'-2%',note:null},
    56:{sub:'yakın temas',joy:'+2-3%',love:null,hate:'-2%',note:null},
    57:{sub:'sözlĂŒ',joy:'+2-3%',love:null,hate:'-2-3%',note:null},
    58:{sub:'telefon',joy:'+2-3%',love:'+2%',hate:'-1%',note:null},
    59:{sub:'fiziksel',joy:'+2-3%',love:null,hate:'-2%',note:null},
    60:{sub:'yakın temas',joy:'+5%',love:null,hate:'-4%',note:null},
    61:{sub:'telefon',joy:'+2-3%',love:null,hate:'-2%',note:null},
    62:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-4%',note:null},
    63:{sub:'fiziksel',joy:'+5%',love:null,hate:'-4%',note:null},
    64:{sub:'yakın temas',joy:null,love:'+5%',hate:null,note:null},
    65:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-4%',note:null},
    66:{sub:'fiziksel',joy:'+5%',love:null,hate:'-4%',note:null},
    67:{sub:'yakın temas',joy:'+5%',love:null,hate:'-4%',note:null},
    68:{sub:'sözlĂŒ',joy:'+2%',love:null,hate:null,note:null},
    69:{sub:'en iyi arkadaß',joy:'+5%',love:'-1%',hate:null,note:null},
    70:{sub:'en iyi arkadaß',joy:'+5%',love:'-1%',hate:null,note:null},
    71:{sub:'sözlĂŒ',joy:null,love:'+2%',hate:null,note:null},
    72:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:null},
    73:{sub:'telefon',joy:null,love:'+2-3%',hate:'-2%',note:null},
    74:{sub:'telefon',joy:null,love:'+2-3%',hate:null,note:null},
    75:{sub:'sözlĂŒ',joy:null,love:'+5%',hate:null,note:null},
    76:{sub:'sözlĂŒ',joy:null,love:'+5%',hate:null,note:null},
    77:{sub:'sözlĂŒ',joy:null,love:'+5%',hate:null,note:null},
    78:{sub:'özel',joy:null,love:'+5%',hate:'-2%',note:'đŸŽ€ ⭐ ƞarkı'},
    79:{sub:'sözlĂŒ',joy:null,love:null,hate:'+2%',note:null},
    80:{sub:'telefon',joy:'-2-3%',love:null,hate:'+2-3%',note:null},
    81:{sub:'sözlĂŒ',joy:null,love:null,hate:'+5%',note:null},
    82:{sub:'yakın temas',joy:null,love:null,hate:'+5%',note:null},
    83:{sub:'telefon',joy:null,love:null,hate:'+5%',note:null},
    84:{sub:'sözlĂŒ',joy:'-5%',love:null,hate:'+5%',note:null},
    85:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:null},
    86:{sub:'telefon',joy:'-3%',love:'+3%',hate:'+2-3%',note:null},
    87:{sub:'sözlĂŒ',joy:null,love:null,hate:'+5%',note:null},
    88:{sub:'yakın temas',joy:null,love:null,hate:'+5%',note:null},
    89:{sub:'fiziksel',joy:null,love:'+5%',hate:null,note:'đŸ‹ïž Spor/Sahil'},
    93:{sub:'yakın temas',joy:'+5%',love:null,hate:null,note:'đŸ‘¶ 🧒 Çocuk/Bebek'},
    94:{sub:'sözlĂŒ',joy:'+2%',love:null,hate:null,note:'đŸ‘¶ Bebeklere'},
    96:{sub:'özel',joy:'+3-5%',love:null,hate:null,note:'đŸŽ€ ⭐ ƞarkı | đŸ‘¶ Bebeklere'},
    101:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:null,note:'🧒 Çocuklara'},
    102:{sub:'yakın temas',joy:'+2%',love:null,hate:null,note:'🧒 Çocuklara'},
    103:{sub:'yakın temas',joy:'+5%',love:null,hate:null,note:'🧒 Çocuklara'},
    104:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:'-4%',note:'🧒 Çocuklara'},
    105:{sub:'sözlĂŒ',joy:'+2%',love:null,hate:null,note:'🧒 Çocuklara'},
    115:{sub:'sözlĂŒ',joy:null,love:null,hate:'+3%',note:null},
    121:{sub:'telefon',joy:'+2-3%',love:null,hate:'+2-3%',note:null},
    129:{sub:'fiziksel',joy:null,love:'+5%',hate:'-3%',note:'đŸŒČ Park/Kırsal'},
    133:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:'🎓 Üniversite'},
    136:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:null,note:'đŸȘŠ Mezarlık'},
    137:{sub:'fiziksel',joy:null,love:null,hate:'+5%',note:null},
    138:{sub:'ölĂŒmcĂŒl',joy:null,love:'-10%',hate:'+10%',note:'🚗 Yol/Üni'},
    139:{sub:'sözlĂŒ',joy:'+5%',love:null,hate:null,note:'📚 Okul/Üni'},
    154:{sub:'sözlĂŒ',joy:null,love:'-15%',hate:null,note:'💔 Aßk 📉'},
    155:{sub:'sözlĂŒ',joy:null,love:null,hate:'-15%',note:'đŸ•Šïž Nefret 📉'},
    156:{sub:'sözlĂŒ',joy:'-15%',love:null,hate:null,note:'â˜č Keyif 📉'},
    157:{sub:'telefon',joy:'-3%',love:'-15%',hate:null,note:null},
    158:{sub:'fiziksel',joy:'+5%',love:null,hate:null,note:'🐟 Alabalık ƞart'},
    161:{sub:'temel',joy:null,love:'+2%',hate:null,note:null},
    162:{sub:'telefon',joy:'+1%',love:null,hate:null,note:null},
    164:{sub:'cinsel',joy:'-1%',love:'+5%',hate:null,note:null},
    166:{sub:'sözlĂŒ',joy:'+0-3%',love:null,hate:'-3%',note:null},
    171:{sub:'telefon',joy:'+2%',love:null,hate:null,note:null}
};
// Merge hardcoded data with user's custom entries (custom overrides on conflict)
const getInteractData = () => {
    const custom = gmGet(DK.INTERACT_CUSTOM, {}) || {};
    return Object.assign({}, INTERACT_DATA, custom);
};

const INTERACT_DEFAULTS = {
    arkadaß:  [34, 62, 1],
    romantik: [35, 78, 10],
    nefret:   [15, 16, 84],
    özel:     [154, 155, 156],
};

const INTERACT_TYPES = ['standart','arkadaß','romantik','nefret','özel'];

// INLINE ACTIONS (Hızlı Bağlantılar)
const W = PM + '/';
const IA_DEF = {
    character: [
        {id:'msg',   icon:'✉',label:'Mesaj',     path:`${W}Conversations/Conversation/`,  idType:'character'},
        {id:'iact',  icon:'👋',label:'İlgilen',   path:`${W}Interact/`,                    idType:'character'},
        {id:'copyid',icon:'📋',label:'ID Kopyala',path:'',                                 idType:'copyid'},
    ],
    locale: [
        {id:'goto',  icon:'đŸ—ș',label:'Git',           path:`${W}Locale/MoveToLocale/`,      idType:'locale'},
        {id:'chars', icon:'đŸ‘„',label:'Mekandakiler',   path:`${W}Locale/CharactersPresent/`, idType:'locale'},
        {id:'copyid',icon:'📋',label:'ID Kopyala',     path:'',                              idType:'copyid'},
    ],
    artist: [
        {id:'upcoming',icon:'đŸŽ”',label:'Gelecek Konserler',path:`${W}Artist/UpcomingPerformances/`,idType:'artist'},
        {id:'past',    icon:'đŸŽ¶',label:'Son Konserler',    path:`${W}Artist/PastPerformances/`,    idType:'artist'},
        {id:'copyid',  icon:'📋',label:'ID Kopyala',       path:'',                               idType:'copyid'},
    ],
    city: [
        {id:'flight',icon:'✈',label:'Uçuß',    path:`${W}City/BookFlight/`, idType:'city'},
        {id:'jet',   icon:'đŸ›©ïž',label:'VIP Jet', path:`${W}City/PrivateJet/`, idType:'city'},
        {id:'road',  icon:'🚗',label:'Kara',     path:`${W}City/RoadTrip/`,   idType:'city'},
    ],
};
// copyid removed from type dropdown — copyid buttons in IA_DEF still work
const IA_TYPES  = ['character','locale','artist','city'];
const IA_LABELS = {
    character:   '🧑 Karakter',
    locale:      '📍 Mekan',
    artist:      '🎾 Sanatçı',
    city:        'đŸ™ïž ƞehir',
};

const getIA  = sec => gmGet(DK.IA+sec, null) || IA_DEF[sec] || [];
const saveIA = (sec,v) => gmSet(DK.IA+sec,v);
const resetIA= sec => gmDel(DK.IA+sec);

// IA Exclusion list helpers
const getIAExcl  = () => gmGet(DK.IA_EXCL, []) || [];
const saveIAExcl = v  => gmSet(DK.IA_EXCL, v);

// Detect own character ID/name from the top nav shortcuts
const getOwnCharInfo = () => {
    const a = document.querySelector('#character-tools-shortcuts a[href*="/Character/"]');
    if (!a) return null;
    const m = a.href.match(/\/Character\/(\d+)/);
    if (!m) return null;
    return { id: m[1], name: (a.textContent || '').trim() };
};

const parseURL = url => { try { return new URL(url.includes('://')?url:'https://p.com'+url).pathname.replace(/\/\d+([?#].*)?$/,'').replace(/\/?$/,'/'); } catch { return url; } };

const openIAEdit = () => mkModal(s('iaEdit'), cont => {
    let active='character';
    const tabs=mk('div'); tabs.style.cssText='display:flex;gap:4px;margin-bottom:10px;flex-wrap:wrap';
    const tBtns={}; cont.appendChild(tabs);
    const secCont=mk('div'); cont.appendChild(secCont);
    const renderSec=()=>{
        secCont.innerHTML='';
        const cfg=getIA(active).map(a=>({...a}));
        const list=mk('div');
        mkDraggable(list,ids=>{ const cur=getIA(active),map={}; cur.forEach(a=>{map[a.id]=a;}); saveIA(active,ids.map(id=>map[id]).filter(Boolean)); renderSec(); });
        cfg.forEach(a=>{
            const row=mk('div','tvis-iarow'); row.draggable=true; row.dataset.did=a.id;
            const dr=mk('span','','â ż'); dr.style.cssText='color:#ccc;cursor:grab;flex-shrink:0';
            const ic=mk('span','',a.icon+' ');
            const lb=mk('span','',a.label); lb.style.flex='1';
            const tp=mk('span','',a.idType); tp.style.cssText='font-size:10px;color:#aaa;flex-shrink:0';
            const rm=mkB('🗑','btn-sm btn-r',()=>{saveIA(active,getIA(active).filter(x=>x.id!==a.id));renderSec();});
            row.append(dr,ic,lb,tp,rm); list.appendChild(row);
        });
        secCont.appendChild(list);
        const rst=mkB(s('iaDefaults'),'btn-sm btn-grey',()=>{if(confirm(s('iaResetConfirm'))){resetIA(active);renderSec();}});
        rst.style.margin='6px 0'; secCont.appendChild(rst);
        const form=mk('div'); form.style.cssText='border-top:1px solid #eee;padding-top:8px;margin-top:2px';
        form.appendChild(mk('div','tvis-sec',s('iaAddSec')));
        const urlI=mk('input'); urlI.placeholder=s('iaUrlPlh'); urlI.style.cssText='width:100%;box-sizing:border-box;padding:4px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin-bottom:3px';
        const nfo=mk('div',''); nfo.style.cssText='font-size:10px;color:#17a2b8;margin-bottom:5px;min-height:13px';
        urlI.addEventListener('input',()=>{const v=urlI.value.trim();nfo.textContent=v?s('iaUrlInfo')+' '+parseURL(v):''});
        const lblI=mk('input'); lblI.placeholder=s('iaLblPlh'); lblI.style.cssText='width:100%;box-sizing:border-box;padding:4px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin-bottom:6px';
        const tRow=mk('div'); tRow.style.cssText='display:flex;align-items:center;gap:6px;margin-bottom:6px';
        const tSel=mk('select'); tSel.style.cssText='flex:1;padding:3px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        IA_TYPES.forEach(tp=>{const o=mk('option','',tp);o.value=tp;tSel.appendChild(o);}); tSel.value=active;
        tRow.append(mk('span','','ID Tipi:'),tSel);
        form.append(urlI,nfo,lblI,tRow);
        form.appendChild(mk('div','tvis-sec','Simge'));
        const getSel=mkIconPicker(form,'🔗');
        form.appendChild(mkB(s('iaSave'),'btn-sm btn-g',()=>{
            const url=urlI.value.trim(),lbl=lblI.value.trim(); if(!url||!lbl) return;
            const c=getIA(active); c.push({id:'c'+Date.now(),icon:getSel(),label:lbl,path:parseURL(url),idType:tSel.value});
            saveIA(active,c); urlI.value=''; lblI.value=''; renderSec();
        }));
        secCont.appendChild(form);
    };
    Object.entries(IA_LABELS).forEach(([sec,lbl])=>{
        const b=mkB(lbl,sec===active?'btn-sm btn-v':'btn-sm btn-grey',()=>{active=sec;Object.entries(tBtns).forEach(([k,b])=>b.className=k===sec?'btn-sm btn-v':'btn-sm btn-grey');renderSec();});
        tBtns[sec]=b; tabs.appendChild(b);
    });
    renderSec();
});

// IA EXCLUSION LIST MODAL
const openIAExclModal = () => mkModal(s('iaExclTitle'), cont => {
    const render = () => {
        cont.innerHTML = '';
        const list = getIAExcl();

        if (!list.length) {
            const em = mk('div', '', s('iaExclEmpty'));
            em.style.cssText = 'color:#999;font-size:12px;margin-bottom:10px';
            cont.appendChild(em);
        } else {
            list.forEach((entry, idx) => {
                const row = mk('div', 'tvis-iarow');
                const idSp   = mk('span', '', entry.id);  idSp.style.cssText = 'font-weight:bold;flex-shrink:0;min-width:50px';
                const nameSp = mk('span', '', entry.name || '—'); nameSp.style.cssText = 'flex:1;color:#555';
                const typeSp = mk('span', '', entry.type || 'character'); typeSp.style.cssText = 'font-size:10px;color:#aaa;flex-shrink:0';
                const delBtn = mkB(s('iaExclDel'), 'btn-sm btn-r', () => {
                    const cur = getIAExcl();
                    cur.splice(idx, 1);
                    saveIAExcl(cur);
                    render();
                });
                row.append(idSp, nameSp, typeSp, delBtn);
                cont.appendChild(row);
            });
        }

        // "Add Myself" button
        const own = getOwnCharInfo();
        const addMeBtn = mkB(s('iaExclAddMe'), 'btn-sm btn-g', () => {
            if (!own) { alert(s('iaExclNoId')); return; }
            const cur = getIAExcl();
            if (cur.some(e => String(e.id) === String(own.id))) return;
            cur.push({ id: own.id, name: own.name, type: 'character' });
            saveIAExcl(cur);
            render();
        });
        if (!own) { addMeBtn.disabled = true; addMeBtn.title = s('iaExclNoId'); }
        addMeBtn.style.marginBottom = '10px';
        cont.appendChild(addMeBtn);

        // Add form
        const form = mk('div'); form.style.cssText = 'border-top:1px solid #eee;padding-top:8px;margin-top:4px';
        form.appendChild(mk('div', 'tvis-sec', s('iaExclAdd')));

        const row = mk('div'); row.style.cssText = 'display:flex;gap:5px;flex-wrap:wrap;align-items:center;margin-bottom:6px';
        const idI   = mk('input'); idI.placeholder = s('iaExclIdPlh');
        idI.style.cssText = 'width:80px;padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        idI.type = 'number'; idI.min = '1';
        const nameI = mk('input'); nameI.placeholder = s('iaExclNamePlh');
        nameI.style.cssText = 'flex:1;min-width:90px;padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        const typeSel = mk('select'); typeSel.style.cssText = 'padding:3px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        ['character','locale','artist','city'].forEach(t => {
            const o = mk('option', '', t); o.value = t; typeSel.appendChild(o);
        });
        row.append(idI, nameI, typeSel);
        form.appendChild(row);
        form.appendChild(mkB(s('iaExclAdd'), 'btn-sm btn-g', () => {
            const id = idI.value.trim(); if (!id) return;
            const cur = getIAExcl();
            if (cur.some(e => String(e.id) === id)) return;
            cur.push({ id, name: nameI.value.trim(), type: typeSel.value });
            saveIAExcl(cur);
            idI.value = ''; nameI.value = '';
            render();
        }));
        cont.appendChild(form);
    };
    render();
});

const applyInlineActions = () => {
    if (!isOnDef(K.ia, true)) return;
    const clip=(id,name,type)=>{ navigator.clipboard?.writeText(id); addClip(id,name,type); };
    const mkBtn=(a,id,name,sec)=>{
        if (a.idType==='copyid'){const b=mk('button','tvis-ia',a.icon);b.title=a.label;b.onclick=e=>{e.preventDefault();e.stopPropagation();clip(id,name,sec);};return b;}
        const el=mk('a','tvis-ia',a.icon); el.title=a.label; el.href=a.path+id; return el;
    };

    // Build exclusion set once for this pass
    const _excl = getIAExcl();
    const _exclIds = new Set(_excl.map(e => String(e.id)));

const SELS = {
        character:   {sel:'a[href*="/Character/"]',               r:/\/Character\/(\d+)(?:[/?#]|$)/},
        locale:      {sel:'a[href*="/Locale/"]',                  r:/\/Locale\/(\d+)(?:[/?#]|$)/},
        artist:      {sel:'a[href*="/Artist/"]',                   r:/\/Artist\/(\d+)(?:[/?#]|$)/},
        city:        {sel:'a[href*="/City/"]',                     r:/\/City\/(\d+)(?:[/?#]|$)/},
    };

    Object.entries(SELS).forEach(([sec,cfg])=>{
        const acts=getIA(sec);
        document.querySelectorAll(cfg.sel).forEach(link=>{
            //Quick Links Exclusion - Buralarda Quick links çalıßmaz
            if(link.dataset.tvisIa||link.closest('#tvis-bar,#tvip-bar,.tvis-ov,.tvip-ov,.tvis-chpop,#character-tools-shortcuts')) return;
            const m=link.href?.match(cfg.r); if(!m) return;
            // ID-based exclusion list check
            if (_exclIds.has(m[1])) return;
            link.dataset.tvisIa='1';
            const span=mk('span','tvis-ia-wrap');
            acts.forEach(a=>span.appendChild(mkBtn(a,m[1],link.textContent.trim(),sec)));
            link.insertAdjacentElement('afterend',span);
        });
    });
};
// INTERACT CUSTOM DATA EDITOR
const openInteractDataEdit = () => mkModal(s('interactDataEdit'), cont => {
    const getCustom  = () => gmGet(DK.INTERACT_CUSTOM, {}) || {};
    const saveCustom = d  => gmSet(DK.INTERACT_CUSTOM, d);

    const render = () => {
        cont.innerHTML = '';
        const custom = getCustom();
        const keys   = Object.keys(custom);

        if (!keys.length) {
            const em = mk('div','',s('interactDataEmpty'));
            em.style.cssText = 'color:#999;font-size:12px;margin-bottom:10px';
            cont.appendChild(em);
        } else {
            const tbl = mk('table','tvis-ih-guide-tbl'); tbl.style.marginBottom='10px';
            const thead = mk('thead');
            const hr = mk('tr');
            ['ID', s('interactType'), s('interactColJoy'), s('interactColLove'), s('interactColHate'), s('interactColNote'), ''].forEach(h => {
                const th = mk('th','',h); hr.appendChild(th);
            });
            thead.appendChild(hr); tbl.appendChild(thead);
            const tbody = mk('tbody');
            keys.sort((a,b)=>Number(a)-Number(b)).forEach(k => {
                const d  = custom[k];
                const tr = mk('tr');
                const subBadge = d.sub ? `<span class="tvis-ih-badge tvis-ih-badge-${d.sub?.[0]}">${d.sub}</span>` : '—';
                [
                    `<b>${k}</b>`,
                    subBadge,
                    d.joy  ? `<span class="tvis-ih-joy">${d.joy}</span>`  : '—',
                    d.love ? `<span class="tvis-ih-love">${d.love}</span>`: '—',
                    d.hate ? `<span class="tvis-ih-hate">${d.hate}</span>`: '—',
                    d.note ? `<span class="tvis-ih-note">${d.note}</span>`: '—',
                ].forEach(html => { const td=mk('td'); td.innerHTML=html; tr.appendChild(td); });
                const delTd = mk('td');
                delTd.appendChild(mkB('🗑','btn-sm btn-r',()=>{
                    const c=getCustom(); delete c[k]; saveCustom(c); render();
                }));
                tr.appendChild(delTd);
                tbody.appendChild(tr);
            });
            tbl.appendChild(tbody);
            cont.appendChild(tbl);
        }

        // ADD FORM
        const form = mk('div'); form.style.cssText='border-top:1px solid #eee;padding-top:8px';
        const row1 = mk('div'); row1.style.cssText='display:flex;gap:5px;flex-wrap:wrap;align-items:center;margin-bottom:6px';
        const inp = (ph, w) => { const i=mk('input'); i.placeholder=ph; i.style.cssText=`width:${w};padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px`; return i; };

        const idI   = inp(s('interactDataId'), '64px');  idI.type='number'; idI.min='1';
        const subS  = mk('select'); subS.style.cssText='padding:3px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px';
        ['arkadaß','romantik','nefret'].forEach(v=>{ const o=mk('option','',v); o.value=v; subS.appendChild(o); });
        const joyI  = inp('😊 Joy',  '72px');
        const lovI  = inp('❀ Love', '72px');
        const hatI  = inp('😡 Hate', '72px');
        const notI  = inp(s('interactColNote'), '120px');
        const dupW  = mk('span',''); dupW.style.cssText='color:#e67e22;font-size:11px;display:none'; dupW.textContent=s('interactDataDup');

        row1.append(idI, subS, joyI, lovI, hatI, notI);
        const addBtn = mkB(s('interactDataAdd'), 'btn-sm btn-g', () => {
            const id = idI.value.trim(); if (!id) return;
            const c  = getCustom();
            if (c[id]) { dupW.style.display=''; return; }
            dupW.style.display='none';
            c[id] = {
                sub:  subS.value,
                joy:  joyI.value.trim() || null,
                love: lovI.value.trim() || null,
                hate: hatI.value.trim() || null,
                note: notI.value.trim() || null,
            };
            saveCustom(c);
            idI.value=''; joyI.value=''; lovI.value=''; hatI.value=''; notI.value='';
            render();
        });
        const delAll = mkB(s('interactDataReset'), 'btn-sm btn-r', () => {
            if (!confirm(s('interactDataResetQ'))) return;
            saveCustom({}); render();
        });
        delAll.style.marginLeft='6px';

        form.append(row1, dupW, addBtn, delAll);
        cont.appendChild(form);
    };
    render();
});

// INTERACT HELPER
const applyInteractHelper = () => {
    if (!isOnDef(K.interact, true)) return;
    if (!location.href.includes('/Interact/')) return;
    if (location.hash.includes('ppmCall')) return;

    const sel = document.getElementById('ctl00_cphTopColumn_ctl00_ddlInteractionTypes');

    // Karakter ID'sini URL'den al
    const charIdMatch = location.href.match(/\/Interact\/(?:Details\/)?(\d+)/);
    const charId = charIdMatch ? charIdMatch[1] : '0';

    // Mevcut tipi yĂŒkle
    let curType = gmGet(DK.INTERACT_TYPE + charId, 'standart');

    // Seçeneğe ikon/değer yaz
    const decorateOptions = () => {
        if (!sel) return;
        [...sel.options].forEach(opt => {
            if (!opt.value || opt.value === '0') return;
            const id   = parseInt(opt.value);
            const data = getInteractData()[id];
            if (!data) return;
            const parts = [];
            if (data.joy)  parts.push(`😊${data.joy}`);
            if (data.love) parts.push(`❀${data.love}`);
            if (data.hate) parts.push(`😡${data.hate}`);
            const baseName = opt.dataset.ihBase || opt.textContent;
            opt.dataset.ihBase = baseName;
            opt.textContent = parts.length ? `${baseName}  (${parts.join('  ')})` : baseName;
            opt.dataset.ihSub = data.sub;
        });
    };
// Filtreye göre seçenekleri gizle/göster
    const applyFilter = (type) => {
        curType = type;
        gmSet(DK.INTERACT_TYPE + charId, type);

        if (sel) {
            const interactData = getInteractData();
            [...sel.options].forEach(opt => {
                if (!opt.value || opt.value === '0') { opt.style.display = ''; return; }

                if (type === 'standart') {
                    opt.style.display = '';
                    return;
                }

                const id = parseInt(opt.value);
                const data = interactData[id];

                if (!data) {
                    opt.style.display = 'none';
                    return;
                }

                const j = data.joy || '';
                const l = data.love || '';
                const h = data.hate || '';
                const s = data.sub || '';

                let isMatch = false;

                if (s === type) {
                    // Kullanıcının "arkadaß", "romantik", "nefret" olarak eklediklerini korur
                    isMatch = true;
                } else if (type === 'arkadaß') {
                    if (j.includes('+') && !l.includes('+') && !h.includes('+')) isMatch = true;
                } else if (type === 'romantik') {
                    if (l.includes('+') || s === 'cinsel') isMatch = true;
                } else if (type === 'nefret') {
                    if (h.includes('+') || (j.includes('-') && !j.includes('+') && !l.includes('+'))) isMatch = true;
                }

                opt.style.display = isMatch ? '' : 'none';
            });

            // Varsayılan seçenekleri sırayla dene
            const defIds = INTERACT_DEFAULTS[type] || [];
            let selected = false;
            for (const defId of defIds) {
                const defOpt = [...sel.options].find(o => o.value === String(defId) && o.style.display !== 'none');
                if (defOpt) { sel.value = defOpt.value; selected = true; break; }
            }
            if (!selected) {
                const first = [...sel.options].find(o => o.value !== '0' && o.style.display !== 'none');
                if (first) sel.value = first.value;
            }
        }

        // Buton stillerini gĂŒncelle
        document.querySelectorAll('.tvis-ih-typebtn').forEach(b => {
            b.classList.toggle('active', b.dataset.type === type);
        });
    };
    // Kıskançlık dropdown'unu bul ve varsayılanı ayarla
    const jealousSel = document.getElementById('ctl00_cphTopColumn_ctl00_ddlSexCausesJealousy');
    if (jealousSel) jealousSel.value = '0'; // Kıskanmam = default

    // Romantizm seviyesini sayfadan oku
    const getLove = () => {
        const rows = document.querySelectorAll('table.width100 tr');
        for (const row of rows) {
            const label = row.querySelector('td.nowrap');
            if (!label) continue;
            const txt = label.textContent.trim().toLowerCase();
            if (txt.includes('aßk') || txt.includes('love') || txt.includes('amor')) {
                const sk = row.querySelector('.sortkey');
                if (sk) return parseInt(sk.textContent.trim()) || 0;
            }
        }
        return -1;
    };

// UI olußtur
    const buildUI = () => {
        if (document.getElementById('tvis-ih-wrap')) return;
        const wrap = mk('div',''); wrap.id = 'tvis-ih-wrap';

        // ROW 1: Arkadaß / Romantik / Nefret
        const barTop = mk('div','tvis-ih-bar'); barTop.style.marginBottom='3px';
        [
            { key:'arkadaß',  label: s('interactFriend')   },
            { key:'romantik', label: s('interactRomantic') },
            { key:'nefret',   label: s('interactHate')     },
        ].forEach(({ key, label }) => {
            const cls = `tvis-ih-typebtn t-${key}${key === curType ? ' active' : ''}`;
            const btn = mk('button', cls, label);
            btn.dataset.type = key; btn.type = 'button';
            btn.onclick = () => applyFilter(key);
            barTop.appendChild(btn);
        });
        wrap.appendChild(barTop);

        // ROW 2: Standart · 📋 Listele/DĂŒzenle
        const barBot = mk('div','tvis-ih-bar');
        const stdBtn = mk('button', `tvis-ih-typebtn${curType === 'standart' ? ' active' : ''}`, s('interactAll'));
        stdBtn.dataset.type = 'standart'; stdBtn.type = 'button';
        stdBtn.onclick = () => applyFilter('standart');
        barBot.appendChild(stdBtn);
        const guideBtn = mk('button','btn-sm btn-grey','📋 Listele / DĂŒzenle');
        guideBtn.style.marginLeft='auto'; guideBtn.type='button';
        guideBtn.onclick = () => openInteractGuide();
        barBot.appendChild(guideBtn);
        wrap.appendChild(barBot);

        // Kıskançlık uyarısı
        if (jealousSel && jealousSel.value === '1') {
            const loveVal = getLove();
            if (loveVal >= 70) wrap.appendChild(mk('div','tvis-ih-warn', s('interactWarn')));
        }

        // Dropdown mevcut ise onun ALTINA ekle (dropdown ĂŒstte, butonlar altta)
        if (sel) {
            sel.insertAdjacentElement('afterend', wrap);
        } else {
            // Seçenek yoksa (ilgilenme hakkı bitti) sayfada uygun bir yere yerleßtir
            const anchor = document.querySelector(
                '#ctl00_cphTopColumn_ctl00_pnlInteract, .interaction-form, form[action*="Interact"], .box, #ppm-content'
            );
            if (anchor) anchor.insertAdjacentElement('afterbegin', wrap);
            else document.body.appendChild(wrap);
        }
    };

    // Rehber modal (İlgilen Verilerini Listele / DĂŒzenle)
    const openInteractGuide = () => {
        mkModal('İlgilen Verilerini Listele / DĂŒzenle', cont => {
            cont.style.cssText = 'font-size:13px;padding-right:20px';
            cont.parentElement.style.overflowX = 'auto';
            cont.parentElement.style.width = 'auto';
            cont.parentElement.style.maxWidth = 'min(98vw,960px)';

            const pageMap = {};
            if (sel) {
                [...sel.options].forEach(opt => {
                    if (!opt.value || opt.value === '0') return;
                    pageMap[parseInt(opt.value)] = opt.dataset.ihBase || opt.textContent.split('  (')[0];
                });
            }

            const renderGuide = () => {
                cont.innerHTML = '';
                const allData = getInteractData();
                const custom  = gmGet(DK.INTERACT_CUSTOM, {}) || {};
                const allIds  = [...new Set([...Object.keys(allData).map(Number), ...Object.keys(pageMap).map(Number)])].sort((a,b)=>a-b);

                const tbl = mk('table','tvis-ih-guide-tbl'); tbl.style.cssText='width:100%;table-layout:auto';
                const thead = mk('thead'); const hrow = mk('tr');
                ['ID', s('interactName'), s('interactType'), '😊', '❀', '😡', s('interactColNote'), '✓', ''].forEach(h => {
                    thead.appendChild(hrow); hrow.appendChild(mk('th','',h));
                });
                thead.appendChild(hrow); tbl.appendChild(thead);

                const tbody = mk('tbody');
                allIds.forEach(id => {
                    const data     = allData[id] || {};
                    const isCustom = !!custom[id];
                    const onPage   = !!pageMap[id];
                    const name     = pageMap[id] || `ID ${id}`;
                    const tr       = mk('tr');
                    if (!onPage) tr.style.opacity = '0.45';
                    if (isCustom) tr.style.background = '#f0fff4';
                    const subBadge = data.sub
                        ? `<span class="tvis-ih-badge tvis-ih-badge-${data.sub?.[0]}">${data.sub}</span>`
                        : '<span class="tvis-ih-note">—</span>';

                    [
                        `<span style="color:#aaa;font-size:10px">${id}</span>`,
                        `<span>${name}</span>`,
                        subBadge,
                        data.joy  ? `<span class="tvis-ih-joy">${data.joy}</span>`   : '—',
                        data.love ? `<span class="tvis-ih-love">${data.love}</span>` : '—',
                        data.hate ? `<span class="tvis-ih-hate">${data.hate}</span>` : '—',
                        data.note ? `<span class="tvis-ih-note">${data.note}</span>` : '—',
                        onPage ? `<span style="color:#28a745;font-weight:700">✓</span>` : '',
                    ].forEach(html => { const td=mk('td'); td.innerHTML=html; tr.appendChild(td); });

                    // Action cell — edit/delete for custom entries
                    const actTd = mk('td'); actTd.style.whiteSpace='nowrap';
                    if (isCustom) {
                        const eBtn = mkB('✏','btn-sm btn-grey', () => {
                            if (document.getElementById('tvis-ih-editrow')) document.getElementById('tvis-ih-editrow').remove();
                            const editRow = mk('tr'); editRow.id='tvis-ih-editrow'; editRow.style.background='#fffde7';
                            const eTd = mk('td'); eTd.colSpan=9; eTd.style.padding='4px 6px';
                            const ef = mk('div'); ef.style.cssText='display:flex;gap:4px;align-items:center;flex-wrap:wrap';
                            const idL = mk('span','',`ID: ${id}`); idL.style.cssText='font-size:10px;color:#aaa;font-weight:600;min-width:40px';
                            const subS=mk('select'); subS.style.cssText='padding:2px 4px;border:1px solid #ccc;border-radius:3px;font-size:11px';
                            ['arkadaß','romantik','nefret'].forEach(v=>{const o=mk('option','',v);o.value=v;if(data.sub===v)o.selected=true;subS.appendChild(o);});
                            const fi=(ph,val,w)=>{const i=mk('input');i.placeholder=ph;i.value=val||'';i.style.cssText=`width:${w};padding:2px 5px;border:1px solid #ccc;border-radius:3px;font-size:11px`;return i;};
                            const jI=fi('😊',data.joy,'64px'), lI=fi('❀',data.love,'64px'), hI=fi('😡',data.hate,'64px'), nI=fi('Not',data.note,'110px');
                            const sv=mkB('✔','btn-sm btn-g',()=>{
                                const c=gmGet(DK.INTERACT_CUSTOM,{})||{};
                                c[id]={sub:subS.value,joy:jI.value.trim()||null,love:lI.value.trim()||null,hate:hI.value.trim()||null,note:nI.value.trim()||null};
                                gmSet(DK.INTERACT_CUSTOM,c); if(sel)decorateOptions(); renderGuide();
                            });
                            const cn=mkB('✕','btn-sm btn-grey',()=>editRow.remove());
                            ef.append(idL,subS,jI,lI,hI,nI,sv,cn);
                            eTd.appendChild(ef); editRow.appendChild(eTd);
                            tr.insertAdjacentElement('afterend',editRow);
                        });
                        const dBtn=mkB('🗑','btn-sm btn-r',()=>{
                        if(!confirm(s('deleteEntry')))return;
                            const c=gmGet(DK.INTERACT_CUSTOM,{})||{}; delete c[id]; gmSet(DK.INTERACT_CUSTOM,c);
                            if(sel)decorateOptions(); renderGuide();
                        });
                        actTd.append(eBtn, dBtn);
                    }
                    tr.appendChild(actTd);
                    tbody.appendChild(tr);
                });

                // INLINE ADD ROW
                const addRow = mk('tr'); addRow.style.background='#f8f0ff';
                const addTd = mk('td'); addTd.colSpan=9;
                addTd.style.cssText='padding:8px 6px;border-top:2px solid #c9b8f0';

                const wip = mk('div'); wip.style.cssText='font-size:9px;color:#e67e22;margin-bottom:5px';
                wip.textContent=s('interactDataWip');

                const af = mk('div'); af.style.cssText='display:flex;gap:4px;align-items:center;flex-wrap:wrap';
                const fi2=(ph,w,tp='text')=>{const i=mk('input');i.placeholder=ph;i.type=tp;if(tp==='number'){i.min='1';i.max='9999';}i.style.cssText=`width:${w};padding:2px 5px;border:1px solid #c9b8f0;border-radius:3px;font-size:11px`;return i;};
                const nId=fi2('ID','52px','number');
                const nSub=mk('select'); nSub.style.cssText='padding:2px 4px;border:1px solid #c9b8f0;border-radius:3px;font-size:11px';
                ['arkadaß','romantik','nefret'].forEach(v=>{const o=mk('option','',v);o.value=v;nSub.appendChild(o);});
                const nJoy=fi2('😊 Joy','64px'), nLov=fi2('❀ Love','64px'), nHat=fi2('😡 Hate','64px'), nNot=fi2('Koßul/Not','110px');
                const dupW=mk('span',''); dupW.style.cssText='color:#e67e22;font-size:10px;display:none'; dupW.textContent=s('interactDataDup');

                const aBtn=mkB('+ Ekle','btn-sm btn-v',()=>{
                    const idv=nId.value.trim(); if(!idv)return;
                    const c=gmGet(DK.INTERACT_CUSTOM,{})||{};
                    if(c[idv]){dupW.style.display='';return;}
                    dupW.style.display='none';
                    c[idv]={sub:nSub.value,joy:nJoy.value.trim()||null,love:nLov.value.trim()||null,hate:nHat.value.trim()||null,note:nNot.value.trim()||null};
                    gmSet(DK.INTERACT_CUSTOM,c);
                    if(sel)decorateOptions();
                    nId.value=''; nJoy.value=''; nLov.value=''; nHat.value=''; nNot.value='';
                    renderGuide();
                    setTimeout(()=>cont.scrollTo({top:cont.scrollHeight,behavior:'smooth'}),50);
                });
                af.append(nId,nSub,nJoy,nLov,nHat,nNot,aBtn,dupW);
                addTd.append(wip,af); addRow.appendChild(addTd);
                tbody.appendChild(addRow);
                tbl.appendChild(tbody);
                cont.appendChild(tbl);

                const leg=mk('div'); leg.style.cssText='font-size:10px;color:#aaa;margin-top:6px';
                leg.textContent=s('interactDataLegend');
                cont.appendChild(leg);
            };
            renderGuide();
        });
    };

    // Baßlat
    decorateOptions();
    buildUI();
    applyFilter(curType);
};

// CHARACTER NOTE
const applyCharNote = () => {
    if (!isOnDef(K.note, true)) return;
    const m=location.href.match(/\/Character\/(\d+)/); if (!m) return;
    const charBox=document.querySelector('.charPresBox'); if(!charBox||document.getElementById('tvis-notebar')) return;
    const allNotes=gmGet(DK.NOTES,{})||{};
    const bar=mk('div','tvis-notebar'); bar.id='tvis-notebar';
    const ta=mk('textarea'); ta.placeholder=s('notePlh'); ta.value=allNotes[m[1]]||'';
    const btn=mkB('đŸ’Ÿ','btn-g btn-sm',()=>{
        const notes=gmGet(DK.NOTES,{})||{}; notes[m[1]]=ta.value; gmSet(DK.NOTES,notes);
        btn.textContent='✅'; setTimeout(()=>btn.textContent='đŸ’Ÿ',1500);
    });
    bar.append(mk('span','','📝 '),ta,btn);
    charBox.insertAdjacentElement('afterend',bar);
};

// DIARY FILTER — searches all entries across all days
const applyDiaryFilter = () => {
    if (!isOnDef(K.diary, true)||!location.href.includes('/Character/Diary')) return;
    const nav=document.querySelector('[id$="_ddlNavigate"]')?.closest('div.box'); if(!nav||document.getElementById('tvis-df')) return;
    const wrap=mk('div'); wrap.id='tvis-df'; wrap.style.marginBottom='10px';
    wrap.innerHTML=`<h2>${s('dfTitle')}</h2><div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:6px"><input id="tvis-df-i" placeholder="${s('dfPlh')}" style="padding:5px 8px;border:1px solid #ccc;border-radius:4px;font-size:12px;width:220px"><button id="tvis-df-c" class="btn-grey btn-sm">${s('dfClear')}</button><span id="tvis-df-n" style="font-size:11px;color:#666"></span></div>`;
    nav.insertAdjacentElement('beforebegin',wrap);
    const inp=document.getElementById('tvis-df-i'), info=document.getElementById('tvis-df-n');

    const allDays = () => document.querySelectorAll('#ppm-content .diaryExtraspace > li');
    const allEntries = () => document.querySelectorAll('#ppm-content .diaryExtraspace > li > ul > li');

    const filter=()=>{
        const q=inp.value.trim().toLowerCase();
        let cnt=0, total=0;
        allDays().forEach(day=>{
            let vis=false;
            day.querySelectorAll(':scope > ul > li').forEach(e=>{
                total++;
                const ok=!q||e.textContent.toLowerCase().includes(q);
                e.style.display=ok?'':'none';
                if(ok){vis=true;cnt++;}
            });
            day.style.display=(!q||vis)?'':'none';
            // show/hide day header (first non-ul element)
            [...day.children].forEach(ch=>{ if(ch.tagName!=='UL') ch.style.display=(!q||vis)?'':'none'; });
        });
        if(q){
            info.textContent=`${cnt} / ${total} ${s('dfCount')}`;
        } else {
            info.textContent=`${total} ${s('dfTotal')}`;
        }
    };

    document.getElementById('tvis-df-c').onclick=()=>{
        inp.value='';
        allDays().forEach(day=>{
            day.style.display='';
            [...day.children].forEach(ch=>ch.style.display='');
        });
        allEntries().forEach(e=>e.style.display='');
        filter(); // recalculate total
    };
    inp.addEventListener('input',filter);
    inp.addEventListener('keyup',e=>{if(e.key==='Enter')filter();});
    filter(); // show total on load
};
// ICON MENU
const openCustomIconsModal = () => mkModal(s('customIconTitle'), cont => {
    const renderCustom = () => {
        chipArea.innerHTML='';
        getCustomIcons().forEach((ico,i) => {
            const chip=mk('span','tvis-custom-chip',ico);
            const del=mk('button','','×'); del.type='button'; del.title='Sil';
            del.onclick=()=>{ const c=getCustomIcons(); c.splice(i,1); gmSet(DK.CUSTOM_ICONS,c); renderCustom(); };
            chip.appendChild(del); chipArea.appendChild(chip);
        });
    };
    const chipArea = mk('div','tvis-custom-icons'); cont.appendChild(chipArea);
    renderCustom();

    const icoInput=mk('input'); icoInput.placeholder=s('customIconPlh');
    icoInput.style.cssText='width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid #ccc;border-radius:3px;font-size:11px;margin:6px 0 3px';
    cont.appendChild(icoInput);

    const btnRow = mk('div'); btnRow.style.cssText='display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px';
    btnRow.append(
        mkB(s('addIcon'),'btn-sm btn-v',()=>{
            const val=icoInput.value.trim(); if(!val) return;
            const c=getCustomIcons();
            [...val].forEach(ico=>{ if(ico.trim()&&!c.includes(ico)) c.push(ico); });
            gmSet(DK.CUSTOM_ICONS,c); icoInput.value=''; renderCustom();
        }),
        mkB(s('delAllIcons'),'btn-sm btn-r',()=>{
            if(!confirm(s('delAllIconsConfirm'))) return;
            gmSet(DK.CUSTOM_ICONS,[]); renderCustom();
        }),
        mkB(s('exportIcons'),'btn-sm btn-b',()=>{
            const icons=getCustomIcons();
            if(!icons.length){ showToast(s('ciNoIcons')); return; }
            navigator.clipboard?.writeText(icons.join('')).then(()=>showToast(s('ciCopied')));
        })
    );
    cont.appendChild(btnRow);

    const geteEl=mk('a','',s('emojiRef'));
    geteEl.href='https://getemoji.com/'; geteEl.target='_blank';
    geteEl.style.cssText='font-size:10px;color:#17a2b8;display:block;text-decoration:none';
    cont.appendChild(geteEl);
//ShareMD-Emoji deposu
        const archiveEl=mk('a','','đŸ—‚ïž Emoji Archive');
    archiveEl.href='https://share-md.com/view?id=3dc5b188-c715-4829-9270-59be829d2de3';
    archiveEl.target='_blank';
    archiveEl.style.cssText='font-size:10px;color:#17a2b8;display:block;text-decoration:none;margin-top:2px';
    cont.appendChild(archiveEl);
});
// MODÜL: Para Giriß Formatlayıcı
// Etiket: applyMoneyFormatter
// Sayfalara uygula: her sayfada çalıßır, input yoksa sessizce geçer
const applyMoneyFormatter = () => {
    if (!isOnDef(K.moneyFmt, true)) return;
    // Para input'larını tanımlayan seçiciler — genißletilebilir
    const SEL = [
        'input[id*="txtPriceTag"]',
        'input[id*="txtAmount"]',
        'input[id*="txtPrice"]',
        'input[id*="txtMoney"]',
        'input[id*="txtCash"]',
        'input[id*="txtGive"]',
        'input[id*="txtPT"]',
        'input[id*="txtWithdrawAmount"]',
        'input[id*="txtDepositAmount"]',
    ].join(',');

    const fmt = v => v.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
    const raw = v => v.replace(/\./g, '');

    const applyTo = inp => {
        if (inp.dataset.mfmt) return;
        inp.dataset.mfmt = '1';

        // Cursor pozisyonunu koruyarak formatla
        inp.addEventListener('input', () => {
            const start   = inp.selectionStart;
            const oldLen  = inp.value.length;
            const digits  = raw(inp.value).replace(/\D/g, '');
            const newVal  = fmt(digits);
            inp.value     = newVal;
            const shift   = newVal.length - oldLen;
            inp.setSelectionRange(start + shift, start + shift);
        });

        // Form gönderilmeden önce noktaları temizle
        const strip = () => { inp.value = raw(inp.value); };
        inp.closest('form')?.addEventListener('submit', strip);

        // ASP.NET postback butonları için de temizle
        inp.closest('form')?.querySelectorAll(
            'input[type=submit], input[type=image], button[type=submit]'
        ).forEach(btn => btn.addEventListener('click', strip));

        // Mevcut değeri formatla
        const init = raw(inp.value || '').replace(/\D/g, '');
        if (init) inp.value = fmt(init);
    };

    document.querySelectorAll(SEL).forEach(applyTo);

    // ASP.NET UpdatePanel sonrası yeniden tara (Debounce eklendi)
    let moTimer;
    const obs = new MutationObserver(() => {
        clearTimeout(moTimer);
        moTimer = setTimeout(() => document.querySelectorAll(SEL).forEach(applyTo), 300);
    });
    obs.observe(document.body, { childList: true, subtree: true });
};
// MODÜL: Forum Ekleme Butonları (Raf entegreli)
const applyForumList = () => {
    if (!isOnDef(K.pins, true)) return;
    if (!location.href.includes('/Forum/') && !location.href.includes('/Thread/')) return;

    const parseId = url => url.match(/\/Thread\/(\d+)/)?.[1];

    const injectAddButtons = () => {
        document.querySelectorAll('table.data td a[href*="/Thread/"]').forEach(link => {
            if (link.dataset.frlIa) return;
            link.dataset.frlIa='1';
            const id=parseId(link.href); if(!id) return;
            const tracked=()=>isForumInRaf(link.href);
            const btn=mk('button','frl-addbtn'+(tracked()?' on':''),tracked()?'📋':'⊕');
            btn.type='button';
            btn.onclick=()=>{
                if(tracked()){openRaf();return;}
                // Show lane picker popup
                const shelf=getShelf(); const fd=shelf.folders['forum'];
                const pop=mk('div');
                pop.style.cssText='position:fixed;z-index:999999;background:#fff;border:1px solid #c9b8f0;border-radius:6px;padding:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);display:flex;flex-direction:column;gap:3px;font-size:11px';
                const rect=btn.getBoundingClientRect();
                pop.style.top=(rect.bottom+4)+'px'; pop.style.left=rect.left+'px';
                fd.columns.forEach((col,ci)=>{
                    const row=mkB(`${col.name} (${col.items.length})`,'btn-sm btn-grey',()=>{
                        addForumToRaf(id,link.textContent.trim(),link.href,ci);
                        btn.textContent='📋'; btn.className='frl-addbtn on'; pop.remove();
                    });
                    row.style.cssText='width:100%;text-align:left'; pop.appendChild(row);
                });
                document.body.appendChild(pop);
                setTimeout(()=>{const close=e=>{if(!pop.contains(e.target)){pop.remove();document.removeEventListener('click',close);}};document.addEventListener('click',close);},50);
            };
            link.insertAdjacentElement('afterend',btn);
        });
    };

    injectAddButtons();
    // MutationObserver for dynamic content (Debounce eklendi)
    let moTimer;
    const obs=new MutationObserver(() => {
        clearTimeout(moTimer);
        moTimer = setTimeout(injectAddButtons, 300);
    });
    obs.observe(document.body,{childList:true,subtree:true});
    setTimeout(()=>obs.disconnect(),5000);
    return {};
};

// ────────────────────────────────────────────────────────────────────────────

// GENRE POPULARITY POPUP
const applyGenrePopup = () => {
    if (!guard(K.genrePopup)) return;
    if (!location.href.includes('/Character/SongToArtist/')) return;
    const content = document.getElementById('ppm-content') || document.querySelector('.content');
    if (!content) return;
    const h1 = content.querySelector('h1');
    if (!h1) return;
    const link = mk('a', '', s('genrePopupBtn'));
    link.href = '#';
    link.style.cssText = 'display:inline-block;margin:6px 0 10px;font-size:12px;color:#6f42c1;font-weight:bold;text-decoration:none;padding:3px 10px;background:#f5f0ff;border:1px solid #c9b8f0;border-radius:4px';
    link.onclick = e => {
        e.preventDefault();
        mkModal(s('genrePopupTitle'), cont => {
            cont.style.cssText = 'padding:4px 0 0';
            const iframe = document.createElement('iframe');
            iframe.className = 'tvis-gpop-iframe';
            iframe.src = `${PM}/Charts/GenrePopularity`;
            cont.appendChild(iframe);
            // widen box after paint
            requestAnimationFrame(() => {
                const box = cont.closest('.tvis-box');
                if (box) box.style.maxWidth = 'min(95vw, 1100px)';
            });
        });
    };
    h1.insertAdjacentElement('afterend', link);
};

// SERENADE HELPER
const applySerenadeHelper = () => {
    if (!guard(K.serenadeHelper)) return;
    if (!location.href.includes('/Locale/RestaurantOrderSerenade/')) return;

    const RADIO_STATIONS = [
        { id: 3,  prefix: '[ROCK]' }, { id: 4,  prefix: '[MR]'   },
        { id: 5,  prefix: '[HM]'   }, { id: 6,  prefix: '[PUNK]' },
        { id: 7,  prefix: '[ELEC]' }, { id: 8,  prefix: '[POP]'  },
        { id: 9,  prefix: '[HH]'   }, { id: 10, prefix: '[R&B]'  },
        { id: 11, prefix: '[REG]'  }, { id: 12, prefix: '[WM]'   },
        { id: 13, prefix: '[C&W]'  }, { id: 14, prefix: '[JAZZ]' },
        { id: 15, prefix: '[BLU]'  }, { id: 16, prefix: '[CLAS]' },
        { id: 17, prefix: '[LAT]'  }, { id: 18, prefix: '[AM]'   },
        { id: 19, prefix: '[FLA]'  },
    ];

    // Next Wednesday 10:00 CET (= 09:00 UTC)
    const nextWedCET = fromMs => {
        const d = new Date(fromMs);
        const dow = d.getUTCDay(); // 0=Sun, 3=Wed
        let days = (3 - dow + 7) % 7;
        if (days === 0 && d.getUTCHours() >= 9) days = 7;
        const nw = new Date(d);
        nw.setUTCDate(d.getUTCDate() + days);
        nw.setUTCHours(9, 0, 0, 0);
        return nw.getTime();
    };
    const isCacheValid = ts => !!ts && Date.now() < nextWedCET(ts);
    const fmtDt = ms => new Date(ms).toLocaleString(dateLocale, {
        weekday:'short', month:'short', day:'numeric', hour:'2-digit', minute:'2-digit'
    });

    // Inject prefixes into serenade dropdown
    const injectPrefixes = () => {
        const ddl = document.getElementById('ctl00_cphLeftColumn_ctl00_ddlSerenade');
        if (!ddl) return;
        const cache = gmGet(DK.RADIO_CACHE, null);
        if (!cache?.tracks) return;
        [...ddl.options].forEach(opt => {
            if (!opt.value || opt.value === '0') return;
            const prefix = cache.tracks[String(opt.value)];
            if (prefix && !opt.text.startsWith('[')) opt.text = `${prefix} ${opt.text}`;
        });
    };

    // Fetch all 17 stations and build cache — sequential, radar-style
    const doFetch = (onDone) => {
        if (BGTASKS.radio.running) return;
        const total = RADIO_STATIONS.length;

        startBackgroundTask('radio', total, async (task) => {
            try {
                await waitGap(); lastFetch = Date.now();
                const baseResp = await fetch(`${PM}/Charts/Radio/`);
                const baseDoc  = new DOMParser().parseFromString(await baseResp.text(), 'text/html');
                const gf = name => baseDoc.querySelector(`[name="${name}"]`)?.value || '';
                const vs = gf('__VIEWSTATE'), vsg = gf('__VIEWSTATEGENERATOR'), ev = gf('__EVENTVALIDATION');

                const tracks = {};
                for (let i = 0; i < RADIO_STATIONS.length; i++) {
                    if (task.cancelled) break;
                    if (i > 0) await new Promise(r => setTimeout(r, 2100 + Math.random() * 2900));
                    if (task.cancelled) break;
                    task.current = i + 1;
                    saveTaskState('radio');
                    await waitGap(); lastFetch = Date.now();
                    try {
                        const { id, prefix } = RADIO_STATIONS[i];
                        const body = new URLSearchParams({
                            '__EVENTTARGET': 'ctl00$cphLeftColumn$ctl00$ddlRadioStations',
                            '__EVENTARGUMENT': '',
                            '__VIEWSTATE': vs, '__VIEWSTATEGENERATOR': vsg, '__EVENTVALIDATION': ev,
                            'ctl00$cphLeftColumn$ctl00$ddlRadioStations': String(id),
                            'ctl00$cphLeftColumn$ctl00$ddlWeeksIntoThePast': '0',
                            'ctl00$cphLeftColumn$ctl00$ddlCountries': '2',
                        });
                        const resp = await fetch(`${PM}/Charts/Radio/`, {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                            body: body.toString(),
                        });
                        const doc = new DOMParser().parseFromString(await resp.text(), 'text/html');
                        const tid = doc.querySelector('#tablechart tbody tr:first-child td:nth-child(2) a')
                            ?.href?.match(/Track\/(\d+)/)?.[1];
                        if (tid) tracks[String(tid)] = prefix;
                    } catch { /* skip station */ }
                }
                if (!task.cancelled) gmSet(DK.RADIO_CACHE, { ts: Date.now(), tracks });
            } catch { /* base fetch failed */ }

            if (!task.cancelled) {
                injectPrefixes();
                const modal = document.getElementById('tvis-modal');
                if (modal) onDone?.();
            }
        });
    };

    // Open helper modal
    let warnState = 0;
    const openHelper = () => {
        mkModal(s('shTitle'), cont => {
            cont.style.minWidth = '320px';
            warnState = 0;

            const render = () => {
                cont.innerHTML = '';
                const cache  = gmGet(DK.RADIO_CACHE, null);
                const ddl    = document.getElementById('ctl00_cphLeftColumn_ctl00_ddlSerenade');
                const tracks = cache?.tracks || {};

                // Build matched list from serenade dropdown
                const matched = [];
                if (ddl) {
                    [...ddl.options].forEach(opt => {
                        if (!opt.value || opt.value === '0') return;
                        const prefix = tracks[String(opt.value)];
                        if (prefix) {
                            const txt = opt.text.replace(/^\[.*?\]\s*/, '');
                            matched.push({ prefix, txt });
                        }
                    });
                } else {
                    // Fallback: show all cached prefixes without labels
                    RADIO_STATIONS.forEach(({ prefix }) => {
                        const tid = Object.keys(tracks).find(k => tracks[k] === prefix);
                        if (tid) matched.push({ prefix, txt: tid });
                    });
                }

                // List
                const list = mk('div', 'tvis-sh-list');
                if (!matched.length) {
                    list.appendChild(mk('div', 'tvis-sh-empty',
                        Object.keys(tracks).length ? s('shNoneMatched') : s('shNoCache')));
                } else {
                    matched.forEach(({ prefix, txt }) => {
                        const row = mk('div', 'tvis-sh-row');
                        row.append(mk('span', 'tvis-sh-prefix', prefix), mk('span', 'tvis-sh-track', txt));
                        list.appendChild(row);
                    });
                }
                cont.appendChild(list);

                // Footer
                const footer = mk('div', 'tvis-sh-footer');
                if (cache?.ts) {
                    footer.appendChild(mk('div', '', `${s('shLastUpd')} ${fmtDt(cache.ts)}`));
                    footer.appendChild(mk('div', '', `${s('shNextUpd')} ${fmtDt(nextWedCET(cache.ts))}`));
                }

                const warnEl = mk('div', 'tvis-sh-warn');
                footer.append(warnEl);

                // Buttons
                const btnRow = mk('div'); btnRow.style.cssText = 'display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:2px';
                const updBtn = mkB(s('shUpdateBtn'), 'btn-sm btn-v', async () => {
                    if (BGTASKS.radio.running) return;
                    if (isCacheValid(cache?.ts)) {
                        if (warnState === 0) {
                            warnState = 1;
                            warnEl.textContent = s('shWarn1').replace('{date}', fmtDt(cache.ts));
                            return;
                        }
                        if (warnState === 1) {
                            warnState = 2;
                            warnEl.textContent = s('shWarn2');
                            return;
                        }
                    }
                    warnEl.textContent = '';
                    doFetch(render);
                });

                const radioLink = mk('a', '', s('shRadioLink'));
                radioLink.href = `${PM}/Charts/Radio/`;
                radioLink.style.cssText = 'font-size:11px;color:#6f42c1;text-decoration:none';
                radioLink.target = '_blank';

                btnRow.append(updBtn, radioLink);
                footer.appendChild(btnRow);
                cont.appendChild(footer);
            };

            render();
        });
    };

    // Insert button before the .box
    const box = document.querySelector('.box');
    if (box) {
        const btn = mkB(s('shBtn'), 'btn-sm btn-v', openHelper);
        btn.style.cssText = 'display:block;margin:6px 0 8px';
        box.insertAdjacentElement('beforebegin', btn);
    }

    injectPrefixes();
};

// //
// SPEED CALLING
const SC_DEFAULT_CFG = {
    interval: 3,
    phoneIds: {
        arkadaß:  [24, 171],
        romantik: [73, 74],
    }
};

const getScCfg   = ()      => Object.assign({}, SC_DEFAULT_CFG, gmGet(DK.SPEEDCALL_CFG, {}));
const getScQueue = ()      => gmGet(DK.SPEEDCALL_Q, []) || [];
const setScQueue = arr     => gmSet(DK.SPEEDCALL_Q, arr);
const getScState = ()      => gmGet(DK.SPEEDCALL_STATE, {idx:0, running:false, failStreak:0}) || {idx:0,running:false,failStreak:0};
const setScState = st      => gmSet(DK.SPEEDCALL_STATE, st);

// Build queue from saved interact types (arkadaß + romantik)
const buildScQueue = (includeTypes) => {
    const queue = [];
    const seen  = new Set();
    // Scan all interact type keys stored in GM
    // We iterate known radar chars + try to find any saved interact type
    // Build from: all tracked chars + any charId key in GM storage
    const allTracked = getAllTracked().map(e => String(e.charId));
    // Also read interact custom list if present
    const custom = gmGet(DK.INTERACT_CUSTOM, {}) || {};
    // Collect unique charIds from radar
    const candidates = [...new Set(allTracked)];
    candidates.forEach(cid => {
        const t = gmGet(DK.INTERACT_TYPE + cid, null);
        if (t && includeTypes.includes(t) && !seen.has(cid)) {
            seen.add(cid);
            // Try to get name from char cache
            const cache = gmGet(DK.CACHE, {}) || {};
            const name = cache[cid]?.name || cid;
            queue.push({ charId: cid, type: t, name });
        }
    });
    return queue;
};

// Modal: configure & start
const openSpeedCallModal = () => {
    mkModal(s('scTitle'), (cont, close) => {
        const cfg   = getScCfg();
        const queue = getScQueue();
        const state = getScState();

        // WHO TO CALL
        cont.appendChild(mk('div','tvis-sec',s('scWho')));
        const chkFriend = Object.assign(mk('input'),{type:'checkbox',checked:true,id:'sc-chk-friend'});
        const chkRom    = Object.assign(mk('input'),{type:'checkbox',checked:true,id:'sc-chk-rom'});
        const lF = mk('label','tvis-chk'); lF.append(chkFriend, mk('span','',s('scWhoFriend'))); cont.appendChild(lF);
        const lR = mk('label','tvis-chk'); lR.append(chkRom,    mk('span','',s('scWhoRom')));    cont.appendChild(lR);

        // Preview list
        const listWrap = mk('div','tvis-sc-charlist');
        const refreshList = () => {
            listWrap.innerHTML = '';
            const inc = [];
            if (chkFriend.checked) inc.push('arkadaß');
            if (chkRom.checked)    inc.push('romantik');
            const chars = buildScQueue(inc);
            if (!chars.length) {
                listWrap.appendChild(mk('div','',s('scNoChars'))).style.cssText='font-size:11px;color:#999;padding:8px';
                return;
            }
            chars.forEach(c => {
                const row = mk('div','tvis-sc-charrow');
                const chk = Object.assign(mk('input'),{type:'checkbox',checked:true});
                chk.dataset.cid  = c.charId;
                chk.dataset.type = c.type;
                chk.dataset.name = c.name;
                const badge = mk('span','tvis-sc-badge '+(c.type==='romantik'?'r':'a'), c.type==='romantik'?'❀':'đŸ‘„');
                const nm    = mk('span','',c.name);
                row.append(chk, badge, nm);
                listWrap.appendChild(row);
            });
        };
        chkFriend.onchange = refreshList;
        chkRom.onchange    = refreshList;
        refreshList();
        cont.appendChild(listWrap);

        cont.appendChild(mk('hr','tvis-hr'));

        // INTERVAL
        cont.appendChild(mk('div','tvis-sec',s('scInterval')));
        const intRow = mk('div'); intRow.style.cssText='display:flex;align-items:center;gap:8px;margin-bottom:4px';
        const slider = Object.assign(mk('input'),{type:'range',min:1,max:10,value:cfg.interval});
        slider.style.cssText='flex:1';
        const intLbl = mk('span','',cfg.interval+'s');
        intLbl.style.cssText='min-width:24px;font-weight:700;color:#6f42c1';
        slider.oninput = () => { intLbl.textContent = slider.value+'s'; };
        intRow.append(slider, intLbl);
        cont.appendChild(intRow);
        cont.appendChild(mk('div','',s('scIntervalNote'))).style.cssText='font-size:10px;color:#aaa;margin-bottom:8px';

        cont.appendChild(mk('hr','tvis-hr'));

        // PHONE IDs
        cont.appendChild(mk('div','tvis-sec',s('scPhoneIds')));
        cont.appendChild(mk('div','',s('scPhoneNote'))).style.cssText='font-size:10px;color:#aaa;margin-bottom:6px';

        const makePhoneRow = (labelKey, typeKey) => {
            const row = mk('div','tvis-sc-phonerow');
            row.appendChild(mk('span','',s(labelKey))).style.cssText='min-width:110px;flex-shrink:0;font-size:11px';
            const inp = mk('input','tvis-sc-phoneinp');
            inp.value = (cfg.phoneIds[typeKey] || []).join(', ');
            inp.dataset.sctype = typeKey;
            row.appendChild(inp);
            cont.appendChild(row);
            return inp;
        };
        const inpFriend = makePhoneRow('scFriendIds','arkadaß');
        const inpRom    = makePhoneRow('scRomIds','romantik');

        cont.appendChild(mk('hr','tvis-hr'));

        // BUTTONS
        const btnRow = mk('div'); btnRow.style.cssText='display:flex;gap:6px;flex-wrap:wrap;margin-top:4px';

        const doStart = (resume) => {
            // Save config
            const newCfg = {
                interval: parseInt(slider.value)||3,
                phoneIds: {
                    arkadaß:  inpFriend.value.split(',').map(x=>parseInt(x.trim())).filter(n=>!isNaN(n)),
                    romantik: inpRom.value.split(',').map(x=>parseInt(x.trim())).filter(n=>!isNaN(n)),
                }
            };
            gmSet(DK.SPEEDCALL_CFG, newCfg);

            if (!resume) {
                // Build queue from checked chars
                const checked = [...listWrap.querySelectorAll('input[type=checkbox]:checked')];
                if (!checked.length) return;
                const q = checked.map(c=>({charId:c.dataset.cid, type:c.dataset.type, name:c.dataset.name}));
                setScQueue(q);
                setScState({idx:0, running:true, failStreak:0});
            } else {
                const st = getScState();
                setScState({...st, running:true, failStreak:0});
            }
            close();
            const q = getScQueue();
            const st = getScState();
            const first = q[st.idx];
            if (!first) return;
            window.open(`${PM}/Interact/Phone/${first.charId}#ppmCall`, '_blank');
        };

        btnRow.appendChild(mkB(s('scStart'),'btn-g',()=>doStart(false)));
        if (queue.length && state.idx > 0 && state.idx < queue.length) {
            const resumeBtn = mkB(`${s('scResume')} (${state.idx}/${queue.length})`,'btn-v',()=>doStart(true));
            btnRow.appendChild(resumeBtn);
        }
        btnRow.appendChild(mkB(s('scReset'),'btn-grey btn-sm',()=>{
            if (!confirm(s('scReset')+'?')) return;
            gmDel(DK.SPEEDCALL_Q); gmDel(DK.SPEEDCALL_STATE);
            close();
        }));
        cont.appendChild(btnRow);
    });
};

// Injected into every Interact/Phone page when #ppmCall is in URL
const applySpeedCall = () => {
    if (!location.href.includes('/Interact/Phone/') && !location.href.includes('/Interact/Details/')) return;
    if (!location.hash.includes('ppmCall')) return;

    const state = getScState();
    if (!state.running) return;

    const queue = getScQueue();
    const cfg   = getScCfg();
    const idx   = state.idx;
    const total = queue.length;
    const current = queue[idx];
    if (!current) {
        // Done
        setScState({...state, running:false});
        injectScBar(null, idx, total, cfg, false, true);
        return;
    }

    // BAR
    let timerHandle   = null;
    let paused        = false;
    let timerLeft     = 0;

    const bar = mk('div','tvis-sc-bar');
    bar.id = 'tvis-sc-bar';

    const statEl  = mk('span','tvis-sc-stat');
    const timerEl = mk('span','tvis-sc-timer','');
    const stopBtn = mkB(s('scBarStop'),'tvis-sc-btn stop',()=>{
        paused = true;
        clearTimeout(timerHandle);
        setScState({...getScState(), running:false});
        stopBtn.style.display='none';
        resumeBtn.style.display='';
        warnEl.textContent='';
        statEl.innerHTML=`<span style="color:#ffd700">⏞ Duraklatıldı</span>`;
        timerEl.textContent='';
    });
    const resumeBtn = mkB(s('scBarResume'),'tvis-sc-btn resume',()=>{
        setScState({...getScState(), running:true, failStreak:0});
        resumeBtn.style.display='none';
        stopBtn.style.display='';
        warnEl.textContent='';
        proceedToNext();
    });
    resumeBtn.style.display='none';
    const warnEl  = mk('span','tvis-sc-warn','');
    warnEl.style.display='none';

    bar.append(statEl, timerEl, warnEl, stopBtn, resumeBtn);
    document.body.prepend(bar);
    // Push page content down
    document.body.style.paddingTop = '34px';

    const updateStat = (name, nextName) => {
        statEl.innerHTML = `📞 <b>${idx+1}${s('scBarOf')}${total}</b> &nbsp;`
            + `<span class="tvis-sc-name">${name||current.charId}</span>`
            + (nextName ? ` &nbsp;â€ș&nbsp; ${s('scBarNext')} <span class="tvis-sc-name">${nextName}</span>` : '');
    };

    const showWarn = (msg) => {
        warnEl.textContent = msg;
        warnEl.style.display='';
    };
    const hideWarn = () => { warnEl.style.display='none'; warnEl.textContent=''; };

    const playAlarm = () => {
        try {
            const ctx = new (window.AudioContext||window.webkitAudioContext)();
            [0,300,600].forEach(delay => {
                const osc = ctx.createOscillator();
                const gain = ctx.createGain();
                osc.connect(gain); gain.connect(ctx.destination);
                osc.frequency.value = 880;
                gain.gain.setValueAtTime(0.4, ctx.currentTime + delay/1000);
                gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + delay/1000 + 0.4);
                osc.start(ctx.currentTime + delay/1000);
                osc.stop(ctx.currentTime + delay/1000 + 0.4);
            });
        } catch(e) {}
    };

    const runCountdown = (secs, onDone) => {
        timerLeft = secs;
        timerEl.textContent = timerLeft + 's';
        const tick = () => {
            timerLeft--;
            timerEl.textContent = timerLeft + 's';
            if (timerLeft <= 0) { timerEl.textContent=''; onDone(); }
            else timerHandle = setTimeout(tick, 1000);
        };
        timerHandle = setTimeout(tick, 1000);
    };

    const proceedToNext = () => {
        const nextIdx = getScState().idx + 1;
        if (nextIdx >= total) {
            setScState({...getScState(), running:false, idx:nextIdx});
            statEl.innerHTML = `✅ <b>${s('scBarDone')}</b>`;
            timerEl.textContent='';
            stopBtn.style.display='none';
            return;
        }
        setScState({...getScState(), idx:nextIdx});
        const next = queue[nextIdx];
        const interval = cfg.interval + Math.random()*2;
        const nextAfter = queue[nextIdx+1];
        updateStat(next.name, nextAfter?.name);
        runCountdown(Math.round(interval), () => {
            location.assign(`${PM}/Interact/Phone/${next.charId}#ppmCall`);
        });
    };

    const doFailStreak = () => {
        const st = getScState();
        const streak = (st.failStreak||0) + 1;
        setScState({...st, failStreak:streak});
        if (streak >= 2) {
            clearTimeout(timerHandle);
            paused = true;
            playAlarm();
            stopBtn.style.display='none';
            resumeBtn.style.display='';
            showWarn(`${s('scBarFail')} — ${s('scBarFailNote')}`);
            timerEl.textContent='';
        } else {
            proceedToNext();
        }
    };

    // ATTEMPT CALL
    const sel = document.querySelector('#ctl00_cphTopColumn_ctl00_ddlInteractionTypes')
             || document.querySelector('select[id*="ddlInteraction"]');

    const phoneIds = (cfg.phoneIds[current.type] || []).map(String);
    const btn      = document.querySelector('#ctl00_cphTopColumn_ctl00_btnInteract')
                  || document.querySelector('input[id*="btnInteract"],button[id*="btnInteract"]');

    const next1 = queue[idx+1];
    updateStat(current.name, next1?.name);

    let called = false;
    if (sel && phoneIds.length) {
        for (const pid of phoneIds) {
            const opt = [...sel.options].find(o=>o.value===pid&&o.style.display!=='none');
            if (opt) {
                sel.value = pid;
                sel.dispatchEvent(new Event('change',{bubbles:true}));
                if (btn) {
                    setTimeout(()=>{
                        btn.click();
                        called = true;
                        setScState({...getScState(), failStreak:0});
                        const interval = cfg.interval + Math.random()*2;
                        runCountdown(Math.round(interval), proceedToNext);
                    }, 400);
                }
                break;
            }
        }
    }

    if (!called) {
        if (!sel) {
            // No interact dropdown found — might be wrong page
            showWarn(s('scBarNoId'));
        } else if (!phoneIds.length) {
            showWarn(s('scBarNoId'));
        } else {
            showWarn(s('scBarNoId'));
        }
        setTimeout(() => doFailStreak(), 600);
    }
};

// SETTINGS MODAL (used by bar link and PopControl button)
function _openSocialModal(pan) {
    const existing = document.getElementById('tvis-set-ov');
    if (existing) { existing.remove(); return; }
    const ov = document.createElement('div'); ov.id = 'tvis-set-ov';
    ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:99997;display:flex;align-items:center;justify-content:center;padding:20px;box-sizing:border-box';
    const origStyle = pan.getAttribute('data-orig-style') || '';
    pan.style.cssText = 'display:block;position:relative;top:auto;right:auto;left:auto;max-height:85vh;overflow-y:auto;border-radius:10px;min-width:260px;max-width:500px;width:92%;';
    ov.appendChild(pan);
    ov.onclick = function(e) {
        if (e.target === ov) {
            document.body.appendChild(pan);
            pan.style.display = 'none';
            ov.remove();
        }
    };
    document.body.appendChild(ov);
}

function _openSocialSettingsModal() {
    const pan = document.getElementById('tvis-hpanel');
    if (!pan) return;
    const ov = document.getElementById('tvis-set-ov');
    if (ov) { document.body.appendChild(pan); pan.style.display = 'none'; ov.remove(); return; }
    _openSocialModal(pan);
}

// EN strings for PopControl export
// EN strings for PopControl — auto-derived from STR
window.__ppcStrSocial = Object.fromEntries(
    Object.entries(STR).map(([k, v]) => [k, v['EN'] ?? v['TR'] ?? k])
);

// ─── POPCONTROL BAĞLANTISI ────────────────────────────────────────────────────
function _connectSocial(bar, pan) {
    if (window.PPC_Social_Done) return;
    const pc = (typeof unsafeWindow !== 'undefined' && unsafeWindow.PopControl) || window.PopControl;
    if (!pc?.register) return;
    try {
        pc.register({
            id: 'social', icon: '🌐', label: 'Social',
            strings: window.__ppcStrSocial || {},
            buttons: [
                { icon: '➕', label: ({ TR: 'Ekle', EN: 'Add', PT: 'Adicionar' }[LANG] || 'Ekle'), onClick: () => quickRaf() },
                { icon: '📌', label: s('pinBtn').replace('📌 ',''), onClick: openRaf },
                { icon: '📋', label: s('menuClip').replace('📋 ',''), onClick: openClip },
                { icon: '📍', label: s('menuRadar').replace('📍 ','').slice(0,5), onClick: openTrackModal },
                { icon: '📞', label: s('scBtn').replace('📞 ','').slice(0,3), onClick: openSpeedCallModal },
                { icon: '🌐', label: ({ TR: 'Social', EN: 'Social', PT: 'Social' }[LANG] || 'Social Ayarlar'), onClick: () => _openSocialSettingsModal() },
            ],
            onUndo: () => { window.PPC_Social_Done = false; document.getElementById('tvis-set-ov')?.remove(); document.body.appendChild(pan); pan.style.display='none'; bar.style.display=''; },
        });
        bar.style.display = 'none';
        window.PPC_Social_Done = true;
        _injectSocialMenuItems();
        console.log('[Social] PopControl bağlantısı baßarılı');
    } catch(e) {
        console.error('[Social] PopControl bağlantı hatası:', e);
    }
}

// MENU
const injectMenu = () => {
    if (document.getElementById('tvis-bar')) return;
    const bar = mk('div','tvis-bar'); bar.id='tvis-bar';
    const pan = mk('div','tvis-hpanel'); pan.id='tvis-hpanel';

    const posBar = () => {
        let offset = 4;
        const helperBar = document.getElementById('tvip-bar');
        if (helperBar) offset += helperBar.offsetWidth + 4;
        bar.style.right = offset + 'px';
        pan.style.right = offset + 'px';
    };

    const lnk = (txt,fn)=>{ const a=mk('a','',txt); a.href='#'; a.onclick=e=>{e.preventDefault();fn();}; return a; };

    if (isOnDef(K.pins, true)) {
        const pinW=mk('span'); pinW.style.cssText='display:inline-flex;align-items:center;gap:3px';
        const addBtn=mk('button','','+ ');
        addBtn.style.cssText='background:#6f42c1;color:#fff;border:none;border-radius:3px;cursor:pointer;font-size:10px;padding:1px 5px;font-weight:bold;line-height:1.4';
        addBtn.onclick=e=>{e.preventDefault();quickRaf();};
        pinW.append(addBtn, lnk(s('pinBtn'),openRaf));
        bar.appendChild(pinW);
    }
    bar.appendChild(lnk(s('menuClip'), openClip));
    if (isOnDef(K.tracking, true)) bar.appendChild(lnk(s('menuRadar'), openTrackModal));
    if (isOnDef(K.speedcall, true)) bar.appendChild(lnk(s('scBtn'), openSpeedCallModal));
    bar.appendChild(lnk(s('menuTitle'), _openSocialSettingsModal));

    const checks = {};
    const mkChk  = (ck,lbl,defVal=true) => { const l=mk('label','tvis-chk'); const c=Object.assign(mk('input'),{type:'checkbox',checked:isOnDef(ck,defVal)}); checks[ck]=c; l.append(c,mk('span','',lbl)); pan.appendChild(l); };
    const mkHr   = () => pan.appendChild(mk('hr','tvis-hr'));
    const mkSec  = txt => pan.appendChild(mk('div','tvis-sec',txt));

    mkHr();

    mkSec('SOSYAL');
    mkChk(K.pins,      s('pins'),           true);
    mkChk(K.charPopup, s('charCard'),       true);
    mkChk(K.tracking,  s('radar'),          true);
    mkChk(K.interact,  s('interactfilter'), true);
    mkChk(K.ia,        s('quickLinks'),     true);
    mkChk(K.note,      s('note'),           true);
    mkChk(K.speedcall, s('speedcall'),      true);
    mkHr();
    mkSec('ARAÇLAR');
    mkChk(K.diary,          s('diary'),          true);
    mkChk(K.moneyFmt,       s('moneyFmt'),       true);
    mkChk(K.genrePopup,     s('genrePopup'),     true);
    mkChk(K.serenadeHelper, s('serenadeHelper'), true);
    mkHr();

    mkSec(s('langLabel'));
    const langRow=mk('div','tvis-lang-row');
    [['TR','đŸ‡čđŸ‡· TĂŒrkçe'],['EN','🇬🇧 English'],['PT','đŸ‡§đŸ‡· PortuguĂȘs']].forEach(([code,label])=>{
        const b=mk('button','tvis-lang-btn'+(LANG===code?' active':''),label);
        b.onclick=()=>{CK.set('ppm_lang',code);location.reload();};
        langRow.appendChild(b);
    });
    pan.appendChild(langRow);
    
    // Ecosystem links
    const ecosystemRow = mk('div');
    ecosystemRow.style.cssText = 'background:#f0f8ff;border-radius:8px;padding:16px;margin-bottom:12px';
    ecosystemRow.innerHTML = `
        <div style="display:flex;gap:20px;justify-content:center;align-items:center">
            <div style="display:flex;align-items:center;gap:10px">
                <span style="font-size:16px">đŸ‡čđŸ‡·</span>
                <a href="https://rentry.org/PopControlEkosistemi" target="_blank" style="color:#1a5276;font-weight:500;text-decoration:none;font-size:13px">Beni Oku</a>
            </div>
            <div style="display:flex;align-items:center;gap:10px">
                <span style="font-size:16px">🇬🇧</span>
                <a href="https://rentry.org/PopControlEcosystem" target="_blank" style="color:#1a5276;font-weight:500;text-decoration:none;font-size:13px">Read Me</a>
            </div>
            <div style="display:flex;align-items:center;gap:10px">
                <span style="font-size:16px">đŸ‡§đŸ‡·</span>
                <a href="https://rentry.org/EcossistemaPopControl" target="_blank" style="color:#1a5276;font-weight:500;text-decoration:none;font-size:13px">Leia-me</a>
            </div>
        </div>
    `;
    pan.appendChild(ecosystemRow);
    
    mkHr();

    const row1=mk('div'); row1.style.cssText='display:flex;flex-wrap:wrap;gap:4px;margin-top:4px';
    const row2=mk('div'); row2.style.cssText='display:flex;flex-wrap:wrap;gap:4px;margin-top:4px';
    const readMeBtn = mk('a','btn-b btn-sm','📖 Beni Oku');
    readMeBtn.href='https://rentry.org/SocialOku'; readMeBtn.target='_blank';
    readMeBtn.style.textDecoration='none';
    row1.append(
        mkB(s('save'),'btn-g',()=>{ Object.entries(checks).forEach(([k,c])=>CK.set(k,c.checked?'1':'0')); location.reload(); }),
        readMeBtn,
        mkB(s('backup'),'btn-b btn-sm',()=>dbExport()),
        mkB(s('restore'),'btn-grey btn-sm',()=>dbImport())
    );
    row2.append(
        mkB(s('iaEdit'),'btn-sm btn-v',()=>openIAEdit()),
        mkB(s('iaExcl'),'btn-sm btn-grey',()=>openIAExclModal()),
        mkB(s('customIconTitle'),'btn-sm btn-grey',()=>openCustomIconsModal())
    );
    pan.append(row1,row2);
    mkHr();

    document.body.append(bar, pan);

    posBar();
    const _posObs = new MutationObserver(posBar);
    _posObs.observe(document.body, { childList: true });
    setTimeout(() => _posObs.disconnect(), 3000);

    document.addEventListener('click', e => {
        if (!bar.contains(e.target) && !pan.contains(e.target)) {
            if (!document.getElementById('tvis-set-ov')) pan.style.display = 'none';
        }
    });

    // PopControl bağlantısı
    const _tryConnect = () => _connectSocial(bar, pan);
    document.addEventListener('PopControlReady', () => setTimeout(_tryConnect, 50), { once: true });
    (function _checkPC(n) {
        if (window.PPC_Social_Done) return;
        const pc = (typeof unsafeWindow !== 'undefined' && unsafeWindow.PopControl) || window.PopControl;
        if (pc?.register) _tryConnect();
        else if (n < 20) setTimeout(() => _checkPC(n + 1), 150);
    })(0);
};

// INIT
applyCharPopup();
applyForumList();
applyMoneyFormatter();
applyCharNote();
applyDiaryFilter();
applyInlineActions();
applyInteractHelper();
applyGenrePopup();
applySerenadeHelper();
applySpeedCall();
injectMenu();

// ── PUBLIC API ──────────────────────────────────────────────────────────────
window.__social_api = {
    openShelf:    () => typeof openRaf                    === 'function' && openRaf(),
    openClip:     () => typeof openClip                   === 'function' && openClip(),
    openRadar:    () => typeof openTrackModal             === 'function' && openTrackModal(),
    openSC:       () => typeof openSpeedCallModal         === 'function' && openSpeedCallModal(),
    openSettings: () => typeof _openSocialSettingsModal   === 'function' && _openSocialSettingsModal(),
    quickAdd:     () => typeof quickRaf                   === 'function' && quickRaf(),
};

// ── TOP VIP MENÜSÜ ENJEKSİYONU ──────────────────────────────────────────────
function _injectSocialMenuItems() {
    if (!location.href.includes('/World/Popmundo.aspx/Character')) return;
    const _D2 = (tr, en, pt) => ({ TR: tr, EN: en, PT: pt }[LANG] || tr);
    const socialButtons = [
        { id: 'mnu-social-add',      label: _D2('➕ Ekle',               '➕ Add',              '➕ Adicionar'),      fn: () => window.__social_api?.quickAdd()     },
        { id: 'mnu-social-shelf',    label: _D2('📌 Rafım',              '📌 Shelf',            '📌 Prateleira'),     fn: () => window.__social_api?.openShelf()    },
        { id: 'mnu-social-clip',     label: _D2('📋 Pano',               '📋 Clipboard',        '📋 Painel'),         fn: () => window.__social_api?.openClip()     },
        { id: 'mnu-social-radar',    label: _D2('📍 Radar',              '📍 Radar',            '📍 Radar'),          fn: () => window.__social_api?.openRadar()    },
        { id: 'mnu-social-sc',       label: _D2('📞 Speed Calling',      '📞 Speed Calling',    '📞 Speed Calling'),  fn: () => window.__social_api?.openSC()       },
        { id: 'mnu-social-settings', label: _D2('🌐 Social Ayarlar',    '🌐 Social Settings',  '🌐 Config Social'),  fn: () => window.__social_api?.openSettings() },
    ];

const _pc = (typeof unsafeWindow !== 'undefined' && unsafeWindow.PopControl) || window.PopControl;
if (_pc?.MenuManager) {
    _pc.MenuManager.registerMenu({id: 'top-vip', title: '⭐ TOP VIP ⭐', position: 'above-career', items: socialButtons, collapsible: true });
        return;
    }

    // ── Standalone fallback (PopControl yoksa) ──────────────────────────
    if (document.getElementById('mnu-social-shelf')) return;
    let ul = document.querySelector('#top-vip-menu ul');
    if (!ul) {
        const ref = [...document.querySelectorAll('.menu h3')]
            .find(h => /Kariyer|Career|Carreira/.test(h.textContent))?.closest('.menu');
        if (!ref) return;
        const isCol = localStorage.getItem('top-vip-collapsed') === 'true';
        const h3 = Object.assign(document.createElement('h3'), { textContent: '⭐ TOP VIP ⭐' });
        h3.style.cssText = 'background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;text-align:center;padding:8px;margin:0;border-radius:6px 6px 0 0;cursor:pointer;box-shadow:0 2px 8px rgba(102,126,234,.3);user-select:none;';
        ul = document.createElement('ul');
        ul.style.cssText = `margin:0;padding:8px 0;background:#f8f9fa;border:1px solid #e9ecef;border-top:none;border-radius:0 0 6px 6px;${isCol ? 'display:none;' : ''}`;
        h3.onclick = () => { const c = ul.style.display === 'none'; ul.style.display = c ? '' : 'none'; localStorage.setItem('top-vip-collapsed', !c); };
        const menu = Object.assign(document.createElement('div'), { id: 'top-vip-menu', className: 'menu' });
        menu.append(h3, ul); ref.before(menu);
        menu.after(Object.assign(document.createElement('div'), { style: 'height:12px' }));
    }
    socialButtons.forEach(btn => {
        if (document.getElementById(btn.id)) return;
        const a = Object.assign(document.createElement('a'), { href: '#', textContent: btn.label });
        a.style.cssText = 'color:#667eea;font-weight:600;text-decoration:none;display:block;padding:4px 12px;border-radius:4px;transition:all .2s;';
        a.onmouseover = () => { a.style.background = '#667eea'; a.style.color = '#fff'; };
        a.onmouseout  = () => { a.style.background = '';        a.style.color = '#667eea'; };
        a.onclick = e => { e.preventDefault(); btn.fn(); };
        const li = Object.assign(document.createElement('li'), { id: btn.id }); li.style.margin = '2px 0';
        li.appendChild(a); ul.appendChild(li);
    });
}
_injectSocialMenuItems();


} catch(e) { if (!e.message || !e.message.includes('__ppsm_device_block__')) throw e; }
})();