/* ============================================================
   auth.jsx — ПРОТОТИП авторизации (mock-бэкенд).
   Реализует UX по ТЗ: вход по номеру телефона с кодом страны,
   пароль задаёт пользователь, подтверждение через SMS (2FA),
   договор оферты нужно прочитать и нажать «Согласен» до оплаты.

   ВНИМАНИЕ — это фронтенд-прототип:
   · пользователи хранятся в localStorage (не в БД);
   · SMS не отправляются — код показывается в модалке (демо);
   · пароль хешируется SHA-256 на клиенте лишь чтобы не держать
     его в открытом виде; в бою хеширование/соль — на сервере.
   Для продакшена нужен backend + реальный SMS-провайдер; точки
   подключения помечены комментарием  // BACKEND:.
   ============================================================ */

const AUTH_USERS_KEY = "al_users_v1";
const AUTH_SESSION_KEY = "al_session_v1";

/* коды стран для селектора (value = ISO, чтобы +7 RU и +7 KZ различались) */
const COUNTRY_CODES = [
  { iso: "RU", code: "+7",   name: "Россия" },
  { iso: "KZ", code: "+7",   name: "Казахстан" },
  { iso: "BY", code: "+375", name: "Беларусь" },
  { iso: "UA", code: "+380", name: "Украина" },
  { iso: "UZ", code: "+998", name: "Узбекистан" },
  { iso: "KG", code: "+996", name: "Кыргызстан" },
  { iso: "CN", code: "+86",  name: "中国" },
  { iso: "US", code: "+1",   name: "USA/Canada" },
  { iso: "GB", code: "+44",  name: "UK" },
  { iso: "DE", code: "+49",  name: "Germany" },
  { iso: "AE", code: "+971", name: "UAE" },
];
const isoToCode = (iso) => (COUNTRY_CODES.find((c) => c.iso === iso) || COUNTRY_CODES[0]).code;

/* ---- SHA-256 (см. примечание в шапке) ---- */
async function sha256(str) {
  const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(str));
  return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");
}

/* ---- store ---- */
function _loadUsers() { try { return JSON.parse(localStorage.getItem(AUTH_USERS_KEY) || "{}"); } catch (e) { return {}; } }
function _saveUsers(u) { try { localStorage.setItem(AUTH_USERS_KEY, JSON.stringify(u)); } catch (e) {} }

const _authSubs = new Set();
function _notifyAuth() { _authSubs.forEach((fn) => fn()); }

const normalizePhone = (iso, raw) => isoToCode(iso) + String(raw || "").replace(/\D/g, "");
const gen6 = () => String(Math.floor(100000 + Math.random() * 900000));

/* authApi — backend-first, с localStorage как кэшем/фолбэком.
   Когда сервер (backend/server.py) доступен, авторизация и покупки идут
   через него; локальное хранилище служит синхронным кэшем текущего
   пользователя, чтобы useAuth/Learn/шапка работали без переписывания.
   Когда сервера нет — всё работает на localStorage (демо-прототип). */
