{{-- ═══════════════════════════════════════════════════════════════
     Global Mesajlaşma — sağ-alt köşede launcher + premium panel.
     • Kapalıyken tek zarif buton (içeriği KAPATMAZ, hiçbir alanı örtmez).
     • Açılınca liste ↔ sohbet arasında kayan tek panel.
     • Birleşik arama (hem sohbetler hem kişiler tek kutudan).
     • Küçült = panele kapanır, launcher kalır (yok olmaz).
     • Dosya/resim gönderimi, sürükle-bırak.
     • Mevcut "Geçmiş & Erişim" (recent-sidebar) butonuna DOKUNULMAZ.
     • Canlılık: hafif polling (soket altyapısı yok).
════════════════════════════════════════════════════════════════ --}}

{{-- Kritik stil: ana stil bloğu markup'tan SONRA geldiği için, ilk paint'te panel
     in-flow görünüp "açılıp hemen kapanıyormuş" gibi flash yapıyordu. Bunu markup'tan
     ÖNCE gizleyerek engelliyoruz (.open kuralı daha özgül olduğu için açılış bozulmaz). --}}
<style>#chatWidget .cw-panel{opacity:0;pointer-events:none;position:fixed;right:26px;bottom:26px;}</style>
<div id="chatWidget">
    {{-- Launcher --}}
    <button class="cw-launcher" id="cwLauncher" aria-label="Mesajlar">
        <span class="cw-launcher-ic cw-ic-open"><i class="fas fa-comment"></i></span>
        <span class="cw-launcher-ic cw-ic-close"><i class="fas fa-chevron-down"></i></span>
        <span class="cw-launcher-badge" id="cwLauncherBadge" hidden>0</span>
    </button>

    {{-- Panel --}}
    <div class="cw-panel" id="cwPanel">

        {{-- ── LİSTE GÖRÜNÜMÜ ── --}}
        <section class="cw-view cw-view-list">
            <header class="cw-head">
                <div class="cw-head-txt">
                    <div class="cw-head-title">Mesajlar</div>
                    <div class="cw-head-sub" id="cwHeadSub">Tüm sohbetleriniz</div>
                </div>
                <div class="cw-head-actions">
                    <button class="cw-head-btn" id="cwMinBtn" title="Küçült"><i class="fas fa-minus"></i></button>
                </div>
            </header>
            <div class="cw-searchbar">
                <i class="fas fa-magnifying-glass"></i>
                <input type="text" id="cwSearch" placeholder="Sohbet veya kişi ara…" autocomplete="off">
                <button class="cw-search-clear" id="cwSearchClear" hidden><i class="fas fa-xmark"></i></button>
            </div>
            <div class="cw-scroll" id="cwScroll">
                <div id="cwContactsWrap" hidden>
                    <div class="cw-section-label">Kişiler</div>
                    <div id="cwContacts"></div>
                </div>
                <div id="cwConvWrap">
                    <div class="cw-section-label" id="cwConvLabel" hidden>Sohbetler</div>
                    <div id="cwList"></div>
                </div>
                <div class="cw-empty" id="cwEmpty" hidden>
                    <div class="cw-empty-ic"><i class="fas fa-comments"></i></div>
                    <div class="cw-empty-t">Henüz sohbet yok</div>
                    <div class="cw-empty-s">Yukarıdan bir kişi arayıp ilk mesajını gönder.</div>
                </div>
            </div>
        </section>

        {{-- ── SOHBET GÖRÜNÜMÜ ── --}}
        <section class="cw-view cw-view-thread">
            <header class="cw-head cw-head-thread">
                <button class="cw-back" id="cwBack" title="Geri"><i class="fas fa-arrow-left"></i></button>
                <span class="cw-avatar cw-avatar-sm" id="cwPeerAvatar"></span>
                <div class="cw-peer">
                    <div class="cw-peer-name" id="cwPeerName">—</div>
                    <div class="cw-peer-sub" id="cwPeerSub">mesajlaşma</div>
                </div>
                <div class="cw-head-actions">
                    <button class="cw-head-btn" id="cwThreadMin" title="Küçült"><i class="fas fa-minus"></i></button>
                </div>
            </header>
            <div class="cw-thread" id="cwThread"></div>

            {{-- Bağlantı seçici (modül linki) --}}
            <div class="cw-linkpicker" id="cwLinkpicker">
                <div class="cw-lp-head">
                    <span><i class="fas fa-link me-2"></i>Modül Bağlantısı Ekle</span>
                    <button class="cw-icon-btn" id="cwLpClose"><i class="fas fa-xmark"></i></button>
                </div>
                <div class="cw-lp-types" id="cwLpTypes"></div>
                <div class="cw-searchbar" style="margin:8px 14px;">
                    <i class="fas fa-magnifying-glass"></i>
                    <input type="text" id="cwLpSearch" placeholder="Ara…" autocomplete="off">
                </div>
                <div class="cw-lp-results" id="cwLpResults"></div>
            </div>

            <div class="cw-atts" id="cwAtts"></div>
            <div class="cw-links" id="cwLinks"></div>
            <div class="cw-compose">
                <button class="cw-compose-btn cw-link" id="cwLinkBtn" title="Modül bağlantısı ekle"><i class="fas fa-link"></i></button>
                <button class="cw-compose-btn cw-attach" id="cwAttach" title="Dosya/Resim"><i class="fas fa-paperclip"></i></button>
                <input type="file" id="cwFile" multiple hidden>
                <textarea id="cwInput" rows="1" placeholder="Mesaj yazın…"></textarea>
                <button class="cw-compose-btn cw-send" id="cwSend" title="Gönder"><i class="fas fa-paper-plane"></i></button>
            </div>
        </section>

    </div>
</div>

