const $ = (sel, root = document) => root.querySelector(sel);
const root = $('#app');

const TAB_GROUPS = [
  { label: 'محتوا', tabs: ['glance', 'radarFuture', 'factoryReports', 'media', 'events', 'banners'] },
  { label: 'کاربران', tabs: ['members', 'newsletter'] },
];
const TAB_LABELS = {
  glance: 'در یک نگاه', radarFuture: 'رادار آینده', factoryReports: 'ماهنامه کارخانه', media: 'ویدیوکست و پادکست',
  events: 'رویدادها', banners: 'بنرها',
  members: 'کاربران سایت', newsletter: 'خبرنامه',
};


const CATEGORIES = [
  'بازار جهانی', 'سیاست‌گذاری', 'انرژی و ESG', 'صادرات', 'تولید داخلی', 'ریسک و بحران',
  'رادار آینده', 'اخبار صنعت', 'گزارش کارخانه',
];
const TYPES = [
  { value: 'quarterly', label: 'فصلی' },
  { value: 'flash',     label: 'فلش' },
  { value: 'risk',      label: 'هشدار ریسک' },
  { value: 'free',      label: 'رایگان' },
  { value: 'special',   label: 'ویژه' },
  { value: 'video',     label: 'ویدیوکست' },
  { value: 'podcast',   label: 'پادکست' },
  { value: 'news',      label: 'خبر' },
  { value: 'radar',     label: 'رادار آینده' },
];

const CONTENT_TYPES = [
  { key: 'report',  label: 'گزارش تحلیلی', icon: '📊', desc: 'گزارش فصلی، فلش یا ویژه با تحلیل بازار', defaultType: 'quarterly',     defaultCategory: '' },
  { key: 'news',    label: 'خبر',           icon: '📰', desc: 'اخبار صنعت فولاد',                        defaultType: 'news',          defaultCategory: 'اخبار صنعت' },
  { key: 'video',   label: 'ویدیوکست',      icon: '🎬', desc: 'ویدیوی تحلیلی یا مصاحبه',               defaultType: 'video',         defaultCategory: '' },
  { key: 'podcast', label: 'پادکست',        icon: '🎙️', desc: 'اپیزود پادکست صوتی',                    defaultType: 'podcast',       defaultCategory: '' },
  { key: 'factory', label: 'گزارش کارخانه', icon: '🏭', desc: 'گزارش تولید و عملیات کارخانه',          defaultType: 'factoryReport', defaultCategory: 'گزارش کارخانه' },
  { key: 'radarFuture', label: 'رادار آینده', icon: '🔭', desc: 'مقالهٔ بلوکی (متن/عکس) برای ۵ زیرمنوی رادار آینده', defaultType: 'radarfuture', defaultCategory: '' },
];

// the 5 رادار آینده sub-sections (block-article categories)
const RADAR_FUTURE_CATEGORIES = [
  'پایداری و فولاد سبز',
  'ژئوپلیتیک و اقتصاد جهانی',
  'فناوری و نوآوری',
  'بازار و زنجیره فولاد',
];

function inferContentType(a) {
  if (!a) return 'report';
  if (a.type === 'video')   return 'video';
  if (a.type === 'podcast') return 'podcast';
  if (a.type === 'radarfuture') return 'radarFuture';
  if (a.type === 'factoryReport' || a.category === 'گزارش کارخانه') return 'factory';
  if (a.type === 'news')    return 'news';
  return 'report';
}

const EVENT_TYPES = [
  { value: 'conference',    label: 'کنگره' },
  { value: 'exhibition',    label: 'نمایشگاه' },
  { value: 'seminar',       label: 'سمینار' },
  { value: 'international', label: 'جهانی' },
];

const RADAR_CATEGORIES = [
  { value: 'market',    label: 'بازارهای جهانی و اقتصادِ کلان' },
  { value: 'tech',      label: 'نوآوری و فناوری‌هایِ تحول‌آفرین' },
  { value: 'commodity', label: 'مواد معدنیِ حیاتی و زنجیره‌ی تامین' },
  { value: 'geo',       label: 'ژئوپلیتیک و امنیتِ اقتصادی' },
  { value: 'energy',    label: 'تجارت و کسب‌وکارِ بین‌الملل' },
];

const SCROLL_DIRS = [
  { value: 'up',    label: 'از پایین' },
  { value: 'left',  label: 'از چپ' },
  { value: 'right', label: 'از راست' },
];

const INTEGRATION_ICONS = [
  { value: 'exchange',  label: 'صرافی' },
  { value: 'globe',     label: 'جهانی' },
  { value: 'chart',     label: 'نمودار' },
  { value: 'activity',  label: 'فعالیت' },
  { value: 'database',  label: 'پایگاه داده' },
  { value: 'newspaper', label: 'خبرگزاری' },
  { value: 'building',  label: 'سازمان' },
  { value: 'trending',  label: 'روند' },
  { value: 'coins',     label: 'کالا' },
];

const TREND_TYPES = [
  { value: 'up',   label: 'صعودی ↑' },
  { value: 'down', label: 'نزولی ↓' },
  { value: 'flat', label: 'ثابت →' },
];

const CHART_SERIES = [
  { value: 'history',    label: 'روند قیمت' },
  { value: 'export',     label: 'صادرات ماهانه' },
  { value: 'comparison', label: 'مقایسه جهانی' },
];

const VISION_ICONS = ['FlaskConical', 'Network', 'Leaf', 'Telescope', 'Sparkles'];

async function api(path, { method = 'GET', body, isForm = false } = {}) {
  const headers = {};
  if (body && !isForm) headers['Content-Type'] = 'application/json';
  const res = await fetch(path, {
    method,
    credentials: 'include',
    headers,
    body: isForm ? body : (body ? JSON.stringify(body) : undefined),
  });
  if (res.status === 401) {
    renderLogin('نیاز به ورود مجدد است');
    throw new Error('unauthorized');
  }
  if (!res.ok) {
    const text = await res.text();
    throw new Error(text || res.statusText);
  }
  if (res.status === 204) return null;
  return res.json();
}

function renderLogin(errorMsg = '') {
  root.innerHTML = `
    <div class="auth-wrap">
      <form class="card auth-card" id="loginForm">
        <h1>ورود به پنل مدیریت</h1>
        <p class="muted">اندیشکده فولاد</p>
        <label>نام کاربری
          <input name="username" autocomplete="username" required />
        </label>
        <label>رمز عبور
          <input name="password" type="password" autocomplete="current-password" required />
        </label>
        ${errorMsg ? `<div class="error">${escapeHtml(errorMsg)}</div>` : ''}
        <button type="submit">ورود</button>
      </form>
    </div>
  `;
  $('#loginForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    try {
      const data = await api('/api/auth/login', {
        method: 'POST',
        body: { username: fd.get('username'), password: fd.get('password') },
      });
      renderRadarList();
    } catch {
      renderLogin('نام کاربری یا رمز عبور اشتباه است');
    }
  });
}

function topbarHtml(active, primaryLabel) {
  const activeGroup = TAB_GROUPS.find(g => g.tabs.includes(active)) || TAB_GROUPS[0];
  const groupBtns = TAB_GROUPS.map(g => `
    <button class="group-btn${g === activeGroup ? ' group-active' : ''}" data-tab="${g.tabs[0]}">${g.label}</button>
  `).join('');
  const subTabs = activeGroup.tabs.map(t => `
    <button data-tab="${t}" class="${active === t ? 'tab-active' : ''}">${TAB_LABELS[t]}</button>
  `).join('');
  return `
    <header class="topbar">
      <div class="topbar-row">
        <div class="brand">پنل اندیشکده فولاد</div>
        <nav class="groups">${groupBtns}</nav>
        <div class="actions">
          <button id="newBtn" class="primary">${primaryLabel}</button>
          <button id="logoutBtn" class="ghost">خروج</button>
        </div>
      </div>
      <nav class="tabs">${subTabs}</nav>
    </header>
  `;
}
function wireTabs() {
  document.querySelectorAll('.tabs button, .groups button').forEach(btn => {
    btn.addEventListener('click', () => {
      const t = btn.dataset.tab;
      if (t === 'glance')           renderRadarList();
      else if (t === 'radarFuture') renderRadarFutureList();
      else if (t === 'factoryReports') renderFactoryReportsList();
      else if (t === 'media')       renderMediaList();
      else if (t === 'events')      renderEventsList();
      else if (t === 'banners')     renderBannersList();
      else if (t === 'members')     renderMembersList();
      else if (t === 'newsletter')  renderNewsletterList();
    });
  });
  $('#logoutBtn').addEventListener('click', async () => {
    await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }).catch(() => {});
    renderLogin();
  });
}

async function renderList() {
  root.innerHTML = `
    ${topbarHtml('articles', '+ مطلب جدید')}
    <main class="page">
      <h2>مطالب</h2>
      <div id="cat-bar" class="cat-bar">
        <button class="cat-btn active" data-cat="">همه</button>
        ${CATEGORIES.map(c => `<button class="cat-btn" data-cat="${escapeAttr(c)}">${escapeHtml(c)}</button>`).join('')}
      </div>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>
  `;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderEditor(null));

  let allItems = [];
  let activeCat = '';

  const safeCoverUrl = (u) => /^\/uploads\/[a-zA-Z0-9._-]+$/.test(String(u || '')) ? u : '';

  function renderItems() {
    const filtered = activeCat ? allItems.filter(a => a.category === activeCat) : allItems;
    if (!filtered.length) {
      $('#list').innerHTML = `<p class="muted">مطلبی در این دسته‌بندی یافت نشد.</p>`;
      return;
    }
    $('#list').innerHTML = filtered.map((a) => `
      <article class="row" data-id="${escapeAttr(a.id)}">
        <div class="row-cover" style="background-image:url('${escapeAttr(safeCoverUrl(a.coverImage))}')"></div>
        <div class="row-main">
          <div class="row-meta">
            ${a.featured ? '<span class="pill red">ویژه</span>' : ''}
            ${a.category ? `<span class="pill">${escapeHtml(a.category)}</span>` : ''}
            ${a.publishDate ? `<span class="muted">${escapeHtml(a.publishDate)}</span>` : ''}
          </div>
          <h3>${escapeHtml(a.title)}</h3>
          <p class="muted clamp-2">${escapeHtml(a.summary)}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>
    `).join('');
  }

  $('#cat-bar').addEventListener('click', (e) => {
    const btn = e.target.closest('.cat-btn');
    if (!btn) return;
    activeCat = btn.dataset.cat;
    document.querySelectorAll('.cat-btn').forEach(b => b.classList.toggle('active', b === btn));
    renderItems();
  });

  $('#list').addEventListener('click', async (e) => {
    const btn = e.target.closest('button[data-action]');
    if (!btn) return;
    const row = btn.closest('.row');
    const id = row.dataset.id;
    if (btn.dataset.action === 'edit') {
      const a = await api(`/api/articles/${id}`);
      renderEditor(a);
    } else if (btn.dataset.action === 'delete') {
      if (!confirm('این مطلب حذف شود؟')) return;
      await api(`/api/articles/${id}`, { method: 'DELETE' });
      renderList();
    }
  });

  try {
    allItems = await api('/api/articles?limit=500');
    if (!allItems.length) {
      $('#list').innerHTML = `<p class="muted">هنوز مطلبی ثبت نشده است.</p>`;
      return;
    }
    renderItems();
  } catch (err) {
    console.error(err);
    $('#list').innerHTML = `<p class="error">خطا در بارگذاری مطالب.</p>`;
  }
}

async function renderRadarFutureList() {
  root.innerHTML = `
    ${topbarHtml('radarFuture', '+ رادار آینده جدید')}
    <main class="page">
      <h2>رادار آینده</h2>
      <p class="muted" style="margin:-4px 0 12px">محتوای صفحات «رادار آینده» سایت (‎/radar/*‎) — مقالهٔ بلوکی به تفکیک ۵ زیرمنو.</p>
      <div id="cat-bar" class="cat-bar">
        <button class="cat-btn active" data-cat="">همه</button>
        ${RADAR_FUTURE_CATEGORIES.map(c => `<button class="cat-btn" data-cat="${escapeAttr(c)}">${escapeHtml(c)}</button>`).join('')}
      </div>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderEditor(null, { contentType: 'radarFuture', type: 'radarfuture', category: '' }));
  let allItems = [], activeCat = '';
  function renderItems() {
    const filtered = activeCat ? allItems.filter(a => a.category === activeCat) : allItems;
    if (!filtered.length) { $('#list').innerHTML = `<p class="muted">مطلبی در این بخش یافت نشد.</p>`; return; }
    $('#list').innerHTML = filtered.map(a => `
      <article class="row" data-id="${escapeAttr(a.id)}">
        <div class="row-cover" style="background-image:url('${escapeAttr(a.coverImage||'')}')"></div>
        <div class="row-main">
          <div class="row-meta">${a.category?`<span class="pill">${escapeHtml(a.category)}</span>`:''}${a.publishDate?`<span class="muted">${escapeHtml(a.publishDate)}</span>`:''}</div>
          <h3>${escapeHtml(a.title)}</h3>
          <p class="muted clamp-2">${escapeHtml(a.summary||'')}</p>
        </div>
        <div class="row-actions"><button data-action="edit">ویرایش</button><button data-action="delete" class="danger">حذف</button></div>
      </article>`).join('');
  }
  $('#cat-bar').addEventListener('click', e => { const b = e.target.closest('.cat-btn'); if (!b) return; activeCat = b.dataset.cat; document.querySelectorAll('.cat-btn').forEach(x => x.classList.toggle('active', x === b)); renderItems(); });
  $('#list').addEventListener('click', async e => {
    const btn = e.target.closest('button[data-action]'); if (!btn) return;
    const id = btn.closest('.row').dataset.id;
    if (btn.dataset.action === 'edit') renderEditor(await api(`/api/articles/${id}`));
    else if (btn.dataset.action === 'delete') { if (!confirm('این مطلب حذف شود؟')) return; await api(`/api/articles/${id}`, { method: 'DELETE' }); renderRadarFutureList(); }
  });
  try {
    const all = await api('/api/articles?limit=500');
    allItems = all.filter(a => a.type === 'radarfuture');
    if (!allItems.length) { $('#list').innerHTML = `<p class="muted">هنوز مطلبی ثبت نشده — با «+ رادار آینده جدید» شروع کن.</p>`; return; }
    renderItems();
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا در بارگذاری.</p>`; }
}