const authApi = {
  currentPhone() { try { return localStorage.getItem(AUTH_SESSION_KEY) || null; } catch (e) { return null; } },   // uid
  getUser(uid) { return _loadUsers()[uid] || null; },
  exists(uid) { return !!_loadUsers()[uid]; },
  listUsers() { const u = _loadUsers(); return Object.keys(u).map((k) => u[k]); },   // для панели автора (офлайн)

  /* какие способы входа доступны на сервере (для отрисовки кнопок) */
  async providers() {
    try { if (await backendUp()) return await apiGet("/api/auth/providers", { auth: false }); } catch (e) {}
    return { vk: false, yandex: false, telegram: { enabled: false, bot: "" }, email: true, demo: true };
  },

  /* VK ID / Яндекс ID: получить URL авторизации и уйти на провайдера.
     Если провайдер не настроен на сервере — демо-вход тестовым пользователем. */
  async oauthLogin(provider) {
    if (await backendUp()) {
      try {
        const r = await apiGet("/api/auth/oauth/" + provider + "/start", { auth: false });
        if (r && r.url) { window.location.href = r.url; return { redirect: true }; }
        if (r && r.demo) return await this.demoLogin(provider);
      } catch (e) { /* упадём в демо ниже */ }
    }
    return await this.demoLogin(provider);
  },

  /* Telegram: реальный Login-виджет отдаёт объект с полем hash; демо — {} */
  async telegramLogin(data) {
    if (await backendUp()) {
      try {
        const r = await apiPost("/api/auth/telegram", data || {}, { auth: false });
        if (r && r.token) return this._applySession(r);
      } catch (e) { if (e && e.status && e.status !== 501) throw e; }
    }
    return await this.demoLogin("telegram");
  },

  /* демо-вход (сервер с DEV_AUTH или полностью офлайн) */
  async demoLogin(provider, extra) {
    if (await backendUp()) {
      try {
        const r = await apiPost("/api/auth/demo", Object.assign({ provider }, extra || {}), { auth: false });
        if (r && r.token) return this._applySession(r);
      } catch (e) {}
    }
    const uid = provider + ":demo";
    const names = { vk: "Демо · VK ID", yandex: "Демо · Яндекс ID", telegram: "Демо · Telegram", email: "Демо · E-mail" };
    const user = { uid, name: (extra && extra.name) || names[provider] || "Демо", email: (extra && extra.email) || "", provider };
    this._cacheUser(Object.assign({ purchased: [] }, user));
    this._setSession(uid);
    return user;
  },

  /* e-mail: старт — сервер (или мок) отправляет код и magic-link */
  async emailStart(email, name) {
    email = String(email || "").trim().toLowerCase();
    if (await backendUp()) {
      const r = await apiPost("/api/auth/email/start", { email, name: name || "" }, { auth: false });
      return { email, backend: true, code: (r && r.dev_code) || null, link: (r && r.dev_link) || null };
    }
    return { email, backend: false, code: gen6() };
  },

  /* e-mail: подтверждение кода */
  async emailVerify(pending, enteredCode) {
    const code = String(enteredCode || "").replace(/\D/g, "");
    if (pending.backend) {
      const r = await apiPost("/api/auth/email/verify", { email: pending.email, code }, { auth: false });
      if (r && r.token) return this._applySession(r);
      return;
    }
    if (code !== pending.code) { const e = new Error("badcode"); e.code = "badcode"; throw e; }
    const uid = "email:" + pending.email;
    const user = { uid, name: pending.email.split("@")[0], email: pending.email, provider: "email" };
    this._cacheUser(Object.assign({ purchased: [] }, user));
    this._setSession(uid);
    return user;
  },

  /* применить ответ сервера {token,user}: токен + кэш + сессия + профиль */
  _applySession(r) {
    if (r.token) setToken(r.token);
    this._cacheUser(r.user);
    this._setSession(r.user.uid);
    this._refreshMe();
    return r.user;
  },

  /* кэш текущего пользователя в al_users_v1 — чтобы синхронные хуки работали */
  _cacheUser(user) {
    if (!user || !user.uid) return;
    const cur = _loadUsers();
    const prev = cur[user.uid] || {};
    cur[user.uid] = Object.assign({ purchased: [], createdAt: Date.now() }, prev, {
      uid: user.uid, name: user.name || prev.name || "", email: user.email || prev.email || "",
      avatar: user.avatar || prev.avatar || "", provider: user.provider || prev.provider || "",
    });
    _saveUsers(cur);
  },

  /* подтянуть профиль + покупки с сервера, обновить кэш */
  async _refreshMe() {
    if (!(await backendUp()) || !getToken()) return;
    try {
      const me = await apiGet("/api/me");
      if (me && me.user) {
        this._cacheUser(me.user);
        const cur = _loadUsers();
        if (cur[me.user.uid]) { cur[me.user.uid].purchased = me.purchased || []; _saveUsers(cur); }
        _notifyAuth();
      }
    } catch (e) { if (e && e.status === 401) this.logout(); }   // токен истёк
  },

  _setSession(uid) { try { localStorage.setItem(AUTH_SESSION_KEY, uid); } catch (e) {} _notifyAuth(); },
  logout() { setToken(null); try { localStorage.removeItem(AUTH_SESSION_KEY); } catch (e) {} _notifyAuth(); },

  async markPurchased(uid, tariffId) {
    if ((await backendUp()) && getToken()) { try { await apiPost("/api/purchase", { tariff: tariffId }); } catch (e) {} }
    const users = _loadUsers();
    users[uid] = Object.assign({ uid, purchased: [], createdAt: Date.now() }, users[uid] || {});
    users[uid].purchased = Array.from(new Set([...(users[uid].purchased || []), tariffId]));
    _saveUsers(users);
    _notifyAuth();
  },
};

