/**
 * ElectionAppView.js — v11 Election Applied + ABC activity cost
 */
import ElectionMapView from './ElectionMapView.js?v=11';
import ElectionCandidateWidget from './ElectionCandidateWidget.js?v=12';
import { renderElectionAbcPanel, bindElectionAbcPanel } from './election/election-accounting-panel.js?v=1';
const TOKEN_KEY = 'acc_token';
const DEMO_PASS = 'Election1234';

const DEMO_SUPPORTERS = [
    { icon: '◇', title: 'هوادار — رضا نوروزی', desc: 'صندوق ۱۰۱+۱۰۲ · زند', u: 'election_supporter_01', tag: 'Field' },
    { icon: '◇', title: 'هوادار — مریم صادقی', desc: 'صندوق ۱۰۲+۱۰۳ · معالی‌آباد', u: 'election_supporter_02', tag: 'Field' },
    { icon: '◇', title: 'هوادار — علی حیدری', desc: 'صندوق ۱۰۳+۱۰۴ · قصرالدشت', u: 'election_supporter_03', tag: 'Field' },
];

const DEMO_STAFF = [
    { icon: '●', title: 'مدیر — GIS/ERP', desc: 'سامانه هوشمند', u: 'election_admin', tag: 'Admin' },
    { icon: '◇', title: 'اقلام تبلیغاتی', desc: 'انبار و توزیع', u: 'election_dept_goods', tag: 'Logistics' },
    { icon: '◇', title: 'رسانه و تبلیغات', desc: 'بنر و کمپین', u: 'election_dept_media', tag: 'Media' },
    { icon: '◇', title: 'برنامه‌ریزی', desc: 'زمان‌بندی ستاد', u: 'election_dept_planning', tag: 'HQ' },
    { icon: '◇', title: 'سیستم توزیع', desc: 'محموله صندوق‌ها', u: 'election_dept_distribution', tag: 'Logistics' },
    { icon: '◇', title: 'شهرستان‌ها', desc: 'ستاد محلی', u: 'election_dept_counties', tag: 'Local' },
    { icon: '◇', title: 'کمیته اقشار', desc: 'بانوان · جوانان', u: 'election_dept_committees', tag: 'Sectors' },
    { icon: '◆', title: 'حوزه مالی', desc: 'بودجه · گراف ABC', u: 'election_dept_financial', tag: 'Finance' },
];

const DEMO_USERS = [...DEMO_SUPPORTERS, ...DEMO_STAFF];

const ROLE_PORTALS = [
    { u: 'election_supporter_01', tag: 'Field', title: 'هوادار میدانی', desc: 'صندوق، شناسایی اطراف، روز رأی', cls: 'ea-portal--field' },
    { u: 'election_dept_media', tag: 'Media', title: 'رسانه و تبلیغات', desc: 'کمپین، بنر، محتوای ستاد', cls: '' },
    { u: 'election_dept_goods', tag: 'Logistics', title: 'اقلام و انبار', desc: 'توزیع اقلام تبلیغاتی به صندوق‌ها', cls: '' },
    { u: 'election_dept_counties', tag: 'Local', title: 'ستاد شهرستان', desc: 'هماهنگی محلی و اقشار', cls: '' },
    { u: 'election_dept_financial', tag: 'Finance', title: 'حوزه مالی', desc: 'بودجه، تراکنش و گراف فعالیت', cls: 'ea-portal--finance' },
    { u: 'election_admin', tag: 'Admin', title: 'مدیر سامانه', desc: 'GIS، ERP، پهنه و کنترل فاز', cls: 'ea-portal--admin' },
];

const PHASE_ICONS = { pre_campaign: '🔍', campaign: '📢', election_day: '🗳️' };

export default class ElectionAppView {
    constructor() {
        this.token = sessionStorage.getItem(TOKEN_KEY) || '';
        this.meta = {};
        this.me = null;
        this.dashboard = null;
        this.screen = 'landing';
        this.tab = 'dept';
        this.selectedStation = null;
        this.selectedDept = null;
        this.poiTypes = {};
        this._mapView = null;
        this._pickedStations = new Set();
        this._candidateWidget = null;
        this.onReady = null;
    }