async function renderMediaList() {
  root.innerHTML = `
    ${topbarHtml('media', '+ ویدیوکست جدید')}
    <main class="page">
      <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap">
        <h2>ویدیوکست و پادکست</h2>
        <button id="newPod" class="primary">+ پادکست جدید</button>
      </div>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderEditor(null, { contentType: 'video', type: 'video', category: '' }));
  $('#newPod').addEventListener('click', () => renderEditor(null, { contentType: 'podcast', type: 'podcast', category: '' }));
  $('#list').addEventListener('click', async e => {
    const btn = e.target.closest('button[data-action]'); if (!btn) return;
    const id = btn.closest('.row').dataset.id;
    if (btn.dataset.action === 'edit') renderEditor(await api(`/api/articles/${id}`));
    else if (btn.dataset.action === 'delete') { if (!confirm('این مورد حذف شود؟')) return; await api(`/api/articles/${id}`, { method: 'DELETE' }); renderMediaList(); }
  });
  try {
    const all = await api('/api/articles?limit=500');
    const items = all.filter(a => a.type === 'video' || a.type === 'podcast');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز موردی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(a => `
      <article class="row" data-id="${escapeAttr(a.id)}">
        <div class="row-cover" style="background-image:url('${escapeAttr(a.coverImage||'')}')"></div>
        <div class="row-main">
          <div class="row-meta"><span class="pill">${a.type==='video'?'ویدیوکست':'پادکست'}</span>${a.publishDate?`<span class="muted">${escapeHtml(a.publishDate)}</span>`:''}</div>
          <h3>${escapeHtml(a.title)}</h3>
          <p class="muted clamp-2">${escapeHtml(a.summary||'')}</p>
        </div>
        <div class="row-actions"><button data-action="edit">ویرایش</button><button data-action="delete" class="danger">حذف</button></div>
      </article>`).join('');
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا در بارگذاری.</p>`; }
}

function renderTypeSelector() {
  root.innerHTML = `
    <header class="topbar">
      <div class="topbar-row">
        <div class="brand">مطلب جدید</div>
        <nav class="groups"></nav>
        <div class="actions">
          <button id="backBtn" class="ghost">← بازگشت</button>
        </div>
      </div>
      <div class="tabs"></div>
    </header>
    <main class="page">
      <h2>چه نوع محتوایی می‌خواهید منتشر کنید؟</h2>
      <div class="type-grid">
        ${CONTENT_TYPES.map(ct => `
          <button class="type-card" data-ctype="${ct.key}">
            <span class="type-icon">${ct.icon}</span>
            <strong>${ct.label}</strong>
            <span class="type-desc">${ct.desc}</span>
          </button>
        `).join('')}
      </div>
    </main>
  `;
  $('#backBtn').addEventListener('click', () => renderList());
  document.querySelectorAll('.type-card').forEach(btn => {
    btn.addEventListener('click', () => {
      const ct = CONTENT_TYPES.find(c => c.key === btn.dataset.ctype);
      if (ct.externalTab === 'radar') { renderRadarList(); return; }
      renderEditor(null, { contentType: ct.key, type: ct.defaultType, category: ct.defaultCategory });
    });
  });
}

function renderEditor(article, draft = {}) {
  if (!article && !draft.contentType) {
    renderTypeSelector();
    return;
  }

  const contentType = draft.contentType || inferContentType(article);
  const ctInfo = CONTENT_TYPES.find(c => c.key === contentType) || CONTENT_TYPES[0];
  const isEdit = !!article;
  const a = article || {
    title: '', category: draft.category || ctInfo.defaultCategory,
    type: draft.type || ctInfo.defaultType,
    author: '', authorRole: '', authorInitial: '',
    publishDate: '', pages: 0, price: 0, isFree: true,
    summary: '', body: '', coverImage: '', tags: [], featured: false,
  };

  // content blocks (interleaved text + chart/image) and citation sources
  let blocks = (Array.isArray(a.blocks) && a.blocks.length)
    ? a.blocks.map(b => ({ ...b }))
    : (a.body ? [{ type: 'text', value: a.body }] : []);
  let sources = Array.isArray(a.sources) ? a.sources.map(s => ({ ...s })) : [];

  const REPORT_TYPES = TYPES.filter(t => ['quarterly','flash','special','risk','free'].includes(t.value));
  const isRadarFuture = contentType === 'radarFuture';
  const hasCover      = ['report','news','video','podcast','factory','radarFuture'].includes(contentType);
  const hasCategory   = ['report','news','radarFuture'].includes(contentType);
  const hasAuthor     = ['report','video','podcast'].includes(contentType);
  const hasPages      = ['report','factory'].includes(contentType);
  const hasPrice      = contentType === 'report';
  const hasBody       = ['report','news','factory','radarFuture'].includes(contentType);
  const hasMediaLink  = ['video','podcast'].includes(contentType);
  const hasReportType = contentType === 'report';
  const categoryOptions = isRadarFuture ? RADAR_FUTURE_CATEGORIES : CATEGORIES;

  root.innerHTML = `
    <header class="topbar">
      <div class="topbar-row">
        <div class="brand">${ctInfo.icon} ${isEdit ? 'ویرایش' : 'ایجاد'} — ${ctInfo.label}</div>
        <nav class="groups"></nav>
        <div class="actions">
          <button id="backBtn" class="ghost">← بازگشت</button>
        </div>
      </div>
      <div class="tabs"></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">

        <div class="col span-2">
          <label>عنوان
            <input name="title" value="${escapeAttr(a.title)}" required placeholder="عنوان ${ctInfo.label}…" />
          </label>
        </div>

        ${hasCategory ? `
        <label>${isRadarFuture ? 'بخش رادار آینده' : 'دسته‌بندی'}
          <select name="category">
            <option value="">انتخاب کنید…</option>
            ${categoryOptions.map(c => `<option value="${escapeAttr(c)}" ${c===a.category?'selected':''}>${escapeHtml(c)}</option>`).join('')}
          </select>
        </label>` : `<input type="hidden" name="category" value="${escapeAttr(a.category)}" />`}

        ${hasReportType ? `
        <label>نوع گزارش
          <select name="type">
            ${REPORT_TYPES.map(t => `<option value="${t.value}" ${t.value===a.type?'selected':''}>${t.label}</option>`).join('')}
          </select>
        </label>` : `<input type="hidden" name="type" value="${escapeAttr(a.type)}" />`}

        <label>تاریخ انتشار (مثلاً «بهمن ۱۴۰۳»)
          <input name="publishDate" value="${escapeAttr(a.publishDate)}" placeholder="بهمن ۱۴۰۳" />
        </label>

        ${hasAuthor ? `
        <label>نویسنده / مجری
          <input name="author" value="${escapeAttr(a.author)}" />
        </label>
        <label>سمت
          <input name="authorRole" value="${escapeAttr(a.authorRole)}" />
        </label>
        <label>حرف آواتار
          <input name="authorInitial" maxlength="2" value="${escapeAttr(a.authorInitial)}" />
        </label>` : `<input type="hidden" name="author" /><input type="hidden" name="authorRole" /><input type="hidden" name="authorInitial" />`}

        ${hasPages ? `
        <label>تعداد صفحات
          <input name="pages" type="number" min="0" value="${a.pages || 0}" />
        </label>` : `<input type="hidden" name="pages" value="0" />`}

        ${hasPrice ? `
        <label>قیمت (ریال)
          <input name="price" type="number" min="0" value="${a.price || 0}" />
        </label>
        <label class="checkbox" style="align-self:flex-end;padding-bottom:10px">
          <input type="checkbox" name="isFree" ${a.isFree?'checked':''} />
          <span>رایگان</span>
        </label>` : `<input type="hidden" name="price" value="0" /><input type="hidden" name="isFree" value="true" />`}

        ${hasCover ? `
        <div class="col span-2">
          <label>تصویر شاخص
            <div class="cover-row">
              <input type="file" id="coverFile" accept="image/*" />
              <input type="hidden" name="coverImage" value="${escapeAttr(a.coverImage)}" />
              <img id="coverPreview" alt="" src="${escapeAttr(a.coverImage)}" style="${a.coverImage?'':'display:none'}" />
            </div>
          </label>
        </div>` : `<input type="hidden" name="coverImage" value="" />`}

        <div class="col span-2">
          <label>${contentType==='radar'?'توضیح سیگنال':'خلاصه'}
            <textarea name="summary" rows="3">${escapeHtml(a.summary)}</textarea>
          </label>
        </div>

        ${hasBody ? `
        <div class="col span-2">
          <label style="display:block;margin-bottom:6px">متن کامل (متن + نمودار / تصویر، به ترتیب دلخواه)</label>
          <div id="blocksEditor" class="blocks-editor"></div>
          <div style="display:flex;gap:8px;margin-top:10px">
            <button type="button" id="addTextBlock" class="ghost">➕ پاراگراف متن</button>
            <button type="button" id="addImageBlock" class="ghost">🖼 تصویر / نمودار</button>
          </div>
        </div>
        <div class="col span-2">
          <label style="display:block;margin-bottom:6px">منابع و ارجاعات</label>
          <div id="sourcesEditor"></div>
          <button type="button" id="addSource" class="ghost" style="margin-top:8px">➕ افزودن منبع</button>
        </div>` : ``}

        ${hasMediaLink ? `
        <div class="col span-2">
          <label>لینک ویدیو / فایل صوتی
            <input name="body" id="mediaUrl" value="${escapeAttr(a.body)}" placeholder="https://… یا فایل آپلود کن" />
          </label>
          <div class="cover-row" style="margin-top:8px">
            <input type="file" id="mediaFile" accept="video/*,audio/*" />
            <span id="mediaStatus" class="muted" style="font-size:12px"></span>
          </div>
        </div>` : (hasBody ? `` : `<input type="hidden" name="body" value="" />`)}

        <div class="col span-2">
          <label>برچسب‌ها (با ویرگول جدا کنید)
            <input name="tags" value="${escapeAttr((a.tags||[]).join('، '))}" placeholder="فولاد، بازار جهانی، …" />
          </label>
        </div>

        <label class="checkbox">
          <input type="checkbox" name="featured" ${a.featured?'checked':''} />
          <span>مطلب ویژه (نمایش برجسته)</span>
        </label>

        <div class="col span-2 row-end">
          <button type="submit" class="primary">${isEdit ? 'ذخیره تغییرات' : `انتشار ${ctInfo.label}`}</button>
          ${!isEdit ? `<button type="button" id="changeTypeBtn" class="ghost">← تغییر نوع محتوا</button>` : ''}
        </div>
      </form>
    </main>
  `;

  const backToList = () => {
    if (contentType === 'radarFuture') return renderRadarFutureList();
    if (contentType === 'video' || contentType === 'podcast') return renderMediaList();
    return renderRadarFutureList();
  };
  $('#backBtn').addEventListener('click', backToList);
  document.getElementById('changeTypeBtn')?.addEventListener('click', () => renderTypeSelector());

  const coverFile = document.getElementById('coverFile');
  if (coverFile) {
    coverFile.addEventListener('change', async (e) => {
      const file = e.target.files?.[0];
      if (!file) return;
      const fd = new FormData();
      fd.append('file', file);
      try {
        const data = await api('/api/uploads', { method: 'POST', body: fd, isForm: true });
        const url = data.url;
        const input = $('input[name="coverImage"]');
        if (input) input.value = url;
        const prev = document.getElementById('coverPreview');
        if (prev) { prev.src = url; prev.style.display = ''; }
      } catch (err) { alert('آپلود ناموفق بود: ' + err.message); }
    });
  }

  // video / podcast media file → object storage (fills the media URL field)
  const mediaFile = document.getElementById('mediaFile');
  if (mediaFile) {
    mediaFile.addEventListener('change', async (e) => {
      const file = e.target.files?.[0];
      if (!file) return;
      const status = document.getElementById('mediaStatus');
      if (status) status.textContent = 'در حال آپلود فایل… (بسته به حجم چند لحظه طول می‌کشد)';
      const fd = new FormData();
      fd.append('file', file);
      try {
        const { url } = await api('/api/uploads/raw', { method: 'POST', body: fd, isForm: true });
        document.getElementById('mediaUrl').value = url;
        if (status) status.textContent = '✓ آپلود شد و در آبجکت استوریج ذخیره شد';
      } catch (err) {
        if (status) status.textContent = '';
        alert('آپلود فایل ناموفق بود: ' + err.message);
      }
    });
  }

  // ── content blocks (text + chart/image, reorderable) ──────────────────
  function renderBlocks() {
    const el = document.getElementById('blocksEditor');
    if (!el) return;
    if (!blocks.length) {
      el.innerHTML = `<div class="muted" style="padding:10px 0">هنوز محتوایی اضافه نشده — یک پاراگراف یا تصویر/نمودار اضافه کنید.</div>`;
      return;
    }
    el.innerHTML = blocks.map((b, i) => {
      const ctrls = `<div style="position:absolute;top:6px;left:6px;display:flex;gap:4px">
        <button type="button" data-act="up" data-i="${i}" class="ghost" style="padding:2px 8px" title="بالا">↑</button>
        <button type="button" data-act="down" data-i="${i}" class="ghost" style="padding:2px 8px" title="پایین">↓</button>
        <button type="button" data-act="del" data-i="${i}" class="ghost" style="padding:2px 8px" title="حذف">✕</button>
      </div>`;
      if (b.type === 'image') {
        return `<div style="position:relative;border:1px solid #e2e8f0;border-radius:8px;padding:12px;margin-bottom:10px;background:#fafafa">
          ${ctrls}
          <div style="display:flex;align-items:center;gap:12px;margin:6px 0 8px">
            ${b.url ? `<img src="${escapeAttr(b.url)}" style="max-width:220px;max-height:150px;border-radius:6px;border:1px solid #e2e8f0" />` : `<div style="width:140px;height:90px;border:1px dashed #cbd5e1;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#94a3b8;font-size:12px">تصویر / نمودار</div>`}
            <input type="file" accept="image/*" data-imgfile="${i}" />
          </div>
          <input type="text" data-cap="${i}" value="${escapeAttr(b.caption || '')}" placeholder="توضیح تصویر / نمودار (اختیاری)" style="width:100%" />
        </div>`;
      }
      return `<div style="position:relative;border:1px solid #e2e8f0;border-radius:8px;padding:12px;margin-bottom:10px">
        ${ctrls}
        <textarea data-txt="${i}" rows="5" placeholder="متن پاراگراف…" style="width:100%;margin-top:18px">${escapeHtml(b.value || '')}</textarea>
      </div>`;
    }).join('');
    el.querySelectorAll('[data-txt]').forEach(t => t.addEventListener('input', e => { blocks[+e.target.dataset.txt].value = e.target.value; }));
    el.querySelectorAll('[data-cap]').forEach(t => t.addEventListener('input', e => { blocks[+e.target.dataset.cap].caption = e.target.value; }));
    el.querySelectorAll('[data-imgfile]').forEach(f => f.addEventListener('change', async e => {
      const file = e.target.files?.[0]; if (!file) return;
      const i = +e.target.dataset.imgfile;
      const fd2 = new FormData(); fd2.append('file', file);
      try { const { url } = await api('/api/uploads', { method: 'POST', body: fd2, isForm: true }); blocks[i].url = url; renderBlocks(); }
      catch (err) { alert('آپلود ناموفق بود: ' + err.message); }
    }));
    el.querySelectorAll('button[data-act]').forEach(btn => btn.addEventListener('click', e => {
      const i = +e.currentTarget.dataset.i, act = e.currentTarget.dataset.act;
      if (act === 'del') blocks.splice(i, 1);
      else if (act === 'up' && i > 0) { [blocks[i - 1], blocks[i]] = [blocks[i], blocks[i - 1]]; }
      else if (act === 'down' && i < blocks.length - 1) { [blocks[i + 1], blocks[i]] = [blocks[i], blocks[i + 1]]; }
      renderBlocks();
    }));
  }
  document.getElementById('addTextBlock')?.addEventListener('click', () => { blocks.push({ type: 'text', value: '' }); renderBlocks(); });
  document.getElementById('addImageBlock')?.addEventListener('click', () => { blocks.push({ type: 'image', url: '', caption: '' }); renderBlocks(); });
  renderBlocks();

  // ── sources / citations ───────────────────────────────────────────────
  function renderSources() {
    const el = document.getElementById('sourcesEditor');
    if (!el) return;
    el.innerHTML = sources.length ? sources.map((s, i) => `
      <div style="display:flex;gap:8px;margin-bottom:6px">
        <input type="text" data-stitle="${i}" value="${escapeAttr(s.title || '')}" placeholder="عنوان منبع" style="flex:1" />
        <input type="text" data-surl="${i}" value="${escapeAttr(s.url || '')}" placeholder="https://… (اختیاری)" style="flex:1" dir="ltr" />
        <button type="button" data-sdel="${i}" class="ghost" style="padding:2px 10px">✕</button>
      </div>`).join('') : `<div class="muted" style="padding:6px 0">منبعی اضافه نشده.</div>`;
    el.querySelectorAll('[data-stitle]').forEach(t => t.addEventListener('input', e => { sources[+e.target.dataset.stitle].title = e.target.value; }));
    el.querySelectorAll('[data-surl]').forEach(t => t.addEventListener('input', e => { sources[+e.target.dataset.surl].url = e.target.value; }));
    el.querySelectorAll('[data-sdel]').forEach(b => b.addEventListener('click', e => { sources.splice(+e.currentTarget.dataset.sdel, 1); renderSources(); }));
  }
  document.getElementById('addSource')?.addEventListener('click', () => { sources.push({ title: '', url: '' }); renderSources(); });
  renderSources();

  $('#editorForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const tagsRaw = String(fd.get('tags') || '').split(/[,،]/).map(s => s.trim()).filter(Boolean);
    const isFreeVal = fd.get('isFree');
    const payload = {
      title:        fd.get('title'),
      category:     fd.get('category') || null,
      type:         fd.get('type') || null,
      author:       fd.get('author') || null,
      authorRole:   fd.get('authorRole') || null,
      authorInitial:fd.get('authorInitial') || null,
      publishDate:  fd.get('publishDate') || null,
      pages:        Number(fd.get('pages') || 0),
      price:        Number(fd.get('price') || 0),
      isFree:       isFreeVal === 'on' || isFreeVal === 'true',
      featured:     fd.get('featured') === 'on',
      summary:      fd.get('summary') || null,
      body:         hasBody
        ? blocks.filter(b => b.type === 'text' && b.value && b.value.trim()).map(b => b.value.trim()).join('\n\n')
        : (fd.get('body') || null),
      coverImage:   fd.get('coverImage') || null,
      blocks:       hasBody ? blocks.filter(b => (b.type === 'text' && b.value && b.value.trim()) || (b.type === 'image' && b.url)) : [],
      sources:      sources.filter(s => (s.title && s.title.trim()) || (s.url && s.url.trim())),
      tags: tagsRaw,
    };
    try {
      if (isEdit) {
        await api(`/api/articles/${article.id}`, { method: 'PUT', body: payload });
      } else {
        await api('/api/articles', { method: 'POST', body: payload });
      }
      backToList();
    } catch (err) { alert('ذخیره ناموفق بود: ' + err.message); }
  });
}