/* при загрузке страницы: если есть токен — проверяем сессию и подтягиваем профиль */
if (typeof getToken === "function" && getToken()) { setTimeout(() => authApi._refreshMe(), 0); }

/* subscribe hook — компоненты обновляются при входе/выходе */
function useAuth() {
  const [phone, setPhone] = React.useState(authApi.currentPhone());
  React.useEffect(() => {
    const fn = () => setPhone(authApi.currentPhone());
    _authSubs.add(fn);
    return () => { _authSubs.delete(fn); };
  }, []);
  return { phone, user: phone ? authApi.getUser(phone) : null, logout: () => authApi.logout() };
}

/* ============================================================
   AuthModal — экраны входа / регистрации + 2FA по SMS
   ============================================================ */
function AuthField({ label, type = "text", value, onChange, placeholder, autoFocus }) {
  const [focus, setFocus] = React.useState(false);
  return (
    <label style={{ display: "block" }}>
      <span style={{ display: "block", marginBottom: 8 }}><Label tone="ink">{label}</Label></span>
      <input type={type} value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder}
        autoFocus={autoFocus} onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
        style={{ width: "100%", height: 50, padding: "0 15px", background: "var(--paper)",
          border: `1px solid ${focus ? "var(--ink)" : "var(--hairline-2)"}`, borderRadius: 6,
          fontFamily: "var(--font-sans)", fontSize: 15.5, color: "var(--ink)", outline: "none",
          transition: "border-color var(--dur) var(--ease)" }} />
    </label>
  );
}

/* кнопка входа через провайдера (VK ID / Яндекс ID / Telegram) */
function ProviderBtn({ onClick, disabled, bg, fg, badge, label }) {
  return (
    <button type="button" onClick={onClick} disabled={disabled}
      onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--ink)"; }}
      onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--hairline-2)"; }}
      style={{ width: "100%", display: "flex", alignItems: "center", gap: 12, height: 52, padding: "0 16px",
        borderRadius: 10, border: "1px solid var(--hairline-2)", background: "var(--paper)",
        cursor: disabled ? "wait" : "pointer", textAlign: "left",
        transition: "border-color var(--dur) var(--ease)" }}>
      <span style={{ width: 30, height: 30, borderRadius: 8, background: bg, color: fg, display: "grid",
        placeItems: "center", fontFamily: "var(--font-sans)", fontWeight: 700, fontSize: 14, flexShrink: 0 }}>{badge}</span>
      <span style={{ fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 14.5, color: "var(--ink)" }}>{label}</span>
      <Icon name="arrow-right" style={{ width: 15, height: 15, strokeWidth: 1.8, color: "var(--ink-3)", marginLeft: "auto" }} />
    </button>
  );
}

/* официальный Telegram Login Widget — рендерит кнопку Telegram и
   отдаёт данные входа в колбэк (проверка подписи — на бэкенде). */
function TelegramLoginButton({ bot, onAuth }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    window.__alTgAuth = (user) => { try { onAuth(user); } catch (e) {} };
    const s = document.createElement("script");
    s.src = "https://telegram.org/js/telegram-widget.js?22";
    s.async = true;
    s.setAttribute("data-telegram-login", bot);
    s.setAttribute("data-size", "large");
    s.setAttribute("data-radius", "10");
    s.setAttribute("data-onauth", "__alTgAuth(user)");
    s.setAttribute("data-request-access", "write");
    const el = ref.current;
    if (el) { el.innerHTML = ""; el.appendChild(s); }
    return () => { try { delete window.__alTgAuth; } catch (e) {} };
  }, [bot]);
  return <div ref={ref} style={{ display: "flex", justifyContent: "center", minHeight: 48 }} />;
}

/* ============================================================
   AuthModal — вход через VK ID · Яндекс ID · Telegram · E-mail
   (код или magic-link). Без SMS. Показываются только настроенные
   способы (по /api/auth/providers); в демо-режиме — все.
   ============================================================ */
