/* ============================================================
   BAN YARO — Admin-Bereich
   Nur für Admins und Moderatoren.
   ============================================================ */

window.Page_admin = (() => {

  let _container = null;
  let _appState  = null;
  let _tab       = 'uebersicht';

  const TABS = [
    { id: 'uebersicht',  label: 'Übersicht',        icon: 'house-line'       },
    { id: 'nutzer',      label: 'Nutzer',            icon: 'users'            },
    { id: 'moderation',  label: 'Moderation',        icon: 'shield-check'     },
    { id: 'zuchter',     label: 'Züchter',           icon: 'certificate'      },
    { id: 'forum',       label: 'Forum',             icon: 'chat-circle-dots' },
    { id: 'social',      label: 'Social Media',      icon: 'camera'           },
    { id: 'analytics',   label: 'Analytics',         icon: 'target'           },
    { id: 'system',      label: 'System',             icon: 'gear'             },
    { id: 'jobs',        label: 'Scheduler',          icon: 'clock'            },
    { id: 'bewerbungen', label: 'Bewerbungen',        icon: 'user-plus'        },
    { id: 'partner',     label: 'Partner',            icon: 'handshake'        },
    { id: 'outreach',    label: 'Outreach',           icon: 'envelope-simple'  },
    { id: 'audit',       label: 'Audit-Log',          icon: 'clipboard-text'   },
  ];

  // ------------------------------------------------------------------
  async function init(container, appState) {
    _container = container;
    _appState  = appState;

    const u = appState.user;
    const isMod = u?.rolle === 'admin' || u?.rolle === 'moderator' || u?.is_moderator;
    if (!isMod) {
      container.innerHTML = _emptyState('shield', 'Kein Zugriff', 'Dieser Bereich ist nur für Admins und Moderatoren.');
      return;
    }

    _render();
  }

  function refresh() { _renderTab(); }
  function onDogChange() {}

  // ------------------------------------------------------------------
  // SHELL
  // ------------------------------------------------------------------
  function _render() {
    _container.innerHTML = `
        <!-- Action Items -->
        <div id="adm-action-items" style="padding:var(--space-3) var(--space-3) 0"></div>

        <!-- Tabs -->
        <div class="by-tabs adm-tabs" id="adm-tabs">
          ${TABS.map(t => `
            <button class="by-tab${t.id === _tab ? ' active' : ''}" data-tab="${t.id}">
              ${UI.icon(t.icon)} ${t.label}
            </button>
          `).join('')}
        </div>

        <!-- Inhalt -->
        <div id="adm-content"></div>
    `;

    _container.querySelector('#adm-tabs')
      ?.style.setProperty('--adm-tab-cols', Math.ceil(TABS.length / 2));
    _container.querySelectorAll('#adm-tabs .by-tab').forEach(btn => {
      btn.addEventListener('click', () => {
        _tab = btn.dataset.tab;
        _container.querySelectorAll('#adm-tabs .by-tab').forEach(b =>
          b.classList.toggle('active', b.dataset.tab === _tab)
        );
        _renderTab();
      });
    });

    _renderActionItems();
    _renderTab();
  }

  async function _renderActionItems() {
    const el = _container.querySelector('#adm-action-items');
    if (!el) return;
    let d;
    try { d = await API.get('/admin/action-items'); } catch { return; }

    const items = [
      { key: 'jobs_pending',      label: 'Bewerbungen',      tab: 'bewerbungen', icon: 'user-plus'       },
      { key: 'breeder_pending',   label: 'Züchter-Anträge',  tab: 'zuchter',     icon: 'certificate'     },
      { key: 'reports_open',      label: 'Meldungen',        tab: 'moderation',  icon: 'warning'         },
      { key: 'fotos_pending',     label: 'Foto-Einreichungen',tab: 'moderation', icon: 'image'           },
      { key: 'poi_edits_pending', label: 'POI-Korrekturen',  tab: 'moderation',  icon: 'map-pin'         },
    ];

    const open = items.filter(i => d[i.key] > 0);
    const usersToday = d.users_today || 0;

    el.innerHTML = `
      <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center;
                  background:var(--c-surface);border:1px solid var(--c-border);
                  border-radius:var(--radius-lg);padding:var(--space-3) var(--space-4)">
        <span style="font-size:var(--text-xs);font-weight:700;color:var(--c-text-muted);
                     text-transform:uppercase;letter-spacing:.06em;margin-right:var(--space-1)">
          ${UI.icon('check-square')} Zu erledigen
        </span>
        ${open.length === 0
          ? `<span style="font-size:var(--text-sm);color:var(--c-success,#4caf50);font-weight:600">
               ${UI.icon('check-circle')} Alles erledigt
             </span>`
          : open.map(i => `
              <button data-action-tab="${i.tab}"
                style="display:inline-flex;align-items:center;gap:4px;
                       background:var(--c-warning-light,#fff3e0);color:var(--c-warning,#e65100);
                       border:1px solid var(--c-warning,#e65100);border-radius:999px;
                       padding:2px 10px;font-size:var(--text-xs);font-weight:700;cursor:pointer">
                ${UI.icon(i.icon)} ${i.label}
                <span style="background:var(--c-warning,#e65100);color:#fff;
                             border-radius:999px;padding:0 6px;margin-left:2px">
                  ${d[i.key]}
                </span>
              </button>`).join('')
        }
        <span style="margin-left:auto;font-size:var(--text-xs);color:var(--c-text-muted)">
          ${UI.icon('user-plus')} ${usersToday} neue Nutzer heute
        </span>
      </div>`;

    el.querySelectorAll('[data-action-tab]').forEach(btn => {
      btn.addEventListener('click', () => {
        _tab = btn.dataset.actionTab;
        _container.querySelectorAll('#adm-tabs .by-tab').forEach(b =>
          b.classList.toggle('active', b.dataset.tab === _tab)
        );
        _renderTab();
      });
    });
  }

  async function _renderTab() {
    const el = _container.querySelector('#adm-content');
    if (!el) return;
    el.innerHTML = `<div style="padding:var(--space-6);text-align:center;color:var(--c-text-muted)">Lade…</div>`;
    try {
      switch (_tab) {
        case 'uebersicht':  await _renderStats(el);       break;
        case 'nutzer':      await _renderUsers(el);       break;
        case 'moderation':  await _renderModeration(el);  break;
        case 'zuchter':     await _renderZuechter(el);    break;
        case 'forum':       await _renderForum(el);       break;
        case 'social':      await _renderSocial(el);       break;
        case 'analytics':   await _renderAnalytics(el);   break;
        case 'system':      await _renderSystem(el);      break;
        case 'jobs':        await _renderJobs(el);        break;
        case 'partner':     await _renderPartner(el);     break;
        case 'outreach':    await _renderOutreach(el);    break;
        case 'audit':       await _renderAudit(el);       break;
        case 'bewerbungen': await _renderBewerbungen(el);  break;
      }
    } catch (e) {
      el.innerHTML = _emptyState('warning', 'Fehler', e.message || 'Unbekannter Fehler.');
    }
  }

  // ------------------------------------------------------------------
  // TAB: SOCIAL MEDIA
  async function _renderSocial(el) {
    const d = await API.get('/admin/social');

    const _PL = { instagram: '📸 Instagram', tiktok: '🎵 TikTok', both: '📱 Beide' };
    const _fmt = iso => iso ? new Date(iso).toLocaleDateString('de-DE', {day:'2-digit',month:'2-digit',year:'numeric'}) : '–';

    // Manager-Tabelle
    const managerRows = d.managers.map(m => `
      <tr>
        <td style="font-weight:600">${_esc(m.name)}</td>
        <td style="text-align:right">${m.published}</td>
        <td style="text-align:right">${m.with_link}
          ${m.published > 0 ? `<span style="font-size:10px;color:var(--c-text-muted)">
            (${Math.round(m.with_link/m.published*100)}%)</span>` : ''}</td>
        <td style="text-align:right">${m.scheduled}</td>
        <td style="text-align:right">${m.ideas}</td>
        <td style="text-align:right;color:var(--c-text-muted)">${m.total}</td>
      </tr>`).join('');

    // Plattform-Balken
    const maxPlat = Math.max(...d.by_platform.map(p => p.n), 1);
    const platBars = d.by_platform.map(p => `
      <div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-2)">
        <div style="width:120px;flex-shrink:0;font-size:var(--text-sm)">${_PL[p.platform]||p.platform}</div>
        <div style="flex:1;background:var(--c-surface-2);border-radius:var(--radius-full);height:8px;overflow:hidden">
          <div style="width:${Math.round(p.n/maxPlat*100)}%;height:100%;
                      background:var(--c-primary);border-radius:var(--radius-full)"></div>
        </div>
        <div style="width:28px;text-align:right;font-weight:600;font-size:var(--text-sm)">${p.n}</div>
      </div>`).join('');

    // Monats-Timeline
    const maxMonth = Math.max(...d.by_month.map(m => m.n), 1);
    const monthBars = [...d.by_month].reverse().map(m => `
      <div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-2)">
        <div style="width:55px;flex-shrink:0;font-size:11px;color:var(--c-text-muted)">${m.monat}</div>
        <div style="flex:1;background:var(--c-surface-2);border-radius:var(--radius-full);height:8px;overflow:hidden">
          <div style="width:${Math.round(m.n/maxMonth*100)}%;height:100%;
                      background:var(--c-success);border-radius:var(--radius-full)"></div>
        </div>
        <div style="width:28px;text-align:right;font-weight:600;font-size:var(--text-sm)">${m.n}</div>
      </div>`).join('');

    // Veröffentlichte Posts (mit/ohne Link)
    const postRows = d.recent_published.map(p => `
      <tr>
        <td style="color:var(--c-text-muted);white-space:nowrap">${_fmt(p.published_at)}</td>
        <td style="font-weight:500;max-width:200px;overflow:hidden;text-overflow:ellipsis;
                   white-space:nowrap">${_esc(p.topic)}</td>
        <td>${_PL[p.platform]||p.platform||'–'}</td>
        <td style="font-size:10px;color:var(--c-text-muted)">${_esc(p.category||'–')}</td>
        <td>${p.ai_score ? '⭐'.repeat(p.ai_score) : '–'}</td>
        <td style="font-weight:500">${_esc(p.manager||'–')}</td>
        <td>${p.post_url
          ? `<a href="${_esc(p.post_url)}" target="_blank" rel="noopener"
               style="font-size:11px;color:var(--c-primary)">🔗 Link</a>`
          : `<span style="font-size:11px;color:var(--c-text-muted)">–</span>`}</td>
      </tr>`).join('');

    el.innerHTML = `
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4);margin-bottom:var(--space-4)">
        <!-- Plattform -->
        <div class="card" style="padding:var(--space-4)">
          <div style="font-size:var(--text-sm);font-weight:700;margin-bottom:var(--space-3)">
            Veröffentlicht nach Plattform
          </div>
          ${platBars || '<div style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Posts</div>'}
        </div>
        <!-- Timeline -->
        <div class="card" style="padding:var(--space-4)">
          <div style="font-size:var(--text-sm);font-weight:700;margin-bottom:var(--space-3)">
            Posts pro Monat
          </div>
          ${monthBars || '<div style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Posts</div>'}
        </div>
      </div>

      <!-- Manager -->
      ${d.managers.length ? `
      <div class="card adm-table-card" style="margin-bottom:var(--space-4)">
        <div style="padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:700;
                    text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-secondary);
                    border-bottom:1px solid var(--c-border)">Manager-Übersicht</div>
        <div class="adm-table-scroll">
          <table class="adm-table">
            <thead><tr>
              <th>Manager</th>
              <th style="text-align:right">Veröffentlicht</th>
              <th style="text-align:right">Mit Link</th>
              <th style="text-align:right">Geplant</th>
              <th style="text-align:right">Ideen</th>
              <th style="text-align:right">Gesamt</th>
            </tr></thead>
            <tbody>${managerRows}</tbody>
          </table>
        </div>
      </div>` : ''}

      <!-- Alle veröffentlichten Posts -->
      <div class="card adm-table-card">
        <div style="padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:700;
                    text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-secondary);
                    border-bottom:1px solid var(--c-border)">
          Veröffentlichte Posts (letzte 50)
        </div>
        <div class="adm-table-scroll">
          <table class="adm-table">
            <thead><tr>
              <th>Datum</th><th>Thema</th><th>Plattform</th>
              <th>Kategorie</th><th>Score</th><th>Manager</th><th>Link</th>
            </tr></thead>
            <tbody>${postRows || `<tr><td colspan="7" style="text-align:center;
              color:var(--c-text-muted);padding:var(--space-6)">Noch keine Posts</td></tr>`}</tbody>
          </table>
        </div>
      </div>`;
  }

  // ------------------------------------------------------------------
  // TAB: ANALYTICS
  async function _renderAnalytics(el) {
    el.innerHTML = `<div style="padding:var(--space-4);color:var(--c-text-muted);font-size:var(--text-sm)">Lade Analytics…</div>`;
    let d;
    try { d = await API.get('/admin/analytics'); }
    catch (err) {
      el.innerHTML = `<div style="padding:var(--space-4);color:var(--c-danger);font-size:var(--text-sm)">
        ${UI.icon('warning')} Fehler: ${_esc(err.message || String(err))}</div>`;
      return;
    }

    const tv  = v => (v != null && typeof v === 'object') ? (v.value ?? 0) : (v ?? 0);
    const fmt = v => Number(v).toLocaleString('de');

    const pv  = d.pageviews?.pageviews ?? [];
    const ses = d.pageviews?.sessions  ?? [];

    // Bounce + Verweildauer
    const _bounces = tv(d.today?.bounces), _vis = tv(d.today?.visits);
    const bounceToday = _vis > 0 ? ((_bounces / _vis) * 100).toFixed(0) + ' %' : '—';
    const _tt = tv(d.week?.totaltime),    _vw  = tv(d.week?.visits);
    const timeWeek = _tt > 0 && _vw > 0 ? Math.round(_tt / _vw) + ' s' : '—';

    // Dual-Series Area+Line Chart (SVG)
    function _dualChart(pvData, sesData) {
      if (!pvData.length) return `<p style="color:var(--c-text-muted);font-size:var(--text-xs);margin:0">Keine Daten</p>`;
      const W = 800, H = 120, padX = 0, padY = 8;
      const pvVals  = pvData.map(p => p.y ?? 0);
      const sesVals = sesData.map(p => p.y ?? 0);
      const maxVal  = Math.max(...pvVals, ...sesVals, 1);
      const n = pvData.length;

      function toXY(vals) {
        return vals.map((v, i) => {
          const x = n === 1 ? W/2 : padX + i * ((W - 2*padX) / (n - 1));
          const y = H - padY - (v / maxVal) * (H - 2*padY);
          return [x.toFixed(1), y.toFixed(1)];
        });
      }
      const pvPts  = toXY(pvVals);
      const sesPts = toXY(sesVals);
      const pvLine  = pvPts.map(p => p.join(',')).join(' ');
      const sesLine = sesPts.map(p => p.join(',')).join(' ');

      // Filled area unter pageviews
      const areaPath = `M ${pvPts[0][0]},${H} ` +
        pvPts.map(p => `L ${p[0]},${p[1]}`).join(' ') +
        ` L ${pvPts[pvPts.length-1][0]},${H} Z`;

      // X-Achsen-Labels: Anfang, Mitte, Ende
      const labelIdx = [0, Math.floor(n/2), n-1].filter((v,i,a) => a.indexOf(v)===i);
      const labels = labelIdx.map(i => {
        const x = n === 1 ? W/2 : padX + i * ((W - 2*padX) / (n - 1));
        const date = pvData[i]?.x ? new Date(pvData[i].x).toLocaleDateString('de',{day:'2-digit',month:'2-digit'}) : '';
        return `<text x="${x.toFixed(0)}" y="${H+14}" text-anchor="middle"
                      font-size="10" fill="currentColor" style="color:var(--c-text-muted)">${date}</text>`;
      }).join('');

      return `<svg viewBox="0 0 ${W} ${H+18}" style="width:100%;height:100px;display:block;overflow:visible"
                   preserveAspectRatio="none">
        <defs>
          <linearGradient id="pvGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stop-color="var(--c-primary)" stop-opacity="0.25"/>
            <stop offset="100%" stop-color="var(--c-primary)" stop-opacity="0.02"/>
          </linearGradient>
        </defs>
        <path d="${areaPath}" fill="url(#pvGrad)"/>
        <polyline points="${pvLine}" fill="none" stroke="var(--c-primary)"
                  stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/>
        <polyline points="${sesLine}" fill="none" stroke="var(--c-success)"
                  stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="4,2"/>
        ${labels}
      </svg>`;
    }

    // Balken-Chart für Top-Pages / Referrers
    function _barChart(items, labelKey = 'x', valKey = 'y') {
      if (!items?.length) return `<p style="color:var(--c-text-muted);font-size:var(--text-sm)">Keine Daten</p>`;
      const maxV = Math.max(...items.map(p => p[valKey] ?? 0), 1);
      return `<div style="display:flex;flex-direction:column;gap:var(--space-2)">
        ${items.map(p => {
          const pct = ((p[valKey] ?? 0) / maxV * 100).toFixed(0);
          return `<div>
            <div style="display:flex;justify-content:space-between;font-size:var(--text-xs);margin-bottom:3px">
              <span style="color:var(--c-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:78%">${_esc(p[labelKey] || '—')}</span>
              <span style="color:var(--c-text-secondary);flex-shrink:0;margin-left:var(--space-2)">${fmt(p[valKey] ?? 0)}</span>
            </div>
            <div style="height:4px;border-radius:2px;background:var(--c-surface-2)">
              <div style="height:100%;width:${pct}%;border-radius:2px;background:var(--c-primary);transition:width .4s"></div>
            </div>
          </div>`;
        }).join('')}
      </div>`;
    }

    el.innerHTML = `
      <div style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)">

        <!-- Stat-Karten -->
        <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:var(--space-3)">
          ${_statCard('user',              'Besucher heute',    fmt(tv(d.today?.visitors)),  'var(--c-primary)')}
          ${_statCard('eye',               'Aufrufe heute',     fmt(tv(d.today?.pageviews)), 'var(--c-primary)')}
          ${_statCard('users',             'Besucher 7 Tage',   fmt(tv(d.week?.visitors)),   'var(--c-success)')}
          ${_statCard('eye',               'Aufrufe 7 Tage',    fmt(tv(d.week?.pageviews)),  'var(--c-success)')}
          ${_statCard('users',             'Besucher 30 Tage',  fmt(tv(d.month?.visitors)),  'var(--c-text-secondary)')}
          ${_statCard('eye',               'Aufrufe 30 Tage',   fmt(tv(d.month?.pageviews)), 'var(--c-text-secondary)')}
          ${_statCard('arrow-u-up-left',   'Bounce heute',      bounceToday,                 'var(--c-text-secondary)')}
          ${_statCard('timer',             'Ø Verweildauer 7d', timeWeek,                    'var(--c-text-secondary)')}
        </div>

        <!-- Verlaufschart 30 Tage -->
        <div class="card" style="padding:var(--space-4)">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-3)">
            <span style="font-size:var(--text-sm);font-weight:var(--weight-semibold)">Verlauf — letzte 30 Tage</span>
            <div style="display:flex;gap:var(--space-3);font-size:10px;color:var(--c-text-muted)">
              <span style="display:flex;align-items:center;gap:4px">
                <span style="width:12px;height:2px;background:var(--c-primary);display:inline-block;border-radius:1px"></span> Aufrufe
              </span>
              <span style="display:flex;align-items:center;gap:4px">
                <span style="width:12px;height:2px;background:var(--c-success);display:inline-block;border-radius:1px;
                             border-bottom:2px dashed var(--c-success);background:none"></span> Besucher
              </span>
            </div>
          </div>
          ${_dualChart(pv, ses)}
        </div>

        <!-- Jahres-Übersicht -->
        <div class="card" style="padding:var(--space-4)">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-4)">
            <span style="font-size:var(--text-sm);font-weight:var(--weight-semibold)">Jahresübersicht — letzte 12 Monate</span>
            <div style="display:flex;gap:var(--space-3);font-size:10px;color:var(--c-text-muted)">
              <span style="display:flex;align-items:center;gap:4px">
                <span style="width:12px;height:10px;background:var(--c-primary);opacity:0.7;display:inline-block;border-radius:2px"></span> Seitenaufrufe
              </span>
              <span style="display:flex;align-items:center;gap:4px">
                <span style="width:12px;height:10px;background:var(--c-success);opacity:0.7;display:inline-block;border-radius:2px"></span> Neuanmeldungen
              </span>
            </div>
          </div>
          ${(() => {
            const pvYear = d.pageviews_year?.pageviews ?? [];
            const regs   = d.monthly_registrations ?? [];

            // Alle Monate der letzten 12 sammeln
            const months = [];
            const now = new Date();
            for (let i = 11; i >= 0; i--) {
              const d2 = new Date(now.getFullYear(), now.getMonth() - i, 1);
              months.push(d2.getFullYear() + '-' + String(d2.getMonth()+1).padStart(2,'0'));
            }

            // Umami liefert x als ISO-Datum-String
            const pvByMonth = {};
            pvYear.forEach(p => {
              const key = (p.x || '').slice(0, 7);
              pvByMonth[key] = (pvByMonth[key] || 0) + (p.y ?? 0);
            });
            const regByMonth = {};
            regs.forEach(r => { regByMonth[r.month] = r.count; });

            const pvVals  = months.map(m => pvByMonth[m]  || 0);
            const regVals = months.map(m => regByMonth[m] || 0);
            const maxPv   = Math.max(...pvVals, 1);
            const maxReg  = Math.max(...regVals, 1);

            const W = 800, H = 120, n = months.length;
            const barW = Math.floor((W - (n-1)*4) / n);

            const bars = months.map((m, i) => {
              const x     = i * (barW + 4);
              const pvH   = Math.round((pvVals[i]  / maxPv)  * (H - 20));
              const regH  = Math.round((regVals[i] / maxReg) * (H - 20));
              const label = m.slice(5); // MM
              return `
                <rect x="${x}" y="${H - 20 - pvH}" width="${barW}" height="${pvH}"
                      fill="var(--c-primary)" opacity="0.65" rx="2"/>
                <rect x="${x + Math.floor(barW*0.55)}" y="${H - 20 - regH}" width="${Math.floor(barW*0.4)}" height="${regH}"
                      fill="var(--c-success)" opacity="0.8" rx="2"/>
                <text x="${x + barW/2}" y="${H - 4}" text-anchor="middle"
                      font-size="9" fill="currentColor" style="color:var(--c-text-muted)">${label}</text>
              `;
            }).join('');

            return `<svg viewBox="0 0 ${W} ${H}" style="width:100%;height:120px;display:block;overflow:visible"
                        preserveAspectRatio="none">${bars}</svg>`;
          })()}
        </div>

        <!-- Top Seiten + Referrers nebeneinander -->
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)">
          <div class="card" style="padding:var(--space-4)">
            <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                        margin-bottom:var(--space-3)">Top Seiten — 30 Tage</div>
            ${_barChart(d.top_pages)}
          </div>
          <div class="card" style="padding:var(--space-4)">
            <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                        margin-bottom:var(--space-3)">Referrers — 30 Tage</div>
            ${_barChart(d.referrers)}
          </div>
        </div>

      </div>`;
  }


  // ------------------------------------------------------------------
  // TAB: ÜBERSICHT
  // ------------------------------------------------------------------
  async function _renderStats(el) {
    const [s, ki, kiH] = await Promise.all([
      API.get('/admin/stats'),
      API.get('/admin/ki/status').catch(() => null),
      API.get('/admin/ki/history').catch(() => null),
    ]);

    const _kiStatusBadge = () => {
      if (!ki) return '';
      if (ki.mode === 'off') {
        return `<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3);
                            padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                            border-radius:var(--radius-md)">
          <span style="width:8px;height:8px;border-radius:50%;background:var(--c-text-muted);flex-shrink:0"></span>
          <span style="font-size:var(--text-xs);color:var(--c-text-muted)">KI-Modus: <strong>off</strong></span>
        </div>`;
      }
      const dot   = ki.local_reachable ? 'var(--c-success)' : 'var(--c-danger)';
      const label = ki.local_reachable ? 'Lokal erreichbar' : 'Nicht erreichbar';
      const model = ki.local_model_loaded || ki.local_model_config || '?';
      return `<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3);
                          padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                          border-radius:var(--radius-md);flex-wrap:wrap">
        <span style="width:8px;height:8px;border-radius:50%;background:${dot};flex-shrink:0;
                     box-shadow:0 0 4px ${dot}"></span>
        <span style="font-size:var(--text-xs);color:var(--c-text-secondary);font-weight:600">${label}</span>
        <span style="font-size:var(--text-xs);color:var(--c-text-muted)">·</span>
        <span style="font-size:var(--text-xs);color:var(--c-text-muted);font-family:monospace">${_esc(model)}</span>
        <span style="margin-left:auto;font-size:10px;padding:1px 6px;border-radius:10px;
                     background:var(--c-surface);color:var(--c-text-muted);border:1px solid var(--c-border)">
          Modus: ${ki.local_reachable ? 'local' : 'cloud'}
        </span>
      </div>`;
    };

    el.innerHTML = `
      <div class="adm-stats-grid">
        ${_statCard('users',           'Nutzer gesamt',      s.users_total,        'var(--c-primary)')}
        ${_statCard('user-plus',       'Neu heute',          s.users_today,        'var(--c-success)')}
        ${_statCard('activity',        'Aktiv (7 Tage)',      s.active_users_7d,    'var(--c-primary)')}
        ${_statCard('paw-print',       'Hunde',              s.dogs_total,         'var(--c-primary)')}
        ${_statCard('chat-circle-dots','Threads',            s.threads,            'var(--c-text-secondary)')}
        ${_statCard('warning',         'Offene Meldungen',   s.open_reports,       s.open_reports > 0 ? 'var(--c-danger)' : 'var(--c-text-muted)')}
        ${_statCard('camera',          'Fotos freizugeben',  s.pending_fotos ?? 0, (s.pending_fotos ?? 0) > 0 ? 'var(--c-warning)' : 'var(--c-text-muted)')}
        ${_statCard('skull',           'Gesperrte User',     s.banned,             s.banned > 0 ? '#f59e0b' : 'var(--c-text-muted)')}
        ${_statCard('warning-octagon', 'Giftk. aktiv',       s.poison_active,      'var(--c-danger)')}
        ${_statCard('bell',            'Push-Abos',          s.push_subscriptions, 'var(--c-text-secondary)')}
        ${_statCard('image',           'Media-Einträge',     s.media_count,        'var(--c-text-secondary)')}
        ${_statCard('map-pin',         'Routen',             s.routes_total,       'var(--c-text-secondary)')}
        ${_statCard('calendar',        'Events',             s.events_total,       'var(--c-text-secondary)')}
        ${_statCard('map-trifold',     'OSM-Marker',         s.osm_total.toLocaleString('de'), 'var(--c-success)')}
        ${_statCard('squares-four',    'Gecachte Tiles',     s.osm_tiles.toLocaleString('de'), 'var(--c-text-secondary)')}
      </div>

      <div class="card" style="padding:var(--space-4)">
        <!-- Header -->
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-3)">
          <p style="font-size:var(--text-sm);font-weight:600;margin:0;display:flex;align-items:center;gap:var(--space-2)">
            <svg class="ph-icon" style="width:16px;height:16px;color:var(--c-primary)" aria-hidden="true"><use href="/icons/phosphor.svg#robot"></use></svg>
            KI-Nutzung
          </p>
          <span style="font-size:var(--text-xs);font-weight:700;padding:2px 10px;border-radius:100px;
                       background:var(--c-primary-subtle);color:var(--c-primary)">
            ${s.ki_today ?? 0} heute · ${s.ki_week ?? 0} (7 Tage)
          </span>
        </div>
        <!-- KI-Status Badge -->
        ${_kiStatusBadge()}
        <!-- Quellen-Zeile -->
        <div style="display:flex;gap:var(--space-2);flex-wrap:wrap;margin-bottom:var(--space-3)">
          ${[
            ['☁️ Claude',    s.ki_cloud_week,  'var(--c-primary)'],
            ['🖥️ Lokal',    s.ki_local_week,  'var(--c-success)'],
            ['🌙 Luna',      s.ki_luna_week,   'var(--c-warning)'],
            ['📅 Monat',     s.ki_month,       'var(--c-text-secondary)'],
            ['👥 User heute',s.ki_users_today, 'var(--c-text-secondary)'],
          ].map(([label, val, color]) => `
            <span style="font-size:var(--text-xs);padding:2px 8px;border-radius:100px;
                         background:var(--c-surface-2);border:1px solid var(--c-border);white-space:nowrap">
              <span style="color:var(--c-text-muted)">${label}</span>
              <strong style="color:${color};margin-left:3px">${val ?? 0}</strong>
            </span>`).join('')}
        </div>
        <!-- Sparkline (30 Tage) -->
        ${(() => {
          const hist = kiH?.daily_history || [];
          if (!hist.length) return '<p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:0 0 var(--space-3)">Noch keine Verlaufsdaten</p>';
          const max = Math.max(...hist.map(d => d.total), 1);
          const W = 400, H = 60, n = hist.length;
          const pts = hist.map((d, i) => {
            const x = n === 1 ? W/2 : (i / (n - 1)) * W;
            const y = H - 5 - (d.total / max) * (H - 10);
            return `${x.toFixed(1)},${y.toFixed(1)}`;
          }).join(' ');
          const first = hist[0]?.date?.slice(5) || '';
          const last  = hist[hist.length-1]?.date?.slice(5) || '';
          return `<div style="margin-bottom:var(--space-3)">
            <svg viewBox="0 0 ${W} ${H}" style="width:100%;height:60px;display:block" preserveAspectRatio="none">
              <polyline points="${pts}" fill="none" stroke="var(--c-primary)" stroke-width="1.5" stroke-linejoin="round"/>
            </svg>
            <div style="display:flex;justify-content:space-between;font-size:10px;color:var(--c-text-muted);margin-top:2px">
              <span>${first}</span><span>30 Tage</span><span>${last}</span>
            </div>
          </div>`;
        })()}
        <!-- Limit-Hinweis -->
        <p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:0 0 var(--space-3)">
          Cloud-Limit: <strong>${s.ki_cloud_weekly_limit ?? 20} Anfragen / Woche</strong> pro User
        </p>
        <!-- Top-Nutzer -->
        ${(kiH?.top_users || []).length ? `
        <p style="font-size:var(--text-xs);font-weight:600;color:var(--c-text-secondary);margin:0 0 var(--space-2);text-transform:uppercase;letter-spacing:.04em">Aktivste Nutzer</p>
        <div class="adm-table-scroll">
          <table class="adm-table">
            <thead><tr>
              <th>Name</th><th>E-Mail</th><th>☁️ Cloud</th><th>Gesamt</th><th>Zuletzt</th>
            </tr></thead>
            <tbody>
              ${(kiH.top_users).map(u => `<tr>
                <td style="font-weight:600">${_esc(u.name)}</td>
                <td style="color:var(--c-text-muted)">${_esc(u.email.length > 22 ? u.email.split('@')[1] : u.email)}</td>
                <td style="color:var(--c-primary);font-weight:600">${u.cloud}</td>
                <td>${u.total}</td>
                <td style="color:var(--c-text-muted)">${u.last_date?.slice(5) || '—'}</td>
              </tr>`).join('')}
            </tbody>
          </table>
        </div>` : ''}
      </div>

      <div class="card" style="padding:var(--space-4)">
        <p style="font-size:var(--text-sm);font-weight:600;margin:0 0 var(--space-3)">OSM-Cache nach Typ</p>
        <div style="display:flex;flex-direction:column;gap:var(--space-2)">
          ${Object.entries(s.osm_by_type).map(([type, count]) => `
            <div style="display:flex;justify-content:space-between;font-size:var(--text-sm)">
              <span style="color:var(--c-text-secondary)">${type}</span>
              <span style="font-weight:600">${count.toLocaleString('de')}</span>
            </div>
          `).join('')}
        </div>
      </div>

      <!-- Social Media Tracking -->
      <div class="card" style="padding:var(--space-4)">
        <p style="font-size:var(--text-sm);font-weight:600;margin:0 0 var(--space-3)">
          📱 Social Media Tracking</p>
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2);
                    margin-bottom:var(--space-3)">
          ${[
            ['Gesamt generiert', s.social_total,     'var(--c-text-secondary)'],
            ['Veröffentlicht',   s.social_published,  'var(--c-success)'],
            ['Geplant',          s.social_scheduled,  'var(--c-primary)'],
            ['Ideen offen',      s.social_ideas,      'var(--c-warning)'],
            ['Diese Woche live', s.social_this_week,  'var(--c-success)'],
          ].map(([label, val, color]) => `
            <div style="background:var(--c-surface-2);border-radius:8px;padding:10px">
              <div style="font-size:10px;color:var(--c-text-muted);margin-bottom:2px">${label}</div>
              <div style="font-size:1.4em;font-weight:700;color:${color}">${val ?? 0}</div>
            </div>`).join('')}
        </div>
        ${Object.keys(s.social_by_cat||{}).length ? `
        <div style="margin-bottom:var(--space-3)">
          <div style="font-size:11px;color:var(--c-text-muted);margin-bottom:6px;
                      font-weight:600;text-transform:uppercase">Kategorien</div>
          <div style="display:flex;gap:6px;flex-wrap:wrap">
            ${Object.entries(s.social_by_cat).map(([cat, n]) => `
              <span style="background:var(--c-surface-2);border-radius:20px;
                           padding:2px 10px;font-size:11px">
                ${cat} <strong>${n}</strong></span>`).join('')}
          </div>
        </div>` : ''}
        ${s.social_recent?.length ? `
        <div>
          <div style="font-size:11px;color:var(--c-text-muted);margin-bottom:6px;
                      font-weight:600;text-transform:uppercase">Letzte 10 Posts</div>
          <div style="display:flex;flex-direction:column;gap:6px">
            ${s.social_recent.map(p => `
              <div style="display:flex;align-items:center;gap:8px;
                          font-size:var(--text-xs);padding:6px 0;
                          border-bottom:1px solid var(--c-border)">
                <span style="padding:2px 7px;border-radius:4px;font-size:10px;
                             background:var(--c-surface-2);flex-shrink:0;
                             color:${{idea:'var(--c-text-muted)',draft:'var(--c-warning)',
                               scheduled:'var(--c-primary)',published:'var(--c-success)',
                               archived:'var(--c-text-muted)'}[p.status]||'inherit'}">
                  ${p.status}</span>
                <span style="flex:1;overflow:hidden;text-overflow:ellipsis;
                             white-space:nowrap">${p.topic}</span>
                <span style="color:var(--c-text-muted);flex-shrink:0">
                  ${(p.published_at||p.created_at||'').slice(0,10)}</span>
              </div>`).join('')}
          </div>
        </div>` : ''}
      </div>

      <div class="card" style="padding:var(--space-4)">
        <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0;line-height:1.6">
          <svg class="ph-icon" aria-hidden="true" style="color:var(--c-primary)">
            <use href="/icons/phosphor.svg#info"></use>
          </svg>
          Ersten Admin per SQL setzen:
          <code style="background:var(--c-surface-2);padding:2px 6px;border-radius:4px;font-size:var(--text-xs);word-break:break-all;display:inline-block">
            UPDATE users SET rolle='admin', is_moderator=1 WHERE email='deine@email.de';
          </code>
        </p>
      </div>
    `;
  }

  function _statCard(icon, label, value, color) {
    return `
      <div class="card" style="padding:var(--space-4);text-align:center">
        <svg class="ph-icon" style="width:24px;height:24px;color:${color};margin-bottom:var(--space-2)"
             aria-hidden="true">
          <use href="/icons/phosphor.svg#${icon}"></use>
        </svg>
        <div style="font-size:var(--text-2xl);font-weight:var(--weight-bold);color:var(--c-text)">
          ${value ?? '—'}
        </div>
        <div style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-top:2px">${label}</div>
      </div>
    `;
  }

  // ------------------------------------------------------------------
  // TAB: NUTZER
  // ------------------------------------------------------------------
  async function _renderUsers(el) {
    el.innerHTML = `
      <div class="adm-filter-row">
        <input id="adm-user-q" type="search" placeholder="Name oder E-Mail…"
               class="adm-filter-input">
        <select id="adm-user-rolle" class="adm-filter-select">
          <option value="">Alle Rollen</option>
          <option value="user">user</option>
          <option value="moderator">moderator</option>
          <option value="admin">admin</option>
        </select>
      </div>
      <div id="adm-user-list">Lade…</div>
    `;

    const load = async () => {
      const q     = el.querySelector('#adm-user-q').value;
      const rolle = el.querySelector('#adm-user-rolle').value;
      const data  = await API.get(`/admin/users?q=${encodeURIComponent(q)}&rolle=${rolle}`);
      _renderUserList(el.querySelector('#adm-user-list'), data.users, data.total);
    };

    let timer;
    el.querySelector('#adm-user-q').addEventListener('input', () => {
      clearTimeout(timer);
      timer = setTimeout(load, 350);
    });
    el.querySelector('#adm-user-rolle').addEventListener('change', load);
    await load();
  }

  function _renderUserList(el, users, total) {
    if (!users.length) {
      el.innerHTML = _emptyState('users', 'Keine Nutzer gefunden', '');
      return;
    }

    const isAdmin = _appState.user?.rolle === 'admin';

    el.innerHTML = `
      <div style="margin-bottom:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted)">
        ${total} Nutzer gefunden
      </div>
      <div style="display:flex;flex-direction:column;gap:var(--space-2)">
        ${users.map(u => `
          <div class="card" style="padding:var(--space-3) var(--space-4);
               ${u.is_banned ? 'opacity:0.6;border-left:3px solid var(--c-danger)' : ''}">
            <div style="display:flex;align-items:center;gap:var(--space-3)">

              <!-- Avatar -->
              <div style="width:36px;height:36px;border-radius:50%;flex-shrink:0;
                          background:var(--c-surface-2);
                          display:flex;align-items:center;justify-content:center;
                          font-weight:var(--weight-bold);color:var(--c-text-secondary)">
                ${_esc(u.name[0].toUpperCase())}
              </div>

              <!-- Info -->
              <div style="flex:1;min-width:0">
                <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--c-text)">
                  ${_esc(u.name)}
                  ${u.is_banned ? `<span style="font-size:10px;padding:1px 5px;border-radius:3px;
                                              background:var(--c-danger);color:#fff;margin-left:4px">
                                    GESPERRT</span>` : ''}
                </div>
                <div style="font-size:var(--text-xs);color:var(--c-text-muted)">
                  ${_esc(u.email)} ·
                  <span style="color:${u.rolle === 'admin' ? 'var(--c-danger)' : u.rolle === 'moderator' ? '#f59e0b' : 'var(--c-text-muted)'}">
                    ${_esc(u.rolle)}
                  </span>
                  · ${u.dog_count} Hund${u.dog_count !== 1 ? 'e' : ''}
                  · ${u.thread_count} Threads
                </div>
                <div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">
                  🗺 ${u.route_count} Routen · ${u.total_km} km
                  · 📍 ${u.poi_count} POIs
                  ${u.last_route ? '· zuletzt ' + new Date(u.last_route).toLocaleDateString('de-DE') : ''}
                </div>
              </div>

              <!-- Aktionen -->
              <div style="display:flex;gap:var(--space-1);flex-shrink:0">
                ${u.is_banned
                  ? `<button class="btn btn-sm btn-ghost adm-unban" data-uid="${u.id}" data-name="${_esc(u.name)}"
                             title="Sperre aufheben" style="color:var(--c-success)">
                       <svg class="ph-icon"><use href="/icons/phosphor.svg#lock-open"></use></svg>
                     </button>`
                  : `<button class="btn btn-sm btn-ghost adm-ban" data-uid="${u.id}" data-name="${_esc(u.name)}"
                             title="Sperren" style="color:var(--c-danger)">
                       <svg class="ph-icon"><use href="/icons/phosphor.svg#lock"></use></svg>
                     </button>`
                }
                ${isAdmin ? `
                  <button class="btn btn-sm btn-ghost adm-rolle" data-uid="${u.id}"
                          data-name="${_esc(u.name)}" data-rolle="${_esc(u.rolle)}"
                          title="Rolle ändern">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#shield"></use></svg>
                  </button>
                  <button class="btn btn-sm btn-ghost adm-delete" data-uid="${u.id}"
                          data-name="${_esc(u.name)}" title="Löschen"
                          style="color:var(--c-danger)">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#trash"></use></svg>
                  </button>
                ` : ''}
              </div>

            </div>
          </div>
        `).join('')}
      </div>
    `;

    // Events
    el.querySelectorAll('.adm-ban').forEach(btn => {
      btn.addEventListener('click', () => _banUser(btn.dataset.uid, btn.dataset.name, true));
    });
    el.querySelectorAll('.adm-unban').forEach(btn => {
      btn.addEventListener('click', () => _banUser(btn.dataset.uid, btn.dataset.name, false));
    });
    el.querySelectorAll('.adm-rolle').forEach(btn => {
      btn.addEventListener('click', () => _changeRolle(btn.dataset.uid, btn.dataset.name, btn.dataset.rolle));
    });
    el.querySelectorAll('.adm-delete').forEach(btn => {
      btn.addEventListener('click', () => _deleteUser(btn.dataset.uid, btn.dataset.name));
    });
  }

  async function _banUser(uid, name, ban) {
    if (ban) {
      const reason = await _prompt(`${name} sperren — Grund (optional):`);
      if (reason === null) return; // abgebrochen
      try {
        await API.patch(`/admin/users/${uid}`, { is_banned: 1, ban_reason: reason || 'Kein Grund angegeben.' });
        UI.toast.success(`${name} gesperrt.`);
        _renderTab();
      } catch (e) { UI.toast.error(e.message); }
    } else {
      try {
        await API.patch(`/admin/users/${uid}`, { is_banned: 0, ban_reason: null });
        UI.toast.success(`Sperre für ${name} aufgehoben.`);
        _renderTab();
      } catch (e) { UI.toast.error(e.message); }
    }
  }

  async function _changeRolle(uid, name, currentRolle) {
    const rollen = ['user', 'moderator', 'admin'].filter(r => r !== currentRolle);
    UI.modal.open({
      title: `Rolle ändern: ${name}`,
      body: `
        <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4)">
          Aktuelle Rolle: <strong>${currentRolle}</strong>
        </p>
        <div style="display:flex;flex-direction:column;gap:var(--space-2)">
          ${rollen.map(r => `
            <button class="btn btn-secondary adm-rolle-choice" data-rolle="${r}" form="">
              ${r === 'admin' ? `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#shield"></use></svg>` : ''}
              ${r === 'moderator' ? `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#star"></use></svg>` : ''}
              ${r === 'user' ? `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#user"></use></svg>` : ''}
              Als <strong>${r}</strong> setzen
            </button>
          `).join('')}
        </div>
      `,
    });

    document.querySelectorAll('.adm-rolle-choice').forEach(btn => {
      btn.addEventListener('click', async () => {
        UI.modal.close();
        try {
          await API.patch(`/admin/users/${uid}`, { rolle: btn.dataset.rolle });
          UI.toast.success(`${name} ist jetzt ${btn.dataset.rolle}.`);
          _renderTab();
        } catch (e) { UI.toast.error(e.message); }
      });
    });
  }

  async function _deleteUser(uid, name) {
    const ok = await UI.modal.confirm({
      title:       `${name} löschen?`,
      message:     'Alle Daten dieses Accounts werden unwiderruflich gelöscht — Hunde, Tagebuch, Beiträge.',
      confirmText: 'Endgültig löschen',
    });
    if (!ok) return;
    try {
      await API.del(`/admin/users/${uid}`);
      UI.toast.success(`${name} gelöscht.`);
      _renderTab();
    } catch (e) { UI.toast.error(e.message); }
  }

  // ------------------------------------------------------------------
  // TAB: FORUM & MELDUNGEN
  // ------------------------------------------------------------------
  async function _renderForum(el) {
    el.innerHTML = `
      <!-- Unternavigation -->
      <div class="adm-subnav">
        <button class="btn btn-primary btn-sm adm-forum-nav" data-view="reports" id="adm-fn-reports">
          Offene Meldungen
        </button>
        <button class="btn btn-ghost btn-sm adm-forum-nav" data-view="threads" id="adm-fn-threads">
          Alle Threads
        </button>
      </div>
      <div id="adm-forum-content">Lade…</div>
    `;

    el.querySelectorAll('.adm-forum-nav').forEach(btn => {
      btn.addEventListener('click', async () => {
        el.querySelectorAll('.adm-forum-nav').forEach(b => {
          b.className = b === btn ? 'btn btn-primary btn-sm adm-forum-nav' : 'btn btn-ghost btn-sm adm-forum-nav';
        });
        await _renderForumView(el.querySelector('#adm-forum-content'), btn.dataset.view);
      });
    });

    await _renderForumView(el.querySelector('#adm-forum-content'), 'reports');
  }

  async function _renderForumView(el, view) {
    el.innerHTML = '<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>';

    if (view === 'reports') {
      const reports = await API.get('/admin/reports');
      if (!reports.length) {
        el.innerHTML = _emptyState('check', 'Keine offenen Meldungen', 'Alles sauber.');
        return;
      }
      el.innerHTML = `
        <div style="display:flex;flex-direction:column;gap:var(--space-3)">
          ${reports.map(r => `
            <div class="card" style="padding:var(--space-4);
                 ${r.resolved ? 'opacity:0.5' : 'border-left:3px solid var(--c-danger)'}">
              <div style="display:flex;align-items:flex-start;gap:var(--space-3)">
                <div style="flex:1;min-width:0">
                  <div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-bottom:var(--space-1)">
                    ${r.resolved ? '✓ Erledigt · ' : ''}
                    ${_esc(r.target_type)} #${r.target_id} ·
                    Gemeldet von <strong>${_esc(r.melder_name)}</strong>
                  </div>
                  <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                               color:var(--c-text);margin-bottom:var(--space-1)">
                    Grund: ${_esc(r.grund)}
                  </div>
                  ${r.content_preview ? `
                    <div style="font-size:var(--text-xs);color:var(--c-text-secondary);
                                 padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                                 border-radius:var(--radius-sm)">
                      ${_esc(r.content_preview)}
                    </div>` : ''}
                </div>
                <div style="display:flex;flex-direction:column;gap:var(--space-2);flex-shrink:0">
                  <button class="btn btn-sm ${r.resolved ? 'btn-ghost' : 'btn-primary'} adm-resolve-btn"
                          data-rid="${r.id}" data-resolved="${r.resolved}"
                          title="${r.resolved ? 'Wieder öffnen' : 'Als erledigt markieren'}">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#${r.resolved ? 'arrow-square-out' : 'check'}"></use></svg>
                  </button>
                  ${!r.resolved ? `
                    <button class="btn btn-sm btn-ghost adm-del-content"
                            data-type="${r.target_type}" data-id="${r.target_id}"
                            title="Inhalt löschen" style="color:var(--c-danger)">
                      <svg class="ph-icon"><use href="/icons/phosphor.svg#trash"></use></svg>
                    </button>` : ''}
                </div>
              </div>
            </div>
          `).join('')}
        </div>
      `;

      el.querySelectorAll('.adm-resolve-btn').forEach(btn => {
        btn.addEventListener('click', async () => {
          try {
            await API.patch(`/admin/reports/${btn.dataset.rid}`, {});
            _renderForumView(el, 'reports');
          } catch (e) { UI.toast.error(e.message); }
        });
      });

      el.querySelectorAll('.adm-del-content').forEach(btn => {
        btn.addEventListener('click', () => _deleteContent(btn.dataset.type, btn.dataset.id, el, 'reports'));
      });

    } else {
      // Threads
      el.innerHTML = `
        <div class="adm-filter-row">
          <input id="adm-thread-q" type="search" placeholder="Threads durchsuchen…"
                 class="adm-filter-input">
          <label class="adm-filter-label">
            <input type="checkbox" id="adm-show-deleted"> Gelöschte
          </label>
        </div>
        <div id="adm-thread-list">Lade…</div>
      `;

      const loadThreads = async () => {
        const q       = el.querySelector('#adm-thread-q').value;
        const deleted = el.querySelector('#adm-show-deleted').checked ? 1 : 0;
        const data    = await API.get(`/admin/forum/threads?q=${encodeURIComponent(q)}&deleted=${deleted}`);
        _renderThreadList(el.querySelector('#adm-thread-list'), data.threads, el);
      };

      let t2;
      el.querySelector('#adm-thread-q').addEventListener('input', () => { clearTimeout(t2); t2 = setTimeout(loadThreads, 350); });
      el.querySelector('#adm-show-deleted').addEventListener('change', loadThreads);
      await loadThreads();
    }
  }

  function _renderThreadList(el, threads, parentEl) {
    if (!threads.length) {
      el.innerHTML = _emptyState('chat-circle-dots', 'Keine Threads', '');
      return;
    }
    el.innerHTML = `
      <div style="display:flex;flex-direction:column;gap:var(--space-2)">
        ${threads.map(t => `
          <div class="card" style="padding:var(--space-3) var(--space-4);
               ${t.is_deleted ? 'opacity:0.5;border-left:3px solid var(--c-danger)' : ''}
               ${t.is_locked ? 'border-left:3px solid #f59e0b' : ''}">
            <div style="display:flex;align-items:center;gap:var(--space-3)">
              <div style="flex:1;min-width:0">
                <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                             color:var(--c-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
                  ${t.is_deleted ? '<s>' : ''}${_esc(t.titel)}${t.is_deleted ? '</s>' : ''}
                </div>
                <div style="font-size:var(--text-xs);color:var(--c-text-muted)">
                  von ${_esc(t.autor_name)} ·
                  ${t.antworten} Antworten ·
                  ${t.is_pinned ? '📌 ' : ''}${t.is_locked ? '🔒 ' : ''}${t.is_deleted ? '🗑 gelöscht' : ''}
                </div>
              </div>
              <div style="display:flex;gap:var(--space-1);flex-shrink:0">
                ${!t.is_deleted ? `
                  <button class="btn btn-sm btn-ghost adm-pin" data-tid="${t.id}"
                          data-pinned="${t.is_pinned}" title="${t.is_pinned ? 'Entpinnen' : 'Anpinnen'}">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#push-pin"></use></svg>
                  </button>
                  <button class="btn btn-sm btn-ghost adm-lock" data-tid="${t.id}"
                          data-locked="${t.is_locked}" title="${t.is_locked ? 'Entsperren' : 'Sperren'}">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#${t.is_locked ? 'lock-open' : 'lock'}"></use></svg>
                  </button>
                  <button class="btn btn-sm btn-ghost adm-del-thread" data-tid="${t.id}"
                          title="Löschen" style="color:var(--c-danger)">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#trash"></use></svg>
                  </button>
                ` : `
                  <button class="btn btn-sm btn-ghost adm-restore-thread" data-tid="${t.id}"
                          title="Wiederherstellen" style="color:var(--c-success)">
                    <svg class="ph-icon"><use href="/icons/phosphor.svg#arrow-square-out"></use></svg>
                  </button>
                `}
              </div>
            </div>
          </div>
        `).join('')}
      </div>
    `;

    el.querySelectorAll('.adm-pin').forEach(btn => {
      btn.addEventListener('click', async () => {
        await API.patch(`/admin/forum/threads/${btn.dataset.tid}`, { is_pinned: btn.dataset.pinned === '1' ? 0 : 1 });
        parentEl.querySelector('#adm-thread-q').dispatchEvent(new Event('input'));
      });
    });
    el.querySelectorAll('.adm-lock').forEach(btn => {
      btn.addEventListener('click', async () => {
        await API.patch(`/admin/forum/threads/${btn.dataset.tid}`, { is_locked: btn.dataset.locked === '1' ? 0 : 1 });
        parentEl.querySelector('#adm-thread-q').dispatchEvent(new Event('input'));
      });
    });
    el.querySelectorAll('.adm-del-thread').forEach(btn => {
      btn.addEventListener('click', () => _deleteContent('thread', btn.dataset.tid, parentEl, 'threads'));
    });
    el.querySelectorAll('.adm-restore-thread').forEach(btn => {
      btn.addEventListener('click', async () => {
        await API.patch(`/admin/forum/threads/${btn.dataset.tid}`, { is_deleted: 0 });
        parentEl.querySelector('#adm-thread-q').dispatchEvent(new Event('input'));
      });
    });
  }

  async function _deleteContent(type, id, parentEl, view) {
    const ok = await UI.modal.confirm({
      title:       `${type === 'thread' ? 'Thread' : 'Beitrag'} löschen?`,
      message:     'Der Inhalt wird als gelöscht markiert.',
      confirmText: 'Löschen',
    });
    if (!ok) return;
    try {
      await API.del(`/admin/forum/${type === 'thread' ? 'threads' : 'posts'}/${id}`);
      UI.toast.success('Gelöscht.');
      _renderForumView(parentEl, view);
    } catch (e) { UI.toast.error(e.message); }
  }

  // ------------------------------------------------------------------
  // TAB: SYSTEM
  // ------------------------------------------------------------------
  async function _renderSystem(el) {
    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-ghost btn-sm" id="adm-sys-refresh">
          ${UI.icon('arrows-clockwise')} Aktualisieren
        </button>
      </div>
      <div id="adm-ors-card"></div>
      <div id="adm-sys-cards">Lade…</div>
      <div class="card" style="margin-top:var(--space-4);padding:var(--space-4)">
        <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                    color:var(--c-text);margin-bottom:var(--space-3)">Medien</div>
        <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-3)">
          <button class="btn btn-secondary btn-sm" id="adm-generate-previews">
            ${UI.icon('images')} Previews generieren (Bestand)
          </button>
        </div>
        <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                    color:var(--c-text);margin-bottom:var(--space-3)">Wiki-Daten</div>
        <div style="display:flex;flex-wrap:wrap;gap:var(--space-2)">
          <button class="btn btn-secondary btn-sm" id="adm-enrichment-status">
            ${UI.icon('arrows-clockwise')} Enrichment-Status
          </button>
          <button class="btn btn-secondary btn-sm" id="adm-evaluate-breeds">
            ${UI.icon('chart-bar')} Qualitätsbewertung (20 Rassen)
          </button>
          <button class="btn btn-secondary btn-sm" id="adm-fetch-photos">
            ${UI.icon('image')} Fotos nachladen
          </button>
        </div>
        <div id="adm-maint-result" style="margin-top:var(--space-2);font-size:var(--text-xs);
             color:var(--c-text-secondary)"></div>
        <div id="adm-eval-result" style="margin-top:var(--space-3);display:none"></div>
      </div>

      <div style="margin-top:var(--space-5)">
        <div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
          <span style="font-size:var(--text-sm);font-weight:600">Server-Logs</span>
          <select id="adm-log-level" class="input" style="width:auto;padding:2px 8px;font-size:var(--text-xs)">
            <option value="">Alle</option>
            <option value="INFO">INFO</option>
            <option value="WARNING">WARNING</option>
            <option value="ERROR">ERROR</option>
          </select>
          <button class="btn btn-ghost btn-sm" id="adm-log-refresh">${UI.icon('arrows-clockwise')}</button>
        </div>
        <div id="adm-log-box" style="
          background:var(--c-surface-2);border-radius:var(--radius-md);
          padding:var(--space-3);font-family:monospace;font-size:11px;
          max-height:420px;overflow-y:auto;line-height:1.6">Lade…</div>
      </div>
    `;
    const loadLogs = async () => {
      const level = el.querySelector('#adm-log-level').value;
      const box   = el.querySelector('#adm-log-box');
      box.textContent = 'Lade…';
      const rows = await API.get(`/admin/logs?lines=200${level ? '&level=' + level : ''}`);
      const COLORS = { ERROR: '#ef4444', WARNING: '#f59e0b', INFO: '#6b7280', DEBUG: '#94a3b8' };
      box.innerHTML = rows.reverse().map(r => {
        const color = COLORS[r.l] || '#6b7280';
        return `<div style="border-bottom:1px solid var(--c-border);padding:2px 0">` +
          `<span style="color:var(--c-text-muted)">${r.t}</span> ` +
          `<span style="color:${color};font-weight:600">${r.l}</span> ` +
          `<span style="color:var(--c-text-secondary)">${_esc(r.n)}</span> ` +
          `<span>${_esc(r.m)}</span></div>`;
      }).join('') || '<span style="color:var(--c-text-muted)">Keine Einträge</span>';
    };
    el.querySelector('#adm-sys-refresh').addEventListener('click', () => {
      _loadSystemCards(el.querySelector('#adm-sys-cards'));
      loadLogs();
    });
    el.querySelector('#adm-log-refresh').addEventListener('click', loadLogs);
    el.querySelector('#adm-log-level').addEventListener('change', loadLogs);
    el.querySelector('#adm-generate-previews').addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      const res = el.querySelector('#adm-maint-result');
      btn.disabled = true;
      res.textContent = 'Generiere Previews… (kann 1–2 Minuten dauern)';
      try {
        const d = await API.post('/admin/media/generate-previews', {});
        res.textContent = `✓ ${d.generated} neu generiert · ${d.skipped} bereits vorhanden · ${d.errors} Fehler`;
      } catch (err) {
        res.textContent = '✗ Fehler: ' + (err.message || err);
      } finally {
        btn.disabled = false;
      }
    });

    el.querySelector('#adm-enrichment-status').addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      const res = el.querySelector('#adm-maint-result');
      btn.disabled = true;
      res.textContent = 'Lade…';
      try {
        const d = await API.get('/admin/wiki/enrichment-status');
        const modelList = Object.entries(d.by_model)
          .map(([m, n]) => `${m}: ${n}`).join(', ');
        res.textContent = `Gesamt: ${d.total} | Angereichert: ${d.enriched} | Kein Wiki: ${d.no_wiki} | Ausstehend: ${d.pending} | Mit Foto: ${d.with_photo} | Modelle: ${modelList || '–'}`;
      } catch (err) {
        res.textContent = '✗ Fehler: ' + (err.message || err);
      } finally {
        btn.disabled = false;
      }
    });

    el.querySelector('#adm-fetch-photos').addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      const res = el.querySelector('#adm-maint-result');
      btn.disabled = true;
      res.textContent = 'Fotos werden geladen… (kann 30–60s dauern)';
      try {
        const d = await API.post('/admin/wiki/fetch-photos?limit=50', {});
        res.textContent = `✓ ${d.found} Foto(s) gespeichert`;
      } catch (err) {
        res.textContent = '✗ Fehler: ' + (err.message || err);
      } finally {
        btn.disabled = false;
      }
    });

    el.querySelector('#adm-evaluate-breeds').addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      const res = el.querySelector('#adm-maint-result');
      const box = el.querySelector('#adm-eval-result');
      btn.disabled = true;
      res.textContent = 'Bewertung läuft… (ca. 30s)';
      box.style.display = 'none';
      try {
        const d = await API.get('/admin/wiki/evaluate?sample=20');
        if (d.error) { res.textContent = '✗ ' + d.error; return; }
        const avg = d.averages;
        const scoreColor = v => v >= 4 ? 'var(--c-success)' : v >= 3 ? 'var(--c-warning)' : 'var(--c-danger)';
        const scoreBar = v => `<span style="color:${scoreColor(v)};font-weight:600">${v.toFixed(1)}</span>`;
        const rows = d.results.filter(r => !r.error).map(r =>
          `<tr>
            <td style="padding:2px 6px">${_esc(r.name)}</td>
            <td style="text-align:center;padding:2px 6px">${scoreBar(r.vollstaendigkeit)}</td>
            <td style="text-align:center;padding:2px 6px">${scoreBar(r.korrektheit)}</td>
            <td style="text-align:center;padding:2px 6px">${scoreBar(r.sprachqualitaet)}</td>
            <td style="text-align:center;padding:2px 6px">${scoreBar(r.konsistenz)}</td>
            <td style="text-align:center;padding:2px 6px;font-weight:700">${scoreBar(r.gesamt)}</td>
            <td style="padding:2px 6px;color:var(--c-text-muted);font-size:0.9em">${_esc(r.hinweis || '')}</td>
          </tr>`
        ).join('');
        box.style.display = 'block';
        box.innerHTML = `
          <div style="font-size:var(--text-xs);font-weight:600;margin-bottom:var(--space-2)">
            Ø-Scores (${d.evaluated}/${d.sample_size} Rassen bewertet)
          </div>
          <div style="display:flex;gap:var(--space-4);flex-wrap:wrap;margin-bottom:var(--space-3)">
            ${['vollstaendigkeit','korrektheit','sprachqualitaet','konsistenz','gesamt'].map(k =>
              `<div style="text-align:center">
                <div style="font-size:1.4em;font-weight:700;color:${scoreColor(avg[k])}">${avg[k]?.toFixed(1) ?? '–'}</div>
                <div style="font-size:0.75em;color:var(--c-text-muted)">${{vollstaendigkeit:'Vollst.',korrektheit:'Korrekt.',sprachqualitaet:'Sprache',konsistenz:'Konsistenz',gesamt:'Gesamt'}[k]}</div>
              </div>`
            ).join('')}
          </div>
          <div style="overflow-x:auto">
            <table style="width:100%;border-collapse:collapse;font-size:var(--text-xs)">
              <thead><tr style="border-bottom:1px solid var(--c-border)">
                <th style="text-align:left;padding:2px 6px">Rasse</th>
                <th style="padding:2px 6px">Vollst.</th><th style="padding:2px 6px">Korrekt.</th>
                <th style="padding:2px 6px">Sprache</th><th style="padding:2px 6px">Konsis.</th>
                <th style="padding:2px 6px">Ges.</th><th style="text-align:left;padding:2px 6px">Hinweis</th>
              </tr></thead>
              <tbody>${rows}</tbody>
            </table>
          </div>`;
        res.textContent = `✓ Bewertung abgeschlossen`;
      } catch (err) {
        res.textContent = '✗ Fehler: ' + (err.message || err);
      } finally {
        btn.disabled = false;
      }
    });

    const [, orsStats] = await Promise.all([
      _loadSystemCards(el.querySelector('#adm-sys-cards')),
      API.get('/admin/ors/stats').catch(() => null),
    ]);
    _renderOrsCard(el.querySelector('#adm-ors-card'), orsStats);
    await loadLogs();
  }

  async function _loadSystemCards(el) {
    el.innerHTML = `<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>`;
    const s = await API.get('/admin/system');
    const diskUsedGb  = s.disk_total_gb - s.disk_free_gb;
    const diskPct     = s.disk_total_gb > 0 ? Math.round(diskUsedGb / s.disk_total_gb * 100) : 0;
    const uptime      = _formatUptime(s.uptime_seconds);
    el.innerHTML = `
      <div class="adm-stats-grid">
        ${_statCard('database',  'Datenbank',      s.db_size_mb.toFixed(1) + ' MB',  'var(--c-primary)')}
        ${_statCard('image',     'Media-Ordner',   s.media_size_mb.toFixed(1) + ' MB','var(--c-text-secondary)')}
        ${_statCard('timer',     'Uptime',          uptime,                            'var(--c-success)')}
        ${_statCard('hard-drive','Disk frei',       s.disk_free_gb.toFixed(1) + ' GB','diskPct > 85 ? "var(--c-danger)" : "var(--c-text-secondary)"')}
      </div>
      <div class="card" style="margin-top:var(--space-4);padding:var(--space-4)">
        <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                    color:var(--c-text);margin-bottom:var(--space-3)">Disk-Auslastung</div>
        <div style="display:flex;align-items:center;gap:var(--space-3)">
          <div style="flex:1;height:8px;background:var(--c-surface-2);border-radius:4px;overflow:hidden">
            <div style="height:100%;width:${diskPct}%;background:${diskPct > 85 ? 'var(--c-danger)' : diskPct > 65 ? '#f59e0b' : 'var(--c-success)'};border-radius:4px;transition:width .3s"></div>
          </div>
          <div style="font-size:var(--text-sm);color:var(--c-text-secondary);white-space:nowrap">
            ${diskPct}% · ${diskUsedGb.toFixed(1)} / ${s.disk_total_gb.toFixed(1)} GB
          </div>
        </div>
        <div style="margin-top:var(--space-3);font-size:var(--text-xs);color:var(--c-text-muted);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:4px">
          <span>Python ${_esc(s.python_version)}</span>
          <span style="font-family:monospace;font-size:var(--text-xs);background:var(--c-surface-2);padding:2px 8px;border-radius:4px;color:var(--c-text-secondary)">
            APP v${typeof APP_VER !== 'undefined' ? APP_VER : '—'} · ${_esc(s.sw_version || '?')}
          </span>
        </div>
      </div>
    `;
  }

  function _renderOrsCard(el, d) {
    if (!el) return;
    if (!d || d.today_count == null) { el.innerHTML = ''; return; }

    const limit   = d.today_limit ?? 2000;
    const count   = d.today_count ?? 0;
    const pct     = Math.min(Math.round(count / limit * 100), 100);
    const barColor = pct < 50 ? '#4ade80' : pct <= 80 ? '#facc15' : '#f87171';

    // Wochensumme + Gesamtsumme aus daily_history
    const hist7     = (d.daily_history || []).slice(-7);
    const weekTotal = hist7.reduce((s, h) => s + (h.count ?? 0), 0);
    const totalAll  = (d.daily_history || []).reduce((s, h) => s + (h.count ?? 0), 0);

    // Sparkline aus daily_history (letzte 30 Tage)
    const hist    = Array.isArray(d.daily_history) ? d.daily_history : [];
    const W = 400, H = 60, padY = 5;
    let sparkline = '';
    if (hist.length >= 2) {
      const maxC = Math.max(...hist.map(h => h.count), 1);
      const pts  = hist.map((h, i) => {
        const x = (i / (hist.length - 1)) * W;
        const y = H - padY - (h.count / maxC) * (H - 2 * padY);
        return `${x.toFixed(1)},${y.toFixed(1)}`;
      }).join(' ');
      sparkline = `<polyline points="${pts}" fill="none" stroke="var(--c-primary)" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round"/>`;
    } else {
      sparkline = `<polyline points="0,55 ${W},55" fill="none" stroke="var(--c-primary)" stroke-width="1.5"/>`;
    }
    const lastDate  = hist.length ? hist[hist.length - 1].date : '';

    // Top-Nutzer-Tabelle
    const topUsers = Array.isArray(d.top_users) ? d.top_users.slice(0, 10) : [];
    const userRows = topUsers.map(u => {
      const emailDisplay = (u.email || '').length > 20
        ? '@' + (u.email || '').split('@')[1]
        : _esc(u.email || '');
      return `<tr>
        <td style="padding:5px 8px;font-weight:500">${_esc(u.name || '–')}</td>
        <td style="padding:5px 8px;color:var(--c-text-muted);font-size:var(--text-xs)">${emailDisplay}</td>
        <td style="padding:5px 8px;text-align:right;font-weight:600">${u.total ?? 0}</td>
        <td style="padding:5px 8px;text-align:right;color:var(--c-text-muted);font-size:var(--text-xs)">${u.last_week || '–'}</td>
      </tr>`;
    }).join('');

    el.innerHTML = `
      <div class="card" style="margin-bottom:var(--space-4);padding:var(--space-4)">

        <!-- Header -->
        <div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
          <svg class="ph-icon" style="width:20px;height:20px;color:var(--c-primary);flex-shrink:0" aria-hidden="true">
            <use href="/icons/phosphor.svg#path"></use>
          </svg>
          <span style="font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--c-text);flex:1">
            OpenRouteService
          </span>
          <div style="display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap">
            <span style="font-size:var(--text-xs);font-weight:700;padding:3px 10px;border-radius:999px;
                         background:${barColor}22;color:${barColor};border:1px solid ${barColor}44">
              ${count.toLocaleString('de')} / ${limit.toLocaleString('de')} heute
            </span>
            <span style="font-size:var(--text-xs);color:var(--c-text-muted);white-space:nowrap">
              ${weekTotal} diese Woche · ${totalAll} gesamt (30 Tage)
            </span>
          </div>
        </div>

        <!-- Fortschrittsbalken -->
        <div style="height:6px;border-radius:3px;background:var(--c-border);overflow:hidden;margin-bottom:var(--space-4)">
          <div style="height:100%;width:${pct}%;background:${barColor};border-radius:3px;transition:width 0.6s ease"></div>
        </div>

        <!-- Sparkline -->
        <div style="margin-bottom:var(--space-1)">
          <svg viewBox="0 0 ${W} ${H}" style="width:100%;height:60px;display:block">
            ${sparkline}
          </svg>
        </div>
        <div style="display:flex;justify-content:space-between;font-size:var(--text-xs);
                    color:var(--c-text-muted);margin-bottom:var(--space-4)">
          <span>30 Tage</span>
          <span>${_esc(lastDate)}</span>
        </div>

        ${topUsers.length ? `
        <!-- Top-Nutzer -->
        <div style="font-size:var(--text-xs);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
                    color:var(--c-text-secondary);margin-bottom:var(--space-2)">Aktivste Nutzer</div>
        <div style="overflow-x:auto">
          <table style="width:100%;border-collapse:collapse;font-size:var(--text-xs)">
            <thead>
              <tr style="border-bottom:1px solid var(--c-border)">
                <th style="text-align:left;padding:4px 8px;color:var(--c-text-muted);font-weight:600">Name</th>
                <th style="text-align:left;padding:4px 8px;color:var(--c-text-muted);font-weight:600">E-Mail</th>
                <th style="text-align:right;padding:4px 8px;color:var(--c-text-muted);font-weight:600">Gesamt</th>
                <th style="text-align:right;padding:4px 8px;color:var(--c-text-muted);font-weight:600">Letzte Woche</th>
              </tr>
            </thead>
            <tbody>${userRows}</tbody>
          </table>
        </div>` : ''}

      </div>`;
  }

  function _formatUptime(secs) {
    const d = Math.floor(secs / 86400);
    const h = Math.floor((secs % 86400) / 3600);
    const m = Math.floor((secs % 3600) / 60);
    if (d > 0) return `${d}d ${h}h`;
    if (h > 0) return `${h}h ${m}min`;
    return `${m}min`;
  }

  // ------------------------------------------------------------------
  // TAB: JOBS
  // ------------------------------------------------------------------
  // TAB: MODERATION
  // ------------------------------------------------------------------
  function _ageLabel(createdAt) {
    if (!createdAt) return '';
    const h = (Date.now() - new Date(createdAt + 'Z').getTime()) / 3600000;
    const overdue = h >= 24;
    const label = h < 1 ? '<1h' : h < 24 ? `${Math.floor(h)}h` : `${Math.floor(h/24)}d ${Math.floor(h%24)}h`;
    return `<span style="font-size:var(--text-xs);font-weight:700;padding:1px 7px;border-radius:999px;
                         margin-left:6px;${overdue
                           ? 'background:#fef2f2;color:#dc2626;border:1px solid #fca5a5'
                           : 'background:var(--c-surface-2);color:var(--c-text-muted);border:1px solid var(--c-border)'}">
              ${overdue ? '⚠️ ' : ''}${label}
            </span>`;
  }

  function _historySection(label, items, renderItem) {
    const id = `hist-${label.replace(/\W/g,'').toLowerCase()}`;
    return `
      <details style="margin-bottom:var(--space-4)">
        <summary style="cursor:pointer;list-style:none;display:flex;align-items:center;gap:var(--space-2);
                        font-size:var(--text-xs);font-weight:700;color:var(--c-text-muted);
                        text-transform:uppercase;letter-spacing:.06em;padding:var(--space-2) 0;
                        border-top:1px solid var(--c-border)">
          ${UI.icon('clock-countdown')} ${items.length} erledigte ${label}
          <svg class="ph-icon" style="margin-left:auto;transition:transform .2s" aria-hidden="true">
            <use href="/icons/phosphor.svg#caret-down"></use>
          </svg>
        </summary>
        <div style="margin-top:var(--space-2);display:flex;flex-direction:column;gap:var(--space-1)">
          ${items.map(item => `
            <div style="font-size:var(--text-xs);color:var(--c-text-secondary);
                        padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                        border-radius:var(--radius-sm);display:flex;align-items:center;flex-wrap:wrap;gap:4px">
              ${renderItem(item)}
            </div>`).join('')}
        </div>
      </details>`;
  }

  async function _renderModeration(el) {
    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-ghost btn-sm" id="adm-mod-refresh">${UI.icon('arrows-clockwise')} Aktualisieren</button>
      </div>
      <div id="adm-mod-content">Lade…</div>
    `;
    el.querySelector('#adm-mod-refresh').addEventListener('click', () => _loadModeration(el.querySelector('#adm-mod-content')));
    await _loadModeration(el.querySelector('#adm-mod-content'));
  }

  async function _loadModeration(el) {
    el.innerHTML = `<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>`;

    const [zuchter, fotos, reports, poiEdits] = await Promise.all([
      API.get('/wiki/zuchter/pending').catch(() => []),
      API.get('/wiki/foto-submissions').catch(() => []),
      API.get('/moderation/reports').catch(() => []),
      API.get('/moderation/poi-edits').catch(() => []),
    ]);
    const zuchterPending = zuchter.filter(z => !z.verified);
    const zuchterDone    = zuchter.filter(z =>  z.verified);
    const fotosPending   = fotos.filter(f => f.status === 'pending');
    const fotosDone      = fotos.filter(f => f.status !== 'pending');
    const reportsPending = reports.filter(r => !r.resolved);
    const reportsDone    = reports.filter(r =>  r.resolved);
    const poiPending     = poiEdits.filter(e => e.status === 'pending');
    const poiDone        = poiEdits.filter(e => e.status !== 'pending');

    const modItems = [
      { label: 'Züchter-Einreichungen', count: zuchterPending.length, icon: 'certificate' },
      { label: 'Foto-Einreichungen',    count: fotosPending.length,   icon: 'image'       },
      { label: 'Forum-Meldungen',       count: reportsPending.length, icon: 'warning'     },
      { label: 'POI-Korrekturen',       count: poiPending.length,     icon: 'map-pin'     },
    ].filter(i => i.count > 0);

    let html = `
      <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center;
                  background:var(--c-surface);border:1px solid var(--c-border);
                  border-radius:var(--radius-lg);padding:var(--space-3) var(--space-4);
                  margin-bottom:var(--space-4)">
        <span style="font-size:var(--text-xs);font-weight:700;color:var(--c-text-muted);
                     text-transform:uppercase;letter-spacing:.06em;margin-right:var(--space-1)">
          ${UI.icon('check-square')} Zu erledigen
        </span>
        ${modItems.length === 0
          ? `<span style="font-size:var(--text-sm);color:var(--c-success,#4caf50);font-weight:600">
               ${UI.icon('check-circle')} Alles erledigt
             </span>`
          : modItems.map(i => `
              <span style="display:inline-flex;align-items:center;gap:4px;
                     background:var(--c-warning-light,#fff3e0);color:var(--c-warning,#e65100);
                     border:1px solid var(--c-warning,#e65100);border-radius:999px;
                     padding:2px 10px;font-size:var(--text-xs);font-weight:700">
                ${UI.icon(i.icon)} ${i.label}
                <strong style="background:var(--c-warning,#e65100);color:#fff;
                               border-radius:999px;padding:0 6px;margin-left:2px">${i.count}</strong>
              </span>`).join('')
        }
      </div>`;

    // --- Züchter-Einreichungen ---
    html += `<h3 style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                         color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.06em;
                         margin-bottom:var(--space-3)">
               Züchter-Einreichungen
               <span style="background:var(--c-primary);color:#fff;border-radius:999px;
                             padding:1px 8px;font-size:var(--text-xs);margin-left:6px">${zuchterPending.length}</span>
             </h3>`;

    if (!zuchterPending.length) {
      html += `<p style="font-size:var(--text-sm);color:var(--c-text-muted);margin-bottom:var(--space-3)">Keine ausstehenden Einreichungen.</p>`;
    } else {
      html += `<div class="card adm-table-card" style="margin-bottom:var(--space-3)"><div class="adm-table-scroll"><table class="adm-table">
        <thead><tr style="background:var(--c-surface-2);text-align:left">
          <th class="adm-th">Rasse</th><th class="adm-th">Name / Zwingername</th>
          <th class="adm-th">Ort</th><th class="adm-th">VDH</th><th class="adm-th">Alter</th><th class="adm-th">Website</th><th class="adm-th"></th>
        </tr></thead><tbody>
        ${zuchterPending.map((z, i) => `
          <tr style="${i%2===1?'background:var(--c-surface-2)':''}">
            <td class="adm-td" style="font-weight:var(--weight-semibold)">${_esc(z.rasse_slug)}</td>
            <td class="adm-td">${_esc(z.name)}${z.zwingername ? `<br><span style="color:var(--c-text-muted);font-size:var(--text-xs)">${_esc(z.zwingername)}</span>` : ''}</td>
            <td class="adm-td">${_esc([z.plz, z.ort, z.bundesland].filter(Boolean).join(' '))}</td>
            <td class="adm-td">${z.vdh_mitglied ? `<span style="color:var(--c-success);display:flex;align-items:center;gap:2px"><svg class="ph-icon" style="width:14px;height:14px" aria-hidden="true"><use href="/icons/phosphor.svg#check"></use></svg> VDH</span>` : '—'}</td>
            <td class="adm-td">${_ageLabel(z.created_at)}</td>
            <td class="adm-td">${z.website ? `<a href="${_esc(z.website)}" target="_blank" style="color:var(--c-primary);font-size:var(--text-xs)">Link</a>` : '—'}</td>
            <td class="adm-td" style="text-align:right;white-space:nowrap">
              <button class="btn btn-sm btn-primary adm-zuchter-approve" data-id="${z.id}" style="margin-right:4px"><svg class="ph-icon" style="width:14px;height:14px" aria-hidden="true"><use href="/icons/phosphor.svg#check"></use></svg> Freigeben</button>
              <button class="btn btn-sm btn-ghost adm-zuchter-delete" data-id="${z.id}" style="color:var(--c-danger)"><svg class="ph-icon" style="width:14px;height:14px" aria-hidden="true"><use href="/icons/phosphor.svg#x"></use></svg></button>
            </td>
          </tr>`).join('')}
        </tbody></table></div></div>`;
    }
    // Züchter-History
    if (zuchterDone.length) html += _historySection('Züchter-Einreichungen', zuchterDone,
      z => `<span style="font-weight:600">${_esc(z.name)}</span> · ${_esc(z.rasse_slug)} ·
            ${UI.icon('check-circle')} ${_esc(z.verified_by_name||'?')} · ${(z.verified_at||'').slice(0,10)}`);

    // --- Wiki-Foto-Einreichungen ---
    html += `<h3 style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                         color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.06em;
                         margin-bottom:var(--space-3)">
               Wiki-Foto-Einreichungen
               <span style="background:var(--c-primary);color:#fff;border-radius:999px;
                             padding:1px 8px;font-size:var(--text-xs);margin-left:6px">${fotosPending.length}</span>
             </h3>`;

    if (!fotosPending.length) {
      html += `<p style="font-size:var(--text-sm);color:var(--c-text-muted);margin-bottom:var(--space-3)">Keine ausstehenden Foto-Einreichungen.</p>`;
    } else {
      html += `<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-4);margin-bottom:var(--space-3)">
        ${fotosPending.map(f => `
          <div class="card" style="padding:var(--space-4)">
            <img src="${_esc(f.foto_url)}" alt=""
                 style="width:100%;height:140px;object-fit:cover;border-radius:var(--radius-md);margin-bottom:var(--space-3)">
            <div style="font-weight:var(--weight-semibold);font-size:var(--text-sm)">${_esc(f.rasse_name)}</div>
            <div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-bottom:var(--space-2)">von ${_esc(f.user_name)}</div>
            <div style="margin-bottom:var(--space-3)">${_ageLabel(f.created_at)}</div>
            ${f.aktuell_foto ? `<img src="${_esc(f.aktuell_foto)}" alt="Aktuell"
                 style="width:100%;height:80px;object-fit:cover;border-radius:var(--radius-sm);
                         opacity:.5;margin-bottom:var(--space-2)">
              <div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-bottom:var(--space-3)">↑ aktuelles Foto</div>` : ''}
            <div style="display:flex;gap:var(--space-2)">
              <button class="btn btn-sm btn-primary adm-foto-approve" data-id="${f.id}" style="flex:1">✓</button>
              <button class="btn btn-sm btn-ghost adm-foto-reject"  data-id="${f.id}" style="color:var(--c-danger)">✗</button>
            </div>
          </div>`).join('')}
      </div>`;
    }

    // Fotos-History
    if (fotosDone.length) html += _historySection('Foto-Einreichungen', fotosDone,
      f => `<img src="${_esc(f.foto_url)}" style="width:32px;height:32px;object-fit:cover;border-radius:4px;vertical-align:middle;margin-right:6px">
            <span style="font-weight:600">${_esc(f.rasse_name||'?')}</span> · von ${_esc(f.user_name||'?')} ·
            ${f.status==='approved' ? `${UI.icon('check-circle')} genehmigt` : `${UI.icon('x-circle')} abgelehnt`}
            ${f.reviewed_by_name ? ` von ${_esc(f.reviewed_by_name)}` : ''} · ${(f.reviewed_at||'').slice(0,10)}`);

    // --- Forum-Meldungen ---
    html += `<h3 style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                         color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.06em;
                         margin:var(--space-4) 0 var(--space-3)">
               Forum-Meldungen
               <span style="background:${reportsPending.length ? 'var(--c-danger)' : 'var(--c-primary)'};color:#fff;
                             border-radius:999px;padding:1px 8px;font-size:var(--text-xs);margin-left:6px">
                 ${reportsPending.length}
               </span>
             </h3>`;
    if (!reportsPending.length) {
      html += `<p style="font-size:var(--text-sm);color:var(--c-text-muted);margin-bottom:var(--space-3)">Keine offenen Meldungen.</p>`;
    } else {
      html += `<div style="display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-3)">
        ${reportsPending.map(r => `
          <div class="card" style="padding:var(--space-4);border-left:3px solid var(--c-danger)">
            <div style="display:flex;align-items:flex-start;gap:var(--space-3)">
              <div style="flex:1;min-width:0">
                <div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-bottom:var(--space-1);display:flex;align-items:center;flex-wrap:wrap;gap:4px">
                  ${_esc(r.target_type)} #${r.target_id} · Gemeldet von <strong>${_esc(r.melder_name || '?')}</strong>
                  ${_ageLabel(r.created_at)}
                </div>
                <div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);margin-bottom:var(--space-1)">
                  Grund: ${_esc(r.grund)}
                </div>
                ${r.content_preview ? `
                  <div style="font-size:var(--text-xs);color:var(--c-text-secondary);
                               padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                               border-radius:var(--radius-sm)">${_esc(r.content_preview)}</div>` : ''}
              </div>
              <button class="btn btn-sm btn-primary adm-mod-resolve" data-rid="${r.id}" title="Als erledigt markieren">
                ${UI.icon('check')}
              </button>
            </div>
          </div>`).join('')}
      </div>`;
    }

    // Meldungen-History
    if (reportsDone.length) html += _historySection('Forum-Meldungen', reportsDone,
      r => `${_esc(r.target_type)} #${r.target_id} · ${_esc(r.grund)} · Gemeldet von ${_esc(r.melder_name||'?')} ·
            ${UI.icon('check-circle')} ${_esc(r.resolved_by_name||'?')} · ${(r.resolved_at||'').slice(0,10)}`);

    // --- POI-Korrekturen ---
    html += `<h3 style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
                         color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.06em;
                         margin:var(--space-2) 0 var(--space-3)">
               POI-Korrekturen
               <span style="background:${poiPending.length ? 'var(--c-warning,#e65100)' : 'var(--c-primary)'};color:#fff;
                             border-radius:999px;padding:1px 8px;font-size:var(--text-xs);margin-left:6px">
                 ${poiPending.length}
               </span>
             </h3>`;
    if (!poiPending.length) {
      html += `<p style="font-size:var(--text-sm);color:var(--c-text-muted)">Keine ausstehenden POI-Korrekturen.</p>`;
    } else {
      html += `<div class="card adm-table-card"><div class="adm-table-scroll">
        <table class="adm-table">
          <thead><tr style="background:var(--c-surface-2);text-align:left">
            <th class="adm-th">Ort</th>
            <th class="adm-th">Feld</th>
            <th class="adm-th">Alt</th>
            <th class="adm-th">Neu</th>
            <th class="adm-th">Von</th>
            <th class="adm-th">Alter</th>
            <th class="adm-th"></th>
          </tr></thead>
          <tbody>
            ${poiPending.map((e, i) => `
              <tr style="${i%2===1?'background:var(--c-surface-2)':''}">
                <td class="adm-td" style="font-weight:var(--weight-semibold)">${_esc(e.poi_name || `OSM #${e.osm_id}`)}</td>
                <td class="adm-td"><code style="font-size:var(--text-xs)">${_esc(e.field)}</code></td>
                <td class="adm-td" style="color:var(--c-text-muted);font-size:var(--text-xs)">${_esc(e.old_value || '—')}</td>
                <td class="adm-td" style="font-size:var(--text-xs)">${_esc(e.new_value || '—')}</td>
                <td class="adm-td" style="color:var(--c-text-muted)">${_esc(e.einreicher_name || '?')}</td>
                <td class="adm-td">${_ageLabel(e.created_at)}</td>
                <td class="adm-td" style="text-align:right;white-space:nowrap">
                  <button class="btn btn-sm btn-primary adm-poi-approve" data-id="${e.id}" style="margin-right:4px">
                    ${UI.icon('check')}
                  </button>
                  <button class="btn btn-sm btn-ghost adm-poi-reject" data-id="${e.id}" style="color:var(--c-danger)">
                    ${UI.icon('x')}
                  </button>
                </td>
              </tr>`).join('')}
          </tbody>
        </table>
      </div></div>`;
    }
    // POI-History
    if (poiDone.length) html += _historySection('POI-Korrekturen', poiDone,
      e => `<span style="font-weight:600">${_esc(e.poi_name||`OSM #${e.osm_id}`)}</span> ·
            <code style="font-size:var(--text-xs)">${_esc(e.field)}</code>:
            <span style="text-decoration:line-through;color:var(--c-text-muted)">${_esc(e.old_value||'—')}</span> →
            ${_esc(e.new_value||'—')} ·
            ${e.status==='approved' ? `${UI.icon('check-circle')} freigegeben` : `${UI.icon('x-circle')} abgelehnt`}
            ${e.mod_name ? ` von ${_esc(e.mod_name)}` : ''} · ${(e.resolved_at||'').slice(0,10)}`);

    el.innerHTML = html;

    // Züchter freigeben
    el.querySelectorAll('.adm-zuchter-approve').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        await API.patch(`/wiki/zuchter/${btn.dataset.id}/verify`, {});
        await _loadModeration(el);
      });
    });

    // Züchter löschen
    el.querySelectorAll('.adm-zuchter-delete').forEach(btn => {
      btn.addEventListener('click', async () => {
        if (!window.confirm('Eintrag löschen?')) return;
        btn.disabled = true;
        await API.delete(`/admin/wiki/zuchter/${btn.dataset.id}`);
        await _loadModeration(el);
      });
    });

    // Foto freigeben
    el.querySelectorAll('.adm-foto-approve').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        await API.patch(`/wiki/foto-submissions/${btn.dataset.id}`, {action: 'approve'});
        await _loadModeration(el);
      });
    });

    // Foto ablehnen
    el.querySelectorAll('.adm-foto-reject').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        await API.patch(`/wiki/foto-submissions/${btn.dataset.id}`, {action: 'reject', reject_reason: 'Nicht geeignet.'});
        await _loadModeration(el);
      });
    });

    // Forum-Meldung erledigen
    el.querySelectorAll('.adm-mod-resolve').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        try {
          await API.patch(`/moderation/reports/${btn.dataset.rid}`, {});
          await _loadModeration(el);
        } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
      });
    });

    // POI-Korrektur freigeben
    el.querySelectorAll('.adm-poi-approve').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        try {
          await API.patch(`/moderation/poi-edits/${btn.dataset.id}`, { action: 'approve' });
          UI.toast.success('Korrektur übernommen.');
          await _loadModeration(el);
        } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
      });
    });

    // POI-Korrektur ablehnen
    el.querySelectorAll('.adm-poi-reject').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        try {
          await API.patch(`/moderation/poi-edits/${btn.dataset.id}`, { action: 'reject' });
          UI.toast.success('Korrektur abgelehnt.');
          await _loadModeration(el);
        } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
      });
    });
  }

  // ------------------------------------------------------------------
  // TAB: ZÜCHTER-ANTRÄGE
  // ------------------------------------------------------------------
  async function _renderZuechter(el) {
    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-ghost btn-sm" id="adm-zuchter-refresh">
          ${UI.icon('arrows-clockwise')} Aktualisieren
        </button>
      </div>
      <div id="adm-zuchter-list">Lade…</div>
    `;
    el.querySelector('#adm-zuchter-refresh').addEventListener('click', () =>
      _loadZuechterAntraege(el.querySelector('#adm-zuchter-list'))
    );
    await _loadZuechterAntraege(el.querySelector('#adm-zuchter-list'));
  }

  async function _loadZuechterAntraege(el) {
    el.innerHTML = `<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>`;
    let antraege;
    try {
      antraege = await API.breeder.pendingList();
    } catch (e) {
      el.innerHTML = _emptyState('warning', 'Fehler', e.message || 'Anträge konnten nicht geladen werden.');
      return;
    }

    if (!antraege.length) {
      el.innerHTML = _emptyState('certificate', 'Keine offenen Anträge', 'Aktuell liegen keine Züchter-Anträge zur Prüfung vor.');
      return;
    }

    el.innerHTML = `
      <div style="display:flex;flex-direction:column;gap:var(--space-3)">
        ${antraege.map(a => `
          <div class="card" style="padding:var(--space-4)">
            <div style="display:flex;align-items:flex-start;gap:var(--space-3);flex-wrap:wrap">

              <!-- Infos -->
              <div style="flex:1;min-width:0">
                <div style="font-weight:var(--weight-semibold);font-size:var(--text-sm);
                            color:var(--c-text);margin-bottom:var(--space-1)">
                  ${_esc(a.name)}
                  <span style="font-size:var(--text-xs);color:var(--c-text-muted);font-weight:400;margin-left:6px">
                    ${_esc(a.email)}
                  </span>
                </div>
                <div style="display:flex;flex-wrap:wrap;gap:var(--space-3);font-size:var(--text-xs);
                            color:var(--c-text-secondary);margin-bottom:var(--space-2)">
                  <span>${UI.icon('paw-print')} ${_esc(a.rasse_text || '–')}</span>
                  <span>${UI.icon('house-line')} ${_esc(a.zwingername || '–')}</span>
                  <span>${UI.icon('users')} ${_esc(a.verein || '–')}</span>
                  <span>${UI.icon('map-pin')} ${_esc(a.stadt || '–')}</span>
                  <span style="color:${a.vdh_mitglied ? 'var(--c-success)' : 'var(--c-text-muted)'}">
                    ${UI.icon('certificate')} VDH: ${a.vdh_mitglied ? 'ja' : 'nein'}
                  </span>
                  ${a.created_at ? `<span style="color:var(--c-text-muted)">${UI.icon('clock')} ${new Date(a.created_at).toLocaleDateString('de-DE')}</span>` : ''}
                </div>
                ${a.beschreibung ? `
                  <div style="font-size:var(--text-xs);color:var(--c-text-secondary);
                              padding:var(--space-2) var(--space-3);background:var(--c-surface-2);
                              border-radius:var(--radius-sm);margin-top:var(--space-1)">
                    ${_esc(a.beschreibung)}
                  </div>` : ''}
              </div>

              <!-- Aktionen -->
              <div style="display:flex;flex-direction:column;gap:var(--space-2);flex-shrink:0">
                <button class="btn btn-sm btn-secondary adm-breeder-docs"
                        data-uid="${a.user_id || a.id}">
                  ${UI.icon('file-text')} Dokumente
                </button>
                <button class="btn btn-sm btn-primary adm-breeder-approve"
                        data-uid="${a.user_id || a.id}" data-name="${_esc(a.name)}">
                  ${UI.icon('check')} Freischalten
                </button>
                <button class="btn btn-sm btn-ghost adm-breeder-reject"
                        data-uid="${a.user_id || a.id}" data-name="${_esc(a.name)}"
                        style="color:var(--c-danger)">
                  ${UI.icon('x')} Ablehnen
                </button>
              </div>

            </div>
          </div>
        `).join('')}
      </div>
    `;

    // Dokumente anzeigen
    el.querySelectorAll('.adm-breeder-docs').forEach(btn => {
      btn.addEventListener('click', async () => {
        const uid = btn.dataset.uid;
        let docs;
        try {
          docs = await API.breeder.documents(uid);
        } catch (e) {
          UI.toast.error(e.message || 'Dokumente konnten nicht geladen werden.');
          return;
        }
        UI.modal.open({
          title: `${UI.icon('file-text')} Hochgeladene Dokumente`,
          body: docs.length
            ? `<div style="display:flex;flex-direction:column;gap:var(--space-3)">
                ${docs.map(d => `
                  <a href="${_esc(API.breeder.documentUrl(uid, d.id))}"
                     target="_blank" rel="noopener"
                     class="btn btn-secondary"
                     style="text-align:left;word-break:break-all">
                    ${UI.icon('file')} ${_esc(d.filename || d.name || 'Dokument ' + d.id)}
                  </a>`).join('')}
              </div>`
            : `<p style="font-size:var(--text-sm);color:var(--c-text-muted)">Keine Dokumente hochgeladen.</p>`,
        });
      });
    });

    // Freischalten
    el.querySelectorAll('.adm-breeder-approve').forEach(btn => {
      btn.addEventListener('click', async () => {
        const ok = window.confirm(`${btn.dataset.name} als Züchter freischalten?`);
        if (!ok) return;
        btn.disabled = true;
        try {
          const res = await API.breeder.approve(btn.dataset.uid);
          UI.toast.success(res.message || `${btn.dataset.name} freigeschaltet.`);
          await _loadZuechterAntraege(el);
        } catch (e) {
          UI.toast.error(e.message || 'Freischaltung fehlgeschlagen.');
          btn.disabled = false;
        }
      });
    });

    // Ablehnen
    el.querySelectorAll('.adm-breeder-reject').forEach(btn => {
      btn.addEventListener('click', () => {
        const uid  = btn.dataset.uid;
        const name = btn.dataset.name;
        UI.modal.open({
          title: `${UI.icon('x-circle')} Antrag ablehnen: ${name}`,
          body: `
            <form id="breeder-reject-form" style="display:flex;flex-direction:column;gap:var(--space-3)">
              <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0">
                Bitte gib einen Ablehnungsgrund an. Dieser wird dem Antragsteller mitgeteilt.
              </p>
              <textarea id="breeder-reject-grund" name="grund" rows="4" required
                        placeholder="z. B. Dokumente unvollständig, Rasse nicht unterstützt…"
                        style="width:100%;box-sizing:border-box;padding:var(--space-2) var(--space-3);
                               border:1.5px solid var(--c-border);border-radius:var(--radius-md);
                               font-size:var(--text-sm);font-family:inherit;
                               background:var(--c-surface);color:var(--c-text);resize:vertical"></textarea>
            </form>
          `,
          footer: `
            <div style="display:flex;flex-direction:column;gap:var(--space-2);width:100%">
              <button class="btn btn-primary" id="breeder-reject-submit"
                      form="breeder-reject-form" style="width:100%;background:var(--c-danger);border-color:var(--c-danger)">
                Antrag ablehnen
              </button>
              <button class="btn btn-ghost" data-modal-close>Abbrechen</button>
            </div>
          `,
        });

        document.getElementById('breeder-reject-form')?.addEventListener('submit', async ev => {
          ev.preventDefault();
          const grund = document.getElementById('breeder-reject-grund')?.value?.trim();
          if (!grund) {
            UI.toast.warning('Bitte einen Ablehnungsgrund angeben.');
            return;
          }
          const submitBtn = document.getElementById('breeder-reject-submit');
          if (submitBtn) submitBtn.disabled = true;
          try {
            const res = await API.breeder.reject(uid, grund);
            UI.modal.close?.();
            UI.toast.success(res.message || `Antrag von ${name} abgelehnt.`);
            await _loadZuechterAntraege(el);
          } catch (e) {
            UI.toast.error(e.message || 'Ablehnung fehlgeschlagen.');
            if (submitBtn) submitBtn.disabled = false;
          }
        });
      });
    });
  }

  // ------------------------------------------------------------------
  async function _renderJobs(el) {
    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-ghost btn-sm" id="adm-jobs-refresh">
          ${UI.icon('arrows-clockwise')} Aktualisieren
        </button>
      </div>
      <div id="adm-jobs-list">Lade…</div>
    `;
    el.querySelector('#adm-jobs-refresh').addEventListener('click', () => _loadJobs(el.querySelector('#adm-jobs-list')));
    await _loadJobs(el.querySelector('#adm-jobs-list'));
  }

  async function _loadJobs(el) {
    el.innerHTML = `<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>`;
    const jobs = await API.get('/admin/scheduler/jobs');
    if (!jobs.length) {
      el.innerHTML = _emptyState('timer', 'Keine Jobs', 'Der Scheduler hat keine registrierten Jobs.');
      return;
    }
    el.innerHTML = `
      <div class="card adm-table-card">
        <div class="adm-table-scroll">
          <table class="adm-table">
            <thead>
              <tr style="background:var(--c-surface-2);text-align:left">
                <th class="adm-th">Job</th>
                <th class="adm-th">Nächster Lauf</th>
                <th class="adm-th">Trigger</th>
                <th class="adm-th"></th>
              </tr>
            </thead>
            <tbody>
              ${jobs.map((j, i) => `
                <tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
                  <td class="adm-td" style="font-weight:var(--weight-semibold);color:var(--c-text)">
                    ${_esc(j.name)}
                    <div class="adm-job-id">${_esc(j.id)}</div>
                  </td>
                  <td class="adm-td" style="color:var(--c-text-secondary);white-space:nowrap">
                    ${j.next_run_time ? _formatDateTime(j.next_run_time) : '<span style="color:var(--c-text-muted)">—</span>'}
                  </td>
                  <td class="adm-td adm-td-trigger">
                    ${_esc(j.trigger)}
                  </td>
                  <td class="adm-td" style="text-align:right">
                    <button class="btn btn-sm btn-ghost adm-job-trigger adm-icon-btn" data-id="${_esc(j.id)}" data-name="${_esc(j.name)}"
                            title="Jetzt ausführen" style="color:var(--c-primary)">
                      ${UI.icon('play')}
                    </button>
                  </td>
                </tr>
              `).join('')}
            </tbody>
          </table>
        </div>
      </div>
    `;
    el.querySelectorAll('.adm-job-trigger').forEach(btn => {
      btn.addEventListener('click', async () => {
        btn.disabled = true;
        try {
          await API.post(`/admin/scheduler/trigger/${encodeURIComponent(btn.dataset.id)}`, {});
          UI.toast.success(`Job "${btn.dataset.name}" wird ausgeführt.`);
        } catch (e) {
          UI.toast.error(e.message || 'Fehler beim Auslösen des Jobs.');
        } finally {
          btn.disabled = false;
        }
      });
    });
  }

  function _formatDateTime(iso) {
    try {
      const d = new Date(iso);
      return d.toLocaleString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric', hour:'2-digit', minute:'2-digit' });
    } catch { return iso; }
  }

  // ------------------------------------------------------------------
  // TAB: AUDIT-LOG
  // ------------------------------------------------------------------
  async function _renderPartner(el) {
    const codes = (await API.get('/admin/partner/codes')) || [];

    el.innerHTML = `
      <div style="display:flex;flex-direction:column;gap:var(--space-5)">

        <!-- Anleitung -->
        <div class="by-card" style="padding:var(--space-4);background:var(--c-surface-2);border-left:3px solid var(--c-primary)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-sm);font-weight:700">So funktioniert das Partner-System</h3>
          <div style="font-size:var(--text-xs);color:var(--c-text-secondary);display:flex;flex-direction:column;gap:var(--space-2)">
            <p style="margin:0"><strong>1. Partner-Code erstellen</strong> — Erstelle einen Code (z. B. <code>HUNDEBLOG</code>) für einen Influencer oder Partner. Der Code wird an die Person weitergegeben.</p>
            <p style="margin:0"><strong>2. Registrierung mit Code</strong> — Wenn sich ein neuer User mit diesem Code registriert, wird er automatisch als <em>Gründer</em> markiert (Platz #1–100, lebenslang kostenlos). Du siehst in der Tabelle wie viele Einlösungen jeder Code hat.</p>
            <p style="margin:0"><strong>3. Partner-Status vergeben</strong> — Den Influencer selbst suchst du unten bei «Nutzer-Status» und setzt <em>Partner-Badge</em> (blaues Badge im Profil) und <em>Gründer-Lizenz</em>. So ist auch er als Gründer #X sichtbar.</p>
            <p style="margin:0"><strong>Max. 100 Gründer</strong> — Ist die Zahl bei einem Code leer, ist sie unbegrenzt. Die globale Grenze über alle Codes hinweg sind 100 Gründer-Plätze.</p>
            <p style="margin:0"><strong>Freunde werben</strong> — Jeder eingeloggte User hat einen persönlichen Einladungslink (Einstellungen → Freunde werben). Bei 10 geworbenen Usern gibt es 20 % Rabatt, bei 20 → 30 %, bei 50 → 50 % — lebenslang, sobald Bezahlfunktionen aktiv sind.</p>
          </div>
        </div>

        <!-- Neuen Code anlegen -->
        <div class="by-card" style="padding:var(--space-4)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-base)">Neuen Partner-Code erstellen</h3>
          <form id="adm-partner-create" style="display:flex;flex-direction:column;gap:var(--space-3)">
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)">
              <div>
                <label class="form-label" style="font-size:var(--text-xs)">Code</label>
                <input class="form-control" name="code" placeholder="z. B. HUNDEBLOG"
                       style="text-transform:uppercase;font-family:monospace;letter-spacing:.08em" required>
              </div>
              <div>
                <label class="form-label" style="font-size:var(--text-xs)">Bezeichnung</label>
                <input class="form-control" name="label" placeholder="z. B. Max Musterhund (Instagram)" required>
              </div>
            </div>
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);align-items:center">
              <div>
                <label class="form-label" style="font-size:var(--text-xs)">Max. Einlösungen <span style="color:var(--c-text-muted)">(leer = unbegrenzt)</span></label>
                <input class="form-control" name="max_uses" type="number" min="1" placeholder="∞">
              </div>
              <div style="display:flex;align-items:center;gap:var(--space-2);padding-top:var(--space-5)">
                <input type="checkbox" id="adm-grants-founder" name="grants_founder" checked
                       style="width:16px;height:16px;accent-color:var(--c-primary)">
                <label for="adm-grants-founder" style="font-size:var(--text-sm);cursor:pointer">
                  Gründer-Lizenz (lebenslang kostenlos)
                </label>
              </div>
            </div>
            <button type="submit" class="btn btn-primary btn-sm" style="align-self:flex-start">
              ${UI.icon('plus')} Code erstellen
            </button>
          </form>
        </div>

        <!-- Aktive Codes -->
        <div class="by-card" style="padding:var(--space-4)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-base)">Aktive Codes</h3>
          <div id="adm-partner-codes-list">
            ${codes.length === 0
              ? `<p style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Partner-Codes angelegt.</p>`
              : `<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm)">
                  <thead>
                    <tr style="border-bottom:1px solid var(--c-border)">
                      <th style="text-align:left;padding:var(--space-2) var(--space-3);color:var(--c-text-muted);font-weight:600;font-size:var(--text-xs)">Code</th>
                      <th style="text-align:left;padding:var(--space-2) var(--space-3);color:var(--c-text-muted);font-weight:600;font-size:var(--text-xs)">Bezeichnung</th>
                      <th style="text-align:center;padding:var(--space-2) var(--space-3);color:var(--c-text-muted);font-weight:600;font-size:var(--text-xs)">Nutzungen</th>
                      <th style="text-align:center;padding:var(--space-2) var(--space-3);color:var(--c-text-muted);font-weight:600;font-size:var(--text-xs)">Gründer</th>
                      <th style="padding:var(--space-2) var(--space-3)"></th>
                    </tr>
                  </thead>
                  <tbody>
                    ${codes.map(c => `
                      <tr style="border-bottom:1px solid var(--c-border)" data-code-id="${c.id}">
                        <td style="padding:var(--space-2) var(--space-3)">
                          <code style="font-weight:700;color:var(--c-primary);letter-spacing:.08em">${c.code}</code>
                        </td>
                        <td style="padding:var(--space-2) var(--space-3);color:var(--c-text)">${c.label}</td>
                        <td style="padding:var(--space-2) var(--space-3);text-align:center;font-weight:600">
                          ${c.uses}${c.max_uses ? `/${c.max_uses}` : ''}
                        </td>
                        <td style="padding:var(--space-2) var(--space-3);text-align:center">
                          ${c.grants_founder ? '✓' : '—'}
                        </td>
                        <td style="padding:var(--space-2) var(--space-3)">
                          <button class="btn btn-ghost btn-sm adm-del-code" data-id="${c.id}"
                                  style="color:var(--c-danger,#dc2626);font-size:var(--text-xs)">
                            ${UI.icon('trash')} Löschen
                          </button>
                        </td>
                      </tr>
                    `).join('')}
                  </tbody>
                </table>`
            }
          </div>
        </div>

        <!-- User-Status vergeben -->
        <div class="by-card" style="padding:var(--space-4)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-base)">Nutzer-Status manuell vergeben</h3>
          <form id="adm-partner-grant" style="display:flex;flex-direction:column;gap:var(--space-3)">
            <div>
              <label class="form-label" style="font-size:var(--text-xs)">User-ID oder Benutzername</label>
              <input class="form-control" name="user_search" id="adm-grant-search"
                     placeholder="Name eingeben…" autocomplete="off">
              <div id="adm-grant-result" style="margin-top:var(--space-2)"></div>
            </div>
            <div style="display:flex;gap:var(--space-4)">
              <label style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer;font-size:var(--text-sm)">
                <input type="checkbox" name="is_founder" value="1"
                       style="width:16px;height:16px;accent-color:var(--c-primary)">
                Gründer-Lizenz
              </label>
              <label style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer;font-size:var(--text-sm)">
                <input type="checkbox" name="is_partner" value="1"
                       style="width:16px;height:16px;accent-color:var(--c-primary)">
                Partner-Badge (Creator)
              </label>
            </div>
            <button type="submit" class="btn btn-secondary btn-sm" style="align-self:flex-start">
              ${UI.icon('check')} Status setzen
            </button>
          </form>
        </div>

      </div>
    `;

    // Code erstellen
    el.querySelector('#adm-partner-create')?.addEventListener('submit', async e => {
      e.preventDefault();
      const btn  = e.target.querySelector('[type="submit"]');
      const fd   = UI.formData(e.target);
      const code = (fd.code || '').trim().toUpperCase();
      if (!code) return;
      await UI.asyncButton(btn, async () => {
        await API.post('/admin/partner/codes', {
          code,
          label:          fd.label || code,
          grants_founder: e.target.querySelector('[name="grants_founder"]').checked ? 1 : 0,
          max_uses:       fd.max_uses ? parseInt(fd.max_uses) : null,
        });
        UI.toast.success(`Code "${code}" erstellt.`);
        await _renderPartner(el);
      });
    });

    // Code löschen
    el.querySelectorAll('.adm-del-code').forEach(btn => {
      btn.addEventListener('click', async () => {
        if (!window.confirm(`Code wirklich löschen?`)) return;
        const id = btn.dataset.id;
        await UI.asyncButton(btn, async () => {
          await API.del(`/admin/partner/codes/${id}`);
          UI.toast.success('Code gelöscht.');
          await _renderPartner(el);
        });
      });
    });

    // User suchen für Status-Vergabe
    let _grantUserId = null;
    const searchInput  = el.querySelector('#adm-grant-search');
    const grantResult  = el.querySelector('#adm-grant-result');
    let _searchTimeout = null;
    searchInput?.addEventListener('input', () => {
      clearTimeout(_searchTimeout);
      _grantUserId = null;
      const q = searchInput.value.trim();
      if (q.length < 1) { grantResult.innerHTML = ''; return; }
      _searchTimeout = setTimeout(async () => {
        try {
          const res = await API.get(`/admin/users?q=${encodeURIComponent(q)}&limit=10`);
          const users = res?.users || res || [];
          if (!users || !users.length) {
            grantResult.innerHTML = `<p style="font-size:var(--text-xs);color:var(--c-text-muted)">Kein User gefunden.</p>`;
            return;
          }
          grantResult.innerHTML = users.map(u => `
            <div class="adm-grant-user" data-id="${u.id}" data-name="${u.name}"
                 data-founder="${u.is_founder||0}" data-partner="${u.is_partner||0}"
                 style="padding:var(--space-2) var(--space-3);border-radius:var(--radius-sm);
                        cursor:pointer;background:var(--c-surface-2);margin-bottom:2px;
                        font-size:var(--text-sm);display:flex;justify-content:space-between">
              <span><strong>${u.name}</strong></span>
              <span style="color:var(--c-text-muted);font-size:var(--text-xs)">
                ${u.rolle}${u.is_founder ? ' · ⭐' : ''}${u.is_partner ? ' · 🤝' : ''}
              </span>
            </div>
          `).join('');
          grantResult.querySelectorAll('.adm-grant-user').forEach(div => {
            div.addEventListener('click', () => {
              _grantUserId = parseInt(div.dataset.id);
              searchInput.value = div.dataset.name;
              // Aktuellen Status in Checkboxen setzen
              const form = el.querySelector('#adm-partner-grant');
              if (form) {
                form.querySelector('[name="is_founder"]').checked = div.dataset.founder === '1';
                form.querySelector('[name="is_partner"]').checked = div.dataset.partner === '1';
              }
              grantResult.innerHTML = `<p style="font-size:var(--text-xs);color:var(--c-success,#16a34a)">✓ ${div.dataset.name} ausgewählt${div.dataset.founder==='1' ? ' · ⭐ Gründer' : ''}${div.dataset.partner==='1' ? ' · 🤝 Partner' : ''}</p>`;
            });
          });
        } catch(e) {
          grantResult.innerHTML = `<p style="font-size:var(--text-xs);color:var(--c-danger)">${e.message || 'Suchfehler'}</p>`;
        }
      }, 400);
    });

    el.querySelector('#adm-partner-grant')?.addEventListener('submit', async e => {
      e.preventDefault();
      if (!_grantUserId) { UI.toast.warning('Bitte erst einen User auswählen.'); return; }
      const btn = e.target.querySelector('[type="submit"]');
      const isFounder = e.target.querySelector('[name="is_founder"]').checked ? 1 : 0;
      const isPartner = e.target.querySelector('[name="is_partner"]').checked ? 1 : 0;
      await UI.asyncButton(btn, async () => {
        const result = await API.post(`/admin/partner/users/${_grantUserId}/grant`, {
          is_founder: isFounder,
          is_partner: isPartner,
        });
        if (!result) throw new Error('Keine Antwort vom Server.');
        UI.toast.success(`Status für ${result.name} gesetzt.`);
        grantResult.innerHTML = `<p style="font-size:var(--text-xs);color:var(--c-success,#16a34a)">✓ Gründer: ${result.is_founder ? 'Ja' : 'Nein'} | Partner: ${result.is_partner ? 'Ja' : 'Nein'}</p>`;
      }).catch(e => UI.toast.error(e.message || 'Fehler beim Speichern.'));
    });
  }

  async function _renderOutreach(el) {
    const [templates, log] = await Promise.all([
      API.get('/outreach/templates').catch(() => []),
      API.get('/outreach/log').catch(() => []),
    ]);

    const accountBadge = a => a === 'support'
      ? `<span style="font-size:10px;background:var(--c-warning-bg,#FEF3C7);color:var(--c-warning,#D97706);padding:1px 6px;border-radius:999px">support@</span>`
      : `<span style="font-size:10px;background:var(--c-primary-bg,#EFF6FF);color:var(--c-primary,#2563EB);padding:1px 6px;border-radius:999px">partner@</span>`;

    el.innerHTML = `
      <div style="display:flex;flex-direction:column;gap:var(--space-5)">

        <!-- Vorlagen-Manager -->
        <div class="by-card" style="padding:var(--space-4)">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-3)">
            <h3 style="margin:0;font-size:var(--text-base)">Vorlagen</h3>
            <button class="btn btn-sm btn-secondary" id="adm-tpl-new">
              ${UI.icon('plus')} Neue Vorlage
            </button>
          </div>
          ${templates.length === 0
            ? `<p style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Vorlagen.</p>`
            : `<div style="display:flex;flex-direction:column;gap:var(--space-2)">
                ${templates.map(t => `
                  <div style="display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-3);
                               background:var(--c-bg-elevated);border-radius:var(--radius-md);border:1px solid var(--c-border)">
                    <div style="flex:1;min-width:0">
                      <div style="display:flex;align-items:center;gap:var(--space-2)">
                        <span style="font-size:var(--text-sm);font-weight:600">${_esc(t.label)}</span>
                        ${accountBadge(t.from_account)}
                      </div>
                      <div style="font-size:var(--text-xs);color:var(--c-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">
                        ${_esc(t.subject)}
                      </div>
                    </div>
                    <div style="display:flex;gap:var(--space-2);flex-shrink:0">
                      <button class="btn btn-xs btn-secondary adm-tpl-load" data-id="${t.id}" title="In Compose laden">
                        ${UI.icon('arrow-bend-up-left')}
                      </button>
                      <button class="btn btn-xs btn-secondary adm-tpl-edit" data-id="${t.id}" title="Bearbeiten">
                        ${UI.icon('pencil-simple')}
                      </button>
                      <button class="btn btn-xs btn-danger adm-tpl-del" data-id="${t.id}" title="Löschen">
                        ${UI.icon('trash')}
                      </button>
                    </div>
                  </div>`).join('')}
              </div>`}
        </div>

        <!-- Compose -->
        <div class="by-card" style="padding:var(--space-4)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-base)">E-Mail senden</h3>
          <form id="adm-outreach-form" style="display:flex;flex-direction:column;gap:var(--space-3)">

            <!-- Absender -->
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)">
              <div>
                <label class="form-label" style="font-size:var(--text-xs)">Absender</label>
                <select id="adm-outreach-from" class="form-control">
                  <option value="partner">partner@banyaro.app (Influencer/Partner)</option>
                  <option value="support">support@banyaro.app (Support/Moderation)</option>
                </select>
              </div>
              <div>
                <label class="form-label" style="font-size:var(--text-xs)">
                  Empfänger <span style="color:var(--c-text-muted)">(Komma-getrennt)</span>
                </label>
                <input class="form-control" id="adm-outreach-to" type="text"
                       placeholder="name@example.com, andere@example.com">
              </div>
            </div>

            <!-- Betreff -->
            <div>
              <label class="form-label" style="font-size:var(--text-xs)">Betreff</label>
              <input class="form-control" id="adm-outreach-subject" type="text">
            </div>

            <!-- Text -->
            <div>
              <label class="form-label" style="font-size:var(--text-xs)">Text</label>
              <textarea id="adm-outreach-body" class="form-control" rows="14"
                        style="font-family:monospace;font-size:var(--text-sm);resize:vertical"></textarea>
            </div>

            <div style="display:flex;gap:var(--space-3);align-items:center">
              <button type="submit" class="btn btn-primary">
                ${UI.icon('paper-plane-tilt')} Senden
              </button>
              <span style="font-size:var(--text-xs);color:var(--c-text-muted)">
                {name} wird nicht automatisch ersetzt — bitte manuell anpassen.
              </span>
            </div>
          </form>
        </div>

        <!-- Versand-Log -->
        <div class="by-card" style="padding:var(--space-4)">
          <h3 style="margin:0 0 var(--space-3);font-size:var(--text-base)">Versand-Log</h3>
          ${log.length === 0
            ? `<p style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine E-Mails gesendet.</p>`
            : `<table style="width:100%;border-collapse:collapse;font-size:var(--text-xs)">
                <thead>
                  <tr style="border-bottom:1px solid var(--c-border)">
                    <th style="text-align:left;padding:var(--space-2);color:var(--c-text-muted)">Von</th>
                    <th style="text-align:left;padding:var(--space-2);color:var(--c-text-muted)">Empfänger</th>
                    <th style="text-align:left;padding:var(--space-2);color:var(--c-text-muted)">Betreff</th>
                    <th style="text-align:left;padding:var(--space-2);color:var(--c-text-muted)">Wer</th>
                    <th style="text-align:left;padding:var(--space-2);color:var(--c-text-muted)">Wann</th>
                  </tr>
                </thead>
                <tbody>
                  ${log.map((l, i) => `
                    <tr data-log-idx="${i}" style="border-bottom:1px solid var(--c-border);cursor:pointer"
                        onmouseover="this.style.background='var(--c-surface-2)'"
                        onmouseout="this.style.background=''">
                      <td style="padding:var(--space-2)">${accountBadge(l.from_account)}</td>
                      <td style="padding:var(--space-2)">${_esc(l.recipient)}</td>
                      <td style="padding:var(--space-2);color:var(--c-text-secondary)">${_esc(l.subject)}</td>
                      <td style="padding:var(--space-2);color:var(--c-text-muted)">${_esc(l.sent_by_name || '')}</td>
                      <td style="padding:var(--space-2);color:var(--c-text-muted)">${(l.sent_at||'').slice(0,16).replace('T',' ')}</td>
                    </tr>`).join('')}
                </tbody>
              </table>`}
        </div>

      </div>
    `;

    // Log-Zeile: Mail-Inhalt anzeigen
    el.querySelectorAll('tr[data-log-idx]').forEach(row => {
      row.addEventListener('click', () => {
        const l = log[Number(row.dataset.logIdx)];
        if (!l) return;
        UI.modal.open({
          title: _esc(l.subject),
          body: `
            <div style="margin-bottom:var(--space-3);font-size:var(--text-sm);color:var(--c-text-muted)">
              <strong>An:</strong> ${_esc(l.recipient)} &nbsp;·&nbsp;
              <strong>Von:</strong> ${_esc(l.from_account)}@banyaro.app &nbsp;·&nbsp;
              ${(l.sent_at||'').slice(0,16).replace('T',' ')}
            </div>
            <pre style="white-space:pre-wrap;font-family:inherit;font-size:var(--text-sm);
                        background:var(--c-surface-2);border-radius:var(--radius-md);
                        padding:var(--space-3);max-height:60vh;overflow-y:auto;
                        color:var(--c-text)">${_esc(l.body || '(kein Text gespeichert)')}</pre>`,
          footer: `<button class="btn btn-secondary" onclick="UI.modal.close()">Schließen</button>`,
        });
      });
    });

    // Vorlage in Compose laden
    function _loadTplIntoCompose(id) {
      const tpl = templates.find(t => t.id === id);
      if (!tpl) return;
      el.querySelector('#adm-outreach-from').value    = tpl.from_account || 'partner';
      el.querySelector('#adm-outreach-subject').value = tpl.subject;
      el.querySelector('#adm-outreach-body').value    = tpl.body;
    }

    el.querySelectorAll('.adm-tpl-load').forEach(btn => {
      btn.addEventListener('click', () => _loadTplIntoCompose(Number(btn.dataset.id)));
    });

    // Vorlage löschen
    el.querySelectorAll('.adm-tpl-del').forEach(btn => {
      btn.addEventListener('click', async () => {
        if (!window.confirm('Vorlage löschen?')) return;
        await API.del(`/outreach/templates/${btn.dataset.id}`);
        await _renderOutreach(el);
      });
    });

    // Vorlage bearbeiten
    el.querySelectorAll('.adm-tpl-edit').forEach(btn => {
      btn.addEventListener('click', () => {
        const tpl = templates.find(t => t.id === Number(btn.dataset.id));
        if (tpl) _openTplModal(el, tpl);
      });
    });

    // Neue Vorlage
    el.querySelector('#adm-tpl-new')?.addEventListener('click', () => _openTplModal(el, null));

    // Senden
    el.querySelector('#adm-outreach-form')?.addEventListener('submit', async e => {
      e.preventDefault();
      const btn          = e.target.querySelector('[type="submit"]');
      const from_account = el.querySelector('#adm-outreach-from').value;
      const to           = (el.querySelector('#adm-outreach-to').value || '')
                             .split(',').map(s => s.trim()).filter(Boolean);
      const subject      = el.querySelector('#adm-outreach-subject').value.trim();
      const body         = el.querySelector('#adm-outreach-body').value.trim();

      if (!to.length) { UI.toast.warning('Bitte mindestens einen Empfänger eingeben.'); return; }
      if (!subject)   { UI.toast.warning('Betreff fehlt.'); return; }
      if (!body)      { UI.toast.warning('Text fehlt.'); return; }

      await UI.asyncButton(btn, async () => {
        const res = await API.post('/outreach/send', { to, subject, body, from_account });
        if (res.sent?.length)   UI.toast.success(`${res.sent.length} E-Mail(s) gesendet.`);
        if (res.failed?.length) UI.toast.error(`${res.failed.length} Fehler: ${res.failed.map(f => f.error).join(', ')}`);
        await _renderOutreach(el);
      });
    });
  }

  function _openTplModal(el, tpl) {
    const isNew = !tpl;
    const id    = `adm-tpl-modal-${Date.now()}`;
    UI.modal.open({
      title: isNew ? 'Neue Vorlage' : 'Vorlage bearbeiten',
      body: `
        <form id="${id}" style="display:flex;flex-direction:column;gap:var(--space-3)">
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)">
            <div>
              <label class="form-label" style="font-size:var(--text-xs)">Name (intern)</label>
              <input class="form-control" id="${id}-key" type="text" placeholder="z.B. willkommen_neu"
                     value="${_esc(tpl?.key || '')}" ${isNew ? '' : 'readonly'}>
            </div>
            <div>
              <label class="form-label" style="font-size:var(--text-xs)">Absender</label>
              <select id="${id}-from" class="form-control">
                <option value="partner" ${(tpl?.from_account||'partner')==='partner'?'selected':''}>partner@banyaro.app</option>
                <option value="support" ${tpl?.from_account==='support'?'selected':''}>support@banyaro.app</option>
              </select>
            </div>
          </div>
          <div>
            <label class="form-label" style="font-size:var(--text-xs)">Bezeichnung (sichtbar)</label>
            <input class="form-control" id="${id}-label" type="text" placeholder="z.B. Willkommensnachricht"
                   value="${_esc(tpl?.label || '')}">
          </div>
          <div>
            <label class="form-label" style="font-size:var(--text-xs)">Betreff</label>
            <input class="form-control" id="${id}-subject" type="text"
                   value="${_esc(tpl?.subject || '')}">
          </div>
          <div>
            <label class="form-label" style="font-size:var(--text-xs)">Text</label>
            <textarea id="${id}-body" class="form-control" rows="12"
                      style="font-family:monospace;font-size:var(--text-sm);resize:vertical">${_esc(tpl?.body || '')}</textarea>
          </div>
        </form>`,
      footer: `
        <button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
        <button class="btn btn-primary" form="${id}" type="submit">Speichern</button>`,
    });

    document.getElementById(id)?.addEventListener('submit', async e => {
      e.preventDefault();
      const payload = {
        label:        document.getElementById(`${id}-label`).value.trim(),
        subject:      document.getElementById(`${id}-subject`).value.trim(),
        body:         document.getElementById(`${id}-body`).value.trim(),
        from_account: document.getElementById(`${id}-from`).value,
      };
      if (!payload.label || !payload.subject || !payload.body) {
        UI.toast.warning('Alle Felder ausfüllen.'); return;
      }
      if (isNew) {
        const key = document.getElementById(`${id}-key`).value.trim();
        if (!key) { UI.toast.warning('Interner Name fehlt.'); return; }
        await API.post('/outreach/templates', { ...payload, key });
      } else {
        await API.put(`/outreach/templates/${tpl.id}`, payload);
      }
      UI.modal.close();
      await _renderOutreach(el);
    });
  }

  async function _renderAudit(el) {
    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-ghost btn-sm" id="adm-audit-refresh">
          ${UI.icon('arrows-clockwise')} Aktualisieren
        </button>
      </div>
      <div id="adm-audit-list">Lade…</div>
    `;
    el.querySelector('#adm-audit-refresh').addEventListener('click', () => _loadAudit(el.querySelector('#adm-audit-list')));
    await _loadAudit(el.querySelector('#adm-audit-list'));
  }

  async function _loadAudit(el) {
    el.innerHTML = `<div style="padding:var(--space-4);text-align:center;color:var(--c-text-muted)">Lade…</div>`;
    const rows = await API.get('/admin/audit?limit=50');
    if (!rows.length) {
      el.innerHTML = _emptyState('list-bullets', 'Keine Einträge', 'Noch keine Admin-Aktionen protokolliert.');
      return;
    }
    el.innerHTML = `
      <div class="card adm-table-card">
        <div class="adm-table-scroll">
          <table class="adm-table">
            <thead>
              <tr style="background:var(--c-surface-2);text-align:left">
                <th class="adm-th">Wann</th>
                <th class="adm-th">Admin</th>
                <th class="adm-th">Aktion</th>
                <th class="adm-th">Ziel</th>
              </tr>
            </thead>
            <tbody>
              ${rows.map((r, i) => `
                <tr style="${i % 2 === 1 ? 'background:var(--c-surface-2)' : ''}">
                  <td class="adm-td" style="color:var(--c-text-muted);white-space:nowrap;font-size:var(--text-xs)">
                    ${_formatDateTime(r.created_at)}
                  </td>
                  <td class="adm-td" style="color:var(--c-text);white-space:nowrap">
                    ${_esc(r.admin_name || '—')}
                  </td>
                  <td class="adm-td">
                    <span class="adm-badge-mono">${_esc(r.action)}</span>
                    ${r.detail ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${_esc(r.detail)}</div>` : ''}
                  </td>
                  <td class="adm-td" style="color:var(--c-text-secondary);font-size:var(--text-xs);white-space:nowrap">
                    ${_esc(r.target || '—')}
                  </td>
                </tr>
              `).join('')}
            </tbody>
          </table>
        </div>
      </div>
    `;
  }

  // ------------------------------------------------------------------
  // HELPERS
  // ------------------------------------------------------------------
  function _prompt(msg) {
    return new Promise(resolve => {
      UI.modal.open({
        title: 'Eingabe',
        body:  `
          <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-3)">${msg}</p>
          <input id="adm-prompt-input" type="text"
                 style="width:100%;box-sizing:border-box;padding:var(--space-2) var(--space-3);
                        border:1.5px solid var(--c-border);border-radius:var(--radius-md);
                        font-size:var(--text-sm);font-family:inherit;
                        background:var(--c-surface);color:var(--c-text)">
        `,
        footer: `
          <button class="btn btn-primary" id="adm-prompt-ok" form="">OK</button>
          <button class="btn btn-ghost"   id="adm-prompt-cancel" form="">Abbrechen</button>
        `,
      });
      document.getElementById('adm-prompt-ok')?.addEventListener('click', () => {
        const val = document.getElementById('adm-prompt-input')?.value || '';
        UI.modal.close();
        resolve(val);
      });
      document.getElementById('adm-prompt-cancel')?.addEventListener('click', () => {
        UI.modal.close();
        resolve(null);
      });
    });
  }

  function _emptyState(icon, title, text) {
    return `
      <div style="text-align:center;padding:var(--space-10) var(--space-4)">
        <svg class="ph-icon" style="width:40px;height:40px;color:var(--c-border);
             margin-bottom:var(--space-3)" aria-hidden="true">
          <use href="/icons/phosphor.svg#${icon}"></use>
        </svg>
        <p style="font-weight:var(--weight-semibold);color:var(--c-text);margin:0 0 var(--space-1)">${title}</p>
        ${text ? `<p style="font-size:var(--text-sm);color:var(--c-text-muted);margin:0">${text}</p>` : ''}
      </div>
    `;
  }

  function _esc(s) {
    if (!s) return '';
    return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
  }

  // ------------------------------------------------------------------
  // BEWERBUNGEN — Social-Media-Job
  // ------------------------------------------------------------------
  async function _renderBewerbungen(el) {
    let _statusFilter = 'pending';

    async function _load() {
      el.innerHTML = `
        <div style="display:flex;gap:var(--space-2);margin-bottom:var(--space-4);flex-wrap:wrap;align-items:center">
          ${['pending','reviewing','accepted','rejected','alle'].map(s => `
            <button class="btn btn-sm ${s===_statusFilter?'btn-primary':'btn-ghost'} adm-bew-filter" data-s="${s}">
              ${s==='pending'   ? `${UI.icon('clock')} Neu`
                : s==='reviewing' ? `${UI.icon('magnifying-glass')} In Prüfung`
                : s==='accepted'  ? `${UI.icon('check-circle')} Angenommen`
                : s==='rejected'  ? `${UI.icon('x')} Abgelehnt`
                : 'Alle'}
            </button>`).join('')}
        </div>
        <div id="adm-bew-list">${UI.skeleton(3)}</div>`;

      el.querySelectorAll('.adm-bew-filter').forEach(btn => {
        btn.addEventListener('click', () => {
          _statusFilter = btn.dataset.s;
          _load();
        });
      });

      try {
        const rows = await API.get(`/jobs/admin/applications?status=${_statusFilter}`);
        const list = el.querySelector('#adm-bew-list');
        if (!rows.length) {
          list.innerHTML = _emptyState('user-plus', 'Keine Bewerbungen', 'Noch keine Bewerbungen in diesem Status.');
          return;
        }
        list.innerHTML = rows.map(r => `
          <div class="card" style="margin-bottom:var(--space-3);padding:var(--space-4)" data-id="${r.id}">
            <div style="display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3)">
              <div style="flex:1;min-width:0">
                <div style="font-weight:700;font-size:var(--text-base)">${_esc(r.name)}
                  ${r.username ? `<span style="color:var(--c-text-muted);font-weight:400;font-size:var(--text-sm)">(@${_esc(r.username)})</span>` : ''}
                </div>
                <div style="color:var(--c-text-secondary);font-size:var(--text-sm);margin-top:2px">
                  ${_esc(r.email)} · @${_esc(r.social_handle||'—')}
                  ${r.dog_name ? ` · 🐕 ${_esc(r.dog_name)} (${_esc(r.dog_rasse||'')})` : ''}
                </div>
                <div style="color:var(--c-text-muted);font-size:var(--text-xs);margin-top:2px">
                  ${r.created_at?.slice(0,16).replace('T',' ')} · ${r.doc_count} Anhang/Anhänge
                </div>
                <div style="margin-top:var(--space-2);font-size:var(--text-sm);color:var(--c-text-secondary);
                            background:var(--c-surface-2);border-radius:var(--radius-md);padding:var(--space-2) var(--space-3)">
                  ${_esc((r.motivation||'').slice(0,200))}${(r.motivation||'').length>200?'…':''}
                </div>
              </div>
              <div style="display:flex;flex-direction:column;gap:var(--space-2);min-width:120px">
                <button class="btn btn-sm btn-primary adm-bew-view" data-id="${r.id}">Details</button>
                <select class="form-control adm-bew-status" data-id="${r.id}"
                        style="font-size:var(--text-xs);padding:var(--space-1) var(--space-2)">
                  <option value="pending"   ${r.status==='pending'  ?'selected':''}>⏳ Neu</option>
                  <option value="reviewing" ${r.status==='reviewing'?'selected':''}>🔍 Prüfung</option>
                  <option value="accepted"  ${r.status==='accepted' ?'selected':''}>✅ Angenommen</option>
                  <option value="rejected"  ${r.status==='rejected' ?'selected':''}>❌ Abgelehnt</option>
                </select>
              </div>
            </div>
          </div>`).join('');

        list.querySelectorAll('.adm-bew-status').forEach(sel => {
          sel.addEventListener('change', async () => {
            const id = sel.dataset.id;
            await API.patch(`/jobs/admin/applications/${id}`, { status: sel.value });
            UI.toast.success('Status aktualisiert.');
            setTimeout(_load, 500);
          });
        });

        list.querySelectorAll('.adm-bew-view').forEach(btn => {
          btn.addEventListener('click', async () => {
            const id = btn.dataset.id;
            const app = await API.get(`/jobs/admin/applications/${id}`);
            const docsHtml = app.docs?.length
              ? app.docs.map(d => `<a href="/api/jobs/admin/applications/${id}/docs/${d.id}"
                  target="_blank" style="display:block;color:var(--c-primary);font-size:var(--text-sm);margin:4px 0">
                  📎 ${_esc(d.filename)}</a>`).join('')
              : '<span style="color:var(--c-text-muted);font-size:var(--text-sm)">Keine Anhänge</span>';

            UI.modal.open({
              title: `Bewerbung — ${_esc(app.name)}`,
              body: `
                <div style="display:grid;gap:var(--space-3)">
                  <div><b>E-Mail:</b> ${_esc(app.email)}</div>
                  <div><b>Social:</b> @${_esc(app.social_handle||'—')}</div>
                  ${app.dog_name ? `<div><b>Hund:</b> ${_esc(app.dog_name)} (${_esc(app.dog_rasse||'')})</div>` : ''}
                  <div><b>Motivation:</b><br>
                    <div style="background:var(--c-surface-2);border-radius:var(--radius-md);padding:var(--space-3);
                                margin-top:var(--space-1);font-size:var(--text-sm);white-space:pre-wrap">${_esc(app.motivation)}</div>
                  </div>
                  <div><b>Anhänge:</b><br>${docsHtml}</div>
                  <div>
                    <b>Admin-Notiz:</b>
                    <textarea id="adm-bew-note" class="form-control" rows="2" style="margin-top:var(--space-1)"
                              placeholder="Interne Notiz / Nachricht an Bewerber">${_esc(app.admin_note||'')}</textarea>
                  </div>
                </div>`,
              footer: `
                <button class="btn btn-secondary" onclick="UI.modal.close()">Schließen</button>
                <button class="btn btn-primary" id="adm-bew-save-note">Notiz speichern</button>`,
            });
            document.getElementById('adm-bew-save-note')?.addEventListener('click', async () => {
              const note = document.getElementById('adm-bew-note')?.value || '';
              await API.patch(`/jobs/admin/applications/${id}`, { admin_note: note });
              UI.toast.success('Notiz gespeichert.');
              UI.modal.close();
            });
          });
        });
      } catch (e) {
        el.querySelector('#adm-bew-list').innerHTML = _emptyState('warning', 'Fehler', e.message);
      }
    }

    await _load();
  }

  // ------------------------------------------------------------------
  return { init, refresh, onDogChange };

})();