function escapeAttr(s) {
  return String(s ?? '').replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
}
function escapeHtml(s) {
  return String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

const RISK_LEVELS = [
  { value: 'critical',    label: 'بحرانی' },
  { value: 'high',        label: 'بالا' },
  { value: 'medium',      label: 'متوسط' },
  { value: 'low',         label: 'پایین' },
  { value: 'opportunity', label: 'فرصت' },
];

async function renderRisksList() {
  root.innerHTML = `
    ${topbarHtml('risks', '+ سیگنال جدید')}
    <main class="page">
      <h2>سیگنال‌های ریسک</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>
  `;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderRiskEditor(null));

  try {
    const items = await api('/api/risks?limit=200');
    if (!items.length) {
      $('#list').innerHTML = `<p class="muted">هنوز سیگنالی ثبت نشده است.</p>`;
      return;
    }
    const SAFE_LEVELS = new Set(['critical', 'high', 'medium', 'low', 'opportunity']);
    const labelOf = (lvl) => (RISK_LEVELS.find(r => r.value === lvl)?.label) || escapeHtml(lvl);
    $('#list').innerHTML = items.map(r => `
      <article class="row risk-row" data-id="${escapeAttr(r.id)}">
        <div class="row-main">
          <div class="row-meta">
            <span class="pill level-${SAFE_LEVELS.has(r.level) ? r.level : 'low'}">${labelOf(r.level)}</span>
            <strong>${escapeHtml(r.name)}</strong>
            ${r.date ? `<span class="muted">${escapeHtml(r.date)}</span>` : ''}
          </div>
          <p class="muted clamp-2">${escapeHtml(r.quote)}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>
    `).join('');

    $('#list').addEventListener('click', async (e) => {
      const btn = e.target.closest('button[data-action]');
      if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') {
        const r = await api(`/api/risks/${id}`);
        renderRiskEditor(r);
      } else if (btn.dataset.action === 'delete') {
        if (!confirm('این سیگنال حذف شود؟')) return;
        await api(`/api/risks/${id}`, { method: 'DELETE' });
        renderRisksList();
      }
    });
  } catch (err) {
    console.error(err);
    $('#list').innerHTML = `<p class="error">خطا در بارگذاری سیگنال‌ها.</p>`;
  }
}

function renderRiskEditor(risk) {
  const r = risk || { quote: '', name: '', date: '', level: 'high', sortOrder: 0 };
  const isEdit = !!risk;

  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش سیگنال ریسک' : 'سیگنال ریسک جدید'}</div>
      <div class="actions">
        <button id="backBtn" class="ghost">← بازگشت</button>
      </div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <div class="col span-2">
          <label>عنوان / منبع
            <input name="name" value="${escapeAttr(r.name)}" required />
          </label>
        </div>
        <label>سطح
          <select name="level">
            ${RISK_LEVELS.map(l => `<option value="${l.value}" ${l.value===r.level?'selected':''}>${l.label}</option>`).join('')}
          </select>
        </label>
        <label>تاریخ / افق (شمسی)
          <input name="date" value="${escapeAttr(r.date)}" />
        </label>
        <label>ترتیب نمایش (عدد کوچک‌تر اول)
          <input name="sortOrder" type="number" value="${r.sortOrder || 0}" />
        </label>
        <div class="col span-2">
          <label>متن سیگنال
            <textarea name="quote" rows="6" required>${escapeHtml(r.quote)}</textarea>
          </label>
        </div>
        <div class="col span-2 row-end">
          <button type="submit" class="primary">${isEdit ? 'ذخیره تغییرات' : 'ایجاد'}</button>
        </div>
      </form>
    </main>
  `;

  $('#backBtn').addEventListener('click', () => renderRisksList());

  $('#editorForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const payload = {
      name: fd.get('name'),
      quote: fd.get('quote'),
      date: fd.get('date') || null,
      level: fd.get('level'),
      sortOrder: Number(fd.get('sortOrder') || 0),
    };
    try {
      if (isEdit) await api(`/api/risks/${risk.id}`, { method: 'PUT', body: payload });
      else await api('/api/risks', { method: 'POST', body: payload });
      renderRisksList();
    } catch (err) {
      alert('ذخیره ناموفق بود: ' + err.message);
    }
  });
}

// ---------- users ----------
async function renderUsersList() {
  root.innerHTML = `
    ${topbarHtml('users', '+ کاربر جدید')}
    <main class="page">
      <h2>کاربران پنل</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>
  `;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderUserEditor(null));

  try {
    const items = await api('/api/users');
    if (!items.length) {
      $('#list').innerHTML = `<p class="muted">هنوز کاربری ثبت نشده است.</p>`;
      return;
    }
    $('#list').innerHTML = items.map(u => `
      <article class="row" data-id="${escapeAttr(u.id)}" data-username="${escapeAttr(u.username)}">
        <div class="row-main">
          <div class="row-meta">
            <strong>${escapeHtml(u.username)}</strong>
            ${u.createdAt ? `<span class="muted">عضویت: ${escapeHtml(u.createdAt)}</span>` : ''}
          </div>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>
    `).join('');

    $('#list').addEventListener('click', async (e) => {
      const btn = e.target.closest('button[data-action]');
      if (!btn) return;
      const row = btn.closest('.row');
      const id = row.dataset.id;
      if (btn.dataset.action === 'edit') {
        renderUserEditor({ id, username: row.dataset.username });
      } else if (btn.dataset.action === 'delete') {
        if (!confirm('این کاربر حذف شود؟')) return;
        try {
          await api(`/api/users/${id}`, { method: 'DELETE' });
          renderUsersList();
        } catch (err) {
          alert('حذف ناموفق بود: ' + friendlyUserError(err.message));
        }
      }
    });
  } catch (err) {
    console.error(err);
    $('#list').innerHTML = `<p class="error">خطا در بارگذاری کاربران.</p>`;
  }
}

function renderUserEditor(user) {
  const u = user || { username: '' };
  const isEdit = !!user;

  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش کاربر' : 'کاربر جدید'}</div>
      <div class="actions">
        <button id="backBtn" class="ghost">← بازگشت</button>
      </div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <div class="col span-2">
          <label>نام کاربری
            <input name="username" value="${escapeAttr(u.username)}" autocomplete="off" required />
          </label>
        </div>
        <div class="col span-2">
          <label>رمز عبور ${isEdit ? '(برای تغییر پر کنید، خالی = بدون تغییر)' : '(حداقل ۸ کاراکتر)'}
            <input name="password" type="password" autocomplete="new-password" ${isEdit ? '' : 'required'} />
          </label>
        </div>
        <div class="col span-2 row-end">
          <button type="submit" class="primary">${isEdit ? 'ذخیره تغییرات' : 'ایجاد کاربر'}</button>
        </div>
      </form>
    </main>
  `;

  $('#backBtn').addEventListener('click', () => renderUsersList());

  $('#editorForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const username = String(fd.get('username') || '').trim();
    const password = String(fd.get('password') || '');
    const payload = { username };
    if (password) payload.password = password;
    try {
      if (isEdit) await api(`/api/users/${user.id}`, { method: 'PUT', body: payload });
      else await api('/api/users', { method: 'POST', body: { username, password } });
      renderUsersList();
    } catch (err) {
      alert('ذخیره ناموفق بود: ' + friendlyUserError(err.message));
    }
  });
}

function friendlyUserError(msg) {
  const m = String(msg || '');
  if (m.includes('username_taken')) return 'این نام کاربری قبلاً ثبت شده است.';
  if (m.includes('username_too_short')) return 'نام کاربری باید حداقل ۳ کاراکتر باشد.';
  if (m.includes('password_too_short')) return 'رمز عبور باید حداقل ۸ کاراکتر باشد.';
  if (m.includes('cannot_delete_self')) return 'نمی‌توانید حساب خودتان را حذف کنید.';
  if (m.includes('cannot_delete_last_user')) return 'آخرین کاربر را نمی‌توان حذف کرد.';
  return m;
}

// ═══════════════════════════════════════════════
//  SITE MEMBERS (phone/OTP users)
// ═══════════════════════════════════════════════
function fmtDateTime(ts) {
  if (!ts) return '—';
  // pg returns timestamptz as "2026-06-27 08:01:07.749392+00" — space separator,
  // microseconds, and a colon-less "+00" offset that Date can't parse. Normalize.
  const iso = String(ts).replace(' ', 'T')
    .replace(/(\.\d{3})\d+/, '$1')                       // trim micro→milliseconds
    .replace(/([+-]\d{2})(\d{2})?$/, (_, h, m) => `${h}:${m || '00'}`); // +00 → +00:00
  const d = new Date(iso);
  if (isNaN(d)) return escapeHtml(String(ts));
  try {
    return new Intl.DateTimeFormat('fa-IR', {
      dateStyle: 'medium', timeStyle: 'short', calendar: 'persian',
    }).format(d);
  } catch { return d.toISOString(); }
}