    _api() { return (window.ACC_ELECTION_CFG?.api || '/acc-engine/api.php/acc/v1').replace(/\/$/, ''); }
    _site() { const b = window.ACC_ELECTION_CFG?.baseUrl || '/acc-engine/'; return b.endsWith('/') ? b : b + '/'; }
    esc(t) { return String(t ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
    fmt(n) { return n == null ? '—' : Number(n).toLocaleString('fa-IR'); }

    async _req(method, path, body) {
        const opts = { method, headers: { 'Content-Type': 'application/json', Accept: 'application/json' } };
        if (this.token) opts.headers.Authorization = `Bearer ${this.token}`;
        if (body && method !== 'GET') opts.body = JSON.stringify(body);
        const r = await fetch(`${this._api()}/${path.replace(/^\//, '')}`, opts);
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw new Error(j.message || `HTTP ${r.status}`);
        return j;
    }

    async render(root) {
        this.root = root;
        try {
            const m = await this._req('GET', 'public/election/meta');
            this.meta = m.data || {};
            this.poiTypes = this.meta.poi_types || {};
        } catch { this.meta = {}; }

        if (this.token) {
            try {
                await this._loadSession();
                this.screen = 'app';
            } catch {
                this.token = '';
                sessionStorage.removeItem(TOKEN_KEY);
                this.screen = 'landing';
            }
        }
        this._paint();
        this._mountCandidateWidget();
    }

    _mountCandidateWidget() {
        if (window._elCandidateWidget) {
            this._candidateWidget = window._elCandidateWidget;
        } else if (!this._candidateWidget) {
            this._candidateWidget = new ElectionCandidateWidget({ hub: this.meta.candidate_hub });
            this._candidateWidget.mount(document.body);
            window._elCandidateWidget = this._candidateWidget;
        }
        this._candidateWidget.setToken(this.token);
        if (this.meta.candidate_hub) this._candidateWidget.hub = this.meta.candidate_hub;
        if (typeof this.onReady === 'function') this.onReady();
    }

    _isSupporter() {
        return this.dashboard?.portal_mode === 'supporter'
            || this.dashboard?.role === 'supporter';
    }

    async _loadSession() {
        const me = await this._req('GET', 'election/me');
        this.me = me.data;
        const dash = await this._req('GET', 'election/dashboard');
        this.dashboard = dash.data;
        if (this.dashboard?.role === 'admin') this.tab = 'units';
        else if (this._isSupporter()) this.tab = 'home';
        else if (this.dashboard?.show_financial && this.dashboard?.department?.slug === 'financial') this.tab = 'accounting';
        else this.tab = 'dept';
        const sts = this.dashboard?.stations || [];
        if (sts.length && !this.selectedStation) this.selectedStation = sts[0].id;
    }

    _paint() {
        if (this.screen === 'app') {
            this.root.innerHTML = this._appShell();
            this._bindApp();
            this._renderTab();
            return;
        }
        this.root.innerHTML = this._landingHtml();
        this._bindLanding();
    }

    _phaseBar(phase) {
        const p = phase?.current_phase || 'pre_campaign';
        const phases = phase?.phases || this.meta.phases || {};
        const keys = Object.keys(phases);
        return `<div class="el-phase-bar">${keys.map(k => `
            <div class="el-phase-step ${k === p ? 'el-phase-step--on' : ''} ${keys.indexOf(k) < keys.indexOf(p) ? 'el-phase-step--done' : ''}">
                <span>${PHASE_ICONS[k] || '•'}</span>
                <small>${this.esc(phases[k]?.split('—')[0]?.trim() || phases[k] || k)}</small>
            </div>`).join('')}</div>`;
    }

    _landingHtml() {
        const s = this.meta.stats || {};
        const seg = s.segment_progress || this.meta.segment_progress || {};
        const site = this._site();
        const portals = ROLE_PORTALS.map(p => `
            <button type="button" class="ea-portal ${p.cls}" data-u="${p.u}" data-p="${DEMO_PASS}">
                <span class="ea-portal__tag">${p.tag}</span>
                <strong>${this.esc(p.title)}</strong>
                <small>${this.esc(p.desc)}</small>
                <span class="ea-portal__go">ورود نقش ←</span>
            </button>`).join('');

        const demoRows = DEMO_USERS.map(d => `
            <button type="button" class="el-demo-row" data-u="${d.u}" data-p="${DEMO_PASS}">
                <span class="el-demo-row__icon">${d.icon}</span>
                <span class="el-demo-row__body"><strong>${this.esc(d.title)}</strong><small>${this.esc(d.desc)}</small><code>${d.u}</code></span>
                <span class="el-demo-row__badge">ورود ↗</span>
            </button>`).join('');

        return `
        <div class="el-app el-landing ea-applied" dir="rtl">
            <div class="ea-util">
                <a href="${site}">ACC Engine</a>
                <a href="${site}melk.php">اقتصاد ملک</a>
                <a href="${site}shop.php">فروشگاه</a>
                <a href="#ea-accounting" class="ea-util__accent">حسابداری فعالیت</a>
            </div>

            <header class="ea-header" id="ea-header">
                <a href="${site}election.php" class="ea-brand">
                    <span class="ea-brand__mark">ه</span>
                    <span class="ea-brand__text">
                        <span class="ea-brand__name">هوادران <em>Applied</em></span>
                        <span class="ea-brand__sub">Civic Campaign Operations</span>
                    </span>
                </a>
                <nav class="ea-nav">
                    <a href="#ea-pillars">اکوسیستم</a>
                    <a href="#ea-portals">ورود نقش‌ها</a>
                    <a href="#ea-story">عملیات میدانی</a>
                    <a href="#ea-accounting">حسابداری</a>
                    <button type="button" id="el-demo-btn">ورود آزمایشی</button>
                </nav>
                <button type="button" class="ea-header__cta ea-header__cta--crimson" data-u="election_supporter_01" data-p="${DEMO_PASS}">ورود هوادار</button>
            </header>

            <div class="el-demo-panel" id="el-demo-panel" style="display:none">
                <div class="el-demo-panel__inner">
                    <div class="el-demo-panel__head">
                        <span>ورود آزمایشی</span>
                        <button type="button" id="el-demo-close">✕</button>
                    </div>
                    <p class="el-demo-note">رمز همه: <code>${DEMO_PASS}</code></p>
                    <div class="el-demo-list">${demoRows}</div>
                </div>
            </div>

            <section class="ea-hero">
                <div class="ea-hero__media" aria-hidden="true"></div>
                <div class="ea-hero__grain" aria-hidden="true"></div>
                <div class="ea-hero__content">
                    <p class="ea-hero__brand">Election <span>Applied</span></p>
                    <h1>سامانه هوادران<br><em>از صندوق تا ستاد</em></h1>
                    <p class="ea-hero__lead">پلتفرم عملیات مدنی انتخابات — صندوق، شناسایی اطراف، ستاد موقت، GIS و شفافیت هزینه فعالیت‌های کمپین.</p>
                    <div class="ea-hero__actions">
                        <a href="#ea-portals" class="ea-btn ea-btn--crimson">ورود به شبکه</a>
                        <a href="#ea-story" class="ea-btn ea-btn--ghost">کشف عملیات</a>
                    </div>
                </div>
            </section>

            <section class="ea-section" id="ea-pillars">
                <div class="ea-section__head ea-reveal">
                    <span class="ea-kicker">Ecosystem</span>
                    <h2>چهار ستون عملیات انتخابات</h2>
                    <p>طراحی‌شده برای مدیریت موقت هزاران نفر در مقطع کوتاه قبل از رأی — نه فقط آمار، بلکه حاکمیت میدانی و مالی.</p>
                </div>
                <div class="ea-pillars ea-reveal">
                    <article class="ea-pillar"><span class="ea-pillar__num">01</span><strong>صندوق‌محور</strong><span>هر هوادار چند صندوق — شناسایی اطراف، اقلام، حضور روز رأی</span></article>
                    <article class="ea-pillar"><span class="ea-pillar__num">02</span><strong>ستاد موقت</strong><span>ساختار اداری فازبندی‌شده که پس از رأی‌گیری منحل می‌شود</span></article>
                    <article class="ea-pillar"><span class="ea-pillar__num">03</span><strong>GIS و پهنه</strong><span>پوشش ۱۰۱۱ پهنه، نقشه، ایستگاه و هوش مکانی برای مدیر</span></article>
                    <article class="ea-pillar"><span class="ea-pillar__num">04</span><strong>شفافیت مالی</strong><span>بودجه، تراکنش و گراف بهای تمام‌شده فعالیت کمپین</span></article>
                </div>
            </section>

            <section class="ea-section ea-section--ink ea-reveal">
                <div class="ea-stats">
                    <div class="ea-stat"><strong>${this.fmt(seg.total ?? s.segments ?? 0)}</strong><span>پهنه GIS</span></div>
                    <div class="ea-stat"><strong>${this.fmt(s.stations ?? 4)}</strong><span>صندوق</span></div>
                    <div class="ea-stat"><strong>۳</strong><span>فاز عملیات</span></div>
                    <div class="ea-stat"><strong>ABC</strong><span>گراف هزینه فعالیت</span></div>
                </div>
            </section>

            <section class="ea-section ea-section--mist" id="ea-portals">
                <div class="ea-section__head ea-reveal">
                    <span class="ea-kicker">Access</span>
                    <h2>ورود به پورتال نقش شما</h2>
                    <p>هر نقش فضای کاری اختصاصی دارد — از هوادار میدانی تا رسانه، شهرستان و مالی.</p>
                </div>
                <div class="ea-portals ea-reveal">${portals}</div>
            </section>

            <section class="ea-section" id="ea-story">
                <div class="ea-story ea-reveal">
                    <div class="ea-story__media" role="img" aria-label="عملیات مدنی انتخابات"></div>
                    <div class="ea-story__body">
                        <span class="ea-kicker">Field Ops</span>
                        <h3>شش مرحله عملیات میدانی روی صندوق</h3>
                        <p>تخصیص صندوق، شناسایی اطراف، تبلیغات، روز رأی، گزارش و تشکیلات — همه در میز کار هوادار. ستاد هم GIS، انبار، بنر و اقشار را مدیریت می‌کند.</p>
                        <div style="display:flex;flex-wrap:wrap;gap:10px">
                            <button type="button" class="ea-btn ea-btn--dark" data-u="election_supporter_01" data-p="${DEMO_PASS}">میز کار هوادار</button>
                            <button type="button" class="ea-btn ea-btn--outline" id="el-open-candidate-widget">راهنمای کاندید</button>
                            <button type="button" class="ea-btn ea-btn--outline" id="el-open-integrity-landing">استاندارد OSCE</button>
                        </div>
                    </div>
                </div>
            </section>

            <section class="ea-section ea-section--mist" id="ea-accounting">
                <div class="ea-section__head ea-reveal">
                    <span class="ea-kicker">Cost Graph</span>
                    <h2>حسابداری فعالیت کمپین</h2>
                    <p>بهای تمام‌شده فعالیت‌های ستاد — سهم رسانه، توزیع، میدانی، مالی و هواداران روی گراف کمپین ↔ فعالیت ↔ خدمه.</p>
                </div>
                <div class="ea-reveal" style="max-width:720px">
                    <button type="button" class="ea-btn ea-btn--dark" data-u="election_dept_financial" data-p="${DEMO_PASS}" data-goto-tab="accounting">ورود به گراف حسابداری ←</button>
                    <p style="margin-top:14px;color:var(--ea-muted);font-size:.92rem">پس از ورود، تب «حسابداری فعالیت» را باز کنید یا از نقش حوزه مالی استفاده کنید.</p>
                </div>
            </section>

            <section class="ea-section">
                <div class="ea-section__head ea-reveal">
                    <span class="ea-kicker">Join</span>
                    <h2>پیوستن هوادار — SMS</h2>
                    <p>دعوت با پیامک، کد تأیید، ثبت‌نام خودکار.</p>
                </div>
                <form class="ea-onboard ea-reveal" id="el-onboarding-form">
                    <label style="display:block;margin-bottom:10px">نام<input name="name" placeholder="نام و نام خانوادگی" style="width:100%;padding:10px;margin-top:4px;border:1px solid var(--ea-line);font-family:inherit"></label>
                    <label style="display:block;margin-bottom:10px">موبایل<input name="phone" required dir="ltr" placeholder="0912..." style="width:100%;padding:10px;margin-top:4px;border:1px solid var(--ea-line);font-family:inherit"></label>
                    <label style="display:block;margin-bottom:10px">کد تأیید<input name="code" dir="ltr" placeholder="پس از دریافت SMS" style="width:100%;padding:10px;margin-top:4px;border:1px solid var(--ea-line);font-family:inherit"></label>
                    <div style="display:flex;gap:10px;flex-wrap:wrap">
                        <button type="button" class="ea-btn ea-btn--outline" id="el-onboard-request">دریافت کد</button>
                        <button type="submit" class="ea-btn ea-btn--crimson">ثبت‌نام ✓</button>
                    </div>
                    <div id="el-onboard-msg" class="el-msg" style="margin-top:12px"></div>
                </form>
            </section>

            <section class="ea-help">
                <div class="ea-help__inner">
                    <div>
                        <h2>چطور کمک کنیم؟</h2>
                        <p>میدان، رسانه، شهرستان یا شفافیت مالی — مسیر درست را انتخاب کنید.</p>
                    </div>
                    <div class="ea-help__actions">
                        <button type="button" class="ea-btn ea-btn--solid" data-u="election_supporter_01" data-p="${DEMO_PASS}">هوادار</button>
                        <button type="button" class="ea-btn" data-u="election_dept_media" data-p="${DEMO_PASS}">رسانه</button>
                        <button type="button" class="ea-btn" data-u="election_dept_financial" data-p="${DEMO_PASS}" data-goto-tab="accounting">حسابداری</button>
                        <button type="button" class="ea-btn" data-u="election_admin" data-p="${DEMO_PASS}">مدیر</button>
                    </div>
                </div>
            </section>

            <footer class="ea-footer">
                <span>© Election Applied — سامانه هوادران</span>
                <span>
                    <a href="${site}">ACC Engine</a> ·
                    <a href="${site}melk.php">ملک</a> ·
                    <a href="${site}shop.php">فروشگاه</a> ·
                    <a href="${site}service.php">خدمات</a>
                </span>
            </footer>
        </div>`;
    }

    _appShell() {
        const dept = this.dashboard?.department;
        const isAdmin = this.dashboard?.role === 'admin';
        const isSup = this._isSupporter();
        const isField = isSup || this.dashboard?.show_stations || dept?.slug === 'field_operations';
        const name = isSup
            ? (this.me?.user?.display_name || 'هوادار')
            : (dept?.title || this.me?.user?.display_name || '');
        const roleLabel = isAdmin ? 'مدیر سامانه' : isSup ? 'هوادار — عملیات میدانی' : 'کاربر واحد';

        let tabs;
        if (isAdmin) {
            tabs = [
                { id: 'units', icon: '🏛️', label: 'واحدها' },
                { id: 'org', icon: '📊', label: 'چارت' },
                { id: 'warehouse', icon: '📦', label: 'انبار' },
                { id: 'banners', icon: '🪧', label: 'بنرها' },
                { id: 'map', icon: '🗺️', label: 'نقشه' },
                { id: 'gis', icon: '🛰️', label: 'GIS' },
                { id: 'segments', icon: '📍', label: 'پهنه 1011' },
                { id: 'financial', icon: '💰', label: 'مالی' },
                { id: 'accounting', icon: '◈', label: 'حسابداری فعالیت' },
                { id: 'candidate-admin', icon: '💡', label: 'پیشنهادات' },
                { id: 'integrity', icon: '🏆', label: 'OSCE' },
                { id: 'sectors', icon: '👥', label: 'اقشار' },
                { id: 'stations', icon: '🗳️', label: 'صندوق' },
                { id: 'sms', icon: '📱', label: 'SMS' },
            ];
        } else if (isSup) {
            tabs = [
                { id: 'home', icon: '🏠', label: 'میز کار' },
                { id: 'candidate', icon: '🗳️', label: 'کاندید' },
                { id: 'sectors', icon: '👥', label: 'اقشار' },
                { id: 'integrity', icon: '🏆', label: 'OSCE' },
                { id: 'map', icon: '🗺️', label: 'نقشه' },
                { id: 'stations', icon: '1️⃣', label: 'صندوق' },
                { id: 'poi', icon: '2️⃣', label: 'شناسایی' },
                { id: 'campaign', icon: '3️⃣', label: 'تبلیغات' },
                { id: 'banners', icon: '🪧', label: 'محل بنر' },
                { id: 'tasks', icon: '4️⃣', label: 'روز رأی' },
                { id: 'report', icon: '5️⃣', label: 'گزارش' },
                { id: 'org-info', icon: '6️⃣', label: 'تشکیلات' },
            ];
        } else {
            tabs = [
                { id: 'dept', icon: dept?.icon || '🏢', label: 'واحد من' },
                ...(dept?.slug === 'counties' ? [{ id: 'county', icon: '🏛️', label: 'شهرستان‌ها' }] : []),
                ...(dept?.slug === 'committees' ? [{ id: 'committee', icon: '👥', label: 'کمیته اقشار' }] : []),
                { id: 'work', icon: '✅', label: 'کارهای واحد' },
                ...(isField ? [
                    { id: 'stations', icon: '🗳️', label: 'صندوق‌ها' },
                    { id: 'poi', icon: '📍', label: 'شناسایی' },
                    { id: 'tasks', icon: '📋', label: 'وظایف فاز' },
                ] : []),
                ...(this.dashboard?.show_map ? [{ id: 'map', icon: '🗺️', label: 'نقشه GIS' }] : []),
                ...(this.dashboard?.show_media ? [{ id: 'campaign', icon: '📢', label: 'تبلیغات' }] : []),
                ...(this.dashboard?.show_banners ? [{ id: 'banners', icon: '🪧', label: 'محل بنر' }] : []),
                ...(this.dashboard?.show_warehouse ? [{ id: 'warehouse', icon: '📦', label: 'انبار' }] : []),
                ...(this.dashboard?.show_financial ? [
                    { id: 'financial', icon: '💰', label: 'مالی' },
                    { id: 'accounting', icon: '◈', label: 'حسابداری فعالیت' },
                ] : []),
                ...(this.dashboard?.department?.slug === 'committees' || this.dashboard?.department?.slug === 'counties'
                    ? [{ id: 'sectors', icon: '👥', label: 'اقشار' }] : []),
                { id: 'report', icon: '📝', label: 'گزارش' },
            ];
        }

        return `<div class="el-app el-workspace ea-applied${isSup ? ' el-workspace--supporter' : ''}" dir="rtl">
            <header class="el-header el-header--app">
                <span class="ea-ws-mark">ه</span>
                <span class="el-brand">${this.esc(name)}</span>
                <span class="el-role">${roleLabel}</span>
                <nav class="el-tabs">${tabs.map(t => `
                    <button type="button" class="el-tab ${t.id === 'accounting' ? 'el-tab--acct' : ''} ${this.tab === t.id ? 'el-tab--on' : ''}" data-tab="${t.id}">${t.icon} ${t.label}</button>
                `).join('')}</nav>
                <button type="button" class="el-btn el-btn--ghost" id="el-logout">خروج</button>
            </header>
            ${this._phaseBar(this.dashboard?.phase)}
            <main class="el-main" id="el-main"></main>
        </div>`;
    }

    _bindLanding() {
        const panel = this.root.querySelector('#el-demo-panel');
        const toggle = s => { if (panel) panel.style.display = s ? 'block' : 'none'; };
        this.root.querySelector('#el-demo-btn')?.addEventListener('click', () => toggle(panel?.style.display === 'none'));
        this.root.querySelector('#el-demo-close')?.addEventListener('click', () => toggle(false));

        const doLogin = async (u, p, gotoTab) => {
            try {
                await this._login(u, p);
                if (gotoTab) {
                    this.tab = gotoTab;
                    this._paint();
                }
            } catch (e) {
                alert(e.message || 'ورود ناموفق');
            }
        };
        this.root.querySelectorAll('[data-u]').forEach(b => {
            b.addEventListener('click', () => doLogin(b.dataset.u, b.dataset.p, b.dataset.gotoTab || ''));
        });

        this._bindOnboarding();
        this.root.querySelector('#el-open-candidate-widget')?.addEventListener('click', () => {
            this._mountCandidateWidget();
            this._candidateWidget?.toggle(true);
            if (this._candidateWidget) this._candidateWidget.section = 'intro';
            this._candidateWidget?._paint();
        });
        this.root.querySelector('#el-open-integrity-landing')?.addEventListener('click', () => {
            this._mountCandidateWidget();
            this._candidateWidget?.toggle(true);
            if (this._candidateWidget) this._candidateWidget.section = 'standards';
            this._candidateWidget?._paint();
        });

        const header = this.root.querySelector('#ea-header');
        if (header) {
            const onScroll = () => header.classList.toggle('ea-header--scrolled', window.scrollY > 24);
            window.addEventListener('scroll', onScroll, { passive: true });
            onScroll();
        }
        const io = typeof IntersectionObserver !== 'undefined'
            ? new IntersectionObserver((ents) => {
                ents.forEach(e => { if (e.isIntersecting) e.target.classList.add('is-in'); });
            }, { threshold: 0.12 })
            : null;
        this.root.querySelectorAll('.ea-reveal').forEach(el => {
            if (io) io.observe(el);
            else el.classList.add('is-in');
        });
    }

    _bindOnboarding() {
        const msg = () => this.root.querySelector('#el-onboard-msg');
        this.root.querySelector('#el-onboard-request')?.addEventListener('click', async () => {
            const form = this.root.querySelector('#el-onboarding-form');
            const phone = form?.phone?.value?.trim();
            const m = msg();
            if (!phone) { m.textContent = 'موبایل الزامی'; m.className = 'el-msg el-msg--err'; return; }
            try {
                const r = await this._req('POST', 'public/election/onboarding/request', { phone });
                m.textContent = r.demo_code ? `✅ کد (دمو): ${r.demo_code}` : (r.demo_mode === false ? '✅ کد از طریق SMS ارسال شد' : '✅ کد ارسال شد');
                m.className = 'el-msg el-msg--ok';
            } catch (e) { m.textContent = e.message; m.className = 'el-msg el-msg--err'; }
        });
        this.root.querySelector('#el-onboarding-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const m = msg();
            const fd = new FormData(e.target);
            try {
                const r = await this._req('POST', 'public/election/onboarding/complete', Object.fromEntries(fd));
                m.textContent = r.login ? `✅ ${r.message} — کاربر: ${r.login}` : '✅ ثبت شد';
                m.className = 'el-msg el-msg--ok';
            } catch (err) { m.textContent = err.message; m.className = 'el-msg el-msg--err'; }
        });
    }

    _bindApp() {
        this.root.querySelector('#el-logout')?.addEventListener('click', () => {
            this.token = ''; sessionStorage.removeItem(TOKEN_KEY);
            this.screen = 'landing'; this.render(this.root);
        });
        this.root.querySelectorAll('[data-tab]').forEach(b => {
            b.addEventListener('click', () => { this.tab = b.dataset.tab; this._paint(); });
        });
    }

    async _login(u, p) {
        const res = await this._req('POST', 'public/auth/login', { username: u, password: p });
        if (!res.success || !res.token) throw new Error(res.message || 'ورود ناموفق');
        this.token = res.token;
        sessionStorage.setItem(TOKEN_KEY, res.token);
        await this._loadSession();
        this.screen = 'app';
        this._paint();
    }

    async _renderTab() {
        const main = this.root.querySelector('#el-main');
        if (!main) return;
        const role = this.dashboard?.role;
        try {
            switch (this.tab) {
                case 'home': main.innerHTML = this._supporterHomeHtml(); this._bindHome(main); break;
                case 'candidate': main.innerHTML = this._candidateTabHtml(); this._bindCandidateTab(main); break;
                case 'dept': main.innerHTML = this._deptHomeHtml(); break;
                case 'work': main.innerHTML = this._deptWorkHtml(); this._bindDeptWork(main); break;
                case 'units': main.innerHTML = this._unitsAdminHtml(); this._bindUnitsAdmin(main); break;
                case 'admin': main.innerHTML = this._adminHtml(); this._bindAdminPhase(main); break;
                case 'stations': main.innerHTML = await this._stationsTabHtml(role); this._bindStationSelect(main); break;
                case 'poi': main.innerHTML = this._poiTabHtml(); this._bindPoi(main); break;
                case 'tasks': main.innerHTML = this._tasksHtml(); this._bindTasks(main); break;
                case 'campaign':
                case 'briefings': main.innerHTML = this._campaignHtml(); this._bindBriefings(main); break;
                case 'banners': main.innerHTML = this._bannersHtml(); this._bindBanners(main); break;
                case 'warehouse': main.innerHTML = await this._warehouseHtml(); this._bindWarehouse(main); break;
                case 'map': await this._renderMapTab(main); break;
                case 'county': main.innerHTML = this._countyPortalHtml(); break;
                case 'committee': main.innerHTML = this._committeePortalHtml(); break;
                case 'org-info': main.innerHTML = this._orgInfoHtml(); break;
                case 'report': main.innerHTML = this._reportHtml(); this._bindReport(main); break;
                case 'gis': {
                    const [gis, erp] = await Promise.all([
                        this._req('GET', 'election/admin/gis-intel'),
                        this._req('GET', 'election/admin/erp-intel'),
                    ]);
                    main.innerHTML = this._gisHtml(gis.data, erp.data);
                    break;
                }
                case 'org': {
                    const org = this.dashboard?.org_structure || this.meta.org_structure;
                    main.innerHTML = this._orgHtml(org);
                    break;
                }
                case 'sms': main.innerHTML = this._smsHtml(); this._bindSms(main); break;
                case 'financial': main.innerHTML = await this._financialHtml(); this._bindFinancial(main); break;
                case 'accounting':
                    main.innerHTML = renderElectionAbcPanel(this.esc.bind(this));
                    await bindElectionAbcPanel(main, {
                        request: (m, p, b) => this._req(m, p, b),
                        esc: this.esc.bind(this),
                        toast: (msg, err) => {
                            const n = document.createElement('div');
                            n.className = err ? 'el-msg el-msg--err' : 'el-msg el-msg--ok';
                            n.textContent = msg;
                            n.style.cssText = 'position:fixed;bottom:24px;left:24px;z-index:9999;padding:12px 16px;background:#fff;border:1px solid #ddd;box-shadow:0 8px 24px rgba(0,0,0,.12)';
                            document.body.appendChild(n);
                            setTimeout(() => n.remove(), 2800);
                        },
                    });
                    break;
                case 'segments': main.innerHTML = await this._segmentsHtml(); this._bindSegments(main); break;
                case 'candidate-admin': main.innerHTML = await this._candidateAdminHtml(); this._bindCandidateAdmin(main); break;
                case 'integrity': main.innerHTML = await this._integrityHtml(); break;
                case 'sectors': main.innerHTML = await this._sectorsPageHtml(); this._bindSectorsPage(main); break;
            }
        } catch (err) {
            main.innerHTML = `<div class="el-msg el-msg--err">${this.esc(err.message)}</div>`;
        }
    }

    _deptHomeHtml() {
        const dept = this.dashboard?.department;
        const d = this.dashboard || {};
        if (!dept) return this._homeHtml();
        const duties = dept.duties || [];
        const bureauId = (this.meta.departments || []).find(x => x.slug === dept.slug)?.bureau;
        const bureau = (this.meta.org_structure?.bureaus || []).find(b => b.id === bureauId);
        return `<div class="el-dept-page">
            <div class="el-adm-lifecycle el-adm-lifecycle--sm">${(this.meta.org_structure?.lifecycle || []).map((l, i) => `
                <div class="el-adm-lifecycle__step"><span class="el-adm-lifecycle__num">${i + 1}</span><strong>${this.esc(l.phase)}</strong></div>
                ${i < 2 ? '<span class="el-adm-lifecycle__arrow">←</span>' : ''}`).join('')}</div>
            <div class="el-hq-banner">
                <span class="el-dept-card__icon el-dept-card__icon--lg">${dept.icon || '🏢'}</span>
                <h2>${this.esc(dept.title)}</h2>
                ${bureau ? `<p class="el-adm-bureau-tag">${bureau.icon || '🏢'} ${this.esc(bureau.title)} — واحد سازمانی ستاد موقت</p>` : ''}
                <p><strong>موضوع کاری:</strong> ${this.esc(dept.work_subject || '')}</p>
            </div>
            <h3>شرح وظایف</h3>
            <ul class="el-duty-list">${duties.map(x => `<li>${this.esc(x)}</li>`).join('')}</ul>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${d.dept_work_pending ?? 0}</strong><span>کار باز</span></div>
                ${d.show_stations ? `<div class="el-card"><strong>${d.station_count ?? 0}</strong><span>صندوق</span></div>` : ''}
                <div class="el-card"><strong>${d.tasks_pending ?? 0}</strong><span>وظیفه فاز</span></div>
            </div>
            <button type="button" class="el-btn el-btn--primary" data-goto="work">✅ کارهای واحد</button>
        </div>`;
    }

    _deptWorkHtml() {
        const items = this.dashboard?.dept_work || [];
        const dept = this.dashboard?.department;
        return `<div class="el-dept-work">
            <h3>کارهای ${this.esc(dept?.title || 'واحد')}</h3>
            <form class="el-poi-form" id="el-dept-work-form">
                <label>عنوان کار<input name="title" required placeholder="کار جدید واحد"></label>
                <label>شرح<textarea name="body" rows="2"></textarea></label>
                <button type="submit" class="el-btn el-btn--primary el-btn--sm">ثبت ✓</button>
            </form>
            <div class="el-mission-list">${items.map(w => `
                <article class="el-mission el-mission--${w.status}">
                    <strong>${this.esc(w.title)}</strong>
                    <p>${this.esc(w.body || '')}</p>
                    ${w.status === 'pending' ? `<button type="button" class="el-btn el-btn--sm el-btn--primary" data-dw="${w.id}">انجام شد</button>` : ''}
                </article>`).join('') || '<p class="el-empty">کاری ثبت نشده</p>'}</div>
        </div>`;
    }

    _bindDeptWork(main) {
        main.querySelector('#el-dept-work-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const fd = new FormData(e.target);
            await this._req('POST', 'election/dept-work', Object.fromEntries(fd));
            await this._loadSession();
            this._paint();
        });
        main.querySelectorAll('[data-dw]').forEach(b => b.addEventListener('click', async () => {
            await this._req('POST', `election/dept-work/${b.dataset.dw}/complete`, {});
            await this._loadSession();
            this._paint();
        }));
        main.querySelectorAll('[data-goto]').forEach(b => {
            b.addEventListener('click', () => { this.tab = b.dataset.goto; this._paint(); });
        });
    }

