/* global React, ReactDOM */
const { useState: useStateM, useEffect: useEffectM, useRef: useRefM } = React;

// ===== Trust Map — expanded rating card inside profile modal =====
// Three universal criteria (Independence / Transparency / Accuracy) shown as
// a full design block — replaces the previously collapsed <details>.
// Same data shape as RatingMicro in components-catalog.jsx.
const TRUST_DEF = [
  { k: 'independence', icon: '🛡', label: 'Независимость', hint: 'от рекламодателей и брокеров',  anchor: 'independence' },
  { k: 'transparency', icon: '🔍', label: 'Прозрачность',  hint: 'открытость сделок и методологии', anchor: 'transparency' },
  { k: 'accuracy',     icon: '🎯', label: 'Достоверность', hint: 'точность прогнозов и фактов',     anchor: 'accuracy' },
];

function bucketScore(s) {
  const n = Number(s) || 0;
  if (n <= 0) return 'empty';
  if (n >= 3.5) return 'high';
  if (n >= 2)   return 'mid';
  return 'low';
}

function TrustMap({ rb, overall }) {
  const [tipOpen, setTipOpen] = useStateM(false);
  // Тултип-пояснение к рейтингу: закрываем по клику вне и по Escape (важно для мобилы,
  // где нет hover). Клик по самому блоку «.tg-trust-label» не закрывает.
  useEffectM(() => {
    if (!tipOpen) return undefined;
    const onDoc = (e) => { if (!e.target.closest('.tg-trust-label')) setTipOpen(false); };
    const onEsc = (e) => e.key === 'Escape' && setTipOpen(false);
    document.addEventListener('click', onDoc);
    document.addEventListener('keydown', onEsc);
    return () => { document.removeEventListener('click', onDoc); document.removeEventListener('keydown', onEsc); };
  }, [tipOpen]);

  if (!rb) return null;
  // Overall scale: 15 segments (3 sections × 5). Each segment lights up
  // proportionally to the average score. Bucketed color matches the row colors.
  const overallBucket = bucketScore(overall);
  const filled = Math.max(0, Math.min(15, Math.round((Number(overall)||0) * 3)));

  return (
    <div className="tg-trust-map">
      <div className="tg-trust-label">
        <span className="tg-trust-label-text">Рейтинг</span>
        <button
          type="button"
          className="tg-trust-info"
          aria-label="Как мы считаем рейтинг"
          aria-expanded={tipOpen}
          onClick={(e) => { e.stopPropagation(); setTipOpen(v => !v); }}
        >i</button>
        {tipOpen && (
          <div className="tg-trust-tip" role="tooltip">
            Независимая оценка редакции. Мы сами проверяем каждого автора по трём
            критериям — независимость, прозрачность и достоверность. Это не реклама
            и не самооценка блогера.
          </div>
        )}
      </div>

      <div className="tg-trust-head">
        <div className="tg-trust-score" aria-label={`Итоговый рейтинг ${Number(overall).toFixed(1)} из 5`}>
          <span className="tg-trust-score-num">{Number(overall).toFixed(1)}</span>
          <span className="tg-trust-score-suffix">/ 5</span>
        </div>
        <div className="tg-trust-scale">
          <div className="tg-trust-scale-bar" aria-hidden="true">
            {Array.from({length:15}).map((_, i) => (
              <span key={i} className="tg-trust-scale-seg"
                data-fill={i < filled ? overallBucket : undefined} />
            ))}
          </div>
        </div>
      </div>

      <div className="tg-trust-list">
        {TRUST_DEF.map(c => {
          const item = rb[c.k] || {};
          const score = Number(item.score) || 0;
          const bucket = bucketScore(score);
          const pct = Math.max(0, Math.min(100, (score / 5) * 100));
          return (
            <div key={c.k} className="tg-trust-row">
              <div className="tg-trust-icon-wrap">
                <div className="tg-trust-icon" data-bucket={bucket} aria-hidden="true">{c.icon}</div>
              </div>
              <div className="tg-trust-text">
                <div className="tg-trust-name">{c.label}</div>
                <div className="tg-trust-hint">{c.hint}</div>
              </div>
              <div className="tg-trust-score-cell num" data-bucket={bucket}>
                {score > 0 ? score.toFixed(1) : '—'}<span className="sl">/5</span>
              </div>
              <div className="tg-trust-bar" aria-hidden="true">
                <span className="tg-trust-bar-fill"
                  data-bucket={bucket}
                  style={{"--fill": pct + '%', width: pct + '%'}} />
              </div>
            </div>
          );
        })}
      </div>

    </div>
  );
}

