/* ═══════════════════════════════════════════════════════════
   Dating Coach — Telegram Mini App
   Single-file build для Babel-in-browser. Все экраны и логика тут,
   чтобы не зависеть от порядка подгрузки внешних JSX-скриптов.
   ═══════════════════════════════════════════════════════════ */

const { useState, useEffect, useCallback, useMemo, useRef } = React;

const TG = window.Telegram && window.Telegram.WebApp;

/* ───────── Icon set (1.7px stroke, 24 viewBox) ───────── */

function Icon({ name, size = 18, style }) {
  const common = {
    width: size, height: size, viewBox: "0 0 24 24",
    fill: "none", stroke: "currentColor",
    strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round",
    style,
  };
  const P = {
    home:     <><path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-7h-6v7H4a1 1 0 01-1-1z"/></>,
    book:     <><path d="M5 4h9a4 4 0 014 4v12H9a4 4 0 01-4-4z"/><path d="M5 4v12a4 4 0 014-4h9"/></>,
    trophy:   <><path d="M8 4h8v4a4 4 0 01-8 0zM5 4H3v3a3 3 0 003 3M19 4h2v3a3 3 0 01-3 3M10 14h4M12 10v4M8 20h8"/></>,
    chart:    <><path d="M4 20V10M10 20V4M16 20v-8M22 20H2"/></>,
    user:     <><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></>,
    flame:    <><path d="M12 3c2 4-2 5-2 9a5 5 0 0010 0c0-4-3-6-4-9-2 2-2 4-4 0z"/></>,
    bolt:     <><path d="M13 3L4 14h7l-1 7 9-11h-7z"/></>,
    play:     <><path d="M8 5l11 7-11 7z" fill="currentColor" stroke="none"/></>,
    arrow:    <><path d="M5 12h14M13 6l6 6-6 6"/></>,
    back:     <><path d="M19 12H5M11 6l-6 6 6 6"/></>,
    check:    <><path d="M5 12l5 5 9-11"/></>,
    heart:    <><path d="M12 20s-7-4.5-7-10a4 4 0 017-2.7A4 4 0 0119 10c0 5.5-7 10-7 10z"/></>,
    sparkle:  <><path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l3 3M15 15l3 3M18 6l-3 3M9 15l-3 3"/></>,
    mic:      <><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 11a7 7 0 0014 0M12 18v3"/></>,
    eye:      <><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></>,
    lock:     <><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 018 0v4"/></>,
    msg:      <><path d="M21 15a2 2 0 01-2 2H8l-5 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></>,
    users:    <><circle cx="9" cy="8" r="4"/><path d="M2 21c0-4 3-6 7-6s7 2 7 6M17 4a4 4 0 010 8M22 21c0-3-2-5-5-6"/></>,
    cal:      <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M8 3v4M16 3v4M3 10h18"/></>,
    bell:     <><path d="M6 9a6 6 0 0112 0c0 6 3 7 3 7H3s3-1 3-7M10 20a2 2 0 004 0"/></>,
    settings: <><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 00-.1-1.2l2-1.5-2-3.4-2.4.9a7 7 0 00-2-1.2l-.4-2.6h-4l-.4 2.6a7 7 0 00-2 1.2l-2.4-.9-2 3.4 2 1.5A7 7 0 005 12a7 7 0 00.1 1.2l-2 1.5 2 3.4 2.4-.9a7 7 0 002 1.2l.4 2.6h4l.4-2.6a7 7 0 002-1.2l2.4.9 2-3.4-2-1.5A7 7 0 0019 12z"/></>,
    target:   <><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none"/></>,
    clock:    <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    crown:    <><path d="M3 19h18M4 7l4 3 4-5 4 5 4-3v10H4z"/></>,
    chev:     <><path d="M9 6l6 6-6 6"/></>,
    moon:     <><path d="M21 13a9 9 0 11-10-10 7 7 0 0010 10z"/></>,
    smile:    <><circle cx="12" cy="12" r="9"/><path d="M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01"/></>,
    lang:     <><path d="M3 5h10M8 3v2M5 18l5-12 5 12M7 13h6M13 20h6M16 18l3-3 3 3"/></>,
    logout:   <><path d="M10 21H5a2 2 0 01-2-2V5a2 2 0 012-2h5M17 16l4-4-4-4M21 12H9"/></>,
    trend:    <><path d="M3 17l6-6 4 4 8-8M14 7h7v7"/></>,
    medal:    <><circle cx="12" cy="15" r="6"/><path d="M9 9L6 3h12l-3 6M12 12v3M11 15h2"/></>,
    gift:     <><rect x="3" y="8" width="18" height="4"/><rect x="4" y="12" width="16" height="9" rx="1"/><path d="M12 8v13M8 8a3 3 0 010-6c2 0 4 6 4 6s2-6 4-6a3 3 0 010 6"/></>,
    fire:     <><path d="M12 3c1 4-3 5-3 9a5 5 0 0010 0c0-3-2-5-3-7-1 2-3 2-4-2zM9 17c.5 2 2 3 3 3s2.5-1 3-3"/></>,
    info:     <><circle cx="12" cy="12" r="9"/><path d="M12 11v6M12 8v.5"/></>,
    palette:  <><path d="M12 3a9 9 0 100 18 2 2 0 002-2 2 2 0 012-2h1a4 4 0 004-4 9 9 0 00-9-10z"/><circle cx="8" cy="10" r="1" fill="currentColor"/><circle cx="12" cy="7" r="1" fill="currentColor"/><circle cx="16" cy="10" r="1" fill="currentColor"/></>,
    shield:   <><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/></>,
  };
  return <svg {...common}>{P[name] || P.sparkle}</svg>;
}

/* ───────── API layer ───────── */

let _initData = "";

function authHeaders() {
  const h = { "Content-Type": "application/json" };
  if (_initData) h["X-Telegram-Init-Data"] = _initData;
  return h;
}