    _unitsAdminHtml() {
        const org = this.dashboard?.org_structure || this.meta.org_structure;
        const depts = this.dashboard?.departments || [];
        const enriched = org ? {
            ...org,
            bureaus: (org.bureaus || []).map(b => ({
                ...b,
                units: (b.units || []).map(u => ({
                    ...u,
                    work_count: depts.find(d => d.slug === u.slug)?.work_count,
                })),
            })),
        } : org;
        return `<div class="el-units-admin">
            <div class="el-intel-note">مدیر ستاد — ${depts.length} واحد سازمانی · هر واحد کاربری مجزا · GIS/ERP فقط اینجا</div>
            ${this._adminStructureHtml(enriched, { clickable: true })}
            <div id="el-dept-detail" class="el-dept-detail"></div>
        </div>`;
    }

    _bindUnitsAdmin(main) {
        main.querySelectorAll('.el-adm-unit[data-dept-slug]').forEach(c => {
            c.addEventListener('click', async () => {
                main.querySelectorAll('.el-adm-unit').forEach(x => x.classList.remove('el-adm-unit--on'));
                c.classList.add('el-adm-unit--on');
                const slug = c.dataset.deptSlug;
                const r = await this._req('GET', `election/dept-work?dept_slug=${slug}`);
                const cat = (this.meta.departments || []).find(x => x.slug === slug) || {};
                const detail = main.querySelector('#el-dept-detail');
                detail.innerHTML = `<h3>${this.esc(cat.title || slug)}</h3>
                    <p class="el-hint">${this.esc(cat.work_subject || '')}</p>
                    <ul>${(r.data || []).map(w => `<li>${this.esc(w.title)} — <span class="el-badge">${w.status}</span></li>`).join('') || '<li>—</li>'}</ul>`;
            });
        });
    }