async function renderMembersList() {
  root.innerHTML = `
    ${topbarHtml('members', '↻ بروزرسانی')}
    <main class="page">
      <h2>کاربران سایت</h2>
      <p class="muted" style="margin:-4px 0 12px">کاربران ثبت‌نامی سایت (موبایل/کد یکبارمصرف). آخرین ورود، شماره تماس، مسدودسازی و حذف.</p>
      <input id="memberSearch" placeholder="جستجو بر اساس نام، ایمیل یا شماره…" style="width:100%;max-width:420px;margin-bottom:14px;padding:9px 12px;border:1px solid #d6d6d6;border-radius:8px" />
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>
  `;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderMembersList());

  let all = [];
  function paint(items) {
    if (!items.length) { $('#list').innerHTML = `<p class="muted">کاربری یافت نشد.</p>`; return; }
    $('#list').innerHTML = items.map(m => `
      <article class="row" data-id="${escapeAttr(m.id)}">
        <div class="row-main">
          <div class="row-meta">
            <strong>${escapeHtml(m.name || 'بی‌نام')}</strong>
            ${m.isActive ? '' : '<span class="pill red">مسدود</span>'}
            ${m.phone ? `<span class="muted" style="direction:ltr">${escapeHtml(m.phone)}</span>` : '<span class="muted">بدون شماره</span>'}
          </div>
          <p class="muted clamp-2">آخرین ورود: ${fmtDateTime(m.lastLogin)} · عضویت: ${fmtDateTime(m.createdAt)}${m.purchases ? ` · ${m.purchases} خرید` : ''}</p>
        </div>
        <div class="row-actions">
          <button data-action="view">جزئیات</button>
          <button data-action="toggle">${m.isActive ? 'مسدود کردن' : 'رفع مسدودی'}</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>
    `).join('');
  }

  $('#list').addEventListener('click', async (e) => {
    const btn = e.target.closest('button[data-action]');
    if (!btn) return;
    const id = btn.closest('.row').dataset.id;
    const m = all.find(x => String(x.id) === String(id));
    if (btn.dataset.action === 'view') {
      renderMemberDetail(id);
    } else if (btn.dataset.action === 'toggle') {
      try {
        await api(`/api/members/${id}`, { method: 'PATCH', body: { isActive: !m.isActive } });
        renderMembersList();
      } catch (err) { alert('عملیات ناموفق بود: ' + err.message); }
    } else if (btn.dataset.action === 'delete') {
      if (!confirm('این کاربر برای همیشه حذف شود؟')) return;
      try {
        await api(`/api/members/${id}`, { method: 'DELETE' });
        renderMembersList();
      } catch (err) {
        alert('حذف ناموفق بود' + (String(err.message).includes('forbidden') ? ' (فقط مالک پنل می‌تواند حذف کند)' : ': ' + err.message));
      }
    }
  });

  $('#memberSearch').addEventListener('input', (e) => {
    const q = e.target.value.trim().toLowerCase();
    paint(!q ? all : all.filter(m =>
      (m.name || '').toLowerCase().includes(q) ||
      (m.email || '').toLowerCase().includes(q) ||
      (m.phone || '').includes(q)));
  });

  try {
    all = await api('/api/members');
    paint(all);
  } catch (err) {
    console.error(err);
    $('#list').innerHTML = `<p class="error">خطا در بارگذاری کاربران.</p>`;
  }
}