async function apiGet(url) {
  const r = await fetch(url, { credentials: "include", headers: authHeaders() });
  if (!r.ok) { const e = new Error(r.status); e.status = r.status; throw e; }
  return r.json();
}
async function apiPost(url, body) {
  const r = await fetch(url, {
    method: "POST", credentials: "include", headers: authHeaders(),
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!r.ok) { const e = new Error(r.status); e.status = r.status; throw e; }
  return r.json();
}
async function apiPatch(url, body) {
  const r = await fetch(url, {
    method: "PATCH", credentials: "include", headers: authHeaders(),
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!r.ok) { const e = new Error(r.status); e.status = r.status; throw e; }
  return r.json();
}

/* ───────── helpers ───────── */

const LEVEL_META = {
  beginner:     { name: "Начальный",   short: "Начальный",  idx: "I",   sub: "Фундамент уверенности" },
  intermediate: { name: "Средний",     short: "Средний",    idx: "II",  sub: "Техники и отношения" },
  advanced:     { name: "Продвинутый", short: "Продвинутый", idx: "III", sub: "Мастерство и рост" },
};
const LEVEL_ORDER = ["beginner", "intermediate", "advanced"];
const POINTS_TO_NEXT = { beginner: 450, intermediate: 600, advanced: 0 };

function levelMeta(id) { return LEVEL_META[id] || { name: id, short: id, idx: "?", sub: "" }; }

function makeInitials(profile) {
  if (!profile) return "?";
  const fn = (profile.first_name || "").trim();
  const ln = (profile.last_name || "").trim();
  if (fn || ln) return ((fn[0] || "") + (ln[0] || "")).toUpperCase() || "?";
  const un = (profile.username || "").trim();
  return un ? un[0].toUpperCase() : "?";
}

function displayName(profile) {
  if (!profile) return "Студент";
  return profile.first_name || profile.username || "Студент";
}

function greeting() {
  const h = new Date().getHours();
  if (h < 6) return "Доброй ночи";
  if (h < 12) return "Доброе утро";
  if (h < 18) return "Добрый день";
  return "Добрый вечер";
}

function haptic(kind = "light") {
  try {
    if (TG && TG.HapticFeedback) {
      if (kind === "success") TG.HapticFeedback.notificationOccurred("success");
      else TG.HapticFeedback.impactOccurred(kind);
    }
  } catch {}
}

/* Группировка ачивок по префиксу id (бэкенд хранит без category) */
function groupAchievements(list) {
  const groups = {
    lessons: { name: "Уроки",   items: [] },
    streak:  { name: "Серии",   items: [] },
    points:  { name: "Баллы",   items: [] },
    level:   { name: "Уровни",  items: [] },
    special: { name: "Особые",  items: [] },
  };
  list.forEach(a => {
    if (a.id.startsWith("lessons_") || a.id === "first_lesson") groups.lessons.items.push(a);
    else if (a.id.startsWith("streak_")) groups.streak.items.push(a);
    else if (a.id.startsWith("points_")) groups.points.items.push(a);
    else if (a.id.startsWith("level_"))  groups.level.items.push(a);
    else groups.special.items.push(a);
  });
  return Object.values(groups).filter(g => g.items.length > 0);
}

/* первый незавершённый урок текущего уровня */
function findCurrentLesson(structure, profileLevel) {
  if (!structure) return null;
  const levelOrderId = profileLevel || "beginner";
  // приоритет — начать с текущего уровня, потом проверить разблокированные предыдущие
  const prefer = [levelOrderId, ...LEVEL_ORDER.filter(x => x !== levelOrderId)];
  for (const lvId of prefer) {
    const lv = structure.find(l => l.id === lvId);
    if (!lv || !lv.unlocked) continue;
    let idx = 0;
    for (const m of lv.modules) {
      for (const les of m.lessons) {
        idx++;
        if (!les.completed) {
          return { level: lv, module: m, lesson: les, lessonIndex: idx };
        }
      }
    }
  }
  return null;
}

/* ───────── Toast ───────── */

const ToastCtx = React.createContext(() => {});

function ToastProvider({ children }) {
  const [msg, setMsg] = useState(null);
  const tRef = useRef(null);
  const show = useCallback((m) => {
    setMsg(m);
    clearTimeout(tRef.current);
    tRef.current = setTimeout(() => setMsg(null), 2800);
  }, []);
  return (
    <ToastCtx.Provider value={show}>
      {children}
      {msg && <div className="dc-toast dc-toast--show">{msg}</div>}
    </ToastCtx.Provider>
  );
}
const useToast = () => React.useContext(ToastCtx);

/* ───────── App-wide data store (минимальный) ───────── */

const DataCtx = React.createContext(null);

function DataProvider({ profile, setProfile, children }) {
  const [progress, setProgress] = useState(null);
  const [structure, setStructure] = useState(null);
  const [structureLoading, setStructureLoading] = useState(false);

  const loadProgress = useCallback(async () => {
    try { setProgress(await apiGet("/api/users/me/progress")); } catch {}
  }, []);

  const loadStructure = useCallback(async (force = false) => {
    if (structure && !force) return structure;
    if (structureLoading) return null;
    setStructureLoading(true);
    try {
      const s = await apiGet("/api/lessons/structure");
      setStructure(s);
      return s;
    } catch {
      return null;
    } finally {
      setStructureLoading(false);
    }
  }, [structure, structureLoading]);

  const invalidate = useCallback(() => {
    setStructure(null);
    loadProgress();
  }, [loadProgress]);

  return (
    <DataCtx.Provider value={{
      profile, setProfile,
      progress, loadProgress,
      structure, loadStructure,
      invalidate,
    }}>
      {children}
    </DataCtx.Provider>
  );
}
const useData = () => React.useContext(DataCtx);

/* ───────── Router (стек экранов) ───────── */

const NavCtx = React.createContext(null);

function NavProvider({ children, initial = { id: "home" } }) {
  const [stack, setStack] = useState([initial]);
  const top = stack[stack.length - 1];

  const push = useCallback((screen) => {
    setStack(s => [...s, screen]);
  }, []);
  const replace = useCallback((screen) => {
    setStack([screen]);
  }, []);
  const back = useCallback(() => {
    setStack(s => s.length > 1 ? s.slice(0, -1) : s);
  }, []);
  const goTab = useCallback((tabId) => {
    setStack([{ id: tabId }]);
  }, []);

  // Telegram BackButton
  useEffect(() => {
    if (!TG || !TG.BackButton) return;
    if (stack.length > 1) {
      TG.BackButton.show();
      const onClick = () => back();
      TG.BackButton.onClick(onClick);
      return () => { try { TG.BackButton.offClick(onClick); } catch {} };
    } else {
      TG.BackButton.hide();
    }
  }, [stack.length, back]);

  return (
    <NavCtx.Provider value={{ top, stack, push, replace, back, goTab }}>
      {children}
    </NavCtx.Provider>
  );
}
const useNav = () => React.useContext(NavCtx);

/* ───────── Reusable: TabBar ───────── */

function TabBar({ active }) {
  const nav = useNav();
  const tabs = [
    { id: "home",     icon: "home",     label: "Главная" },
    { id: "learn",    icon: "book",     label: "Уроки" },
    { id: "ach",      icon: "trophy",   label: "Награды" },
    { id: "stats",    icon: "chart",    label: "Статистика" },
  ];
  return (
    <div className="dc-tabbar">
      {tabs.map(t => (
        <div key={t.id}
             className={"dc-tab " + (active === t.id ? "dc-tab--active" : "")}
             onClick={() => { haptic("light"); nav.goTab(t.id); }}>
          <Icon name={t.icon} size={18}/>
          <span>{t.label}</span>
        </div>
      ))}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 1: Auth
   ═══════════════════════════════════════════════════════════ */

function AuthScreen({ onAuthed }) {
  const [phase, setPhase] = useState("loading"); // loading | needLogin
  const toast = useToast();

  useEffect(() => {
    let cancelled = false;
    (async () => {
      // 1) JWT cookie
      try {
        const s = await apiGet("/api/auth/session");
        if (s && s.authenticated && !cancelled) { onAuthed(s.user); return; }
      } catch {}
      // 2) Portal cookie
      try {
        const p = await apiGet("/api/auth/platform/auto");
        if (p && p.ok && !cancelled) { onAuthed(p.user); return; }
      } catch {}
      // 3) Telegram WebApp initData
      if (TG && TG.initData) {
        try {
          const t = await apiPost("/api/auth/telegram", { initData: TG.initData });
          if (t && t.ok && !cancelled) { onAuthed(t.user); return; }
        } catch {}
      }
      if (!cancelled) setPhase("needLogin");
    })();
    return () => { cancelled = true; };
  }, [onAuthed]);

  return (
    <div className="dc">
      <div className="auth">
        <div className="auth__mark"><Icon name="sparkle" size={44} /></div>
        <div className="auth__kicker">TG Play · Dating Coach</div>
        <h1 className="auth__title">Коуч по общению <em>и уверенности</em></h1>
        <p className="auth__sub">36 уроков, реальные сценарии и ежедневная практика.</p>

        <div className="auth__bullets">
          <div className="auth__bullet">
            <div className="auth__bullet-dot"><Icon name="check" size={12} /></div>
            <div><b style={{color:"var(--text-1)"}}>3 уровня</b> — от основ до продвинутых техник общения</div>
          </div>
          <div className="auth__bullet">
            <div className="auth__bullet-dot"><Icon name="check" size={12} /></div>
            <div><b style={{color:"var(--text-1)"}}>17 достижений</b> и прогресс, который видно</div>
          </div>
          <div className="auth__bullet">
            <div className="auth__bullet-dot"><Icon name="check" size={12} /></div>
            <div><b style={{color:"var(--text-1)"}}>Ежедневная серия</b> — 5 минут в день достаточно</div>
          </div>
        </div>

        <div className="auth__cta">
          {phase === "loading" ? (
            <button className="btn btn--primary btn--block" disabled>
              <span className="boot-splash__spinner" style={{width:14,height:14,borderWidth:2}}/> Проверяем сессию…
            </button>
          ) : (
            <a href="https://tgplay.ru/" className="btn btn--primary btn--block"
               style={{textDecoration:"none"}}>
              Войти через tgplay.ru <Icon name="arrow" size={16} />
            </a>
          )}
        </div>
        <p className="auth__hint">
          {phase === "loading"
            ? "Подгружаем твой профиль…"
            : "Авторизуйся на tgplay.ru и вернись сюда"}
        </p>
      </div>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 2: Home / Dashboard
   ═══════════════════════════════════════════════════════════ */

function HomeScreen() {
  const { profile, progress, structure, loadStructure } = useData();
  const nav = useNav();

  useEffect(() => { loadStructure(); }, [loadStructure]);

  const initials = makeInitials(profile);
  const name = displayName(profile);
  const streak = progress?.current_streak ?? 0;
  const completed = progress?.completed_lessons ?? 0;
  const total = progress?.total_lessons ?? 36;
  const points = progress?.points ?? profile?.points ?? 0;

  // Неделя: восстановим последние 7 дней по стрику.
  // Локальный понедельник как старт недели.
  const today = new Date();
  const dow = (today.getDay() + 6) % 7; // 0=Mon...6=Sun
  const weekLabels = ["Пн","Вт","Ср","Чт","Пт","Сб","Вс"];
  const week = weekLabels.map((d, i) => {
    if (i < dow) {
      // прошедший день недели — закрашен, если стрик «дотягивается» назад
      const daysBack = dow - i;
      return { d, done: streak >= (daysBack + 1) };
    }
    if (i === dow) return { d, today: true, done: streak >= 1 };
    return { d };
  });

  const cur = useMemo(() => findCurrentLesson(structure, profile?.level), [structure, profile]);

  // continue card — индекс урока «X из 36»
  const lessonNo = cur ? (() => {
    let n = 0;
    for (const lv of structure || []) {
      for (const m of lv.modules) {
        for (const l of m.lessons) {
          n++;
          if (lv.id === cur.level.id && m.id === cur.module.id && l.id === cur.lesson.id) return n;
        }
      }
    }
    return n;
  })() : 0;

  return (
    <div className="dc">
      <div className="dc-body" style={{paddingTop:14}}>
        <div className="home-head">
          <div className="avatar">{initials}</div>
          <div className="home-head__who">
            <p className="home-head__greet">{greeting()}</p>
            <div className="home-head__name">{name}</div>
          </div>
          <button className="icon-btn" onClick={() => nav.push({id:"settings"})}>
            <Icon name="settings" size={18} />
          </button>
        </div>

        {/* streak hero */}
        <div className="streak-hero">
          <div className="streak-hero__top">
            <div>
              <div className="streak-hero__label"><Icon name="fire" size={12}/> Серия</div>
              <div className="streak-hero__count">
                <span className="streak-hero__num">{streak}</span>
                <span className="streak-hero__unit">{streak === 1 ? "день" : streak >= 2 && streak <= 4 ? "дня подряд" : "дней подряд"}</span>
              </div>
              <p className="streak-hero__sub">
                {streak === 0 ? "Начни сегодня — открой первый урок"
                 : streak < 3 ? "Хорошее начало, не теряй темп"
                 : streak < 7 ? "Уже три дня! Продолжай"
                 : "Дисциплина — это сила"}
              </p>
            </div>
          </div>
          <div className="streak-week">
            {week.map((x, i) => (
              <div key={i} className={"streak-day " + (x.done ? "streak-day--done " : "") + (x.today ? "streak-day--today" : "")}>
                <div className="streak-day__dot">
                  {x.done ? <Icon name="check" size={13}/> : x.today ? <Icon name="bolt" size={12}/> : null}
                </div>
                {x.d}
              </div>
            ))}
          </div>
        </div>

        {/* continue lesson */}
        <div className="sec-head">
          <h3>{cur ? "Продолжить" : "Все уроки пройдены"}</h3>
          <a onClick={() => nav.goTab("learn")}>Все уроки</a>
        </div>

        {cur ? (
          <div className="cont-card" onClick={() => nav.push({
            id: "lesson",
            levelId: cur.level.id, moduleId: cur.module.id, lessonId: cur.lesson.id,
          })}>
            <div className="cont-card__art"><Icon name="eye" size={34} /></div>
            <div className="cont-card__body">
              <div className="cont-card__eyebrow">Урок {String(lessonNo).padStart(2,"0")} из {total}</div>
              <div className="cont-card__title">{cur.lesson.title}</div>
              <div className="cont-card__meta">
                <span>{cur.module.name.replace(/^\W+\s*/, "")}</span>
                <span>·</span>
                <span>{levelMeta(cur.level.id).short}</span>
              </div>
              <div className="pbar pbar--thin">
                <span style={{width: total ? Math.round(completed/total*100) + "%" : "0%"}}/>
              </div>
            </div>
            <button className="cont-card__arrow"><Icon name="play" size={12} /></button>
          </div>
        ) : (
          <div className="cont-card" onClick={() => nav.goTab("ach")}>
            <div className="cont-card__art"><Icon name="trophy" size={34} /></div>
            <div className="cont-card__body">
              <div className="cont-card__eyebrow">Курс пройден</div>
              <div className="cont-card__title">Посмотри свои достижения</div>
              <div className="cont-card__meta">
                <span>{progress?.achievements_count || 0}/17 наград</span>
              </div>
            </div>
            <button className="cont-card__arrow"><Icon name="arrow" size={12} /></button>
          </div>
        )}

        {/* фокус — реальные числа */}
        <div className="sec-head">
          <h3>Твой прогресс</h3>
        </div>
        <div className="focus-rail">
          <div className="focus-tile">
            <div className="focus-tile__num">{points}</div>
            <div className="focus-tile__title">Очков</div>
            <div className="focus-tile__meta">+10 за урок</div>
          </div>
          <div className="focus-tile">
            <div className="focus-tile__num">{total ? Math.round(completed/total*100) : 0}%</div>
            <div className="focus-tile__title">Курс пройден</div>
            <div className="focus-tile__meta">{completed} из {total}</div>
          </div>
          <div className="focus-tile">
            <div className="focus-tile__num">{progress?.achievements_count || 0}</div>
            <div className="focus-tile__title">Достижений</div>
            <div className="focus-tile__meta">из 17</div>
          </div>
        </div>
      </div>
      <TabBar active="home" />
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 3: Learning — список уровней + модули
   ═══════════════════════════════════════════════════════════ */

function LearningScreen() {
  const { profile, progress, structure, loadStructure } = useData();
  const nav = useNav();
  const [openLevel, setOpenLevel] = useState(profile?.level || "beginner");

  useEffect(() => { loadStructure(); }, [loadStructure]);

  if (!structure) {
    return (
      <div className="dc">
        <div className="dc-topbar">
          <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Обучение</div>
        </div>
        <div className="loader"><div className="loader__sp"/></div>
        <TabBar active="learn" />
      </div>
    );
  }

  const currentLevel = structure.find(l => l.id === (profile?.level || "beginner")) || structure[0];
  const curStats = (() => {
    let total = 0, done = 0;
    currentLevel.modules.forEach(m => m.lessons.forEach(l => { total++; if (l.completed) done++; }));
    return { total, done, pct: total ? Math.round(done/total*100) : 0 };
  })();
  const points = progress?.points ?? profile?.points ?? 0;
  const meta = levelMeta(currentLevel.id);

  const opened = structure.find(l => l.id === openLevel);

  return (
    <div className="dc">
      <div className="dc-topbar">
        <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Обучение</div>
      </div>
      <div className="dc-body">
        <div className="level-hero">
          <div className="level-hero__badge"><Icon name="bolt" size={10}/> Твой текущий уровень</div>
          <h2 className="level-hero__title">{meta.short} — {meta.sub.toLowerCase()}</h2>
          <p className="level-hero__sub">
            Ты освоил {curStats.done} {curStats.done === 1 ? "урок" : "уроков"} из {curStats.total}.
            {curStats.total - curStats.done > 0 && ` Осталось ${curStats.total - curStats.done}, чтобы открыть следующий.`}
          </p>
          <div className="pbar"><span style={{width: curStats.pct + "%"}}/></div>
          <div className="level-hero__stats">
            <div>
              <div className="level-hero__stat-num">{curStats.done}<span style={{color:"var(--text-3)",fontSize:14}}>/{curStats.total}</span></div>
              <div className="level-hero__stat-label">Уроков</div>
            </div>
            <div>
              <div className="level-hero__stat-num">{points}</div>
              <div className="level-hero__stat-label">Очков</div>
            </div>
            <div>
              <div className="level-hero__stat-num">{progress?.current_streak || 0}<span style={{color:"var(--text-3)",fontSize:14}}>д</span></div>
              <div className="level-hero__stat-label">Серия</div>
            </div>
          </div>
        </div>

        <div className="sec-head" style={{marginTop:0}}>
          <h3>Путь обучения</h3>
          <a>3 уровня · {progress?.total_lessons || 36} уроков</a>
        </div>
        <div className="path-list">
          {structure.map(lv => {
            let total = 0, done = 0;
            lv.modules.forEach(m => m.lessons.forEach(l => { total++; if (l.completed) done++; }));
            const pct = total ? Math.round(done/total*100) : 0;
            const state = !lv.unlocked ? "locked"
                          : (lv.id === (profile?.level || "beginner") ? "current" : "done");
            const lm = levelMeta(lv.id);
            return (
              <div key={lv.id}
                   className={"path-level path-level--" + state}
                   onClick={() => lv.unlocked && setOpenLevel(lv.id)}>
                <div className="path-level__head">
                  <div className="path-level__mark">
                    {state === "locked" ? <Icon name="lock" size={16}/> : lm.idx}
                  </div>
                  <div className="path-level__body">
                    <div className="path-level__title">{lm.name} уровень</div>
                    <div className="path-level__sub">{lm.sub}</div>
                  </div>
                  <div className="path-level__caret"><Icon name="chev" size={18}/></div>
                </div>
                <div className="path-level__bottom">
                  <div className="path-level__progress-meta num-mono">{done}/{total}</div>
                  <div className="pbar path-level__bar"><span style={{width: pct + "%"}}/></div>
                </div>
              </div>
            );
          })}
        </div>

        <div className="sec-head">
          <h3>Модули — {levelMeta(opened.id).short}</h3>
          {(() => {
            let t=0, d=0;
            opened.modules.forEach(m => m.lessons.forEach(l => { t++; if (l.completed) d++; }));
            return <a className="num-mono">{d}/{t}</a>;
          })()}
        </div>

        {!opened.unlocked && (
          <div className="dc-error">🔒 Этот уровень ещё закрыт. Пройди уроки текущего уровня.</div>
        )}

        <div className="mod-list">
          {opened.modules.map((m, mi) => {
            const total = m.lessons.length;
            const done = m.lessons.filter(l => l.completed).length;
            const state = done === total ? "done" : (done > 0 ? "current" : "todo");
            return (
              <div key={m.id} className={"mod mod--" + state}>
                <div className="mod__head">
                  <div className="mod__index">{String(mi+1).padStart(2,"0")}</div>
                  <div className="mod__title">{m.name}</div>
                  <div className="mod__pct">{done}/{total}</div>
                </div>
                <div className="pbar pbar--thin"><span style={{width: total ? (done/total*100) + "%" : "0%"}}/></div>
                <div className="mod__lessons">
                  {m.lessons.map((les, li) => {
                    const prevCompleted = li === 0 ? true : m.lessons[li-1].completed;
                    const lstate = les.completed ? "done"
                                   : (!opened.unlocked ? "lock"
                                   : prevCompleted ? "current" : "todo");
                    return (
                      <div key={les.id}
                           className={"mod-lesson mod-lesson--" + lstate}
                           onClick={() => opened.unlocked && nav.push({
                             id: "lesson", levelId: opened.id, moduleId: m.id, lessonId: les.id,
                           })}>
                        <div className="mod-lesson__dot">
                          {lstate === "done" ? <Icon name="check" size={10}/>
                           : lstate === "current" ? <Icon name="play" size={8}/>
                           : lstate === "lock" ? <Icon name="lock" size={9}/> : null}
                        </div>
                        <div className="mod-lesson__title">{les.title}</div>
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })}
        </div>
      </div>
      <TabBar active="learn" />
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 4: Lesson reader
   ═══════════════════════════════════════════════════════════ */

function LessonScreen({ levelId, moduleId, lessonId }) {
  const { structure, loadStructure, invalidate } = useData();
  const nav = useNav();
  const toast = useToast();
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [completing, setCompleting] = useState(false);

  useEffect(() => { loadStructure(); }, [loadStructure]);

  useEffect(() => {
    let cancelled = false;
    setData(null);
    setError(null);
    (async () => {
      try {
        const d = await apiGet(`/api/lessons/${levelId}/${moduleId}/${lessonId}`);
        if (!cancelled) setData(d);
      } catch (e) {
        if (!cancelled) setError(e.status === 403 ? "locked" : "error");
      }
    })();
    return () => { cancelled = true; };
  }, [levelId, moduleId, lessonId]);

  // Хлебные крошки и индекс
  const crumbs = (() => {
    if (!structure) return null;
    const lv = structure.find(l => l.id === levelId);
    if (!lv) return null;
    const m = lv.modules.find(x => x.id === moduleId);
    if (!m) return null;
    const lessonIdx = m.lessons.findIndex(l => l.id === lessonId);
    return { lv, m, lessonIdx, lvMeta: levelMeta(lv.id) };
  })();

  // Глобальный номер урока для прогресс-бара чтения
  const globalIdx = useMemo(() => {
    if (!structure) return null;
    let n = 0, total = 0;
    let cur = 0;
    for (const lv of structure) {
      for (const m of lv.modules) {
        for (const l of m.lessons) {
          n++;
          total++;
          if (lv.id === levelId && m.id === moduleId && l.id === lessonId) cur = n;
        }
      }
    }
    return { cur, total };
  }, [structure, levelId, moduleId, lessonId]);

  const onComplete = async () => {
    if (completing) return;
    setCompleting(true);
    try {
      const r = await apiPost(`/api/lessons/${levelId}/${moduleId}/${lessonId}/complete`);
      haptic("success");
      invalidate();
      // celebration
      nav.replace({
        id: "celeb",
        result: r,
        levelId, moduleId, lessonId,
        title: data?.title || "",
      });
    } catch {
      toast("Не удалось завершить урок");
    } finally {
      setCompleting(false);
    }
  };

  return (
    <div className="dc">
      <div className="dc-topbar">
        <button className="dc-topbar__back" onClick={() => nav.back()}>
          <Icon name="back" size={16}/>
        </button>
        <div className="dc-topbar__title">
          {globalIdx ? `Урок ${String(globalIdx.cur).padStart(2,"0")}` : "Урок"}
        </div>
      </div>

      {globalIdx && (
        <div className="lesson__progress">
          <span style={{width: Math.round(globalIdx.cur / globalIdx.total * 100) + "%"}}/>
        </div>
      )}

      {error === "locked" ? (
        <div className="dc-error" style={{marginTop:24}}>
          🔒 Этот уровень ещё заблокирован.<br/>Пройди все уроки текущего уровня.
        </div>
      ) : error ? (
        <div className="dc-error" style={{marginTop:24}}>Ошибка загрузки урока</div>
      ) : !data ? (
        <div className="loader"><div className="loader__sp"/></div>
      ) : (
        <>
          <div className="lesson">
            {crumbs && (
              <div className="lesson__crumbs">
                {crumbs.lvMeta.short} · {crumbs.m.name.replace(/^\W+\s*/, "")}
              </div>
            )}
            <h1 className="lesson__title">{data.title}</h1>
            <div className="lesson__meta">
              <span className="lesson__meta-item">
                <Icon name="bolt" size={11}/> <strong>+{data.points}</strong> очков
              </span>
              {data.completed && (
                <span className="lesson__meta-item">
                  <Icon name="check" size={11}/> <strong>Пройден</strong>
                </span>
              )}
            </div>
            <div className="lesson__content"
                 dangerouslySetInnerHTML={{__html: data.content}}/>
          </div>

          <div className="lesson-foot">
            <button className="btn btn--ghost" onClick={() => nav.back()}>
              <Icon name="back" size={14}/> Назад
            </button>
            {data.completed ? (
              <button className="btn btn--ghost" style={{flex:2}} onClick={() => nav.back()}>
                <Icon name="check" size={14}/> Уже пройден
              </button>
            ) : (
              <button className="btn btn--primary" style={{flex:2}}
                      onClick={onComplete} disabled={completing}>
                {completing ? "…" : <>Завершить урок · +{data.points} <Icon name="arrow" size={14}/></>}
              </button>
            )}
          </div>
        </>
      )}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 5: Celebration
   ═══════════════════════════════════════════════════════════ */

function CelebrationScreen({ result, levelId, moduleId, lessonId, title }) {
  const { structure, profile, progress } = useData();
  const nav = useNav();

  // Найти следующий урок
  const next = useMemo(() => {
    if (!structure) return null;
    for (const lv of structure) {
      for (const m of lv.modules) {
        for (let i = 0; i < m.lessons.length; i++) {
          const l = m.lessons[i];
          if (lv.id === levelId && m.id === moduleId && l.id === lessonId) {
            // следующий — может быть в этом же модуле
            if (i + 1 < m.lessons.length) {
              return { level: lv, module: m, lesson: m.lessons[i+1] };
            }
            // или первый незавершённый дальше по структуре
            return findCurrentLesson(structure, profile?.level);
          }
        }
      }
    }
    return null;
  }, [structure, profile, levelId, moduleId, lessonId]);

  // % прохождения текущего уровня
  const pct = useMemo(() => {
    if (!structure) return 0;
    const lvId = result?.level_up || profile?.level || "beginner";
    const lv = structure.find(l => l.id === lvId);
    if (!lv) return 0;
    let t = 0, d = 0;
    lv.modules.forEach(m => m.lessons.forEach(l => { t++; if (l.completed) d++; }));
    return t ? Math.round(d/t*100) : 0;
  }, [structure, profile, result]);

  const newAch = result?.new_achievements?.[0];
  const wasAlready = result?.already_completed;

  return (
    <div className="dc">
      <div className="celeb">
        <div className="celeb__trophy">
          <Icon name={result?.level_up ? "crown" : "sparkle"} size={58}/>
        </div>
        <div className="celeb__kicker">
          {result?.level_up ? "Новый уровень!" : wasAlready ? "Урок уже пройден" : "Урок завершён"}
        </div>
        <h1 className="celeb__title">
          {result?.level_up
            ? `Открыт ${levelMeta(result.level_up).name.toLowerCase()} уровень`
            : "Ещё один шаг к уверенности"}
        </h1>
        <p className="celeb__sub">
          {wasAlready
            ? `Урок «${title}» был пройден ранее.`
            : `Ты прошёл урок «${title}». Молодец — не останавливайся.`}
        </p>

        <div className="celeb-stats">
          <div className="celeb-stat">
            <div className="celeb-stat__num">+{wasAlready ? 0 : 10}</div>
            <div className="celeb-stat__label">Очков</div>
          </div>
          <div className="celeb-stat">
            <div className="celeb-stat__num">{result?.current_streak ?? progress?.current_streak ?? 0}</div>
            <div className="celeb-stat__label">Серия</div>
          </div>
          <div className="celeb-stat">
            <div className="celeb-stat__num">{pct}%</div>
            <div className="celeb-stat__label">Уровень</div>
          </div>
        </div>

        {newAch && (
          <div className="celeb-ach">
            <div className="celeb-ach__icon">
              <span style={{fontSize:24}}>{newAch.emoji || "🏆"}</span>
            </div>
            <div>
              <div className="celeb-ach__kicker">Новое достижение</div>
              <div className="celeb-ach__name">{newAch.name}</div>
            </div>
          </div>
        )}

        <div className="celeb__cta">
          {next ? (
            <button className="btn btn--primary btn--block"
                    onClick={() => nav.replace({
                      id: "lesson",
                      levelId: next.level.id,
                      moduleId: next.module.id,
                      lessonId: next.lesson.id,
                    })}>
              Следующий урок: {next.lesson.title} <Icon name="arrow" size={14}/>
            </button>
          ) : (
            <button className="btn btn--primary btn--block"
                    onClick={() => nav.goTab("ach")}>
              К достижениям <Icon name="arrow" size={14}/>
            </button>
          )}
          <button className="btn btn--ghost btn--block"
                  onClick={() => nav.goTab("learn")}>
            К карте курса
          </button>
        </div>
      </div>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 6: Achievements
   ═══════════════════════════════════════════════════════════ */

const ACH_ICON_MAP = {
  first_lesson:"target", lessons_5:"book", lessons_10:"medal",
  lessons_20:"crown",    lessons_all:"trophy",
  streak_3:"fire", streak_7:"flame", streak_14:"bolt", streak_30:"shield",
  level_intermediate:"bolt", level_advanced:"crown",
  points_50:"bolt", points_100:"sparkle", points_200:"gift", points_500:"crown",
  early_bird:"sparkle", completionist:"crown",
};

function AchievementsScreen() {
  const [list, setList] = useState(null);
  const [error, setError] = useState(false);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const data = await apiGet("/api/achievements/");
        if (!cancelled) setList(data);
      } catch {
        if (!cancelled) setError(true);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  if (error) {
    return (
      <div className="dc">
        <div className="dc-topbar">
          <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Достижения</div>
        </div>
        <div className="dc-error">Не удалось загрузить достижения</div>
        <TabBar active="ach" />
      </div>
    );
  }

  if (!list) {
    return (
      <div className="dc">
        <div className="dc-topbar">
          <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Достижения</div>
        </div>
        <div className="loader"><div className="loader__sp"/></div>
        <TabBar active="ach" />
      </div>
    );
  }

  const total = list.length;
  const earned = list.filter(a => a.unlocked).length;
  const groups = groupAchievements(list);

  const r = 30, c = 2 * Math.PI * r;
  const pct = total ? earned / total : 0;

  const renderAch = (a) => (
    <div key={a.id} className={"ach ach--" + (a.unlocked ? "unlocked" : "locked")}
         title={a.description}>
      <div className="ach__icon">
        {a.unlocked
          ? <Icon name={ACH_ICON_MAP[a.id] || "trophy"} size={18}/>
          : <Icon name="lock" size={18}/>}
      </div>
      <div className="ach__name">{a.name}</div>
    </div>
  );

  return (
    <div className="dc">
      <div className="dc-topbar">
        <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Достижения</div>
      </div>
      <div className="dc-body">
        <div className="ach-summary">
          <div className="ach-ring">
            <svg viewBox="0 0 68 68">
              <circle cx="34" cy="34" r={r} stroke="oklch(1 0 0 / 0.1)" strokeWidth="5" fill="none"/>
              <circle cx="34" cy="34" r={r} stroke="url(#gradR)" strokeWidth="5" fill="none"
                      strokeDasharray={c} strokeDashoffset={c * (1 - pct)} strokeLinecap="round"
                      transform="rotate(-90 34 34)"/>
              <defs>
                <linearGradient id="gradR" x1="0" y1="0" x2="1" y2="1">
                  <stop offset="0" stopColor="oklch(0.74 0.175 20)"/>
                  <stop offset="1" stopColor="oklch(0.52 0.20 340)"/>
                </linearGradient>
              </defs>
            </svg>
            <div className="ach-ring__num">{earned}<small>/{total}</small></div>
          </div>
          <div className="ach-summary__body">
            <div className="ach-summary__title">
              {earned === total ? "Все достижения собраны!"
               : earned === 0 ? "Начни путь — пройди первый урок"
               : "На пути к перфекционисту"}
            </div>
            <div className="ach-summary__sub">
              {earned === total ? "Невероятно — ты собрал всё"
               : `Осталось ${total - earned} достижений до полного набора`}
            </div>
          </div>
        </div>

        {groups.map(g => {
          const gEarned = g.items.filter(a => a.unlocked).length;
          return (
            <React.Fragment key={g.name}>
              <div className="ach-group">
                <span>{g.name}</span>
                <span className="num-mono muted">{gEarned}/{g.items.length}</span>
              </div>
              <div className="ach-grid">{g.items.map(renderAch)}</div>
            </React.Fragment>
          );
        })}
      </div>
      <TabBar active="ach" />
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 7: Stats
   ═══════════════════════════════════════════════════════════ */

function StatsScreen() {
  const { profile, progress, structure, loadStructure } = useData();
  useEffect(() => { loadStructure(); }, [loadStructure]);

  const initials = makeInitials(profile);
  const name = displayName(profile);
  const lvm = levelMeta(profile?.level);
  const points = progress?.points ?? profile?.points ?? 0;
  const completed = progress?.completed_lessons ?? 0;
  const total = progress?.total_lessons ?? 36;
  const streak = progress?.current_streak ?? 0;
  const best = progress?.best_streak ?? 0;
  const ach = progress?.achievements_count ?? 0;

  const curLevel = structure?.find(l => l.id === (profile?.level || "beginner"));
  const curStats = (() => {
    if (!curLevel) return { done: 0, total: 0, pct: 0 };
    let t = 0, d = 0;
    curLevel.modules.forEach(m => m.lessons.forEach(l => { t++; if (l.completed) d++; }));
    return { done: d, total: t, pct: t ? Math.round(d/t*100) : 0 };
  })();

  const toNext = POINTS_TO_NEXT[profile?.level || "beginner"];
  const remaining = toNext > 0 ? Math.max(0, toNext - points) : 0;

  // Heatmap не выводим — нет API daily activity. Вместо неё — разбивка по модулям текущего уровня.

  return (
    <div className="dc">
      <div className="dc-topbar">
        <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Статистика</div>
      </div>
      <div className="dc-body">
        <div className="stat-top">
          <div className="stat-top__row">
            <div className="stat-top__avatar">{initials}</div>
            <div>
              <div className="stat-top__name">{name}</div>
              <div className="stat-top__level">{lvm.name.toUpperCase()} · {curStats.done}/{curStats.total} УРОКОВ</div>
            </div>
          </div>
          <div className="pbar"><span style={{width: curStats.pct + "%"}}/></div>
          <div className="stat-top__xp">
            <div>
              <div className="stat-top__xp-num">{points} <span style={{fontSize:12,color:"var(--text-3)",fontWeight:600,letterSpacing:0}}>очков</span></div>
            </div>
            {toNext > 0 && (
              <div className="stat-top__xp-next">
                до {profile?.level === "beginner" ? "среднего" : "продвинутого"}: {remaining}
              </div>
            )}
          </div>
        </div>

        <div className="stat-grid">
          <div className="stat-kpi">
            <div className="stat-kpi__label"><Icon name="fire" size={11}/> Серия</div>
            <div className="stat-kpi__num">{streak}<span style={{fontSize:13,color:"var(--text-3)",fontWeight:600}}> дн.</span></div>
            <div className="stat-kpi__delta">▲ лучшая {best} дн.</div>
          </div>
          <div className="stat-kpi">
            <div className="stat-kpi__label"><Icon name="book" size={11}/> Уроки</div>
            <div className="stat-kpi__num">{completed}<span style={{fontSize:13,color:"var(--text-3)",fontWeight:600}}>/{total}</span></div>
            <div className="stat-kpi__hint">{total ? Math.round(completed/total*100) : 0}% курса</div>
          </div>
          <div className="stat-kpi">
            <div className="stat-kpi__label"><Icon name="trophy" size={11}/> Достижения</div>
            <div className="stat-kpi__num">{ach}<span style={{fontSize:13,color:"var(--text-3)",fontWeight:600}}>/17</span></div>
            <div className="stat-kpi__hint">{Math.round(ach/17*100)}% открыто</div>
          </div>
          <div className="stat-kpi">
            <div className="stat-kpi__label"><Icon name="bolt" size={11}/> Очки</div>
            <div className="stat-kpi__num">{points}</div>
            <div className="stat-kpi__hint">+10 за урок</div>
          </div>
        </div>

        {curLevel && (
          <div className="break">
            <div className="break__title">Разбивка — {lvm.short} уровень</div>
            {curLevel.modules.map(m => {
              const t = m.lessons.length;
              const d = m.lessons.filter(l => l.completed).length;
              const pct = t ? Math.round(d/t*100) : 0;
              return (
                <div className="break__row" key={m.id}>
                  <div className="break__name">{m.name.replace(/^\W+\s*/, "")}</div>
                  <div className="break__val">{d}/{t}</div>
                  <div className="break__bar"><span style={{width: pct + "%"}}/></div>
                </div>
              );
            })}
          </div>
        )}
      </div>
      <TabBar active="stats" />
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   Экран 8: Settings
   ═══════════════════════════════════════════════════════════ */

function SettingsScreen() {
  const { profile, setProfile } = useData();
  const nav = useNav();
  const toast = useToast();
  const [s, setS] = useState(null);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const data = await apiGet("/api/settings/");
        if (!cancelled) setS(data);
      } catch {}
    })();
    return () => { cancelled = true; };
  }, []);

  const Switch = ({ on, onClick, disabled }) => (
    <button className={"switch " + (on ? "switch--on" : "")}
            onClick={onClick} disabled={disabled}/>
  );

  const update = async (patch) => {
    if (saving) return;
    setSaving(true);
    setS(prev => ({ ...prev, ...patch })); // optimistic
    try {
      const next = await apiPatch("/api/settings/", patch);
      setS(next);
      toast("Сохранено");
      haptic("light");
    } catch {
      toast("Не удалось сохранить");
      // откат — перечитать
      try { setS(await apiGet("/api/settings/")); } catch {}
    } finally {
      setSaving(false);
    }
  };

  const onLogout = async () => {
    try { await apiPost("/api/auth/logout"); } catch {}
    setProfile(null);
  };

  const initials = makeInitials(profile);
  const name = displayName(profile);
  const lvm = levelMeta(profile?.level);

  return (
    <div className="dc">
      <div className="dc-topbar">
        <button className="dc-topbar__back" onClick={() => nav.back()}>
          <Icon name="back" size={16}/>
        </button>
        <div className="dc-topbar__title" style={{fontSize:20, letterSpacing:"-0.025em"}}>Настройки</div>
      </div>
      <div className="dc-body">
        <div className="set-card" style={{marginTop:6}}>
          <div className="set-row">
            <div className="avatar" style={{width:44, height:44, borderRadius:14, fontSize:15}}>{initials}</div>
            <div className="set-row__body">
              <div className="set-row__title">{name}</div>
              <div className="set-row__sub">tgplay.ru · {lvm.name} уровень</div>
            </div>
          </div>
        </div>

        {!s ? (
          <div className="loader"><div className="loader__sp"/></div>
        ) : (
          <>
            <div className="set-group-label">Уведомления</div>
            <div className="set-card">
              <div className="set-row">
                <div className="set-row__icon"><Icon name="bell" size={15}/></div>
                <div className="set-row__body">
                  <div className="set-row__title">Уведомления</div>
                  <div className="set-row__sub">Прогресс и достижения</div>
                </div>
                <Switch on={s.notifications}
                        disabled={saving}
                        onClick={() => update({ notifications: !s.notifications })}/>
              </div>
              <div className="set-row">
                <div className="set-row__icon"><Icon name="cal" size={15}/></div>
                <div className="set-row__body">
                  <div className="set-row__title">Ежедневное напоминание</div>
                  <div className="set-row__sub">Не дать серии прерваться</div>
                </div>
                <Switch on={s.daily_reminder}
                        disabled={saving}
                        onClick={() => update({ daily_reminder: !s.daily_reminder })}/>
              </div>
              <div className="set-row">
                <div className="set-row__icon"><Icon name="clock" size={15}/></div>
                <div className="set-row__body">
                  <div className="set-row__title">Время напоминания</div>
                </div>
                <input type="time" className="set-row__value"
                       value={s.reminder_time || "09:00"}
                       disabled={saving}
                       style={{background:"none", border:"none", color:"var(--text-1)", fontFamily:"var(--font-display)", fontWeight:700}}
                       onChange={e => update({ reminder_time: e.target.value })}/>
              </div>
            </div>

            <div className="set-group-label">Информация</div>
            <div className="set-card">
              <div className="set-row">
                <div className="set-row__icon"><Icon name="clock" size={15}/></div>
                <div className="set-row__body">
                  <div className="set-row__title">Часовой пояс</div>
                </div>
                <div className="set-row__value muted" style={{fontSize:12}}>{s.timezone || "—"}</div>
              </div>
              <div className="set-row">
                <div className="set-row__icon"><Icon name="info" size={15}/></div>
                <div className="set-row__body">
                  <div className="set-row__title">О приложении</div>
                </div>
                <div className="set-row__value muted">v 1.1</div>
              </div>
            </div>
          </>
        )}

        <div className="set-card" style={{marginTop:14}}>
          <div className="set-row" style={{color:"var(--alert)", cursor:"pointer"}} onClick={onLogout}>
            <div className="set-row__icon" style={{background:"oklch(0.68 0.22 28 / 0.14)", color:"var(--alert)"}}>
              <Icon name="logout" size={15}/>
            </div>
            <div className="set-row__body">
              <div className="set-row__title" style={{color:"var(--alert)"}}>Выйти</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════
   App root + router
   ═══════════════════════════════════════════════════════════ */

function Router() {
  const nav = useNav();
  const t = nav.top;
  switch (t.id) {
    case "home":     return <HomeScreen/>;
    case "learn":    return <LearningScreen/>;
    case "ach":      return <AchievementsScreen/>;
    case "stats":    return <StatsScreen/>;
    case "lesson":   return <LessonScreen levelId={t.levelId} moduleId={t.moduleId} lessonId={t.lessonId}/>;
    case "celeb":    return <CelebrationScreen result={t.result} levelId={t.levelId} moduleId={t.moduleId} lessonId={t.lessonId} title={t.title}/>;
    case "settings": return <SettingsScreen/>;
    default:         return <HomeScreen/>;
  }
}

function App() {
  const [profile, setProfile] = useState(null);
  const [bootDone, setBootDone] = useState(false);

  // первичный bootstrap — не блокируем, просто отдаём AuthScreen и он сам решает
  useEffect(() => { setBootDone(true); }, []);

  // когда логинимся/разлогиниваемся — обновляем шапку tgplay
  useEffect(() => {
    if (window.TgPlayHeader && profile) {
      try { window.TgPlayHeader.setUser(profile); } catch {}
    }
  }, [profile]);

  if (!bootDone) return null;

  if (!profile) {
    return (
      <ToastProvider>
        <AuthScreen onAuthed={(u) => {
          setProfile(u);
          haptic("success");
        }}/>
      </ToastProvider>
    );
  }

  return (
    <ToastProvider>
      <DataProvider profile={profile} setProfile={setProfile}>
        <NavProvider initial={{ id: "home" }}>
          <BootstrapData/>
          <Router/>
        </NavProvider>
      </DataProvider>
    </ToastProvider>
  );
}

/* отдельный компонент чтобы тянуть прогресс при первом открытии любого экрана */
function BootstrapData() {
  const { loadProgress } = useData();
  useEffect(() => { loadProgress(); }, [loadProgress]);
  return null;
}

/* ───────── Init ───────── */

(function init() {
  if (TG) {
    try {
      TG.ready();
      TG.expand();
      if (TG.initData) _initData = TG.initData;
    } catch {}
  }
  const root = ReactDOM.createRoot(document.getElementById("root"));
  root.render(<App/>);
})();
