🌟 Route49

Popmundo turne planlayıcısı — coğrafi optimizasyon, şablon sistemi ve konser arayüzü yardımcısı.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         🌟 Route49
// @name:tr      🌟 Route49
// @name:en      🌟 Route49
// @name:pt-BR   🌟 Route49
// @namespace    pop.route49
// @version      1.3
// @description     Popmundo turne planlayıcısı — coğrafi optimizasyon, şablon sistemi ve konser arayüzü yardımcısı.
// @description:tr  Popmundo turne planlayıcısı — coğrafi optimizasyon, şablon sistemi ve konser arayüzü yardımcısı.
// @description:en  Popmundo tour planner — geographic optimization, template system and booking interface helper.
// @description:pt-BR Planejador de turnê Popmundo — otimização geográfica, sistema de modelos e assistente de interface de shows.
// @author       luke-james-gibson
// @license      MIT
// @match        https://*.popmundo.com/*
// @run-at       document-end
// @grant        unsafeWindow
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_info
// ==/UserScript==

(function () {
    'use strict';

    try { const p = JSON.parse(localStorage.getItem('ppc_enabled') || '{}'); if (p['route49'] === false) return; } catch {}

    // ─── UTILS ───────────────────────────────────────────────────────────────────
    const log     = (...a) => console.log('[Route49]', ...a);
    const delay   = ms => new Promise(r => setTimeout(r, ms));
    const rdelay  = () => { try { const f = JSON.parse(localStorage.getItem('GreasyMonkey_r49_settings')||GM_getValue('r49_settings','{"fastMode":false}')).fastMode; return delay(f ? 500+Math.random()*1000 : 2000+Math.random()*4000); } catch { return delay(2000+Math.random()*4000); } };
    const mk      = (tag, cls, txt) => { const e = document.createElement(tag); if (cls) e.className = cls; if (txt != null) e.textContent = txt; return e; };
    const mkB     = (txt, cls, fn) => Object.assign(mk('button', cls, txt), { onclick: fn, type: 'button' });
    const $       = s => document.querySelector(s);
    const norm    = s => { try { return String(s||'').normalize('NFD').replace(/\p{M}/gu,'').toLowerCase().trim(); } catch { return String(s||'').toLowerCase().replace(/[\u0300-\u036f]/g,'').trim(); } };
    const fmtISO  = d => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
    const fmtDisp = d => `${String(d.getDate()).padStart(2,'0')}.${String(d.getMonth()+1).padStart(2,'0')}.${d.getFullYear()}`;
    const addDays = (d, n) => { const r = new Date(d); r.setDate(r.getDate() + n); return r; };

    // ─── LANGUAGE ─────────────────────────────────────────────────────────────────
    const LANG = (() => { try { const m = document.cookie.match(/ppm_lang=([^;]+)/); return m ? m[1] : 'TR'; } catch { return 'TR'; } })();
    const _D   = (tr, en, pt) => ({ TR: tr, EN: en, PT: pt }[LANG] || tr);
    const _LC  = (() => { try { return JSON.parse(localStorage.getItem('ppc_lc_route49') || '{}'); } catch { return {}; } })();
    const T    = k => _LC[k] || S[k] || k;

    function setLang(lang) {
        document.cookie = `ppm_lang=${lang};path=/;max-age=31536000`;
        location.reload();
    }

    // ─── PM DATE ENGINE ───────────────────────────────────────────────────────────
    const PM_ANCHOR   = new Date('2026-02-25T00:00:00');
    const MS_DAY      = 86400000;
    const PM_YEAR_LEN = 56;
    const TODAY       = new Date();

    const realToPM  = d => { const days = Math.floor((d - PM_ANCHOR) / MS_DAY); return { year: 152 + Math.floor(days / PM_YEAR_LEN), day: ((days % PM_YEAR_LEN) + PM_YEAR_LEN) % PM_YEAR_LEN + 1 }; };
    const pmToReal  = (year, day) => new Date(PM_ANCHOR.getTime() + ((year - 152) * PM_YEAR_LEN + (day - 1)) * MS_DAY);
    const dateLabel = d => { const p = realToPM(d); return `${fmtDisp(d)} (${_D('Yıl','Year','Ano')} ${p.year} ${_D('Gün','Day','Dia')} ${p.day})`; };

    // ─── SPECIAL DAYS ─────────────────────────────────────────────────────────────
    const SPECIAL_DAYS = {
        1:  { icon:'🎊', label:_D('Yeni Yılın İlk Günü','New Year\'s Day','Ano Novo'),                anchor:false },
        9:  { icon:'💥', label:_D('Big Bang','Big Bang','Big Bang'),                                   anchor:true  },
        13: { icon:'🎉', label:_D('Popopalooza Günü','Popopalooza Day','Dia Popopalooza'),              anchor:false },
        22: { icon:'🦑', label:_D('Kraken\'in Dönüşü','Return of the Kraken','Retorno do Kraken'),     anchor:false },
        28: { icon:'💀', label:_D('Ölüler Günü','Day of the Dead','Dia dos Mortos'),                   anchor:true  },
        40: { icon:'🏔️', label:_D('Aziz Kobe Günü','Saint Kobe\'s Day','Dia de São Kobe'),            anchor:true  },
        48: { icon:'🎃', label:_D('Cadılar Bayramı','Halloween','Halloween'),                           anchor:false },
        52: { icon:'🎄', label:_D('Noel','Christmas','Natal'),                                          anchor:false },
        54: { icon:'🕊️', label:_D('Kurtuluş Günü','Liberation Day','Dia da Libertação'),              anchor:false },
        56: { icon:'🥂', label:_D('Yeni Yıl Arifesi','New Year\'s Eve','Véspera de Ano Novo'),         anchor:false },
    };
    const ANCHOR_DAYS = Object.entries(SPECIAL_DAYS).filter(([,v]) => v.anchor);

    // ─── CITY CATALOG ─────────────────────────────────────────────────────────────
    const CITIES =[
        {id:8,  en:'Amsterdam',      tr:'Amsterdam',      tz:1  },
        {id:35, en:'Ankara',         tr:'Ankara',         tz:3  },
        {id:61, en:'Antalya',        tr:'Antalya',        tz:3  },
        {id:58, en:'Baku',           tr:'Bakü',           tz:4  },
        {id:9,  en:'Barcelona',      tr:'Barselona',      tz:1  },
        {id:36, en:'Belgrade',       tr:'Belgrad',        tz:1  },
        {id:7,  en:'Berlin',         tr:'Berlin',         tz:1  },
        {id:33, en:'Brussels',       tr:'Brüksel',        tz:1  },
        {id:42, en:'Budapest',       tr:'Budapeşte',      tz:1  },
        {id:17, en:'Buenos Aires',   tr:'Buenos Aires',   tz:-3 },
        {id:46, en:'Bucharest',      tr:'Bükreş',         tz:2  },
        {id:55, en:'Jakarta',        tr:'Cakarta',        tz:7  },
        {id:29, en:'Dubrovnik',      tr:'Dubrovnik',      tz:1  },
        {id:27, en:'Glasgow',        tr:'Glasgow',        tz:0  },
        {id:19, en:'Helsinki',       tr:'Helsinki',       tz:2  },
        {id:30, en:'Istanbul',       tr:'İstanbul',       tz:3  },
        {id:47, en:'Izmir',          tr:'İzmir',          tz:3  },
        {id:51, en:'Johannesburg',   tr:'Johannesburg',   tz:2  },
        {id:22, en:'Copenhagen',     tr:'Kopenhag',       tz:1  },
        {id:56, en:'Kyiv',           tr:'Kyiv',           tz:2  },
        {id:5,  en:'London',         tr:'Londra',         tz:0  },
        {id:14, en:'Los Angeles',    tr:'Los Angeles',    tz:-8 },
        {id:24, en:'Madrid',         tr:'Madrid',         tz:1  },
        {id:54, en:'Manila',         tr:'Manila',         tz:8  },
        {id:10, en:'Melbourne',      tr:'Melbourne',      tz:11 },
        {id:32, en:'Mexico City',    tr:'Mexico City',    tz:-6 },
        {id:52, en:'Milan',          tr:'Milano',         tz:1  },
        {id:38, en:'Montreal',       tr:'Montreal',       tz:-5 },
        {id:18, en:'Moscow',         tr:'Moskova',        tz:3  },
        {id:11, en:'Nashville',      tr:'Nashville',      tz:-6 },
        {id:6,  en:'New York',       tr:'New York',       tz:-5 },
        {id:20, en:'Paris',          tr:'Paris',          tz:1  },
        {id:31, en:'Porto',          tr:'Porto',          tz:0  },
        {id:25, en:'Rio de Janeiro', tr:'Rio de Janeiro', tz:-3 },
        {id:23, en:'Rome',           tr:'Roma',           tz:1  },
        {id:45, en:'Shanghai',       tr:'Şangay',         tz:8  },
        {id:21, en:'Sao Paulo',      tr:'Sao Paulo',      tz:-3 },
        {id:49, en:'Sarajevo',       tr:'Saraybosna',     tz:1  },
        {id:50, en:'Seattle',        tr:'Seattle',        tz:-8 },
        {id:60, en:'Chicago',        tr:'Şikago',         tz:-6 },
        {id:39, en:'Singapore',      tr:'Singapur',       tz:8  },
        {id:53, en:'Sofia',          tr:'Sofya',          tz:2  },
        {id:1,  en:'Stockholm',      tr:'Stokholm',       tz:1  },
        {id:34, en:'Tallinn',        tr:'Tallinn',        tz:2  },
        {id:62, en:'Tokyo',          tr:'Tokyo',          tz:9  },
        {id:16, en:'Toronto',        tr:'Toronto',        tz:-5 },
        {id:26, en:'Tromsø',         tr:'Tromsø',         tz:1  },
        {id:48, en:'Warsaw',         tr:'Varşova',        tz:1  },
        {id:28, en:'Vilnius',        tr:'Vilnius',        tz:2  },
    ];
    const cityById  = id  => CITIES.find(c => c.id === id);
    const cityByAny = str => CITIES.find(c => norm(c.en)===norm(str) || norm(c.tr)===norm(str));
    const cityName  = c   => c ? (LANG==='TR' ? c.tr : c.en) : '?';

    // ─── TOUR TYPES & PLANS (v0.5 Architecture) ───────────────────────────────────
    const _TT =[30,47,61,35,58,18,56,45,54,55,39,62,10,17,25,21,32,14,50,60,11,16,38,6,5,27,31,24,9,20,33,8,7,22,26,1,19,34,28,48,42,46,53,36,49,29,23,52,51];
    const _LI =[5,27,6,38,16,11,60,50,14,32,21,25,17,10,55,39,54,45,62,51,31,24,9,20,33,8,7,22,26,1,19,34,28,48,42,46,53,36,49,29,23,52,18,56,58,35,61,47,30];

    const TOUR_PLANS = {
        'tt': { name:'☀️ Güneş İzinde (Istanbul → Johannesburg)', legs:_TT },
        'li': { name:'🏙️ Prime Line (London → Istanbul)', legs:_LI },
        'custom': { name:_D('✏️ Özel Rota','✏️ Custom Route','✏️ Rota Personalizada'), legs:[] },
    };

    const TOUR_TYPES = {
        'relax':    { name:'😌 Relax (56 Gün)', dpc:2, doubleDay:true, durationDays:56 },
        'blitz':    { name:'⚡ Blitz (25 Gün)', dpc:1, doubleDay:true,  durationDays:25, blitzMode:true },
        'hardcore': { name:'🤘  Hardcore (51 Gün)', dpc:2, doubleDay:true,  durationDays:51 },
        'custom':   { name:'⚙️ Özel Tarihler',  dpc:1, doubleDay:false, durationDays:56 },
    };

    // ─── STORAGE ──────────────────────────────────────────────────────────────────
    const GMK = {
        status:  'r49_status',   // 'IDLE'|'RUNNING'|'PAUSED'
        tour:    'r49_tour',
        idx:     'r49_idx',
        sets:    'r49_settings',
        restore: 'r49_restore',
        stadU:   'r49_stad_used',
        stadY:   'r49_stad_year',
        schemas: 'r49_schemas',  // Dynamic array of saved schemas
    };

    const gmGet = (k,d) => { try { const v=GM_getValue(k,null); return v!==null?JSON.parse(v):d; } catch { return d; } };
    const gmSet = (k,v) => { try { GM_setValue(k,JSON.stringify(v)); } catch {} };
    const gmDel = k     => { try { GM_deleteValue(k); } catch {} };

    // Migration function for v0.4 -> v0.5 settings
    function migrateSettings(sets) {
        if (!sets) return sets;
        if (sets.template) {
            const t = sets.template;
            if (t === 'hardcore') { sets.tourType = 'hardcore'; sets.tourPlan = 'hc'; }
            else if (t === 'blitz') { sets.tourType = 'blitz'; sets.tourPlan = 'tt'; }
            else if (t === 'londonIstanbul') { sets.tourType = 'relax'; sets.tourPlan = 'li'; }
            else if (t === 'timeTraveler') { sets.tourType = 'relax'; sets.tourPlan = 'tt'; }
            else if (t === 'custom') { sets.tourType = 'custom'; sets.tourPlan = 'custom'; }
            else { sets.tourType = 'relax'; sets.tourPlan = 'tt'; }
            delete sets.template;
            gmSet(GMK.sets, sets);
        }

        let schemas = gmGet(GMK.schemas,[]);
        let migrated = false;['r49_prof_1', 'r49_prof_2', 'r49_prof_3'].forEach(k => {
            const old = gmGet(k, null);
            if (old) {
                schemas.push({ id: Date.now()+Math.random(), name: old.name || 'Migrated Plan', tour: old.tour, settings: old.settings, templateDays: old.templateDays });
                gmDel(k); migrated = true;
            }
        });
        if (migrated) gmSet(GMK.schemas, schemas);
        return sets;
    }

    // ─── STRINGS ──────────────────────────────────────────────────────────────────
    const S = {
        title:          _D('🌟 Route49',                    '🌟 Route49',                      '🌟 Route49'),
        tabPlan:        _D('📋 Plan',                       '📋 Plan',                         '📋 Plano'),
        tabSaved:       _D('💾 Şemalar',                    '💾 Schemas',                      '💾 Esquemas'),
        tabSettings:    _D('⚙️ Ayarlar',                   '⚙️ Settings',                     '⚙️ Config'),
        tourType:       _D('Turne Türü',                    'Tour Type',                       'Tipo de Turnê'),
        tourPlan:       _D('Turne Planı',                   'Tour Plan',                       'Plano de Turnê'),
        startCity:      _D('Başlangıç Şehri',               'Start City',                      'Cidade Inicial'),
        customHint:     _D('Şehir adları (İngilizce), her satıra bir tane:','City names (English), one per line:','Nomes das cidades (inglês), um por linha:'),
        artistId:       _D('Sanatçı ID',                    'Artist ID',                       'ID do Artista'),
        startDate:      _D('Başlangıç',                     'Start',                           'Início'),
        endDate:        _D('Bitiş',                         'Fim',                             'Fim'),
        showsPerCity:   _D('Şehir başına 2',                '2 per city',                      '2 por cidade'),
        doubleDay:      _D('Günde 2 konser',                '2 shows per day',                 '2 shows por dia'),
        showsDDNote:    _D('Günde 2 konser seçili değilse şehir başına 2 konser yapılamaz.','Requires 2 shows/day to enable 2 per city.','Requer 2 shows/dia para ativar 2 por cidade.'),
        showTimes:      _D('Konser Saatleri (Ctrl+tık)',    'Show Times (Ctrl+click)',          'Horários (Ctrl+clique)'),
        fameScore:      _D('Ortalama Şöhret',               'Avg. Fame Score',                 'Fama Média'),
        priceRange:     _D('Bilet Fiyatı (M$)',             'Ticket Price (M$)',               'Ingresso (M$)'),
        minStars:       _D('Minimum Yıldız',                'Min. Stars',                      'Estrelas Mínimas'),
        sortMode:       _D('Kulüp Sıralaması',              'Club Sort',                       'Ordenação'),
        sortHigh:       _D('En Yüksek Fiyat',               'Highest Price',                   'Maior Preço'),
        sortLow:        _D('En Düşük Fiyat',                'Lowest Price',                    'Menor Preço'),
        sortMid:        _D('Orta Fiyat',                    'Mid-Range',                       'Preço Médio'),
        sdTitle:        _D('Özel Gün Ayarları',             'Special Day Settings',            'Config. de Dias Especiais'),
        sdAra:          _D('Ara',                           'Rest',                            'Descanso'),
        stadCities:     _D('Stadyum Şehirleri',             'Stadium Cities',                  'Cidades Estádio'),
        citiesLabel:    _D('Şehirler',                      'Cities',                          'Cidades'),
        selAll:         _D('Tümü',                          'All',                             'Todos'),
        selNone:        _D('Hiçbiri',                       'None',                            'Nenhum'),
        btnPreview:     _D('👁 Önizle',                      '👁 Preview',                       '👁 Pré-ver'),
        btnStart:       _D('▶ Başlat',                      '▶ Start',                         '▶ Iniciar'),
        btnStop:        _D('⏹ Durdur',                      '⏹ Stop',                          '⏹ Parar'),
        btnPause:       _D('⏸ Duraklat',                   '⏸ Pause',                         '⏸ Pausar'),
        btnResume:      _D('▶ Devam',                       '▶ Resume',                        '▶ Retomar'),
        btnExportCSV:   _D('⬇ CSV İndir',                   '⬇ Export CSV',                    '⬇ Exportar'),
        btnImportCSV:   _D('⬆ CSV Yükle',                   '⬆ Import CSV',                    '⬆ Importar'),
        btnClose:       _D('✕ Kapat',                       '✕ Close',                         '✕ Fechar'),
        btnReadme:      _D('📖 Beni Oku',                   '📖 README',                        '📖 Leia-me'),
        btnTemplates:   _D('🗺️ Turne Şablonları',          '🗺️ Tour Templates',               '🗺️ Modelos'),
        colDay:         _D('Pop Günü',                      'Pop Day',                         'Dia Pop'),
        colDate:        _D('Tarih',                         'Date',                            'Data'),
        colTime:        _D('Saat',                          'Time',                            'Hora'),
        colCity:        _D('Şehir',                         'City',                            'Cidade'),
        colVenue:       _D('Mekan',                         'Venue',                           'Local'),
        colPrice:       _D('Fiyat',                         'Price',                           'Preço'),
        venueBar:       _D('Bar',                           'Bar',                             'Bar'),
        venueStad:      _D('🏟 Stadyum',                   '🏟 Stadium',                      '🏟 Estádio'),
        warnTZ:         _D('⏰ Saat Farkı',                 '⏰ TZ Gap',                        '⏰ Fuso'),
        warnFuture:     _D('⏳ Henüz Erken',                '⏳ Too Early',                     '⏳ Cedo'),
        statusIdle:     _D('Hazır.',                        'Ready.',                          'Pronto.'),
        statusDone:     _D('✅ Tur tamamlandı!',            '✅ Tour complete!',                '✅ Turnê completa!'),
        statusFuture:   _D('⏳ Devam için bekle:',          '⏳ Wait to continue:',             '⏳ Aguardar:'),
        limit57:        _D('57 gün sınırı — plan kaydedildi.','57-day limit — plan saved.','Limite 57 dias — plano salvo.'),
        errorPaused:    _D('Hata tespit edildi, duraklatıldı.','Error detected, paused.','Erro detectado, pausado.'),
        noTour:         _D('Tur boş. Şehir veya tarih ayarlarını kontrol et.','Tour is empty.','Turnê vazia.'),
        confirmStop:    _D('Durdur ve verileri temizle?','Stop and clear data?','Parar e limpar dados?'),
        confirmApplyAll:_D('TÜM kalan konserlere uygula?','Apply to ALL remaining shows?','Aplicar a TODOS os shows?'),
        savedPlanHdr:   _D('Son Kaydedilen',                'Last Saved',                      'Último Salvo'),
        btnEdit:        _D('Düzenle',                       'Edit',                            'Editar'),
        btnStartPlan:   _D('▶ Başlat',                      '▶ Start',                         '▶ Iniciar'),
        btnNextCycle:   _D('🔄 Döngü',                      '🔄 Cycle',                        '🔄 Ciclo'),
        planName:       _D('Şema Adı',                      'Schema Name',                     'Nome do Esquema'),
        planDays:       _D('Döngü (gün)',                   'Cycle (days)',                    'Ciclo (dias)'),
        planNotes:      _D('Notlar',                        'Notes',                           'Notas'),
        btnSave:        _D('💾 Kaydet',                      '💾 Save',                          '💾 Salvar'),
        summaryShows:   _D('konser',                        'shows',                           'shows'),
    };

    // ─── PRICE GUIDE ──────────────────────────────────────────────────────────────
    const PRICE_GUIDE =[
        {score:0, label:_D('Gerçekten Berbat','Truly Abysmal','Realmente Abismal'),    min:1,  max:5  },
        {score:1, label:_D('Berbat','Abysmal','Abismal'),                              min:1,  max:6  },
        {score:2, label:_D('Yavan','Bottom Dwelling','Raso'),                          min:2,  max:7  },
        {score:3, label:_D('Korkunç','Horrendous','Horrendo'),                         min:4,  max:8  },
        {score:4, label:_D('İğrenç','Dreadful','Horrível'),                            min:6,  max:9  },
        {score:5, label:_D('Çok Kötü','Terrible','Muito Ruim'),                        min:8,  max:11 },
        {score:6, label:_D('Zayıf','Poor','Fraco'),                                    min:10, max:13 },
        {score:7, label:_D('Ortalama Altı','Below Average','Abaixo da Média'),         min:12, max:15 },
        {score:8, label:_D('Vasat','Mediocre','Mediano'),                              min:14, max:20 },
        {score:9, label:_D('Ortalama Üstü','Above Average','Acima da Média'),          min:16, max:25 },
        {score:10,label:_D('Düzgün','Decent','Decente'),                               min:18, max:30 },
        {score:11,label:_D('Hoş','Nice','Agradável'),                                  min:20, max:35 },
        {score:12,label:_D('Çok Hoş','Pleasant','Muito Agradável'),                    min:25, max:45 },
        {score:13,label:_D('İyi','Good','Bom'),                                        min:30, max:50 },
        {score:14,label:_D('Çok İyi','Sweet','Muito Bom'),                             min:35, max:55 },
        {score:15,label:_D('Şahane','Splendid','Esplêndido'),                          min:40, max:60 },
        {score:16,label:_D('Fevkalade','Awesome','Incrível'),                          min:45, max:75 },
        {score:17,label:_D('Harika','Great','Ótimo'),                                  min:50, max:80 },
        {score:18,label:_D('Müthiş','Terrific','Terrífico'),                           min:55, max:85 },
        {score:19,label:_D('Harikulade','Wonderful','Maravilhoso'),                    min:60, max:90 },
        {score:20,label:_D('İnanılmaz','Incredible','Incrível'),                       min:65, max:95 },
        {score:21,label:_D('Mükemmel','Perfect','Perfeito'),                           min:70, max:100},
        {score:22,label:_D('Çığır Açan','Revolutionary','Revolucionário'),             min:75, max:105},
        {score:23,label:_D('Akla Zarar','Mind Melting','De Cair o Queixo'),            min:80, max:110},
        {score:24,label:_D('Yeri Göğü İnleten','Earth Shaking','De Abalar a Terra'),  min:85, max:115},
        {score:25,label:_D('İHTİŞAMLI','GOD SMACKING','IMPRESSIONANTE'),               min:90, max:120},
        {score:26,label:_D('DESTANSI','G. S. GLORIOUS','GLORIOSO'),                    min:95, max:125},
    ];

    // ─── DEFAULTS ─────────────────────────────────────────────────────────────────
    const MIN_DATE_STR = fmtISO(addDays(TODAY, 3));
    const DEF = {
        tourType:'relax', tourPlan:'tt', startCityId:30,
        doubleDay:true, dpc:2, fastMode:false,
        showTimes:['14:00:00','22:00:00'],
        priceMin:30, priceMax:50, minStars:50, sortMode:'price_desc',
        startDate:MIN_DATE_STR, endDate:fmtISO(addDays(new Date(MIN_DATE_STR+'T00:00:00'), 56)),
        artistId:'', enabledCities:CITIES.map(c=>c.id), stadiumCities:[], anchors:{},
    };

    // ─── BOOKSHOW SELECTORS ───────────────────────────────────────────────────────
    const SEL = {
        venueType:'#ctl00_cphLeftColumn_ctl01_ddlVenueTypes',
        city:     '#ctl00_cphLeftColumn_ctl01_ddlCities',
        day:      '#ctl00_cphLeftColumn_ctl01_ddlDays',
        hour:     '#ctl00_cphLeftColumn_ctl01_ddlHours',
        findBtn:  '#ctl00_cphLeftColumn_ctl01_btnFindClubs',
        clubTable:'#tableclubs',
        bookBtn:  '#ctl00_cphLeftColumn_ctl01_btnBookShow',
    };
    const IS_BOOKSHOW = /\/Artist\/BookShow/i.test(window.location.pathname);
    // ─── TOUR BUILDER (v0.5 Blitz & Anchor Logic) ─────────────────────────────────
    function normLeg(l) { return typeof l==='number' ? {id:l,gapAfter:0} : {id:l.id,gapAfter:l.gapAfter||0}; }

    function buildTour(settings) {
        const typeKey = settings.tourType || 'relax';
        const planKey = settings.tourPlan || 'tt';
        const typeCfg = TOUR_TYPES[typeKey] || TOUR_TYPES['relax'];

        let rawLegs;
        if (planKey==='custom') rawLegs = parseCustomRoute(settings.customRoute||'').map(id=>({id,gapAfter:0}));
        else rawLegs = (TOUR_PLANS[planKey]?.legs||[]).map(normLeg);

        const enabled  = new Set(settings.enabledCities||DEF.enabledCities);
        const stadSet  = new Set(settings.stadiumCities||[]);
        const anchors  = settings.anchors||{};
        const minDateLimit = new Date(MIN_DATE_STR+'T00:00:00');

        let stadUsed = (() => {
            const cy=realToPM(new Date()).year, ly=gmGet(GMK.stadY,cy);
            return ly===cy ? gmGet(GMK.stadU,0) : 0;
        })();

        let sDateStr = settings.startDate; if(new Date(sDateStr+'T00:00:00') < minDateLimit) sDateStr = MIN_DATE_STR;
        const startDate = new Date(sDateStr+'T00:00:00');
        const endDate   = new Date(settings.endDate  +'T00:00:00');

// Resolve anchor dates
        const anchorDates = {}; // isoDate -> {cityId, restDays}
        const anchorCities = new Set();
        for (const[dayStr,anch] of Object.entries(anchors)) {
            if (!anch.cityId && !anch.restDays) continue;
            const pmDay = parseInt(dayStr);
            const startPM = realToPM(startDate);
            for (let yo=0; yo<=2; yo++) {
                const cand = pmToReal(startPM.year+yo, pmDay);
                if (cand>=startDate && cand<=endDate) {
                    anchorDates[fmtISO(cand)] = { cityId: anch.cityId, restDays: anch.restDays };
                    if (anch.cityId) anchorCities.add(anch.cityId);
                    break;
                }
            }
        }

        let pendingAnchors = Object.entries(anchorDates).map(([d, a]) => ({ date: new Date(d+'T00:00:00'), cityId: a.cityId, restDays: a.restDays })).sort((a,b)=>a.date-b.date);

        // Remove anchored cities from normal flow, except start/end
        const legs = rawLegs.filter((l, i) => {
            if (i === 0 || i === rawLegs.length - 1) return true;
            return !anchorCities.has(l.id);
        });

        let startIdx=0;
        if (settings.startCityId && planKey!=='custom') {
            const fi = legs.findIndex(l=>l.id===settings.startCityId);
            if (fi>0) startIdx=fi;
        }

        const orderedLegs = legs.slice(startIdx).concat(legs.slice(0, startIdx));

        let cursor = new Date(startDate);
        const tour =[];
        let blitzToggle = 0; // 0 = 14:00, 1 = 22:00

        const time22 = settings.showTimes?.includes('22:00:00') ? '22:00:00' : (settings.showTimes?.slice(-1)[0]||'22:00:00');
        const time14 = settings.showTimes?.includes('14:00:00') ? '14:00:00' : (settings.showTimes?.[0]||'14:00:00');
        const singleTime = settings.showTimes?.[0]||'22:00:00';

        for (let i=0; i<orderedLegs.length; i++) {
            const leg    = orderedLegs[i];
            const cityId = leg.id;

            if (!enabled.has(cityId)) { if (leg.gapAfter) cursor=addDays(cursor,leg.gapAfter); continue; }
            if (cursor > endDate) break;

// Dinlenme günlerini işleyen yardımcı fonksiyon
            const processAnchors = () => {
                while (pendingAnchors.length > 0 && pendingAnchors[0].date <= cursor) {
                    const anc = pendingAnchors.shift();
                    if (anc.cityId) {
                        let aTime = time22;
                        if (tour.length > 0) {
                            const lc = cityById(tour[tour.length-1].cityId), tc = cityById(anc.cityId);
                            if (lc && tc && Math.abs(lc.tz - tc.tz) > 10) aTime = '22:00:00';
                        }
                        tour.push(mkShow(anc.cityId, anc.date, aTime, stadSet.has(anc.cityId)));
                    }
                    const nextAvail = addDays(anc.date, (anc.cityId ? 1 : 0) + (anc.restDays || 0));
                    if (cursor < nextAvail) cursor = nextAvail;
                }
            };

            processAnchors();
            if (cursor > endDate) break;

            let baseT1 = time14, baseT2 = time22;
            if (tour.length > 0) {
                const lc = cityById(tour[tour.length-1].cityId), tc = cityById(cityId);
                if (lc && tc && Math.abs(lc.tz - tc.tz) > 10) baseT1 = '22:00:00';
            }

            const isStad = stadSet.has(cityId) && stadUsed<10;
            if (isStad) stadUsed++;

            const isDouble = typeCfg.blitzMode ? true : settings.doubleDay;
            const dpcVal   = typeCfg.blitzMode ? 1 : settings.dpc;

if (typeCfg.blitzMode) {
                tour.push(mkShow(cityId, cursor, blitzToggle === 0 ? baseT1 : baseT2, isStad));
                if (blitzToggle === 1) cursor = addDays(cursor, 1);
                blitzToggle = blitzToggle === 0 ? 1 : 0;
            } else if (isDouble && dpcVal >= 2) {
                tour.push(mkShow(cityId, cursor, baseT1, isStad));
                tour.push(mkShow(cityId, cursor, baseT2, false));
                cursor = addDays(cursor, 1);
            } else {
                tour.push(mkShow(cityId, cursor, isDouble ? baseT2 : singleTime, isStad));
                cursor = addDays(cursor, 1);
            }

            if (leg.gapAfter) cursor=addDays(cursor,leg.gapAfter);
        }

// Final sweep for remaining anchors
        while(pendingAnchors.length > 0 && pendingAnchors[0].date <= endDate) {
            const anc = pendingAnchors.shift();
            if (anc.cityId) tour.push(mkShow(anc.cityId, anc.date, time22, stadSet.has(anc.cityId)));
        }

        // Sort naturally by date & time
        tour.sort((a,b) => new Date(a.date+'T'+a.time) - new Date(b.date+'T'+b.time));

        // Annotate special days + warnings
        const maxBook = addDays(TODAY,57);
        for (const show of tour) {
            const d = new Date(show.date+'T00:00:00');
            const pmDay = realToPM(d).day;
            if (SPECIAL_DAYS[pmDay]) show.specialDay=pmDay;
            show.warnings=[];
            if (d>maxBook) show.warnings.push('future');
        }
        for (let i=1;i<tour.length;i++) {
            const p=cityById(tour[i-1].cityId), c=cityById(tour[i].cityId);
            if (p&&c && Math.abs(p.tz-c.tz)>8) tour[i].warnings.push('timezone');
        }

        return tour;
    }

    function mkShow(cityId, dateObj, time, wantStad) {
        return {cityId, date:fmtISO(dateObj), time, venueType:wantStad?'stadium':'bar', booked:false, skipped:false};
    }

    function parseCustomRoute(text) {
        return text.split('\n').map(l=>l.trim()).filter(Boolean).map(l=>cityByAny(l)).filter(Boolean).map(c=>c.id);
    }

    function tourSummary(tour) {
        if (!tour.length) return '';
        const cities  = new Set(tour.map(t=>t.cityId)).size;
        const stads   = tour.filter(t=>t.venueType==='stadium').length;
        const booked  = tour.filter(t=>t.booked).length;
        const future  = tour.filter(t=>(t.warnings||[]).includes('future')).length;
        let s=`${tour.length} ${T('summaryShows')} · ${cities} ${_D('şehir','cities','cidades')} · 🏟${stads}/10`;
        if (booked)  s+=` · ✅${booked}`;
        if (future)  s+=` · ⏳${future}`;
        return s;
    }

    // ─── CSV ──────────────────────────────────────────────────────────────────────
    function tourToCSV(tour, settings) {
        const BOM='\uFEFF';
        const hdr=['Pop Day','Date','Time','City','Venue','Price Min','Price Max','Status'].join(',');
        const rows=tour.map(t=>{
            const c=cityById(t.cityId), pm=realToPM(new Date(t.date+'T00:00:00'));
            const sd=t.specialDay?SPECIAL_DAYS[t.specialDay]?.icon:'';
            return[`${pm.year}-${pm.day}${sd?' '+sd:''}`, t.date, t.time.slice(0,5),
                `"${c?.en||t.cityId}"`, t.venueType==='stadium'?'Stadium':'Bar',
                settings?.priceMin??'', settings?.priceMax??'',
                t.booked?'booked':t.skipped?'skipped':''].join(',');
        });
        return BOM+[hdr,...rows].join('\r\n');
    }
    function csvToTour(csvText) {
        const lines=csvText.replace(/^\uFEFF/,'').trim().split(/\r?\n/);
        const tour = lines.slice(1).map(line=>{
            const cols=line.split(',').map(c=>c.replace(/^"|"$/g,'').trim());
            if (cols.length<4) return null;
            const city=cityByAny(cols[3]);
            if (!city) return null;
            let date=cols[1];
            if(date.includes('.')) { const p=date.split('.'); date=`${p[2]}-${p[1].padStart(2,'0')}-${p[0].padStart(2,'0')}`; }
            if(!date.match(/^\d{4}-\d{2}-\d{2}$/)) return null;
            const time=cols[2].length===5?cols[2]+':00':cols[2];
            return {cityId:city.id,date:cols[1],time,venueType:/stadium/i.test(cols[4]||'')?'stadium':'bar',booked:cols[7]==='booked',skipped:cols[7]==='skipped'};
        }).filter(Boolean);

        const maxBook = addDays(TODAY,57);
        for (const show of tour) {
            const d = new Date(show.date+'T00:00:00');
            const pmDay = realToPM(d).day;
            if (SPECIAL_DAYS[pmDay]) show.specialDay=pmDay;
            show.warnings=[];
            if (d>maxBook) show.warnings.push('future');
        }
        for (let i=1;i<tour.length;i++) {
            const p=cityById(tour[i-1].cityId), c=cityById(tour[i].cityId);
            if (p&&c && Math.abs(p.tz-c.tz)>8) tour[i].warnings.push('timezone');
        }
        return tour;
    }

    function dlCSV(text, fname) {
        const blob=new Blob([text],{type:'text/csv;charset=utf-8;'});
        const url=URL.createObjectURL(blob);
        const a=document.createElement('a'); a.href=url; a.download=fname; a.style.display='none';
        document.body.appendChild(a); a.click(); a.remove();
        setTimeout(()=>URL.revokeObjectURL(url),1000);
    }

    // ─── BOOKING ENGINE ───────────────────────────────────────────────────────────
    function isStadRow(row) { return !!(row.cells[1]?.querySelector('img[title]')); }

    function parseClubRow(row) {
        const name  = row.cells[0]?.querySelector('a')?.textContent?.trim()||'';
        const radio = row.cells[0]?.querySelector('input[type="radio"]');
        const avTxt = row.cells[1]?.textContent||'';
        const avM   = avTxt.match(/(\d+)\s*\/\s*(\d+)/);
        const stars = parseInt(row.querySelector('.sortkey')?.textContent||'0');
        const price = parseFloat((row.cells[row.cells.length-1]?.textContent||'').replace(/\s/g,'').replace(/M\$/,'').replace(',','.'))||0;
        return {name,radio,remaining:avM?(parseInt(avM[2])-parseInt(avM[1])):99,stars,price,stadium:isStadRow(row)};
    }

    function detectError() { return !!document.querySelector('.notification-real.notification-error,.notification-error'); }

    async function attemptBook(radio) {
        if (!radio) return false;
        radio.click();
        await delay(400);
        const btn=$(SEL.bookBtn); if (!btn) return false;
        btn.click();
        await delay(900);
        const ok=Array.from(document.querySelectorAll('.ui-dialog-buttonpane button,.ui-dialog button'))
            .find(b=>/yes|ok|onayla|evet|sim|confirm/i.test(b.textContent));
        if (ok) { ok.click(); await delay(1200); }
        if (detectError()) return false;
        return true;
    }

    async function findAndBook(settings, show) {
        const tbl=$(SEL.clubTable); if (!tbl) return false;

        const dayEl = $(SEL.day);
        if (dayEl && dayEl.value !== show.date) {
            log(`[Strict Match] Table loaded but date (${dayEl.value}) differs from target (${show.date}).`);
            return false;
        }

        const rows    = Array.from(tbl.querySelectorAll('tbody tr'));
        const minStar = settings.minStars ?? 50;
        const pMin    = settings.priceMin ?? DEF.priceMin;
        const pMax    = settings.priceMax ?? DEF.priceMax;
        const wantSt  = show.venueType==='stadium';
        const sort    = settings.sortMode||'price_desc';

        let cands = rows.map(parseClubRow).filter(c=>{
            if (!c.radio||c.remaining<=0) return false;
            if (c.stars < minStar) return false;
            if (c.price<pMin||c.price>pMax) return false;
            return true;
        });

        // Fallback: drop stars
        if (!cands.length) cands = rows.map(parseClubRow).filter(c=>c.radio&&c.remaining>0&&c.price>=pMin&&c.price<=pMax);

        if (wantSt) { const st=cands.filter(c=>c.stadium); cands=st.length?st:cands.filter(c=>!c.stadium); }
        else { const bars=cands.filter(c=>!c.stadium); if (bars.length) cands=bars; }

        if (sort==='price_asc')  cands.sort((a,b)=>a.price-b.price);
        else if (sort==='price_mid') { const mid=(pMin+pMax)/2; cands.sort((a,b)=>Math.abs(a.price-mid)-Math.abs(b.price-mid)); }
        else cands.sort((a,b)=>b.price-a.price);

        for (const c of cands) {
            const ok=await attemptBook(c.radio);
            if (ok) {
                if (c.stadium) {
                    const cy=realToPM(new Date()).year, ly=gmGet(GMK.stadY,cy);
                    gmSet(GMK.stadU,(ly===cy?gmGet(GMK.stadU,0):0)+1); gmSet(GMK.stadY,cy);
                }
                log(`Booked: ${c.name} (${c.price} M$) ${show.date} ${show.time}`);
                return true;
            }
            if (detectError()) { log('Error detected, pausing.'); gmSet(GMK.status,'PAUSED'); updateFloatBar(); return false; }
            await delay(400);
        }
        return false;
    }

    function waitForTable(cb, ms=20000) {
        const t0=Date.now();
        const iv=setInterval(()=>{
            if ($(SEL.clubTable)) { clearInterval(iv); cb(); }
            else if (Date.now()-t0>ms) { clearInterval(iv); log('Table timeout — pausing'); gmSet(GMK.status,'PAUSED'); updateFloatBar(); }
        },300);
    }

    // ─── PROCESS NEXT SHOW ────────────────────────────────────────────────────────
    async function processNextShow(settings) {
        if (gmGet(GMK.status,'IDLE')!=='RUNNING') return;

        const tour = gmGet(GMK.tour,[]);
        let   idx  = gmGet(GMK.idx,0);

  // Skip already-handled (booked, failed max retries, or user unchecked)
        while (idx<tour.length && (tour[idx].booked || tour[idx].skipped || tour[idx].willBook === false)) idx++;

        if (idx>=tour.length) {
            gmSet(GMK.status,'IDLE'); updateFloatBar();
            showPanelStatus(T('statusDone'),'#28a745');
            return;
        }

        const show = tour[idx];

        // 57-day limit
        const showDate=new Date(show.date+'T00:00:00');
        const maxBook =addDays(TODAY,57);
        if (showDate>maxBook) {
            const wait=Math.ceil((showDate-maxBook)/MS_DAY);
            gmSet(GMK.idx,idx); gmSet(GMK.status,'PAUSED');
            updateFloatBar(`${T('statusFuture')} ${wait}d`);
            showPanelStatus(`${T('limit57')} (+${wait}d)`,'#e67e00');
            return;
        }

        const city=cityById(show.cityId);
        updateFloatBar();
        showPanelStatus(`▶ ${idx+1}/${tour.length}: ${cityName(city)} ${show.date} ${show.time}`,'#28a745');

const handleInvalidDate = async () => {
            log(`[Strict Match] Date ${show.date} not available in dropdown. Skipping show.`);
            tour[idx]={...show, booked:false, skipped:true};
            gmSet(GMK.tour,tour); gmSet(GMK.idx,idx+1);
            await rdelay();
            window.location.href=`https://${window.location.hostname}/World/Popmundo.aspx/Artist/BookShow/${settings.artistId}`;
        };

        // Restore mode (after city postback)
        const restore=gmGet(GMK.restore,null);
        if (restore) {
            gmDel(GMK.restore);
            const dayEl=$(SEL.day), hourEl=$(SEL.hour);
            if (dayEl) { dayEl.value=restore.date; if (dayEl.value !== restore.date) return handleInvalidDate(); }
            if (hourEl) { const o=Array.from(hourEl.options).find(o=>o.value.startsWith(restore.time.slice(0,5))); if(o) hourEl.value=o.value; }
            const venEl=$(SEL.venueType); if(venEl) venEl.value='0';
            await delay(250);
            $(SEL.findBtn)?.click();
            waitForTable(()=>bookAndAdvance(settings,show,idx,tour));
            return;
        }

        // Set city
        const cityEl=$(SEL.city); if(!cityEl) return;
        if (parseInt(cityEl.value)!==show.cityId) {
            gmSet(GMK.restore,{date:show.date,time:show.time});
            cityEl.value=String(show.cityId);
            cityEl.dispatchEvent(new Event('change',{bubbles:true}));
            return; // postback
        }

        if (!$(SEL.clubTable)) {
            const dayEl=$(SEL.day), hourEl=$(SEL.hour);
            if (dayEl) { dayEl.value=show.date; if (dayEl.value !== show.date) return handleInvalidDate(); }
            if (hourEl) { const o=Array.from(hourEl.options).find(o=>o.value.startsWith(show.time.slice(0,5))); if(o) hourEl.value=o.value; }
            const venEl=$(SEL.venueType); if(venEl) venEl.value='0';
            await delay(250);
            $(SEL.findBtn)?.click();
            waitForTable(()=>bookAndAdvance(settings,show,idx,tour));
        } else {
            await bookAndAdvance(settings,show,idx,tour);
        }
    }

    async function bookAndAdvance(settings, show, idx, tour) {
        if (gmGet(GMK.status,'IDLE')!=='RUNNING') return;

        const booked = await findAndBook(settings, show);
        if (gmGet(GMK.status,'IDLE')!=='RUNNING') return;

        if (booked) {
            tour[idx] = { ...show, booked: true, skipped: false };
            delete tour[idx]._retry;
            gmSet(GMK.tour, tour);
            gmSet(GMK.idx, idx + 1);
        } else {
            const retries = (show._retry || 0) + 1;
            if (retries >= 2) {
                log(`Skipped (max retries): ${show.date} ${show.time}`);
                tour[idx] = { ...show, booked: false, skipped: true };
                delete tour[idx]._retry;
                gmSet(GMK.tour, tour);
                gmSet(GMK.idx, idx + 1);
            } else {
                log(`Retry ${retries} for: ${show.date} ${show.time}`);
                tour[idx] = { ...show, _retry: retries };
                gmSet(GMK.tour, tour);
                // Do not increment idx, so it will retry
            }
        }

        await rdelay();
        const aid=settings.artistId;
        window.location.href=`https://${window.location.hostname}/World/Popmundo.aspx/Artist/BookShow/${aid}`;
    }

    // ─── FLOATING STATUS BAR ──────────────────────────────────────────────────────

    function injectFloatBar() {
        if (document.getElementById('r49-float')) return;
        const bar=mk('div'); bar.id='r49-float';
        bar.style.cssText='position:fixed;top:0;left:0;right:0;z-index:2147483647;background:#2d1b5e;color:#fff;font-family:sans-serif;font-size:12px;display:none;align-items:center;gap:8px;padding:4px 12px;box-shadow:0 2px 8px rgba(0,0,0,.5);';
        const txt=mk('span'); txt.id='r49-float-txt'; txt.style.flex='1';
        const logBtn=mkB('📜','',()=>openLogViewer());
        logBtn.style.cssText='padding:2px 8px;border:1px solid #fcd34d;border-radius:4px;background:transparent;color:#fcd34d;cursor:pointer;font-size:11px;margin-right:4px;';
        const editBtn=mkB('✏️','',()=>openFloatEditor());
        editBtn.style.cssText='padding:2px 8px;border:1px solid #a78bfa;border-radius:4px;background:transparent;color:#a78bfa;cursor:pointer;font-size:11px;';
        editBtn.title=_D('Mevcut Konseri Düzenle','Edit Current Show','Editar Show');

        const saveBtn=mkB('💾','',()=>{
            const t=gmGet(GMK.tour,[]); const s=gmGet(GMK.sets,null);
            if(!t.length) return;
            const name = prompt(_D('Şema Adı:','Schema Name:','Nome do Esquema:'), `Saved_${fmtISO(new Date())}`);
            if (name) {
                const sc = gmGet(GMK.schemas,[]);
                sc.push({ id: Date.now(), name, tour: t, settings: s, templateDays: 56 });
                gmSet(GMK.schemas, sc);
                stopBooking();
            }
        });
        saveBtn.style.cssText='padding:2px 8px;border:1px solid #4ade80;border-radius:4px;background:transparent;color:#4ade80;cursor:pointer;font-size:11px;';
        saveBtn.title=_D('Daha Sonra Devam Et','Save & Continue Later','Salvar e Continuar Mais Tarde');

        const pbtn=mk('button'); pbtn.id='r49-float-pbtn';
        pbtn.style.cssText='padding:2px 10px;border:1px solid #fff;border-radius:4px;background:transparent;color:#fff;cursor:pointer;font-size:11px;';
        bar.append(txt,editBtn,saveBtn,pbtn);
        document.body.prepend(bar);
        setInterval(updateFloatBar,1500);
        updateFloatBar();
    }

    function updateFloatBar(customMsg) {
        const bar=document.getElementById('r49-float');
        const txt=document.getElementById('r49-float-txt');
        const pbtn=document.getElementById('r49-float-pbtn');
        if (!bar||!txt) return;

        const status=gmGet(GMK.status,'IDLE');
        const tour  =gmGet(GMK.tour,[]);
        const idx   =gmGet(GMK.idx,0);
        const sets  =gmGet(GMK.sets,null);

        if (status==='IDLE'&&!tour.length) { bar.style.display='none'; return; }
        bar.style.display='flex';

if (customMsg) { txt.textContent=customMsg; }
        else if (status==='PAUSED' || status==='RUNNING') {
            const s=tour[Math.min(idx, tour.length-1)];
            if (s) {
                const c = cityName(cityById(s.cityId)) || '?';
                const vIcon = s.venueType==='stadium'?'🏟':'🎵';
                const vName = s.venueType==='stadium'?T('venueStad'):T('venueBar');
                const p = sets ? `${sets.priceMin}-${sets.priceMax}` : '';
                const stars = sets ? Math.floor(sets.minStars/10) : '5';
                const dStr = fmtDisp(new Date(s.date+'T00:00:00'));
                const tStr = (s.time||'').slice(0,5);
                const prefix = status==='PAUSED' ? '⏸' : '▶';

                txt.textContent=`${prefix} ${vIcon} ${c} | ${dStr} | ${tStr} | ${vName} | ${p} M$ | ${stars}★ | ${idx+1}/${tour.length}`;
            } else {
                txt.textContent=`${status==='PAUSED'?'⏸':'▶'} Route49 — ${idx}/${tour.length}`;
            }
        } else {
            txt.textContent=`🌟 Route49 — ${idx}/${tour.length}`;
        }

        // Auto update active summary in schemas tab if present
        const activeSumm = document.getElementById('r49-active-summary');
        if (activeSumm) activeSumm.textContent = tourSummary(tour);

        if (pbtn) {
            pbtn.textContent=status==='PAUSED'?T('btnResume'):T('btnPause');
            pbtn.onclick=()=>{
                if (status==='PAUSED') {
                    gmSet(GMK.status,'RUNNING');
                    const s=gmGet(GMK.sets,null);
                    if (s?.artistId) window.location.href=`https://${window.location.hostname}/World/Popmundo.aspx/Artist/BookShow/${s.artistId}`;
                } else {
                    gmSet(GMK.status,'PAUSED');
                }
                updateFloatBar();
            };
        }
    }

    function openFloatEditor() {
        if (document.getElementById('r49-float-ed')) return;
        const tour=gmGet(GMK.tour,[]); const idx=gmGet(GMK.idx,0); const settings=gmGet(GMK.sets,{});
        if (!tour.length) return;
        const show=tour[Math.min(idx,tour.length-1)]; if (!show) return;

        const ov=mk('div'); ov.id='r49-float-ed';
        ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:2147483646;display:flex;align-items:center;justify-content:center;';
        const box=mk('div');
        box.style.cssText='background:#fff;border-radius:10px;padding:18px;width:360px;max-width:95vw;font-family:sans-serif;font-size:13px;box-shadow:0 6px 32px rgba(0,0,0,.4);';

        const ttl=mk('div','',_D('Mevcut Konseri Düzenle','Edit Current Show','Editar Show'));
        ttl.style.cssText='font-weight:700;font-size:14px;color:#6f42c1;margin-bottom:12px;';
        box.appendChild(ttl);

        const inpSt='width:100%;padding:5px;border:1px solid #c9b8f0;border-radius:4px;box-sizing:border-box;font-family:sans-serif;';
        const fld=(lbl,el)=>{ const w=mk('div'); w.style.marginBottom='8px'; const l=mk('label','',lbl); l.style.cssText='display:block;font-size:11px;font-weight:600;margin-bottom:3px;color:#555;'; w.append(l,el); box.appendChild(w); return el; };

        const citySel=mk('select'); citySel.style.cssText=inpSt;
        CITIES.forEach(c=>{ const o=mk('option','',cityName(c)); o.value=String(c.id); if(c.id===show.cityId) o.selected=true; citySel.appendChild(o); });
        fld(T('colCity'),citySel);

        const dateInp=mk('input'); dateInp.type='date'; dateInp.value=show.date; dateInp.style.cssText=inpSt;
        fld(T('startDate'),dateInp);

        const timeSel=mk('select'); timeSel.style.cssText=inpSt;['14:00:00','16:00:00','18:00:00','20:00:00','22:00:00'].forEach(t=>{
            const o=mk('option','',t.slice(0,5)); o.value=t; if(t===show.time||t.startsWith(show.time.slice(0,5))) o.selected=true; timeSel.appendChild(o);
        });
        fld(T('colTime'),timeSel);

        const vSel=mk('select'); vSel.style.cssText=inpSt;
        [['bar',T('venueBar')],['stadium',T('venueStad')]].forEach(([v,l])=>{ const o=mk('option','',l); o.value=v; if(v===show.venueType) o.selected=true; vSel.appendChild(o); });
        fld(T('colVenue'),vSel);

        const pRow=mk('div'); pRow.style.cssText='display:flex;gap:6px;align-items:center;';
        const pMinI=mk('input'); pMinI.type='number'; pMinI.value=settings.priceMin||DEF.priceMin; pMinI.style.cssText='width:70px;padding:5px;border:1px solid #c9b8f0;border-radius:4px;';
        const pMaxI=mk('input'); pMaxI.type='number'; pMaxI.value=settings.priceMax||DEF.priceMax; pMaxI.style.cssText='width:70px;padding:5px;border:1px solid #c9b8f0;border-radius:4px;';
        pRow.append(pMinI,mk('span','','–'),pMaxI);
        fld(T('priceRange'),pRow);

        const bRow=mk('div'); bRow.style.cssText='display:flex;gap:8px;margin-top:12px;';
        const thisB=mkB(_D('Bu Konsere','This Show','Este Show'),'',()=>{ applyEdit(show,idx,tour,settings,citySel,dateInp,timeSel,vSel,pMinI,pMaxI,false); ov.remove(); });
        const allB =mkB(_D('Tüm Kalanlara','All Remaining','Todos Restantes'),'',()=>{ if(confirm(T('confirmApplyAll'))) applyEdit(show,idx,tour,settings,citySel,dateInp,timeSel,vSel,pMinI,pMaxI,true); ov.remove(); });
        const cancB=mkB(T('btnClose'),'',()=>ov.remove());
        [thisB,allB].forEach(b=>b.style.cssText='padding:6px 12px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#6f42c1;');
        cancB.style.cssText='padding:6px 12px;border:1px solid #ccc;border-radius:5px;cursor:pointer;font-size:12px;background:#fff;';
        bRow.append(thisB,allB,cancB);
        box.appendChild(bRow);
        ov.append(box); ov.onclick=e=>{if(e.target===ov)ov.remove();}; document.body.appendChild(ov);
    }

    function applyEdit(show,idx,tour,settings,citySel,dateInp,timeSel,vSel,pMinI,pMaxI,applyAll) {
        const newCityId=parseInt(citySel.value);
        const newDate  =dateInp.value;
        const newTime  =timeSel.value;
        const newVenue =vSel.value;
        const shift    =newDate&&show.date ? Math.round((new Date(newDate+'T00:00:00')-new Date(show.date+'T00:00:00'))/MS_DAY) : 0;
        if (applyAll) {
            for (let i=idx;i<tour.length;i++) if (!tour[i].booked&&!tour[i].skipped) {
                if (shift) { const d=addDays(new Date(tour[i].date+'T00:00:00'),shift); tour[i].date=fmtISO(d); }
                tour[i].time=newTime; tour[i].venueType=newVenue;
            }
            settings.priceMin=parseFloat(pMinI.value); settings.priceMax=parseFloat(pMaxI.value);
            gmSet(GMK.sets,settings);
        } else {
            tour[idx]={...show,cityId:newCityId,date:newDate,time:newTime,venueType:newVenue};
        }
        gmSet(GMK.tour,tour);
    }

    // ─── UI HELPERS ───────────────────────────────────────────────────────────────
    const inpSt = 'padding:4px;border:1px solid #c9b8f0;border-radius:4px;box-sizing:border-box;font-family:inherit;font-size:12px;';
    const btnSt = 'padding:4px 10px;border:1px solid #6f42c1;border-radius:4px;cursor:pointer;font-size:12px;background:#e8e0f9;color:#6f42c1;font-family:inherit;';
    const fieldRow=(lbl,el,note)=>{ const w=mk('div'); w.style.cssText='margin-bottom:8px;'; const l=mk('label','',lbl); l.style.cssText='display:block;font-weight:600;font-size:11px;margin-bottom:3px;color:#444;'; w.append(l,el); if(note){const n=mk('div','',note);n.style.cssText='font-size:10px;color:#888;margin-top:2px;';w.appendChild(n);}  return w; };

    function showPanelStatus(txt,color) { const el=document.getElementById('r49-status'); if(!el) return; el.textContent=txt; if(color) el.style.color=color; }

    // ─── GATHER SETTINGS ──────────────────────────────────────────────────────────
    function gatherSettings() {
        const saved = gmGet(GMK.sets, null);
        const g=id=>document.getElementById(id);
        if (!g('r49-panel') && saved) return saved; // Panel kapalıyken eski ayarları koru (Fiyat NaN hatası çözümü)
        const type=g('r49-ttype')?.value||'relax';
        const plan=g('r49-tplan')?.value||'tt';
        const times=Array.from(document.querySelectorAll('#r49-times option:checked')).map(o=>o.value);
        const doubleDay=g('r49-doubleday')?.checked===true;
        const dpc=doubleDay && g('r49-dpc')?.checked ? 2 : 1;
        const enabledCities=CITIES.filter(c=>{const el=g(`r49-city-${c.id}`);return el?el.checked:true;}).map(c=>c.id);
        const stadiumCities=CITIES.filter(c=>g(`r49-stad-${c.id}`)?.checked).map(c=>c.id);
        const anchors={};
        for (const [day] of ANCHOR_DAYS) {
            const cityId=parseInt(g(`r49-sd-city-${day}`)?.value||'0')||null;
            const rest  =parseInt(g(`r49-sd-rest-${day}`)?.value ||'0')||0;
            if (cityId || rest > 0) anchors[day]={cityId,restDays:rest};
        }
        return {
            artistId:    g('r49-artist')?.value?.trim()||'',
            tourType:    type,
            tourPlan:    plan,
            startCityId: parseInt(g('r49-startcity')?.value||'0')||DEF.startCityId,
            customRoute: g('r49-custom')?.value||'',
            startDate:   g('r49-start')?.value||DEF.startDate,
            endDate:     g('r49-end')?.value  ||DEF.endDate,
            doubleDay, dpc,
            fastMode:    g('r49-fastmode')?.checked===true,
            showTimes:   times.length?times:DEF.showTimes,
            priceMin:    parseFloat(g('r49-pmin')?.value||String(DEF.priceMin)),
            priceMax:    parseFloat(g('r49-pmax')?.value||String(DEF.priceMax)),
            minStars:    parseInt(g('r49-minstars')?.value||'50'),
            sortMode:    g('r49-sort')?.value||'price_desc',
            enabledCities, stadiumCities, anchors,
        };
    }

    function applySettingsToUI(cfg) {
        if (!cfg) return;
        const g=id=>document.getElementById(id);
        if (cfg.fastMode !== undefined && g('r49-fastmode')) g('r49-fastmode').checked = !!cfg.fastMode;
        if (cfg.artistId    && g('r49-artist'))    g('r49-artist').value    = cfg.artistId;
        if (cfg.tourType    && g('r49-ttype'))     g('r49-ttype').value = cfg.tourType;
        if (cfg.tourPlan    && g('r49-tplan'))     { g('r49-tplan').value = cfg.tourPlan; toggleCustom(); }
        if (cfg.startCityId && g('r49-startcity')) g('r49-startcity').value = String(cfg.startCityId);
        if (cfg.startDate   && g('r49-start'))     { g('r49-start').value=cfg.startDate;  updateDL('r49-start','r49-start-lbl'); }
        if (cfg.endDate     && g('r49-end'))       { g('r49-end').value=cfg.endDate;      updateDL('r49-end',  'r49-end-lbl');   }
        if (cfg.doubleDay   !== undefined && g('r49-doubleday')) { g('r49-doubleday').checked=!!cfg.doubleDay; syncDoubleDayUI(); }
        if (cfg.dpc         !== undefined && g('r49-dpc'))       g('r49-dpc').checked = cfg.dpc>=2;
        if (cfg.priceMin    !== undefined && g('r49-pmin'))  g('r49-pmin').value=cfg.priceMin;
        if (cfg.priceMax    !== undefined && g('r49-pmax'))  g('r49-pmax').value=cfg.priceMax;
        if (cfg.minStars    !== undefined && g('r49-minstars')) g('r49-minstars').value=String(cfg.minStars);
        if (cfg.sortMode    && g('r49-sort'))       g('r49-sort').value=cfg.sortMode;
        if (Array.isArray(cfg.showTimes) && g('r49-times')) Array.from(g('r49-times').options).forEach(o=>o.selected=cfg.showTimes.includes(o.value));
        if (Array.isArray(cfg.enabledCities)) CITIES.forEach(c=>{const el=g(`r49-city-${c.id}`);if(el)el.checked=cfg.enabledCities.includes(c.id);});
        if (Array.isArray(cfg.stadiumCities)) CITIES.forEach(c=>{const el=g(`r49-stad-${c.id}`);if(el)el.checked=cfg.stadiumCities.includes(c.id);});
        if (cfg.anchors) for (const [d,a] of Object.entries(cfg.anchors)) {
            const ce=g(`r49-sd-city-${d}`); if(ce&&a.cityId) ce.value=String(a.cityId);
            const re=g(`r49-sd-rest-${d}`); if(re) re.value=String(a.restDays||0);
        }
        updateSummary();
    }

function toggleCustom() {
        const p=document.getElementById('r49-tplan')?.value;
        const t=document.getElementById('r49-ttype')?.value;
        const elC=document.getElementById('r49-custom-wrap');
        const elS=document.getElementById('r49-startcity-wrap');
        const elEnd=document.getElementById('r49-end-wrap');
        const elG2=elEnd?.parentElement;

        if (elC) elC.style.display=p==='custom'?'block':'none';
        if (elS) elS.style.display=p!=='custom'?'flex':'none';
        if (elEnd) elEnd.style.display=t==='custom'?'block':'none';
        if (elG2) elG2.style.gridTemplateColumns = t==='custom'?'repeat(auto-fit, minmax(130px, 1fr))':'1fr';
    }

    function syncDoubleDayUI() {
        const t=document.getElementById('r49-ttype')?.value;
        const dd=document.getElementById('r49-doubleday')?.checked;
        const dpcEl=document.getElementById('r49-dpc');
        const dpcRow=document.getElementById('r49-dpc-row');
        if (dpcEl) { if (!dd || t==='blitz') { dpcEl.checked=false; dpcEl.disabled=true; } else dpcEl.disabled=false; }
        if (dpcRow) dpcRow.style.opacity=(dd && t!=='blitz')?'1':'0.4';
    }

    function updateDL(inputId,labelId) {
        const inp=document.getElementById(inputId), lbl=document.getElementById(labelId);
        if(!inp||!lbl||!inp.value) return;
        lbl.textContent=dateLabel(new Date(inp.value+'T00:00:00'));
    }

    function updateSummary() {
        const el=document.getElementById('r49-summary'); if(!el) return;
        try { const s=gatherSettings(); el.textContent=tourSummary(buildTour(s)); } catch { el.textContent=''; }
    }

    function updateStadBadge() {
        const el=document.getElementById('r49-stad-badge'); if(!el) return;
        const cy=realToPM(new Date()).year, ly=gmGet(GMK.stadY,cy);
        const used=ly===cy?gmGet(GMK.stadU,0):0;
        el.textContent=`🏟 ${used}/10`; el.style.color=used>=10?'#dc3545':'#28a745';
    }

    // ─── GLOBAL OPTIMIZATION ENGINE ───────────────────────────────────────────────
    function recalcWarnings(tour) {
        const maxBook = addDays(TODAY, 57);
        let stadCountByYear = {};
        for (let i = 0; i < tour.length; i++) {
            const d = new Date(tour[i].date + 'T00:00:00');
            tour[i].warnings = [];
            if (d > maxBook) tour[i].warnings.push('future');

            if (tour[i].venueType === 'stadium' && tour[i].willBook !== false) {
                const pmYear = realToPM(d).year;
                stadCountByYear[pmYear] = (stadCountByYear[pmYear] || 0) + 1;
                if (stadCountByYear[pmYear] > 10) tour[i].warnings.push('stadium_limit');
            }

            if (i > 0) {
                const p = cityById(tour[i-1].cityId), c = cityById(tour[i].cityId);

                if (tour[i-1].date === tour[i].date && tour[i-1].cityId !== tour[i].cityId && tour[i].willBook !== false && tour[i-1].willBook !== false) {
                    tour[i].warnings.push('impossible_flight');
                }
                else if (p && c && Math.abs(p.tz - c.tz) > 8) {
                    tour[i].warnings.push('timezone');
                }
            }
        }
    }

// ─── PREVIEW MODAL ────────────────────────────────────────────────────────────
    function openPreview(extTour = null, extSettings = null, schemaId = null) {
        try {
            const settings = extSettings || gatherSettings();
            let tour = extTour ? JSON.parse(JSON.stringify(extTour)) : buildTour(settings);
            let isModified = false;

            const ov = mk('div');
            ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:99999;display:flex;align-items:flex-start;justify-content:center;padding:40px 12px;overflow-y:auto;';
            const box = mk('div');
            box.style.cssText = 'background:#fff;border-radius:10px;padding:18px;width:100%;max-width:860px;box-shadow:0 6px 32px rgba(0,0,0,.35);font-family:inherit;font-size:13px;';

            const hdr = mk('div');
            hdr.style.cssText = 'display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap;';
            const htl = mk('span','',`🌟 Route49 — ${tour.length} ${T('summaryShows')}`);
            htl.style.cssText = 'font-weight:700;font-size:15px;flex:1;color:#6f42c1;';

            const saveBtn = mkB('💾 ' + T('btnSave'), '', () => {
                if (schemaId === 'active') { gmSet(GMK.tour, tour); }
                else if (schemaId) {
                    const sc = gmGet(GMK.schemas,[]); const idx = sc.findIndex(x=>x.id===schemaId);
                    if(idx!==-1){ sc[idx].tour = tour; gmSet(GMK.schemas, sc); }
                } else {
                    gmSet(GMK.tour, tour); gmSet(GMK.idx, 0);
                }
                isModified = false;
                const tab = document.getElementById('r49-tab-saved');
                if (tab && tab.style.display === 'block') renderSchemas(tab);
                const sumEl = document.getElementById('r49-summary');
                if (sumEl && !schemaId) sumEl.textContent = tourSummary(tour);
                alert(_D('Değişiklikler kaydedildi.','Changes saved.','Alterações salvas.'));
            });

            const closeBtn = mkB(T('btnClose'), '', () => {
                if (isModified) {
                    if (confirm(_D('Değişiklikler kaydedilmeden çıkılsın mı?', 'Exit without saving?', 'Sair sem salvar?'))) {
                        ov.remove();
                    }
                } else {
                    ov.remove();
                }
            });
            saveBtn.style.cssText = btnSt;
            closeBtn.style.cssText = 'padding:5px 10px;border:1px solid #dc3545;border-radius:5px;cursor:pointer;font-size:12px;background:#fff0f0;color:#dc3545;font-family:inherit;';

            const copyBtn = mkB('📋 Kopyala', '', () => {
                const txt = tour.map(s => `${s.date} ${s.time.slice(0,5)} ${cityName(cityById(s.cityId))}`).join('\n');
                navigator.clipboard.writeText(txt); alert('Panoya kopyalandı!');
            });
            const csvBtn = mkB('⬇ CSV', '', () => dlCSV(tourToCSV(tour, settings), 'tour.csv'));
            copyBtn.style.cssText = 'padding:4px 12px;border:none;border-radius:4px;cursor:pointer;font-size:12px;font-weight:700;background:#6f42c1;color:#fff;box-shadow:0 2px 4px rgba(0,0,0,0.1);';
            csvBtn.style.cssText = btnSt;
            hdr.append(htl, copyBtn, csvBtn, saveBtn, closeBtn);
            box.appendChild(hdr);
const sumBar = mk('div','',tourSummary(tour));
            sumBar.style.cssText = 'font-size:11px;color:#6f42c1;font-weight:600;margin-bottom:10px;';
            box.appendChild(sumBar);

            // Bilgi Metni
            const intro = mk('div', '', _D('Turnede ziyaret edilecek şehirlerin sıralamasını sürükle bırak ile değiştirebilirsiniz. Aynı şehirdeki konserler bölünmeden blok halinde taşınır. Sürükleme sırasında oluşan saat dezavantajları tabloda uyarı olarak belirir. 4 saatten fazla dezavantajı olan konserleri sağdaki kutucuktan devredışı bırakmanız önerilir. Sonuçtan memnun kalırsanız kaydedin.', 'Drag and drop rows to reorder. Shows in the same city move together. Time disadvantages appear as warnings. It is recommended to disable shows with >4h disadvantage. Save when satisfied.', 'Arraste e solte para reordenar. Shows na mesma cidade movem-se juntos. Desvantagens de tempo aparecem como avisos. Recomenda-se desativar shows com desvantagem >4h. Salve quando satisfeito.'));
            intro.style.cssText = 'font-size:11px;color:#555;margin-bottom:12px;padding:8px;background:#f8f9fa;border-left:4px solid #6f42c1;border-radius:4px;';
            box.appendChild(intro);

            // Ayarla - Hepsi / Hiçbiri Butonları
            const chkBtnRow = mk('div'); chkBtnRow.style.cssText = 'display:flex;gap:8px;margin-bottom:8px;align-items:center;';
            const chkLbl = mk('span', '', _D('Tablo Kontrolü:', 'Table Control:', 'Controle da Tabela:')); chkLbl.style.cssText = 'font-size:12px;font-weight:bold;color:#6f42c1;';
            const chkAll = mkB(_D('Tümünü Ayarla', 'Set All', 'Definir Todos'), '', () => { tour.forEach(s => s.willBook = true); isModified = true; renderTable(); });
            const chkNone = mkB(_D('Hiçbirini Ayarlama', 'Set None', 'Definir Nenhum'), '', () => { tour.forEach(s => s.willBook = false); isModified = true; renderTable(); });
            [chkAll, chkNone].forEach(b => b.style.cssText = btnSt);
            chkBtnRow.append(chkLbl, chkAll, chkNone);
            box.appendChild(chkBtnRow);

            const tbl = mk('table');
            tbl.style.cssText = 'width:100%;border-collapse:collapse;font-size:12px;';

            const thead = mk('thead');
            const headRow = mk('tr');
            [T('colDay'), T('colDate'), T('colTime'), T('colCity'), T('colVenue'), T('colPrice'), '', _D('Ayarla', 'Set', 'Def.'), _D('Sil', 'Del', 'Exc.')].forEach(h => {
                const th = mk('th','',h);
                th.style.cssText = 'padding:5px 6px;text-align:left;border-bottom:2px solid #6f42c1;font-size:11px;color:#6f42c1;white-space:nowrap;';
                headRow.appendChild(th);
            });
            thead.appendChild(headRow);
            tbl.appendChild(thead);

            const tbody = mk('tbody');
            let draggedIdx = null;

            const renderTable = () => {
                tbody.innerHTML = '';
                tour.forEach((show, i) => {
                    const c = cityById(show.cityId);
                    const pm = realToPM(new Date(show.date + 'T00:00:00'));
                    const sd = show.specialDay ? SPECIAL_DAYS[show.specialDay] : null;
                    const warns = show.warnings ||[];
                    const tr = mk('tr');

                    tr.draggable = true;
                    tr.style.cursor = 'grab';
                    tr.ondragstart = e => { draggedIdx = i; e.dataTransfer.effectAllowed = 'move'; tr.style.opacity = '0.5'; };
                    tr.ondragend = e => { tr.style.opacity = '1'; };
                    tr.ondragover = e => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; tr.style.borderTop = '2px solid #6f42c1'; };
                    tr.ondragleave = e => { tr.style.borderTop = ''; };
tr.ondrop = e => {
                        e.preventDefault(); tr.style.borderTop = '';
                        if (draggedIdx === null || draggedIdx === i) return;

                        const draggedItem = tour[draggedIdx];
                        const targetItem = tour[i];

                        // Diziden çıkar ve hedefe yerleştir
                        tour.splice(draggedIdx, 1);
                        tour.splice(i, 0, draggedItem);

                        // Tarih ve zaman dizilimini temizle
                        const chronoSlots = tour.map(s => ({ date: s.date, time: s.time, specialDay: s.specialDay }));
                        chronoSlots.sort((a,b) => new Date(a.date+'T'+a.time) - new Date(b.date+'T'+b.time));

                        for (let j = 0; j < tour.length; j++) {
                            tour[j].date = chronoSlots[j].date;
                            tour[j].time = chronoSlots[j].time;
                            tour[j].specialDay = chronoSlots[j].specialDay;
                        }

                        isModified = true;
                        recalcWarnings(tour);
                        renderTable();
                    };

                    let bg = i % 2 === 0 ? '#fff' : '#faf7ff';
                    let rowFw = 'normal';
                    let rowColor = 'inherit';

                    if (sd) {
                        const cm = {'💀':'#fff0e0','🏔️':'#e8f5e9','💥':'#fff3e0','🎃':'#fff8e1','🎄':'#e8f5e9','🎉':'#f3e5f5','🦑':'#e0f7fa'};
                        bg = cm[sd.icon] || '#f3e5f5';
                        if (['💥','💀','🏔️'].includes(sd.icon)) {
                            bg = '#fed7aa'; rowFw = 'bold'; rowColor = '#9a3412';
                        }
                    }
                    if (warns.includes('future') && rowFw === 'normal') bg = '#fff9e6';
                    tr.style.background = bg;

                    let wt = ''; let wtColor = rowColor; let wtFw = rowFw; let wtTitle = '';

                    if (warns.includes('timezone') && i > 0) {
                        const pC = cityById(tour[i-1].cityId);
                        if (pC && c) {
                            const diff = c.tz - pC.tz;
                            const h = Math.abs(diff);
                            if (diff < 0) {
                                wt = '⏰ ' + _D(`+${h}s Avantaj`,`+${h}h Adv.`,`+${h}h Vant.`);
                                wtTitle = _D(`${h} Saat Avantaj`,`${h} Hours Advantage`,`${h} Horas Vantagem`);
                                wtColor = '#16a34a'; wtFw = '700';
                            } else {
                                wt = '⏰ ' + _D(`-${h}s Dezavantaj`,`-${h}h Disadv.`,`-${h}h Desv.`);
                                wtTitle = _D(`${h} Saat Dezavantaj`,`${h} Hours Disadvantage`,`${h} Horas Desvantagem`);
                                wtColor = '#dc2626'; wtFw = '700';
                            }
                        }
                    }
                    if (warns.includes('future')) {
                        wt += (wt ? ' | ' : '') + '⏳';
                        wtTitle += (wtTitle ? ' | ' : '') + T('warnFuture');
                    }

                    if (warns.includes('impossible_flight')) {
                        wt += (wt ? ' | ' : '') + '🚨 ' + _D('İmkansız!','Impossible!','Impossível!');
                        wtTitle += (wtTitle ? ' | ' : '') + _D('Aynı gün farklı şehirde konser verilemez!','Cannot play in different cities on the same day!','Não pode tocar em cidades diferentes no mesmo dia!');
                        wtColor = '#dc2626'; wtFw = '900';
                    }
                    if (warns.includes('stadium_limit')) {
                        wt += (wt ? ' | ' : '') + '❌ ' + _D('Kota Dolu','Limit Reached','Limite Atingido');
                        wtTitle += (wtTitle ? ' | ' : '') + _D('Stadyum Kotası Dolu! (Maks 10)','Stadium Limit Reached! (Max 10)','Limite de Estádio Atingido! (Max 10)');
                        wtColor = '#dc2626'; wtFw = '900';
                    }

                    if (i < tour.length - 1) {
                        const nC = cityById(tour[i+1].cityId);
                        if (c && nC) {
                            const diff = nC.tz - c.tz;
                            if (diff > 4 && show.time.startsWith('22') && i>0 && tour[i-1].date === show.date && tour[i-1].cityId === show.cityId) {
                                wt += (wt?' | ':'') + `⚠️ -${diff}s ` + _D('Riskli','Risky','Risco');
                                wtTitle += (wtTitle?' | ':'') + _D(`+${diff} Saat Dezavantaj - Bu konseri iptal etmeniz önerilir.`,`+${diff}h Disadvantage - Recommended to disable this show.`,`+${diff}h Desvantagem - Recomendado desativar este show.`);
                                wtColor = '#dc2626'; wtFw = '700';
                            }
                        }
                    }

                    let dayStr = `${sd ? sd.icon + ' ' : ''}${pm.year}-${pm.day}`;
                    let dayFw = rowFw, dayColor = rowColor;
                    if (sd && ['💥','💀','🏔️'].includes(sd.icon)) { dayFw = '900'; dayColor = '#b45309'; }

                    const setChk = mk('input'); setChk.type = 'checkbox';
                    setChk.checked = show.willBook !== false; // default true
                    if (show.booked) { setChk.disabled = true; setChk.style.opacity = '0.5'; }
                    setChk.style.cursor = 'pointer';
                    setChk.onchange = () => { show.willBook = setChk.checked; isModified = true; renderTable(); };

                    const delBtn = mkB('🗑️', '', () => { tour.splice(i, 1); isModified = true; renderTable(); });
                    delBtn.style.cssText = 'background:transparent;border:none;cursor:pointer;font-size:14px;';
                    delBtn.title = _D('Konseri Sil', 'Delete Show', 'Excluir Show');

                    const rowData =[
                        { txt: dayStr, fw: dayFw, col: dayColor },
                        { txt: fmtDisp(new Date(show.date + 'T00:00:00')) },
                        { txt: show.time.slice(0, 5) },
                        { txt: cityName(c) || show.cityId },
                        { txt: show.venueType === 'stadium' ? T('venueStad') : T('venueBar') },
                        { txt: `${settings.priceMin}–${settings.priceMax} M$` },
                        { txt: wt, fw: wtFw, col: wtColor, title: wtTitle },
                        { el: setChk },
                        { el: delBtn }
                    ];

                    rowData.forEach(d => {
                        const td = mk('td');
                        if (d.txt !== undefined) td.textContent = d.txt;
                        if (d.el) td.appendChild(d.el);
                        if (d.title) td.title = d.title;
                        td.style.cssText = `padding:4px 6px;border-bottom:1px solid #f0ecff;white-space:nowrap;font-weight:${d.fw||rowFw};color:${d.col||rowColor};`;
                        tr.appendChild(td);
                    });
                    tbody.appendChild(tr);
                });
            };


            renderTable();
            tbl.appendChild(tbody);

            const tblWrap = mk('div');
            tblWrap.style.cssText = 'width:100%;overflow-x:auto;margin-bottom:10px;';
            tblWrap.appendChild(tbl);
            box.appendChild(tblWrap);
            const legend = mk('div');

            legend.style.cssText = 'margin-top:10px;font-size:11px;color:#666;display:flex;gap:12px;flex-wrap:wrap;';
            [[T('warnTZ'), '⏰'],[T('warnFuture'), '⏳']].forEach(([l, i]) => legend.appendChild(mk('span','',`${i} = ${l}`)));
            Object.values(SPECIAL_DAYS).forEach(sd => legend.appendChild(mk('span','',`${sd.icon} = ${sd.label}`)));
            box.appendChild(legend);

            ov.append(box);
            ov.onclick = e => {
                if (e.target === ov) {
                    if (isModified && !confirm(_D('Değişiklikler kaydedilmeden çıkılsın mı?', 'Exit without saving?', 'Sair sem salvar?'))) return;
                    ov.remove();
                }
            };
            document.body.appendChild(ov);
        } catch (err) {
            console.error("[Route49] Önizleme Hatası:", err);
            alert("Önizleme oluşturulurken bir hata oluştu. Lütfen konsolu (F12) kontrol edin.");
        }
    }
    // ─── INJECT MAIN UI ───────────────────────────────────────────────────────────
    function injectUI() {
        if (document.getElementById('r49-panel')) return;
        const container=document.querySelector('#ppm-content')||document.querySelector('#content')||document.body;
        const panel=mk('div'); panel.id='r49-panel';
        panel.style.cssText='border:2px solid #6f42c1;border-radius:8px;background:#f5f0ff;padding:12px;margin-bottom:14px;font-family:inherit;font-size:13px;max-width:100%;box-sizing:border-box;';

        // Header (Title + Artist ID)
        const hdr=mk('div'); hdr.style.cssText='display:flex;align-items:center;gap:10px;margin-bottom:10px;';
        const ttl=mk('span','',T('title')); ttl.style.cssText='font-weight:700;font-size:15px;color:#6f42c1;';
        const artInp=mk('input'); artInp.id='r49-artist'; artInp.type='text'; artInp.placeholder=T('artistId');
        artInp.style.cssText=inpSt+'width:100px;font-weight:600;color:#333;';
        const urlAid=window.location.pathname.match(/\/BookShow\/(\d+)/)?.[1]; if(urlAid) artInp.value=urlAid;
        const badge=mk('span'); badge.id='r49-stad-badge'; badge.style.cssText='font-size:12px;font-weight:700;padding:2px 8px;border-radius:10px;background:#e8f5e9;margin-left:auto;';
        hdr.append(ttl,artInp,badge); panel.appendChild(hdr);

        // Tabs
        const tabBar=mk('div'); tabBar.style.cssText='display:flex;gap:4px;margin-bottom:10px;';
        const TABS=[['plan',T('tabPlan')],['saved',T('tabSaved')],['settings',T('tabSettings')]];
        const panes={};
        TABS.forEach(([id,lbl])=>{
            const btn=mkB(lbl,'',()=>{
                TABS.forEach(([tid])=>{
                    document.getElementById(`r49-tab-${tid}`)?.style.setProperty('display','none');
                    const tb=document.getElementById(`r49-tbtn-${tid}`); if(tb){tb.style.background='#e8e0f9';tb.style.color='#6f42c1';}
                });
                document.getElementById(`r49-tab-${id}`)?.style.setProperty('display','block');
                btn.style.background='#6f42c1'; btn.style.color='#fff';
                if (id==='saved') renderSchemas(panes['saved']); // Render on click
            });
            btn.id=`r49-tbtn-${id}`;
            btn.style.cssText='padding:4px 12px;border:1px solid #6f42c1;border-radius:4px;cursor:pointer;font-size:12px;background:#e8e0f9;color:#6f42c1;font-family:inherit;';
            tabBar.appendChild(btn);
            const pane=mk('div'); pane.id=`r49-tab-${id}`; pane.style.display='none';
            panes[id]=pane;
        });
        panel.appendChild(tabBar);

        // TAB: PLAN
        const plan=panes['plan'];
        const tpRow=mk('div'); tpRow.style.cssText='display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px;';
        // ── Turne Türü
        const tySel=mk('select'); tySel.id='r49-ttype'; tySel.style.cssText=inpSt+'width:100%;';
        Object.entries(TOUR_TYPES).forEach(([k,t])=>{ const o=mk('option','',t.name); o.value=k; tySel.appendChild(o); });
tySel.onchange=()=>{
            syncDoubleDayUI();
            toggleCustom();
            const cfg = TOUR_TYPES[tySel.value];
            if (cfg.durationDays) {
                const sd=document.getElementById('r49-start')?.value||MIN_DATE_STR;
                const ed=fmtISO(addDays(new Date(sd+'T00:00:00'), cfg.durationDays));
                const endEl=document.getElementById('r49-end'); if(endEl){ endEl.value=ed; updateDL('r49-end','r49-end-lbl'); }
            }
            updateSummary();
        };
        const tyWrap=fieldRow(T('tourType'),tySel); tyWrap.style.flex='1';

        // ── Turne Planı
        const plSel=mk('select'); plSel.id='r49-tplan'; plSel.style.cssText=inpSt+'width:100%;';
        Object.entries(TOUR_PLANS).forEach(([k,t])=>{ const o=mk('option','',t.name); o.value=k; plSel.appendChild(o); });
        plSel.onchange=()=>{ toggleCustom(); updateSummary(); };
        const plWrap=fieldRow(T('tourPlan'),plSel); plWrap.style.flex='1';

        tpRow.append(tyWrap, plWrap); plan.appendChild(tpRow);

        // ── Başlangıç Şehri
        const scWrap=mk('div'); scWrap.id='r49-startcity-wrap'; scWrap.style.cssText='display:flex;align-items:center;gap:8px;margin-bottom:8px;';
        const scSel=mk('select'); scSel.id='r49-startcity'; scSel.style.cssText=inpSt;
        CITIES.forEach(c=>{ const o=mk('option','',cityName(c)); o.value=String(c.id); if(c.id===DEF.startCityId)o.selected=true; scSel.appendChild(o); });
        scSel.onchange=updateSummary;
        scWrap.append(mk('label','',T('startCity')+':'),scSel);
        plan.appendChild(scWrap);

        // ── Custom route
        const customWrap=mk('div'); customWrap.id='r49-custom-wrap'; customWrap.style.display='none';
        const customTA=mk('textarea'); customTA.id='r49-custom';
        customTA.style.cssText='width:100%;height:80px;font-family:monospace;font-size:11px;border:1px solid #c9b8f0;border-radius:4px;box-sizing:border-box;padding:4px;';
        customTA.placeholder=T('customHint'); customTA.onchange=updateSummary;
        customWrap.append(customTA);
        plan.appendChild(customWrap);

        // ── Dates (2-col)
        const g2=mk('div'); g2.style.cssText='display:grid;grid-template-columns:repeat(auto-fit, minmax(130px, 1fr));gap:8px;margin-bottom:8px;';
        const mkDateW=(id,lbl,def)=>{
            const w=mk('div'); w.id=id+'-wrap';
            const l=mk('label','',lbl+':'); l.style.cssText='display:block;font-weight:600;font-size:11px;margin-bottom:3px;color:#444;';
            const inp=mk('input'); inp.type='date'; inp.id=id; inp.value=def; inp.min=MIN_DATE_STR; inp.style.cssText=inpSt+'width:100%;';
            const dl=mk('div'); dl.id=id+'-lbl'; dl.style.cssText='font-size:10px;color:#777;margin-top:1px;';
            inp.onchange=()=>{
                updateDL(id,id+'-lbl');
                if (id === 'r49-start') {
                    const tySel = document.getElementById('r49-ttype');
                    if (tySel && tySel.value !== 'custom') {
                        const cfg = TOUR_TYPES[tySel.value];
                        if (cfg && cfg.durationDays) {
                            const ed = fmtISO(addDays(new Date(inp.value+'T00:00:00'), cfg.durationDays));
                            const endEl = document.getElementById('r49-end');
                            if(endEl) { endEl.value=ed; updateDL('r49-end','r49-end-lbl'); }
                        }
                    }
                }
                updateSummary();
            };
            w.append(l,inp,dl); return w;
        };

        g2.appendChild(mkDateW('r49-start',T('startDate'),DEF.startDate));
        g2.appendChild(mkDateW('r49-end',T('endDate'),DEF.endDate));
        plan.appendChild(g2);

        // ── Times & Options (Flex row)
        const toRow=mk('div'); toRow.style.cssText='display:flex;flex-wrap:wrap;gap:12px;margin-bottom:8px;align-items:stretch;';

        const cbWrap=mk('div'); cbWrap.style.cssText='flex:1;border:1px solid #e0d8ff;border-radius:6px;padding:8px;';
        const ddRow=mk('label'); ddRow.style.cssText='display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;margin-bottom:4px;';
        const ddChk=mk('input'); ddChk.type='checkbox'; ddChk.id='r49-doubleday'; ddChk.checked=true;
        ddChk.onchange=()=>{ syncDoubleDayUI(); updateSummary(); };
        ddRow.append(ddChk, mk('span','',T('doubleDay')));

        const dpcRow=mk('div'); dpcRow.id='r49-dpc-row';
        const dpcLbl=mk('label'); dpcLbl.style.cssText='display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;';
        const dpcChk=mk('input'); dpcChk.type='checkbox'; dpcChk.id='r49-dpc'; dpcChk.checked=true;
        dpcChk.onchange=updateSummary;
        dpcLbl.append(dpcChk, mk('span','',T('showsPerCity')));
        dpcRow.appendChild(dpcLbl);
        const ddNote=mk('div','',T('showsDDNote')); ddNote.style.cssText='font-size:10px;color:#888;margin-top:4px;';
        cbWrap.append(ddRow,dpcRow,ddNote);

        const timeSel=mk('select'); timeSel.id='r49-times'; timeSel.multiple=true; timeSel.size=5;
        timeSel.style.cssText='width:120px;height:auto;overflow-y:hidden;padding:4px;border:1px solid #c9b8f0;border-radius:4px;font-size:12px;';['14:00:00','16:00:00','18:00:00','20:00:00','22:00:00'].forEach(t=>{
            const o=mk('option','',t.slice(0,5)); o.value=t; if(t==='14:00:00'||t==='22:00:00') o.selected=true; timeSel.appendChild(o);
        });
        const timeWrap=mk('div');
        const timeLbl=mk('label','',T('showTimes')); timeLbl.style.cssText='display:block;font-weight:600;font-size:11px;margin-bottom:3px;color:#444;';
        timeWrap.append(timeLbl,timeSel);

        toRow.append(cbWrap, timeWrap); plan.appendChild(toRow);

        // ── Fame score → price
        const fameSel=mk('select'); fameSel.id='r49-fame'; fameSel.style.cssText=inpSt+'width:100%;margin-bottom:5px;';
        PRICE_GUIDE.forEach(g=>{ const o=mk('option','',`${g.score}: ${g.label} → ${g.min}–${g.max}`); o.value=String(g.score); fameSel.appendChild(o); });
        fameSel.value='13';
        fameSel.onchange=()=>{ const g=PRICE_GUIDE[parseInt(fameSel.value)]; if(g){document.getElementById('r49-pmin').value=g.min;document.getElementById('r49-pmax').value=g.max;} };
        const pRow=mk('div'); pRow.style.cssText='display:flex;flex-wrap:wrap;align-items:center;gap:6px;';
        const pMin=mk('input'); pMin.id='r49-pmin'; pMin.type='number'; pMin.min='0'; pMin.value=String(PRICE_GUIDE[13].min); pMin.style.cssText='width:70px;'+inpSt;
        const pMax=mk('input'); pMax.id='r49-pmax'; pMax.type='number'; pMax.min='0'; pMax.value=String(PRICE_GUIDE[13].max); pMax.style.cssText='width:70px;'+inpSt;
        pRow.append(mk('span','','Min:'),pMin,mk('span','','–Max:'),pMax);
        const priceW=mk('div');
        const prL=mk('label','',T('fameScore')+':'); prL.style.cssText='display:block;font-weight:600;font-size:11px;margin-bottom:3px;color:#444;';
        const prL2=mk('label','',T('priceRange')+':'); prL2.style.cssText='display:block;font-weight:600;font-size:11px;margin-bottom:3px;margin-top:5px;color:#444;';
        priceW.append(prL,fameSel,prL2,pRow); priceW.style.marginBottom='8px';
        plan.appendChild(priceW);

        // ── Min stars + sort (2-col)
        const g2b=mk('div'); g2b.style.cssText='display:grid;grid-template-columns:repeat(auto-fit, minmax(130px, 1fr));gap:8px;margin-bottom:8px;';
        const starSel=mk('select'); starSel.id='r49-minstars'; starSel.style.cssText=inpSt+'width:100%;';
        [[10,'1 ★'],[20,'2 ★★'],[30,'3 ★★★'],[40,'4 ★★★★'],[50,'5 ★★★★★']].forEach(([v,l])=>{ const o=mk('option','',l); o.value=String(v); if(v===50)o.selected=true; starSel.appendChild(o); });
        const starW=fieldRow(T('minStars'),starSel);
        const sortSel=mk('select'); sortSel.id='r49-sort'; sortSel.style.cssText=inpSt+'width:100%;';
        [['price_desc',T('sortHigh')],['price_asc',T('sortLow')],['price_mid',T('sortMid')]].forEach(([v,l])=>{ const o=mk('option','',l); o.value=v; sortSel.appendChild(o); });
        const sortW=fieldRow(T('sortMode'),sortSel);
        g2b.append(starW,sortW); plan.appendChild(g2b);

        // ── Özel Gün Ayarları
        const sdSec=mk('div'); sdSec.style.cssText='margin-bottom:8px;border:1px solid #e0d8ff;border-radius:6px;padding:8px;';
        const sdTtl=mk('div','',T('sdTitle')+':'); sdTtl.style.cssText='font-weight:600;font-size:12px;margin-bottom:6px;';
        sdSec.appendChild(sdTtl);
        for (const [day,sd] of ANCHOR_DAYS) {
            const row=mk('div'); row.style.cssText='display:flex;align-items:center;gap:6px;margin-bottom:5px;flex-wrap:wrap;';
            const lbl=mk('span','',`${sd.icon} ${sd.label}`); lbl.style.cssText='font-size:11px;min-width:140px;';
            const cSel=mk('select'); cSel.id=`r49-sd-city-${day}`; cSel.style.cssText=inpSt+'flex:1;min-width:100px;';
            const noOpt=mk('option','',_D('— Seç —','— Pick —','— Escolha —')); noOpt.value='0'; cSel.appendChild(noOpt);
            CITIES.forEach(c=>{ const o=mk('option','',cityName(c)); o.value=String(c.id); cSel.appendChild(o); });
            cSel.onchange=updateSummary;
            const araSel=mk('select'); araSel.id=`r49-sd-rest-${day}`; araSel.style.cssText=inpSt+'width:110px;';
            [0,1,2,3,4,5].forEach(v=>{ const o=mk('option','',`${v} `+_D('Gün Dinlen','Days Rest','Dias Resto')); o.value=String(v); araSel.appendChild(o); });
            araSel.onchange=updateSummary;
            row.append(lbl,cSel,araSel);
            sdSec.appendChild(row);
        }
        plan.appendChild(sdSec);

        // ── Stadyum Şehirleri
        const stadSec=mk('div'); stadSec.style.cssText='margin-bottom:8px;';
        const stadTtlRow=mk('div'); stadTtlRow.style.cssText='display:flex;align-items:center;gap:8px;margin-bottom:4px;';
        const stadTtl=mk('span','',T('stadCities')+':'); stadTtl.style.cssText='font-weight:600;font-size:12px;flex:1;';
        const stNone=mkB(T('selNone'),'',()=>{ CITIES.forEach(c=>{const e=g(`r49-stad-${c.id}`);if(e)e.checked=false;}); updateSummary(); updateStadBadge(); });
        stNone.style.cssText=btnSt; stadTtlRow.append(stadTtl, stNone);
        const stadGrid=mk('div'); stadGrid.style.cssText='display:flex;flex-wrap:wrap;gap:4px;max-height:90px;overflow-y:auto;border:1px solid #e0d8ff;border-radius:4px;padding:4px;';
        CITIES.forEach(c=>{
            const lbl=mk('label'); lbl.style.cssText='display:flex;align-items:center;gap:3px;font-size:11px;background:#fff;border:1px solid #e0d8ff;border-radius:4px;padding:2px 6px;cursor:pointer;';
            const chk=mk('input'); chk.type='checkbox'; chk.id=`r49-stad-${c.id}`;
            chk.onchange=()=>{ updateSummary(); updateStadBadge(); };
            lbl.append(chk,mk('span','',cityName(c))); stadGrid.appendChild(lbl);
        });
        stadSec.append(stadTtlRow,stadGrid); plan.appendChild(stadSec);

        // ── Şehirler
        const cityTitle=mk('div'); cityTitle.style.cssText='display:flex;align-items:center;gap:8px;margin-bottom:4px;';
        const cityLbl=mk('span','',T('citiesLabel')+':'); cityLbl.style.cssText='font-weight:600;font-size:12px;flex:1;';
        const allBtn=mkB(T('selAll'),'',()=>{ CITIES.forEach(c=>{const e=document.getElementById(`r49-city-${c.id}`);if(e)e.checked=true;}); updateSummary(); });
        const noneBtn=mkB(T('selNone'),'',()=>{ CITIES.forEach(c=>{const e=document.getElementById(`r49-city-${c.id}`);if(e)e.checked=false;}); updateSummary(); });[allBtn,noneBtn].forEach(b=>b.style.cssText=btnSt);
        cityTitle.append(cityLbl,allBtn,noneBtn);
        const cityGrid=mk('div'); cityGrid.style.cssText='display:flex;flex-wrap:wrap;gap:4px;max-height:160px;overflow-y:auto;border:1px solid #e0d8ff;border-radius:4px;padding:4px;margin-bottom:8px;';
        CITIES.forEach(c=>{
            const lbl=mk('label'); lbl.style.cssText='display:flex;align-items:center;gap:3px;font-size:11px;background:#fff;border:1px solid #e0d8ff;border-radius:4px;padding:2px 6px;cursor:pointer;min-width:90px;';
            const chk=mk('input'); chk.type='checkbox'; chk.id=`r49-city-${c.id}`; chk.checked=true; chk.onchange=updateSummary;
            lbl.append(chk,mk('span','',cityName(c))); cityGrid.appendChild(lbl);
        });
        plan.append(cityTitle,cityGrid);

        // ════════════════════════════════════════════════════════════
        // TAB: ŞEMALAR (SCHEMAS)
        // ════════════════════════════════════════════════════════════
        const saved=panes['saved'];
        // Initial render deferred to tab click for performance

        // ════════════════════════════════════════════════════════════
        // TAB: SETTINGS
        // ════════════════════════════════════════════════════════════
        const sets=panes['settings'];
        sets.style.paddingTop='4px';

        // Links
        const mkLink=(lbl,url)=>{ const a=document.createElement('a'); a.href=url; a.textContent=lbl; a.target='_blank'; a.style.cssText='padding:6px 14px;border:1px solid #6f42c1;border-radius:5px;font-size:12px;color:#6f42c1;text-decoration:none;background:#fff;display:inline-block;'; return a; };
        const linkRow=mk('div'); linkRow.style.cssText='display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;';
        linkRow.append(mkLink(T('btnReadme'),'https://rentry.org/Route49oku'), mkLink(T('btnTemplates'),'https://rentry.org/Route49sablon'));
        sets.appendChild(linkRow);

        // Language buttons
        const langLbl=mk('div','',_D('Dil / Language / Idioma')); langLbl.style.cssText='font-weight:600;font-size:12px;margin-bottom:6px;';
        const langRow=mk('div'); langRow.style.cssText='display:flex;gap:6px;';
        [['TR','🇹🇷 Türkçe'],['EN','🇬🇧 English'],['PT','🇧🇷 Português']].forEach(([code,lbl])=>{
            const b=mkB(lbl,'',()=>setLang(code));
            b.style.cssText=btnSt+(LANG===code?'background:#6f42c1;color:#fff;font-weight:700;':'');
            langRow.appendChild(b);
        });
        sets.append(langLbl,langRow);

        // Advanced Settings
        const advLbl = mk('div','',_D('Gelişmiş Ayarlar','Advanced Settings','Configurações Avançadas'));
        advLbl.style.cssText='font-weight:600;font-size:12px;margin:12px 0 6px;';

        const fastLbl = mk('label'); fastLbl.style.cssText='display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;margin-bottom:8px;';
        const fastChk = mk('input'); fastChk.type='checkbox'; fastChk.id='r49-fastmode';
        fastChk.onchange = updateSummary;
        fastLbl.append(fastChk, mk('span','','⚡ ' + _D('Hızlı Mod (Riskli)','Fast Mode (Risky)','Modo Rápido (Risco)')));

        const resetBtn = mkB(_D('🔄 Varsayılanlara Dön','Reset Defaults','Redefinir Padrões'),'',()=>{
            if(confirm(_D('Tüm ayarlar sıfırlansın mı?','Reset all settings?','Redefinir tudo?'))) {
                gmDel(GMK.sets); location.reload();
            }
        });
        resetBtn.style.cssText = btnSt + 'background:#fff0f0;color:#dc3545;border-color:#dc3545;';

        sets.append(advLbl, fastLbl, resetBtn);

        // ── Append panes
        Object.values(panes).forEach(p=>panel.appendChild(p));

// (openPreview moved to global scope)

        // ── Summary + controls
        const sumEl=mk('div'); sumEl.id='r49-summary'; sumEl.style.cssText='font-size:11px;color:#555;min-height:1.2em;margin:8px 0 4px;';
        panel.appendChild(sumEl);

        const ctrlRow=mk('div'); ctrlRow.style.cssText='display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px;';
        const prevBtn=mkB(T('btnPreview'),'',()=>{
            // If there's an active tour, preview the active tour's state instead of generating a new one
            const t = gmGet(GMK.tour,[]);
            if (t.length > 0) openPreview(t, gmGet(GMK.sets,{}), 'active');
            else openPreview(); // Otherwise generate a fresh one from UI
        });
        const startBtn=mkB(T('btnStart'),'',()=>startBooking());
        const stopBtn=mkB(T('btnStop'),'',()=>{ if(confirm(T('confirmStop'))) stopBooking(); });
        prevBtn.style.cssText='padding:6px 14px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#6f42c1;';
        startBtn.style.cssText='padding:6px 14px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#28a745;';
        stopBtn.style.cssText='padding:6px 14px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#dc3545;';
        ctrlRow.append(prevBtn,startBtn,stopBtn);
        panel.appendChild(ctrlRow);

        const statusEl=mk('div'); statusEl.id='r49-status'; statusEl.style.cssText='font-size:12px;font-weight:600;color:#555;min-height:1.2em;';
        statusEl.textContent=T('statusIdle');
        panel.appendChild(statusEl);

        // Inject into page
        const ref=container.querySelector('.entityLogo')||container.querySelector('h1')||container.firstElementChild;
        if (ref) container.insertBefore(panel,ref); else container.prepend(panel);

        // Activate plan tab
        document.getElementById('r49-tbtn-plan').click();

        // Post-inject
        updateStadBadge();
        updateDL('r49-start','r49-start-lbl');
        updateDL('r49-end','r49-end-lbl');
        toggleCustom();
        syncDoubleDayUI();
        updateSummary();
    }

    // ─── ŞEMALAR (SCHEMAS) ────────────────────────────────────────────────────────
    function renderSchemas(container) {
        container.innerHTML='';

      // Yalnızca Global CSV Import Butonu (Bilgisayardan şema yüklemek için)
        const hr = mk('div'); hr.style.cssText = 'display:flex; gap:8px; margin-bottom:12px; padding-bottom:10px; border-bottom:1px solid #e0d8ff;';
        const iBtn = mkB(T('btnImportCSV'), '', () => {
            const inp = mk('input'); inp.type = 'file'; inp.accept = '.csv,text/csv';
            inp.onchange = e => {
                const f = e.target.files?.[0]; if(!f) return;
                const r = new FileReader();
                r.onload = ev => {
                    try {
                        const imp = csvToTour(String(ev.target.result));
                        if(!imp.length){ alert('No valid rows'); return; }
                        const sc = gmGet(GMK.schemas,[]);
                        sc.push({ id: Date.now(), name: `Imported_${fmtISO(new Date())}`, tour: imp, settings: DEF, templateDays: 56 });
                        gmSet(GMK.schemas, sc);
                        renderSchemas(container);
                        alert(`${imp.length} ${T('summaryShows')} OK`);
                    } catch { alert('CSV error'); }
                };
                r.readAsText(f);
            }; inp.click();
        });
        iBtn.style.cssText = btnSt;
        hr.appendChild(iBtn); container.appendChild(hr);

        // "Son Kaydedilen" = active GMK.tour
        const activeTour=gmGet(GMK.tour,[]);
        const activeSets=gmGet(GMK.sets,null);
        if (activeTour.length) {
            const hdrRow = mk('div'); hdrRow.style.cssText = 'display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;';
            const hdr=mk('div','',T('savedPlanHdr')+':'); hdr.style.cssText='font-weight:700;font-size:12px;color:#6f42c1;';
            const saveBtn=mkB(T('btnSave'), '', () => {
                const sc = gmGet(GMK.schemas,[]);
                sc.push({ id: Date.now(), name: `Schema ${fmtISO(new Date())}`, tour: activeTour, settings: activeSets, templateDays: 56 });
                gmSet(GMK.schemas, sc);
                renderSchemas(container);
            });
            saveBtn.style.cssText = 'padding:2px 8px; font-size:11px; background:#6f42c1; color:#fff; border:none; border-radius:4px; cursor:pointer;';
            hdrRow.append(hdr, saveBtn); container.appendChild(hdrRow);

            const card = buildPlanCard({id:'active', name:T('savedPlanHdr'), tour:activeTour, settings:activeSets, templateDays:56}, container);
            // Dynamic summary
            const as = mk('div', '', tourSummary(activeTour)); as.id = 'r49-active-summary'; as.style.cssText = 'font-size:11px;color:#555;margin-bottom:6px;';
            card.insertBefore(as, card.firstChild);
            container.appendChild(card);

            const sep=mk('hr'); sep.style.cssText='border:none;border-top:1px solid #e0d8ff;margin:10px 0;'; container.appendChild(sep);
        }

        // Render dynamic schemas
        const schemas = gmGet(GMK.schemas,[]);
        if (!activeTour.length && !schemas.length) {
            const emptyState = mk('div', '', _D('Henüz kaydedilmiş bir turne şeması bulunmuyor.', 'No saved tour schemas found.', 'Nenhum esquema de turnê salvo encontrado.'));
            emptyState.style.cssText = 'color:#888; font-style:italic; text-align:center; padding:20px 0; font-size:12px;';
            container.appendChild(emptyState);
        } else {
            schemas.forEach(sc => {
                const slotHdr=mk('div', '', sc.name);
                slotHdr.style.cssText='font-weight:700;font-size:12px;color:#888;margin-bottom:6px;';
                container.appendChild(slotHdr);
                container.appendChild(buildPlanCard(sc, container));
            });
        }
    }
    function buildPlanCard(planObj, tabContainer) {
        const {id, name, tour, settings, templateDays} = planObj;
        const card=mk('div'); card.style.cssText='background:#fff;border:1px solid #e0d8ff;border-radius:6px;padding:8px;margin-bottom:12px;';

const actRow = mk('div'); actRow.style.cssText='display:flex;gap:4px;margin-bottom:6px;flex-wrap:wrap;';

        const selAllBtn = mkB(T('selAll'), '', () => {
            document.querySelectorAll(`[id^="r49-plan-chk-${id}-"]:not(:disabled)`).forEach(cb=>cb.checked=true);
        });
        const selNoneBtn = mkB(T('selNone'), '', () => {
            document.querySelectorAll(`[id^="r49-plan-chk-${id}-"]:not(:disabled)`).forEach(cb=>cb.checked=false);
        });
        [selAllBtn, selNoneBtn].forEach(b => b.style.cssText='padding:2px 8px;font-size:11px;border:1px solid #c9b8f0;border-radius:4px;cursor:pointer;background:#fff;color:#6f42c1;');

const tmBtn = mkB('🚀 '+_D('İleri Sar','Auto-Forward','Avançar'), '', () => {
            if(!tour||!tour.length) return;
            let shift = 0;
            let firstDate = new Date(tour[0].date+'T00:00:00');
            const todayLimit = new Date(); todayLimit.setHours(0,0,0,0);
            const cycleDays = planObj.templateDays || 56;
            while (firstDate < todayLimit) { firstDate = addDays(firstDate, cycleDays); shift += cycleDays; }
            if (shift > 0) {
                const newTour = tour.map(s => ({...s, date: fmtISO(addDays(new Date(s.date+'T00:00:00'), shift)), booked:false, skipped:false}));
                const newPlan = {...planObj, id: Date.now() + Math.random(), tour: newTour, name: `${name} (İleri Sarıldı)`};
                const sc = gmGet(GMK.schemas,[]); sc.push(newPlan); gmSet(GMK.schemas, sc);
                renderSchemas(tabContainer);
                alert(_D('Tarihler ileri sarıldı, yeni şema kopyası oluşturuldu.','Dates forwarded, cloned to new schema.','Datas avançadas, clone criado.'));
            } else {
                alert(_D('Tarihler zaten gelecekte.','Dates are already in the future.','As datas já estão no futuro.'));
            }
        });

        tmBtn.style.cssText='padding:2px 8px;font-size:11px;border:1px solid #17a2b8;color:#17a2b8;border-radius:4px;cursor:pointer;background:#f8f9fa;';

        actRow.append(selAllBtn, selNoneBtn, tmBtn);
        card.appendChild(actRow);

        // Show list with checkboxes
        const listDiv=mk('div'); listDiv.style.cssText='max-height:160px;overflow-y:auto;border:1px solid #e0d8ff;border-radius:4px;padding:4px;margin-bottom:6px;font-size:11px;';

        (tour||[]).forEach((show,si)=>{
            const row=mk('div'); row.style.cssText='display:flex;align-items:center;gap:5px;padding:2px 4px;border-radius:3px;'+(si%2===0?'background:#faf7ff;':'');
            const chk=mk('input'); chk.type='checkbox'; chk.id=`r49-plan-chk-${id}-${si}`;
            chk.checked=!show.booked;
            if (show.booked) { chk.style.opacity='0.5'; chk.disabled=true; }

            const c=cityById(show.cityId);
            const sd=show.specialDay?SPECIAL_DAYS[show.specialDay]?.icon||'🎵':'🎵';
            const pm=realToPM(new Date(show.date+'T00:00:00'));
            const dateParts = show.date.split('-');
            const mmdd = `${dateParts[1]}-${dateParts[2]}`; // MM-DD
            const bIcon=show.booked?'✅':show.skipped?'⏭':'';
            const pMin=settings?.priceMin||0, pMax=settings?.priceMax||0;
            const stars=settings?Math.floor(settings.minStars/10):5;
            const vStr = show.venueType==='stadium' ? T('venueStad') : T('venueBar');

            // Format: 🎵 152-16 03-12 22:00 İstanbul | Bar | 10-20 M$ | 5★
            const txt=mk('span','',`${sd} ${pm.year}-${pm.day} ${mmdd} ${show.time.slice(0,5)} ${cityName(c)} | ${vStr} | ${pMin}-${pMax} M$ | ${stars}★ ${bIcon}`);
            txt.style.flex='1';
            row.append(chk,txt); listDiv.appendChild(row);
        });
        card.appendChild(listDiv);

        // Action buttons
        const btnRow=mk('div'); btnRow.style.cssText='display:flex;gap:6px;flex-wrap:wrap;';
        const editBtn=mkB(T('btnEdit'),'',()=>openSchemaEditor(planObj, tabContainer)); editBtn.style.cssText=btnSt;
        const logBtn=mkB('📜 Log','',()=>openLogViewer()); logBtn.style.cssText=btnSt;

        const startBtn=mkB(T('btnStartPlan'),'',()=>{

            const selectedTour=(tour||[]).filter((_,si)=>document.getElementById(`r49-plan-chk-${id}-${si}`)?.checked);
            if (!selectedTour.length) { alert(_D('Konser seçilmedi.','No shows selected.','Nenhum show selecionado.')); return; }
            const aid=settings?.artistId||document.getElementById('r49-artist')?.value?.trim()||'';
            if (!aid) { alert(T('artistId')+'?'); return; }
            const s={...settings, artistId:aid};
            selectedTour.forEach(show => { if (show.willBook === undefined) show.willBook = true; });
            gmSet(GMK.tour,selectedTour); gmSet(GMK.idx,0); gmSet(GMK.sets,s); gmSet(GMK.status,'CHECK_UPCOMING');
            updateFloatBar();
            window.location.href=`https://${window.location.hostname}/World/Popmundo.aspx/Artist/UpcomingPerformances/${aid}`;
        });
        startBtn.style.cssText='padding:4px 10px;border:none;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#28a745;';

        const cycPrevBtn=mkB('⏪ ' + _D('Geri Döngü','Prev Cycle','Ciclo Ant.'),'',()=>{
            const days=planObj.templateDays||56;
            const newTour=(tour||[]).map(s=>({...s,date:fmtISO(addDays(new Date(s.date+'T00:00:00'),-days)),booked:false,skipped:false}));
            const newPlan={...planObj, id: Date.now() + Math.random(), tour:newTour, name:`${name} -${days}d`};
            const sc = gmGet(GMK.schemas,[]); sc.push(newPlan); gmSet(GMK.schemas, sc);
            if (id === 'active') alert(_D('Geri döngü şeması kaydedildi.','Prev cycle schema saved.','Esquema de ciclo anterior salvo.'));
            renderSchemas(tabContainer);
        });
        const cycNextBtn=mkB('⏩ ' + _D('İleri Döngü','Next Cycle','Ciclo Seg.'),'',()=>{
            const days=planObj.templateDays||56;
            const newTour=(tour||[]).map(s=>({...s,date:fmtISO(addDays(new Date(s.date+'T00:00:00'),days)),booked:false,skipped:false}));
            const newPlan={...planObj, id: Date.now() + Math.random(), tour:newTour, name:`${name} +${days}d`};
            const sc = gmGet(GMK.schemas,[]); sc.push(newPlan); gmSet(GMK.schemas, sc);
            if (id === 'active') alert(_D('İleri döngü şeması kaydedildi.','Next cycle schema saved.','Esquema de ciclo seguinte salvo.'));
            renderSchemas(tabContainer);
        });
        [cycPrevBtn, cycNextBtn].forEach(b=>b.style.cssText=btnSt);

        const expBtn=mkB(T('btnExportCSV'),'',()=>dlCSV(tourToCSV(tour, settings), `${name.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.csv`));
        expBtn.style.cssText=btnSt;

        const schemaPrevBtn=mkB('👁 '+_D('Önizle','Preview','Pré-ver'),'',()=>openPreview(tour, settings, id));
        schemaPrevBtn.style.cssText=btnSt;

        btnRow.append(editBtn,startBtn,cycPrevBtn,cycNextBtn,schemaPrevBtn,expBtn); card.appendChild(btnRow);
        return card;
    }

    function openSchemaEditor(planObj, tabContainer) {
        if (document.getElementById('r49-plan-ed')) return;
        const ov=mk('div'); ov.id='r49-plan-ed';
        ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:99998;display:flex;align-items:center;justify-content:center;';
        const box=mk('div'); box.style.cssText='background:#fff;border-radius:10px;padding:18px;width:380px;max-width:95vw;font-family:sans-serif;font-size:13px;box-shadow:0 6px 32px rgba(0,0,0,.4);';

        const ttl=mk('div','',T('btnEdit')); ttl.style.cssText='font-weight:700;font-size:14px;color:#6f42c1;margin-bottom:12px;';
        box.appendChild(ttl);

        const ist='width:100%;padding:5px;border:1px solid #c9b8f0;border-radius:4px;box-sizing:border-box;font-family:sans-serif;font-size:12px;';

        const nameInp=mk('input'); nameInp.type='text'; nameInp.value=planObj.name||''; nameInp.style.cssText=ist;
        box.appendChild(fieldRow(T('planName'),nameInp));

        const daysInp=mk('input'); daysInp.type='number'; daysInp.min='1'; daysInp.max='365'; daysInp.value=planObj.templateDays||56; daysInp.style.cssText='width:80px;'+ist;
        box.appendChild(fieldRow(T('planDays'),daysInp));

        const notesTA=mk('textarea'); notesTA.style.cssText='height:60px;'+ist; notesTA.placeholder=T('planNotes');
        notesTA.value=planObj.notes||'';
        box.appendChild(fieldRow(T('planNotes'),notesTA));

        const bRow=mk('div'); bRow.style.cssText='display:flex;gap:8px;margin-top:12px;';
        const saveB=mkB(T('btnSave'),'',()=>{
            const updated={...planObj,name:nameInp.value,templateDays:parseInt(daysInp.value)||56,notes:notesTA.value};
            if (planObj.id === 'active') { gmSet(GMK.sets,{...planObj.settings,templateDays:parseInt(daysInp.value)||56}); }
            else {
                const sc = gmGet(GMK.schemas,[]);
                const idx = sc.findIndex(x => x.id === planObj.id);
                if (idx!==-1) { sc[idx] = updated; gmSet(GMK.schemas, sc); }
            }
            ov.remove(); renderSchemas(tabContainer);
        });
        const delB=mkB(_D('Sil','Delete','Excluir'),'',()=>{
            if (!confirm(_D('Sil?','Delete?','Excluir?'))) return;
            if (planObj.id !== 'active') {
                const sc = gmGet(GMK.schemas,[]);
                gmSet(GMK.schemas, sc.filter(x=>x.id!==planObj.id));
                renderSchemas(tabContainer);
            }
            ov.remove();
        });
        const cancB=mkB(T('btnClose'),'',()=>ov.remove());
        saveB.style.cssText='padding:6px 14px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#6f42c1;';
        delB.style.cssText='padding:6px 14px;border:none;border-radius:5px;cursor:pointer;font-size:12px;font-weight:600;color:#fff;background:#dc3545;';
        cancB.style.cssText='padding:6px 10px;border:1px solid #ccc;border-radius:5px;cursor:pointer;font-size:12px;background:#fff;';
        bRow.append(saveB, planObj.id!=='active'?delB:mk('span'), cancB);
        box.appendChild(bRow);
        ov.append(box); ov.onclick=e=>{if(e.target===ov)ov.remove();}; document.body.appendChild(ov);
    }

    // ─── START / STOP ─────────────────────────────────────────────────────────────
    async function startBooking() {
        const settings=gatherSettings();
        if (!settings.artistId) { alert(T('artistId')+'?'); return; }
        const tour=buildTour(settings);
        if (!tour.length) { alert(T('noTour')); return; }
        // Varsayılan olarak hepsini ayarla (willBook) yap
        tour.forEach(s => { if (s.willBook === undefined) s.willBook = true; });
        gmSet(GMK.tour,tour); gmSet(GMK.idx,0); gmSet(GMK.sets,settings); gmSet(GMK.status,'CHECK_UPCOMING');
        updateFloatBar();
        showPanelStatus(_D('Yaklaşan konserler kontrol ediliyor...','Checking upcoming shows...','Verificando próximos shows...'),'#6f42c1');
        const path=`/World/Popmundo.aspx/Artist/UpcomingPerformances/${settings.artistId}`;
        window.location.href=`https://${window.location.hostname}${path}`;
    }

    function stopBooking() {[GMK.status,GMK.tour,GMK.idx,GMK.sets,GMK.restore].forEach(gmDel);
        updateFloatBar(); location.reload();
    }

    function checkUpcomingAndProceed() {
        const tour = gmGet(GMK.tour, []);
        const settings = gmGet(GMK.sets, null);
        if (!tour.length || !settings) { gmSet(GMK.status, 'IDLE'); return; }

        const cityLinks = document.querySelectorAll('a[href*="/World/Popmundo.aspx/City/"]');
        const existingCityIds = new Set();
        cityLinks.forEach(a => {
            const m = a.href.match(/\/City\/(\d+)/);
            if (m) existingCityIds.add(parseInt(m[1]));
        });

        const conflictCities = new Set();
        tour.forEach(show => {
            if (existingCityIds.has(show.cityId) && !show.booked && show.willBook !== false) {
                conflictCities.add(show.cityId);
            }
        });

        if (conflictCities.size > 0) {
            const cityNames = Array.from(conflictCities).map(id => cityName(cityById(id)) || id).join(', ');
            const msg = _D(
                `Dikkat: ${cityNames} şehirlerinde halihazırda konserleriniz var!\n\nBu şehirlerdeki yeni konser planları otomatik olarak devredışı bırakılsın mı?`,
                `Warning: You already have shows in ${cityNames}!\n\nDisable new planned shows in these cities?`,
                `Aviso: Você já tem shows em ${cityNames}!\n\nDesativar novos shows planejados nestas cidades?`
            );

            if (confirm(msg)) {
                tour.forEach(show => {
                    if (conflictCities.has(show.cityId)) show.willBook = false;
                });
                gmSet(GMK.tour, tour);
            }

            if (!confirm(_D('Turne planına devam etmek istiyor musunuz?', 'Continue with tour plan?', 'Continuar com o plano?'))) {
                gmSet(GMK.status, 'IDLE');
                updateFloatBar();
                return;
            }
        }

        gmSet(GMK.status, 'RUNNING');
        window.location.href = `https://${window.location.hostname}/World/Popmundo.aspx/Artist/BookShow/${settings.artistId}`;
    }

// ─── POPCONTROL / HELPERHUB ───────────────────────────────────────────────────
    function registerWithPopControl() {
        const PC=(typeof unsafeWindow!=='undefined')&&(unsafeWindow.PopControl||unsafeWindow.HelperHub);
        if (!PC?.register) return;
        PC.register({
            id:'route49', icon:'🌟', label:'Route49',
            buttons:[{
                icon:'🌟', label:'Route49',
                onClick:()=>{ window.location.href='/World/Popmundo.aspx/Artist/BookShow/'; }
            }],
            onUndo:()=>document.getElementById('r49-panel')?.remove(),
        });
    }

    // ─── INIT ─────────────────────────────────────────────────────────────────────
    async function init() {
        // Floating bar on every page
        if (document.body) injectFloatBar(); else window.addEventListener('load',injectFloatBar);

        // PopControl
        const tryReg=()=>{ try{registerWithPopControl();}catch{} };
        tryReg(); setTimeout(tryReg,1500);

        // Migrate Old Settings to new v0.5 Architecture
        let settings = gmGet(GMK.sets, null);
        if (settings) settings = migrateSettings(settings);

        // BookShow UI
        if (IS_BOOKSHOW) {
            const tryInject=()=>{ if(!document.getElementById('r49-panel')) { injectUI(); if(settings) applySettingsToUI(settings); } };
            if (document.readyState==='complete') tryInject(); else window.addEventListener('load',tryInject);
            const iv=setInterval(()=>{ if(!document.getElementById('r49-panel')) tryInject(); },3000);
            window.addEventListener('beforeunload',()=>clearInterval(iv));
        }

        // Check running state
        const status=gmGet(GMK.status,'IDLE');

        if (status === 'CHECK_UPCOMING') {
            if (window.location.pathname.includes('/UpcomingPerformances/')) {
                checkUpcomingAndProceed();
            }
            return;
        }

        if (status!=='RUNNING') return;
        if (!settings) { gmSet(GMK.status,'IDLE'); return; }

        // If running but NOT on BookShow → redirect there
        if (!IS_BOOKSHOW) {
            const aid=settings.artistId;
            if (aid) { await delay(500); window.location.href=`https://${window.location.hostname}/World/Popmundo.aspx/Artist/BookShow/${aid}`; }
            return;
        }

        // On BookShow + RUNNING → continue
        await delay(700);
        const p=document.getElementById('r49-panel'); if(p) p.style.opacity='0.6';
        processNextShow(settings);
    }

    // ─── LOGGING SYSTEM ──────────────────────────────────────────────────────────
    function addLog(msg) {
        const logs = gmGet('r49_logs', []);
        logs.push(`[${new Date().toLocaleTimeString()}] ${msg}`);
        if(logs.length > 100) logs.shift();
        gmSet('r49_logs', logs);
    }

    function openLogViewer() {
        const ov = mk('div'); ov.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:99999;display:flex;align-items:center;justify-content:center;';
        const box = mk('div'); box.style.cssText = 'background:#fff;padding:20px;width:400px;max-height:80vh;overflow-y:auto;border-radius:8px;';
        const logs = gmGet('r49_logs', []);
        box.innerHTML = `<div style="font-weight:bold;margin-bottom:10px;">Logs</div>` + logs.map(l => `<div style="font-size:11px;border-bottom:1px solid #eee;">${l}</div>`).join('');
        box.appendChild(mkB('✕ Kapat', '', () => ov.remove()));
        ov.onclick = e => { if(e.target === ov) ov.remove(); };
        document.body.appendChild(ov);
    }

    init().catch(e=>console.error('[Route49] init error:',e));

// Global manuel entegrasyon için expose et
window.registerWithPopControl = registerWithPopControl;

})();