function AuthModal({ open, onClose, onAuthed }) {
  const { t } = useT();
  const [step, setStep] = React.useState("choose");   // choose | code
  const [email, setEmail] = React.useState("");
  const [code, setCode] = React.useState("");
  const [pending, setPending] = React.useState(null); // {email, backend, code?, link?}
  const [err, setErr] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [prov, setProv] = React.useState(null);        // конфиг способов входа

  React.useEffect(() => { if (open) { setStep("choose"); setErr(""); setCode(""); setPending(null);
    if (authApi.providers) authApi.providers().then(setProv); } }, [open]);
  React.useEffect(() => { if (window.lucide) lucide.createIcons(); });
  if (!open) return null;

  // какие способы показывать: в демо — все; в бою — только настроенные
  const demo = !prov || prov.demo;
  const showVk = demo || (prov && prov.vk);
  const showYandex = demo || (prov && prov.yandex);
  const tgReal = !!(prov && prov.telegram && prov.telegram.enabled && prov.telegram.bot);
  const showTelegram = demo || tgReal;
  const showEmail = demo || (prov && prov.email);

  const emailOk = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email.trim());

  const finishAuthed = () => {
    const uid = authApi.currentPhone();
    onClose();
    // по ТЗ: после входа сразу в личный кабинет. Если у вызова свой обработчик
    // (форма оплаты / сам кабинет) — отдаём управление ему; иначе → learn.html.
    if (onAuthed) onAuthed(uid);
    else window.location.href = "learn.html";
  };

  const doProvider = async (provider) => {
    setErr(""); setBusy(true);
    try {
      const res = await authApi.oauthLogin(provider);   // vk | yandex
      if (res && res.redirect) return;                  // ушли на страницу провайдера
      finishAuthed();                                    // демо-вход прошёл сразу
    } catch (e) { setErr("Не удалось войти. Попробуйте ещё раз."); setBusy(false); }
  };

  const doTelegram = async () => {
    setErr(""); setBusy(true);
    try {
      // Боевой вход: Telegram Login Widget передаёт объект с полем hash в
      // window.__tgAuthData (см. комментарий ниже). Иначе — демо/сервер.
      await authApi.telegramLogin(window.__tgAuthData || {});
      finishAuthed();
    } catch (e) { setErr("Не удалось войти через Telegram."); setBusy(false); }
  };

  const startEmail = async (e) => {
    if (e) e.preventDefault();
    setErr("");
    if (!emailOk) return setErr("Введите корректный e-mail");
    setBusy(true);
    try { const p = await authApi.emailStart(email.trim(), ""); setPending(p); setStep("code"); }
    catch (e2) { setErr(e2.code === "bad_email" ? "Введите корректный e-mail" : "Не удалось отправить письмо"); }
    finally { setBusy(false); }
  };

  const verifyEmail = async (e) => {
    if (e) e.preventDefault();
    setErr(""); setBusy(true);
    try { await authApi.emailVerify(pending, code); finishAuthed(); }
    catch (e2) {
      const bad = ["badcode", "bad_code", "code_expired"].indexOf(e2.code) >= 0;
      setErr(bad ? "Неверный или истёкший код" : "Ошибка входа");
      setBusy(false);
    }
  };

  const shell = (children) => (
    <div onMouseDown={onClose} style={{ position: "fixed", inset: 0, zIndex: 120,
      background: "rgba(14,14,12,0.55)", backdropFilter: "blur(4px)", WebkitBackdropFilter: "blur(4px)",
      display: "grid", placeItems: "center", padding: 20 }}>
      <div onMouseDown={(e) => e.stopPropagation()} style={{ width: "min(440px, 100%)",
        background: "var(--paper)", borderRadius: 14, border: "1px solid var(--hairline)",
        boxShadow: "0 40px 120px rgba(14,14,12,0.28)", padding: "clamp(26px,4vw,38px)", position: "relative" }}>
        <button onClick={onClose} aria-label="Закрыть" style={{ position: "absolute", top: 16, right: 16,
          width: 36, height: 36, borderRadius: 8, border: "1px solid var(--hairline-2)", background: "var(--paper)",
          cursor: "pointer", display: "grid", placeItems: "center" }}>
          <Icon name="x" style={{ width: 16, height: 16, strokeWidth: 1.8 }} />
        </button>
        {children}
      </div>
    </div>
  );

  if (step === "code") {
    return shell(
      <form onSubmit={verifyEmail}>
        <div style={{ marginBottom: 6 }}><Label>Вход по e-mail</Label></div>
        <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 300, fontSize: 27, letterSpacing: "-0.01em",
          color: "var(--ink)", margin: "0 0 10px" }}>Введите код из письма</h3>
        <p style={{ fontFamily: "var(--font-sans)", fontSize: 14, color: "var(--ink-2)", margin: "0 0 20px" }}>
          Мы отправили код и ссылку для входа на <b style={{ color: "var(--ink)" }}>{pending.email}</b>.
        </p>

        {/* демо-подсказка: код/ссылка известны клиенту только в деморежиме */}
        {pending && (pending.code || pending.link) && (
          <div style={{ padding: "12px 14px", marginBottom: 18, background: "var(--surface)",
            border: "1px dashed var(--hairline-2)", borderRadius: 8 }}>
            {pending.code && (
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <Icon name="mail" style={{ width: 15, height: 15, strokeWidth: 1.6, color: "var(--ink-3)" }} />
                <span style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, color: "var(--ink-3)" }}>
                  Демо-код:{" "}
                  <b style={{ fontFamily: "var(--font-mono)", color: "var(--ink)", letterSpacing: "0.08em" }}>{pending.code}</b>
                </span>
              </div>
            )}
            {pending.link && (
              <a href={pending.link} style={{ display: "inline-flex", alignItems: "center", gap: 6, marginTop: pending.code ? 8 : 0,
                fontFamily: "var(--font-sans)", fontSize: 12.5, color: "var(--ink-2)", textDecoration: "underline",
                textUnderlineOffset: 3 }}>
                Войти по magic-ссылке <Icon name="arrow-up-right" style={{ width: 12, height: 12, strokeWidth: 1.8 }} />
              </a>
            )}
          </div>
        )}

        <AuthField label="Код из письма" value={code} onChange={setCode} placeholder="6 цифр" autoFocus />
        {err && <p style={{ margin: "12px 0 0", color: "var(--down)", fontFamily: "var(--font-sans)", fontSize: 13.5 }}>{err}</p>}

        <button type="submit" disabled={busy} style={{ width: "100%", height: 52, marginTop: 18, borderRadius: 999, border: "none",
          background: "var(--ink)", color: "var(--paper-on-ink)", cursor: busy ? "wait" : "pointer",
          fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 12, letterSpacing: "0.14em",
          textTransform: "uppercase", boxShadow: "var(--shadow-pill)" }}>Войти</button>

        <div style={{ display: "flex", justifyContent: "space-between", marginTop: 16 }}>
          <button type="button" onClick={() => { setStep("choose"); setErr(""); setCode(""); }}
            style={{ background: "none", border: "none", cursor: "pointer", fontFamily: "var(--font-sans)",
              fontSize: 13.5, color: "var(--ink-2)" }}>← Назад</button>
          <button type="button" onClick={() => startEmail()}
            style={{ background: "none", border: "none", cursor: "pointer", fontFamily: "var(--font-sans)",
              fontSize: 13.5, color: "var(--ink-2)", textDecoration: "underline", textUnderlineOffset: 3 }}>
            Отправить ещё раз
          </button>
        </div>
      </form>
    );
  }

  return shell(
    <React.Fragment>
      <div style={{ marginBottom: 6 }}><Label>Вход в кабинет</Label></div>
      <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 300, fontSize: 27, letterSpacing: "-0.01em",
        color: "var(--ink)", margin: "0 0 22px" }}>Войдите удобным способом</h3>

      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {showVk && (
          <ProviderBtn onClick={() => doProvider("vk")} disabled={busy}
            bg="#0077FF" fg="#fff" badge="VK" label="Войти через VK ID" />
        )}
        {showYandex && (
          <ProviderBtn onClick={() => doProvider("yandex")} disabled={busy}
            bg="#FC3F1D" fg="#fff" badge="Я" label="Войти через Яндекс ID" />
        )}
        {showTelegram && (tgReal
          ? <TelegramLoginButton bot={prov.telegram.bot}
              onAuth={async (user) => { setErr(""); setBusy(true);
                try { await authApi.telegramLogin(user); finishAuthed(); }
                catch (e) { setErr("Не удалось войти через Telegram."); setBusy(false); } }} />
          : <ProviderBtn onClick={doTelegram} disabled={busy}
              bg="#229ED9" fg="#fff"
              badge={<Icon name="send" style={{ width: 15, height: 15, strokeWidth: 1.9 }} />}
              label="Войти через Telegram" />
        )}
      </div>

      {/* разделитель + e-mail (если способ доступен) */}
      {showEmail && (
      <React.Fragment>
      <div style={{ display: "flex", alignItems: "center", gap: 12, margin: "20px 0 16px" }}>
        <span style={{ flex: 1, height: 1, background: "var(--hairline)" }} />
        <span style={{ fontFamily: "var(--font-sans)", fontSize: 12, color: "var(--ink-3)", letterSpacing: "0.04em" }}>или по e-mail</span>
        <span style={{ flex: 1, height: 1, background: "var(--hairline)" }} />
      </div>

      <form onSubmit={startEmail}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 12 }}>
          <input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
            placeholder="you@example.com" autoFocus
            style={{ width: "100%", height: 50, padding: "0 15px", background: "var(--paper)",
              border: "1px solid var(--hairline-2)", borderRadius: 8, fontFamily: "var(--font-sans)",
              fontSize: 15.5, color: "var(--ink)", outline: "none" }} />
          <button type="submit" disabled={busy || !emailOk} style={{ width: "100%", height: 50, borderRadius: 999, border: "none",
            background: emailOk ? "var(--ink)" : "var(--surface-2)", color: emailOk ? "var(--paper-on-ink)" : "var(--ink-4)",
            cursor: busy ? "wait" : (emailOk ? "pointer" : "not-allowed"),
            fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 12, letterSpacing: "0.14em",
            textTransform: "uppercase" }}>Получить код / ссылку</button>
        </div>
      </form>
      </React.Fragment>
      )}

      {err && <p style={{ margin: "14px 0 0", color: "var(--down)", fontFamily: "var(--font-sans)", fontSize: 13.5 }}>{err}</p>}

      <p style={{ fontFamily: "var(--font-sans)", fontSize: 11.5, lineHeight: 1.5, color: "var(--ink-3)", margin: "18px 0 0" }}>
        Нажимая «Войти», вы соглашаетесь с условиями оферты и обработкой персональных данных.
      </p>
    </React.Fragment>
  );
}

