☰

đŸ’Ș Anaboles farmen

FarmGod vollstĂ€ndig integriert – keine externe AbhĂ€ngigkeit

Dette scriptet burde ikke installeres direkte. Det er et bibliotek for andre script Ă„ inkludere med det nye metadirektivet // @require https://update.greasyfork.org/scripts/587597/1880936/%F0%9F%92%AA%20Anaboles%20farmen.js

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         đŸ’Ș Anaboles farmen
// @version      25
// @include      https://*/game.php*screen=am_farm*
// @namespace    https://greasyfork.org/users/1388863
// @description  FarmGod vollstĂ€ndig integriert – keine externe AbhĂ€ngigkeit
// @grant        unsafeWindow
// ==/UserScript==

(function () {
    'use strict';

    // Hub-Check: respektiert den Ein/Aus-Schalter im IntelliScripts Hub (id: 'autofarm')
    function isEnabledInHub() {
        try {
            const reg = JSON.parse(localStorage.getItem('intellifarm_registry') || '{}');
            return reg.autofarm !== false; // Default: aktiviert, falls Hub fehlt/Eintrag fehlt
        } catch { return true; }
    }
    if (!isEnabledInHub()) {
        return;
    }

    // Screen-Guard: lÀuft jetzt evtl. per @require unter dem breiteren @match des Hubs,
    // daher muss die ursprĂŒngliche @include-EinschrĂ€nkung (screen=am_farm) hier im Code selbst geprĂŒft werden.
    if (typeof game_data === 'undefined' || game_data.screen !== 'am_farm') {
        return;
    }

    const domain = window.location.hostname.split('.')[0];

    const DEFAULTS = {
        enterMin: 250, enterMax: 500,
        reloadMin: 600, reloadMax: 900,
        webhookUrl: '',
        holdEnter: false, holdInterval: 50,
        optionGroup: 0, optionDistance: 25,
        optionTime: 10, optionLosses: false,
        optionMaxloot: true, optionNewbarbs: true,
        villageDistances: {},
        villageSettings: {},
        // Nachtmodus
        nightModeEnabled: false,
        nightStart: '23:00',
        nightEnd: '07:00',
        nightReloadMin: 300,
        nightReloadMax: 600,
        nightOptionTime: 20,
        nightOptionMaxloot: true,
        nightOptionLosses: false,
        // ZufÀllige Pausen
        randomPauseEnabled: false,
        randomPauseIntervalMin: 20,
        randomPauseIntervalMax: 40,
        randomPauseDurationMin: 5,
        randomPauseDurationMax: 15,
        kattaEnabled: false,
        kattaGroup: 0,
        kattaAxe: 0,
        kattaRam: 0,
        kattaSpy: 0,
        kattaCata: 1,
        kattaTarget: 'wall',
        kattaOnRed: true,
        kattaOnYellow: false,
    };

    function loadSettings() {
        try {
            const saved = JSON.parse(localStorage.getItem(domain + '_autofarm_settings') || '{}');
            const merged = Object.assign({}, DEFAULTS, saved);
            // Objekt-Felder explizit mergen damit sie nicht von DEFAULTS ĂŒberschrieben werden
            merged.villageSettings = saved.villageSettings || {};
            merged.villageDistances = saved.villageDistances || {};
            return merged;
        }
        catch (e) { return Object.assign({}, DEFAULTS); }
    }
    function saveSettings(s) { localStorage.setItem(domain + '_autofarm_settings', JSON.stringify(s)); }
    function loadPosition() { try { return JSON.parse(localStorage.getItem(domain + '_autofarm_pos') || 'null'); } catch (e) { return null; } }
    function savePosition(x, y) { localStorage.setItem(domain + '_autofarm_pos', JSON.stringify({ x, y })); }
    function loadMinimized() { return localStorage.getItem(domain + '_autofarm_minimized') === 'true'; }
    function saveMinimized(val) { localStorage.setItem(domain + '_autofarm_minimized', val); }

    let settings = loadSettings();
    let isRunning = JSON.parse(localStorage.getItem(domain + '_isRunning')) || false;
    let isMinimized = loadMinimized();
    let intervalId, holdIntervalId, countdownInterval, hourlyAlertInterval;
    let emptyFarmChecks = 0;
    let captchaAlertSent = localStorage.getItem(domain + '_captcha_paused') === 'true';
    let currentStatus = 'Bereit', currentCountdownText = '';
    let holdRepeatCount = 0;
    let todayLoot = null;
    let todayVillages = null;
    const EMPTY_FARM_THRESHOLD = 4;

    function randomDelay(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }

    // =====================================================================
    // DISCORD
    // =====================================================================
    function sendDiscordCaptchaAlert() {
        settings = loadSettings();
        if (!settings.webhookUrl) return;
        fetch(settings.webhookUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                username: 'Anaboles farmen',
                embeds: [{
                    title: '⚠ Captcha erkannt!',
                    description: 'Anaboles farmen wurde gestoppt.',
                    color: 0xe74c3c,
                    fields: [
                        { name: '🌐 Server', value: domain, inline: true },
                        { name: '🕒 Zeit', value: new Date().toLocaleString('de-DE'), inline: true },
                        { name: '🔗 Seite', value: window.location.href, inline: false }
                    ],
                    footer: { text: 'Anaboles farmen – Captcha Alert' }
                }]
            })
        }).catch(e => console.error('[Autofarm] Webhook Fehler:', e));
    }

    function sendDiscordHourlyUpdate() {
        settings = loadSettings();
        if (!settings.webhookUrl) return;
        const avg = (todayLoot && todayVillages && todayVillages.value > 0)
            ? formatLoot(Math.round(todayLoot.value / todayVillages.value)) + ' / Angriff'
            : '–';
        fetch(settings.webhookUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                username: 'Anaboles farmen',
                embeds: [{
                    title: '📊 StĂŒndliches Update',
                    description: `Anaboles farmen lÀuft auf **${domain}**`,
                    color: 0x27ae60,
                    fields: [
                        { name: '📩 Rohstoffe heute', value: todayLoot ? `${todayLoot.value.toLocaleString('de-DE')} (Rang ${todayLoot.rank})` : '–', inline: false },
                        { name: 'đŸ˜ïž Dörfer heute', value: todayVillages ? `${todayVillages.value.toLocaleString('de-DE')} (Rang ${todayVillages.rank})` : '–', inline: false },
                        { name: '⚡ Schnitt', value: avg, inline: false },
                        { name: '🕒 Zeit', value: new Date().toLocaleString('de-DE'), inline: true },
                        { name: '⚙ Status', value: isRunning ? '✅ LĂ€uft' : 'âč Gestoppt', inline: true }
                    ],
                    footer: { text: 'Anaboles farmen – StĂŒndliches Update' }
                }]
            })
        }).catch(e => console.error('[Autofarm] Webhook Fehler:', e));
    }

    const HOURLY_ALERT_KEY = domain + '_autofarm_last_hourly_alert';

    function checkAndSendHourlyAlert() {
        if (!isRunning) return;
        if (!loadSettings().webhookUrl) return;
        const last = parseInt(localStorage.getItem(HOURLY_ALERT_KEY) || '0');
        const now = Date.now();
        if (now - last >= 60 * 60 * 1000) {
            localStorage.setItem(HOURLY_ALERT_KEY, now);
            // Daten laden, dann erst senden wenn Daten wirklich da sind
            fetchTodayLoot(sendDiscordHourlyUpdate);
        }
    }

    function startHourlyAlert() {
        clearInterval(hourlyAlertInterval);
        // Timestamp nur setzen wenn noch keiner vorhanden (ĂŒberlebt Reloads)
        if (!localStorage.getItem(HOURLY_ALERT_KEY)) {
            localStorage.setItem(HOURLY_ALERT_KEY, Date.now());
        }
        // Jede Minute prĂŒfen ob eine Stunde vergangen ist (reload-sicher)
        hourlyAlertInterval = setInterval(checkAndSendHourlyAlert, 60 * 1000);
    }

    function stopHourlyAlert() {
        clearInterval(hourlyAlertInterval);
        // Timestamp zurĂŒcksetzen damit beim nĂ€chsten Start neu gezĂ€hlt wird
        localStorage.removeItem(HOURLY_ALERT_KEY);
    }

    // =====================================================================
    // TAGESERGEBNIS
    // =====================================================================
    function parseRankingPage(html) {
        const $html = $(html);
        const bodyText = $html.text ? $html.text() : $(html).text();
        const matchDE = bodyText.match(/Mein heutiges Ergebnis[^\d]*([\d\.]+)/i);
        const matchEN = bodyText.match(/My result today[^\d]*([\d,]+)/i);
        const matchRaw = matchDE || matchEN;
        let value = null;
        if (matchRaw) value = parseInt(matchRaw[1].replace(/\./g, '').replace(/,/g, ''));
        let rank = null;
        $html.find('tr').each((i, row) => {
            const $row = $(row);
            if ($row.find('b, strong').length > 0) {
                const cells = $row.find('td');
                if (cells.length >= 2) {
                    const r = parseInt(cells.eq(0).text().trim());
                    if (!isNaN(r) && r > 0) rank = r;
                }
            }
        });
        return { value, rank };
    }

    function fetchTodayLoot(callback) {
        const urlRes = TribalWars.buildURL('GET', 'ranking', { mode: 'in_a_day', type: 'loot_res' });
        const urlVil = TribalWars.buildURL('GET', 'ranking', { mode: 'in_a_day', type: 'loot_vil' });
        Promise.all([$.get(urlRes), $.get(urlVil)]).then(([htmlRes, htmlVil]) => {
            const res = parseRankingPage(htmlRes);
            const vil = parseRankingPage(htmlVil);
            if (res.value && !isNaN(res.value)) todayLoot = { value: res.value, rank: res.rank || '?', updated: new Date() };
            if (vil.value && !isNaN(vil.value)) todayVillages = { value: vil.value, rank: vil.rank || '?', updated: new Date() };
            updateLootDisplay();
            console.log(`[Autofarm] Rohstoffe: ${res.value} | Dörfer: ${vil.value}`);
            if (typeof callback === 'function') callback();
        }).catch(e => console.warn('[Autofarm] Loot-Abruf fehlgeschlagen:', e));
    }

    function formatLoot(val) {
        if (!val || isNaN(val)) return '–';
        if (val >= 1000000) return (val / 1000000).toFixed(1) + 'M';
        if (val >= 1000) return (val / 1000).toFixed(1) + 'K';
        return val.toLocaleString('de-DE');
    }

    function updateLootDisplay() {
        const mini = document.getElementById('af-loot-mini');
        const fullRes = document.getElementById('af-loot-res');
        const fullVil = document.getElementById('af-loot-vil');
        const fullAvg = document.getElementById('af-loot-avg');
        const resText = todayLoot ? `📩 ${formatLoot(todayLoot.value)} (Rang ${todayLoot.rank})` : '📩 –';
        const vilText = todayVillages ? `đŸ˜ïž ${todayVillages.value.toLocaleString('de-DE')} Dörfer (Rang ${todayVillages.rank})` : 'đŸ˜ïž –';
        const avg = (todayLoot && todayVillages && todayVillages.value > 0) ? Math.round(todayLoot.value / todayVillages.value) : null;
        const avgText = avg ? `⚡ ${formatLoot(avg)} / Angriff` : '⚡ –';
        if (mini) mini.innerHTML = `${resText}<br>${vilText}<br>${avgText}`;
        if (fullRes) fullRes.innerText = todayLoot ? `${todayLoot.value.toLocaleString('de-DE')} (Rang ${todayLoot.rank})` : '–';
        if (fullVil) fullVil.innerText = todayVillages ? `${todayVillages.value.toLocaleString('de-DE')} (Rang ${todayVillages.rank})` : '–';
        if (fullAvg) fullAvg.innerText = avg ? `${avg.toLocaleString('de-DE')} / Angriff` : '–';
    }

    // =====================================================================
    // GRUPPE ZURÜCKSETZEN
    // =====================================================================
    function resetGroupToAll() {
        if (settings.optionGroup === 0) return;
        // Gruppe im Farm-Assistenten zurĂŒck auf "Alle" (group_id 0)
        const url = TribalWars.buildURL('GET', 'am_farm', { ajax: 'change_group', group: 0 });
    }

    // =====================================================================
    // NACHTMODUS & ZUFÄLLIGE PAUSEN
    // =====================================================================
    let randomPauseTimeout = null;
    let isRandomPausing = false;

    function isNightMode() {
        settings = loadSettings();
        if (!settings.nightModeEnabled) return false;
        const now = new Date();
        const currentMinutes = now.getHours() * 60 + now.getMinutes();
        const [startH, startM] = settings.nightStart.split(':').map(Number);
        const [endH, endM] = settings.nightEnd.split(':').map(Number);
        const startMinutes = startH * 60 + startM;
        const endMinutes = endH * 60 + endM;
        // Über Mitternacht
        if (startMinutes > endMinutes) {
            return currentMinutes >= startMinutes || currentMinutes < endMinutes;
        }
        return currentMinutes >= startMinutes && currentMinutes < endMinutes;
    }

    function getReloadDelay() {
        settings = loadSettings();
        if (isNightMode()) {
            return randomDelay(settings.nightReloadMin, settings.nightReloadMax);
        }
        return randomDelay(settings.reloadMin, settings.reloadMax);
    }

    const RANDOM_PAUSE_KEY = domain + '_autofarm_next_pause';
    const RANDOM_PAUSE_ACTIVE_KEY = domain + '_autofarm_pause_active';

    // Gibt die Reload-Zeit zurĂŒck – bei fĂ€lliger Pause: lĂ€ngeres Intervall
    function getRandomPauseReloadDelay(normalDelay) {
        settings = loadSettings();
        if (!settings.randomPauseEnabled) return normalDelay;
        // ZufÀllige Pausen nur im Nachtmodus wenn nightModeEnabled
        if (settings.nightModeEnabled && !isNightMode()) return normalDelay;

        const now = Date.now();
        const nextPause = parseInt(localStorage.getItem(RANDOM_PAUSE_KEY) || '0');

        if (nextPause === 0) {
            // Ersten Pause-Zeitpunkt setzen
            const intervalSec = randomDelay(
                settings.randomPauseIntervalMin * 60,
                settings.randomPauseIntervalMax * 60
            );
            localStorage.setItem(RANDOM_PAUSE_KEY, now + intervalSec * 1000);
            console.log(`[Autofarm] NĂ€chste Pause in ${Math.round(intervalSec/60)} Min`);
            return normalDelay;
        }

        if (now >= nextPause) {
            // Pause fĂ€llig – lĂ€ngeres Reload-Intervall verwenden
            const durationSec = randomDelay(
                settings.randomPauseDurationMin * 60,
                settings.randomPauseDurationMax * 60
            );
            // NĂ€chste Pause einplanen ab jetzt + Pausendauer + normales Intervall
            const intervalSec = randomDelay(
                settings.randomPauseIntervalMin * 60,
                settings.randomPauseIntervalMax * 60
            );
            localStorage.setItem(RANDOM_PAUSE_KEY, now + durationSec * 1000 + intervalSec * 1000);
            localStorage.setItem(RANDOM_PAUSE_ACTIVE_KEY, '1');
            console.log(`[Autofarm] Pause fÀllig: ${Math.round(durationSec/60)} Min lÀngeres Reload`);
            isRandomPausing = true;
            return durationSec; // Reload-Intervall = Pausendauer
        }

        return normalDelay;
    }

    function scheduleRandomPause(callback) {
        callback(); // direkt aufrufen – Pause-Logik ist in startCountdown integriert
    }

    function clearRandomPause() {
        if (randomPauseTimeout) { clearTimeout(randomPauseTimeout); randomPauseTimeout = null; }
        localStorage.removeItem(RANDOM_PAUSE_KEY);
        localStorage.removeItem(RANDOM_PAUSE_ACTIVE_KEY);
        isRandomPausing = false;
    }

    // =====================================================================
    // FARMGOD LIBRARY
    // =====================================================================
    const FarmLib = (function () {
        if (typeof window.twLib === 'undefined') {
            window.twLib = {
                queues: null,
                init: function () { if (this.queues === null) this.queues = this.queueLib.createQueues(5); },
                queueLib: {
                    maxAttempts: 3,
                    Item: function (action, arg, promise = null) { this.action = action; this.arguments = arg; this.promise = promise; this.attempts = 0; },
                    Queue: function () {
                        this.list = []; this.working = false; this.length = 0;
                        this.doNext = function () {
                            let item = this.dequeue(), self = this;
                            $[item.action](...item.arguments)
                                .done(function () { item.promise.resolve.apply(null, arguments); self.start(); })
                                .fail(function () { item.attempts += 1; if (item.attempts < twLib.queueLib.maxAttempts) self.enqueue(item, true); else item.promise.reject.apply(null, arguments); self.start(); });
                        };
                        this.start = function () { if (this.length) { this.working = true; this.doNext(); } else this.working = false; };
                        this.dequeue = function () { this.length -= 1; return this.list.shift(); };
                        this.enqueue = function (item, front = false) { front ? this.list.unshift(item) : this.list.push(item); this.length += 1; if (!this.working) this.start(); };
                    },
                    createQueues: function (amount) { let arr = []; for (let i = 0; i < amount; i++) arr[i] = new twLib.queueLib.Queue(); return arr; },
                    addItem: function (item) { let min = twLib.queues.map(q => q.length).reduce((n, c) => (c < n ? c : n), 0); twLib.queues[min].enqueue(item); },
                    orchestrator: function (type, arg) { let p = $.Deferred(); twLib.queueLib.addItem(new twLib.queueLib.Item(type, arg, p)); return p; },
                },
                ajax: function () { return twLib.queueLib.orchestrator('ajax', arguments); },
                get: function () { return twLib.queueLib.orchestrator('get', arguments); },
                post: function () { return twLib.queueLib.orchestrator('post', arguments); },
            };
            twLib.init();
        }

        const setUnitSpeeds = () => $.when($.get('/interface.php?func=get_unit_info')).then((xml) => {
            let u = {}; $(xml).find('config').children().map((i, el) => { u[$(el).prop('nodeName')] = $(el).find('speed').text().toNumber(); });
            localStorage.setItem('FarmGod_unitSpeeds', JSON.stringify(u));
        });
        const getUnitSpeeds = () => JSON.parse(localStorage.getItem('FarmGod_unitSpeeds')) || false;
        if (!getUnitSpeeds()) setUnitSpeeds();

        const determineNextPage = (page, $html) => {
            let vl = $html.find('#scavenge_mass_screen').length > 0 ? $html.find('tr[id*="scavenge_village"]').length : $html.find('tr.row_a, tr.row_ax, tr.row_b, tr.row_bx').length;
            let ns = $html.find('.paged-nav-item').first().closest('td').find('select').first();
            let nl = $html.find('#am_widget_Farm').length > 0
                ? parseInt($('#plunder_list_nav').first().find('a.paged-nav-item, strong.paged-nav-item')[$('#plunder_list_nav').first().find('a.paged-nav-item, strong.paged-nav-item').length - 1].textContent.replace(/\D/g, '')) - 1
                : ns.length > 0 ? ns.find('option').length - 1 : $html.find('.paged-nav-item').not('[href*="page=-1"]').length;
            let ps = $('#mobileHeader').length > 0 ? 10 : parseInt($html.find('input[name="page_size"]').val());
            if (page == -1 && vl == 1000) return Math.floor(1000 / ps);
            else if (page < nl) return page + 1;
            return false;
        };

        const processPage = (url, page, wrapFn) => {
            const fullUrl = url + (url.match('am_farm') ? `&Farm_page=${page}` : `&page=${page}`);
                        return twLib.ajax({ url: fullUrl }).then((html) => {
                return wrapFn(page, $(html));
            }).catch(e => {
                console.error(`[AF] processPage ERROR p=${page}:`, e);
                throw e;
            });
        };
        const processAllPages = (url, processorFn) => {
            let page = url.match('am_farm') || url.match('scavenge_mass') ? 0 : -1;
            let wrapFn = (page, $html) => { let dnp = determineNextPage(page, $html);if (dnp) { processorFn($html); return processPage(url, dnp, wrapFn); } else return processorFn($html); };
            return processPage(url, page, wrapFn);
        };

        const getDistance = (o, t) => Math.hypot(o.toCoord(true).x - t.toCoord(true).x, o.toCoord(true).y - t.toCoord(true).y);
        const subtractArrays = (a1, a2) => { let r = a1.map((v, i) => v - a2[i]); return r.some(v => v < 0) ? false : r; };
        const getCurrentServerTime = () => { let [h, m, s, d, mo, y] = $('#serverTime').closest('p').text().match(/\d+/g); return new Date(y, mo - 1, d, h, m, s).getTime(); };
        const timestampFromString = (timestr) => {
            try {
            const lang = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).lang;
            if (!lang) return 0;
            let d = $('#serverDate').text().split('/').map(x => +x);
            let tp = new RegExp(lang['aea2b0aa9ae1534226518faaefffdaad'].replace('%s', '([\\d+|:]+)')).exec(timestr);
            let tom = new RegExp(lang['57d28d1b211fddbb7a499ead5bf23079'].replace('%s', '([\\d+|:]+)')).exec(timestr);
            let lat = new RegExp(lang['0cb274c906d622fa8ce524bcfbb7552d'].replace('%1', '([\\d+|\\.]+)').replace('%2', '([\\d+|:]+)')).exec(timestr);
            let t, date;
            if (tp) { t = tp[1].split(':'); date = new Date(d[2], d[1]-1, d[0], t[0], t[1], t[2], t[3]||0); }
            else if (tom) { t = tom[1].split(':'); date = new Date(d[2], d[1]-1, d[0]+1, t[0], t[1], t[2], t[3]||0); }
            else if (lat) { d = (lat[1]+d[2]).split('.').map(x=>+x); t = lat[2].split(':'); date = new Date(d[2], d[1]-1, d[0], t[0], t[1], t[2], t[3]||0); }
            else return 0;
            return date.getTime();
            } catch(e) { return 0; }
        };

        if (!String.prototype.toCoord) String.prototype.toCoord = function (o) { let c = (this.match(/\d{1,3}\|\d{1,3}/g)||[false]).pop(); return c && o ? {x:c.split('|')[0],y:c.split('|')[1]} : c; };
        if (!String.prototype.toNumber) String.prototype.toNumber = function () { return parseFloat(this); };
        if (!Number.prototype.toNumber) Number.prototype.toNumber = function () { return parseFloat(this); };

        return { getUnitSpeeds, processPage, processAllPages, getDistance, subtractArrays, getCurrentServerTime, timestampFromString };
    })();


    // =====================================================================
    // KATTA ENGINE — Rot/Gelb Angriffe
    // =====================================================================
    const KATTA_SENT_KEY = domain + '_katta_sent';
    let kattaAllFarms = {}; // wird nach getData befĂŒllt // {coord: timestamp}

    function kattaLoadSent() {
        try { return JSON.parse(localStorage.getItem(KATTA_SENT_KEY) || '{}'); } catch(e) { return {}; }
    }
    function kattaSaveSent(obj) { localStorage.setItem(KATTA_SENT_KEY, JSON.stringify(obj)); }

    function kattaShouldAttack(coord, color) {
        const s = loadSettings();
        if (!s.kattaEnabled) return false;
        if (color === 'red' && !s.kattaOnRed) return false;
        if (color === 'yellow' && !s.kattaOnYellow) return false;
        if (color !== 'red' && color !== 'yellow') return false;
        const sent = kattaLoadSent();
        if (!sent[coord]) return true; // noch nie geschickt
        const age = Date.now() - sent[coord];
        return age >= 24 * 60 * 60 * 1000; // Àlter als 24h
    }

    function kattaMarkSent(coord) {
        const sent = kattaLoadSent();
        sent[coord] = Date.now();
        kattaSaveSent(sent);
    }

    // WÀhlt nÀchstes Dorf aus Gruppe das genug Truppen hat
    // LĂ€dt unitMap mit direktem fetch (nicht twLib-Queue) um Farm-Loop nicht zu blockieren
    async function kattaLoadUnitMap(group) {
        const gd = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).game_data;
        const csrf = gd && gd.csrf;
        const villages = await FarmGodCore.loadVillages(group);
        const unitMap = {};

        const fetchPage = async (page) => {
            const url = `/game.php?village=${gd.village.id}&screen=overview_villages&mode=combined&group=${group}&page=${page}&h=${csrf}`;
            const html = await fetch(url, { credentials: 'include' }).then(r => r.text());
            const $html = $(html);
            const units = gd.units; // ["spear","sword","axe",...]
            $html.find('#combined_table').find('.row_a,.row_b').each((i, el) => {
                const $el = $(el);
                const coord = $el.find('.quickedit-label').first().text().trim().match(/\d+\|\d+/)?.[0];
                if (!coord) return;
                const unitItems = $el.find('.unit-item');
                unitMap[coord] = {
                    id:       villages[coord] && villages[coord].id,
                    axe:      parseInt(unitItems.eq(units.indexOf('axe')).text())      || 0,
                    ram:      parseInt(unitItems.eq(units.indexOf('ram')).text())      || 0,
                    spy:      parseInt(unitItems.eq(units.indexOf('spy')).text())      || 0,
                    catapult: parseInt(unitItems.eq(units.indexOf('catapult')).text()) || 0,
                };
            });
            // NĂ€chste Seite prĂŒfen
            const nextMatch = $html.find('#pager_form').find('input[name=page]').attr('max');
            return nextMatch ? parseInt(nextMatch) : page;
        };

        let page = 0;
        const maxPage = await fetchPage(0);
        for (let p = 1; p <= maxPage; p++) {
            await fetchPage(p);
        }
        return unitMap;
    }

    // WÀhlt nÀchstes Dorf aus unitMap das genug Truppen hat (nach Distanz)
    function kattaFindVillage(targetCoord, troops, unitMap) {
        const candidates = Object.entries(unitMap)
            .filter(([, u]) =>
                u.id &&
                u.axe      >= troops.axe &&
                u.ram      >= troops.ram &&
                u.spy      >= troops.spy &&
                u.catapult >= troops.catapult
            )
            .map(([coord, u]) => ({ coord, id: u.id, dist: FarmLib.getDistance(coord, targetCoord) }))
            .sort((a, b) => a.dist - b.dist);
        return candidates[0] || null;
    }

    // Zieht verplante Truppen lokal ab
    function kattaReserveTroops(unitMap, coord, troops) {
        if (!unitMap[coord]) return;
        unitMap[coord].axe      -= troops.axe;
        unitMap[coord].ram      -= troops.ram;
        unitMap[coord].spy      -= troops.spy;
        unitMap[coord].catapult -= troops.catapult;
    }

    async function kattaSendAttack(villageId, target, troops, building) {
        const base = window.location.origin + '/game.php';
        const gd = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).game_data;
        const csrf = gd && gd.csrf;
        if (!csrf) throw new Error('CSRF fehlt');

        // Schritt 1: Versammlungsplatz im iframe laden → CSRF-Feldname holen
        const { tokenField, tokenValue } = await new Promise((resolve, reject) => {
            const iframe = document.createElement('iframe');
            iframe.style.cssText = 'display:none;width:0;height:0;border:0;';
            iframe.src = `${base}?village=${villageId}&screen=place`;
            iframe.onload = () => {
                try {
                    const iDoc = iframe.contentDocument || iframe.contentWindow.document;
                    let tokenField = null, tokenValue = null;
                    iDoc.querySelectorAll('input[type=hidden]').forEach(inp => {
                        if (/^[0-9a-f]{10,}$/.test(inp.name)) { tokenField = inp.name; tokenValue = inp.value; }
                    });
                    document.body.removeChild(iframe);
                    if (tokenField) resolve({ tokenField, tokenValue });
                    else reject(new Error('Token nicht im iframe'));
                } catch(e) { document.body.removeChild(iframe); reject(e); }
            };
            iframe.onerror = () => { document.body.removeChild(iframe); reject(new Error('iframe Fehler')); };
            document.body.appendChild(iframe);
        });

        // Schritt 2: try=confirm
        const step2params = new URLSearchParams({
            source_village: villageId,
            x: target.x,
            y: target.y,
            target_type: 'coord',
            input: `${target.x}|${target.y}`,
            attack: 'Angreifen',
            template_id: '',
            spy:      troops.spy      || 0,
            axe:      troops.axe      || 0,
            ram:      troops.ram      || 0,
            catapult: troops.catapult || 0,
            spear: 0, sword: 0, archer: 0, light: 0, marcher: 0, heavy: 0, snob: 0,
        });
        step2params.set(tokenField, tokenValue);

        const step2html = await fetch(`${base}?village=${villageId}&screen=place&try=confirm&h=${csrf}`, {
            method: 'POST', credentials: 'include',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: step2params.toString(),
        }).then(r => r.text());

        // Schritt 3: BestÀtigung
        const step3params = new URLSearchParams();
        for (const [, name, value] of step2html.matchAll(/name="([^"]+)"\s+value="([^"]*)"/g)) {
            step3params.set(name, value);
        }
        if (!step3params.has('ch')) throw new Error('ch-Token fehlt in BestÀtigungsseite');

        // Katapult-ZielgebÀude setzen falls in BestÀtigungsseite ein building-Select vorhanden
        step3params.set('building', building || 'wall');
        step3params.set('h', csrf);
        step3params.set('cb', 'troop_confirm_submit');
        step3params.set('submit_confirm', 'Angreifen');
        step3params.set('attack_name', '');

        const step3res = await fetch(`${base}?village=${villageId}&screen=place&action=command`, {
            method: 'POST', credentials: 'include',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Referer': `${base}?village=${villageId}&screen=place&try=confirm`,
            },
            body: step3params.toString(),
        });
        if (!step3res.ok) throw new Error(`HTTP ${step3res.status}`);
    }

    // Hauptfunktion: alle rot/gelben Farmen prĂŒfen und Katta-Angriffe schicken
    let kattaPhaseRunning = false;
    async function runKattaPhase(farms) {
        const s = loadSettings();
        if (!s.kattaEnabled) return;
        if (kattaPhaseRunning) { console.log('[Katta] Phase lĂ€uft bereits — ĂŒbersprungen'); return; }
        kattaPhaseRunning = true;

        const troops = {
            axe:      parseInt(s.kattaAxe)  || 0,
            ram:      parseInt(s.kattaRam)  || 0,
            spy:      parseInt(s.kattaSpy)  || 0,
            catapult: parseInt(s.kattaCata) || 0,
        };

        // Katta-Log bereinigen: Dörfer die jetzt grĂŒn/blau sind rausnehmen
        const sent = kattaLoadSent();
        let cleaned = 0;
        Object.entries(farms).forEach(([coord, f]) => {
            if (sent[coord] && (f.color === 'green' || f.color === 'blue')) {
                delete sent[coord];
                cleaned++;
            }
        });
        if (cleaned > 0) { kattaSaveSent(sent); console.log(`[Katta] ${cleaned} Dörfer aus Log entfernt (jetzt grĂŒn/blau)`); }

        // Duplikate vermeiden: Set der bereits in dieser Runde angegriffenen Coords
        const attackedThisRound = new Set();
        const targets = Object.entries(farms)
            .filter(([coord, f]) => kattaShouldAttack(coord, f.color))
            .filter(([coord]) => { if (attackedThisRound.has(coord)) return false; attackedThisRound.add(coord); return true; })
            .map(([coord, f]) => ({ coord, f }));

        if (!targets.length) return;

        setStatus(`⚔ ${targets.length} Katta-Angriffe werden geprĂŒft...`, '#e67e22');

        // Einmalig unitMap laden — Truppen werden lokal abgezogen
        const unitMap = await kattaLoadUnitMap(s.kattaGroup);

        let sentCount = 0;
        for (const { coord } of targets) {
            try {
                const [x, y] = coord.split('|');
                const village = kattaFindVillage(coord, troops, unitMap);
                if (!village) {
                    console.log(`[Katta] Kein Dorf mit Truppen fĂŒr ${coord} — ĂŒbersprungen`);
                    continue;
                }

                await kattaSendAttack(village.id, { x, y }, troops, s.kattaTarget);
                kattaReserveTroops(unitMap, village.coord, troops); // lokal abziehen
                kattaMarkSent(coord);
                sentCount++;
                console.log(`[Katta] ✓ ${coord} von ${village.coord} (${sentCount}/${targets.length})`);

                if (targets.indexOf(targets.find(t => t.coord === coord)) < targets.length - 1) {
                    await new Promise(r => setTimeout(r, 500 + Math.random() * 200));
                }
            } catch(e) {
                console.error(`[Katta] Fehler bei ${coord}:`, e);
            }
        }
        setStatus(`✅ ${sentCount} Katta-Angriffe gesendet`, '#27ae60');
        kattaPhaseRunning = false;
    }

    // =====================================================================
    // FARMGOD KERN
    // =====================================================================
    const FarmGodCore = (function (lib) {
        let farmBusy = false;

        const buildGroupSelect = (id) => $.get(TribalWars.buildURL('GET', 'groups', { ajax: 'load_group_menu' })).then((groups) => {
            let html = `<select class="optionGroup" style="background:#1a1a1a;color:#fff;border:1px solid #555;border-radius:4px;padding:2px;width:100%;">`;
            groups.result.forEach(val => { if (val.type == 'separator') html += `<option disabled=""/>`; else html += `<option value="${val.group_id}" ${val.group_id == id ? 'selected' : ''}>${val.name}</option>`; });
            return html + `</select>`;
        });

        const loadVillages = (group) => {
            let villages = {};
            let processor = ($html) => {
                const mobile = $('#mobileHeader').length > 0;
                if (mobile) {
                    jQuery($html).find('.overview-container > div').each((i, el) => {
                        try { const id=jQuery(el).find('.quickedit-vn').data('id'),name=jQuery(el).find('.quickedit-label').attr('data-text'),coord=jQuery(el).find('.quickedit-label').text().toCoord(); if(coord)villages[coord]={name,id}; } catch(e){}
                    });
                } else {
                    $html.find('#combined_table').find('.row_a,.row_b').filter((i,el)=>$(el).find('.bonus_icon_33').length==0).map((i,el)=>{
                        let $qel=$(el).find('.quickedit-label').first(),coord=$qel.text().toCoord();
                        if(coord)villages[coord]={name:$qel.data('text'),id:parseInt($(el).find('.quickedit-vn').first().data('id'))};
                    });
                }
                return villages;
            };
            return lib.processAllPages(TribalWars.buildURL('GET','overview_villages',{mode:'combined',group,page_size:1000}),processor).then(()=>villages);
        };

        const getData = (group, newbarbs, losses) => {
            const game_data = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).game_data;
            let data = { villages:{}, commands:{}, farms:{templates:{},farms:{}} };
            let skipUnits = ['ram','catapult','knight','snob','militia'];

            let villagesProcessor = ($html) => {
                const mobile = $('#mobileHeader').length > 0;
                if (mobile) {
                    jQuery($html).find('.overview-container > div').each((i,el)=>{
                        try {
                            const vid=jQuery(el).find('.quickedit-vn').data('id'),name=jQuery(el).find('.quickedit-label').attr('data-text'),coord=jQuery(el).find('.quickedit-label').text().toCoord();
                            const units=new Array(game_data.units.length).fill(0);
                            jQuery(el).find('.overview-units-row > div.unit-row-item').each((_,ue)=>{const img=jQuery(ue).find('img'),span=jQuery(ue).find('span.unit-row-name');if(img.length&&span.length){let ut=img.attr('src').split('unit_')[1].replace('@2x.webp','').replace('.webp','').replace('.png','');const ui=game_data.units.indexOf(ut);if(ui!==-1)units[ui]=parseInt(span.text())||0;}});
                            data.villages[coord]={name,id:vid,units:units.filter((_,i)=>skipUnits.indexOf(game_data.units[i])===-1)};
                        } catch(e){}
                    });
                } else {
                    $html.find('#combined_table').find('.row_a,.row_b').filter((i,el)=>$(el).find('.bonus_icon_33').length==0).map((i,el)=>{
                        let $el=$(el),$qel=$el.find('.quickedit-label').first();
                        let units=$el.find('.unit-item').filter((idx)=>skipUnits.indexOf(game_data.units[idx])==-1).map((idx,e)=>$(e).text().toNumber()).get();
                        return(data.villages[$qel.text().toCoord()]={name:$qel.data('text'),id:parseInt($el.find('.quickedit-vn').first().data('id')),units});
                    });
                }
                return data;
            };

            let commandsProcessor = ($html) => {
                $html.find('#commands_table').find('.row_a,.row_ax,.row_b,.row_bx').map((i,el)=>{
                    let $el=$(el),coord=$el.find('.quickedit-label').first().text().toCoord();
                    if(coord){if(!data.commands[coord])data.commands[coord]=[];data.commands[coord].push(Math.round(lib.timestampFromString($el.find('td').eq(2).text().trim())/1000));}
                });
                return data;
            };

            let farmProcessor = ($html) => {
                if($.isEmptyObject(data.farms.templates)){
                    let us=lib.getUnitSpeeds();
                    $html.find('form[action*="action=edit_all"]').find('input[type="hidden"][name*="template"]').closest('tr').map((i,el)=>{
                        let $el=$(el);
                        return(data.farms.templates[$el.prev('tr').find('a.farm_icon').first().attr('class').match(/farm_icon_(.*)\s/)[1]]={
                            id:$el.find('input[type="hidden"][name*="template"][name*="[id]"]').first().val().toNumber(),
                            units:$el.find('input[type="text"],input[type="number"]').map((i,e)=>$(e).val().toNumber()).get(),
                            speed:Math.max(...$el.find('input[type="text"],input[type="number"]').map((i,e)=>$(e).val().toNumber()>0?us[$(e).attr('name').trim().split('[')[0]]:0).get()),
                        });
                    });
                }
                $html.find('#plunder_list').find('tr[id^="village_"]').map((i,el)=>{
                    let $el=$(el);
                    return(data.farms.farms[$el.find('a[href*="screen=report&mode=all&view="]').first().text().toCoord()]={
                        id:$el.attr('id').split('_')[1].toNumber(),
                        color:$el.find('img[src*="graphic/dots/"]').attr('src').match(/dots\/(green|yellow|red|blue|red_blue)/)[1],
                        max_loot:$el.find('img[src*="max_loot/1"]').length>0,
                    });
                });
                return data;
            };

            let findNewbarbs = () => newbarbs ? twLib.get('/map/village.txt').then((all)=>{
                all.match(/[^\r\n]+/g).forEach(vd=>{let [id,name,x,y,pid]=vd.split(','),coord=`${x}|${y}`;if(pid==0&&!data.farms.farms[coord])data.farms.farms[coord]={id:id.toNumber()};});
                return data;
            }) : data;

            let filterFarms = () => {
                data.farms.allFarms = Object.assign({}, data.farms.farms); // alle Farmen vor Filter merken
                data.farms.farms=Object.fromEntries(Object.entries(data.farms.farms).filter(([k,v])=>!v.color||(v.color!='red'&&v.color!='red_blue'&&(v.color!='yellow'||losses))));
                return data;
            };

            return Promise.all([
                lib.processAllPages(TribalWars.buildURL('GET','overview_villages',{mode:'combined',group}),villagesProcessor).catch(e=>console.warn('[AF] villages error:',e)),
                lib.processAllPages(TribalWars.buildURL('GET','overview_villages',{mode:'commands',type:'attack'}),commandsProcessor).catch(e=>console.warn('[AF] commands error:',e)),
                lib.processAllPages(TribalWars.buildURL('GET','am_farm'),farmProcessor).catch(e=>console.warn('[AF] farm error:',e)),
                Promise.resolve(findNewbarbs()).catch(e=>console.warn('[AF] newbarbs error:',e)),
            ]).then(filterFarms).then(()=>data);
        };

        const isInArea = (farmCoord, x1, y1, x2, y2) => {
            const fc = farmCoord.toCoord(true);
            if (!fc) return false;
            const fx = parseFloat(fc.x), fy = parseFloat(fc.y);
            const minX = Math.min(x1, x2), maxX = Math.max(x1, x2);
            const minY = Math.min(y1, y2), maxY = Math.max(y1, y2);
            return fx >= minX && fx <= maxX && fy >= minY && fy <= maxY;
        };

        const farmAllowed = (farmCoord, dist, vs, optionDistance) => {
            if (!vs) return dist < optionDistance; // kein individuelles Setting → Standard
            const mode = vs.mode || 'distance';
            const maxDist = vs.distance !== undefined ? parseFloat(vs.distance) : optionDistance;
            const areaOk = isInArea(farmCoord,
                vs.x1 !== undefined ? vs.x1 : 0,
                vs.y1 !== undefined ? vs.y1 : 0,
                vs.x2 !== undefined ? vs.x2 : 999,
                vs.y2 !== undefined ? vs.y2 : 999);
            if (mode === 'distance') return dist < maxDist;
            if (mode === 'area')     return areaOk;
            if (mode === 'both')     return dist < maxDist && areaOk;
            return dist < optionDistance;
        };

        const createPlanning = (optionDistance, optionTime, optionMaxloot, data, villageDistances, villageSettings) => {
            let plan={counter:0,farms:{}};
            let serverTime=Math.round(lib.getCurrentServerTime()/1000);
            for(let prop in data.villages){
                const vs = villageSettings && villageSettings[prop] ? villageSettings[prop] : null;
                // Fallback auf altes villageDistances System
                let distForVillage;
                if (!vs && villageDistances && villageDistances[prop] !== undefined) {
                    distForVillage = parseFloat(villageDistances[prop]);
                } else {
                    distForVillage = optionDistance;
                }
                let orderedFarms=Object.keys(data.farms.farms).map(k=>({coord:k,dis:lib.getDistance(prop,k)})).sort((a,b)=>a.dis>b.dis?1:-1);
                orderedFarms.forEach(el=>{
                    let fi=data.farms.farms[el.coord],tn=optionMaxloot&&fi.max_loot?'b':'a',tmpl=data.farms.templates[tn];
                    let unitsLeft=lib.subtractArrays(data.villages[prop].units,tmpl.units);
                    let dist=lib.getDistance(prop,el.coord),arrival=Math.round(serverTime+dist*tmpl.speed*60+Math.round(plan.counter/5));
                    let maxTD=Math.round(optionTime*60),timeDiff=true;
                    if(data.commands[el.coord]){if(!fi.color&&data.commands[el.coord].length>0)timeDiff=false;data.commands[el.coord].forEach(ts=>{if(Math.abs(ts-arrival)<maxTD){timeDiff=false;}});}
                    else data.commands[el.coord]=[];
                    const allowed = vs ? farmAllowed(el.coord, dist, vs, optionDistance) : dist < distForVillage;
                    if(unitsLeft&&timeDiff&&allowed){
                        plan.counter++;
                        if(!plan.farms[prop])plan.farms[prop]=[];
                        plan.farms[prop].push({origin:{coord:prop,name:data.villages[prop].name,id:data.villages[prop].id},target:{coord:el.coord,id:fi.id},fields:dist,template:{name:tn,id:tmpl.id}});
                        data.villages[prop].units=unitsLeft;data.commands[el.coord].push(arrival);
                    }
                });
            }
            return plan;
        };

        const buildTable = (plan) => {
            let html=`<div class="vis farmGodContent"><h4>FarmGod</h4><table class="vis" width="100%">
                <tr><div id="FarmGodProgessbar" class="progress-bar live-progress-bar progress-bar-alive" style="width:98%;margin:5px auto;"><div style="background:rgb(146,194,0);"></div><span class="label" style="margin-top:0px;"></span></div></tr>
                <tr><th style="text-align:center;">Herkunft</th><th style="text-align:center;">Ziel</th><th style="text-align:center;">Felder</th><th style="text-align:center;">Farm</th></tr>`;
            if(!$.isEmptyObject(plan)){for(let prop in plan)plan[prop].forEach((val,i)=>{html+=`<tr class="farmRow row_${i%2==0?'a':'b'}"><td style="text-align:center;"><a href="${game_data.link_base_pure}info_village&id=${val.origin.id}">${val.origin.name} (${val.origin.coord})</a></td><td style="text-align:center;"><a href="${game_data.link_base_pure}info_village&id=${val.target.id}">${val.target.coord}</a></td><td style="text-align:center;">${val.fields.toFixed(2)}</td><td style="text-align:center;"><a href="#" data-origin="${val.origin.id}" data-target="${val.target.id}" data-template="${val.template.id}" class="farmGod_icon farm_icon farm_icon_${val.template.name}" style="margin:auto;"></a></td></tr>`;});}
            else html+=`<tr><td colspan="4" style="text-align:center;">Keine Farms mit den aktuellen Einstellungen möglich.</td></tr>`;
            return html+`</table></div>`;
        };

        const sendFarm = ($this) => {
            let n=Timing.getElapsedTimeSinceLoad();
            if(!farmBusy&&!(Accountmanager.farm.last_click&&n-Accountmanager.farm.last_click<200)){
                farmBusy=true;Accountmanager.farm.last_click=n;let $pb=$('#FarmGodProgessbar');
                TribalWars.post(Accountmanager.send_units_link.replace(/village=(\d+)/,'village='+$this.data('origin')),null,
                    {target:$this.data('target'),template_id:$this.data('template'),source:$this.data('origin')},
                    (r)=>{UI.SuccessMessage(r.success);$pb.data('current',$pb.data('current')+1);UI.updateProgressBar($pb,$pb.data('current'),$pb.data('max'));$this.closest('.farmRow').remove();farmBusy=false;},
                    (r)=>{UI.ErrorMessage(r||'Fehler!');$pb.data('current',$pb.data('current')+1);UI.updateProgressBar($pb,$pb.data('current'),$pb.data('max'));$this.closest('.farmRow').remove();farmBusy=false;}
                );
            }
        };

        const bindEventHandlers = () => {
            $('.farmGod_icon').off('click').on('click',function(){sendFarm($(this));});
            $(document).off('keydown.farmgod').on('keydown.farmgod',(e)=>{if((e.keyCode||e.which)==13)$('.farmGod_icon').first().trigger('click');});
        };

        const planAndRender = () => {
                        settings=loadSettings();
            const gd2 = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).game_data;
            if(!gd2||!gd2.features.Premium.active||!gd2.features.FarmAssistent.active){UI.ErrorMessage('Farmgod benötigt Premium + Farm-Assistent!');return Promise.reject();}
            setStatus('⏳ Lade Daten...','#f0a500');
            const effectiveTime = isNightMode() ? settings.nightOptionTime : settings.optionTime;
                const effectiveMaxloot = isNightMode() ? settings.nightOptionMaxloot : settings.optionMaxloot;
                const effectiveLosses = isNightMode() ? settings.nightOptionLosses : settings.optionLosses;
                return getData(settings.optionGroup,settings.optionNewbarbs,effectiveLosses).then(data=>{
                let plan=createPlanning(settings.optionDistance,effectiveTime,effectiveMaxloot,data,settings.villageDistances,settings.villageSettings);
                $('.farmGodContent').remove();$('#am_widget_Farm').first().before(buildTable(plan.farms));
                bindEventHandlers();UI.InitProgressBars();UI.updateProgressBar($('#FarmGodProgessbar'),0,plan.counter);$('#FarmGodProgessbar').data('current',0).data('max',plan.counter);
                setStatus(`✅ ${plan.counter} Farms geplant`,'#27ae60');
                kattaAllFarms = data.farms.allFarms || {}; // fĂŒr Katta-Phase merken
                return plan;
            });
        };

        return { planAndRender, buildGroupSelect, loadVillages };
    })(FarmLib);

    // =====================================================================
    // ENTER / STATUS
    // =====================================================================
    function fireEnterDown(r){const o={key:'Enter',code:'Enter',keyCode:13,which:13,bubbles:true,cancelable:true,repeat:r};document.dispatchEvent(new KeyboardEvent('keydown',o));document.dispatchEvent(new KeyboardEvent('keypress',o));}
    function fireEnterUp(){document.dispatchEvent(new KeyboardEvent('keyup',{key:'Enter',code:'Enter',keyCode:13,which:13,bubbles:true,cancelable:true,repeat:false}));}

    function setStatus(text,color){
        currentStatus=text;
        const el=document.getElementById('af-status-mini');if(el){el.innerText=text;el.style.color=color||'#f0a500';}
        const full=document.getElementById('af-countdown');if(full){full.innerText=text;full.style.color=color||'#f0a500';full.style.display='block';}
        // Tag/Nacht Modus anzeigen
        const modeEl=document.getElementById('af-mode-mini');
        if(modeEl){
            if(isNightMode()){modeEl.innerText='🌙 Nachtmodus';modeEl.style.color='#8e44ad';}
            else{modeEl.innerText='☀ Tagmodus';modeEl.style.color='#f0a500';}
        }
    }
    function setCountdown(text){
        currentCountdownText=text;
        const el=document.getElementById('af-timer-mini');if(el)el.innerText=text;
        const full=document.getElementById('af-countdown');if(full){full.innerText=text;full.style.display='block';}
    }

    function getFarmGodProgress(){
        const pb=document.getElementById('FarmGodProgessbar');
        if(!pb)return null;
        const label=pb.querySelector('.label');
        if(!label)return null;
        const text=(label.innerText||label.textContent||'').trim().replace(/\./g,'');
        const m=text.match(/^(\d+)\s*\/\s*(\d+)$/);
        if(m)return{current:parseInt(m[1]),total:parseInt(m[2])};
        return null;
    }
    function hasFarmsRemaining(){
        const p=getFarmGodProgress();
        if(p!==null){
            if(p.total===0)return false;
            return p.current<p.total;
        }
        const visibleRows=document.querySelectorAll('.farmRow');
        return visibleRows.length>0;
    }

    function startHoldEnter(){
        holdRepeatCount=0;fireEnterDown(false);holdRepeatCount++;
        holdIntervalId=setInterval(()=>{
            if(!isRunning){stopHoldEnter();return;}
            fireEnterDown(true);holdRepeatCount++;
            const p=getFarmGodProgress();
            if(p){
                if(p.total===0){stopHoldEnter();setStatus('😮 Keine Farms','#aaa');triggerEndOfLoop();return;}
                if(p.current>=p.total){stopHoldEnter();setStatus('✅ Alle erledigt','#27ae60');triggerEndOfLoop();return;}
                setStatus(`⚔ Farmt... ${p.current}/${p.total}`,'#27ae60');
            }
        },settings.holdInterval);
    }
    function stopHoldEnter(){clearInterval(holdIntervalId);fireEnterUp();holdRepeatCount=0;}

    function pressEnterRandomly(){
        settings=loadSettings();const delay=randomDelay(settings.enterMin,settings.enterMax);
        fireEnterDown(false);fireEnterUp();
        setTimeout(()=>{
            if(!hasFarmsRemaining()){emptyFarmChecks++;if(emptyFarmChecks>=EMPTY_FARM_THRESHOLD){clearTimeout(intervalId);setStatus('🔄 Fertig','#e74c3c');triggerEndOfLoop();return;}}
            else{emptyFarmChecks=0;const p=getFarmGodProgress();setStatus(p&&p.total>0?`⚔ Farmt... ${p.current}/${p.total}`:'⚔ Farmt...','#27ae60');}
        },300);
        intervalId=setTimeout(pressEnterRandomly,delay);
    }

    function triggerEndOfLoop(){
        resetGroupToAll();
        fetchTodayLoot();
        scheduleRandomPause(startCountdown);
    }

    // =====================================================================
    // CAPTCHA
    // =====================================================================
    function isCaptchaPresent(){return['#captcha','.captcha','iframe[src*="captcha"]','iframe[src*="recaptcha"]','.g-recaptcha','#recaptcha','[class*="captcha"]','[id*="captcha"]'].some(s=>document.querySelector(s));}
    function handleCaptchaDetected(){
        if(captchaAlertSent)return;
        captchaAlertSent=true;
        localStorage.setItem(domain + '_captcha_paused', 'true');
        sendDiscordCaptchaAlert();

        // Pausieren statt stoppen
        clearTimeout(intervalId);
        stopHoldEnter();
        clearInterval(countdownInterval);
        clearRandomPause();
        // isRunning bleibt true – Script ist pausiert nicht gestoppt

        setStatus('⚠ Captcha – bitte lösen!','#e74c3c');

        // Fortsetzen Button anzeigen
        const resumeBtn = document.getElementById('af-resume-btn');
        if(resumeBtn) resumeBtn.style.display = 'block';
        const miniResumeBtn2 = document.getElementById('af-mini-resume-btn');
        if(miniResumeBtn2) miniResumeBtn2.style.display = 'inline-block';

        // Automatisch prĂŒfen ob Captcha weg ist nach jedem Reload
        // (wird durch startCaptchaObserver + isCaptchaPresent beim nÀchsten Seitenload gehandelt)
        console.log('[Autofarm] Captcha erkannt – pausiert. Bitte lösen und Seite neu laden oder Fortsetzen klicken.');
    }

    function resumeAfterCaptcha(){
        if(isCaptchaPresent()){
            setStatus('⚠ Captcha noch vorhanden!','#e74c3c');
            return;
        }
        // Alle laufenden Intervalle/Timeouts sauber stoppen
        clearTimeout(intervalId);
        clearInterval(countdownInterval);
        clearInterval(holdIntervalId);
        stopHoldEnter();
        clearRandomPause();

        captchaAlertSent=false;
        localStorage.removeItem(domain + '_captcha_paused');
        emptyFarmChecks=0;

        const resumeBtn=document.getElementById('af-resume-btn');
        if(resumeBtn)resumeBtn.style.display='none';
        const miniResumeBtn=document.getElementById('af-mini-resume-btn');
        if(miniResumeBtn)miniResumeBtn.style.display='none';

        setStatus('⏳ Fortsetze...','#f0a500');
        startProcess();
        updateButtonState();
    }
    function startCaptchaObserver(){
        if(isCaptchaPresent()){
            // Captcha noch da – pausieren
            handleCaptchaDetected();
            return;
        }
        if(captchaAlertSent && isRunning){
            // Captcha war da aber ist jetzt weg nach Reload
            // startProcess lÀuft bereits (wegen isRunning=true aus localStorage)
            // nur State zurĂŒcksetzen, kein erneuter startProcess
            console.log('[Autofarm] Captcha gelöst – setze State zurĂŒck.');
            captchaAlertSent=false;
            localStorage.removeItem(domain + '_captcha_paused');
            const resumeBtn=document.getElementById('af-resume-btn');
            if(resumeBtn)resumeBtn.style.display='none';
            const miniResumeBtn=document.getElementById('af-mini-resume-btn');
            if(miniResumeBtn)miniResumeBtn.style.display='none';
        }
        const o=new MutationObserver(()=>{if(isRunning&&isCaptchaPresent())handleCaptchaDetected();});
        o.observe(document.body,{childList:true,subtree:true});
    }

    // =====================================================================
    // PROZESS
    // =====================================================================
    function checkFarmsAndStart(){
        const p=getFarmGodProgress();
        if(p&&p.total===0){setStatus('😮 Keine Farms','#aaa');triggerEndOfLoop();return;}
        settings=loadSettings();
        if(settings.holdEnter){setStatus('⚔ Farmt...','#27ae60');startHoldEnter();}
        else{setStatus('⚔ Farmt...','#27ae60');pressEnterRandomly();}
    }

    function startProcess(){
        captchaAlertSent=false;
        localStorage.removeItem(domain + '_captcha_paused');
        emptyFarmChecks=0;
        startHourlyAlert();
        // Reihenfolge: 1) am_farm laden+filtern (in planAndRender via kattaAllFarms)
        //              2) Katta-Angriffe planen+senden
        //              3) Farm-Angriffe planen+senden
        setStatus('⏳ Lade Farm-Daten...','#f0a500');
        FarmGodCore.planAndRender()
            .then(() => {
                const targets = Object.entries(kattaAllFarms).filter(([coord,f]) => kattaShouldAttack(coord, f.color));
                if (targets.length === 0) return;
                return runKattaPhase(kattaAllFarms);
            })
            .catch(e => console.error('[Katta] Fehler:', e))
            .then(()=>setTimeout(()=>checkFarmsAndStart(),randomDelay(1000,2000)))
            .catch(e=>{console.error(e);setStatus('❌ Fehler','#e74c3c');});
    }

    function stopProcess(){
        clearTimeout(intervalId);
        stopHoldEnter();
        clearInterval(countdownInterval);
        stopHourlyAlert();
        clearRandomPause();
        isRunning=false;
        localStorage.setItem(domain+'_isRunning',false);
        updateButtonState();
        if(!captchaAlertSent){
            setStatus('âč Gestoppt','#aaa');
            const cd=document.getElementById('af-countdown');
            if(cd)cd.style.display='none';
        }
    }

    function toggleProcess(){
        if(isRunning)stopProcess();
        else{
            isRunning=true;
            localStorage.setItem(domain+'_isRunning',true);
            updateButtonState();
            startProcess();
        }
    }

    function startCountdown(){
        clearInterval(countdownInterval); // sicherstellen kein doppelter Countdown
        settings=loadSettings();
        const nightMode = isNightMode();
        let normalDelay = nightMode
            ? randomDelay(settings.nightReloadMin, settings.nightReloadMax)
            : randomDelay(settings.reloadMin, settings.reloadMax);
        let t = getRandomPauseReloadDelay(normalDelay);
        const isPause = localStorage.getItem(RANDOM_PAUSE_ACTIVE_KEY) === '1';
        if (isPause) localStorage.removeItem(RANDOM_PAUSE_ACTIVE_KEY);
        const modeLabel = isPause ? '😮' : (nightMode ? '🌙' : '🔁');
        if (isPause) setStatus(`😮 Pause ${Math.round(t/60)} Min...`, '#8e44ad');
        countdownInterval=setInterval(()=>{
            if(t<=0){
                clearInterval(countdownInterval);
                isRandomPausing=false;
                location.reload();
            } else {
                setCountdown(`${modeLabel} ${isPause?'Pause':'Loop'} in: ${Math.floor(t/60)}m ${t%60}s`);
                t--;
            }
        },1000);
    }

    function updateButtonState(){
        const btn=document.getElementById('af-toggle-btn');
        const miniBtn=document.getElementById('af-mini-toggle-btn');
        const label=isRunning?'Stop Looting':'Start Looting';
        const color=isRunning?'#c0392b':'#27ae60';
        if(btn){btn.textContent=label;btn.style.backgroundColor=color;}
        if(miniBtn){miniBtn.textContent=isRunning?'Stop':'Start';miniBtn.style.backgroundColor=color;}
    }
    function toggleMinimize(){isMinimized=!isMinimized;saveMinimized(isMinimized);applyMinimizeState();}
    function applyMinimizeState(){
        const body=document.getElementById('af-body');
        const mini=document.getElementById('af-mini-status');
        const arrow=document.getElementById('af-arrow');
        const miniToggle=document.getElementById('af-mini-toggle-btn');
        if(!body||!mini||!arrow)return;
        if(isMinimized){
            body.style.display='none';
            mini.style.display='flex';
            arrow.textContent='▌';
            if(miniToggle)miniToggle.style.display='block';
        }else{
            body.style.display='block';
            mini.style.display='none';
            arrow.textContent='â–Č';
            if(miniToggle)miniToggle.style.display='none';
        }
    }

    function makeDraggable(container,handle){
        let d=false,sx,sy,sl,st;
        handle.style.cursor='grab';
        handle.addEventListener('mousedown',(e)=>{if(['af-arrow','af-toggle-btn'].includes(e.target.id))return;d=true;sx=e.clientX;sy=e.clientY;sl=parseInt(container.style.left)||0;st=parseInt(container.style.top)||0;handle.style.cursor='grabbing';e.preventDefault();});
        document.addEventListener('mousemove',(e)=>{if(!d)return;container.style.left=Math.max(0,Math.min(window.innerWidth-container.offsetWidth,sl+e.clientX-sx))+'px';container.style.top=Math.max(0,Math.min(window.innerHeight-container.offsetHeight,st+e.clientY-sy))+'px';container.style.bottom='auto';container.style.right='auto';});
        document.addEventListener('mouseup',()=>{if(!d)return;d=false;handle.style.cursor='grab';savePosition(parseInt(container.style.left),parseInt(container.style.top));});
        handle.addEventListener('touchstart',(e)=>{if(e.target.id==='af-arrow')return;const t=e.touches[0];d=true;sx=t.clientX;sy=t.clientY;sl=parseInt(container.style.left)||0;st=parseInt(container.style.top)||0;e.preventDefault();},{passive:false});
        document.addEventListener('touchmove',(e)=>{if(!d)return;const t=e.touches[0];container.style.left=Math.max(0,Math.min(window.innerWidth-container.offsetWidth,sl+t.clientX-sx))+'px';container.style.top=Math.max(0,Math.min(window.innerHeight-container.offsetHeight,st+t.clientY-sy))+'px';container.style.bottom='auto';container.style.right='auto';e.preventDefault();},{passive:false});
        document.addEventListener('touchend',()=>{if(!d)return;d=false;savePosition(parseInt(container.style.left),parseInt(container.style.top));});
    }

    // =====================================================================
    // UI
    // =====================================================================
    function mk(tag,styles,text){const e=document.createElement(tag);if(styles)Object.assign(e.style,styles);if(text!==undefined)e.textContent=text;return e;}
    function inp(id,type,value,min,width){const e=document.createElement('input');e.id=id;e.type=type;e.value=value;if(min!==undefined)e.min=min;Object.assign(e.style,{width:width||'70px',padding:'3px 5px',borderRadius:'4px',border:'1px solid #555',backgroundColor:'#1a1a1a',color:'#fff',fontSize:'12px',boxSizing:'border-box'});return e;}

    function buildTabSettings(body){
        const s=document.createElement('div');s.id='af-tab-settings';
        s.style.maxHeight='340px';s.style.overflowY='auto';s.style.paddingRight='4px';
        const add=(label,children)=>{s.appendChild(mk('div',{color:'#aaa',fontSize:'12px',marginBottom:'2px'},label));const row=mk('div',{display:'flex',gap:'6px',alignItems:'center',marginBottom:'6px'});children.forEach(c=>row.appendChild(c));s.appendChild(row);};
        const sep=()=>s.appendChild(mk('div',{borderTop:'1px solid #444',margin:'8px 0'}));
        const sec=(t)=>s.appendChild(mk('div',{color:'#f0a500',fontWeight:'bold',fontSize:'12px',marginBottom:'6px'},t));
        const addCb=(id,label,checked)=>{const w=mk('div',{display:'flex',alignItems:'center',gap:'6px',marginBottom:'5px'});const cb=document.createElement('input');cb.id=id;cb.type='checkbox';cb.checked=checked;const l=mk('label',{color:'#fff',fontSize:'12px',cursor:'pointer'},label);l.htmlFor=id;w.appendChild(cb);w.appendChild(l);s.appendChild(w);};

        sec('đŸŒŸ FarmGod Einstellungen');
        s.appendChild(mk('div',{color:'#aaa',fontSize:'12px',marginBottom:'2px'},'Gruppe:'));
        const gw=mk('div',{marginBottom:'6px'});gw.id='af-group-wrapper';gw.innerHTML='<span style="color:#aaa;font-size:11px;">LĂ€dt...</span>';s.appendChild(gw);
        FarmGodCore.buildGroupSelect(settings.optionGroup).then(html=>{gw.innerHTML=html;});

        add('Standard-Reichweite (Felder):',[inp('af-distance','number',settings.optionDistance,1,'80px'),mk('span',{color:'#aaa'},'Felder')]);
        add('Mindestzeit zwischen Farms:',[inp('af-time','number',settings.optionTime,0,'80px'),mk('span',{color:'#aaa'},'min')]);
        addCb('af-losses','Farms mit Teilverlusten senden',settings.optionLosses);
        addCb('af-maxloot','B-Farm bei vollem Loot senden',settings.optionMaxloot);
        addCb('af-newbarbs','Neue Barbarendörfer hinzufĂŒgen',settings.optionNewbarbs);

        sep();
        sec('⌚ Enter-Einstellungen');
        add('Reload-Intervall:',[inp('af-reload-min','number',settings.reloadMin,10,'65px'),mk('span',{color:'#aaa'},'–'),inp('af-reload-max','number',settings.reloadMax,10,'65px'),mk('span',{color:'#aaa'},'s')]);
        add('Enter-Intervall (Einzel):',[inp('af-enter-min','number',settings.enterMin,50,'65px'),mk('span',{color:'#aaa'},'–'),inp('af-enter-max','number',settings.enterMax,50,'65px'),mk('span',{color:'#aaa'},'ms')]);
        addCb('af-hold-enter','Enter gedrĂŒckt halten (Schnellmodus)',settings.holdEnter);
        add('Wiederholrate (Hold):',[inp('af-hold-interval','number',settings.holdInterval,10,'65px'),mk('span',{color:'#666',fontSize:'11px'},'ms (OS Key-Repeat)')]);

        sep();
        sec('🔔 Discord');
        s.appendChild(mk('div',{color:'#aaa',fontSize:'12px',marginBottom:'2px'},'Webhook URL:'));
        const wi=inp('af-webhook-url','text',settings.webhookUrl||'',undefined,'100%');wi.placeholder='https://discord.com/api/webhooks/...';wi.style.marginBottom='8px';s.appendChild(wi);

        sep();
        sec('📊 Tagesergebnis');
        const lootTable=mk('div',{fontSize:'12px',marginBottom:'4px'});
        const lootRes=mk('div',{color:'#27ae60',marginBottom:'2px'},'📩 –');lootRes.id='af-loot-res';
        const lootVil=mk('div',{color:'#3498db',marginBottom:'2px'},'đŸ˜ïž –');lootVil.id='af-loot-vil';
        const lootAvg=mk('div',{color:'#e67e22',marginBottom:'4px'},'⚡ –');lootAvg.id='af-loot-avg';
        lootTable.appendChild(lootRes);lootTable.appendChild(lootVil);lootTable.appendChild(lootAvg);
        s.appendChild(lootTable);
        s.appendChild(mk('div',{color:'#666',fontSize:'10px'},'Aktualisierung nach jedem Loop'));

        const saveBtn=mk('button',{display:'block',width:'100%',marginBottom:'8px',marginTop:'8px'},'Einstellungen speichern'); saveBtn.className='af-btn af-btn-primary';
        saveBtn.addEventListener('click',()=>{
            const sel=document.querySelector('#af-group-wrapper select');
            const ns={
                optionGroup:sel?parseInt(sel.value):settings.optionGroup,
                optionDistance:Math.max(1,parseFloat(document.getElementById('af-distance').value)||DEFAULTS.optionDistance),
                optionTime:Math.max(0,parseFloat(document.getElementById('af-time').value)||DEFAULTS.optionTime),
                optionLosses:document.getElementById('af-losses').checked,
                optionMaxloot:document.getElementById('af-maxloot').checked,
                optionNewbarbs:document.getElementById('af-newbarbs').checked,
                villageDistances:loadSettings().villageDistances,
                villageSettings:loadSettings().villageSettings,
                enterMin:Math.max(50,parseInt(document.getElementById('af-enter-min').value)||DEFAULTS.enterMin),
                enterMax:Math.max(50,parseInt(document.getElementById('af-enter-max').value)||DEFAULTS.enterMax),
                reloadMin:Math.max(10,parseInt(document.getElementById('af-reload-min').value)||DEFAULTS.reloadMin),
                reloadMax:Math.max(10,parseInt(document.getElementById('af-reload-max').value)||DEFAULTS.reloadMax),
                holdEnter:document.getElementById('af-hold-enter').checked,
                holdInterval:Math.max(10,parseInt(document.getElementById('af-hold-interval').value)||DEFAULTS.holdInterval),
                webhookUrl:document.getElementById('af-webhook-url').value.trim(),
            };
            if(ns.enterMin>ns.enterMax)[ns.enterMin,ns.enterMax]=[ns.enterMax,ns.enterMin];
            if(ns.reloadMin>ns.reloadMax)[ns.reloadMin,ns.reloadMax]=[ns.reloadMax,ns.reloadMin];
            saveSettings(ns);settings=ns;
            saveBtn.textContent='✓ Gespeichert!';setTimeout(()=>{saveBtn.textContent='Einstellungen speichern';},1500);
        });
        s.appendChild(saveBtn);
        body.appendChild(s);
    }

    // Gecachte Dorfliste fĂŒr Village-Tab
    let cachedVillages = {};

    function buildTabVillages(body) {
        const s = document.createElement('div');
        s.id = 'af-tab-villages';
        s.style.display = 'none';

        // Header mit + Button
        const header = mk('div', {display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:'8px'});
        header.appendChild(mk('div', {color:'#aaa', fontSize:'11px'}, 'Dörfer mit individuellen Einstellungen:'));
        const addBtn = mk('button', {border:'none', borderRadius:'50%', width:'22px', height:'22px', backgroundColor:'#27ae60', color:'#fff', fontSize:'16px', cursor:'pointer', lineHeight:'20px', padding:'0', flexShrink:'0'}, '+');
        header.appendChild(addBtn);
        s.appendChild(header);

        // Liste der konfigurierten Dörfer
        const configList = mk('div', {maxHeight:'300px', overflowY:'auto'});
        configList.id = 'af-vs-config-list';
        s.appendChild(configList);

        // Modal Overlay
        // Altes Modal entfernen falls vorhanden
        const existingModal = document.getElementById('af-vs-modal');
        if (existingModal) existingModal.remove();

        const modal = mk('div', {
            display:'none', position:'fixed', top:'0', left:'0', width:'100%', height:'100%',
            backgroundColor:'rgba(0,0,0,0.7)', zIndex:'20000', justifyContent:'center', alignItems:'center'
        });
        modal.id = 'af-vs-modal';

        const modalBox = mk('div', {
            backgroundColor:'#2c2c2c', borderRadius:'8px', padding:'16px', minWidth:'260px', maxWidth:'300px',
            maxHeight:'80vh', overflowY:'auto', color:'#fff', fontFamily:'Arial, sans-serif', fontSize:'13px',
            position:'relative', margin:'auto', top:'50%', transform:'translateY(-50%)'
        });

        // Modal Titel
        const modalTitle = mk('div', {fontWeight:'bold', fontSize:'14px', marginBottom:'12px', borderBottom:'1px solid #555', paddingBottom:'6px'}, 'Dorf konfigurieren');
        modalBox.appendChild(modalTitle);

        // Dorf-Auswahl Dropdown
        modalBox.appendChild(mk('div', {color:'#aaa', fontSize:'12px', marginBottom:'2px'}, 'Dorf:'));
        const villageSelect = document.createElement('select');
        villageSelect.id = 'af-vs-modal-village';
        Object.assign(villageSelect.style, {width:'100%', backgroundColor:'#1a1a1a', color:'#fff', border:'1px solid #555', borderRadius:'4px', padding:'4px', fontSize:'12px', marginBottom:'10px', boxSizing:'border-box'});
        modalBox.appendChild(villageSelect);

        // Modus
        modalBox.appendChild(mk('div', {color:'#aaa', fontSize:'12px', marginBottom:'2px'}, 'Modus:'));
        const modeSelect = document.createElement('select');
        modeSelect.id = 'af-vs-modal-mode';
        Object.assign(modeSelect.style, {width:'100%', backgroundColor:'#1a1a1a', color:'#fff', border:'1px solid #555', borderRadius:'4px', padding:'4px', fontSize:'12px', marginBottom:'10px', boxSizing:'border-box'});
        [['distance','Nur Distanz'], ['area','Nur Bereich'], ['both','Distanz + Bereich']].forEach(([val, label]) => {
            const opt = document.createElement('option'); opt.value = val; opt.textContent = label;
            modeSelect.appendChild(opt);
        });
        modalBox.appendChild(modeSelect);

        // Distanz-Zeile
        const distRow = mk('div', {marginBottom:'10px'});
        distRow.id = 'af-vs-modal-distrow';
        distRow.appendChild(mk('div', {color:'#aaa', fontSize:'12px', marginBottom:'2px'}, 'Reichweite:'));
        const distRowInner = mk('div', {display:'flex', alignItems:'center', gap:'6px'});
        const distInp = inp('af-vs-modal-dist', 'number', settings.optionDistance, 1, '80px');
        distRowInner.appendChild(distInp);
        distRowInner.appendChild(mk('span', {color:'#aaa', fontSize:'12px'}, 'Felder'));
        distRow.appendChild(distRowInner);
        modalBox.appendChild(distRow);

        // Bereich
        const areaDiv = mk('div', {marginBottom:'10px'});
        areaDiv.id = 'af-vs-modal-areadiv';
        areaDiv.appendChild(mk('div', {color:'#aaa', fontSize:'12px', marginBottom:'4px'}, 'Farmbereich:'));

        const makeCoordRow = (label, xId, yId) => {
            const row = mk('div', {display:'flex', alignItems:'center', gap:'4px', marginBottom:'4px'});
            row.appendChild(mk('span', {color:'#aaa', fontSize:'11px', minWidth:'28px'}, label));
            const xi = inp(xId, 'number', 0, 0, '60px'); xi.placeholder = 'X';
            const yi = inp(yId, 'number', 0, 0, '60px'); yi.placeholder = 'Y';
            row.appendChild(xi);
            row.appendChild(mk('span', {color:'#555', fontSize:'12px'}, '|'));
            row.appendChild(yi);
            return row;
        };
        areaDiv.appendChild(makeCoordRow('Von:', 'af-vs-modal-x1', 'af-vs-modal-y1'));
        areaDiv.appendChild(makeCoordRow('Bis:', 'af-vs-modal-x2', 'af-vs-modal-y2'));
        modalBox.appendChild(areaDiv);

        // Modus-Visibility
        const updateModalVisibility = () => {
            const mode = modeSelect.value;
            distRow.style.display = (mode === 'distance' || mode === 'both') ? 'block' : 'none';
            areaDiv.style.display = (mode === 'area' || mode === 'both') ? 'block' : 'none';
        };
        modeSelect.addEventListener('change', updateModalVisibility);
        updateModalVisibility();

        // Buttons
        const btnRow = mk('div', {display:'flex', gap:'8px', marginTop:'4px'});
        const saveModalBtn = mk('button', {flex:'1', padding:'6px', border:'none', borderRadius:'4px', cursor:'pointer', backgroundColor:'#27ae60', color:'#fff', fontSize:'12px', fontWeight:'bold'}, 'Speichern');
        const cancelModalBtn = mk('button', {flex:'1', padding:'6px', border:'none', borderRadius:'4px', cursor:'pointer', backgroundColor:'#555', color:'#fff', fontSize:'12px'}, 'Abbrechen');
        btnRow.appendChild(saveModalBtn);
        btnRow.appendChild(cancelModalBtn);
        modalBox.appendChild(btnRow);

        modal.appendChild(modalBox);
        document.body.appendChild(modal);

        // Modal schließen
        cancelModalBtn.addEventListener('click', () => { modal.style.display = 'none'; });
        modal.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; });

        // Konfigurations-Liste neu rendern
        function renderConfigList() {
            configList.innerHTML = '';
            settings = loadSettings();
            const vs = settings.villageSettings || {};
                const entries = Object.entries(vs);
            if (entries.length === 0) {
                configList.appendChild(mk('div', {color:'#666', fontSize:'11px', padding:'8px 0'}, 'Keine individuellen Einstellungen vorhanden.'));
                return;
            }
            entries.forEach(([coord, cfg]) => {
                const vName = cachedVillages[coord] ? cachedVillages[coord].name : coord;
                const row = mk('div', {
                    display:'flex', alignItems:'center', gap:'6px', marginBottom:'6px',
                    padding:'5px', borderRadius:'4px', backgroundColor:'#1e1e1e', border:'1px solid #333'
                });
                // Info
                const info = mk('div', {flex:'1', overflow:'hidden'});
                info.appendChild(mk('div', {fontSize:'11px', color:'#ccc', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}, `${vName} (${coord})`));
                const modeLabels = {distance:'Distanz', area:'Bereich', both:'Distanz + Bereich'};
                let detail = modeLabels[cfg.mode] || cfg.mode;
                if ((cfg.mode === 'distance' || cfg.mode === 'both') && cfg.distance) detail += ` · ${cfg.distance} Felder`;
                if (cfg.mode === 'area' || cfg.mode === 'both') detail += ` · (${cfg.x1}|${cfg.y1})-(${cfg.x2}|${cfg.y2})`;
                info.appendChild(mk('div', {fontSize:'10px', color:'#888', marginTop:'2px'}, detail));
                row.appendChild(info);

                // Bearbeiten
                const editBtn = mk('button', {border:'none', borderRadius:'4px', padding:'3px 7px', cursor:'pointer', backgroundColor:'#2980b9', color:'#fff', fontSize:'11px'}, '✏');
                editBtn.addEventListener('click', () => openModal(coord, cfg));
                row.appendChild(editBtn);

                // Löschen
                const delBtn = mk('button', {border:'none', borderRadius:'4px', padding:'3px 7px', cursor:'pointer', backgroundColor:'#c0392b', color:'#fff', fontSize:'11px'}, '🗑');
                delBtn.addEventListener('click', () => {
                    settings = loadSettings();
                    delete settings.villageSettings[coord];
                    delete settings.villageDistances[coord];
                    saveSettings(settings);
                    renderConfigList();
                });
                row.appendChild(delBtn);
                configList.appendChild(row);
            });
        }

        // Modal öffnen (neu oder bearbeiten)
        function openModal(editCoord, existingCfg) {
            // Dorf-Dropdown befĂŒllen
            villageSelect.innerHTML = '';
            settings = loadSettings();
            const usedCoords = Object.keys(settings.villageSettings || {});

            if (Object.keys(cachedVillages).length === 0) {
                // Dörfer noch nicht geladen
                const loadingOpt = document.createElement('option');
                loadingOpt.textContent = '⏳ Wird geladen...';
                loadingOpt.disabled = true;
                villageSelect.appendChild(loadingOpt);
                FarmGodCore.loadVillages(settings.optionGroup).then(villages => {
                    cachedVillages = villages;
                    openModal(editCoord, existingCfg);
                });
                modal.style.display = 'flex';
                return;
            }

            Object.entries(cachedVillages).sort(([,a],[,b])=>a.name.localeCompare(b.name)).forEach(([coord, v]) => {
                // Beim Bearbeiten: alle anzeigen; beim Neuanlegen: bereits konfigurierte ausblenden
                if (!editCoord && usedCoords.includes(coord)) return;
                const opt = document.createElement('option');
                opt.value = coord;
                opt.textContent = `${v.name} (${coord})`;
                if (coord === editCoord) opt.selected = true;
                villageSelect.appendChild(opt);
            });

            if (villageSelect.options.length === 0) {
                const opt = document.createElement('option');
                opt.textContent = 'Alle Dörfer bereits konfiguriert';
                opt.disabled = true;
                villageSelect.appendChild(opt);
            }

            // Felder vorausfĂŒllen wenn bearbeiten
            if (existingCfg) {
                modeSelect.value = existingCfg.mode || 'distance';
                distInp.value = existingCfg.distance || settings.optionDistance;
                document.getElementById('af-vs-modal-x1').value = existingCfg.x1 !== undefined ? existingCfg.x1 : 0;
                document.getElementById('af-vs-modal-y1').value = existingCfg.y1 !== undefined ? existingCfg.y1 : 0;
                document.getElementById('af-vs-modal-x2').value = existingCfg.x2 !== undefined ? existingCfg.x2 : 999;
                document.getElementById('af-vs-modal-y2').value = existingCfg.y2 !== undefined ? existingCfg.y2 : 999;
            } else {
                modeSelect.value = 'distance';
                distInp.value = settings.optionDistance;
                document.getElementById('af-vs-modal-x1').value = 0;
                document.getElementById('af-vs-modal-y1').value = 0;
                document.getElementById('af-vs-modal-x2').value = 999;
                document.getElementById('af-vs-modal-y2').value = 999;
            }
            updateModalVisibility();
            villageSelect.disabled = !!editCoord;
            modal.style.display = 'flex';
        }

        // Speichern aus Modal
        saveModalBtn.addEventListener('click', () => {
            const coord = villageSelect.value;
            if (!coord) return;
            const mode = modeSelect.value;
            const entry = { mode };
            if (mode === 'distance' || mode === 'both') {
                const d = parseFloat(distInp.value);
                if (!isNaN(d) && d > 0) entry.distance = d;
            }
            if (mode === 'area' || mode === 'both') {
                entry.x1 = parseFloat(document.getElementById('af-vs-modal-x1').value) || 0;
                entry.y1 = parseFloat(document.getElementById('af-vs-modal-y1').value) || 0;
                entry.x2 = parseFloat(document.getElementById('af-vs-modal-x2').value) || 999;
                entry.y2 = parseFloat(document.getElementById('af-vs-modal-y2').value) || 999;
            }
            settings = loadSettings();
            if (!settings.villageSettings) settings.villageSettings = {};
            settings.villageSettings[coord] = entry;
            // villageDistances sync
            if (!settings.villageDistances) settings.villageDistances = {};
            if ((mode === 'distance' || mode === 'both') && entry.distance) {
                settings.villageDistances[coord] = entry.distance;
            } else {
                delete settings.villageDistances[coord];
            }
            saveSettings(settings);
            modal.style.display = 'none';
            renderConfigList();
        });

        // + Button öffnet Modal
        addBtn.addEventListener('click', () => openModal(null, null));

        // Beim Tab-Klick Dörfer im Hintergrund laden
        if (tabBtn) {
            tabBtn.addEventListener('click', () => {
                if (Object.keys(cachedVillages).length === 0) {
                    settings = loadSettings();
                    FarmGodCore.loadVillages(settings.optionGroup).then(v => { cachedVillages = v; });
                }
            });
        }

        // Dörfer im Hintergrund laden, dann Liste rendern
        function loadAndRender() {
            settings = loadSettings();
            if (Object.keys(cachedVillages).length === 0) {
                FarmGodCore.loadVillages(settings.optionGroup).then(v => {
                    cachedVillages = v;
                    renderConfigList();
                }).catch(() => renderConfigList()); // Fallback: Koordinaten zeigen
            } else {
                renderConfigList();
            }
        }

        setTimeout(() => loadAndRender(), 100);

        // Custom Event fĂŒr switchTab
        document.addEventListener('af-render-config-list', () => loadAndRender());

        body.appendChild(s);
    }

    function switchTab(tab){
        ['settings','katta'].forEach(t=>{
            const el=document.getElementById(`af-tab-${t}`),btn=document.getElementById(`af-tabbt-${t}`);
            if(el)el.style.display=t===tab?'block':'none';
            if(btn)btn.className='af-tab-btn'+(t===tab?' active':'');
        });
        // Bij wisselen naar dörfer tab: lijst opnieuw renderen
        if(tab==='villages'||tab==='night'){
            const cl=document.getElementById('af-vs-config-list');
            if(cl){
                const s=loadSettings();
                const vs=s.villageSettings||{};
                    cl.innerHTML='';
                const entries=Object.entries(vs);
                if(entries.length===0){
                    cl.appendChild(document.createElement('div')).innerText='Keine individuellen Einstellungen vorhanden.';
                    cl.firstChild.style.cssText='color:#666;font-size:11px;padding:8px 0';
                } else {
                    // renderConfigList existiert im closure von buildTabVillages
                    // daher rufen wir es ĂŒber ein Custom Event auf
                    document.dispatchEvent(new CustomEvent('af-render-config-list'));
                }
            }
        }
    }

    function initializeUI(){
        const existing=document.getElementById('af-container');if(existing)existing.remove();

        // ── CSS-Variablen & globale Styles ──────────────────────────────
        if (!document.getElementById('af-styles')) {
            const style = document.createElement('style');
            style.id = 'af-styles';
            style.textContent = `
                #af-container * { box-sizing: border-box; }
                #af-container { --bg0: #0d1117; --bg1: #161b22; --bg2: #21262d; --bg3: #30363d;
                    --gold: #c9a84c; --gold-dim: #8a6f2e; --blue: #4a9eff; --green: #3fb950;
                    --red: #f85149; --orange: #f0883e; --text: #e6edf3; --muted: #8b949e; }
                #af-container input[type=number], #af-container input[type=text],
                #af-container select {
                    background: var(--bg0) !important; color: var(--text) !important;
                    border: 1px solid var(--bg3) !important; border-radius: 6px !important;
                    padding: 5px 8px !important; font-size: 12px !important;
                    transition: border-color .15s;
                }
                #af-container input:focus, #af-container select:focus {
                    outline: none !important; border-color: var(--blue) !important;
                }
                #af-container input[type=checkbox] { accent-color: var(--gold); width:14px; height:14px; }
                .af-btn {
                    border: none; border-radius: 6px; cursor: pointer; font-weight: 600;
                    font-size: 12px; padding: 6px 12px; transition: opacity .15s, transform .1s;
                    letter-spacing: .3px;
                }
                .af-btn:hover { opacity: .85; }
                .af-btn:active { transform: scale(.97); }
                .af-btn-primary { background: var(--blue); color: #fff; }
                .af-btn-gold { background: linear-gradient(135deg, var(--gold), var(--gold-dim)); color: #0d1117; }
                .af-btn-danger { background: var(--red); color: #fff; }
                .af-btn-ghost { background: var(--bg3); color: var(--text); }
                .af-tab-btn {
                    flex: 1; padding: 6px 8px; border: none; background: transparent;
                    color: var(--muted); font-size: 11px; font-weight: 600; cursor: pointer;
                    border-bottom: 2px solid transparent; transition: color .15s, border-color .15s;
                    letter-spacing: .4px; text-transform: uppercase;
                }
                .af-tab-btn.active { color: var(--gold); border-bottom-color: var(--gold); }
                .af-section-label {
                    font-size: 10px; font-weight: 700; letter-spacing: 1px;
                    text-transform: uppercase; color: var(--muted); margin: 12px 0 6px;
                }
                .af-section-label:first-child { margin-top: 0; }
                .af-divider { border: none; border-top: 1px solid var(--bg3); margin: 10px 0; }
                .af-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
                .af-label { color: var(--muted); font-size: 12px; flex: 1; }
                .af-pulse { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
                    background: var(--green); box-shadow: 0 0 0 0 rgba(63,185,80,.4);
                    animation: af-pulse 2s infinite; }
                .af-pulse.paused { background: var(--orange); box-shadow: none; animation: none; }
                .af-pulse.stopped { background: var(--muted); box-shadow: none; animation: none; }
                @keyframes af-pulse {
                    0% { box-shadow: 0 0 0 0 rgba(63,185,80,.4); }
                    70% { box-shadow: 0 0 0 6px rgba(63,185,80,0); }
                    100% { box-shadow: 0 0 0 0 rgba(63,185,80,0); }
                }
                .af-progress-bar { height: 3px; background: var(--bg3); border-radius: 2px; overflow: hidden; margin: 4px 0 8px; }
                .af-progress-fill { height: 100%; background: linear-gradient(90deg, var(--gold), var(--blue));
                    border-radius: 2px; transition: width .4s ease; width: 0%; }
            `;
            document.head.appendChild(style);
        }

        const mk2 = (tag, styles, text) => {
            const e = document.createElement(tag);
            if (styles) Object.assign(e.style, styles);
            if (text !== undefined) e.textContent = text;
            return e;
        };

        const container = mk('div', {
            backgroundColor: 'var(--bg1)', color: 'var(--text)',
            fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
            fontSize: '13px', margin: '0 0 10px 0', borderRadius: '10px',
            boxShadow: '0 4px 24px rgba(0,0,0,.6)', overflow: 'hidden',
            border: '1px solid var(--bg3)'
        });
        container.id = 'af-container';

        // ── Header ───────────────────────────────────────────────────────
        const titleBar = mk('div', {
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            padding: '10px 14px', backgroundColor: 'var(--bg0)',
            borderBottom: '1px solid var(--bg3)', userSelect: 'none', cursor: 'pointer'
        });

        const titleLeft = mk('div', { display: 'flex', alignItems: 'center', gap: '10px' });

        // Logo + Name
        const logoWrap = mk('div', { display: 'flex', alignItems: 'center', gap: '8px' });
        const pulse = mk('div'); pulse.className = 'af-pulse' + (isRunning ? '' : ' stopped');
        pulse.id = 'af-pulse';
        const nameEl = mk('span', { fontWeight: '700', fontSize: '14px', letterSpacing: '.5px',
            background: 'linear-gradient(90deg, var(--gold), #e8c97a)', WebkitBackgroundClip: 'text',
            WebkitTextFillColor: 'transparent' }, 'Anaboles farmen');
        logoWrap.appendChild(pulse);
        logoWrap.appendChild(nameEl);
        titleLeft.appendChild(logoWrap);

        // Mini-Status
        const miniStatus = mk('div', { display: isMinimized ? 'flex' : 'none', alignItems: 'center', gap: '12px', fontSize: '12px' });
        miniStatus.id = 'af-mini-status';
        const statusMini = mk('span', { color: 'var(--gold)', fontWeight: '600' }, currentStatus); statusMini.id = 'af-status-mini';
        const timerMini = mk('span', { color: 'var(--muted)' }, currentCountdownText); timerMini.id = 'af-timer-mini';
        const modeMini = mk('span', { fontSize: '11px' }, ''); modeMini.id = 'af-mode-mini';
        const lootMini = mk('span', { color: 'var(--green)', fontSize: '11px' }, ''); lootMini.id = 'af-loot-mini';
        miniStatus.appendChild(statusMini);
        miniStatus.appendChild(timerMini);
        miniStatus.appendChild(modeMini);
        miniStatus.appendChild(lootMini);

        const miniResumeBtn = mk('button', {
            display: captchaAlertSent ? 'inline-block' : 'none',
            marginLeft: '8px', padding: '2px 8px', border: 'none', borderRadius: '4px',
            cursor: 'pointer', color: '#fff', fontSize: '11px', backgroundColor: 'var(--orange)'
        }, '▶ Fortsetzen');
        miniResumeBtn.id = 'af-mini-resume-btn';
        miniResumeBtn.addEventListener('click', (e) => { e.stopPropagation(); resumeAfterCaptcha(); });
        miniStatus.appendChild(miniResumeBtn);
        titleLeft.appendChild(miniStatus);
        titleBar.appendChild(titleLeft);

        const titleRight = mk('div', { display: 'flex', alignItems: 'center', gap: '6px' });

        const miniToggleBtn = mk('button', {
            display: isMinimized ? 'block' : 'none',
            padding: '3px 10px', border: 'none', borderRadius: '4px',
            cursor: 'pointer', color: '#0d1117', fontSize: '11px', fontWeight: '700',
            background: 'linear-gradient(135deg, var(--gold), var(--gold-dim))'
        });
        miniToggleBtn.id = 'af-mini-toggle-btn';
        miniToggleBtn.addEventListener('click', (e) => { e.stopPropagation(); toggleProcess(); });
        titleRight.appendChild(miniToggleBtn);

        const arrowBtn = mk('button', {
            background: 'none', border: 'none', color: 'var(--muted)',
            cursor: 'pointer', fontSize: '12px', padding: '2px 4px',
            borderRadius: '4px', transition: 'color .15s'
        }, isMinimized ? 'â–Œ' : 'â–Č');
        arrowBtn.id = 'af-arrow';
        arrowBtn.addEventListener('click', (e) => { e.stopPropagation(); toggleMinimize(); });
        titleRight.appendChild(arrowBtn);
        titleBar.appendChild(titleRight);
        titleBar.addEventListener('click', () => toggleMinimize());
        container.appendChild(titleBar);

        // ── Body ─────────────────────────────────────────────────────────
        const body = mk('div', { display: isMinimized ? 'none' : 'block', padding: '12px 14px' });
        body.id = 'af-body';

        // Progress bar (dekorativ, zeigt Farm-Fortschritt)
        const progressWrap = mk('div'); progressWrap.className = 'af-progress-bar';
        const progressFill = mk('div'); progressFill.className = 'af-progress-fill'; progressFill.id = 'af-progress-fill';
        progressWrap.appendChild(progressFill);
        body.appendChild(progressWrap);

        const countdown = mk('div', { display: 'none', marginBottom: '8px', color: 'var(--gold)', fontWeight: '600', fontSize: '12px' });
        countdown.id = 'af-countdown'; body.appendChild(countdown);

        // Tabs
        const tabBar = mk('div', {
            display: 'flex', gap: '0', marginBottom: '12px',
            borderBottom: '1px solid var(--bg3)'
        });
        [['settings', '⚙ Einstellungen'], ['katta', '⚒ Rammen']].forEach(([id, label]) => {
            const btn = mk('button', {}, label);
            btn.className = 'af-tab-btn';
            btn.id = `af-tabbt-${id}`;
            btn.addEventListener('click', () => switchTab(id));
            tabBar.appendChild(btn);
        });
        body.appendChild(tabBar);
        buildTabSettings(body);
        buildTabKatta(body);

        // Start/Stop Button
        const controlButton = mk('button', { display: 'block', width: '100%', padding: '8px', marginTop: '10px' });
        controlButton.className = 'af-btn af-btn-gold';
        controlButton.id = 'af-toggle-btn';
        controlButton.addEventListener('click', toggleProcess);
        body.appendChild(controlButton);

        const resumeButton = mk('button', {
            display: captchaAlertSent ? 'block' : 'none',
            width: '100%', padding: '8px', marginTop: '6px'
        }, '▶ Fortsetzen (Captcha gelöst)');
        resumeButton.className = 'af-btn af-btn-ghost';
        resumeButton.id = 'af-resume-btn';
        resumeButton.addEventListener('click', resumeAfterCaptcha);
        body.appendChild(resumeButton);

        container.appendChild(body);

        const farmWidget = document.getElementById('am_widget_Farm');
        if (farmWidget) {
            farmWidget.parentNode.insertBefore(container, farmWidget);
        } else {
            document.body.appendChild(container);
        }

        updateButtonState();
        ['settings', 'katta'].forEach(t => {
            const btn = document.getElementById(`af-tabbt-${t}`);
            if (btn) btn.className = 'af-tab-btn' + (t === 'settings' ? ' active' : '');
        });
    }


    function buildTabKatta(body) {
        const s = document.createElement('div');
        s.id = 'af-tab-katta';
        s.style.display = 'none';
        s.style.maxHeight = '340px';
        s.style.overflowY = 'auto';
        s.style.paddingRight = '4px';

        const mk2 = (tag, styles, text) => { const e = document.createElement(tag); if(styles)Object.assign(e.style,styles); if(text!==undefined)e.textContent=text; return e; };
        const sec = (t) => { const d=mk2('div',{}); d.className='af-section-label'; d.textContent=t; s.appendChild(d); };
        const sep = () => { const d=document.createElement('hr'); d.className='af-divider'; s.appendChild(d); };
        const addCb = (id, label, checked) => {
            const w = mk2('div',{display:'flex',alignItems:'center',gap:'6px',marginBottom:'5px'});
            const cb = document.createElement('input'); cb.id=id; cb.type='checkbox'; cb.checked=checked;
            const l = mk2('label',{color:'#fff',fontSize:'12px',cursor:'pointer'},label); l.htmlFor=id;
            w.appendChild(cb); w.appendChild(l); s.appendChild(w);
        };
        const addRow = (label, children) => {
            s.appendChild(mk2('div',{color:'#aaa',fontSize:'12px',marginBottom:'2px'},label));
            const row = mk2('div',{display:'flex',gap:'6px',alignItems:'center',marginBottom:'6px'});
            children.forEach(c=>row.appendChild(c)); s.appendChild(row);
        };
        const numInp = (id, val, w) => {
            const e = document.createElement('input'); e.id=id; e.type='number'; e.value=val; e.min=0;
            Object.assign(e.style,{width:w||'60px',padding:'3px 5px',borderRadius:'4px',border:'1px solid #555',backgroundColor:'#1a1a1a',color:'#fff',fontSize:'12px',boxSizing:'border-box'});
            return e;
        };

        const st = loadSettings();

        sec('🔹 Rammen bei roten/gelben Berichten');
        addCb('katta-enabled', 'Aktiviert', st.kattaEnabled);
        addCb('katta-on-red', 'Bei roten Berichten', st.kattaOnRed);
        addCb('katta-on-yellow', 'Bei gelben Berichten', st.kattaOnYellow);

        sep();
        sec('đŸ˜ïž Angreifende Gruppe');
        const gw = mk2('div',{marginBottom:'6px'}); gw.id='katta-group-wrapper';
        gw.innerHTML='<span style="color:#aaa;font-size:11px;">LĂ€dt...</span>';
        s.appendChild(gw);
        FarmGodCore.buildGroupSelect(st.kattaGroup).then(html=>{gw.innerHTML=html;});

        sep();
        sec('⚔ Truppenanzahl');
        addRow('AxtkÀmpfer:', [numInp('katta-axe', st.kattaAxe)]);
        addRow('Rammbock:', [numInp('katta-ram', st.kattaRam)]);
        addRow('SpÀher:', [numInp('katta-spy', st.kattaSpy)]);
        addRow('Katapult:', [numInp('katta-cata', st.kattaCata)]);

        sep();
        sec('🎯 Katapult-ZielgebĂ€ude');
        const buildingSelect = document.createElement('select');
        Object.assign(buildingSelect.style, {width:'100%',backgroundColor:'#1a1a1a',color:'#fff',border:'1px solid #555',borderRadius:'4px',padding:'4px',fontSize:'12px',marginBottom:'10px',boxSizing:'border-box'});
        buildingSelect.id = 'katta-building';
        const buildings = [
            ['wall','Wall'],['main','HauptgebÀude'],['barracks','Kaserne'],
            ['stable','Stall'],['garage','Werkstatt'],['market','Marktplatz'],
            ['wood','HolzfÀller'],['stone','Lehmgrube'],['iron','Eisenmine'],
            ['farm','Bauernhof'],['storage','Speicher'],['hide','Versteck'],
        ];
        buildings.forEach(([val, label]) => {
            const o = document.createElement('option'); o.value=val; o.textContent=label;
            if (val === st.kattaTarget) o.selected=true;
            buildingSelect.appendChild(o);
        });
        s.appendChild(buildingSelect);

        sep();
        // Gesendete Koordinaten anzeigen
        const sentInfo = mk2('div',{color:'#666',fontSize:'10px',marginBottom:'6px'});
        const sent = kattaLoadSent();
        const sentCount = Object.keys(sent).length;
        sentInfo.textContent = `Gespeicherte Katta-Logs: ${sentCount} Dörfer`;
        s.appendChild(sentInfo);
        const clearBtn = mk2('button',{display:'block',width:'100%',marginBottom:'8px'},'🗑 Ramm-Log löschen'); clearBtn.className='af-btn af-btn-danger';
        clearBtn.addEventListener('click', () => {
            localStorage.removeItem(KATTA_SENT_KEY);
            sentInfo.textContent = 'Gespeicherte Katta-Logs: 0 Dörfer';
        });
        s.appendChild(clearBtn);

        const saveBtn = mk2('button',{display:'block',width:'100%'},'Einstellungen speichern'); saveBtn.className='af-btn af-btn-primary';
        saveBtn.addEventListener('click', () => {
            const sel = document.querySelector('#katta-group-wrapper select');
            const ns = Object.assign(loadSettings(), {
                kattaEnabled:   document.getElementById('katta-enabled').checked,
                kattaOnRed:     document.getElementById('katta-on-red').checked,
                kattaOnYellow:  document.getElementById('katta-on-yellow').checked,
                kattaGroup:     sel ? parseInt(sel.value) : st.kattaGroup,
                kattaAxe:       parseInt(document.getElementById('katta-axe').value) || 0,
                kattaRam:       parseInt(document.getElementById('katta-ram').value) || 0,
                kattaSpy:       parseInt(document.getElementById('katta-spy').value) || 0,
                kattaCata:      parseInt(document.getElementById('katta-cata').value) || 0,
                kattaTarget:    document.getElementById('katta-building').value,
            });
            saveSettings(ns); settings = ns;
            saveBtn.textContent = '✓ Gespeichert!';
            setTimeout(()=>{ saveBtn.textContent='Einstellungen speichern'; }, 1500);
        });
        s.appendChild(saveBtn);
        body.appendChild(s);
    }

    // =====================================================================
    // START
    // =====================================================================
    function buildTabNight(body) {
        const s = document.createElement('div');
        s.id = 'af-tab-night';
        s.style.display = 'none';

        const sep = () => s.appendChild(mk('div', {borderTop:'1px solid #444', margin:'8px 0'}));
        const sec = (t) => s.appendChild(mk('div', {color:'#f0a500', fontWeight:'bold', fontSize:'12px', marginBottom:'6px'}, t));
        const addCb = (id, label, checked) => {
            const w = mk('div', {display:'flex', alignItems:'center', gap:'6px', marginBottom:'6px'});
            const cb = document.createElement('input'); cb.id = id; cb.type = 'checkbox'; cb.checked = checked;
            const l = mk('label', {color:'#fff', fontSize:'12px', cursor:'pointer'}, label); l.htmlFor = id;
            w.appendChild(cb); w.appendChild(l); s.appendChild(w);
        };
        const add = (label, children) => {
            s.appendChild(mk('div', {color:'#aaa', fontSize:'12px', marginBottom:'2px'}, label));
            const row = mk('div', {display:'flex', gap:'6px', alignItems:'center', marginBottom:'6px'});
            children.forEach(c => row.appendChild(c));
            s.appendChild(row);
        };

        // Nachtmodus
        sec('🌙 Nachtmodus');
        addCb('af-night-enabled', 'Nachtmodus aktivieren', settings.nightModeEnabled);

        add('Nacht von:', [
            inp('af-night-start', 'time', settings.nightStart, undefined, '90px'),
            mk('span', {color:'#aaa'}, 'bis'),
            inp('af-night-end', 'time', settings.nightEnd, undefined, '90px')
        ]);

        add('Reload-Intervall (Nacht):', [
            inp('af-night-reload-min', 'number', settings.nightReloadMin, 10, '65px'),
            mk('span', {color:'#aaa'}, '–'),
            inp('af-night-reload-max', 'number', settings.nightReloadMax, 10, '65px'),
            mk('span', {color:'#aaa'}, 's')
        ]);

        add('Mindestzeit zwischen Farms (Nacht):', [
            inp('af-night-option-time', 'number', settings.nightOptionTime, 0, '80px'),
            mk('span', {color:'#aaa'}, 'min')
        ]);
        addCb('af-night-maxloot', 'B-Farm bei vollem Loot senden (Nacht)', settings.nightOptionMaxloot);
        addCb('af-night-losses', 'Farms mit Teilverlusten senden (Nacht)', settings.nightOptionLosses);

        // Nachtmodus Status
        const nightStatusEl = mk('div', {fontSize:'11px', marginBottom:'6px', padding:'4px', borderRadius:'4px', backgroundColor:'#1e1e1e'});
        nightStatusEl.id = 'af-night-status';
        nightStatusEl.innerText = isNightMode() ? '🌙 Nachtmodus aktiv' : '☀ Tagmodus aktiv';
        nightStatusEl.style.color = isNightMode() ? '#8e44ad' : '#f0a500';
        s.appendChild(nightStatusEl);

        sep();

        // ZufÀllige Pausen
        sec('⏞ ZufĂ€llige Pausen');
        addCb('af-pause-enabled', 'ZufÀllige Pausen aktivieren', settings.randomPauseEnabled);

        add('Pause alle:', [
            inp('af-pause-interval-min', 'number', settings.randomPauseIntervalMin, 1, '55px'),
            mk('span', {color:'#aaa'}, '–'),
            inp('af-pause-interval-max', 'number', settings.randomPauseIntervalMax, 1, '55px'),
            mk('span', {color:'#aaa'}, 'Min')
        ]);

        add('Pausendauer:', [
            inp('af-pause-duration-min', 'number', settings.randomPauseDurationMin, 1, '55px'),
            mk('span', {color:'#aaa'}, '–'),
            inp('af-pause-duration-max', 'number', settings.randomPauseDurationMax, 1, '55px'),
            mk('span', {color:'#aaa'}, 'Min')
        ]);

        sep();

        const saveBtn = mk('button', {display:'block', width:'100%', padding:'5px', border:'none', borderRadius:'4px', cursor:'pointer', backgroundColor:'#2980b9', color:'#fff', fontSize:'12px'}, 'Einstellungen speichern');
        saveBtn.addEventListener('click', () => {
            const cur = loadSettings();
            const ns = Object.assign({}, cur, {
                nightModeEnabled: document.getElementById('af-night-enabled').checked,
                nightStart: document.getElementById('af-night-start').value,
                nightEnd: document.getElementById('af-night-end').value,
                nightReloadMin: Math.max(10, parseInt(document.getElementById('af-night-reload-min').value) || DEFAULTS.nightReloadMin),
                nightReloadMax: Math.max(10, parseInt(document.getElementById('af-night-reload-max').value) || DEFAULTS.nightReloadMax),
                nightOptionTime: Math.max(0, parseFloat(document.getElementById('af-night-option-time').value) || DEFAULTS.nightOptionTime),
                nightOptionMaxloot: document.getElementById('af-night-maxloot').checked,
                nightOptionLosses: document.getElementById('af-night-losses').checked,
                randomPauseEnabled: document.getElementById('af-pause-enabled').checked,
                randomPauseIntervalMin: Math.max(1, parseInt(document.getElementById('af-pause-interval-min').value) || DEFAULTS.randomPauseIntervalMin),
                randomPauseIntervalMax: Math.max(1, parseInt(document.getElementById('af-pause-interval-max').value) || DEFAULTS.randomPauseIntervalMax),
                randomPauseDurationMin: Math.max(1, parseInt(document.getElementById('af-pause-duration-min').value) || DEFAULTS.randomPauseDurationMin),
                randomPauseDurationMax: Math.max(1, parseInt(document.getElementById('af-pause-duration-max').value) || DEFAULTS.randomPauseDurationMax),
            });
            if (ns.nightReloadMin > ns.nightReloadMax) [ns.nightReloadMin, ns.nightReloadMax] = [ns.nightReloadMax, ns.nightReloadMin];
            if (ns.randomPauseIntervalMin > ns.randomPauseIntervalMax) [ns.randomPauseIntervalMin, ns.randomPauseIntervalMax] = [ns.randomPauseIntervalMax, ns.randomPauseIntervalMin];
            if (ns.randomPauseDurationMin > ns.randomPauseDurationMax) [ns.randomPauseDurationMin, ns.randomPauseDurationMax] = [ns.randomPauseDurationMax, ns.randomPauseDurationMin];
            saveSettings(ns); settings = ns;
            // Status aktualisieren
            const el = document.getElementById('af-night-status');
            if (el) { el.innerText = isNightMode() ? '🌙 Nachtmodus aktiv' : '☀ Tagmodus aktiv'; el.style.color = isNightMode() ? '#8e44ad' : '#f0a500'; }
            saveBtn.textContent = '✓ Gespeichert!';
            setTimeout(() => { saveBtn.textContent = 'Einstellungen speichern'; }, 1500);
        });
        s.appendChild(saveBtn);
        body.appendChild(s);
    }

    initializeUI();
    startCaptchaObserver();
    fetchTodayLoot();

    if(isRunning)startProcess();
    else setStatus('âč Bereit','#aaa');

})();