{{-- Stiller inline (bu partial layout'a @stack('styles')'den sonra dahil edildiği için @push çalışmaz) --}}
<style>
    #chatWidget {
        --a:#5b5bf0; --a2:#8b5cf6;
        --ink:#0e1526; --ink2:#1b2437;
        --text:#0f172a; --muted:#8b93a7; --soft:#f4f5f9; --soft2:#eceef4;
        --border:#eceef4; --white:#fff; --online:#22c55e;
        --shadow:0 24px 60px -12px rgba(14,21,38,.34), 0 8px 20px -8px rgba(14,21,38,.2);
        --font: 'Inter', -apple-system, system-ui, sans-serif;
    }
    #chatWidget { font-family:var(--font); }
    #chatWidget * { box-sizing:border-box; }
    /* Font'u * ile vermiyoruz; aksi halde id-seçici Font Awesome ikon font'unu ezip ikonları bozar.
       Metin öğeleri font'u #chatWidget'tan miras alır; ikonlar (.fas/.far) kendi font'unu korur. */

    /* ── Launcher ── */
    .cw-launcher {
        position:fixed; right:26px; bottom:26px; z-index:1035;
        width:62px; height:62px; border-radius:20px; border:none; cursor:pointer;
        background:radial-gradient(120% 120% at 30% 20%, #2a3550 0%, var(--ink) 60%);
        box-shadow:0 14px 30px -6px rgba(14,21,38,.5), inset 0 1px 0 rgba(255,255,255,.08);
        display:flex; align-items:center; justify-content:center; color:#fff;
        transition:transform .28s cubic-bezier(.34,1.56,.64,1), box-shadow .28s, border-radius .28s;
    }
    .cw-launcher::before { content:""; position:absolute; inset:0; border-radius:inherit;
        background:linear-gradient(135deg, var(--a), var(--a2)); opacity:0; transition:opacity .3s; }
    .cw-launcher:hover { transform:translateY(-3px) rotate(-4deg); border-radius:24px; }
    .cw-launcher:hover::before { opacity:.16; }
    .cw-launcher-ic { position:absolute; display:flex; font-size:1.35rem; transition:transform .3s, opacity .3s; }
    .cw-ic-open { transform:scale(1); opacity:1; }
    .cw-ic-close { transform:scale(.4); opacity:0; }
    #chatWidget.open .cw-ic-open { transform:scale(.4); opacity:0; }
    #chatWidget.open .cw-ic-close { transform:scale(1); opacity:1; }
    #chatWidget.open .cw-launcher { transform:translateY(0) rotate(0); border-radius:18px; }
    .cw-launcher-badge {
        position:absolute; top:-5px; right:-5px; min-width:22px; height:22px; padding:0 6px; border-radius:11px;
        background:linear-gradient(135deg,#fb7185,#e11d48); color:#fff; font-size:.7rem; font-weight:800;
        display:flex; align-items:center; justify-content:center; border:2.5px solid #fff;
        box-shadow:0 4px 10px rgba(225,29,72,.4); animation:cwBadgePop .3s ease; }
    @keyframes cwBadgePop { from { transform:scale(0); } to { transform:scale(1); } }

    /* ── Panel ── */
    .cw-panel {
        position:fixed; right:26px; bottom:26px; z-index:1053;
        width:390px; max-width:calc(100vw - 40px);
        height:min(650px, calc(100vh - 120px));
        background:var(--white); border-radius:26px; overflow:hidden;
        box-shadow:var(--shadow); border:1px solid rgba(236,238,244,.9);
        display:flex; opacity:0; transform:translateY(24px) scale(.96);
        transform-origin:bottom right; pointer-events:none;
        transition:opacity .26s ease, transform .3s cubic-bezier(.34,1.4,.5,1);
    }
    #chatWidget.open .cw-panel { opacity:1; transform:translateY(0) scale(1); pointer-events:auto; }

    /* iki görünüm yan yana, kaydırma ile geçiş */
    .cw-view { position:absolute; inset:0; display:flex; flex-direction:column; background:var(--white);
        transition:transform .34s cubic-bezier(.4,0,.2,1), opacity .3s; }
    .cw-view-list { transform:translateX(0); }
    .cw-view-thread { transform:translateX(100%); opacity:0; pointer-events:none; }
    .cw-panel.thread .cw-view-list { transform:translateX(-24%); opacity:0; pointer-events:none; }
    .cw-panel.thread .cw-view-thread { transform:translateX(0); opacity:1; pointer-events:auto; }
    /* Panel kapalıyken (küçültülünce) hiçbir iç öğe tıklama yakalamasın — yoksa görünmez panel launcher'ı bloklar */
    #chatWidget:not(.open) .cw-panel, #chatWidget:not(.open) .cw-panel * { pointer-events:none !important; }

    /* ── Başlık (grafit) ── */
    .cw-head { position:relative; flex-shrink:0; display:flex; align-items:center; gap:12px;
        padding:18px 18px 16px; color:#fff;
        background:linear-gradient(135deg, var(--ink) 0%, var(--ink2) 100%); }
    .cw-head::after { content:""; position:absolute; top:0; right:0; width:60%; height:100%;
        background:radial-gradient(80% 120% at 100% 0%, rgba(91,91,240,.34), transparent 70%); pointer-events:none; }
    .cw-head-txt { flex:1; min-width:0; position:relative; z-index:1; }
    .cw-head-title { font-size:1.12rem; font-weight:800; letter-spacing:-.01em; }
    .cw-head-sub { font-size:.74rem; color:rgba(255,255,255,.6); margin-top:1px; }
    .cw-head-actions { display:flex; gap:6px; position:relative; z-index:1; }
    .cw-head-btn { width:34px; height:34px; border-radius:11px; border:none; cursor:pointer;
        background:rgba(255,255,255,.12); color:#fff; transition:.15s; }
    .cw-head-btn:hover { background:rgba(255,255,255,.24); }

    .cw-head-thread { padding:14px 16px; }
    .cw-back { width:34px; height:34px; border-radius:11px; border:none; cursor:pointer; flex-shrink:0;
        background:rgba(255,255,255,.12); color:#fff; transition:.15s; position:relative; z-index:1; }
    .cw-back:hover { background:rgba(255,255,255,.24); }
    .cw-peer { flex:1; min-width:0; position:relative; z-index:1; }
    .cw-peer-name { font-weight:800; font-size:.98rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cw-peer-sub { font-size:.72rem; color:rgba(255,255,255,.62); display:flex; align-items:center; gap:5px; }
    /* Durum noktası varsayılan GRİ; yalnızca gerçekten çevrimiçiyse (.on) yeşil yanar */
    .cw-peer-sub::before { content:""; width:7px; height:7px; border-radius:50%; background:#94a3b8; box-shadow:0 0 0 3px rgba(148,163,184,.18); transition:background .2s, box-shadow .2s; }
    .cw-peer-sub.on::before { background:var(--online); box-shadow:0 0 0 3px rgba(34,197,94,.22); }

    /* ── Arama ── */
    .cw-searchbar { flex-shrink:0; display:flex; align-items:center; gap:10px; margin:14px 16px 6px;
        padding:11px 14px; background:var(--soft); border:1px solid transparent; border-radius:14px; color:var(--muted); transition:.15s; }
    .cw-searchbar:focus-within { background:#fff; border-color:var(--a); box-shadow:0 0 0 4px rgba(91,91,240,.1); }
    .cw-searchbar input { flex:1; border:none; background:none; outline:none; font-size:.88rem; color:var(--text); }
    .cw-search-clear { border:none; background:none; color:var(--muted); cursor:pointer; padding:0; }

    /* ── Liste ── */
    .cw-scroll { flex:1; overflow-y:auto; padding:6px 10px 14px; }
    .cw-scroll::-webkit-scrollbar { width:7px; }
    .cw-scroll::-webkit-scrollbar-thumb { background:#e4e7ee; border-radius:7px; }
    .cw-section-label { font-size:.66rem; font-weight:800; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); padding:10px 10px 5px; }

    .cw-conv { display:flex; align-items:center; gap:12px; padding:10px 11px; border-radius:15px; cursor:pointer;
        transition:background .14s; position:relative; }
    .cw-conv:hover { background:var(--soft); }
    .cw-conv-body { flex:1; min-width:0; }
    .cw-conv-top { display:flex; justify-content:space-between; align-items:baseline; gap:8px; }
    .cw-conv-name { font-weight:700; color:var(--text); font-size:.9rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cw-conv-time { font-size:.68rem; color:var(--muted); flex-shrink:0; font-weight:600; }
    .cw-conv-preview { font-size:.8rem; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-top:2px; }
    .cw-conv-preview.unread { color:var(--text); font-weight:600; }
    .cw-conv-unread { min-width:20px; height:20px; padding:0 6px; border-radius:10px; background:linear-gradient(135deg,var(--a),var(--a2));
        color:#fff; font-size:.66rem; font-weight:800; display:flex; align-items:center; justify-content:center; flex-shrink:0;
        box-shadow:0 3px 8px rgba(91,91,240,.34); }
    .cw-conv-start { color:var(--a); font-size:.9rem; flex-shrink:0; }

    /* ── Avatar ── */
    .cw-avatar { display:inline-flex; align-items:center; justify-content:center; width:46px; height:46px; border-radius:15px;
        color:#fff; font-weight:800; font-size:.9rem; overflow:hidden; flex-shrink:0; background-size:cover; background-position:center;
        box-shadow:0 2px 6px rgba(15,23,42,.12); }
    .cw-avatar-sm { width:40px; height:40px; font-size:.82rem; border-radius:13px; border:2px solid rgba(255,255,255,.25); box-shadow:none; }

    /* ── Çevrimiçi göstergesi ── */
    .cw-avaw { position:relative; display:inline-flex; flex-shrink:0; }
    .cw-dot { position:absolute; right:-2px; bottom:-2px; width:13px; height:13px; border-radius:50%;
        background:#94a3b8; border:2.5px solid #fff; transition:background .2s; }
    .cw-dot.on { background:#22c55e; }

    /* ── Boş durum ── */
    .cw-empty { display:flex; flex-direction:column; align-items:center; text-align:center; padding:44px 24px; color:var(--muted); }
    .cw-empty-ic { width:72px; height:72px; border-radius:22px; background:linear-gradient(135deg,rgba(91,91,240,.12),rgba(139,92,246,.12));
        display:flex; align-items:center; justify-content:center; font-size:1.7rem; color:var(--a); margin-bottom:14px; }
    .cw-empty-t { font-weight:800; color:var(--text); font-size:.98rem; }
    .cw-empty-s { font-size:.82rem; margin-top:4px; max-width:220px; }

    /* ── Sohbet (thread) ── */
    .cw-thread { flex:1; overflow-y:auto; padding:18px 16px; display:flex; flex-direction:column; gap:3px;
        background:linear-gradient(180deg,#fafbfd,#f5f6fa); }
    .cw-thread::-webkit-scrollbar { width:7px; }
    .cw-thread::-webkit-scrollbar-thumb { background:#e4e7ee; border-radius:7px; }
    .cw-day { align-self:center; font-size:.66rem; font-weight:700; color:var(--muted); background:rgba(15,23,42,.05);
        padding:3px 12px; border-radius:20px; margin:10px 0 6px; }
    .cw-msg { max-width:78%; padding:7px 12px; font-size:.87rem; line-height:1.42; word-wrap:break-word; overflow-wrap:anywhere; margin-top:2px; }
    /* Saat baloncuk içinde float — taşmasın diye clearfix */
    .cw-msg::after { content:''; display:table; clear:both; }
    .cw-msg-in { align-self:flex-start; background:#fff; color:#1e293b; border-radius:16px 16px 16px 5px; box-shadow:0 1px 2px rgba(15,23,42,.07); }
    .cw-msg-out { align-self:flex-end; background:linear-gradient(135deg,var(--a),var(--a2)); color:#fff; border-radius:16px 16px 5px 16px; box-shadow:0 4px 12px -2px rgba(91,91,240,.4); }
    .cw-msg + .cw-msg-in.cw-same, .cw-msg + .cw-msg-out.cw-same { margin-top:2px; }
    .cw-msg-sender { font-size:.66rem; font-weight:800; opacity:.7; margin-bottom:2px; }
    /* Saat mesajla AYNI satırda (son satırın sağına yaslanır) → daha çok mesaj görünür */
    .cw-msg-time { float:right; font-size:.62rem; opacity:.62; margin:5px -3px -1px 9px; line-height:1; white-space:nowrap; }
    .cw-tick { font-size:.6rem; margin-left:3px; }
    .cw-tick-read { color:#5eead4; opacity:1; }   /* okundu → turkuaz çift tik (mor baloncukta belirgin) */
    .cw-msg.sending { opacity:.55; }
    .cw-msg-att { display:flex; flex-direction:column; gap:6px; margin-top:5px; }
    .cw-att-img { max-width:200px; max-height:210px; border-radius:12px; cursor:pointer; display:block; }
    .cw-att-imgwrap { position:relative; display:inline-block; }
    .cw-att-imgdl { position:absolute; top:6px; right:6px; width:30px; height:30px; border-radius:9px; background:rgba(15,23,42,.62); color:#fff; display:flex; align-items:center; justify-content:center; text-decoration:none; opacity:0; transition:.15s; font-size:.78rem; }
    .cw-att-imgwrap:hover .cw-att-imgdl { opacity:1; }
    .cw-att-file { display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:11px; background:rgba(0,0,0,.06); color:inherit; }
    .cw-msg-out .cw-att-file { background:rgba(255,255,255,.18); }
    .cw-att-fic { font-size:1.15rem; flex-shrink:0; }
    .cw-att-meta { flex:1; min-width:0; display:flex; flex-direction:column; }
    .cw-att-name { font-size:.78rem; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cw-att-size { font-size:.66rem; opacity:.7; }
    .cw-att-act { width:28px; height:28px; border-radius:8px; display:flex; align-items:center; justify-content:center; color:inherit; text-decoration:none; flex-shrink:0; transition:.14s; font-size:.78rem; background:rgba(0,0,0,.07); }
    .cw-msg-out .cw-att-act { background:rgba(255,255,255,.16); }
    .cw-att-act:hover { background:rgba(0,0,0,.15); }
    .cw-msg-out .cw-att-act:hover { background:rgba(255,255,255,.32); }
    .cw-msg-out .cw-att-name, .cw-msg-out .cw-att-size, .cw-msg-out .cw-att-fic { color:#fff; }
    .cw-msg-in .cw-att-name, .cw-msg-in .cw-att-fic { color:var(--text); }
    .cw-msg-in .cw-att-size { color:var(--muted); }

    /* ── Composer ── */
    .cw-atts { display:flex; flex-wrap:wrap; gap:6px; padding:0 14px; background:#fff; }
    .cw-atts:not(:empty) { padding:10px 14px 0; }
    .cw-att-chip { display:flex; align-items:center; gap:6px; background:var(--soft); color:#4338ca; font-size:.72rem; font-weight:700; border-radius:9px; padding:5px 9px; }
    .cw-att-chip button { border:none; background:none; color:#6366f1; cursor:pointer; padding:0; font-size:.95rem; line-height:1; }
    .cw-compose { flex-shrink:0; display:flex; align-items:flex-end; gap:9px; padding:12px 14px; background:#fff; border-top:1px solid var(--border); }
    .cw-compose-btn { width:40px; height:40px; border-radius:13px; border:none; cursor:pointer; flex-shrink:0; transition:.16s; display:flex; align-items:center; justify-content:center; font-size:.95rem; }
    .cw-attach { background:var(--soft); color:#64748b; }
    .cw-attach:hover { background:var(--soft2); color:#334155; }
    .cw-send { background:linear-gradient(135deg,var(--a),var(--a2)); color:#fff; box-shadow:0 5px 14px -3px rgba(91,91,240,.5); }
    .cw-send:hover { transform:translateY(-2px); }
    .cw-send:active { transform:translateY(0); }
    .cw-compose textarea { flex:1; resize:none; border:1px solid var(--border); border-radius:15px; padding:10px 14px; font-size:.87rem; max-height:100px; outline:none; line-height:1.4; background:var(--soft); transition:.15s; }
    .cw-compose textarea:focus { background:#fff; border-color:var(--a); box-shadow:0 0 0 4px rgba(91,91,240,.1); }

    /* ── Bağlantı: compose butonu ── */
    .cw-link { background:var(--soft); color:#64748b; }
    .cw-link:hover { background:var(--soft2); color:var(--a); }

    /* ── Bekleyen link chip'leri (composer üstü) ── */
    .cw-links { display:flex; flex-wrap:wrap; gap:6px; }
    .cw-links:not(:empty) { padding:10px 14px 0; }
    .cw-link-chip { display:flex; align-items:center; gap:7px; background:#eef2ff; color:#4338ca; font-size:.74rem; font-weight:700; border-radius:9px; padding:5px 9px; max-width:100%; }
    .cw-link-chip i.fa-xmark { color:#818cf8; cursor:pointer; }
    .cw-link-chip span { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:180px; }
    .cw-doc-chip { background:#dcfce7; color:#15803d; }
    .cw-doc-chip i.fa-xmark { color:#22c55e; }

    /* ── Bağlantı seçici overlay ── */
    .cw-linkpicker { position:absolute; left:0; right:0; bottom:0; z-index:5; background:#fff; border-top:1px solid var(--border);
        box-shadow:0 -18px 40px rgba(15,23,42,.14); border-radius:20px 20px 0 0; display:none; flex-direction:column; max-height:78%; }
    .cw-linkpicker.open { display:flex; animation:cwSlideUp .22s ease; }
    @keyframes cwSlideUp { from { transform:translateY(20px); opacity:0; } to { transform:translateY(0); opacity:1; } }
    .cw-lp-head { display:flex; align-items:center; justify-content:space-between; padding:14px 16px 8px; font-weight:800; color:var(--text); }
    .cw-lp-types { display:flex; flex-wrap:wrap; gap:6px; padding:2px 14px; }
    .cw-lp-type { display:inline-flex; align-items:center; gap:6px; border:1px solid var(--border); background:#fff; color:#475569;
        font-size:.76rem; font-weight:700; border-radius:20px; padding:6px 12px; cursor:pointer; transition:.14s; }
    .cw-lp-type:hover { border-color:#c7d2fe; }
    .cw-lp-type.active { background:linear-gradient(135deg,var(--a),var(--a2)); border-color:transparent; color:#fff; }
    .cw-lp-results { flex:1; overflow-y:auto; padding:2px 10px 12px; }
    .cw-lp-item { display:flex; align-items:center; gap:11px; padding:9px 11px; border-radius:13px; cursor:pointer; transition:background .14s; }
    .cw-lp-item:hover { background:var(--soft); }
    .cw-lp-ic { width:38px; height:38px; border-radius:12px; display:flex; align-items:center; justify-content:center; flex-shrink:0;
        background:linear-gradient(135deg,rgba(91,91,240,.12),rgba(139,92,246,.12)); color:var(--a); font-size:.95rem; }
    .cw-lp-body { flex:1; min-width:0; }
    .cw-lp-name { font-weight:700; color:var(--text); font-size:.86rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cw-lp-sub { font-size:.72rem; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cw-lp-add { color:var(--a); font-size:.9rem; }
    .cw-lp-empty { text-align:center; color:var(--muted); font-size:.83rem; padding:18px; }

    /* ── İptal edilmiş mesaj ── */
    .cw-msg-revoked { background:#f1f5f9 !important; color:#94a3b8 !important; box-shadow:none !important; border:1px dashed #cbd5e1; }
    .cw-msg-revoked.cw-msg-out { background:#f1f5f9 !important; }
    .cw-revoked-note { font-size:.76rem; font-weight:700; color:#ef4444; display:flex; align-items:center; gap:6px; }
    .cw-revoked-body { font-size:.82rem; text-decoration:line-through; opacity:.7; margin-top:3px; }

    /* ── Mesajdaki link kartları ── */
    .cw-msg-links { display:flex; flex-direction:column; gap:6px; margin-top:5px; }
    .cw-link-card { display:flex; align-items:center; gap:10px; padding:9px 11px; border-radius:12px; cursor:pointer; text-decoration:none;
        background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.2); transition:.14s; }
    .cw-msg-in .cw-link-card { background:#f3f5fb; border-color:#e6e9f2; }
    .cw-link-card:hover { filter:brightness(.97); transform:translateY(-1px); }
    .cw-msg-out .cw-link-card:hover { background:rgba(255,255,255,.22); }
    .cw-lc-ic { width:32px; height:32px; border-radius:10px; display:flex; align-items:center; justify-content:center; flex-shrink:0; font-size:.85rem;
        background:rgba(255,255,255,.24); color:#fff; }
    .cw-msg-in .cw-lc-ic { background:linear-gradient(135deg,rgba(91,91,240,.14),rgba(139,92,246,.14)); color:var(--a); }
    .cw-lc-body { flex:1; min-width:0; display:flex; flex-direction:column; }
    .cw-lc-type { font-size:.6rem; font-weight:800; text-transform:uppercase; letter-spacing:.05em; line-height:1.3; }
    .cw-lc-label { font-size:.84rem; font-weight:700; line-height:1.25; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    /* Giden (mor) baloncuk → beyaz yazılar */
    .cw-msg-out .cw-lc-type { color:rgba(255,255,255,.82); }
    .cw-msg-out .cw-lc-label { color:#fff; }
    /* Gelen (beyaz) baloncuk → koyu yazılar */
    .cw-msg-in .cw-lc-type { color:var(--muted); }
    .cw-msg-in .cw-lc-label { color:var(--text); }

    @media (max-width:520px) {
        .cw-panel { right:12px; left:12px; bottom:12px; width:auto; max-width:none; height:calc(100vh - 90px); }
        .cw-launcher { right:16px; bottom:16px; }
    }

    /* ── Quick-view açıkken: chat SOLA taşınır ve overlay'in ÜSTÜNDE kalır.
       Overlay z:1050 olduğundan chat'e tıklamak overlay'e (→ drawer kapatmaya) gitmez;
       drawer kapanınca body sınıfı kalkar, chat sağdaki yerine döner. ── */
    body.qv-drawer-open #chatWidget .cw-launcher { right: auto; left: 26px; z-index: 1060; }
    body.qv-drawer-open #chatWidget .cw-panel { right: auto; left: 26px; z-index: 1062; }
    @media (max-width:520px) {
        body.qv-drawer-open #chatWidget .cw-launcher { left: 16px; }
        body.qv-drawer-open #chatWidget .cw-panel { left: 12px; right: 12px; }
    }
</style>

@push('scripts')
@php
    $reverbOn = config('broadcasting.default') === 'reverb' && config('broadcasting.connections.reverb.key');
@endphp
@if($reverbOn)
<script src="https://cdn.jsdelivr.net/npm/pusher-js@8.4.0/dist/web/pusher.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/laravel-echo@1.16.1/dist/echo.iife.js"></script>
@endif
<script>
window.__CHAT_REVERB = @js([
    'enabled' => (bool) $reverbOn,
    'key' => config('broadcasting.connections.reverb.key'),
    'host' => config('broadcasting.connections.reverb.options.host') ?: request()->getHost(),
    'port' => (int) (config('broadcasting.connections.reverb.options.port') ?: 8080),
    'scheme' => config('broadcasting.connections.reverb.options.scheme') ?: (request()->isSecure() ? 'https' : 'http'),
    'authEndpoint' => url('/broadcasting/auth'),
]);
(function () {
    const CHAT = {
        base: @js(url('agency/chat')),
        contacts: @js(route('agency.chat.contacts')),
        conversations: @js(route('agency.chat.conversations')),
        poll: @js(route('agency.chat.poll')),
        start: @js(route('agency.chat.start')),
        linkTypes: @js(route('agency.chat.link-types')),
        linkables: @js(route('agency.chat.linkables')),
        me: {{ auth()->id() ?? 0 }},
    };
    const LINK_LABELS = { customer:'Müşteri', resource:'Kaynak', supplier:'Tedarikçi', tour:'Tur', departure:'Kalkış', sale:'Satış', contract:'Kontrat', task:'Görev' };
    const CSRF = document.querySelector('meta[name="csrf-token"]').content;
    const $ = id => document.getElementById(id);
    const widget = $('chatWidget'), panel = $('cwPanel');

    const state = { conversations: [], openId: null, lastMsgId: 0, pending: [], pendingLinks: [], pendingDocs: [], linkTypes: [], activeType: null, peer: null, lastDay: null };
    let msgTimer = null;
    let socketOK = false; // Reverb bağlıysa true → polling yavaşlar (soket birincil)

    // ── Yardımcılar ──
    function hue(s) { let h = 0; for (let i = 0; i < (s||'').length; i++) h = s.charCodeAt(i) + ((h << 5) - h); return Math.abs(h) % 360; }
    function esc(s) { const d = document.createElement('div'); d.textContent = s == null ? '' : s; return d.innerHTML; }
    function avatar(o, cls) {
        cls = cls || 'cw-avatar';
        if (o && o.avatar) return `<span class="${cls}" style="background-image:url('${o.avatar}')"></span>`;
        const bg = `linear-gradient(135deg, hsl(${hue(o && (o.title||o.name) || '?')},62%,58%), hsl(${(hue(o && (o.title||o.name) || '?')+34)%360},62%,48%))`;
        return `<span class="${cls}" style="background:${bg}">${esc((o && o.initials) || '?')}</span>`;
    }

    // ── Çevrimiçi durumu (Reverb presence) ──
    const ONLINE = new Set();          // o an bağlı kullanıcı id'leri
    let presenceOn = false;            // Reverb yoksa nokta hiç gösterilmez (yanıltıcı olmasın)
    const peerIdOf = (c) => (c && c.type === 'dm') ? (+c.peer_id || 0) : 0;

    /** Avatar + (varsa) çevrimiçi noktası. uid=0 ise nokta basılmaz (grup vb.). */
    function avatarP(o, uid, cls) {
        const u = +uid || 0;
        const dot = (presenceOn && u) ? `<i class="cw-dot${ONLINE.has(u) ? ' on' : ''}" data-uid="${u}"></i>` : '';
        return `<span class="cw-avaw">${avatar(o, cls)}${dot}</span>`;
    }
    /** Yeniden render etmeden mevcut noktaları tazeler. */
    function paintPresence() {
        document.querySelectorAll('.cw-dot[data-uid]').forEach(d => d.classList.toggle('on', ONLINE.has(+d.dataset.uid)));
        paintPeerSub();
    }
    /** Presence kanalından ayrıl ve soketi kapat (çıkış yapıldığında). */
    function leavePresence(echo) {
        try { echo.leave('chat.presence'); echo.disconnect(); } catch (e) {}
        presenceOn = false; socketOK = false;
        ONLINE.clear();
        paintPresence();
    }
    function paintPeerSub() {
        const el = $('cwPeerSub'); if (!el) return;
        const u = peerIdOf(state.peer);
        const on = !!(presenceOn && u && ONLINE.has(u));
        el.classList.toggle('on', on); // nokta rengi yalnızca gerçekten çevrimiçiyse yeşil
        if (!presenceOn || !u) { el.textContent = 'mesajlaşma'; return; }
        el.textContent = on ? 'Çevrimiçi' : 'Çevrimdışı';
    }

    function api(url, opts) {
        opts = opts || {};
        opts.headers = Object.assign({ 'X-Requested-With':'XMLHttpRequest', 'X-CSRF-TOKEN':CSRF }, opts.headers || {});
        return fetch(url, opts).then(r => r.json());
    }
    function dayLabel(iso) {
        if (!iso) return '';
        const d = new Date(iso), now = new Date();
        const diff = Math.floor((now.setHours(0,0,0,0) - new Date(iso).setHours(0,0,0,0)) / 86400000);
        if (diff === 0) return 'Bugün';
        if (diff === 1) return 'Dün';
        return d.toLocaleDateString('tr-TR', { day:'numeric', month:'long' });
    }

    // ── Panel aç/kapa ──
    function openPanel() {
        widget.classList.add('open');
        // Panel yeniden açılınca (küçültülmüşse) ve bir sohbeti görüntülüyorsak okundu say
        if (state.openId && panel.classList.contains('thread')) markRead(state.openId);
    }
    function closePanel() { widget.classList.remove('open'); }
    function togglePanel() { widget.classList.contains('open') ? closePanel() : openPanel(); }
    function showList() { panel.classList.remove('thread'); stopMsgPolling(); state.openId = null; }
    // Okundu yalnız kullanıcı sohbeti gerçekten görüntülüyorken işaretlensin
    function isViewingThread() {
        return widget.classList.contains('open') && panel.classList.contains('thread') && document.visibilityState === 'visible';
    }

    // ── Launcher badge ──
    function updateBadge() {
        const total = state.conversations.reduce((s, c) => s + (c.unread || 0), 0);
        const b = $('cwLauncherBadge');
        if (total > 0) { b.hidden = false; b.textContent = total > 99 ? '99+' : total; }
        else b.hidden = true;
        const unreadConvs = state.conversations.filter(c => c.unread > 0).length;
        $('cwHeadSub').textContent = total > 0 ? `${total} okunmamış · ${unreadConvs} sohbet` : 'Tüm sohbetleriniz';
    }

    // ── Liste render ──
    function renderList() {
        const items = state.conversations;
        const list = $('cwList');
        $('cwConvLabel').hidden = !items.length;
        $('cwEmpty').hidden = items.length > 0 || isSearching();
        list.innerHTML = items.map(convRow).join('');
        list.querySelectorAll('.cw-conv').forEach(el => el.addEventListener('click', () => openChat(+el.dataset.id)));
        updateBadge();
    }
    function convRow(c) {
        const lm = c.last_message;
        const preview = lm ? (lm.mine ? 'Siz: ' : '') + esc(lm.preview || '') : '<span style="opacity:.6">Sohbeti başlatın</span>';
        return `<div class="cw-conv" data-id="${c.id}">
            ${avatarP(c, peerIdOf(c))}
            <div class="cw-conv-body">
                <div class="cw-conv-top"><span class="cw-conv-name">${esc(c.title)}</span><span class="cw-conv-time">${lm ? lm.time : ''}</span></div>
                <div class="cw-conv-preview ${c.unread>0?'unread':''}">${preview}</div>
            </div>
            ${c.unread > 0 ? `<span class="cw-conv-unread">${c.unread>99?'99+':c.unread}</span>` : ''}
        </div>`;
    }

    // ── Sohbet aç ──
    function openChat(convId) {
        const c = state.conversations.find(x => x.id === convId) || state.peer;
        state.openId = convId; state.lastMsgId = 0; state.peer = c; state.lastDay = null;
        $('cwPeerName').textContent = c ? c.title : '';
        $('cwPeerAvatar').outerHTML = avatar(c, 'cw-avatar cw-avatar-sm').replace('<span', '<span id="cwPeerAvatar"');
        paintPeerSub();
        $('cwThread').innerHTML = '<div class="cw-day">Yükleniyor…</div>';
        clearPending(); clearLinks(); closeLinkPicker();
        panel.classList.add('thread');
        openPanel();
        loadMessages(true);
        markRead(convId);
        startMsgPolling();
        setTimeout(() => $('cwInput').focus(), 200);
    }

    let msgBusy = false;
    function loadMessages(toBottom) {
        if (!state.openId) return;
        if (!toBottom && msgBusy) return; // arka plan poll'u; önceki istek hâlâ uçuşta → atla (yavaş sunucuda birikmesin)
        msgBusy = true;
        const url = `${CHAT.base}/conversations/${state.openId}/messages` + (state.lastMsgId ? `?after_id=${state.lastMsgId}` : '');
        api(url).then(d => {
            if (!d.messages) return;
            if (state.lastMsgId === 0) { $('cwThread').innerHTML = ''; state.lastDay = null; }
            let added = false;
            d.messages.forEach(m => { appendMessage(m); state.lastMsgId = Math.max(state.lastMsgId, m.id); added = true; });
            if (d.conversation) $('cwPeerName').textContent = d.conversation.title;
            if (added && (toBottom || nearBottom())) scrollBottom();
            if (added && d.messages.some(m => !m.mine) && isViewingThread()) markRead(state.openId);
        }).catch(() => {}).finally(() => { msgBusy = false; });
    }

    function appendMessage(m) {
        const t = $('cwThread');
        // Aynı mesaj birden çok yolla (poll + gönderim yanıtı + soket) gelebilir → id ile yineleme engelle
        if (m.id && t.querySelector('.cw-msg[data-id="' + m.id + '"]')) return;
        const day = dayLabel(m.at);
        if (day && day !== state.lastDay) { const dd = document.createElement('div'); dd.className='cw-day'; dd.textContent=day; t.appendChild(dd); state.lastDay = day; }
        const div = document.createElement('div');
        div.className = 'cw-msg ' + (m.mine ? 'cw-msg-out' : 'cw-msg-in');
        div.dataset.id = m.id;

        if (m.revoked) {
            div.classList.add('cw-msg-revoked');
            div.innerHTML = revokedHtml(m);
            t.appendChild(div);
            return;
        }

        let h = '';
        if (!m.mine && m.sender) h += `<div class="cw-msg-sender">${esc(m.sender.name)}</div>`;
        if (m.body) h += esc(m.body).replace(/\n/g, '<br>');
        if (m.attachments && m.attachments.length) {
            h += '<div class="cw-msg-att">';
            m.attachments.forEach(a => {
                if (a.kind === 'image') {
                    h += `<div class="cw-att-imgwrap">
                        <img class="cw-att-img" src="${a.url}" onclick="window.open('${a.url}','_blank')" alt="">
                        <a class="cw-att-imgdl" href="${a.download_url}" title="İndir" onclick="event.stopPropagation()"><i class="fas fa-download"></i></a>
                    </div>`;
                } else {
                    h += `<div class="cw-att-file">
                        <i class="fas fa-file-lines cw-att-fic"></i>
                        <span class="cw-att-meta"><span class="cw-att-name">${esc(a.name)}</span>${a.size ? `<span class="cw-att-size">${esc(a.size)}</span>` : ''}</span>
                        <a class="cw-att-act" href="${a.url}" target="_blank" title="Aç"><i class="fas fa-up-right-from-square"></i></a>
                        <a class="cw-att-act cw-att-dl" href="${a.download_url}" title="İndir"><i class="fas fa-download"></i></a>
                    </div>`;
                }
            });
            h += '</div>';
        }
        if (m.links && m.links.length) {
            h += '<div class="cw-msg-links">';
            m.links.forEach((l, i) => {
                h += `<a class="cw-link-card" data-i="${i}">
                    <span class="cw-lc-ic"><i class="fas ${l.icon || 'fa-link'}"></i></span>
                    <span class="cw-lc-body"><span class="cw-lc-type">${esc(LINK_LABELS[l.type] || l.type)}</span><span class="cw-lc-label">${esc(l.label)}</span></span>
                </a>`;
            });
            h += '</div>';
        }
        h += `<span class="cw-msg-time">${esc(m.time || '')}${m.mine ? tickHtml(m.read) : ''}</span>`;
        div.innerHTML = h;
        if (m.links && m.links.length) {
            div.querySelectorAll('.cw-link-card').forEach(el => el.addEventListener('click', () => openLink(m.links[+el.dataset.i])));
        }
        t.appendChild(div);
    }

    // Okundu tiki: okunduysa çift + renkli, değilse tek
    function tickHtml(read) {
        return ` <i class="fas ${read ? 'fa-check-double cw-tick cw-tick-read' : 'fa-check cw-tick'}"></i>`;
    }

    function revokedHtml(m) {
        let h = '<div class="cw-revoked-note"><i class="fas fa-ban"></i> Bu içerik geri çekildi / iptal edildi</div>';
        if (m.body) h += `<div class="cw-revoked-body">${esc(m.body).replace(/\n/g, '<br>')}</div>`;
        h += `<span class="cw-msg-time">${esc(m.time || '')}</span>`;
        return h;
    }

    // Link kartına tıklama → quick-view drawer (varsa) ya da yeni sekme
    function openLink(l) {
        if (!l || !l.url) return;
        let path = l.url;
        try { path = new URL(l.url, location.origin).pathname + new URL(l.url, location.origin).search; } catch (e) {}
        if (l.qv && typeof window.openQuickView === 'function') {
            try { window.openQuickView(path); return; } catch (e) {}
        }
        window.open(l.url, '_blank');
    }

    // Mevcut (render edilmiş) mesajlarda iptal/geri-çekme durumunu yakalar.
    // (Normal poll after_id ile yalnız YENİ mesaj çeker; iptal mevcut mesajı değiştirir.)
    let patchBusy = false;
    function patchThread() {
        if (!state.openId || patchBusy) return;
        patchBusy = true;
        api(`${CHAT.base}/conversations/${state.openId}/messages`).then(d => {
            (d.messages || []).forEach(m => {
                const el = $('cwThread').querySelector(`.cw-msg[data-id="${m.id}"]`);
                if (!el) return;
                if (m.revoked) {
                    if (!el.classList.contains('cw-msg-revoked')) { el.classList.add('cw-msg-revoked'); el.innerHTML = revokedHtml(m); }
                    return;
                }
                // Okundu tikini güncelle (gönderdiğim mesajlar)
                if (m.mine) {
                    const tick = el.querySelector('.cw-tick');
                    if (tick) {
                        const isRead = tick.classList.contains('cw-tick-read');
                        if (m.read && !isRead) tick.className = 'fas fa-check-double cw-tick cw-tick-read';
                        else if (!m.read && isRead) tick.className = 'fas fa-check cw-tick';
                    }
                }
            });
        }).catch(() => {}).finally(() => { patchBusy = false; });
    }

    function nearBottom() { const b = $('cwThread'); return b.scrollHeight - b.scrollTop - b.clientHeight < 140; }
    function scrollBottom() { const b = $('cwThread'); b.scrollTop = b.scrollHeight; }

    // ── Gönder ──
    function send() {
        const input = $('cwInput'), body = input.value.trim();
        if ((!body && !state.pending.length && !state.pendingLinks.length && !state.pendingDocs.length) || !state.openId) return;
        const fd = new FormData();
        fd.append('body', body);
        state.pending.forEach(f => fd.append('attachments[]', f));
        if (state.pendingLinks.length) fd.append('links', JSON.stringify(state.pendingLinks));
        if (state.pendingDocs.length) fd.append('contract_docs', JSON.stringify(state.pendingDocs.map(d => d.id)));

        const tmp = document.createElement('div');
        tmp.className = 'cw-msg cw-msg-out sending';
        const ph = state.pendingDocs.length ? '📄' : (state.pendingLinks.length ? '🔗' : '📎');
        tmp.innerHTML = (body ? esc(body).replace(/\n/g,'<br>') : ph) + '<span class="cw-msg-time">gönderiliyor…</span>';
        $('cwThread').appendChild(tmp); scrollBottom();
        input.value = ''; input.style.height = 'auto';
        clearPending(); clearLinks();

        api(`${CHAT.base}/conversations/${state.openId}/messages`, { method:'POST', body:fd })
            .then(d => { tmp.remove(); if (d.success && d.message) { appendMessage(d.message); state.lastMsgId = Math.max(state.lastMsgId, d.message.id); scrollBottom(); refreshSoon(); } })
            .catch(() => { const t = tmp.querySelector('.cw-msg-time'); if (t) t.textContent = 'gönderilemedi'; });
    }

    // ── Ekler ──
    function addFiles(files) { Array.from(files).forEach(f => state.pending.push(f)); renderPending(); }
    function renderPending() {
        $('cwAtts').innerHTML = state.pending.map((f,i) =>
            `<span class="cw-att-chip"><i class="fas fa-${(f.type||'').startsWith('image')?'image':'file'}"></i>${esc(f.name.slice(0,16))}<button data-i="${i}">&times;</button></span>`).join('');
        $('cwAtts').querySelectorAll('button').forEach(b => b.addEventListener('click', () => { state.pending.splice(+b.dataset.i,1); renderPending(); }));
    }
    function clearPending() { state.pending = []; $('cwAtts').innerHTML = ''; $('cwFile').value = ''; }

    // ── Modül bağlantısı ekleme ──
    function loadLinkTypes() {
        if (state.linkTypes.length) return Promise.resolve();
        return api(CHAT.linkTypes).then(d => { state.linkTypes = d.types || []; }).catch(() => {});
    }
    function openLinkPicker() {
        loadLinkTypes().then(() => {
            if (!state.activeType && state.linkTypes.length) state.activeType = state.linkTypes[0].key;
            renderTypeChips();
            $('cwLpSearch').value = '';
            searchLinkables('');
            $('cwLinkpicker').classList.add('open');
            setTimeout(() => $('cwLpSearch').focus(), 160);
        });
    }
    function closeLinkPicker() { $('cwLinkpicker').classList.remove('open'); }
    function renderTypeChips() {
        $('cwLpTypes').innerHTML = state.linkTypes.map(t =>
            `<button class="cw-lp-type ${t.key === state.activeType ? 'active' : ''}" data-t="${t.key}"><i class="fas ${t.icon}"></i>${esc(t.label)}</button>`).join('');
        $('cwLpTypes').querySelectorAll('.cw-lp-type').forEach(b => b.addEventListener('click', () => {
            state.activeType = b.dataset.t; renderTypeChips(); searchLinkables($('cwLpSearch').value);
        }));
    }
    let lpT = null;
    function searchLinkables(q) {
        if (!state.activeType) return;
        $('cwLpResults').innerHTML = '<div class="cw-lp-empty">Aranıyor…</div>';
        clearTimeout(lpT);
        lpT = setTimeout(() => {
            api(`${CHAT.linkables}?type=${state.activeType}&q=${encodeURIComponent(q)}`).then(d => {
                const rows = d.results || [];
                if (!rows.length) { $('cwLpResults').innerHTML = '<div class="cw-lp-empty">Sonuç bulunamadı.</div>'; return; }
                $('cwLpResults').innerHTML = rows.map((r, i) => `
                    <div class="cw-lp-item" data-i="${i}">
                        <div class="cw-lp-ic"><i class="fas ${r.icon}"></i></div>
                        <div class="cw-lp-body"><div class="cw-lp-name">${esc(r.label)}</div>${r.sub ? `<div class="cw-lp-sub">${esc(r.sub)}</div>` : ''}</div>
                        <i class="fas fa-plus cw-lp-add"></i>
                    </div>`).join('');
                $('cwLpResults').querySelectorAll('.cw-lp-item').forEach(el => el.addEventListener('click', () => addLink(rows[+el.dataset.i])));
            }).catch(() => { $('cwLpResults').innerHTML = '<div class="cw-lp-empty">Hata oluştu.</div>'; });
        }, 220);
    }
    function addLink(link) {
        if (!link) return;
        // Belge (kontrat) — link değil, dosya olarak eklenir
        if (link.doc) {
            if (state.pendingDocs.length >= 6 || state.pendingDocs.find(d => d.id === link.id)) { closeLinkPicker(); return; }
            state.pendingDocs.push({ id: link.id, label: link.label, icon: link.icon });
            renderPendingLinks();
            closeLinkPicker();
            return;
        }
        if (state.pendingLinks.length >= 6) return;
        if (state.pendingLinks.find(l => l.type === link.type && l.id === link.id && l.url === link.url)) { closeLinkPicker(); return; }
        state.pendingLinks.push(link);
        renderPendingLinks();
        closeLinkPicker();
    }
    function renderPendingLinks() {
        const linkChips = state.pendingLinks.map((l, i) =>
            `<span class="cw-link-chip" data-k="l" data-i="${i}"><i class="fas ${l.icon}"></i><span>${esc(l.label)}</span><i class="fas fa-xmark cw-chip-x"></i></span>`).join('');
        const docChips = state.pendingDocs.map((d, i) =>
            `<span class="cw-link-chip cw-doc-chip" data-k="d" data-i="${i}"><i class="fas ${d.icon || 'fa-file-signature'}"></i><span>${esc(d.label)}</span><i class="fas fa-xmark cw-chip-x"></i></span>`).join('');
        $('cwLinks').innerHTML = linkChips + docChips;
        $('cwLinks').querySelectorAll('.cw-chip-x').forEach(x => x.addEventListener('click', () => {
            const chip = x.closest('.cw-link-chip');
            if (chip.dataset.k === 'd') state.pendingDocs.splice(+chip.dataset.i, 1);
            else state.pendingLinks.splice(+chip.dataset.i, 1);
            renderPendingLinks();
        }));
    }
    function clearLinks() { state.pendingLinks = []; state.pendingDocs = []; $('cwLinks').innerHTML = ''; }

    function markRead(id) {
        api(`${CHAT.base}/conversations/${id}/read`, { method:'POST' })
            .then(() => { const c = state.conversations.find(x => x.id === id); if (c) c.unread = 0; renderList(); }).catch(() => {});
    }

    // ── Polling ──
    function startMsgPolling() {
        stopMsgPolling();
        let tick = 0;
        msgTimer = setInterval(() => {
            if (!socketOK) loadMessages(false);       // soket varken yeni mesajı olay tetikler
            if (++tick % 4 === 0) patchThread();       // iptal/geri-çekme senkronu (her ~10sn)
        }, 2500);
    }

    // ── Reverb (WebSocket) — varsa anlık; yoksa polling'e düşer ──
    function initEcho() {
        try {
            const cfg = window.__CHAT_REVERB;
            if (!cfg || !cfg.enabled || !cfg.key) return;
            if (typeof window.Echo !== 'function' || typeof window.Pusher === 'undefined') return;

            const echo = new window.Echo({
                broadcaster: 'reverb',
                key: cfg.key,
                wsHost: cfg.host,
                wsPort: cfg.port,
                wssPort: cfg.port,
                forceTLS: cfg.scheme === 'https',
                enabledTransports: ['ws', 'wss'],
                authEndpoint: cfg.authEndpoint,
                auth: { headers: { 'X-CSRF-TOKEN': CSRF } },
            });

            // Çevrimiçi kullanıcılar: presence kanalı üyeliği = bağlı olmak.
            presenceOn = true;
            echo.join('chat.presence')
                .here((users) => { ONLINE.clear(); (users || []).forEach(u => ONLINE.add(+u.id)); paintPresence(); })
                .joining((u) => { if (u) { ONLINE.add(+u.id); paintPresence(); } })
                .leaving((u) => { if (u) { ONLINE.delete(+u.id); paintPresence(); } })
                .error(() => { presenceOn = false; paintPresence(); });

            echo.private('chat.user.' + CHAT.me).listen('.message.sent', (e) => {
                if (e && e.conversation_id === state.openId) { loadMessages(false); patchThread(); }
                refreshConvs();
            }).listen('.session.ended', () => {
                // Başka bir sekmede çıkış yapıldı: bu sekmenin soketi de kapanmalı,
                // yoksa presence üyeliği sürer ve kullanıcı çevrimiçi görünür.
                leavePresence(echo);
            });

            const pusher = echo.connector && echo.connector.pusher;
            if (pusher && pusher.connection) {
                // Soket koparsa presence üyeliği de geçersizdir; bayat yeşil nokta göstermeyelim.
                const dropped = () => { socketOK = false; ONLINE.clear(); paintPresence(); };
                pusher.connection.bind('connected', () => { socketOK = true; });
                pusher.connection.bind('unavailable', dropped);
                pusher.connection.bind('disconnected', dropped);
                pusher.connection.bind('failed', dropped);
            }
            window.__chatEcho = echo;
        } catch (e) { socketOK = false; presenceOn = false; }
    }
    function stopMsgPolling() { if (msgTimer) { clearInterval(msgTimer); msgTimer = null; } }
    let pollBusy = false;
    function refreshConvs() { if (pollBusy) return; pollBusy = true; api(CHAT.conversations).then(d => { if (d.conversations) { state.conversations = d.conversations; renderList(); } }).catch(() => {}).finally(() => { pollBusy = false; }); }
    let rt = null; function refreshSoon() { clearTimeout(rt); rt = setTimeout(refreshConvs, 400); }
    function poll() { if (pollBusy) return; pollBusy = true; api(CHAT.poll).then(d => { if (d.conversations) { state.conversations = d.conversations; renderList(); } }).catch(() => {}).finally(() => { pollBusy = false; }); }

    // ── Birleşik arama ──
    function isSearching() { return $('cwSearch').value.trim().length > 0; }
    let st = null;
    function onSearch() {
        const q = $('cwSearch').value.trim();
        $('cwSearchClear').hidden = !q;
        // sohbetleri yerelde filtrele
        const list = $('cwList');
        const filtered = q ? state.conversations.filter(c => (c.title||'').toLowerCase().includes(q.toLowerCase())) : state.conversations;
        $('cwConvLabel').hidden = !filtered.length;
        $('cwEmpty').hidden = filtered.length > 0 || !!q;
        list.innerHTML = filtered.map(convRow).join('');
        list.querySelectorAll('.cw-conv').forEach(el => el.addEventListener('click', () => openChat(+el.dataset.id)));
        // kişileri sunucudan ara
        if (!q) { $('cwContactsWrap').hidden = true; return; }
        clearTimeout(st);
        st = setTimeout(() => {
            api(`${CHAT.contacts}?q=${encodeURIComponent(q)}`).then(d => {
                const cs = d.contacts || [];
                $('cwContactsWrap').hidden = !cs.length;
                $('cwContacts').innerHTML = cs.map(u => `
                    <div class="cw-conv" data-uid="${u.id}">
                        ${avatarP(u, u.id)}
                        <div class="cw-conv-body"><div class="cw-conv-name">${esc(u.name)}</div>
                        <div class="cw-conv-preview">Sohbet başlat</div></div>
                        <i class="fas fa-paper-plane cw-conv-start"></i>
                    </div>`).join('');
                $('cwContacts').querySelectorAll('.cw-conv').forEach(r => r.addEventListener('click', () => startWith(+r.dataset.uid)));
            }).catch(() => {});
        }, 250);
    }
    function startWith(userId) {
        api(CHAT.start, { method:'POST', headers:{ 'Content-Type':'application/json' }, body:JSON.stringify({ user_id:userId }) })
            .then(d => {
                if (d.success && d.conversation) {
                    if (!state.conversations.find(c => c.id === d.conversation.id)) state.conversations.unshift(Object.assign({ unread:0, last_message:null }, d.conversation));
                    state.peer = d.conversation;
                    $('cwSearch').value = ''; $('cwSearchClear').hidden = true; $('cwContactsWrap').hidden = true;
                    openChat(d.conversation.id);
                }
            }).catch(() => {});
    }

    // ── Olaylar ──
    $('cwLauncher').addEventListener('click', togglePanel);
    $('cwMinBtn').addEventListener('click', closePanel);
    $('cwThreadMin').addEventListener('click', closePanel);
    $('cwBack').addEventListener('click', showList);
    $('cwSend').addEventListener('click', send);
    $('cwInput').addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } });
    $('cwInput').addEventListener('input', function () { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 100) + 'px'; });
    $('cwAttach').addEventListener('click', () => $('cwFile').click());
    $('cwFile').addEventListener('change', e => addFiles(e.target.files));
    $('cwLinkBtn').addEventListener('click', openLinkPicker);
    $('cwLpClose').addEventListener('click', closeLinkPicker);
    $('cwLpSearch').addEventListener('input', e => searchLinkables(e.target.value));
    $('cwSearch').addEventListener('input', onSearch);
    $('cwSearchClear').addEventListener('click', () => { $('cwSearch').value = ''; onSearch(); });
    // Sekmeye geri dönünce ve sohbet görüntüleniyorsa okundu say
    document.addEventListener('visibilitychange', () => { if (isViewingThread() && state.openId) markRead(state.openId); });

    const th = $('cwThread');
    ['dragover','drop'].forEach(ev => th.addEventListener(ev, e => { e.preventDefault(); if (ev === 'drop' && e.dataTransfer.files.length) addFiles(e.dataTransfer.files); }));

    // ── Başlat ──
    refreshConvs();
    initEcho();
    let gtick = 0;
    setInterval(() => { if (socketOK && (++gtick % 6 !== 0)) return; poll(); }, 4000); // soket varken ~24sn güvenlik, yoksa 4sn
})();
</script>
@endpush