/* ============================================================
   OfferModal — договор оферты; «Согласен» активна после прочтения
   ============================================================ */
function OfferModal({ open, onClose, onAccept }) {
  const { t } = useT();
  const [canAccept, setCanAccept] = React.useState(false);
  const bodyRef = React.useRef(null);
  React.useEffect(() => { if (open) setCanAccept(false); }, [open]);
  if (!open) return null;
  const paras = t("auth.offerBody");
  const onScroll = () => {
    const el = bodyRef.current; if (!el) return;
    if (el.scrollTop + el.clientHeight >= el.scrollHeight - 24) setCanAccept(true);
  };
  return (
    <div onMouseDown={onClose} style={{ position: "fixed", inset: 0, zIndex: 121,
      background: "rgba(14,14,12,0.55)", backdropFilter: "blur(4px)", WebkitBackdropFilter: "blur(4px)",
      display: "grid", placeItems: "center", padding: 20 }}>
      <div onMouseDown={(e) => e.stopPropagation()} style={{ width: "min(680px, 100%)", maxHeight: "86vh",
        background: "var(--paper)", borderRadius: 14, border: "1px solid var(--hairline)",
        boxShadow: "0 40px 120px rgba(14,14,12,0.28)", display: "flex", flexDirection: "column",
        padding: "clamp(24px,3.4vw,34px)" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
          <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 300, fontSize: 26, letterSpacing: "-0.01em",
            color: "var(--ink)", margin: 0 }}>{t("auth.offerTitle")}</h3>
          <button onClick={onClose} aria-label={t("auth.back")} style={{ width: 36, height: 36, borderRadius: 8,
            border: "1px solid var(--hairline-2)", background: "var(--paper)", cursor: "pointer",
            display: "grid", placeItems: "center" }}>
            <Icon name="x" style={{ width: 16, height: 16, strokeWidth: 1.8 }} />
          </button>
        </div>

        <div ref={bodyRef} onScroll={onScroll} style={{ overflowY: "auto", paddingRight: 8, flex: 1,
          borderTop: "1px solid var(--hairline)", borderBottom: "1px solid var(--hairline)", padding: "20px 8px 20px 0" }}>
          {(Array.isArray(paras) ? paras : [String(paras)]).map((p, i) => (
            <p key={i} style={{ fontFamily: "var(--font-sans)", fontSize: 14.5, lineHeight: 1.7,
              color: i === 0 ? "var(--ink)" : "var(--ink-2)", margin: i === 0 ? "0 0 18px" : "0 0 14px" }}>{p}</p>
          ))}
        </div>

        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16,
          marginTop: 18, flexWrap: "wrap" }}>
          <span style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, color: "var(--ink-3)" }}>
            {canAccept ? "" : t("auth.offerReadHint")}
          </span>
          <button onClick={() => { onAccept(); onClose(); }} disabled={!canAccept}
            style={{ height: 48, padding: "0 28px", borderRadius: 999, border: "none",
              background: canAccept ? "var(--ink)" : "var(--surface-2)",
              color: canAccept ? "var(--paper-on-ink)" : "var(--ink-4)",
              cursor: canAccept ? "pointer" : "not-allowed",
              fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 12, letterSpacing: "0.14em",
              textTransform: "uppercase", transition: "background var(--dur) var(--ease)" }}>
            {t("auth.offerAgreeBtn")}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   AccountChip — «Войти» / телефон+выход (для шапки подстраниц)
   ============================================================ */