window.TrustMap = TrustMap;

// ===== Profile Modal (Telegram-style) =====
function ProfileModal({ blogger, onClose }) {
  useEffectM(() => {
    if (!blogger) return undefined;
    const onEsc = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", onEsc);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onEsc); document.body.style.overflow = prev; };
  }, [blogger, onClose]);

  if (!blogger) return null;
  const b = blogger;

  return (
    <div className={"modal-overlay " + (b ? "active":"")} onClick={onClose}>
      <div className="profile-modal" onClick={(e)=>e.stopPropagation()}>
        <button className="modal-close" onClick={onClose} aria-label="Закрыть">×</button>

        <div className="tg-header" style={{"--prof-c": b.color}}>
          <div className="tg-top">
            <window.Avatar b={b} size={72} radius={999} className="tg-avatar" />
            <div className="tg-name-block">
              <h2>
                {b.name}
                {b.verified && (
                  <span className="verified-badge" aria-label="Верифицирован" title="Верифицирован">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                  </span>
                )}
              </h2>
              <div className="tg-handle">{b.handle}</div>
              <div className="tg-status"><span className="online-dot"></span>активен сегодня</div>
              {(() => {
                // «Золотая рамка» — внутренний админский тег (управляет рамкой карточки),
                // клиентам как бейдж не показываем. Зеркалит фильтр в каталоге.
                const visibleBadges = (Array.isArray(b.badges) ? b.badges : [])
                  .filter(x => !(typeof x === "string" && /Золотая\s+рамка/i.test(x)));
                if (visibleBadges.length === 0) return null;
                return (
                  <div className="tg-badges">
                    {visibleBadges.map((bg, i) => <span key={i} className="tg-badge">{bg}</span>)}
                  </div>
                );
              })()}
            </div>
          </div>
          <div className="tg-meta-row">
            <span className="tg-meta-pill"><span className="star">★</span> {b.rating}</span>
            <span className="tg-meta-pill">с {b.since}</span>
            <span className="tg-meta-pill">{window.fmtK(b.totalSubs)} подписчиков</span>
          </div>
        </div>

        <div className="tg-body">
          <div className="tg-section">
            <div className="tg-section-label">Об авторе</div>
            <p className="tg-bio">{b.bio}</p>
          </div>

          <div className="tg-section">
            <div className="tg-section-label">Специализация</div>
            <div className="tg-specs">
              {b.specs.map(s => <span key={s} className="spec-pill">{s}</span>)}
            </div>
          </div>

          {b.ratingBreakdown && (
            <div className="tg-section">
              <TrustMap rb={b.ratingBreakdown} overall={Number(b.rating)||0} />
            </div>
          )}

          {Array.isArray(b.strengths) && b.strengths.length > 0 && (
            <div className="tg-section">
              <div className="tg-section-label">Сильные стороны</div>
              <div className="tg-strengths">
                {b.strengths.map((s, i) => (
                  <span key={i} className="tg-strength-tag">
                    <span className="tg-strength-ico" aria-hidden="true">
                      {window.TrustIcon ? <window.TrustIcon slug={s.icon} /> : '✓'}
                    </span>
                    {s.label}
                  </span>
                ))}
              </div>
            </div>
          )}

          {Array.isArray(b.attentionPoints) && b.attentionPoints.length > 0 && (
            <div className="tg-section">
              <div className="tg-section-label">На что обратить внимание</div>
              <ul className="tg-attention-list">
                {b.attentionPoints.map((a, i) => (
                  <li key={i} className="tg-attention-item">{a.label}</li>
                ))}
              </ul>
            </div>
          )}

          {Array.isArray(b.articles) && b.articles.length > 0 && (
            <div className="tg-section">
              <div className="tg-section-label">Статьи с участием</div>
              <ul className="tg-articles-list">
                {b.articles.map((art, i) => (
                  <li key={i} className="tg-articles-item">
                    <a href={`/zhurnal/${art.slug}`} target="_blank" rel="noopener">
                      <span className="tg-articles-title">{art.title}</span>
                      {art.published_at && (
                        <span className="tg-articles-date">
                          {new Date(art.published_at).toLocaleDateString('ru-RU', {day:'numeric',month:'short',year:'numeric'})}
                        </span>
                      )}
                    </a>
                  </li>
                ))}
              </ul>
            </div>
          )}

          <div className="tg-section">
            <div className="tg-section-label">Статистика</div>
            <div className="tg-stats" style={{gridTemplateColumns:"repeat(2,1fr)"}}>
              <div className="tg-stat">
                <div className="tg-stat-num num accent">{window.fmtK(b.totalSubs)}</div>
                <div className="tg-stat-lab">Подписчиков</div>
              </div>
              <div className="tg-stat">
                <div className="tg-stat-num num">{b.rating}</div>
                <div className="tg-stat-lab">Рейтинг</div>
              </div>
            </div>
          </div>

          <div className="tg-section">
            <div className="tg-section-label">Площадки</div>
            <div className="tg-platforms">
              {(b.channels && b.channels.length ? b.channels : b.platforms).map((p, i) => (
                <a key={i} className="tg-platform" href={p.url} target="_blank" rel="noopener">
                  <div className="tg-plat-icon" data-p={p.k}>
                    <window.PlatIcon p={p.k} size={22} />
                  </div>
                  <div className="tg-plat-body">
                    <div className="tg-plat-name">{p.name}</div>
                    <div className="tg-plat-handle">{p.handle || b.handle}</div>
                  </div>
                  <div className="tg-plat-subs num">
                    {window.fmtK(p.subs)}
                    <span className="sl">Подписчиков</span>
                  </div>
                </a>
              ))}
            </div>
          </div>

          {Array.isArray(b.trust && b.trust.cards) && b.trust.cards.length > 0 && (
            <div className="tg-section">
              <div className="tg-section-label">Доверие и проверка</div>
              <div className="tg-trust-grid">
                {b.trust.cards.map((card, i) => (
                  <div key={i} className="tg-trust-cell">
                    <div className="tg-trust-icon"><window.TrustIcon slug={card.icon} /></div>
                    <div>
                      <div className="tg-trust-lab">{card.title}</div>
                      <div className="tg-trust-val">{card.body}</div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ===== Add Blogger Form (contact-only) =====
function AddBloggerModal({ open, onClose, kind }) {
  const isPartner = kind === "partner";
  const [contact, setContact] = useStateM("");
  const [consent, setConsent] = useStateM(false);
  const [submitted, setSubmitted] = useStateM(false);
  const [sending, setSending] = useStateM(false);
  const [errorMsg, setErrorMsg] = useStateM("");
  const [attempted, setAttempted] = useStateM(false);
  const inputRef = useRefM(null);

  useEffectM(() => {
    if (!open) {
      setContact(""); setConsent(false); setSubmitted(false);
      setSending(false); setErrorMsg(""); setAttempted(false);
    }
  }, [open]);

  // autofocus the contact field as soon as the modal opens
  useEffectM(() => {
    if (!open) return;
    const t = setTimeout(() => inputRef.current?.focus?.(), 60);
    return () => clearTimeout(t);
  }, [open]);

  if (!open) return null;

  const ready = contact.trim().length >= 2 && consent;

  // Подсказка под кнопкой — чтобы юзер видел, чего не хватает.
  const blockerHint = () => {
    if (contact.trim().length < 2) return "Укажите контакт для связи.";
    if (!consent) return "Поставьте галочку согласия на обработку ПД.";
    return "";
  };

  const focusFirstInvalid = () => {
    if (contact.trim().length < 2) inputRef.current?.focus?.();
  };

  const submit = async () => {
    setErrorMsg("");
    setSending(true);
    const payload = { contact: contact.trim(), consent: true, type: isPartner ? "partner" : "blogger" };
    try {
      const res = await fetch("/api/submit-blogger", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok && data.ok) {
        setSubmitted(true);
        setTimeout(() => onClose(), 2800);
      } else {
        setErrorMsg((data.errors && data.errors[0]?.message) || data.message || "Не удалось отправить. Попробуйте позже.");
      }
    } catch (_err) {
      setErrorMsg("Проблемы с сетью. Попробуйте ещё раз.");
    } finally {
      setSending(false);
    }
  };

  const trySubmit = () => {
    if (sending) return;
    if (ready) { submit(); }
    else { setAttempted(true); focusFirstInvalid(); }
  };

  const onKeyDown = (e) => {
    if (e.key !== 'Enter') return;
    e.preventDefault();
    trySubmit();
  };

  return (
    <div className={"modal-overlay active"} onClick={onClose}>
      <div className="form-modal" onClick={(e)=>e.stopPropagation()}>
        <button className="modal-close" onClick={onClose} aria-label="Закрыть">×</button>

        {submitted ? (
          <div style={{textAlign:"center",padding:"30px 0"}}>
            <div style={{width:64,height:64,borderRadius:"50%",background:"rgba(38,217,127,0.15)",border:"1px solid var(--green)",display:"grid",placeItems:"center",margin:"0 auto 18px"}}>
              <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#26d97f" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
            </div>
            <h2 style={{marginBottom:8}}>Заявка отправлена</h2>
            <p style={{color:"var(--text-2)",fontSize:14}}>{isPartner ? "Спасибо! Свяжемся с вами в Telegram по сотрудничеству." : "Мы проверим данные в течение 1–2 дней и свяжемся в Telegram."}</p>
          </div>
        ) : (
          <>
            <h2>{isPartner ? "Обсудить сотрудничество" : "Добавить блогера в базу"}</h2>
            <p className="form-sub">{isPartner ? "Партнёрство с авторами ИнвестБлогеров" : "Размещение бесплатное. Модерация 1–2 дня."}</p>
            <p style={{color:"var(--text-2)",fontSize:13.5,lineHeight:1.55,margin:"0 0 18px"}}>
              {isPartner ? "Оставьте контакт — расскажем, как работаем с брендами, и подберём авторов." : "Оставьте контакт — мы свяжемся и уточним детали."}
            </p>

            <div onKeyDown={onKeyDown}>
              <div className="form-group">
                <label>Как с вами связаться? <span className="req">*</span></label>
                <input ref={inputRef} className="form-input" type="text" value={contact} onChange={e=>setContact(e.target.value)}
                  placeholder="@username в Telegram, email или телефон" maxLength="100"/>
              </div>
              <label style={{display:"flex",alignItems:"flex-start",gap:10,padding:"12px 14px",border:"1px solid var(--border)",borderRadius:8,background:"rgba(255,255,255,0.02)",cursor:"pointer",fontSize:13,lineHeight:1.5,color:"var(--text-2)"}}>
                <input type="checkbox" checked={consent} onChange={e=>setConsent(e.target.checked)} style={{marginTop:2,flexShrink:0}}/>
                <span>
                  Я даю согласие на обработку персональных данных в соответствии с
                  {' '}<a href="/privacy.html" target="_blank" rel="noopener" style={{color:"var(--green)",textDecoration:"underline"}}>Политикой обработки ПД</a>
                  {' '}и принимаю условия
                  {' '}<a href="/terms.html" target="_blank" rel="noopener" style={{color:"var(--green)",textDecoration:"underline"}}>Пользовательского соглашения</a>.
                </span>
              </label>
              {errorMsg && <div style={{color:"var(--red)",fontSize:13,marginTop:8}}>{errorMsg}</div>}
            </div>

            {!ready && blockerHint() && (
              <div className={"form-warn " + (attempted ? "form-warn-loud" : "")} role={attempted ? "alert" : undefined}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
                <span>{blockerHint()}</span>
              </div>
            )}
            <div className="form-actions">
              <div></div>
              <button className="btn btn-primary" data-state={ready && !sending ? "ready" : "tentative"} onClick={trySubmit} disabled={sending}>
                {sending ? "Отправляем..." : "Отправить заявку"}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

// ===== Footer =====
function Footer() {
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-grid">
          <div className="footer-brand">
            <a href="#" className="brand">
              <img src="/logo.svg" alt="" className="brand-logo-img" width="32" height="32" />
              Инвест Блогеры
            </a>
            <p>Каталог проверенных инвест-авторов. С 2015 года на рынке инвест-контента.</p>
          </div>
          <div className="footer-col">
            <h4>Каталог</h4>
            <a href="#catalog">Все авторы</a>
            <a href="#rankings">Рейтинг</a>
            <a href="#collections">Подборки</a>
          </div>
          <div className="footer-col">
            <h4>Проект</h4>
            <a href="#about">О нас</a>
            <a href="/terms.html">Пользовательское соглашение</a>
            <a href="/privacy.html">Политика обработки ПД</a>
          </div>
          <div className="footer-col">
            <h4>Контакты</h4>
            <a href="https://t.me/investbloggers_manager" target="_blank" rel="noopener">Telegram</a>
            <a href="mailto:hello@investbloggers.ru">Email</a>
          </div>
        </div>
        <div className="footer-disclaimer" style={{marginTop:24,padding:"16px 0",borderTop:"1px solid var(--border)",color:"var(--text-3)",fontSize:12,lineHeight:1.6}}>
          Информация на сайте носит справочный характер и не является индивидуальной инвестиционной рекомендацией в смысле Федерального закона № 39-ФЗ «О рынке ценных бумаг». Размещение блогера в каталоге не означает оценки его компетенции Администрацией. Решения об инвестициях принимайте самостоятельно или после консультации с лицензированным финансовым советником.
        </div>
        <div className="footer-bottom">
          <span>© 2015–2026 Инвест Блогеры · Все права защищены</span>
          <a className="support-link" href="https://t.me/investbloggers_manager" target="_blank" rel="noopener">
            <window.PlatIcon p="tg" size={13}/> Поддержка
          </a>
        </div>
      </div>
    </footer>
  );
}

// ===== Audit Overlay =====
function AuditOverlay({ open, onClose }) {
  const findings = window.AUDIT_FINDINGS;
  if (!open) return null;
  return (
    <div className="modal-overlay active" onClick={onClose} style={{alignItems:"center"}}>
      <div className="form-modal" onClick={e=>e.stopPropagation()} style={{maxWidth:640}}>
        <button className="modal-close" onClick={onClose}>×</button>
        <div style={{display:"inline-flex",alignItems:"center",gap:8,padding:"4px 10px",borderRadius:999,background:"rgba(245,185,66,0.12)",border:"1px solid rgba(245,185,66,0.3)",fontFamily:"var(--mono)",fontSize:10,letterSpacing:"0.12em",color:"var(--amber)",fontWeight:700,marginBottom:14}}>
          UX/UI АУДИТ · 12 НАБЛЮДЕНИЙ
        </div>
        <h2>Что не так с текущим сайтом</h2>
        <p className="form-sub">Ключевые проблемы и решения, применённые в редизайне</p>
        <div style={{maxHeight:"55vh",overflowY:"auto",margin:"0 -8px",padding:"0 8px"}}>
          {findings.map((f, i) => (
            <div key={i} style={{padding:"14px 0",borderBottom:"1px solid var(--border)"}}>
              <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:6}}>
                <span style={{fontFamily:"var(--mono)",fontSize:11,fontWeight:800,color:"var(--text-3)"}}>{String(i+1).padStart(2,"0")}</span>
                <span style={{padding:"2px 8px",borderRadius:999,fontSize:10,fontFamily:"var(--mono)",fontWeight:700,letterSpacing:"0.08em",background:f.sev==="high"?"rgba(255,87,87,0.15)":f.sev==="med"?"rgba(245,185,66,0.15)":"rgba(38,217,127,0.15)",color:f.sev==="high"?"#ff8080":f.sev==="med"?"var(--amber)":"var(--green)",border:"1px solid currentColor"}}>
                  {f.sev==="high"?"КРИТИЧНО":f.sev==="med"?"ВАЖНО":"УЛУЧШЕНИЕ"}
                </span>
                <h4 style={{fontSize:14,fontWeight:700}}>{f.title}</h4>
              </div>
              <p style={{fontSize:13,color:"var(--text-2)",lineHeight:1.55,marginBottom:4}}><b style={{color:"var(--red)"}}>Было:</b> {f.before}</p>
              <p style={{fontSize:13,color:"var(--text-2)",lineHeight:1.55}}><b style={{color:"var(--green)"}}>Стало:</b> {f.after}</p>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ===== Collection Modal (podium of 1st/2nd/3rd + rest-list) =====
function CollectionModal({ data, onClose, onOpenProfile }) {
  useEffectM(() => {
    if (!data) return undefined;
    const onEsc = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", onEsc);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onEsc); document.body.style.overflow = prev; };
  }, [data, onClose]);

  if (!data) return null;
  const { c, authors } = data;
  const podium = (authors || []).slice(0, 3);
  const rest = (authors || []).slice(3);
  const medals = [
    { cls: "gold",   label: "1 место", icon: "★" },
    { cls: "silver", label: "2 место", icon: "★" },
    { cls: "bronze", label: "3 место", icon: "★" },
  ];

  const handleOpen = (b) => { onClose(); setTimeout(() => onOpenProfile(b), 50); };

  return (
    <div className="modal-overlay active" onClick={onClose}>
      <div className="coll-modal" onClick={(e)=>e.stopPropagation()} style={{"--coll-c": c.accent}}>
        <button className="modal-close" onClick={onClose} aria-label="Закрыть">×</button>

        <div className="cm-header">
          <div className="cm-kicker">
            <span className="cm-hero num">{c.hero}</span>
            <span>Подборка · {c.count} {window.plur(c.count,"автор","автора","авторов")}</span>
          </div>
          <h2 className="cm-title">{c.title}</h2>
          <p className="cm-sub">{c.sub}</p>
        </div>

        {podium.length > 0 && (
          <div className="cm-podium" data-count={podium.length}>
            {podium.map((b, i) => (
              <button key={b.id} className={"cm-slot slot-" + medals[i].cls} onClick={()=>handleOpen(b)}>
                <span className="cm-medal">{medals[i].icon}<span>{medals[i].label}</span></span>
                <window.Avatar b={b} size={80} radius={999} className="cm-slot-avatar" />
                <div className="cm-slot-name">{b.name}</div>
                <div className="cm-slot-handle">{b.handle}</div>
                <div className="cm-slot-subs num">{window.fmtK(b.totalSubs)}<span>подписчиков</span></div>
                <div className="cm-slot-platforms">
                  {(b.platforms || []).slice(0,3).map((p, j) => (
                    <span key={j} className="cm-plat" data-p={p.k}><window.PlatIcon p={p.k} size={12}/></span>
                  ))}
                </div>
              </button>
            ))}
          </div>
        )}

        {rest.length > 0 && (
          <div className="cm-rest">
            <div className="cm-rest-label">Ещё в подборке · {rest.length}</div>
            <div className="cm-rest-list">
              {rest.map((b, i) => (
                <button key={b.id} className="cm-row" onClick={()=>handleOpen(b)}>
                  <span className="cm-row-rank num">#{String(i+4).padStart(2,"0")}</span>
                  <window.Avatar b={b} size={36} radius={10} className="cm-row-avatar" />
                  <div className="cm-row-body">
                    <div className="cm-row-name">{b.name}</div>
                    <div className="cm-row-handle">{b.handle}{(b.specs||[])[0] ? ' · ' + (b.specs||[])[0] : ''}</div>
                  </div>
                  <div className="cm-row-subs num">{window.fmtK(b.totalSubs)}</div>
                </button>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ===== Partners Modal (все партнёры карточками) =====
function PartnersModal({ open, partners = [], onClose }) {
  useEffectM(() => {
    if (!open) return undefined;
    const onEsc = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", onEsc);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onEsc); document.body.style.overflow = prev; };
  }, [open, onClose]);

  if (!open) return null;

  const SOCIAL_NAMES = {
    tg: 'Telegram', yt: 'YouTube', vk: 'VKontakte', ig: 'Instagram',
    rt: 'RuTube', dz: 'Дзен', mx: 'Max', sl: 'Smart-Lab', ps: 'Пульс',
  };

  const Card = (p, i) => {
    const logo = p.logoCard || p.logo;
    const style = { "--accent": p.accent || "#26d97f" };
    const socials = Array.isArray(p.socials) ? p.socials : [];
    const interactive = !!p.url || socials.length > 0;
    return (
      <div key={i} className={"pm-card" + (interactive ? " is-interactive" : "")} style={style}>
        <span className="pm-logo-wrap">
          {logo
            ? <img className="pm-logo" src={logo} alt={p.name} loading="lazy" />
            : <span className="pm-logo-fallback">{p.name}</span>}
        </span>
        {p.desc ? <span className="pm-desc">{p.desc}</span> : null}
        {socials.length > 0 && (
          <div className="pm-socials">
            {socials.map((s, j) => (
              <a key={j} className="pm-social" data-p={s.k} href={s.url}
                 target="_blank" rel="noopener"
                 aria-label={SOCIAL_NAMES[s.k] || s.k} title={SOCIAL_NAMES[s.k] || s.k}>
                <window.PlatIcon p={s.k} size={16} />
              </a>
            ))}
          </div>
        )}
        {p.url ? <a className="pm-link" href={p.url} target="_blank" rel="noopener">Перейти на сайт →</a> : null}
      </div>
    );
  };

  return (
    <div className="modal-overlay active" onClick={onClose}>
      <div className="coll-modal pm-modal" onClick={(e)=>e.stopPropagation()} style={{"--coll-c": "#26d97f"}}>
        <button className="modal-close" onClick={onClose} aria-label="Закрыть">×</button>

        <div className="cm-header">
          <div className="cm-kicker"><span>Партнёры · {partners.length}</span></div>
          <h2 className="cm-title">Наши партнёры</h2>
          <p className="cm-sub">Компании и медиа, с которыми мы сотрудничаем и которым доверяем.</p>
        </div>

        <div className="pm-grid">
          {partners.map(Card)}
        </div>
      </div>
    </div>
  );
}

// ===== Channel Promo Popup =====
// Всплывающая карточка снизу справа с приглашением в Telegram-канал.
// Появляется через 5 сек после загрузки; при закрытии (× или клик по кнопке)
// факт пишется в cookie на 3 дня — повторно не показываем.
const PROMO_COOKIE = 'ib_channel_promo';
function getCookieM(n){ const m = document.cookie.match('(?:^|; )' + n + '=([^;]*)'); return m ? decodeURIComponent(m[1]) : null; }
function setCookieM(n, v, days){
  const d = new Date(); d.setTime(d.getTime() + days * 864e5);
  document.cookie = n + '=' + encodeURIComponent(v) + ';expires=' + d.toUTCString() + ';path=/;SameSite=Lax';
}

function ChannelPopup() {
  const [visible, setVisible] = useStateM(false);
  useEffectM(() => {
    if (getCookieM(PROMO_COOKIE)) return undefined;
    const t = setTimeout(() => setVisible(true), 5000);
    return () => clearTimeout(t);
  }, []);
  if (!visible) return null;
  const url = window.CHANNEL_URL || "https://t.me/+nVDrQTEWb40xOGJl";
  const dismiss = () => { setCookieM(PROMO_COOKIE, '1', 3); setVisible(false); };
  return (
    <div className="tg-promo" role="dialog" aria-label="Подписаться на Telegram-канал">
      <button className="tg-promo-close" onClick={dismiss} aria-label="Закрыть">×</button>
      <div className="tg-promo-head">
        <img src="/logo.svg" alt="" className="tg-promo-logo" />
        <span>Инвест Блогеры</span>
      </div>
      <p className="tg-promo-text">Подписывайся на телеграм-канал Инвестблогера, ещё больше интересного контента тут.</p>
      <a className="btn btn-primary tg-promo-cta" href={url} target="_blank" rel="noopener" onClick={dismiss}>
        <window.PlatIcon p="tg" size={16} /> Подписаться в Telegram
      </a>
    </div>
  );
}

window.ProfileModal = ProfileModal;
window.CollectionModal = CollectionModal;
window.PartnersModal = PartnersModal;
window.AddBloggerModal = AddBloggerModal;
window.Footer = Footer;
window.AuditOverlay = AuditOverlay;
window.ChannelPopup = ChannelPopup;

// ===== AUDIT FINDINGS =====
window.AUDIT_FINDINGS = [
  { sev:"high", title:"Нет визуальной иерархии и WOW-фактора", before:"Блочная сетка карточек без акцентов, статичный фон, никакой визуальной подписи.", after:"Терминальная эстетика Bloomberg/Terminal: живые свечи, тикер-лента, монохромно-зелёный акцент, крупная типографика." },
  { sev:"high", title:"Неясно, для кого сайт", before:"Заголовок «Каталог инвест-блогеров» не объясняет, в чём ценность и для кого.", after:"3 явные роли в hero: подписчику / автору / рекламодателю — каждая ведёт к своему сценарию." },
  { sev:"high", title:"Карточка блогера не внушает доверия", before:"Только имя, платформы, подписчики — нет признаков живого канала или экспертности.", after:"Добавлены: рейтинг, sparkline-активности, trust-панель (посты, частота, реклама), специализации, верификация." },
  { sev:"high", title:"Нет умного поиска", before:"Только фильтры по тегам. Нельзя спросить «дивиденды с YouTube 100K+».", after:"AI-поиск на Claude: понимает запросы на естественном языке, возвращает объяснение + список авторов." },
  { sev:"med", title:"Иконки соцсетей обезличены", before:"Один общий серый значок на все платформы — неразличимо.", after:"Настоящие брендированные иконки Telegram/YouTube/VK/Дзен с фирменными цветами." },
  { sev:"med", title:"Подборки — декоративные, нерабочие", before:"Плоские карточки с текстом, без данных кто входит в подборку.", after:"Коллекции с аватарами авторов, count, кураторской подписью; клик открывает фильтрованный каталог." },
  { sev:"med", title:"Нет рейтинга / топа", before:"Все блогеры на одной полке — невозможно понять, кто топ.", after:"Отдельная секция «Лидеры по охвату» с ранжированием, горизонтальной каруселью и 8 топ-карточек." },
  { sev:"med", title:"Форма добавления — скучный лонгформ", before:"Длинная форма «всё сразу», высокий барьер.", after:"3 шага с прогрессом + сегментированный переключатель роли (подписчик / автор / продюсер)." },
  { sev:"med", title:"Мобильные фильтры занимают экран", before:"Боковая колонка фильтров везде, на мобильном душит каталог.", after:"Sticky desktop + bottom-sheet toggle на мобильном с счётчиком активных фильтров." },
  { sev:"low", title:"Мёртвый hero без движения", before:"Статичный фон, нет ощущения «живых инвестиций».", after:"Лёгкая визуализация свечного графика + пульсирующий LIVE-индикатор + бегущая строка тикеров." },
  { sev:"low", title:"Одинаковые CTA всюду", before:"Везде «Добавить блогера» — не учитывает контекст.", after:"3 раздельных CTA-плитки внизу: для авторов / рекламодателей / помощь." },
  { sev:"low", title:"Отсутствие профиля автора", before:"Клик на карточку ведёт сразу на Telegram — теряем пользователя.", after:"Полный TG-style профиль со всей инфой, площадками, доверием и кнопкой перехода." }
];