    _supporterHomeHtml() {
        const d = this.dashboard || {};
        const sup = d.supporter || {};
        const steps = this.meta.field_workflow || [];
        const sts = d.stations || [];
        const pois = d.pois || [];
        const banners = d.banner_spots || [];
        const progress = {
            stations: sts.length > 0,
            poi: pois.length >= 3,
            campaign: (d.shipments || []).some(s => s.status === 'received') || (d.briefings || []).length > 0,
            tasks: (d.tasks || []).some(t => t.status === 'done'),
            report: false,
        };
        return `<div class="el-supporter-home">
            <div class="el-hq-banner el-hq-banner--supporter">
                <h2>${this.esc(d.tagline || 'هوادار — عملیات میدانی')}</h2>
                <p>${this.esc(sup.branch?.name || '')} ${sup.branch?.category_label ? '· ' + this.esc(sup.branch.category_label) : ''}</p>
                <p>فاز: <strong>${this.esc(d.phase?.phase_label || '')}</strong> — ${sts.length} صندوق</p>
            </div>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${sts.length}</strong><span>صندوق</span></div>
                <div class="el-card"><strong>${pois.length}</strong><span>مکان شناسایی</span></div>
                <div class="el-card"><strong>${banners.length}</strong><span>محل بنر</span></div>
                <div class="el-card"><strong>${d.tasks_pending ?? 0}</strong><span>وظیفه باز</span></div>
                <div class="el-card"><strong>${(d.shipments || []).filter(s => s.status === 'shipped').length}</strong><span>محموله</span></div>
            </div>
            <h3>مسیر ۶ مرحله‌ای عملیات میدانی</h3>
            <div class="el-workflow-track">${steps.map(w => {
                const done = w.tab === 'stations' ? progress.stations
                    : w.tab === 'poi' ? progress.poi
                    : w.tab === 'campaign' ? progress.campaign
                    : w.tab === 'tasks' ? progress.tasks
                    : false;
                return `<button type="button" class="el-workflow-step ${done ? 'el-workflow-step--done' : ''}" data-goto="${w.tab}">
                    <span class="el-workflow-step__num">${w.step}</span>
                    <strong>${this.esc(w.title)}</strong>
                    <small>${this.esc(w.desc)}</small>
                </button>`;
            }).join('')}</div>
            <h3>صندوق‌های من</h3>
            <div class="el-station-grid">${sts.map(s => this._stationCard(s)).join('') || '<p class="el-empty">صندوقی تخصیص نشده</p>'}</div>
        </div>`;
    }

    _campaignHtml() {
        const items = this.dashboard?.warehouse_items || [];
        const wh = this.dashboard?.warehouse || {};
        const shipments = this.dashboard?.shipments || [];
        return `${this._briefingsHtml()}
            <section class="el-shipment-chain">
                <h3>🔗 زنجیره انبار → محموله → صندوق</h3>
                <div class="el-shipment-list">${shipments.map(s => `
                    <article class="el-shipment el-shipment--${s.status}">
                        <strong>${this.esc(s.title || 'محموله')}</strong>
                        <span class="el-badge">${this.esc(s.status)}</span>
                        ${(s.items || []).length ? `<ul class="el-shipment-items">${s.items.map(i =>
                            `<li>${this.esc(i.name)} × ${i.qty}</li>`).join('')}</ul>` : ''}
                        ${s.warehouse_move ? `<small>انبار #${s.warehouse_move.id}</small>` : ''}
                        ${s.status === 'shipped' ? `<button type="button" class="el-btn el-btn--sm el-btn--primary" data-ship="${s.id}">دریافت ✓</button>` : ''}
                    </article>`).join('') || '<p class="el-empty">محموله‌ای نیست</p>'}
            </section>
            <section class="el-warehouse-preview">
                <h3>📦 انبار ستاد (${this.fmt(wh.items || items.length)} قلم)</h3>
                <div class="el-table-wrap"><table class="el-table el-table--compact">
                    <thead><tr><th>کد</th><th>قلم</th><th>موجود</th></tr></thead>
                    <tbody>${items.slice(0, 10).map(i => `<tr>
                        <td><code>${this.esc(i.sku)}</code></td>
                        <td>${this.esc(i.name)}</td>
                        <td>${this.fmt(i.available_qty)}</td>
                    </tr>`).join('')}</tbody>
                </table></div>
            </section>`;
    }

    _bannersHtml() {
        const spots = this.dashboard?.banner_spots || [];
        const sts = this.dashboard?.stations || [];
        const types = this.meta.banner_spot_types || {};
        const statuses = { planned: 'برنامه', approved: 'تأیید', installed: 'نصب', verified: 'بازرسی', removed: 'جمع' };
        const sid = this.selectedStation || sts[0]?.id;
        const canEdit = this.dashboard?.role === 'admin' || this._isSupporter()
            || this.dashboard?.show_banners;
        return `<div class="el-banners-page">
            <p class="el-hint">ثبت و پیگیری <strong>محل نصب بنر و پوستر</strong> — برنامه توزیع تبلیغات (شرح وظایف: واحد رسانه)</p>
            ${canEdit ? `<form class="el-poi-form" id="el-banner-form">
                ${sts.length > 1 ? `<label>صندوق<select name="station_id" required>
                    ${sts.map(s => `<option value="${s.id}" ${s.id == sid ? 'selected' : ''}>${this.esc(s.code)} — ${this.esc(s.name)}</option>`).join('')}
                </select></label>` : `<input type="hidden" name="station_id" value="${sid || ''}">`}
                <label>نوع محل<select name="spot_type" required>
                    ${Object.entries(types).map(([k,v]) => `<option value="${k}">${this.esc(v)}</option>`).join('')}
                </select></label>
                <label>شرح محل<input name="location_desc" required placeholder="مثلاً: دیوار کوچه نانوایی"></label>
                <label>آدرس<input name="address" placeholder="خیابان، کوچه"></label>
                <label>ابعاد<input name="size" placeholder="۳×۶ / A3"></label>
                <label>توضیح<textarea name="notes" rows="2"></textarea></label>
                <button type="submit" class="el-btn el-btn--primary">ثبت محل نصب ✓</button>
                <div id="el-banner-msg" class="el-msg"></div>
            </form>` : ''}
            <h3>محل‌های ثبت‌شده (${spots.length})</h3>
            <div class="el-banner-list">${spots.map(b => `
                <article class="el-banner-item el-banner-item--${b.status}">
                    <div class="el-banner-item__head">
                        <span class="el-tag">${this.esc(b.spot_type_label)}</span>
                        <span class="el-badge">${this.esc(b.status_label || statuses[b.status] || b.status)}</span>
                    </div>
                    <strong>${this.esc(b.location_desc)}</strong>
                    <small>${this.esc(b.address || '')} · ${this.esc(b.size || '')}</small>
                    ${canEdit && b.status === 'planned' ? `<button type="button" class="el-btn el-btn--sm" data-banner-status="${b.id}" data-status="installed">نصب شد ✓</button>` : ''}
                    ${this.dashboard?.role === 'admin' && b.status === 'installed' ? `<button type="button" class="el-btn el-btn--sm el-btn--primary" data-banner-status="${b.id}" data-status="verified">بازرسی OK</button>` : ''}
                </article>`).join('') || '<p class="el-empty">محل بنری ثبت نشده</p>'}
            </div>
        </div>`;
    }