function AccountChip({ height = 44 }) {
  const { t } = useT();
  const { phone, user, logout } = useAuth();
  const [open, setOpen] = React.useState(false);
  const dot = Math.min(28, height - 6);   // размер круглой кнопки выхода под высоту чипа
  if (phone) {
    const who = (user && (user.name || user.email)) || "Профиль";
    return (
      <div style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
        <a href="learn.html" style={{ height, padding: "0 16px", borderRadius: 999, textDecoration: "none",
          border: "1px solid var(--ink)", background: "var(--ink)", color: "var(--paper-on-ink)",
          fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 11, letterSpacing: "0.14em",
          textTransform: "uppercase", display: "inline-flex", alignItems: "center", gap: 8 }}>
          {t("learn.title")}
          <Icon name="arrow-up-right" style={{ width: 13, height: 13, strokeWidth: 1.8 }} />
        </a>
        <div style={{ display: "inline-flex", alignItems: "center", gap: 8, height, padding: "0 6px 0 12px",
          borderRadius: 999, border: "1px solid var(--hairline-2)", background: "var(--paper)" }}>
          <span title={who} style={{ fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 12.5, color: "var(--ink)",
            maxWidth: 160, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{who}</span>
          <button onClick={logout} aria-label={t("auth.logout")} title={t("auth.logout")}
            style={{ width: dot, height: dot, borderRadius: 999, border: "none", background: "var(--surface)",
              cursor: "pointer", display: "grid", placeItems: "center", marginLeft: 2 }}>
            <Icon name="arrow-up-right" style={{ width: 13, height: 13, strokeWidth: 1.8, transform: "rotate(45deg)" }} />
          </button>
        </div>
      </div>
    );
  }
  return (
    <React.Fragment>
      <button onClick={() => setOpen(true)} style={{ height, padding: "0 16px", borderRadius: 999,
        border: "1px solid var(--hairline-2)", background: "var(--paper)", cursor: "pointer",
        fontFamily: "var(--font-sans)", fontWeight: 600, fontSize: 11, letterSpacing: "0.14em",
        textTransform: "uppercase", color: "var(--ink)", display: "inline-flex", alignItems: "center", gap: 8 }}>
        <Icon name="lock" style={{ width: 13, height: 13, strokeWidth: 1.7 }} />
        {t("auth.login")}
      </button>
      <AuthModal open={open} onClose={() => setOpen(false)} />
    </React.Fragment>
  );
}

Object.assign(window, {
  COUNTRY_CODES, normalizePhone, authApi, useAuth, AuthModal, OfferModal, AccountChip,
});