async function renderMemberDetail(id) {
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">جزئیات کاربر</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page"><div id="detail"><p class="muted">در حال بارگذاری…</p></div></main>
  `;
  $('#backBtn').addEventListener('click', () => renderMembersList());
  try {
    const m = await api(`/api/members/${id}`);
    const field = (label, val, ltr) => `
      <div style="display:flex;gap:8px;padding:10px 0;border-bottom:1px solid #eee">
        <span class="muted" style="min-width:120px">${label}</span>
        <strong${ltr ? ' style="direction:ltr"' : ''}>${val}</strong>
      </div>`;
    const buys = m.purchases?.length
      ? m.purchases.map(p => `<li>${escapeHtml(p.title || p.articleId)} — ${fmtDateTime(p.purchasedAt)}${p.amount ? ` (${p.amount.toLocaleString('fa-IR')} تومان)` : ''}</li>`).join('')
      : '<li class="muted">خریدی ثبت نشده</li>';
    $('#detail').innerHTML = `
      <div class="card" style="max-width:560px;padding:20px 24px">
        <h2 style="margin:0 0 6px">${escapeHtml(m.name || 'بی‌نام')} ${m.isActive ? '' : '<span class="pill red">مسدود</span>'}</h2>
        ${field('شماره موبایل:', m.phone ? escapeHtml(m.phone) : '—', true)}
        ${field('ایمیل:', m.email ? escapeHtml(m.email) : '—', true)}
        ${field('آخرین ورود:', fmtDateTime(m.lastLogin))}
        ${field('تاریخ عضویت:', fmtDateTime(m.createdAt))}
        ${field('وضعیت:', m.isActive ? 'فعال' : 'مسدود')}
        <h3 style="margin:18px 0 6px">خریدها (${m.purchases?.length || 0})</h3>
        <ul style="margin:0;padding-inline-start:18px">${buys}</ul>
        <h3 style="margin:18px 0 6px">فعالیت اخیر</h3>
        <div id="activity"><p class="muted">در حال بارگذاری…</p></div>
        <div style="display:flex;gap:10px;margin-top:20px">
          <button id="toggleBtn">${m.isActive ? 'مسدود کردن' : 'رفع مسدودی'}</button>
          <button id="delBtn" class="danger">حذف کاربر</button>
        </div>
      </div>`;
    $('#toggleBtn').addEventListener('click', async () => {
      try { await api(`/api/members/${id}`, { method: 'PATCH', body: { isActive: !m.isActive } }); renderMemberDetail(id); }
      catch (err) { alert('عملیات ناموفق بود: ' + err.message); }
    });
    $('#delBtn').addEventListener('click', async () => {
      if (!confirm('این کاربر برای همیشه حذف شود؟')) return;
      try { await api(`/api/members/${id}`, { method: 'DELETE' }); renderMembersList(); }
      catch (err) { alert('حذف ناموفق بود: ' + err.message); }
    });

    // activity timeline (loaded separately so the card renders instantly)
    try {
      const acts = await api(`/api/members/${id}/activity`);
      if (!acts.length) {
        $('#activity').innerHTML = `<p class="muted">فعالیتی ثبت نشده.</p>`;
      } else {
        $('#activity').innerHTML = `<ul style="margin:0;padding-inline-start:18px;max-height:260px;overflow:auto">` +
          acts.map(a => `<li style="padding:3px 0">
            <span class="pill${a.kind === 'click' ? ' red' : ''}">${a.kind === 'click' ? 'کلیک' : 'بازدید'}</span>
            ${a.kind === 'click' && a.label ? `«${escapeHtml(a.label)}» در ` : ''}<span style="direction:ltr">${escapeHtml(a.path || '')}</span>
            <span class="muted"> — ${fmtDateTime(a.at)}</span>
          </li>`).join('') + `</ul>`;
      }
    } catch { $('#activity').innerHTML = `<p class="error">خطا در بارگذاری فعالیت.</p>`; }
  } catch (err) {
    $('#detail').innerHTML = `<p class="error">خطا در بارگذاری.</p>`;
  }
}

// ═══════════════════════════════════════════════
//  NEWSLETTER SUBSCRIBERS
// ═══════════════════════════════════════════════
async function renderNewsletterList() {
  root.innerHTML = `
    ${topbarHtml('newsletter', '↻ بروزرسانی')}
    <main class="page">
      <h2>عضویت در خبرنامه</h2>
      <p class="muted" style="margin:-4px 0 12px">ایمیل‌هایی که از فرم فوتر سایت ثبت شده‌اند.</p>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>
  `;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderNewsletterList());

  try {
    const items = await api('/api/newsletter');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز ایمیلی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = `<p class="muted" style="margin-bottom:10px">${items.length.toLocaleString('fa-IR')} ایمیل</p>` +
      items.map(s => `
      <article class="row" data-id="${escapeAttr(s.id)}">
        <div class="row-main">
          <div class="row-meta">
            <strong style="direction:ltr">${escapeHtml(s.email)}</strong>
            <span class="muted">${fmtDateTime(s.createdAt)}</span>
          </div>
        </div>
        <div class="row-actions"><button data-action="delete" class="danger">حذف</button></div>
      </article>`).join('');
    $('#list').addEventListener('click', async (e) => {
      const btn = e.target.closest('button[data-action="delete"]');
      if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (!confirm('این ایمیل حذف شود؟')) return;
      try { await api(`/api/newsletter/${id}`, { method: 'DELETE' }); renderNewsletterList(); }
      catch (err) { alert('حذف ناموفق بود: ' + err.message); }
    });
  } catch (err) {
    console.error(err);
    $('#list').innerHTML = `<p class="error">خطا در بارگذاری.</p>`;
  }
}

// ═══════════════════════════════════════════════
//  EVENTS
// ═══════════════════════════════════════════════
async function renderEventsList() {
  root.innerHTML = `
    ${topbarHtml('events', '+ رویداد جدید')}
    <main class="page">
      <h2>رویدادها</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderEventEditor(null));
  try {
    const items = await api('/api/events?limit=200');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز رویدادی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(e => `
      <article class="row" data-id="${escapeAttr(e.id)}">
        <div class="row-main">
          <div class="row-meta">
            ${e.type ? `<span class="pill">${escapeHtml(EVENT_TYPES.find(t=>t.value===e.type)?.label||e.type)}</span>` : ''}
            ${e.cityFa ? `<span class="muted">${escapeHtml(e.cityFa)}</span>` : ''}
            ${e.dateFa ? `<span class="muted">${escapeHtml(e.dateFa)}</span>` : ''}
            <span class="pill ${e.registrationOpen?'green':'red'}">${e.registrationOpen?'ثبت‌نام باز':'بسته'}</span>
          </div>
          <h3>${escapeHtml(e.titleFa)}</h3>
          <p class="muted clamp-2">${escapeHtml(e.descriptionFa||'')}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderEventEditor(await api(`/api/events/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این رویداد حذف شود؟')) return;
        await api(`/api/events/${id}`, { method: 'DELETE' });
        renderEventsList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderEventEditor(event) {
  const e = event || { titleFa:'', titleEn:'', dateFa:'', dateEn:'', monthFa:'', monthEn:'', year:'',
    type:'', locationFa:'', locationEn:'', cityFa:'', cityEn:'', descriptionFa:'', descriptionEn:'',
    registrationOpen:true, sortOrder:0 };
  const isEdit = !!event;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش رویداد':'رویداد جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>عنوان (فارسی) <input name="titleFa" value="${escapeAttr(e.titleFa)}" required /></label>
        <label>عنوان (انگلیسی) <input name="titleEn" value="${escapeAttr(e.titleEn||'')}" /></label>
        <label>نوع
          <select name="type">
            <option value="">—</option>
            ${EVENT_TYPES.map(t=>`<option value="${t.value}" ${t.value===e.type?'selected':''}>${t.label}</option>`).join('')}
          </select>
        </label>
        <label class="checkbox"><input type="checkbox" name="registrationOpen" ${e.registrationOpen?'checked':''}><span>ثبت‌نام باز است</span></label>
        <label>تاریخ (فارسی) <input name="dateFa" value="${escapeAttr(e.dateFa||'')}" /></label>
        <label>تاریخ (انگلیسی) <input name="dateEn" value="${escapeAttr(e.dateEn||'')}" /></label>
        <label>ماه (فارسی) <input name="monthFa" value="${escapeAttr(e.monthFa||'')}" /></label>
        <label>ماه (انگلیسی) <input name="monthEn" value="${escapeAttr(e.monthEn||'')}" /></label>
        <label>سال <input name="year" value="${escapeAttr(e.year||'')}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${e.sortOrder||0}" /></label>
        <label>شهر (فارسی) <input name="cityFa" value="${escapeAttr(e.cityFa||'')}" /></label>
        <label>شهر (انگلیسی) <input name="cityEn" value="${escapeAttr(e.cityEn||'')}" /></label>
        <div class="col span-2"><label>مکان (فارسی) <input name="locationFa" value="${escapeAttr(e.locationFa||'')}" /></label></div>
        <div class="col span-2"><label>مکان (انگلیسی) <input name="locationEn" value="${escapeAttr(e.locationEn||'')}" /></label></div>
        <div class="col span-2"><label>توضیحات (فارسی) <textarea name="descriptionFa" rows="4">${escapeHtml(e.descriptionFa||'')}</textarea></label></div>
        <div class="col span-2"><label>توضیحات (انگلیسی) <textarea name="descriptionEn" rows="4">${escapeHtml(e.descriptionEn||'')}</textarea></label></div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderEventsList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      titleFa: fd.get('titleFa'), titleEn: fd.get('titleEn')||null,
      dateFa: fd.get('dateFa')||null, dateEn: fd.get('dateEn')||null,
      monthFa: fd.get('monthFa')||null, monthEn: fd.get('monthEn')||null,
      year: fd.get('year')||null, type: fd.get('type')||null,
      locationFa: fd.get('locationFa')||null, locationEn: fd.get('locationEn')||null,
      cityFa: fd.get('cityFa')||null, cityEn: fd.get('cityEn')||null,
      descriptionFa: fd.get('descriptionFa')||null, descriptionEn: fd.get('descriptionEn')||null,
      registrationOpen: fd.get('registrationOpen') === 'on',
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/events/${event.id}`, { method:'PUT', body:payload });
      else await api('/api/events', { method:'POST', body:payload });
      renderEventsList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  TEAM & EXPERTS (shared UI, isExpert flag)
// ═══════════════════════════════════════════════
async function renderTeamList(isExpert) {
  const tab = isExpert ? 'experts' : 'team';
  const label = isExpert ? 'خبرگان' : 'تیم';
  root.innerHTML = `
    ${topbarHtml(tab, `+ ${isExpert?'خبره':'عضو'} جدید`)}
    <main class="page">
      <h2>${isExpert?'شبکه خبرگان':'اعضای تیم'}</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderTeamEditor(null, isExpert));
  try {
    const items = await api(`/api/team?expert=${isExpert?1:0}`);
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز ${label}ی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(m => `
      <article class="row" data-id="${escapeAttr(m.id)}">
        <div class="row-avatar">${escapeHtml(m.initial||m.nameFa?.charAt(0)||'؟')}</div>
        <div class="row-main">
          <div class="row-meta">
            ${m.roleFa ? `<span class="pill">${escapeHtml(m.roleFa)}</span>` : ''}
            ${m.expertRoomFa ? `<span class="muted">${escapeHtml(m.expertRoomFa)}</span>` : ''}
            ${m.reportCount ? `<span class="muted">${m.reportCount} گزارش</span>` : ''}
          </div>
          <h3>${escapeHtml(m.nameFa)}</h3>
          <p class="muted clamp-2">${escapeHtml(m.bioFa||'')}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderTeamEditor(await api(`/api/team/${id}`), isExpert);
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این عضو حذف شود؟')) return;
        await api(`/api/team/${id}`, { method:'DELETE' });
        renderTeamList(isExpert);
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderTeamEditor(member, isExpert) {
  const m = member || { nameFa:'', nameEn:'', roleFa:'', roleEn:'', bioFa:'', bioEn:'',
    expertise:[], email:'', initial:'', photo:'', reportCount:0,
    expertRoomFa:'', expertRoomEn:'', telegram:'', linkedin:'', twitter:'', website:'', sortOrder:0 };
  const isEdit = !!member;
  const expertiseStr = Array.isArray(m.expertise) ? m.expertise.join('، ') : '';
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش':'جدید'} — ${isExpert?'خبره':'عضو تیم'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>نام (فارسی) <input name="nameFa" value="${escapeAttr(m.nameFa)}" required /></label>
        <label>نام (انگلیسی) <input name="nameEn" value="${escapeAttr(m.nameEn||'')}" /></label>
        <label>سمت (فارسی) <input name="roleFa" value="${escapeAttr(m.roleFa||'')}" /></label>
        <label>سمت (انگلیسی) <input name="roleEn" value="${escapeAttr(m.roleEn||'')}" /></label>
        <label>حرف آواتار <input name="initial" maxlength="2" value="${escapeAttr(m.initial||'')}" /></label>
        <label>تعداد گزارش <input name="reportCount" type="number" min="0" value="${m.reportCount||0}" /></label>
        <label>ایمیل <input name="email" type="email" value="${escapeAttr(m.email||'')}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${m.sortOrder||0}" /></label>
        <div class="col span-2"><label>تخصص‌ها (با ویرگول جدا کنید) <input name="expertise" value="${escapeAttr(expertiseStr)}" /></label></div>
        ${isExpert ? `
        <label>اتاق فکر (فارسی) <input name="expertRoomFa" value="${escapeAttr(m.expertRoomFa||'')}" /></label>
        <label>اتاق فکر (انگلیسی) <input name="expertRoomEn" value="${escapeAttr(m.expertRoomEn||'')}" /></label>
        <label>تلگرام <input name="telegram" value="${escapeAttr(m.telegram||'')}" /></label>
        <label>لینکدین <input name="linkedin" value="${escapeAttr(m.linkedin||'')}" /></label>
        <label>توییتر <input name="twitter" value="${escapeAttr(m.twitter||'')}" /></label>
        <label>وبسایت <input name="website" value="${escapeAttr(m.website||'')}" /></label>` : ''}
        <div class="col span-2"><label>بیوگرافی (فارسی) <textarea name="bioFa" rows="4">${escapeHtml(m.bioFa||'')}</textarea></label></div>
        <div class="col span-2"><label>بیوگرافی (انگلیسی) <textarea name="bioEn" rows="4">${escapeHtml(m.bioEn||'')}</textarea></label></div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderTeamList(isExpert));
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const expertiseRaw = String(fd.get('expertise')||'').split(/[,،]/).map(s=>s.trim()).filter(Boolean);
    const payload = {
      nameFa: fd.get('nameFa'), nameEn: fd.get('nameEn')||null,
      roleFa: fd.get('roleFa')||null, roleEn: fd.get('roleEn')||null,
      bioFa: fd.get('bioFa')||null, bioEn: fd.get('bioEn')||null,
      expertise: expertiseRaw, email: fd.get('email')||null,
      initial: fd.get('initial')||null, reportCount: Number(fd.get('reportCount')||0),
      isExpert: isExpert,
      expertRoomFa: fd.get('expertRoomFa')||null, expertRoomEn: fd.get('expertRoomEn')||null,
      telegram: fd.get('telegram')||null, linkedin: fd.get('linkedin')||null,
      twitter: fd.get('twitter')||null, website: fd.get('website')||null,
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/team/${member.id}`, { method:'PUT', body:payload });
      else await api('/api/team', { method:'POST', body:payload });
      renderTeamList(isExpert);
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  PLANS
// ═══════════════════════════════════════════════
async function renderPlansList() {
  root.innerHTML = `
    ${topbarHtml('plans', '+ پلان جدید')}
    <main class="page">
      <h2>پلان‌های اشتراک</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderPlanEditor(null));
  try {
    const items = await api('/api/plans');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز پلانی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(p => `
      <article class="row" data-id="${escapeAttr(p.id)}">
        <div class="row-main">
          <div class="row-meta">
            ${p.isFeatured ? '<span class="pill red">ویژه</span>' : ''}
            ${p.badgeFa ? `<span class="pill">${escapeHtml(p.badgeFa)}</span>` : ''}
            <span class="muted">${Number(p.price).toLocaleString()} ریال / ${escapeHtml(p.periodFa||'')}</span>
          </div>
          <h3>${escapeHtml(p.nameFa)}</h3>
          <p class="muted">${Array.isArray(p.features) ? p.features.length : 0} ویژگی</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderPlanEditor(await api(`/api/plans/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این پلان حذف شود؟')) return;
        await api(`/api/plans/${id}`, { method:'DELETE' });
        renderPlansList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderPlanEditor(plan) {
  const p = plan || { nameFa:'', nameEn:'', price:0, periodFa:'', periodEn:'',
    features:[], badgeFa:'', badgeEn:'', isFeatured:false, ctaFa:'', ctaEn:'', sortOrder:0 };
  const isEdit = !!plan;
  const featStr = Array.isArray(p.features)
    ? p.features.map(f => typeof f === 'object' ? f.fa||'' : f).join('\n')
    : '';
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش پلان':'پلان جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>نام (فارسی) <input name="nameFa" value="${escapeAttr(p.nameFa)}" required /></label>
        <label>نام (انگلیسی) <input name="nameEn" value="${escapeAttr(p.nameEn||'')}" /></label>
        <label>قیمت (ریال) <input name="price" type="number" min="0" value="${p.price||0}" /></label>
        <label>دوره (فارسی) <input name="periodFa" value="${escapeAttr(p.periodFa||'')}" /></label>
        <label>دوره (انگلیسی) <input name="periodEn" value="${escapeAttr(p.periodEn||'')}" /></label>
        <label>برچسب (فارسی) <input name="badgeFa" value="${escapeAttr(p.badgeFa||'')}" /></label>
        <label>برچسب (انگلیسی) <input name="badgeEn" value="${escapeAttr(p.badgeEn||'')}" /></label>
        <label>دکمه CTA (فارسی) <input name="ctaFa" value="${escapeAttr(p.ctaFa||'')}" /></label>
        <label>دکمه CTA (انگلیسی) <input name="ctaEn" value="${escapeAttr(p.ctaEn||'')}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${p.sortOrder||0}" /></label>
        <label class="checkbox"><input type="checkbox" name="isFeatured" ${p.isFeatured?'checked':''}><span>پلان ویژه (هایلایت)</span></label>
        <div class="col span-2">
          <label>ویژگی‌ها (هر ویژگی در یک خط — فارسی)
            <textarea name="features" rows="8">${escapeHtml(featStr)}</textarea>
          </label>
        </div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderPlansList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const featLines = String(fd.get('features')||'').split('\n').map(s=>s.trim()).filter(Boolean);
    const payload = {
      nameFa: fd.get('nameFa'), nameEn: fd.get('nameEn')||null,
      price: Number(fd.get('price')||0),
      periodFa: fd.get('periodFa')||null, periodEn: fd.get('periodEn')||null,
      features: featLines,
      badgeFa: fd.get('badgeFa')||null, badgeEn: fd.get('badgeEn')||null,
      isFeatured: fd.get('isFeatured') === 'on',
      ctaFa: fd.get('ctaFa')||null, ctaEn: fd.get('ctaEn')||null,
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/plans/${plan.id}`, { method:'PUT', body:payload });
      else await api('/api/plans', { method:'POST', body:payload });
      renderPlansList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  RADAR (رادار آینده)
// ═══════════════════════════════════════════════
// section pages on the site → which raw categories feed them
const RADAR_PAGE_SLUGS = [
  { slug: 'market',         label: 'بازار و زنجیره فولاد',      cats: ['market','commodity'] },
  { slug: 'sustainability', label: 'پایداری و فولاد سبز',       cats: ['energy','commodity'] },
  { slug: 'geopolitics',    label: 'ژئوپلیتیک و اقتصاد جهانی', cats: ['geo','market'] },
  { slug: 'technology',     label: 'فناوری و نوآوری',           cats: ['tech'] },
];

function sectionLabelsForCategory(cat) {
  return RADAR_PAGE_SLUGS.filter(s => s.cats.includes(cat)).map(s => s.label);
}

async function renderRadarList() {
  root.innerHTML = `
    ${topbarHtml('glance', '+ در یک نگاه جدید')}
    <main class="page">
      <h2>در یک نگاه</h2>
      <p class="muted" style="margin:-4px 0 12px">محتوای صفحهٔ «در یک نگاه» سایت (‎/at-a-glance‎) — به تفکیک دسته.</p>
      <div id="section-bar" class="cat-bar">
        <button class="cat-btn active" data-cat="">همه</button>
        ${RADAR_CATEGORIES.map(c => `<button class="cat-btn" data-cat="${c.value}">${c.label}</button>`).join('')}
      </div>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderRadarEditor(null));

  let allItems = [];
  let activeCat = '';

  const safeImgUrl = (u) => /^(\/uploads\/[a-zA-Z0-9._-]+|\/[a-zA-Z0-9._\/-]+)$/.test(String(u || '')) ? u : '';
  const catLabel = (v) => (RADAR_CATEGORIES.find(c => c.value === v) || {}).label || v;

  function renderItems() {
    const filtered = activeCat ? allItems.filter(r => r.category === activeCat) : allItems;
    if (!filtered.length) { $('#list').innerHTML = `<p class="muted">مطلبی در این دسته یافت نشد.</p>`; return; }
    $('#list').innerHTML = filtered.map(r => {
      return `
      <article class="row" data-id="${escapeAttr(r.id)}">
        <div class="row-cover" style="background-image:url('${escapeAttr(safeImgUrl(r.img))}')"></div>
        <div class="row-main">
          <div class="row-meta">
            ${r.status === 'draft' ? `<span class="pill" style="background:#b45309;color:#fff">پیش‌نویس</span>` : ''}
            ${r.category ? `<span class="pill">${escapeHtml(catLabel(r.category))}</span>` : ''}
            ${r.dateFa ? `<span class="muted">${escapeHtml(r.dateFa)}</span>` : ''}
          </div>
          <h3>${escapeHtml(r.titleFa||'')}</h3>
          <p class="muted clamp-2">${escapeHtml(r.excerptFa||'')}</p>
        </div>
        <div class="row-actions">
          ${r.status === 'draft' ? `<button data-action="publish" style="background:#15803d;color:#fff">انتشار</button>` : ''}
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`;
    }).join('');
  }

  $('#section-bar').addEventListener('click', e => {
    const btn = e.target.closest('.cat-btn'); if (!btn) return;
    activeCat = btn.dataset.cat;
    document.querySelectorAll('#section-bar .cat-btn').forEach(b => b.classList.toggle('active', b === btn));
    renderItems();
  });

  $('#list').addEventListener('click', async ev => {
    const btn = ev.target.closest('button[data-action]'); if (!btn) return;
    const id = btn.closest('.row').dataset.id;
    if (btn.dataset.action === 'edit') renderRadarEditor(await api(`/api/radar/${id}`));
    else if (btn.dataset.action === 'publish') {
      await api(`/api/radar/${id}/publish`, { method: 'POST' });
      renderRadarList();
    }
    else if (btn.dataset.action === 'delete') {
      if (!confirm('این مطلب حذف شود؟')) return;
      await api(`/api/radar/${id}`, { method: 'DELETE' });
      renderRadarList();
    }
  });

  try {
    allItems = await api('/api/admin/radar?limit=500');
    if (!allItems.length) { $('#list').innerHTML = `<p class="muted">هنوز مطلبی ثبت نشده.</p>`; return; }
    renderItems();
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderRadarEditor(item) {
  const r = item || { category:'', img:'', authorName:'', authorAvatar:'',
    titleFa:'', dateFa:'', excerptFa:'', bodyFa:'', analysisFa:'',
    titleEn:'', dateEn:'', excerptEn:'', bodyEn:'', analysisEn:'', tags:[], source:'', sortOrder:0 };
  const isEdit = !!item;

  function sectionBadges(cat) {
    const labels = sectionLabelsForCategory(cat);
    if (!labels.length) return '<span class="muted" style="font-size:12px">—</span>';
    return labels.map(l => `<span class="pill green">${escapeHtml(l)}</span>`).join(' ');
  }

  root.innerHTML = `
    <header class="topbar">
      <div class="topbar-row">
        <div class="brand">📌 ${isEdit?'ویرایش':'مطلب جدید'} — در یک نگاه</div>
        <nav class="groups"></nav>
        <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
      </div>
      <div class="tabs"></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">

        <div class="col span-2">
          <label>بخش سایت
            <select name="category" id="catSelect">
              <option value="">انتخاب کنید…</option>
              ${RADAR_CATEGORIES.map(c=>`<option value="${c.value}" ${c.value===r.category?'selected':''}>${c.label}</option>`).join('')}
            </select>
          </label>
          <div id="sectionBadges" style="margin-top:8px;display:flex;gap:6px;flex-wrap:wrap;align-items:center">
            <span class="muted" style="font-size:12px">نمایش در بخش‌های سایت:</span>
            ${sectionBadges(r.category)}
          </div>
        </div>

        <div class="col span-2">
          <label>تصویر شاخص
            <div class="cover-row">
              <input type="file" id="radarCoverFile" accept="image/*" />
              <input type="hidden" name="img" value="${escapeAttr(r.img||'')}" />
              <img id="radarCoverPreview" alt="" src="${escapeAttr(r.img||'')}" style="${r.img?'':'display:none'}" />
            </div>
          </label>
        </div>

        <div class="col span-2" style="border-top:1px solid var(--rule);padding-top:16px;margin-top:4px">
          <strong style="font-size:13px;color:var(--ink-3)">فارسی</strong>
        </div>

        <div class="col span-2">
          <label>عنوان (فارسی) <input name="titleFa" value="${escapeAttr(r.titleFa)}" required /></label>
        </div>
        <label>تاریخ (فارسی) <input name="dateFa" value="${escapeAttr(r.dateFa||'')}" placeholder="۱۴ خرداد ۱۴۰۴" /></label>
        <label>نام نویسنده <input name="authorName" value="${escapeAttr(r.authorName||'')}" /></label>
        <label>منبع <input name="source" value="${escapeAttr(r.source||'')}" placeholder="مثلاً Financial Times" /></label>
        <div class="col span-2">
          <label>هشتگ‌ها (با ویرگول جدا کنید) <input name="tags" value="${escapeAttr((r.tags||[]).join('، '))}" placeholder="فولاد سبز، هیدروژن، اروپا" /></label>
        </div>
        <div class="col span-2">
          <label>چکیده (فارسی) <textarea name="excerptFa" rows="3">${escapeHtml(r.excerptFa||'')}</textarea></label>
        </div>
        <div class="col span-2">
          <label>متن کامل (فارسی) <textarea name="bodyFa" rows="8">${escapeHtml(r.bodyFa||'')}</textarea></label>
        </div>
        <div class="col span-2">
          <label>تحلیل استراتژیک (فارسی — برای اعضا) <textarea name="analysisFa" rows="4">${escapeHtml(r.analysisFa||'')}</textarea></label>
        </div>

        <div class="col span-2" style="border-top:1px solid var(--rule);padding-top:16px;margin-top:4px">
          <strong style="font-size:13px;color:var(--ink-3)">English</strong>
        </div>

        <div class="col span-2">
          <label>Title (English) <input name="titleEn" value="${escapeAttr(r.titleEn||'')}" /></label>
        </div>
        <label>Date (English) <input name="dateEn" value="${escapeAttr(r.dateEn||'')}" placeholder="June 4, 2025" /></label>
        <div></div>
        <div class="col span-2">
          <label>Excerpt (English) <textarea name="excerptEn" rows="3">${escapeHtml(r.excerptEn||'')}</textarea></label>
        </div>
        <div class="col span-2">
          <label>Body (English) <textarea name="bodyEn" rows="8">${escapeHtml(r.bodyEn||'')}</textarea></label>
        </div>
        <div class="col span-2">
          <label>Strategic Analysis (English) <textarea name="analysisEn" rows="4">${escapeHtml(r.analysisEn||'')}</textarea></label>
        </div>

        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${r.sortOrder||0}" /></label>

        <div class="col span-2 row-end">
          <button type="submit" class="primary">${isEdit?'ذخیره تغییرات':'انتشار مطلب رادار'}</button>
        </div>
      </form>
    </main>`;

  $('#backBtn').addEventListener('click', () => renderRadarList());

  document.getElementById('catSelect').addEventListener('change', e => {
    const cat = e.target.value;
    const badgesEl = document.getElementById('sectionBadges');
    badgesEl.innerHTML = `<span class="muted" style="font-size:12px">نمایش در بخش‌های سایت:</span> ${sectionBadges(cat)}`;
  });

  document.getElementById('radarCoverFile').addEventListener('change', async e => {
    const file = e.target.files?.[0]; if (!file) return;
    const fd = new FormData(); fd.append('file', file);
    try {
      const { url } = await api('/api/uploads', { method: 'POST', body: fd, isForm: true });
      $('input[name="img"]').value = url;
      const prev = document.getElementById('radarCoverPreview');
      prev.src = url; prev.style.display = '';
    } catch (err) { alert('آپلود ناموفق: ' + err.message); }
  });

  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      titleFa: fd.get('titleFa'), titleEn: fd.get('titleEn')||null,
      category: fd.get('category')||null,
      img: fd.get('img')||null,
      authorName: fd.get('authorName')||null,
      authorAvatar: r.authorAvatar || null,
      dateFa: fd.get('dateFa')||null, dateEn: fd.get('dateEn')||null,
      excerptFa: fd.get('excerptFa')||null, excerptEn: fd.get('excerptEn')||null,
      bodyFa: fd.get('bodyFa')||null, bodyEn: fd.get('bodyEn')||null,
      analysisFa: fd.get('analysisFa')||null, analysisEn: fd.get('analysisEn')||null,
      source: fd.get('source')||null,
      tags: String(fd.get('tags')||'').split(/[,،]/).map(s=>s.trim()).filter(Boolean),
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/radar/${item.id}`, { method:'PUT', body:payload });
      else await api('/api/radar', { method:'POST', body:payload });
      renderRadarList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

async function renderRadarPagesList() {
  root.innerHTML = `
    ${topbarHtml('radarPages', '')}
    <main class="page">
      <h2>صفحات رادار آینده</h2>
      <p class="muted">۵ صفحه ثابت. محتوای هیرو (کارت ویژه) و بنر هر دسته را اینجا ویرایش کنید.</p>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  const newBtn = $('#newBtn'); if (newBtn) newBtn.style.display = 'none';
  try {
    const saved = await api('/api/radar-pages');
    const bySlug = {}; saved.forEach(p => { bySlug[p.slug] = p; });
    $('#list').innerHTML = RADAR_PAGE_SLUGS.map(s => {
      const p = bySlug[s.slug];
      return `
      <article class="row" data-slug="${escapeAttr(s.slug)}">
        <div class="row-main">
          <div class="row-meta">
            <span class="pill">${escapeHtml(s.slug)}</span>
            ${p ? '<span class="muted">ذخیره‌شده</span>' : '<span class="muted">پیش‌فرض (هنوز ذخیره نشده)</span>'}
          </div>
          <h3>${escapeHtml((p && p.labelFa) || s.label)}</h3>
          <p class="muted clamp-2">${escapeHtml((p && p.bannerTitleFa) || '')}</p>
        </div>
        <div class="row-actions"><button data-action="edit">ویرایش</button></div>
      </article>`;
    }).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const slug = btn.closest('.row').dataset.slug;
      const def = RADAR_PAGE_SLUGS.find(x => x.slug === slug);
      renderRadarPageEditor(bySlug[slug] || { slug, labelFa: def.label }, def);
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderRadarPageEditor(p, def) {
  const r = Object.assign({
    slug: def.slug, sourceCategories: [], labelFa: def.label, labelEn: '',
    latestHeadingFa: '', latestHeadingEn: '',
    featuredTitleFa: '', featuredTitleEn: '', featuredDateFa: '', featuredDateEn: '', featuredImg: '',
    bannerKickerFa: 'تحلیل ویژه', bannerKickerEn: 'Special Analysis',
    bannerTitleFa: '', bannerTitleEn: '', bannerDescFa: '', bannerDescEn: '',
    bannerBookImg: '', sortOrder: 0,
  }, p || {});
  const catChecked = (c) => (r.sourceCategories || []).includes(c) ? 'checked' : '';
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">ویرایش صفحه: ${escapeHtml(r.labelFa)}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>عنوان دسته (فارسی) <input name="labelFa" value="${escapeAttr(r.labelFa)}" required /></label>
        <label>عنوان دسته (انگلیسی) <input name="labelEn" value="${escapeAttr(r.labelEn||'')}" /></label>
        <div class="col span-2"><label>دسته‌های منبع کارت‌ها
          <div style="display:flex;gap:14px;flex-wrap:wrap;margin-top:6px">
            ${RADAR_CATEGORIES.map(c=>`<label style="display:inline-flex;gap:5px;align-items:center;font-weight:400"><input type="checkbox" name="srcCat" value="${c.value}" ${catChecked(c.value)} /> ${c.label}</label>`).join('')}
          </div>
        </label></div>
        <label>تیتر تازه‌ترین‌ها (فارسی) <input name="latestHeadingFa" value="${escapeAttr(r.latestHeadingFa||'')}" /></label>
        <label>تیتر تازه‌ترین‌ها (انگلیسی) <input name="latestHeadingEn" value="${escapeAttr(r.latestHeadingEn||'')}" /></label>

        <div class="col span-2"><h3 style="margin:10px 0 0">کارت ویژه (هیرو)</h3></div>
        <label>عنوان ویژه (فارسی) <input name="featuredTitleFa" value="${escapeAttr(r.featuredTitleFa||'')}" /></label>
        <label>عنوان ویژه (انگلیسی) <input name="featuredTitleEn" value="${escapeAttr(r.featuredTitleEn||'')}" /></label>
        <label>تاریخ ویژه (فارسی) <input name="featuredDateFa" value="${escapeAttr(r.featuredDateFa||'')}" /></label>
        <label>تاریخ ویژه (انگلیسی) <input name="featuredDateEn" value="${escapeAttr(r.featuredDateEn||'')}" /></label>
        <div class="col span-2"><label>تصویر ویژه (URL) <input name="featuredImg" value="${escapeAttr(r.featuredImg||'')}" /></label></div>

        <div class="col span-2"><h3 style="margin:10px 0 0">بنر تحلیل ویژه</h3></div>
        <label>برچسب بنر (فارسی) <input name="bannerKickerFa" value="${escapeAttr(r.bannerKickerFa||'')}" /></label>
        <label>برچسب بنر (انگلیسی) <input name="bannerKickerEn" value="${escapeAttr(r.bannerKickerEn||'')}" /></label>
        <label>عنوان بنر (فارسی) <input name="bannerTitleFa" value="${escapeAttr(r.bannerTitleFa||'')}" /></label>
        <label>عنوان بنر (انگلیسی) <input name="bannerTitleEn" value="${escapeAttr(r.bannerTitleEn||'')}" /></label>
        <div class="col span-2"><label>توضیح بنر (فارسی) <textarea name="bannerDescFa" rows="3">${escapeHtml(r.bannerDescFa||'')}</textarea></label></div>
        <div class="col span-2"><label>توضیح بنر (انگلیسی) <textarea name="bannerDescEn" rows="3">${escapeHtml(r.bannerDescEn||'')}</textarea></label></div>
        <div class="col span-2"><label>تصویر کتاب بنر (URL) <input name="bannerBookImg" value="${escapeAttr(r.bannerBookImg||'')}" /></label></div>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${r.sortOrder||0}" /></label>
        <div class="col span-2 row-end"><button type="submit" class="primary">ذخیره</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderRadarPagesList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      sourceCategories: fd.getAll('srcCat'),
      labelFa: fd.get('labelFa'), labelEn: fd.get('labelEn')||null,
      latestHeadingFa: fd.get('latestHeadingFa')||null, latestHeadingEn: fd.get('latestHeadingEn')||null,
      featuredTitleFa: fd.get('featuredTitleFa')||null, featuredTitleEn: fd.get('featuredTitleEn')||null,
      featuredDateFa: fd.get('featuredDateFa')||null, featuredDateEn: fd.get('featuredDateEn')||null,
      featuredImg: fd.get('featuredImg')||null,
      bannerKickerFa: fd.get('bannerKickerFa')||null, bannerKickerEn: fd.get('bannerKickerEn')||null,
      bannerTitleFa: fd.get('bannerTitleFa')||null, bannerTitleEn: fd.get('bannerTitleEn')||null,
      bannerDescFa: fd.get('bannerDescFa')||null, bannerDescEn: fd.get('bannerDescEn')||null,
      bannerBookImg: fd.get('bannerBookImg')||null,
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      await api(`/api/radar-pages/${r.slug}`, { method:'PUT', body:payload });
      renderRadarPagesList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  FACTORY REPORTS (گزارش کارخانه)
// ═══════════════════════════════════════════════
async function renderFactoryReportsList() {
  root.innerHTML = `
    ${topbarHtml('factoryReports', '+ گزارش جدید')}
    <main class="page">
      <h2>گزارش کارخانه</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderFactoryReportEditor(null));
  try {
    const items = await api('/api/factory-reports?limit=50');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز گزارشی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(r => `
      <article class="row" data-id="${escapeAttr(r.id)}">
        <div class="row-main">
          <div class="row-meta">
            ${r.tagFa ? `<span class="pill">${escapeHtml(r.tagFa)}</span>` : ''}
            ${r.dateFa ? `<span class="muted">${escapeHtml(r.dateFa)}</span>` : ''}
            <span class="muted">${escapeHtml(SCROLL_DIRS.find(d=>d.value===r.scrollDir)?.label||r.scrollDir||'')}</span>
          </div>
          <h3>${escapeHtml(r.titleFa)}</h3>
          <p class="muted clamp-2">${escapeHtml(r.excerptFa||'')}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderFactoryReportEditor(await api(`/api/factory-reports/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این گزارش حذف شود؟')) return;
        await api(`/api/factory-reports/${id}`, { method: 'DELETE' });
        renderFactoryReportsList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderFactoryReportEditor(report) {
  const r = report || { img:'', tagFa:'', tagEn:'', titleFa:'', titleEn:'', dateFa:'', dateEn:'',
    excerptFa:'', excerptEn:'', fileUrl:'', scrollDir:'up', sortOrder:0 };
  const isEdit = !!report;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش گزارش':'گزارش جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>عنوان (فارسی) <input name="titleFa" value="${escapeAttr(r.titleFa)}" required /></label>
        <label>عنوان (انگلیسی) <input name="titleEn" value="${escapeAttr(r.titleEn||'')}" /></label>
        <label>برچسب (فارسی) <input name="tagFa" value="${escapeAttr(r.tagFa||'')}" /></label>
        <label>برچسب (انگلیسی) <input name="tagEn" value="${escapeAttr(r.tagEn||'')}" /></label>
        <label>تاریخ (فارسی) <input name="dateFa" value="${escapeAttr(r.dateFa||'')}" /></label>
        <label>تاریخ (انگلیسی) <input name="dateEn" value="${escapeAttr(r.dateEn||'')}" /></label>
        <label>جهت ورود
          <select name="scrollDir">
            ${SCROLL_DIRS.map(d=>`<option value="${d.value}" ${d.value===r.scrollDir?'selected':''}>${d.label}</option>`).join('')}
          </select>
        </label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${r.sortOrder||0}" /></label>
        <div class="col span-2">
          <label style="display:block;margin-bottom:6px">تصویر کاور</label>
          <input type="file" id="factoryCoverFile" accept="image/*" style="display:block;margin-bottom:8px" />
          <input type="text" name="img" value="${escapeAttr(r.img||'')}" placeholder="آدرس تصویر (یا از دکمه بالا آپلود کنید)" style="width:100%" />
          <img id="factoryCoverPreview" alt="" src="${escapeAttr(r.img||'')}" style="${r.img?'':'display:none'};max-width:200px;max-height:130px;border-radius:6px;margin-top:8px" />
        </div>
        <div class="col span-2">
          <label style="display:block;margin-bottom:6px">فایل ماهنامه (PDF) — مستقیم دانلود می‌شود</label>
          <input type="file" id="factoryFile" accept="application/pdf" style="display:block;margin-bottom:8px" />
          <input type="text" name="fileUrl" value="${escapeAttr(r.fileUrl||'')}" placeholder="آدرس فایل (یا از دکمه بالا آپلود کنید)" style="width:100%" />
          <span id="factoryFileStatus" class="muted" style="display:block;font-size:12px;margin-top:6px"></span>
        </div>
        <div class="col span-2"><label>خلاصه (فارسی) <textarea name="excerptFa" rows="3">${escapeHtml(r.excerptFa||'')}</textarea></label></div>
        <div class="col span-2"><label>خلاصه (انگلیسی) <textarea name="excerptEn" rows="3">${escapeHtml(r.excerptEn||'')}</textarea></label></div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderFactoryReportsList());
  document.getElementById('factoryCoverFile').addEventListener('change', async e => {
    const file = e.target.files?.[0]; if (!file) return;
    const fd = new FormData(); fd.append('file', file);
    try {
      const { url } = await api('/api/uploads', { method:'POST', body:fd, isForm:true });
      $('input[name="img"]').value = url;
      const prev = document.getElementById('factoryCoverPreview');
      if (prev) { prev.src = url; prev.style.display = ''; }
    } catch (err) { alert('آپلود تصویر ناموفق: ' + err.message); }
  });
  document.getElementById('factoryFile').addEventListener('change', async e => {
    const file = e.target.files?.[0]; if (!file) return;
    const status = document.getElementById('factoryFileStatus');
    if (status) status.textContent = 'در حال آپلود فایل…';
    const fd = new FormData(); fd.append('file', file);
    try {
      const { url } = await api('/api/uploads/raw', { method:'POST', body:fd, isForm:true });
      $('input[name="fileUrl"]').value = url;
      if (status) status.textContent = '✓ آپلود شد';
    } catch (err) { if (status) status.textContent = ''; alert('آپلود ناموفق: ' + err.message); }
  });
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      img: fd.get('img')||null,
      tagFa: fd.get('tagFa')||null, tagEn: fd.get('tagEn')||null,
      titleFa: fd.get('titleFa'), titleEn: fd.get('titleEn')||null,
      dateFa: fd.get('dateFa')||null, dateEn: fd.get('dateEn')||null,
      excerptFa: fd.get('excerptFa')||null, excerptEn: fd.get('excerptEn')||null,
      fileUrl: fd.get('fileUrl')||null,
      scrollDir: fd.get('scrollDir')||'up',
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/factory-reports/${report.id}`, { method:'PUT', body:payload });
      else await api('/api/factory-reports', { method:'POST', body:payload });
      renderFactoryReportsList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  INTEGRATIONS (منابع داده)
// ═══════════════════════════════════════════════
async function renderIntegrationsList() {
  root.innerHTML = `
    ${topbarHtml('integrations', '+ منبع جدید')}
    <main class="page">
      <h2>منابع داده</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderIntegrationEditor(null));
  try {
    const items = await api('/api/integrations?limit=50');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز منبعی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(it => `
      <article class="row" data-id="${escapeAttr(it.id)}">
        <div class="row-main">
          <div class="row-meta">
            ${it.icon ? `<span class="pill">${escapeHtml(INTEGRATION_ICONS.find(i=>i.value===it.icon)?.label||it.icon)}</span>` : ''}
            <span class="muted">سلول ${it.gridCol}×${it.gridRow}</span>
            ${it.accent ? `<span class="pill" style="background:${escapeAttr(it.accent)}">&nbsp;</span>` : ''}
          </div>
          <h3>${escapeHtml(it.name)}</h3>
          ${it.logo ? `<p class="muted clamp-2">${escapeHtml(it.logo)}</p>` : ''}
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderIntegrationEditor(await api(`/api/integrations/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این منبع حذف شود؟')) return;
        await api(`/api/integrations/${id}`, { method: 'DELETE' });
        renderIntegrationsList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderIntegrationEditor(integration) {
  const it = integration || { name:'', icon:'globe', logo:'', accent:'', gridCol:1, gridRow:1, sortOrder:0 };
  const isEdit = !!integration;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش منبع':'منبع جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <div class="col span-2"><label>نام <input name="name" value="${escapeAttr(it.name)}" required /></label></div>
        <label>آیکن
          <select name="icon">
            ${INTEGRATION_ICONS.map(i=>`<option value="${i.value}" ${i.value===it.icon?'selected':''}>${i.label}</option>`).join('')}
          </select>
        </label>
        <label>رنگ تأکید <input name="accent" value="${escapeAttr(it.accent||'')}" placeholder="#CD9E53" /></label>
        <label>ستون شبکه (۱-۶) <input name="gridCol" type="number" min="1" max="6" value="${it.gridCol||1}" /></label>
        <label>ردیف شبکه (۱-۵) <input name="gridRow" type="number" min="1" max="5" value="${it.gridRow||1}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${it.sortOrder||0}" /></label>
        <div class="col span-2"><label>مسیر لوگو (اختیاری) <input name="logo" value="${escapeAttr(it.logo||'')}" placeholder="/logos/lme.svg" /></label></div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderIntegrationsList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      name: fd.get('name'),
      icon: fd.get('icon')||'globe',
      logo: fd.get('logo')||null,
      accent: fd.get('accent')||null,
      gridCol: Number(fd.get('gridCol')||1),
      gridRow: Number(fd.get('gridRow')||1),
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/integrations/${integration.id}`, { method:'PUT', body:payload });
      else await api('/api/integrations', { method:'POST', body:payload });
      renderIntegrationsList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  INSTITUTE STATS (آمار)
// ═══════════════════════════════════════════════
async function renderStatsList() {
  root.innerHTML = `
    ${topbarHtml('stats', '+ آمار جدید')}
    <main class="page">
      <h2>آمار اندیشکده</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderStatEditor(null));
  try {
    const items = await api('/api/institute-stats');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز آماری ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(s => `
      <article class="row" data-id="${escapeAttr(s.id)}">
        <div class="row-main">
          <div class="row-meta">
            <span class="pill">${s.value}${s.suffixFa ? escapeHtml(s.suffixFa) : ''}</span>
          </div>
          <h3>${escapeHtml(s.labelFa)}</h3>
          ${s.labelEn ? `<p class="muted clamp-2">${escapeHtml(s.labelEn)}</p>` : ''}
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderStatEditor(await api(`/api/institute-stats/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این آمار حذف شود؟')) return;
        await api(`/api/institute-stats/${id}`, { method: 'DELETE' });
        renderStatsList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderStatEditor(stat) {
  const s = stat || { id: '', labelFa: '', labelEn: '', value: 0, suffixFa: '', sortOrder: 0 };
  const isEdit = !!stat;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش آمار' : 'آمار جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>شناسه (لاتین، بدون فاصله)
          <input name="id" value="${escapeAttr(s.id || '')}" ${isEdit ? 'readonly' : ''} placeholder="total-reports" required />
        </label>
        <label>مقدار (عدد) <input name="value" type="number" value="${s.value || 0}" required /></label>
        <label>برچسب (فارسی) <input name="labelFa" value="${escapeAttr(s.labelFa)}" required /></label>
        <label>برچسب (انگلیسی) <input name="labelEn" value="${escapeAttr(s.labelEn || '')}" /></label>
        <label>پسوند (فارسی، مثل +) <input name="suffixFa" value="${escapeAttr(s.suffixFa || '')}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${s.sortOrder || 0}" /></label>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit ? 'ذخیره' : 'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderStatsList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      id: fd.get('id'),
      labelFa: fd.get('labelFa'), labelEn: fd.get('labelEn') || null,
      value: Number(fd.get('value') || 0),
      suffixFa: fd.get('suffixFa') || null,
      sortOrder: Number(fd.get('sortOrder') || 0),
    };
    try {
      if (isEdit) await api(`/api/institute-stats/${stat.id}`, { method: 'PUT', body: payload });
      else await api('/api/institute-stats', { method: 'POST', body: payload });
      renderStatsList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  MARKET PRICES (قیمت‌ها)
// ═══════════════════════════════════════════════
async function renderMarketPricesList() {
  root.innerHTML = `
    ${topbarHtml('mprices', '+ قیمت جدید')}
    <main class="page">
      <h2>قیمت‌های بازار</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderMarketPriceEditor(null));
  try {
    const items = await api('/api/market-prices');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز قیمتی ثبت نشده.</p>`; return; }
    const trendLabel = (t) => (TREND_TYPES.find(x => x.value === t)?.label) || t;
    $('#list').innerHTML = items.map(p => `
      <article class="row" data-id="${escapeAttr(p.id)}">
        <div class="row-main">
          <div class="row-meta">
            <span class="pill">${p.value} ${escapeHtml(p.unit || '')}</span>
            <span class="muted">${escapeHtml(trendLabel(p.trend))} ${p.changePercent}%</span>
          </div>
          <h3>${escapeHtml(p.name)}</h3>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderMarketPriceEditor(await api(`/api/market-prices/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این قیمت حذف شود؟')) return;
        await api(`/api/market-prices/${id}`, { method: 'DELETE' });
        renderMarketPricesList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderMarketPriceEditor(price) {
  const p = price || { id: '', name: '', value: 0, unit: '', change: 0, changePercent: 0, trend: 'flat', sortOrder: 0 };
  const isEdit = !!price;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش قیمت' : 'قیمت جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>شناسه (لاتین) <input name="id" value="${escapeAttr(p.id || '')}" ${isEdit ? 'readonly' : ''} placeholder="steel-billet" required /></label>
        <label>نام محصول (فارسی) <input name="name" value="${escapeAttr(p.name)}" required /></label>
        <label>مقدار / قیمت <input name="value" type="number" step="any" value="${p.value || 0}" required /></label>
        <label>واحد (مثل تومان/کیلو) <input name="unit" value="${escapeAttr(p.unit || '')}" /></label>
        <label>تغییر (مقدار) <input name="change" type="number" step="any" value="${p.change || 0}" /></label>
        <label>تغییر (درصد) <input name="changePercent" type="number" step="any" value="${p.changePercent || 0}" /></label>
        <label>روند
          <select name="trend">
            ${TREND_TYPES.map(t => `<option value="${t.value}" ${t.value === p.trend ? 'selected' : ''}>${t.label}</option>`).join('')}
          </select>
        </label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${p.sortOrder || 0}" /></label>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit ? 'ذخیره' : 'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderMarketPricesList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      id: fd.get('id'),
      name: fd.get('name'),
      value: Number(fd.get('value') || 0),
      unit: fd.get('unit') || null,
      change: Number(fd.get('change') || 0),
      changePercent: Number(fd.get('changePercent') || 0),
      trend: fd.get('trend'),
      sortOrder: Number(fd.get('sortOrder') || 0),
    };
    try {
      if (isEdit) await api(`/api/market-prices/${price.id}`, { method: 'PUT', body: payload });
      else await api('/api/market-prices', { method: 'POST', body: payload });
      renderMarketPricesList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  MARKET CHART POINTS (نمودارها)
// ═══════════════════════════════════════════════
async function renderChartPointsList() {
  root.innerHTML = `
    ${topbarHtml('charts', '+ نقطه جدید')}
    <main class="page">
      <h2>نقاط نمودار بازار</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderChartPointEditor(null));
  try {
    const items = await api('/api/market-chart-points?limit=500');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز نقطه‌ای ثبت نشده.</p>`; return; }
    const seriesLabel = (s) => (CHART_SERIES.find(x => x.value === s)?.label) || s;
    $('#list').innerHTML = items.map(c => `
      <article class="row" data-id="${escapeAttr(c.id)}">
        <div class="row-main">
          <div class="row-meta">
            <span class="pill">${escapeHtml(seriesLabel(c.series))}</span>
            <span class="muted">${c.value}</span>
            ${c.meta ? `<span class="muted">${escapeHtml(c.meta)}</span>` : ''}
          </div>
          <h3>${escapeHtml(c.label)}</h3>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderChartPointEditor(await api(`/api/market-chart-points/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این نقطه حذف شود؟')) return;
        await api(`/api/market-chart-points/${id}`, { method: 'DELETE' });
        renderChartPointsList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderChartPointEditor(point) {
  const c = point || { id: '', series: 'history', label: '', value: 0, meta: '', sortOrder: 0 };
  const isEdit = !!point;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش نقطه نمودار' : 'نقطه نمودار جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>سری داده
          <select name="series">
            ${CHART_SERIES.map(s => `<option value="${s.value}" ${s.value === c.series ? 'selected' : ''}>${s.label}</option>`).join('')}
          </select>
        </label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${c.sortOrder || 0}" /></label>
        <label>برچسب (ماه فارسی / نام کشور) <input name="label" value="${escapeAttr(c.label)}" required /></label>
        <label>مقدار (قیمت / تناژ) <input name="value" type="number" step="any" value="${c.value || 0}" required /></label>
        <div class="col span-2">
          <label>متادیتا (فقط «مقایسه جهانی» — JSON: {"flag":"🇮🇷","currency":"IRR","unit":"تومان/کیلو"})
            <input name="meta" value="${escapeAttr(c.meta || '')}" />
          </label>
        </div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit ? 'ذخیره' : 'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderChartPointsList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      series: fd.get('series'),
      label: fd.get('label'),
      value: Number(fd.get('value') || 0),
      meta: fd.get('meta') || null,
      sortOrder: Number(fd.get('sortOrder') || 0),
    };
    try {
      if (isEdit) await api(`/api/market-chart-points/${point.id}`, { method: 'PUT', body: payload });
      else await api('/api/market-chart-points', { method: 'POST', body: payload });
      renderChartPointsList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  VISION ITEMS (چشم‌انداز — About)
// ═══════════════════════════════════════════════
async function renderVisionList() {
  root.innerHTML = `
    ${topbarHtml('vision', '+ آیتم جدید')}
    <main class="page">
      <h2>چشم‌انداز</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderVisionEditor(null));
  try {
    const items = await api('/api/vision-items?limit=200');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز آیتمی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(v => `
      <article class="row" data-id="${escapeAttr(v.id)}">
        <div class="row-main">
          <div class="row-meta">
            ${v.icon ? `<span class="pill">${escapeHtml(v.icon)}</span>` : ''}
            ${v.titleEn ? `<span class="muted">${escapeHtml(v.titleEn)}</span>` : ''}
          </div>
          <h3>${escapeHtml(v.titleFa)}</h3>
          <p class="muted clamp-2">${escapeHtml(v.descFa||'')}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderVisionEditor(await api(`/api/vision-items/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این آیتم حذف شود؟')) return;
        await api(`/api/vision-items/${id}`, { method: 'DELETE' });
        renderVisionList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderVisionEditor(item) {
  const v = item || { icon:'', titleFa:'', titleEn:'', descFa:'', descEn:'', sortOrder:0 };
  const isEdit = !!item;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش آیتم':'آیتم جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>عنوان (فارسی) <input name="titleFa" value="${escapeAttr(v.titleFa)}" required /></label>
        <label>عنوان (انگلیسی) <input name="titleEn" value="${escapeAttr(v.titleEn||'')}" /></label>
        <label>آیکون
          <select name="icon">
            <option value="">—</option>
            ${VISION_ICONS.map(ic=>`<option value="${ic}" ${ic===v.icon?'selected':''}>${ic}</option>`).join('')}
          </select>
        </label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${v.sortOrder||0}" /></label>
        <div class="col span-2"><label>توضیحات (فارسی) <textarea name="descFa" rows="3">${escapeHtml(v.descFa||'')}</textarea></label></div>
        <div class="col span-2"><label>توضیحات (انگلیسی) <textarea name="descEn" rows="3">${escapeHtml(v.descEn||'')}</textarea></label></div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderVisionList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      icon: fd.get('icon')||null,
      titleFa: fd.get('titleFa'), titleEn: fd.get('titleEn')||null,
      descFa: fd.get('descFa')||null, descEn: fd.get('descEn')||null,
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/vision-items/${item.id}`, { method:'PUT', body:payload });
      else await api('/api/vision-items', { method:'POST', body:payload });
      renderVisionList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  ADVISORY BOARD (شورای مشورتی — About)
// ═══════════════════════════════════════════════
async function renderAdvisoryList() {
  root.innerHTML = `
    ${topbarHtml('advisory', '+ عضو جدید')}
    <main class="page">
      <h2>شورای مشورتی</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderAdvisoryEditor(null));
  try {
    const items = await api('/api/advisory-board?limit=200');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز عضوی ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(m => `
      <article class="row" data-id="${escapeAttr(m.id)}">
        <div class="row-avatar">${escapeHtml(m.nameFa?.charAt(0)||'؟')}</div>
        <div class="row-main">
          <div class="row-meta">
            ${m.roleFa ? `<span class="pill">${escapeHtml(m.roleFa)}</span>` : ''}
            ${m.nameEn ? `<span class="muted">${escapeHtml(m.nameEn)}</span>` : ''}
          </div>
          <h3>${escapeHtml(m.nameFa)}</h3>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderAdvisoryEditor(await api(`/api/advisory-board/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این عضو حذف شود؟')) return;
        await api(`/api/advisory-board/${id}`, { method: 'DELETE' });
        renderAdvisoryList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderAdvisoryEditor(member) {
  const m = member || { nameFa:'', nameEn:'', roleFa:'', roleEn:'', sortOrder:0 };
  const isEdit = !!member;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit?'ویرایش عضو':'عضو جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <label>نام (فارسی) <input name="nameFa" value="${escapeAttr(m.nameFa)}" required /></label>
        <label>نام (انگلیسی) <input name="nameEn" value="${escapeAttr(m.nameEn||'')}" /></label>
        <label>سمت (فارسی) <input name="roleFa" value="${escapeAttr(m.roleFa||'')}" /></label>
        <label>سمت (انگلیسی) <input name="roleEn" value="${escapeAttr(m.roleEn||'')}" /></label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${m.sortOrder||0}" /></label>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit?'ذخیره':'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderAdvisoryList());
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      nameFa: fd.get('nameFa'), nameEn: fd.get('nameEn')||null,
      roleFa: fd.get('roleFa')||null, roleEn: fd.get('roleEn')||null,
      sortOrder: Number(fd.get('sortOrder')||0),
    };
    try {
      if (isEdit) await api(`/api/advisory-board/${member.id}`, { method:'PUT', body:payload });
      else await api('/api/advisory-board', { method:'POST', body:payload });
      renderAdvisoryList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ═══════════════════════════════════════════════
//  BANNERS
// ═══════════════════════════════════════════════
const POSITIONS = [
  { value: 'featured',             label: 'صفحه اصلی (زیر رویدادها)' },
  { value: 'glance',               label: 'صفحه در یک نگاه (پایین)' },
  { value: 'media-split',          label: 'صفحه رسانه (بین ویدیو و پادکست)' },
  { value: 'radar-sustainability', label: 'صفحه رادار: پایداری و فولاد سبز' },
  { value: 'radar-geopolitics',    label: 'صفحه رادار: ژئوپلیتیک و اقتصاد جهانی' },
  { value: 'radar-technology',     label: 'صفحه رادار: فناوری و نوآوری' },
  { value: 'radar-market',         label: 'صفحه رادار: بازار و زنجیره فولاد' },
];

async function renderBannersList() {
  root.innerHTML = `
    ${topbarHtml('banners', '+ بنر جدید')}
    <main class="page">
      <h2>بنرها</h2>
      <div id="list" class="list"><p class="muted">در حال بارگذاری…</p></div>
    </main>`;
  wireTabs();
  $('#newBtn').addEventListener('click', () => renderBannerEditor(null));
  try {
    const items = await api('/api/banners');
    if (!items.length) { $('#list').innerHTML = `<p class="muted">هنوز بنری ثبت نشده.</p>`; return; }
    $('#list').innerHTML = items.map(b => `
      <article class="row" data-id="${escapeAttr(b.id)}">
        ${b.image ? `<div class="row-cover" style="background-image:url('${escapeAttr(b.image)}')"></div>` : ''}
        <div class="row-main">
          <div class="row-meta">
            ${b.active ? '<span class="pill green">فعال</span>' : '<span class="pill">غیرفعال</span>'}
            <span class="pill">${escapeHtml(POSITIONS.find(p=>p.value===b.position)?.label || b.position)}</span>
          </div>
          <h3>${escapeHtml(b.titleFa)}</h3>
          <p class="muted clamp-2">${escapeHtml(b.subtitleFa||'')}</p>
        </div>
        <div class="row-actions">
          <button data-action="edit">ویرایش</button>
          <button data-action="delete" class="danger">حذف</button>
        </div>
      </article>`).join('');
    $('#list').addEventListener('click', async ev => {
      const btn = ev.target.closest('button[data-action]'); if (!btn) return;
      const id = btn.closest('.row').dataset.id;
      if (btn.dataset.action === 'edit') renderBannerEditor(await api(`/api/banners/${id}`));
      else if (btn.dataset.action === 'delete') {
        if (!confirm('این بنر حذف شود؟')) return;
        await api(`/api/banners/${id}`, { method: 'DELETE' });
        renderBannersList();
      }
    });
  } catch (err) { $('#list').innerHTML = `<p class="error">خطا: ${escapeHtml(err.message)}</p>`; }
}

function renderBannerEditor(banner) {
  const b = banner || { overlineFa:'', overlineEn:'', titleFa:'', titleEn:'', subtitleFa:'', subtitleEn:'',
    ctaLabelFa:'', ctaLabelEn:'', ctaUrl:'', image:'', position:'featured', active:true, sortOrder:0 };
  const isEdit = !!banner;
  root.innerHTML = `
    <header class="topbar">
      <div class="brand">${isEdit ? 'ویرایش بنر' : 'بنر جدید'}</div>
      <div class="actions"><button id="backBtn" class="ghost">← بازگشت</button></div>
    </header>
    <main class="page editor">
      <form id="editorForm" class="grid">
        <div class="col span-2"><label>برچسب بالای عنوان (فارسی) — مثلاً «ماهنامه شماره ۱۲ منتشر شد…» <input name="overlineFa" value="${escapeAttr(b.overlineFa||'')}" /></label></div>
        <div class="col span-2"><label>برچسب بالای عنوان (انگلیسی) <input name="overlineEn" value="${escapeAttr(b.overlineEn||'')}" /></label></div>
        <label>عنوان (فارسی) <input name="titleFa" value="${escapeAttr(b.titleFa)}" required /></label>
        <label>عنوان (انگلیسی) <input name="titleEn" value="${escapeAttr(b.titleEn||'')}" /></label>
        <div class="col span-2"><label>زیرعنوان (فارسی) <input name="subtitleFa" value="${escapeAttr(b.subtitleFa||'')}" /></label></div>
        <div class="col span-2"><label>زیرعنوان (انگلیسی) <input name="subtitleEn" value="${escapeAttr(b.subtitleEn||'')}" /></label></div>
        <label>متن دکمه (فارسی) <input name="ctaLabelFa" value="${escapeAttr(b.ctaLabelFa||'')}" /></label>
        <label>متن دکمه (انگلیسی) <input name="ctaLabelEn" value="${escapeAttr(b.ctaLabelEn||'')}" /></label>
        <div class="col span-2">
          <label>لینک دکمه <input id="ctaUrl" name="ctaUrl" value="${escapeAttr(b.ctaUrl||'')}" /></label>
          <label style="margin-top:8px">آپلود فایل PDF گزارش (لینک دکمه را پر می‌کند)
            <input type="file" id="pdfFile" accept="application/pdf" />
          </label>
        </div>
        <label>موقعیت
          <select name="position">
            ${POSITIONS.map(p=>`<option value="${p.value}" ${p.value===b.position?'selected':''}>${p.label}</option>`).join('')}
          </select>
        </label>
        <label>ترتیب نمایش <input name="sortOrder" type="number" value="${b.sortOrder||0}" /></label>
        <label class="checkbox col span-2"><input type="checkbox" name="active" ${b.active?'checked':''}><span>فعال (نمایش داده شود)</span></label>
        <div class="col span-2">
          <label>تصویر بنر
            <input id="imageUrl" name="imageUrl" placeholder="/uploads/... یا آپلود کنید" value="${escapeAttr(b.image||'')}" />
          </label>
          <label style="margin-top:8px">آپلود تصویر
            <input type="file" id="imageFile" accept="image/*" />
          </label>
          ${b.image ? `<img src="${escapeAttr(b.image)}" style="margin-top:8px;max-height:160px;border-radius:8px;object-fit:cover" />` : ''}
        </div>
        <div class="col span-2 row-end"><button type="submit" class="primary">${isEdit ? 'ذخیره' : 'ایجاد'}</button></div>
      </form>
    </main>`;
  $('#backBtn').addEventListener('click', () => renderBannersList());
  $('#pdfFile').addEventListener('change', async ev => {
    const file = ev.target.files[0]; if (!file) return;
    const fd = new FormData(); fd.append('file', file);
    try {
      const res = await api('/api/uploads/raw', { method:'POST', body:fd, isForm:true });
      $('#ctaUrl').value = res.url;
    } catch (err) { alert('آپلود PDF ناموفق: ' + err.message); }
  });
  $('#imageFile').addEventListener('change', async ev => {
    const file = ev.target.files[0]; if (!file) return;
    const fd = new FormData(); fd.append('file', file);
    try {
      const res = await api('/api/uploads', { method:'POST', body:fd, isForm:true });
      $('#imageUrl').value = res.url;
    } catch (err) { alert('آپلود ناموفق: ' + err.message); }
  });
  $('#editorForm').addEventListener('submit', async ev => {
    ev.preventDefault();
    const fd = new FormData(ev.target);
    const payload = {
      overlineFa: fd.get('overlineFa') || null,
      overlineEn: fd.get('overlineEn') || null,
      titleFa:    fd.get('titleFa'),
      titleEn:    fd.get('titleEn') || null,
      subtitleFa: fd.get('subtitleFa') || null,
      subtitleEn: fd.get('subtitleEn') || null,
      ctaLabelFa: fd.get('ctaLabelFa') || null,
      ctaLabelEn: fd.get('ctaLabelEn') || null,
      ctaUrl:     fd.get('ctaUrl') || null,
      image:      fd.get('imageUrl') || null,
      position:   fd.get('position') || 'featured',
      active:     fd.get('active') === 'on',
      sortOrder:  Number(fd.get('sortOrder') || 0),
    };
    try {
      if (isEdit) await api(`/api/banners/${banner.id}`, { method:'PUT', body:payload });
      else await api('/api/banners', { method:'POST', body:payload });
      renderBannersList();
    } catch (err) { alert('ذخیره ناموفق: ' + err.message); }
  });
}

// ─────────────────────────────────────────────
function renderImport() {
  root.innerHTML = `
    ${topbarHtml('import', '')}
    <div class="page-body" style="max-width:820px;margin:2rem auto;padding:0 1rem">
      <h2 style="margin-bottom:.25rem">⬇️ ایمپورت از Gemini</h2>
      <p style="color:#888;font-size:.875rem;margin-bottom:1.5rem">
        خروجی JSON که Gemini داد رو اینجا paste کن و دکمه ایمپورت رو بزن.
        گزارش توی <strong>مطالب</strong> و آیتم‌های رادار توی <strong>رادار</strong> ذخیره می‌شن.
      </p>

      <div id="import-status"></div>

      <textarea id="import-json" rows="22" style="
        width:100%;box-sizing:border-box;font-family:monospace;font-size:.8rem;
        border:1.5px solid #ddd;border-radius:8px;padding:1rem;resize:vertical;
        direction:ltr;background:#fafafa;outline:none;
      " placeholder='{ "report": { "id": "...", "title": "...", ... }, "radar_items": [...], "fa_summary_long": "..." }'></textarea>

      <div style="display:flex;gap:.75rem;margin-top:1rem;align-items:center">
        <button id="import-btn" class="primary" style="padding:.7rem 2rem;font-size:1rem">ایمپورت</button>
        <button id="import-clear" class="ghost">پاک کردن</button>
        <span id="import-count" style="color:#aaa;font-size:.82rem"></span>
      </div>

      <div id="import-result" style="margin-top:1.5rem"></div>
    </div>
  `;

  setupTopbar();

  const jsonTA  = document.getElementById('import-json');
  const statusEl = document.getElementById('import-status');
  const resultEl = document.getElementById('import-result');
  const countEl  = document.getElementById('import-count');

  jsonTA.addEventListener('input', () => {
    try {
      const d = JSON.parse(jsonTA.value);
      const ra = d.radar_items?.length || 0;
      countEl.textContent = `✓ JSON معتبر — گزارش: ${d.report?.title ? '1' : '0'} | رادار: ${ra}`;
      countEl.style.color = '#22c55e';
    } catch {
      countEl.textContent = 'JSON نامعتبر';
      countEl.style.color = '#ef4444';
    }
  });

  document.getElementById('import-clear').onclick = () => {
    jsonTA.value = ''; countEl.textContent = ''; resultEl.innerHTML = '';
  };

  document.getElementById('import-btn').onclick = async () => {
    let data;
    try { data = JSON.parse(jsonTA.value); }
    catch { statusEl.innerHTML = '<div class="alert alert-error">JSON نامعتبر است</div>'; return; }

    const btn = document.getElementById('import-btn');
    btn.disabled = true; btn.textContent = 'در حال ایمپورت...';
    statusEl.innerHTML = '';

    try {
      const result = await api('/api/admin/import', { method:'POST', body: data });

      resultEl.innerHTML = `
        <div style="background:#f0fdf4;border:1px solid #bbf7d0;border-radius:10px;padding:1.25rem 1.5rem">
          <div style="font-weight:700;color:#166534;font-size:1rem;margin-bottom:.75rem">✓ ایمپورت موفق</div>
          <div style="display:flex;flex-direction:column;gap:.4rem;font-size:.875rem;color:#166534">
            <div>📄 گزارش: <code style="background:#dcfce7;padding:2px 6px;border-radius:4px">${result.article}</code></div>
            ${result.radar.length ? `<div>🔭 آیتم‌های رادار: ${result.radar.length} مورد اضافه شد</div>` : ''}
          </div>
          <div style="margin-top:1rem;display:flex;gap:.5rem">
            <a href="#" onclick="document.querySelector('[data-tab=articles]').click();return false"
               style="font-size:.8rem;color:#16a34a;text-decoration:underline">مشاهده در مطالب ←</a>
            ${result.radar.length ? `<a href="#" onclick="document.querySelector('[data-tab=radar]').click();return false"
               style="font-size:.8rem;color:#16a34a;text-decoration:underline">مشاهده در رادار ←</a>` : ''}
          </div>
        </div>
      `;
      jsonTA.value = ''; countEl.textContent = '';
    } catch (err) {
      statusEl.innerHTML = `<div class="alert alert-error">خطا: ${err.message}</div>`;
    } finally {
      btn.disabled = false; btn.textContent = 'ایمپورت';
    }
  };
}

// ─────────────────────────────────────────────
api('/api/auth/me').then(() => renderRadarList()).catch(() => renderLogin());