    _bindBanners(main) {
        main.querySelector('#el-banner-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-banner-msg');
            try {
                await this._req('POST', 'election/banners', Object.fromEntries(new FormData(e.target)));
                msg.textContent = '✅ ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                await this._loadSession();
                this.tab = 'banners';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelectorAll('[data-banner-status]').forEach(btn => {
            btn.addEventListener('click', async () => {
                await this._req('POST', `election/banners/${btn.dataset.bannerStatus}`, { status: btn.dataset.status });
                await this._loadSession();
                this._paint();
            });
        });
    }

    async _warehouseHtml() {
        let items = this.dashboard?.warehouse_items || [];
        let summary = this.dashboard?.warehouse || {};
        if (!items.length) {
            const r = await this._req('GET', 'election/warehouse');
            items = r.data?.items || [];
            summary = r.data?.summary || {};
        }
        const canIssue = this.dashboard?.role === 'admin' || this.dashboard?.show_warehouse;
        let stations = this.dashboard?.stations || [];
        if (canIssue && !stations.length) {
            const sr = await this._req('GET', 'election/stations');
            stations = sr.data || [];
        }
        return `<div class="el-warehouse-page">
            <div class="el-intel-note">📦 انبار اقلام تبلیغاتی ستاد — ${this.fmt(summary.total_stock)} قلم در انبار</div>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${this.fmt(summary.items || items.length)}</strong><span>نوع قلم</span></div>
                <div class="el-card"><strong>${this.fmt(summary.available)}</strong><span>قابل توزیع</span></div>
            </div>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>کد</th><th>نام</th><th>دسته</th><th>موجود</th><th>رزرو</th><th>واحد</th></tr></thead>
                <tbody>${items.map(i => `<tr>
                    <td><code>${this.esc(i.sku)}</code></td>
                    <td>${this.esc(i.name)}</td>
                    <td>${this.esc(i.category_label)}</td>
                    <td>${this.fmt(i.stock_qty)}</td>
                    <td>${this.fmt(i.reserved_qty)}</td>
                    <td>${this.esc(i.unit)}</td>
                </tr>`).join('')}</tbody>
            </table></div>
            ${canIssue ? `<form class="el-poi-form" id="el-wh-ship">
                <h3>🚚 صدور انبار + ایجاد محموله (زنجیره کامل)</h3>
                <label>صندوق<select name="station_id" required>
                    ${stations.map(s => `<option value="${s.id}">${this.esc(s.code)} — ${this.esc(s.name)}</option>`).join('')}
                    ${!stations.length ? '<option value="">صندوقی نیست</option>' : ''}
                </select></label>
                <label>قلم<select name="item_id" required>${items.map(i =>
                    `<option value="${i.id}">${this.esc(i.name)} (${this.fmt(i.available_qty)})</option>`).join('')}</select></label>
                <label>تعداد<input name="qty" type="number" min="1" value="1"></label>
                <button type="submit" class="el-btn el-btn--primary">صدور + ارسال محموله ✓</button>
                <div id="el-wh-ship-msg" class="el-msg"></div>
            </form>
            <form class="el-poi-form" id="el-wh-issue">
                <h3>صدور ساده از انبار</h3>
                <label>قلم<select name="item_id" required>${items.map(i =>
                    `<option value="${i.id}">${this.esc(i.name)} (${this.fmt(i.available_qty)} ${this.esc(i.unit)})</option>`
                ).join('')}</select></label>
                <label>تعداد<input name="qty" type="number" min="1" value="1" required></label>
                <label>یادداشت<input name="notes" placeholder="مثلاً: صندوق ۱۰۱"></label>
                <button type="submit" class="el-btn el-btn--primary el-btn--sm">ثبت صدور</button>
                <div id="el-wh-msg" class="el-msg"></div>
            </form>` : ''}
        </div>`;
    }

    _bindWarehouse(main) {
        main.querySelector('#el-wh-ship')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-wh-ship-msg');
            const fd = new FormData(e.target);
            const body = {
                station_id: parseInt(fd.get('station_id'), 10),
                item_id: parseInt(fd.get('item_id'), 10),
                qty: parseInt(fd.get('qty'), 10) || 1,
            };
            try {
                await this._req('POST', 'election/warehouse/ship', body);
                msg.textContent = '✅ محموله ایجاد شد';
                msg.className = 'el-msg el-msg--ok';
                await this._loadSession();
                this.tab = 'warehouse';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelector('#el-wh-issue')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-wh-msg');
            const fd = new FormData(e.target);
            const body = Object.fromEntries(fd);
            body.qty = parseInt(body.qty, 10);
            body.item_id = parseInt(body.item_id, 10);
            try {
                await this._req('POST', 'election/warehouse/issue', body);
                msg.textContent = '✅ صادر شد';
                msg.className = 'el-msg el-msg--ok';
                await this._loadSession();
                this.tab = 'warehouse';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
    }

    _orgInfoHtml() {
        const org = this.meta.org_structure || this.dashboard?.org_structure;
        const exec = (org?.bureaus || []).find(b => b.id === 'executive');
        return `<div class="el-org-info">
            <p class="el-hint">مرحله ۶ — شما زیرمجموعه <strong>اداره امور اجرایی و میدانی</strong> هستید؛ ستاد در مقطع کوتاه تشکیل و پس از انتخابات منحل می‌شود.</p>
            ${exec ? `<div class="el-adm-bureau el-adm-bureau--highlight">
                <header class="el-adm-bureau__head"><span>${exec.icon}</span><strong>${this.esc(exec.title)}</strong></header>
                <div class="el-adm-bureau__units">${(exec.units || []).map(u => `<span class="el-tag">${u.icon} ${this.esc(u.title)}</span>`).join('')}</div>
            </div>` : ''}
            ${this._adminStructureHtml(org, { compact: true })}
        </div>`;
    }

    _homeHtml() {
        const d = this.dashboard || {};
        const sts = d.stations || [];
        const phase = d.phase?.phase_label || '';
        return `<div class="el-home">
            <div class="el-hq-banner">
                <h2>${this.esc(d.tagline || '')}</h2>
                <p>فاز جاری: <strong>${this.esc(phase)}</strong> — ${sts.length} صندوق تخصیص‌یافته</p>
            </div>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${sts.length}</strong><span>صندوق من</span></div>
                <div class="el-card"><strong>${d.tasks_pending ?? 0}</strong><span>وظیفه باز</span></div>
                <div class="el-card"><strong>${(d.pois || []).length}</strong><span>مکان شناسایی‌شده</span></div>
                <div class="el-card"><strong>${(d.briefings || []).length}</strong><span>پیام دریافتی</span></div>
                <div class="el-card"><strong>${(d.shipments || []).filter(s => s.status !== 'received').length}</strong><span>محموله در راه</span></div>
            </div>
            <h3>صندوق‌های من</h3>
            <div class="el-station-grid">${sts.map(s => this._stationCard(s)).join('') || '<p class="el-empty">صندوقی تخصیص نشده</p>'}</div>
            <div class="el-quick-actions">
                <button type="button" class="el-btn el-btn--primary" data-goto="poi">📍 شناسایی اطراف</button>
                <button type="button" class="el-btn" data-goto="tasks">✅ وظایف</button>
                <button type="button" class="el-btn" data-goto="briefings">📢 پیام‌ها</button>
            </div>
        </div>`;
    }

    _stationCard(s) {
        return `<article class="el-station-card" data-station="${s.id}">
            <code>${this.esc(s.code)}</code>
            <strong>${this.esc(s.name)}</strong>
            <span>${this.esc(s.neighborhood || '')}</span>
            <div class="el-station-card__meta">
                <span>👥 ${this.fmt(s.voter_count)} رأی‌دهنده</span>
                <span>📍 ${s.poi_count || 0} مکان</span>
            </div>
            <small>${this.esc(s.address || '')}</small>
        </article>`;
    }

    _bindHome(main) {
        main.querySelectorAll('[data-goto]').forEach(b => {
            b.addEventListener('click', () => { this.tab = b.dataset.goto; this._paint(); });
        });
    }

    _adminHtml() {
        const d = this.dashboard || {};
        const districts = d.districts || [];
        const seg = d.segment_progress || {};
        return `<div class="el-admin">
            <div class="el-intel-note">🔒 GIS/ERP فقط مدیر — هواداران داده sanitize‌شده می‌بینند</div>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${this.fmt(seg.total || 0)}/${this.fmt(seg.target || 1011)}</strong><span>پهنه</span></div>
                <div class="el-card"><strong>${districts.length}</strong><span>منطقه</span></div>
                <div class="el-card"><strong>${(d.stations || []).length}</strong><span>صندوق</span></div>
                <div class="el-card"><strong>${this.fmt(d.erp?.gis_parcels)}</strong><span>پارسل GIS</span></div>
            </div>
            <div class="el-segment-progress el-segment-progress--inline">
                <div class="el-segment-progress__bar"><span style="width:${Math.min(100, seg.percent || 0)}%"></span></div>
                <small>${seg.percent || 0}% — ${this.fmt(seg.from_gis || 0)} از GIS</small>
            </div>
            <p><button type="button" class="el-btn el-btn--primary el-btn--sm" data-goto="segments">مدیریت پهنه 1011 →</button>
            <button type="button" class="el-btn el-btn--sm" data-goto="financial">داشبورد مالی →</button></p>
            <h3>تغییر فاز انتخابات</h3>
            <form class="el-phase-form" id="el-phase-form">
                <select name="current_phase">
                    ${Object.entries(d.phase?.phases || this.meta.phases || {}).map(([k,v]) =>
                        `<option value="${k}" ${k === d.phase?.current_phase ? 'selected' : ''}>${this.esc(v)}</option>`
                    ).join('')}
                </select>
                <button type="submit" class="el-btn el-btn--primary el-btn--sm">اعمال فاز</button>
                <span class="el-assign-msg" id="el-phase-msg"></span>
            </form>
            <h3>مناطق و مدیران</h3>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>منطقه</th><th>صندوق‌ها</th></tr></thead>
                <tbody>${districts.map(n => `<tr>
                    <td>${this.esc(n.name)}</td>
                    <td>${this.fmt(n.station_count)}</td>
                </tr>`).join('')}</tbody>
            </table></div>
        </div>`;
    }

    _bindAdminPhase(main) {
        main.querySelector('#el-phase-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-phase-msg');
            const phase = new FormData(e.target).get('current_phase');
            try {
                await this._req('POST', 'election/admin/phase', { current_phase: phase });
                msg.textContent = '✅ فاز به‌روز شد';
                msg.className = 'el-assign-msg el-msg--ok';
                await this._loadSession();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-assign-msg el-msg--err';
            }
        });
        main.querySelectorAll('[data-goto]').forEach(b => {
            b.addEventListener('click', () => { this.tab = b.dataset.goto; this._paint(); });
        });
    }

    async _stationsTabHtml(role) {
        const max = this.dashboard?.max_stations || this.meta.max_stations || 3;
        let mine = this.dashboard?.stations || [];
        let pickable = this.dashboard?.pickable_stations || [];
        if (this._isSupporter() && !pickable.length) {
            const r = await this._req('GET', 'election/pickable-stations');
            pickable = r.data || [];
        }
        if (role === 'admin') {
            const r = await this._req('GET', 'election/stations');
            mine = r.data || [];
        }
        const canPick = this._isSupporter();
        return `<div class="el-stations-page">
            <p class="el-hint">هر هوادار حداکثر <strong>${max} صندوق</strong> — خودتان انتخاب کنید یا از نقشه</p>
            ${canPick ? `<div class="el-station-pick">
                <h3>انتخاب صندوق (self-service)</h3>
                <div class="el-station-grid">${pickable.map(s => `
                    <label class="el-station-card el-station-card--pick ${s.is_mine ? 'el-station-card--on' : ''}">
                        <input type="checkbox" name="pick_station" value="${s.id}" ${s.is_mine ? 'checked disabled' : ''} ${!s.can_pick && !s.is_mine ? 'disabled' : ''}>
                        ${this._stationCardInner(s)}
                        <small>${s.is_mine ? '✓ تخصیص‌یافته' : `${s.supporter_count || 0} هوادار`}</small>
                    </label>`).join('')}
                </div>
                <button type="button" class="el-btn el-btn--primary" id="el-pick-stations">ثبت صندوق‌های انتخابی ✓</button>
                <div id="el-pick-msg" class="el-msg"></div>
            </div>` : ''}
            <h3>صندوق‌های ${canPick ? 'من' : 'سیستم'}</h3>
            <div class="el-station-grid">${mine.map(s => this._stationCard(s)).join('') || '<p class="el-empty">صندوقی نیست</p>'}</div>
        </div>`;
    }

    _stationCardInner(s) {
        return `<code>${this.esc(s.code)}</code><strong>${this.esc(s.name)}</strong><span>${this.esc(s.neighborhood || '')}</span>`;
    }

    _bindStationSelect(main) {
        main.querySelector('#el-pick-stations')?.addEventListener('click', async () => {
            const ids = [...main.querySelectorAll('[name=pick_station]:checked:not(:disabled)')].map(c => parseInt(c.value, 10));
            const msg = main.querySelector('#el-pick-msg');
            if (!ids.length) { msg.textContent = 'صندوق انتخاب کنید'; msg.className = 'el-msg el-msg--err'; return; }
            try {
                await this._req('POST', 'election/my-stations/pick', { station_ids: ids, mode: 'add' });
                msg.textContent = '✅ صندوق ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                await this._loadSession();
                this.tab = 'stations';
                this._paint();
            } catch (e) { msg.textContent = e.message; msg.className = 'el-msg el-msg--err'; }
        });
        main.querySelectorAll('[data-station]').forEach(c => {
            c.addEventListener('click', () => {
                this.selectedStation = parseInt(c.dataset.station, 10);
                main.querySelectorAll('.el-station-card').forEach(x =>
                    x.classList.toggle('el-station-card--on', parseInt(x.dataset.station, 10) === this.selectedStation)
                );
            });
        });
        main.querySelectorAll('[data-goto]').forEach(b => {
            b.addEventListener('click', () => { this.tab = b.dataset.goto; this._paint(); });
        });
    }

    async _renderMapTab(main) {
        main.innerHTML = `<div class="el-map-page"><p class="el-hint">نقشه GIS — read-only · صندوق · شناسایی · بنر · پهنه (هدف: ۱۰۱۱)</p><div id="el-map-root"></div></div>`;
        const root = main.querySelector('#el-map-root');
        let data = this.dashboard?.map_data;
        if (!data?.markers?.length) {
            const r = await this._req('GET', 'election/map');
            data = r.data;
        }
        this._mapView?.destroy();
        this._mapView = new ElectionMapView({
            container: root,
            data,
            onPickStation: this._isSupporter() ? async id => {
                await this._req('POST', 'election/my-stations/pick', { station_ids: [id], mode: 'add' });
                await this._loadSession();
                this.tab = 'stations';
                this._paint();
            } : null,
        });
        await this._mapView.render(data);
    }

    _countyPortalHtml() {
        const cp = this.dashboard?.county_portal || {};
        const counties = cp.counties || Object.entries(this.meta.county_zones || {}).map(([slug, z]) => ({ slug, ...z }));
        return `<div class="el-county-portal">
            <div class="el-intel-note">🏛️ پورتال شهرستان‌ها — ستاد محلی · هدف پهنه‌بندی ${this.fmt(cp.target || 1011)}</div>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${this.fmt(cp.segments || 0)}/${this.fmt(cp.target || 1011)}</strong><span>پهنه</span></div>
                <div class="el-card"><strong>${this.fmt(cp.stations || 0)}</strong><span>صندوق</span></div>
                <div class="el-card"><strong>${this.fmt(cp.supporters || 0)}</strong><span>هوادار</span></div>
            </div>
            <div class="el-county-grid">${counties.map(c => `
                <article class="el-county-card">
                    <span class="el-county-card__icon">${c.icon || '🏛️'}</span>
                    <strong>${this.esc(c.name)}</strong>
                    <small>${this.fmt(c.station_count || 0)} صندوق · ${this.fmt(c.segment_count || 0)} پهنه</small>
                </article>`).join('')}</div>
            <h3>سرشاخه‌های محلی</h3>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>سرشاخه</th><th>دسته</th><th>هوادار</th></tr></thead>
                <tbody>${(cp.branches || []).map(b => `<tr>
                    <td>${this.esc(b.title)}</td><td>${this.esc(b.category_label)}</td><td>${this.fmt(b.supporter_count)}</td>
                </tr>`).join('') || '<tr><td colspan="3">—</td></tr>'}</tbody>
            </table></div>
        </div>`;
    }

    _committeePortalHtml() {
        const cp = this.dashboard?.committee_portal || {};
        const committees = cp.committees || Object.entries(this.meta.committee_types || {}).map(([slug, c]) => ({ slug, ...c }));
        return `<div class="el-committee-portal">
            <div class="el-intel-note">👥 پورتال کمیته اقشار — جوانان · بانوان · اصناف · …</div>
            <div class="el-committee-grid">${committees.map(c => `
                <article class="el-committee-card">
                    <span>${c.icon || '👥'}</span>
                    <strong>${this.esc(c.title)}</strong>
                    <small>${this.esc(c.sample_task || '')}</small>
                </article>`).join('')}</div>
            <h3>کارهای باز واحد</h3>
            <ul>${(cp.dept_work || []).map(w => `<li>${this.esc(w.title)} — ${w.status}</li>`).join('') || '<li>—</li>'}</ul>
        </div>`;
    }

    _poiTabHtml() {
        const sts = this.dashboard?.stations || [];
        const pois = this.dashboard?.pois || [];
        const types = this.dashboard?.poi_types || this.poiTypes;
        const sid = this.selectedStation || sts[0]?.id;
        const filtered = pois.filter(p => !sid || parseInt(p.station_id, 10) === sid);
        return `<div class="el-poi-page">
            <p class="el-hint">فاز شناسایی — نانوایی، مدرسه، مسجد و… <strong>اطراف هر صندوق</strong></p>
            ${sts.length > 1 ? `<select id="el-poi-station" class="el-select">
                ${sts.map(s => `<option value="${s.id}" ${s.id == sid ? 'selected' : ''}>${this.esc(s.code)} — ${this.esc(s.name)}</option>`).join('')}
            </select>` : ''}
            <form class="el-poi-form" id="el-poi-form">
                <input type="hidden" name="station_id" value="${sid || ''}">
                <label>نوع مکان<select name="poi_type" required>
                    ${Object.entries(types).map(([k,v]) => `<option value="${k}">${this.esc(v)}</option>`).join('')}
                </select></label>
                <label>نام<input name="name" required placeholder="مثلاً نانوایی سنگک"></label>
                <label>آدرس<input name="address" placeholder="خیابان، کوچه"></label>
                <label>توضیح<textarea name="notes" rows="2"></textarea></label>
                <button type="submit" class="el-btn el-btn--primary">ثبت مکان ✓</button>
                <div id="el-poi-msg" class="el-msg"></div>
            </form>
            <h3>مکان‌های ثبت‌شده (${filtered.length})</h3>
            <div class="el-poi-list">${filtered.map(p => `
                <article class="el-poi-item">
                    <span class="el-tag">${this.esc(p.poi_type_label)}</span>
                    <strong>${this.esc(p.name)}</strong>
                    <small>${this.esc(p.address || '')}</small>
                </article>`).join('') || '<p class="el-empty">هنوز ثبت نشده — شروع کنید</p>'}
            </div>
        </div>`;
    }

    _bindPoi(main) {
        main.querySelector('#el-poi-station')?.addEventListener('change', e => {
            this.selectedStation = parseInt(e.target.value, 10);
            const hid = main.querySelector('[name=station_id]');
            if (hid) hid.value = this.selectedStation;
        });
        main.querySelector('#el-poi-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-poi-msg');
            const fd = new FormData(e.target);
            try {
                await this._req('POST', 'election/pois', Object.fromEntries(fd));
                msg.textContent = '✅ مکان ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                e.target.reset();
                await this._loadSession();
                this.tab = 'poi';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
    }

    _tasksHtml() {
        const tasks = this.dashboard?.tasks || [];
        const phase = this.dashboard?.phase?.current_phase;
        const filtered = tasks.filter(t => !phase || t.phase === phase);
        const all = filtered.length ? filtered : tasks;
        if (!all.length) return '<p class="el-empty">وظیفه‌ای نیست</p>';
        return `<div class="el-mission-list">${all.map(t => `
            <article class="el-mission el-mission--${this.esc(t.status)}">
                <div class="el-mission__head">
                    <strong>${this.esc(t.title)}</strong>
                    <span class="el-badge">${this.esc(t.phase)}</span>
                </div>
                <p>${this.esc(t.body)}</p>
                ${t.status === 'pending' ? `<button type="button" class="el-btn el-btn--primary el-btn--sm" data-task="${t.id}">انجام شد ✓</button>` : ''}
            </article>`).join('')}</div>`;
    }

    _bindTasks(main) {
        main.querySelectorAll('[data-task]').forEach(btn => {
            btn.addEventListener('click', async () => {
                btn.disabled = true;
                try {
                    await this._req('POST', `election/tasks/${btn.dataset.task}/complete`, {});
                    await this._loadSession();
                    this._paint();
                } catch (err) { btn.disabled = false; alert(err.message); }
            });
        });
    }

    _briefingsHtml() {
        const items = this.dashboard?.briefings || [];
        const shipments = this.dashboard?.shipments || [];
        return `<div class="el-briefings">
            <h3>شعارها و اقدامات کاندید (دریافتی)</h3>
            <div class="el-content-list">${items.map(b => `
                <article class="el-content">
                    <span class="el-tag">${this.esc(b.briefing_type)} · ${this.esc(b.phase || '')}</span>
                    <h4>${this.esc(b.title)}</h4>
                    <p>${this.esc(b.body)}</p>
                </article>`).join('') || '<p class="el-empty">پیامی نیست</p>'}</div>
            <h3>کالای تبلیغاتی (فاز تبلیغات)</h3>
            <div class="el-shipment-list">${shipments.map(s => `
                <article class="el-shipment el-shipment--${s.status}">
                    <strong>${this.esc(s.title || 'محموله')}</strong>
                    <span class="el-badge">${this.esc(s.status)}</span>
                    ${s.status === 'shipped' ? `<button type="button" class="el-btn el-btn--sm el-btn--primary" data-ship="${s.id}">دریافت کردم ✓</button>` : ''}
                </article>`).join('') || '<p class="el-hint">محموله‌ای ثبت نشده</p>'}
            </div>
        </div>`;
    }

    _bindBriefings(main) {
        main.querySelectorAll('[data-ship]').forEach(btn => {
            btn.addEventListener('click', async () => {
                try {
                    await this._req('POST', `election/shipments/${btn.dataset.ship}/confirm`, {});
                    await this._loadSession();
                    this._paint();
                } catch (err) { alert(err.message); }
            });
        });
    }

    _reportHtml() {
        const sts = this.dashboard?.stations || [];
        const phase = this.dashboard?.phase?.current_phase || 'pre_campaign';
        return `<form class="el-report-form" id="el-report-form">
            <h3>گزارش به ستاد — برای تصمیم‌گیری</h3>
            <p class="el-hint">اطلاعات میدانی اطراف صندوق را گزارش دهید</p>
            <label>صندوق<select name="station_id">
                <option value="">— عمومی —</option>
                ${sts.map(s => `<option value="${s.id}">${this.esc(s.code)} — ${this.esc(s.name)}</option>`).join('')}
            </select></label>
            <label>عنوان<input name="title" required placeholder="مثلاً: وضعیت حضور مردم"></label>
            <label>شرح<textarea name="body" rows="4" required></textarea></label>
            <input type="hidden" name="phase" value="${phase}">
            <button type="submit" class="el-btn el-btn--primary">ارسال گزارش</button>
            <div id="el-report-msg" class="el-msg"></div>
        </form>`;
    }

    _bindReport(main) {
        main.querySelector('#el-report-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-report-msg');
            const fd = new FormData(e.target);
            const body = Object.fromEntries(fd);
            if (body.station_id) body.station_id = parseInt(body.station_id, 10);
            try {
                await this._req('POST', 'election/reports', body);
                msg.textContent = '✅ گزارش ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                e.target.reset();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
    }

    _gisHtml(g, e) {
        if (!g?.available) return `<p class="el-hint el-hint--warn">${this.esc(g?.message || 'GIS نیست')}</p>`;
        const nbs = (g.neighborhoods || []).slice(0, 10);
        return `<div class="el-intel">
            <div class="el-dash-cards">
                <div class="el-card"><strong>${this.fmt(nbs.length)}+</strong><span>محله</span></div>
                <div class="el-card"><strong>${this.fmt(e?.gis_parcels)}</strong><span>پارسل</span></div>
                <div class="el-card"><strong>${this.fmt(e?.melk_cases)}</strong><span>ERP</span></div>
            </div>
            <h3>محلات (GIS — فقط مدیر)</h3>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>محله</th><th>پارسل</th><th>واحد</th></tr></thead>
                <tbody>${nbs.map(n => `<tr><td>${this.esc(n.name)}</td><td>${this.fmt(n.parcel_count)}</td><td>${this.fmt(n.unit_count)}</td></tr>`).join('')}</tbody>
            </table></div>
        </div>`;
    }

    _adminStructureHtml(org, opts = {}) {
        const o = org || {};
        const compact = !!opts.compact;
        const clickable = opts.clickable !== false && !compact;
        const lifecycle = o.lifecycle || [];
        const bureaus = o.bureaus || [];
        const head = o.head || {};

        const lifecycleHtml = lifecycle.length ? `<div class="el-adm-lifecycle${compact ? ' el-adm-lifecycle--sm' : ''}">
            ${lifecycle.map((l, i) => `
                <div class="el-adm-lifecycle__step">
                    <span class="el-adm-lifecycle__num">${i + 1}</span>
                    <div>
                        <strong>${this.esc(l.phase)}</strong>
                        ${compact ? '' : `<small>${this.esc(l.desc || '')}</small>`}
                    </div>
                </div>
                ${i < lifecycle.length - 1 ? '<span class="el-adm-lifecycle__arrow">←</span>' : ''}`).join('')}
        </div>` : '';

        const headHtml = head.title ? `<div class="el-adm-head">
            <div class="el-adm-head__seal">🏛️</div>
            <div class="el-adm-head__body">
                <h3>${this.esc(head.title)}</h3>
                <span class="el-adm-head__sub">${this.esc(head.subtitle || '')}</span>
                ${head.note && !compact ? `<p class="el-adm-head__note">${this.esc(head.note)}</p>` : ''}
            </div>
        </div>` : '';

        const bureausHtml = bureaus.map(b => `<section class="el-adm-bureau">
            <header class="el-adm-bureau__head">
                <span class="el-adm-bureau__icon">${b.icon || '🏢'}</span>
                <div>
                    <strong>${this.esc(b.title)}</strong>
                    <small>${this.esc(b.desc || '')}</small>
                </div>
            </header>
            <div class="el-adm-bureau__units">
                ${(b.units || []).map(u => `<article class="el-adm-unit${clickable ? ' el-adm-unit--click' : ''}" data-dept-slug="${u.slug || ''}">
                    <span class="el-adm-unit__icon">${u.icon || '📁'}</span>
                    <strong>${this.esc(u.title)}</strong>
                    <small>${this.esc(u.work_subject || '')}</small>
                    ${u.work_count != null ? `<em class="el-adm-unit__badge">${u.work_count} کار باز</em>` : ''}
                </article>`).join('')}
            </div>
        </section>`).join('');

        return `<div class="el-adm-office${compact ? ' el-adm-office--compact' : ''}">
            ${lifecycleHtml}
            ${headHtml}
            <div class="el-adm-bureaus">${bureausHtml || '<p class="el-empty">تشکیلات تعریف نشده</p>'}</div>
        </div>`;
    }

    _orgHtml(org) {
        return `<div class="el-org-page">
            <p class="el-hint">چارت تشکیلات — ستاد انتخابات (ساختار اداری موقت)</p>
            ${this._adminStructureHtml(org || this.meta.org_structure)}
        </div>`;
    }

    _smsHtml() {
        const cfg = this.meta.sms_config || {};
        return `<div class="el-sms-page">
            <section class="el-sms-config">
                <h3>⚙️ تنظیمات SMS / OTP</h3>
                <form class="el-sms-form" id="el-sms-config-form">
                    <label>Provider
                        <select name="sms_provider">
                            <option value="log" ${cfg.provider === 'log' ? 'selected' : ''}>log (دمو)</option>
                            <option value="kavenegar" ${cfg.provider === 'kavenegar' ? 'selected' : ''}>کاوه‌نگار</option>
                            <option value="melipayamak" ${cfg.provider === 'melipayamak' ? 'selected' : ''}>ملی‌پیامک</option>
                            <option value="ghasedak" ${cfg.provider === 'ghasedak' ? 'selected' : ''}>قاصدک</option>
                        </select>
                    </label>
                    <label>API Key<input name="sms_api_key" dir="ltr" placeholder="${cfg.has_api_key ? '•••• تنظیم شده' : 'کلید API'}"></label>
                    <label>شماره فرستنده<input name="sms_sender" dir="ltr" value="${this.esc(cfg.sender || '')}"></label>
                    <label>قالب OTP کاوه‌نگار<input name="otp_template" dir="ltr" value="${this.esc(cfg.otp_template || 'verify')}"></label>
                    <label class="el-check"><input type="checkbox" name="otp_demo" ${cfg.otp_demo !== false ? 'checked' : ''}> حالت دمو OTP (نمایش کد در UI)</label>
                    <button type="submit" class="el-btn el-btn--primary">ذخیره تنظیمات</button>
                    <div id="el-sms-config-msg" class="el-msg"></div>
                </form>
            </section>
            <form class="el-sms-form" id="el-sms-form">
                <h3>SMS — دعوت هوادار</h3>
                <label>موبایل<input name="phone" required dir="ltr"></label>
                <label>متن<textarea name="message" rows="3" required>سامانه هوادران: ${location.origin}/acc-engine/election.php</textarea></label>
                <button type="submit" class="el-btn el-btn--primary">ارسال</button>
                <div id="el-sms-msg" class="el-msg"></div>
            </form>
            <form class="el-sms-form" id="el-onboard-admin">
                <h3>📱 Onboarding — ارسال کد تأیید</h3>
                <label>موبایل هوادار<input name="phone" required dir="ltr" placeholder="0912..."></label>
                <button type="submit" class="el-btn el-btn--primary">ارسال کد onboarding</button>
                <div id="el-onboard-admin-msg" class="el-msg"></div>
            </form>
        </div>`;
    }

    _bindSms(main) {
        main.querySelector('#el-sms-config-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-sms-config-msg');
            const fd = new FormData(e.target);
            const body = {
                sms_provider: fd.get('sms_provider'),
                sms_api_key: fd.get('sms_api_key'),
                sms_sender: fd.get('sms_sender'),
                otp_template: fd.get('otp_template'),
                otp_demo: fd.get('otp_demo') === 'on',
            };
            try {
                const r = await this._req('POST', 'election/admin/sms-config', body);
                this.meta.sms_config = r.config || body;
                msg.textContent = '✅ تنظیمات ذخیره شد';
                msg.className = 'el-msg el-msg--ok';
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelector('#el-onboard-admin')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-onboard-admin-msg');
            const phone = new FormData(e.target).get('phone');
            try {
                const r = await this._req('POST', 'election/admin/onboarding', { phone });
                msg.textContent = r.demo_code ? `✅ کد (دمو): ${r.demo_code}` : (r.demo_mode === false ? '✅ OTP ارسال شد' : '✅ ارسال شد');
                msg.className = 'el-msg el-msg--ok';
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelector('#el-sms-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-sms-msg');
            try {
                await this._req('POST', 'election/admin/sms', Object.fromEntries(new FormData(e.target)));
                msg.textContent = '✅ ثبت شد';
                msg.className = 'el-msg el-msg--ok';
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
    }

    async _financialHtml() {
        const r = await this._req('GET', 'election/financial');
        const d = r.data || {};
        const s = d.summary || {};
        const cats = d.categories || this.meta.budget_categories || {};
        const fmtMoney = n => Number(n || 0).toLocaleString('fa-IR');
        return `<div class="el-financial">
            <h2>💰 مدیریت مالی ستاد</h2>
            <p style="margin-bottom:12px;display:flex;flex-wrap:wrap;gap:8px">
                <button type="button" class="el-btn el-btn--sm el-btn--primary" id="el-goto-abc">◈ حسابداری فعالیت (گراف ABC)</button>
                <a href="/acc-engine/election-accounting.php" class="el-btn el-btn--sm" target="_blank" rel="noopener">📒 دفتر کل کمپین</a>
            </p>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${fmtMoney(s.planned)}</strong><span>بودجه برنامه</span></div>
                <div class="el-card"><strong>${fmtMoney(s.spent)}</strong><span>هزینه‌شده</span></div>
                <div class="el-card"><strong>${fmtMoney(s.remaining)}</strong><span>مانده بودجه</span></div>
                <div class="el-card"><strong>${fmtMoney(s.balance)}</strong><span>تراز نقد</span></div>
            </div>
            <h3>خطوط بودجه</h3>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>ردیف</th><th>دسته</th><th>مبلغ برنامه (ریال)</th><th></th></tr></thead>
                <tbody>${(d.budget_lines || []).map(b => `<tr>
                    <td>${this.esc(b.label)}</td>
                    <td>${this.esc(b.category_label || b.category)}</td>
                    <td><input type="number" class="el-budget-amt" data-id="${b.id}" value="${b.planned_amount || 0}" dir="ltr"></td>
                    <td><button type="button" class="el-btn el-btn--sm el-btn-save-budget" data-id="${b.id}">ذخیره</button></td>
                </tr>`).join('') || '<tr><td colspan="4">خط بودجه‌ای نیست</td></tr>'}
                </tbody>
            </table></div>
            <h3>ثبت تراکنش</h3>
            <form class="el-fin-tx-form" id="el-fin-tx-form">
                <select name="direction"><option value="out">پرداخت</option><option value="in">دریافت</option></select>
                <select name="category">${Object.entries(cats).map(([k,v]) => `<option value="${k}">${this.esc(v)}</option>`).join('')}</select>
                <input name="amount" type="number" placeholder="مبلغ (ریال)" required dir="ltr">
                <input name="description" placeholder="شرح">
                <button type="submit" class="el-btn el-btn--primary">ثبت ✓</button>
                <div id="el-fin-tx-msg" class="el-msg"></div>
            </form>
            <h3>آخرین تراکنش‌ها</h3>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>تاریخ</th><th>نوع</th><th>دسته</th><th>مبلغ</th><th>شرح</th></tr></thead>
                <tbody>${(d.transactions || []).slice(0, 20).map(t => `<tr>
                    <td>${this.esc(t.entry_date)}</td>
                    <td>${t.direction === 'in' ? 'دریافت' : 'پرداخت'}</td>
                    <td>${this.esc(t.category_label || t.category)}</td>
                    <td>${fmtMoney(t.amount)}</td>
                    <td>${this.esc(t.description || '')}</td>
                </tr>`).join('') || '<tr><td colspan="5">تراکنشی نیست</td></tr>'}
                </tbody>
            </table></div>
        </div>`;
    }

    _bindFinancial(main) {
        main.querySelector('#el-goto-abc')?.addEventListener('click', () => {
            this.tab = 'accounting';
            this._paint();
        });
        main.querySelector('#el-fin-tx-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-fin-tx-msg');
            try {
                await this._req('POST', 'election/financial/transactions', Object.fromEntries(new FormData(e.target)));
                msg.textContent = '✅ ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                this.tab = 'financial';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelectorAll('.el-btn-save-budget').forEach(btn => {
            btn.addEventListener('click', async () => {
                const id = btn.dataset.id;
                const inp = main.querySelector(`.el-budget-amt[data-id="${id}"]`);
                try {
                    await this._req('POST', 'election/financial/budget', {
                        id: +id,
                        planned_amount: +(inp?.value || 0),
                    });
                    btn.textContent = '✓';
                    setTimeout(() => { btn.textContent = 'ذخیره'; }, 1500);
                } catch (err) { alert(err.message); }
            });
        });
    }

    async _segmentsHtml() {
        const r = await this._req('GET', 'election/admin/segments?limit=50');
        const d = r.data || {};
        const st = d.stats || {};
        return `<div class="el-segments">
            <h2>🗺️ پهنه‌بندی 1011 — GIS شیراز</h2>
            <div class="el-segment-progress">
                <div class="el-segment-progress__bar"><span style="width:${Math.min(100, st.percent || 0)}%"></span></div>
                <strong>${this.fmt(st.total || 0)} / ${this.fmt(st.target || 1011)}</strong>
                <small>${st.percent || 0}% — ${this.fmt(st.from_gis || 0)} از GIS · ${this.fmt(st.voters || 0)} رأی‌دهنده تخمینی</small>
            </div>
            <div class="el-segment-actions">
                <button type="button" class="el-btn el-btn--primary" id="el-import-segments">Import از GIS (تکمیل تا 1011)</button>
                <button type="button" class="el-btn el-btn--ghost" id="el-reimport-segments">بازسازی کامل (replace)</button>
                <span id="el-import-msg" class="el-msg"></span>
            </div>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>کد</th><th>محله</th><th>بخش</th><th>رأی‌دهنده</th><th>منبع</th><th>بلوک GIS</th></tr></thead>
                <tbody>${(d.segments || []).map(s => `<tr>
                    <td><code>${this.esc(s.code)}</code></td>
                    <td>${this.esc(s.neighborhood)}</td>
                    <td>${s.part_no || 1}</td>
                    <td>${this.fmt(s.voter_count)}</td>
                    <td>${this.esc(s.import_source || 'seed')}</td>
                    <td><small>${this.esc(s.gis_block_code || '—')}</small></td>
                </tr>`).join('') || '<tr><td colspan="6">پهنه‌ای نیست</td></tr>'}
                </tbody>
            </table></div>
        </div>`;
    }

    _bindSegments(main) {
        const runImport = async (replace) => {
            const msg = main.querySelector('#el-import-msg');
            msg.textContent = '⏳ در حال import...';
            msg.className = 'el-msg';
            try {
                const r = await this._req('POST', 'election/admin/import-segments', { replace });
                msg.textContent = `✅ ${this.fmt(r.imported)} جدید — مجموع ${this.fmt(r.total)} (${r.source || ''})`;
                msg.className = 'el-msg el-msg--ok';
                await this._loadSession();
                this.tab = 'segments';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        };
        main.querySelector('#el-import-segments')?.addEventListener('click', () => runImport(false));
        main.querySelector('#el-reimport-segments')?.addEventListener('click', () => {
            if (confirm('همه پهنه‌ها حذف و از GIS بازسازی شوند؟')) runImport(true);
        });
    }

    _candidateTabHtml() {
        const hub = this.meta.candidate_hub || {};
        const p = hub.profile || {};
        const i = p.intro || {};
        return `<div class="el-candidate-page">
            <div class="el-hq-banner">
                <h2>${this.esc(p.name || 'کاندید')}</h2>
                <p>${this.esc(p.title || '')}</p>
            </div>
            <p class="el-hint">برای تجربه کامل از <strong>ویجت شناور «راهنمای کاندید»</strong> (پایین چپ) استفاده کنید — شامل چت هوشمند و ثبت پیشنهاد.</p>
            <article class="el-cw-section">
                <h3>${this.esc(i.headline || 'معرفی')}</h3>
                <p>${this.esc(i.summary || '')}</p>
            </article>
            <button type="button" class="el-btn el-btn--primary" id="el-open-cw-from-tab">🗳️ باز کردن راهنمای هوشمند</button>
        </div>`;
    }

    _bindCandidateTab(main) {
        main.querySelector('#el-open-cw-from-tab')?.addEventListener('click', () => {
            this._mountCandidateWidget();
            this._candidateWidget?.toggle(true);
        });
    }

    async _candidateAdminHtml() {
        const r = await this._req('GET', 'election/admin/candidate-suggestions');
        const d = r.data || {};
        const sections = d.sections || {};
        const statusLabel = { new: 'جدید', reviewed: 'بررسی', accepted: 'پذیرفته', rejected: 'رد' };
        return `<div class="el-candidate-admin">
            <h2>💡 پیشنهادات هوادار برای کاندید</h2>
            <div class="el-dash-cards">
                <div class="el-card"><strong>${this.fmt(d.stats?.total || 0)}</strong><span>کل</span></div>
                <div class="el-card"><strong>${this.fmt(d.stats?.new || 0)}</strong><span>جدید</span></div>
            </div>
            <div class="el-table-wrap"><table class="el-table">
                <thead><tr><th>بخش</th><th>متن</th><th>نویسنده</th><th>وضعیت</th><th></th></tr></thead>
                <tbody>${(d.items || []).map(s => `<tr>
                    <td>${this.esc(sections[s.section] || s.section)}</td>
                    <td>${this.esc(s.body)}</td>
                    <td>${this.esc(s.author_name || s.user_name || '—')}</td>
                    <td><span class="el-badge">${statusLabel[s.status] || s.status}</span></td>
                    <td>${s.status === 'new' ? `
                        <button type="button" class="el-btn el-btn--sm" data-sug="${s.id}" data-st="accepted">✓</button>
                        <button type="button" class="el-btn el-btn--sm el-btn--ghost" data-sug="${s.id}" data-st="rejected">✕</button>
                    ` : ''}</td>
                </tr>`).join('') || '<tr><td colspan="5">پیشنهادی نیست</td></tr>'}
                </tbody>
            </table></div>
        </div>`;
    }

    _bindCandidateAdmin(main) {
        main.querySelectorAll('[data-sug]').forEach(btn => {
            btn.addEventListener('click', async () => {
                try {
                    await this._req('POST', `election/admin/candidate-suggestions/${btn.dataset.sug}`, {
                        status: btn.dataset.st,
                    });
                    this.tab = 'candidate-admin';
                    this._paint();
                } catch (e) { alert(e.message); }
            });
        });
    }

    async _integrityHtml() {
        const r = await this._req('GET', 'election/integrity');
        const d = r.data || {};
        const c = d.certificate || {};
        const levelColors = { excellent: '#16a34a', good: '#2563eb', developing: '#ea580c', critical: '#dc2626' };
        return `<div class="el-integrity-page">
            <div class="el-osce-cert el-osce-cert--large">
                <span class="el-osce-cert__badge">${c.badge || '🏆'}</span>
                <div>
                    <h2>${this.esc(c.title || 'گواهی ACC-OSCE')}</h2>
                    <p>${this.esc(c.subtitle || '')}</p>
                    <strong class="el-osce-score">${d.average ?? 0}/100</strong>
                </div>
            </div>
            <p class="el-hint">${this.esc(d.framework || '')} · ${this.esc(d.reference || '')}</p>
            <h3>۱۲ محور یکپارچگی (زنده از سامانه)</h3>
            <div class="el-osce-grid">${(d.pillars || []).map(p => `
                <article class="el-osce-card el-osce-card--${p.level}">
                    <header><code>${p.code}</code> ${this.esc(p.title)} <span>${p.score}%</span></header>
                    <div class="el-segment-progress__bar"><span style="width:${p.score}%;background:${levelColors[p.level] || '#ea580c'}"></span></div>
                    <small>${this.esc(p.evidence || '')} ${p.auto ? '· خودکار' : ''}</small>
                    <em>${this.esc(p.osce_ref || '')}</em>
                </article>`).join('')}</div>
            <h3>اولویت بهبود (Gap Analysis)</h3>
            <ul class="el-gap-list">${(d.gaps || []).map(g => `
                <li><code>${g.code}</code> <strong>${this.esc(g.pillar)}</strong> (${g.score}%) — ${this.esc(g.action)}</li>
            `).join('') || '<li>همه محورها بالای ۷۰٪ ✓</li>'}</ul>
            <h3>ادارات ستاد × OSCE</h3>
            <div class="el-table-wrap"><table class="el-table el-table--compact">
                <thead><tr><th>واحد</th><th>محور</th><th>نقش OSCE</th></tr></thead>
                <tbody>${((await this._req('GET', 'election/sectors')).data?.departments || []).slice(0, 12).map(dep => `
                    <tr><td>${dep.icon} ${this.esc(dep.title)}</td><td>${this.esc(dep.pillar || '')}</td><td><small>${this.esc(dep.osce_role || '')}</small></td></tr>
                `).join('')}</tbody>
            </table></div>
        </div>`;
    }

    async _sectorsPageHtml() {
        const r = await this._req('GET', 'election/sectors');
        const d = r.data || {};
        const groups = d.by_group || {};
        const labels = d.group_labels || {};
        let cards = '';
        for (const [gk, items] of Object.entries(groups)) {
            cards += `<section class="el-sector-group"><h3>${this.esc(labels[gk] || gk)}</h3>
                <div class="el-sector-matrix">${items.map(s => `
                    <article class="el-sector-card" data-sector="${s.slug}">
                        <span class="el-sector-card__icon">${s.icon}</span>
                        <strong>${this.esc(s.title)}</strong>
                        <p>${this.esc(s.message || '')}</p>
                        <ul>${(s.playbook || []).map(p => `<li>${this.esc(p)}</li>`).join('')}</ul>
                        <div class="el-cw-chips">${(s.chips || []).map(c =>
                            `<span class="el-cw-chip el-cw-chip--static">${this.esc(c)}</span>`).join('')}</div>
                        <footer>واحد: ${this.esc(s.dept || '')} · ${s.engagements || 0} رویداد · OSCE ${this.esc(s.pillar_meta?.code || '')}</footer>
                    </article>`).join('')}
                </div></section>`;
        }
        const recent = d.total_engagements ? (await this._req('GET', 'election/sectors')).data : d;
        return `<div class="el-sectors-page">
            <div class="el-dash-cards">
                <div class="el-card"><strong>${Object.keys(d.sectors || {}).length}</strong><span>قشر</span></div>
                <div class="el-card"><strong>${this.fmt(d.total_engagements || 0)}</strong><span>تعامل</span></div>
                <div class="el-card"><strong>${this.fmt(d.integrity?.average || 0)}</strong><span>امتیاز OSCE</span></div>
            </div>
            ${cards}
            <section class="el-sector-engage-form">
                <h3>➕ ثبت تعامل با قشر / اصناف</h3>
                <form id="el-sector-engage-form" class="el-fin-tx-form">
                    <select name="sector_slug" required>${Object.entries(d.sectors || {}).map(([k, v]) =>
                        `<option value="${k}">${v.icon} ${this.esc(v.title)}</option>`).join('')}</select>
                    <input name="title" placeholder="عنوان (مثلاً جلسه اتحادیه)" required>
                    <input name="location" placeholder="محل">
                    <input name="attendees" type="number" min="0" placeholder="حاضرین">
                    <textarea name="description" placeholder="خلاصه" rows="2"></textarea>
                    <button type="submit" class="el-btn el-btn--primary">ثبت تعامل ✓</button>
                    <div id="el-sector-engage-msg" class="el-msg"></div>
                </form>
            </section>
        </div>`;
    }

    _bindSectorsPage(main) {
        main.querySelector('#el-sector-engage-form')?.addEventListener('submit', async e => {
            e.preventDefault();
            const msg = main.querySelector('#el-sector-engage-msg');
            try {
                await this._req('POST', 'election/sectors/engage', Object.fromEntries(new FormData(e.target)));
                msg.textContent = '✅ ثبت شد';
                msg.className = 'el-msg el-msg--ok';
                this.tab = 'sectors';
                this._paint();
            } catch (err) {
                msg.textContent = err.message;
                msg.className = 'el-msg el-msg--err';
            }
        });
        main.querySelectorAll('[data-sector]').forEach(card => {
            card.addEventListener('click', () => {
                const sel = main.querySelector('[name="sector_slug"]');
                if (sel) sel.value = card.dataset.sector;
                main.querySelector('.el-sector-engage-form')?.scrollIntoView({ behavior: 'smooth' });
            });
        });
    }
}
