/* ============================================================
   screens-b.jsx — Calendar, Courses, Notes, Stats, Graph
   ============================================================ */
const React = window.React;
const { useState, useRef, useEffect } = React;
const Icon = window.Icon;
const A = window.PlannerActions;

/* ================= CALENDAR ================= */
const HOURS = [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22];
function timeToMin(t) { const [h, m] = t.split(":").map(Number); return h * 60 + m; }

function CalendarScreen({ state, nav }) {
  const Cmp = window;
  const [overHour, setOverHour] = useState(null);
  const [editingTask, setEditingTask] = useState(null);
  const [editTime, setEditTime] = useState("");
  const [editTimeEnd, setEditTimeEnd] = useState("");
  const dragId = useRef(null);
  const scheduled = state.tasks.filter((t) => t.time);
  const unscheduled = state.tasks.filter((t) => !t.time && !t.done);
  const SLOT_H = 72;
  const top0 = HOURS[0] * 60;

  const onDropHour = (h) => {
    if (dragId.current != null) {
      A.scheduleTask(dragId.current, String(h).padStart(2, "0") + ":00");
      dragId.current = null; setOverHour(null);
    }
  };

  const openTimeEditor = (t, e) => {
    e.stopPropagation();
    if (editingTask === t.id) { setEditingTask(null); return; }
    setEditingTask(t.id);
    setEditTime(t.time || "");
    setEditTimeEnd(t.timeEnd || "");
  };

  const saveTime = (t) => {
    if (editTime) {
      A.scheduleTask(t.id, editTime, editTimeEnd || undefined);
    } else {
      A.unscheduleTask(t.id);
    }
    setEditingTask(null);
  };

  return (
    <div className="page page--wide screen-enter">
      <div className="page-head">
        <div className="page-head__titles">
          <div className="kicker-row"><span className="eyebrow-mono">Расписание</span><span className="date-stamp">{state.dateLabel}</span></div>
          <h1 className="page-title">Календарь дня</h1>
        </div>
        <div className="page-actions"><Cmp.GButton variant="ghost" icon="today" onClick={() => nav({ screen: "today" })}>К задачам</Cmp.GButton></div>
      </div>

      <div className="cols" style={{ gridTemplateColumns: "1fr 300px", alignItems: "start" }}>
        <div className="cal">
          <div className="cal__times">
            {HOURS.map((h) => <div key={h} className="cal__time">{String(h).padStart(2, "0")}:00</div>)}
          </div>
          <div className="cal__track">
            {HOURS.map((h) => (
              <div key={h} className={"cal__slot" + (overHour === h ? " cal__slot--over" : "")}
                onDragOver={(e) => { e.preventDefault(); setOverHour(h); }}
                onDragLeave={() => setOverHour((cur) => (cur === h ? null : cur))}
                onDrop={() => onDropHour(h)} />
            ))}
            {scheduled.map((t) => {
              const top = (timeToMin(t.time) - top0) / 60 * SLOT_H;
              const h = Math.max((t.dur / 60) * SLOT_H - 6, 44);
              const linked = window.PlannerLookup.entity(state, t.linkId);
              const cls = t.kind === "course" ? " cal__event--course" : t.kind === "material" ? " cal__event--material" : "";
              return (
                <div key={t.id} className={"cal__event" + cls} style={{ top, height: h }}
                  draggable onDragStart={() => { dragId.current = t.id; }}
                  onClick={(e) => openTimeEditor(t, e)}>
                  <div className="cal__event-time">{t.time}{t.timeEnd ? "–" + t.timeEnd : ""} · {t.dur}м · {t.pts} PTS</div>
                  <div className="cal__event-title">{t.title}</div>
                  {editingTask === t.id && (
                    <div className="cal__time-editor" onClick={(e) => e.stopPropagation()}
                      style={{ position: "absolute", top: "100%", left: 0, right: 0, background: "var(--paper-00)", border: "var(--bd-bold)", padding: 10, zIndex: 20, display: "flex", flexDirection: "column", gap: 8 }}>
                      <div className="row-3" style={{ gap: 8, alignItems: "center" }}>
                        <span className="e-label" style={{ minWidth: 40 }}>С</span>
                        <input type="time" value={editTime} onChange={(e) => setEditTime(e.target.value)}
                          style={{ border: "1px solid var(--ink-40)", padding: "4px 8px", fontFamily: "var(--font-mono)", background: "var(--paper-00)", fontSize: "var(--t-small)" }} />
                      </div>
                      <div className="row-3" style={{ gap: 8, alignItems: "center" }}>
                        <span className="e-label" style={{ minWidth: 40 }}>До</span>
                        <input type="time" value={editTimeEnd} onChange={(e) => setEditTimeEnd(e.target.value)}
                          style={{ border: "1px solid var(--ink-40)", padding: "4px 8px", fontFamily: "var(--font-mono)", background: "var(--paper-00)", fontSize: "var(--t-small)" }} />
                      </div>
                      <div className="row-2" style={{ gap: 6 }}>
                        <Cmp.GButton variant="signal" onClick={() => saveTime(t)} style={{ padding: "4px 10px", fontSize: 12 }}>OK</Cmp.GButton>
                        <Cmp.GButton variant="ghost" onClick={() => { A.unscheduleTask(t.id); setEditingTask(null); }} style={{ padding: "4px 10px", fontSize: 12 }}>Снять</Cmp.GButton>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        </div>

        <div>
          <Cmp.SectionRule kicker="Перетащите →">Без времени</Cmp.SectionRule>
          <div className="unscheduled">
            {unscheduled.length === 0 && <div className="empty">Всё запланировано.</div>}
            {unscheduled.map((t) => (
              <div key={t.id} className="unscheduled__chip" draggable
                style={{ position: "relative" }}
                onDragStart={(e) => { dragId.current = t.id; e.currentTarget.classList.add("dragging"); }}
                onDragEnd={(e) => e.currentTarget.classList.remove("dragging")}
                onClick={(e) => openTimeEditor(t, e)}>
                <span className="task__handle"><Icon name="drag" size={16} /></span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: "var(--t-small)", lineHeight: 1.15 }}>{t.title}</div>
                  <div className="mono" style={{ fontSize: 12, color: "var(--text-muted)" }}>{t.dur}м · +{t.pts}</div>
                </div>
                {editingTask === t.id && (
                  <div className="cal__time-editor" onClick={(e) => e.stopPropagation()}
                    style={{ position: "absolute", top: "100%", left: 0, right: 0, background: "var(--paper-00)", border: "var(--bd-bold)", padding: 10, zIndex: 20, display: "flex", flexDirection: "column", gap: 8 }}>
                    <div className="row-3" style={{ gap: 8, alignItems: "center" }}>
                      <span className="e-label" style={{ minWidth: 40 }}>С</span>
                      <input type="time" value={editTime} onChange={(e) => setEditTime(e.target.value)}
                        style={{ border: "1px solid var(--ink-40)", padding: "4px 8px", fontFamily: "var(--font-mono)", background: "var(--paper-00)", fontSize: "var(--t-small)" }} />
                    </div>
                    <div className="row-3" style={{ gap: 8, alignItems: "center" }}>
                      <span className="e-label" style={{ minWidth: 40 }}>До</span>
                      <input type="time" value={editTimeEnd} onChange={(e) => setEditTimeEnd(e.target.value)}
                        style={{ border: "1px solid var(--ink-40)", padding: "4px 8px", fontFamily: "var(--font-mono)", background: "var(--paper-00)", fontSize: "var(--t-small)" }} />
                    </div>
                    <div className="row-2" style={{ gap: 6 }}>
                      <Cmp.GButton variant="signal" onClick={() => saveTime(t)} style={{ padding: "4px 10px", fontSize: 12 }}>OK</Cmp.GButton>
                      <Cmp.GButton variant="ghost" onClick={() => setEditingTask(null)} style={{ padding: "4px 10px", fontSize: 12 }}>Отмена</Cmp.GButton>
                    </div>
                  </div>
                )}
              </div>
            ))}
          </div>
          <div className="callout-hint" style={{ marginTop: "var(--s-5)", padding: "var(--s-4)", border: "1px dashed var(--ink-40)" }}>
            <div className="hand" style={{ fontSize: "1.2rem" }}>Тащи задачу на час →</div>
            <div className="muted" style={{ fontSize: "var(--t-small)", marginTop: 4 }}>Перетащи блок на сетке, чтобы перенести. Клик — редактор времени.</div>
          </div>
        </div>
      </div>
    </div>
  );
}
function navTo2(nav, e) {
  if (e._kind === "course") nav({ screen: "course", id: e.id });
  else if (e._kind === "note") nav({ screen: "notes", id: e.id });
  else nav({ screen: "material", id: e.id });
}

/* ================= COURSES ================= */
function CoursesScreen({ state, nav }) {
  const Cmp = window;
  const [adding, setAdding] = useState(false);
  const [title, setTitle] = useState("");
  const [desc, setDesc] = useState("");
  const [tags, setTags] = useState("");

  const submit = () => {
    if (!title.trim()) return;
    const tagArr = tags.split(",").map((t) => t.trim()).filter(Boolean);
    A.addCourse({ title: title.trim(), desc: desc.trim(), tags: tagArr });
    setTitle(""); setDesc(""); setTags(""); setAdding(false);
    nav({ screen: "courses" });
  };

  return (
    <div className="page page--wide screen-enter">
      <div className="page-head">
        <div className="page-head__titles">
          <div className="kicker-row"><span className="eyebrow-mono">Курсы</span><span className="date-stamp">{state.courses.length} активных</span></div>
          <h1 className="page-title">Мои курсы</h1>
        </div>
        <div className="page-actions"><Cmp.GButton icon="plus" variant="ink" onClick={() => setAdding(!adding)}>Новый курс</Cmp.GButton></div>
      </div>

      {adding && (
        <div className="task" style={{ display: "block", padding: "var(--s-5)", marginBottom: "var(--s-5)" }}>
          <Cmp.SectionRule kicker="Новый">Создать курс</Cmp.SectionRule>
          <div className="stack-3">
            <input autoFocus value={title} onChange={(e) => setTitle(e.target.value)}
              placeholder="Название курса"
              style={{ width: "100%", border: "1px solid var(--ink-100)", background: "var(--paper-00)", padding: "10px 12px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body-lg)", outline: "none", boxSizing: "border-box" }} />
            <textarea value={desc} onChange={(e) => setDesc(e.target.value)}
              placeholder="Описание курса…"
              rows={2}
              style={{ width: "100%", border: "1px solid var(--ink-100)", background: "var(--paper-00)", padding: "10px 12px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body)", resize: "vertical", outline: "none", boxSizing: "border-box" }} />
            <input value={tags} onChange={(e) => setTags(e.target.value)}
              placeholder="Теги через запятую: наука, cs"
              style={{ width: "100%", border: "1px solid var(--ink-40)", background: "var(--paper-00)", padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: "var(--t-small)", outline: "none", boxSizing: "border-box" }} />
            <div className="row-2" style={{ gap: 8, marginTop: 4 }}>
              <Cmp.GButton variant="signal" icon="check" onClick={submit}>Создать</Cmp.GButton>
              <Cmp.GButton variant="ghost" onClick={() => setAdding(false)}>Отмена</Cmp.GButton>
            </div>
          </div>
        </div>
      )}

      <div className="lib-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))" }}>
        {state.courses.map((c) => {
          const all = c.modules.flatMap((m) => m.tasks);
          const done = all.filter((t) => t.done).length;
          const pts = all.filter((t) => t.done).reduce((s, t) => s + t.pts, 0);
          const totalPts = all.reduce((s, t) => s + t.pts, 0);
          const courseLog = window.courseTimeLog(c);
          const totalSec = window.timeWeek(courseLog);
          const timePts = c.modules.reduce((s, m) => s + window.courseTimePts(window.timeWeek(m.timeLog), c.ptsRates), 0) + Math.round((window.timeWeek(c.timeLog) / 3600) * 15);
          return (
            <div key={c.id} className="task" style={{ display: "block", padding: 0, cursor: "pointer" }} onClick={() => nav({ screen: "course", id: c.id })}>
              <div style={{ height: 8, background: c.coverImg ? `url(${c.coverImg}) center/cover` : `linear-gradient(90deg, ${c.cover.from}, ${c.cover.to})` }} />
              <div style={{ padding: "var(--s-5)" }}>
                <div className="course-head" style={{ marginBottom: 16 }}>
                  <div className="course-cover" style={c.coverImg
                    ? { width: 76, flex: "0 0 76px", backgroundImage: `url(${c.coverImg})`, backgroundSize: "cover", backgroundPosition: "center" }
                    : { width: 76, flex: "0 0 76px", background: `linear-gradient(150deg, ${c.cover.from}, ${c.cover.to})` }} />
                  <div>
                    <div className="module__title" style={{ marginBottom: 6 }}>{c.title}</div>
                    <div className="row-2 wrap gap-2">{c.tags.map((t) => <Cmp.GTag key={t}>{t}</Cmp.GTag>)}</div>
                  </div>
                </div>
                <div className="row-3" style={{ justifyContent: "space-between", marginBottom: 6 }}>
                  <span className="meter-num">{done}/{all.length} шагов</span>
                  <span className="task__pts pts-ink">{pts}/{totalPts} PTS</span>
                </div>
                <Cmp.ProgressBar value={done} total={all.length} ink />
                {timePts > 0 && (
                  <div className="row-3" style={{ justifyContent: "space-between", marginTop: 8 }}>
                    <span className="e-label"><Icon name="clock" size={12} style={{ display: "inline", verticalAlign: "-1px" }} /> {window.fmtDur(totalSec)}</span>
                    <span className="task__pts pts-pos">+{timePts} PTS за время</span>
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function CourseScreen({ state, id, nav }) {
  const Cmp = window;
  const c = state.courses.find((x) => x.id === id);
  if (!c) return <div className="page"><div className="empty">Курс не найден.</div></div>;
  const all = c.modules.flatMap((m) => m.tasks);
  const done = all.filter((t) => t.done).length;
  const linked = c.links.map((lid) => window.PlannerLookup.entity(state, lid)).filter(Boolean);

  const [addingModule, setAddingModule] = useState(false);
  const [modTitle, setModTitle] = useState("");
  const [addingTaskFor, setAddingTaskFor] = useState(null);
  const [taskTitle, setTaskTitle] = useState("");
  const [taskPts, setTaskPts] = useState(20);
  const [openMod, setOpenMod] = useState(null);

  const submitModule = () => {
    if (!modTitle.trim()) return;
    A.addModule(c.id, modTitle.trim());
    setModTitle(""); setAddingModule(false);
  };
  const submitTask = (modId) => {
    if (!taskTitle.trim()) return;
    A.addCourseTask(c.id, modId, taskTitle.trim(), taskPts);
    setTaskTitle(""); setTaskPts(20); setAddingTaskFor(null);
  };

  const rates = c.ptsRates || window.DEFAULT_RATES;
  const totalPts = c.modules.reduce((s, m) => s + window.courseTimePts(window.timeWeek(m.timeLog), rates), 0);
  const courseLevelSec = window.timeWeek(c.timeLog);
  const courseLevelPts = Math.round((courseLevelSec / 3600) * 15);
  const todayPts = window.courseTimePtsToday(c, state.todayIdx);
  const isTimerCourse = state.timer && state.timer.kind === "course" && state.timer.id === c.id;

  return (
    <div className="page page--wide screen-enter">
      <div className="row-3" style={{ marginBottom: "var(--s-5)" }}>
        <span className="task__link" onClick={() => nav({ screen: "courses" })}><Icon name="back" size={14} />Курсы</span>
      </div>
      <div className="course-head" style={{ marginBottom: "var(--s-6)" }}>
        <div className="course-cover" style={c.coverImg
          ? { backgroundImage: `url(${c.coverImg})`, backgroundSize: "cover", backgroundPosition: "center" }
          : { background: `linear-gradient(150deg, ${c.cover.from}, ${c.cover.to})` }} />
        <div className="stack-3" style={{ flex: 1 }}>
          <div className="eyebrow-mono">Курс</div>
          <h1 className="page-title" style={{ margin: 0 }}>{c.title}</h1>
          <p style={{ color: "var(--text-secondary)", maxWidth: "60ch", margin: 0 }}>{c.desc}</p>
          <div className="row-3 wrap gap-3" style={{ marginTop: 4 }}>
            <span className="e-label">{done}/{all.length} шагов выполнено</span>
            <div style={{ width: 180 }}><Cmp.ProgressBar value={done} total={all.length} ink /></div>
            {linked.map((e) => <Cmp.LinkChip key={e.id} entity={e} onClick={() => navTo2(nav, e)} />)}
          </div>
          <div className="row-3 wrap gap-3" style={{ marginTop: 4, alignItems: "center" }}>
            {isTimerCourse
              ? <Cmp.GButton variant="signal" icon="stop" onClick={() => A.stopTimer()} style={{ fontSize: "var(--t-small)", padding: "4px 12px" }}>Стоп курс</Cmp.GButton>
              : <Cmp.GButton variant="ghost" icon="play" onClick={() => A.startTimer("course", c.id)} style={{ fontSize: "var(--t-small)", padding: "4px 12px" }}>Старт курс</Cmp.GButton>}
            <span className="e-label"><Icon name="clock" size={12} style={{ display: "inline", verticalAlign: "-1px" }} /> курс: {window.fmtDur(courseLevelSec)}</span>
            {courseLevelPts > 0 && <span className="task__pts pts-pos" style={{ fontSize: "var(--t-small)" }}>+{courseLevelPts} PTS (15/ч)</span>}
            <Cmp.GButton variant="ghost" style={{ fontSize: "var(--t-small)", padding: "4px 12px" }}
              onClick={() => { const inp = document.createElement("input"); inp.type = "file"; inp.accept = "image/*"; inp.onchange = (ev) => { const file = ev.target.files[0]; if (!file) return; const r = new FileReader(); r.onload = (re) => A.setCourseCoverImg(c.id, re.target.result); r.readAsDataURL(file); }; inp.click(); }}>
              Загрузить обложку
            </Cmp.GButton>
          </div>
        </div>
      </div>

      <div className="cols" style={{ gridTemplateColumns: "1fr 320px", alignItems: "start", gap: "var(--s-6)" }}>
        <div>
          {c.modules.map((mod, mi) => {
            const modSec = window.timeWeek(mod.timeLog);
            const modPts = window.courseTimePts(modSec, rates);
            const isTimerMod = state.timer && state.timer.kind === "module" && state.timer.id === mod.id;
            return (
              <div className="module" key={mod.id}>
                <div className="module__head">
                  <span className="module__num">МОДУЛЬ {String(mi + 1).padStart(2, "0")}</span>
                  <span className="module__title">{mod.title}</span>
                  <span className="spacer" />
                  <span className="meter-num">{mod.tasks.filter((t) => t.done).length}/{mod.tasks.length}</span>
                  <button className="note-card__action" onClick={() => A.removeModule(c.id, mod.id)} title="Удалить модуль" style={{ marginLeft: 8 }}>
                    <Icon name="close" size={13} />
                  </button>
                </div>

                <div className="row-3 wrap gap-3" style={{ padding: "6px 0 8px", alignItems: "center" }}>
                  {isTimerMod
                    ? <Cmp.GButton variant="signal" icon="stop" onClick={() => A.stopTimer()} style={{ fontSize: "var(--t-small)", padding: "4px 10px" }}>Стоп</Cmp.GButton>
                    : <Cmp.GButton variant="ghost" icon="play" onClick={() => A.startTimer("module", mod.id, c.id)} style={{ fontSize: "var(--t-small)", padding: "4px 10px" }}>Старт</Cmp.GButton>}
                  <span className="e-label"><Icon name="clock" size={12} style={{ display: "inline", verticalAlign: "-1px" }} /> {window.fmtDur(modSec)}</span>
                  {modPts > 0 && <span className="task__pts pts-pos" style={{ fontSize: "var(--t-small)" }}>+{modPts} PTS</span>}
                  <span className="task__link" onClick={() => setOpenMod(openMod === mod.id ? null : mod.id)} style={{ marginLeft: "auto", fontSize: "var(--t-small)" }}>
                    {openMod === mod.id ? "свернуть" : "время ▾"}
                  </span>
                </div>

                {openMod === mod.id && (
                  <Cmp.TimeBlock log={mod.timeLog} todayIdx={state.todayIdx} timer={state.timer} kind="module" id={mod.id} label={mod.title}
                    onStart={(k, i) => A.startTimer(k, i, c.id)} onStop={() => A.stopTimer()} onAdd={(sec) => A.logTime("module", mod.id, sec, c.id)} />
                )}

                <div className="module__tasks">
                  {mod.tasks.map((t) => (
                    <div key={t.id} className={"ctask" + (t.done ? " ctask--done" : "")}>
                      <button className={"task__check" + (t.done ? " task__check--on" : "")} style={{ width: 22, height: 22, flex: "0 0 22px" }} onClick={() => A.toggleCourseTask(c.id, t.id)}>
                        {t.done && <Icon name="check" size={14} />}
                      </button>
                      <span className="ctask__title">{t.title}</span>
                      <span className={"task__pts " + (t.done ? "pts-pos" : "pts-ink")}>+{t.pts}</span>
                      <button className="note-card__action" onClick={() => A.removeCourseTask(c.id, mod.id, t.id)} title="Удалить шаг">
                        <Icon name="close" size={12} />
                      </button>
                    </div>
                  ))}
                </div>

                {addingTaskFor === mod.id ? (
                  <div className="row-3" style={{ gap: 6, padding: "8px 0" }}>
                    <input autoFocus value={taskTitle} onChange={(e) => setTaskTitle(e.target.value)}
                      placeholder="Название шага"
                      onKeyDown={(e) => e.key === "Enter" && submitTask(mod.id)}
                      style={{ flex: 1, border: "1px solid var(--ink-40)", background: "var(--paper-00)", padding: "6px 10px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body)", outline: "none" }} />
                    <Cmp.Stepper value={taskPts} min={0} step={5} onChange={setTaskPts} suffix="PTS" />
                    <Cmp.GButton variant="signal" icon="check" onClick={() => submitTask(mod.id)} style={{ padding: "6px 10px" }}>OK</Cmp.GButton>
                    <Cmp.GButton variant="ghost" onClick={() => setAddingTaskFor(null)} style={{ padding: "6px 10px" }}>✕</Cmp.GButton>
                  </div>
                ) : (
                  <div style={{ padding: "6px 0" }}>
                    <span className="task__link" onClick={() => { setAddingTaskFor(mod.id); setTaskTitle(""); setTaskPts(20); }}>
                      <Icon name="plus" size={12} /> добавить шаг
                    </span>
                  </div>
                )}
              </div>
            );
          })}

          {addingModule ? (
            <div className="module" style={{ padding: "var(--s-4)" }}>
              <div className="row-3" style={{ gap: 8 }}>
                <input autoFocus value={modTitle} onChange={(e) => setModTitle(e.target.value)}
                  placeholder="Название модуля"
                  onKeyDown={(e) => e.key === "Enter" && submitModule()}
                  style={{ flex: 1, border: "1px solid var(--ink-100)", background: "var(--paper-00)", padding: "8px 12px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body)", outline: "none" }} />
                <Cmp.GButton variant="signal" icon="check" onClick={submitModule}>OK</Cmp.GButton>
                <Cmp.GButton variant="ghost" onClick={() => setAddingModule(false)}>Отмена</Cmp.GButton>
              </div>
            </div>
          ) : (
            <div style={{ marginTop: "var(--s-4)" }}>
              <Cmp.GButton variant="ghost" icon="plus" onClick={() => { setAddingModule(true); setModTitle(""); }}>Добавить модуль</Cmp.GButton>
            </div>
          )}
        </div>

        <div className="stack-4">
          <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
            <div style={{ marginBottom: 12 }}>
              <Icon name="award" size={16} style={{ display: "inline", verticalAlign: "-2px" }} />
              <span className="block__title" style={{ marginLeft: 6 }}>Баллы за время</span>
            </div>
            <div className="row-3" style={{ justifyContent: "space-between", marginBottom: 16 }}>
              <div>
                <div className="e-label">Всего</div>
                <div className="meter-num pts-pos" style={{ fontSize: 22 }}>+{totalPts + courseLevelPts} PTS</div>
              </div>
              <div style={{ textAlign: "right" }}>
                <div className="e-label">Сегодня</div>
                <div className="meter-num pts-pos" style={{ fontSize: 18 }}>+{todayPts} PTS</div>
              </div>
            </div>

            {c.modules.length > 0 && (
              <div className="stack-2" style={{ marginBottom: 16 }}>
                <div className="e-label" style={{ marginBottom: 4 }}>По модулям</div>
                {c.modules.map((mod) => {
                  const ms = window.timeWeek(mod.timeLog);
                  const mp = window.courseTimePts(ms, rates);
                  return (
                    <div key={mod.id} className="row-3" style={{ justifyContent: "space-between", fontSize: "var(--t-small)" }}>
                      <span style={{ color: "var(--text-secondary)" }}>{mod.title}</span>
                      <span className="mono">{mp > 0 ? "+" + mp : 0}</span>
                    </div>
                  );
                })}
                {courseLevelSec > 0 && (
                  <div className="row-3" style={{ justifyContent: "space-between", fontSize: "var(--t-small)", borderTop: "var(--bd-hair)", paddingTop: 4, marginTop: 4 }}>
                    <span style={{ color: "var(--text-secondary)" }}>Курс (без модуля)</span>
                    <span className="mono">{courseLevelPts > 0 ? "+" + courseLevelPts : 0} <span style={{ color: "var(--text-faint)" }}>15/ч</span></span>
                  </div>
                )}
              </div>
            )}

            <div className="e-label" style={{ marginBottom: 8 }}>Ставки (PTS/час)</div>
            <div className="stack-3">
              <div className="row-3" style={{ justifyContent: "space-between", alignItems: "center" }}>
                <span className="e-label">Первый час</span>
                <Cmp.Stepper value={rates.firstHour} min={0} step={5} onChange={(v) => A.setCourseRate(c.id, "firstHour", v)} />
              </div>
              <div className="row-3" style={{ justifyContent: "space-between", alignItems: "center" }}>
                <span className="e-label">1–10 часов</span>
                <Cmp.Stepper value={rates.first10h} min={0} step={5} onChange={(v) => A.setCourseRate(c.id, "first10h", v)} />
              </div>
              <div className="row-3" style={{ justifyContent: "space-between", alignItems: "center" }}>
                <span className="e-label">После 10 ч</span>
                <Cmp.Stepper value={rates.normal} min={0} step={5} onChange={(v) => A.setCourseRate(c.id, "normal", v)} />
              </div>
            </div>
          </div>

          <div style={{ marginTop: "var(--s-3)" }}>
            <Cmp.GButton variant="ghost" icon="close" onClick={() => { if (confirm("Удалить курс «" + c.title + "»?")) { A.removeCourse(c.id); nav({ screen: "courses" }); } }}
              style={{ color: "var(--signal)", fontSize: "var(--t-small)" }}>Удалить курс</Cmp.GButton>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ================= NOTES ================= */
function NotesScreen({ state, nav, focusId }) {
  const Cmp = window;
  const [tag, setTag] = useState(null);
  const [adding, setAdding] = useState(false);
  const [editing, setEditing] = useState(null);
  const [draftTitle, setDraftTitle] = useState("");
  const [draftBody, setDraftBody] = useState("");
  const [draftTags, setDraftTags] = useState("");
  const allTags = [...new Set(state.notes.flatMap((n) => n.tags))];
  let notes = tag ? state.notes.filter((n) => n.tags.includes(tag)) : state.notes;
  notes = [...notes].sort((a, b) => (b.pinned ? 1 : 0) - (a.pinned ? 1 : 0));

  const openAdd = () => {
    setDraftTitle(""); setDraftBody(""); setDraftTags(""); setEditing(null); setAdding(true);
  };
  const openEdit = (n, e) => {
    e.stopPropagation();
    setDraftTitle(n.title); setDraftBody(n.body); setDraftTags(n.tags.join(", ")); setEditing(n.id); setAdding(true);
  };
  const submitNote = () => {
    if (!draftTitle.trim()) return;
    const tags = draftTags.split(",").map((t) => t.trim()).filter(Boolean);
    if (editing) {
      A.updateNote(editing, { title: draftTitle.trim(), body: draftBody.trim(), tags });
    } else {
      A.addNote({ title: draftTitle.trim(), body: draftBody.trim(), tags });
    }
    setAdding(false); setEditing(null);
  };

  return (
    <div className="page page--wide screen-enter">
      <div className="page-head">
        <div className="page-head__titles">
          <div className="kicker-row"><span className="eyebrow-mono">Записная книжка</span><span className="date-stamp">{state.notes.length} заметок</span></div>
          <h1 className="page-title">Заметки</h1>
        </div>
        <div className="page-actions"><Cmp.GButton icon="plus" variant="ink" onClick={openAdd}>Заметка</Cmp.GButton></div>
      </div>

      {adding && (
        <div className="task" style={{ display: "block", padding: "var(--s-5)", marginBottom: "var(--s-5)" }}>
          <Cmp.SectionRule kicker={editing ? "Редактирование" : "Новая"}>{editing ? "Изменить заметку" : "Создать заметку"}</Cmp.SectionRule>
          <div className="stack-3">
            <input autoFocus value={draftTitle} onChange={(e) => setDraftTitle(e.target.value)}
              placeholder="Заголовок заметки"
              style={{ width: "100%", border: "1px solid var(--ink-100)", background: "var(--paper-00)", padding: "10px 12px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body-lg)", outline: "none", boxSizing: "border-box" }} />
            <textarea value={draftBody} onChange={(e) => setDraftBody(e.target.value)}
              placeholder="Текст заметки…"
              rows={4}
              style={{ width: "100%", border: "1px solid var(--ink-100)", background: "var(--paper-00)", padding: "10px 12px", fontFamily: "var(--font-slab)", fontSize: "var(--t-body)", resize: "vertical", outline: "none", boxSizing: "border-box" }} />
            <input value={draftTags} onChange={(e) => setDraftTags(e.target.value)}
              placeholder="Теги через запятую: наука, идеи"
              style={{ width: "100%", border: "1px solid var(--ink-40)", background: "var(--paper-00)", padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: "var(--t-small)", outline: "none", boxSizing: "border-box" }} />
            <div className="row-2" style={{ gap: 8, marginTop: 4 }}>
              <Cmp.GButton variant="signal" icon="check" onClick={submitNote}>{editing ? "Сохранить" : "Создать"}</Cmp.GButton>
              <Cmp.GButton variant="ghost" onClick={() => { setAdding(false); setEditing(null); }}>Отмена</Cmp.GButton>
            </div>
          </div>
        </div>
      )}

      <div className="row-2 wrap gap-2" style={{ marginBottom: "var(--s-5)" }}>
        <Cmp.GTag active={!tag} onClick={() => setTag(null)}>все</Cmp.GTag>
        {allTags.map((tg) => <Cmp.GTag key={tg} active={tag === tg} onClick={() => setTag(tg)}>{tg}</Cmp.GTag>)}
      </div>
      <div className="note-grid">
        {notes.map((n) => {
          const links = n.links.map((lid) => window.PlannerLookup.entity(state, lid)).filter(Boolean);
          return (
            <div key={n.id} className={"note-card" + (n.pinned ? " note-card--pin" : "")}>
              <div className="row-3" style={{ justifyContent: "space-between", marginBottom: 6 }}>
                <span className="e-label">{n.date}</span>
                <div className="row-2" style={{ gap: 6 }}>
                  <button className="note-card__action" onClick={(e) => { e.stopPropagation(); A.toggleNotePin(n.id); }} title={n.pinned ? "Открепить" : "Закрепить"}>
                    <Icon name="pin" size={14} style={{ color: n.pinned ? "var(--signal)" : "var(--text-faint)" }} />
                  </button>
                  <button className="note-card__action" onClick={(e) => openEdit(n, e)} title="Редактировать">
                    <Icon name="plus" size={14} style={{ color: "var(--text-faint)", transform: "rotate(45deg)" }} />
                  </button>
                  <button className="note-card__action" onClick={(e) => { e.stopPropagation(); A.removeNote(n.id); }} title="Удалить">
                    <Icon name="close" size={14} style={{ color: "var(--text-faint)" }} />
                  </button>
                </div>
              </div>
              <div className="note-card__title" onClick={() => links[0] && navTo2(nav, links[0])}>{n.title}</div>
              <div className={n.hand ? "note-card__hand" : "note-card__body"}>{n.body}</div>
              <div className="note-card__foot">
                {n.tags.map((tg) => <span key={tg} className="link-chip__kind">#{tg}</span>)}
                {links.length > 0 && <span className="spacer" />}
                {links.map((e) => <Cmp.LinkChip key={e.id} entity={e} onClick={(ev) => { ev.stopPropagation(); navTo2(nav, e); }} />)}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ================= STATS ================= */
function StatsScreen({ state, day, nav }) {
  const Cmp = window;
  const hist = state.history.map((h, idx) => idx === state.todayIdx ? { ...h, taskPts: day.taskPts, habitPts: day.habitPts } : h);
  const maxStack = Math.max(...hist.map((h) => h.taskPts + Math.max(h.habitPts, 0)), day.target, 1);
  const weekTotal = hist.reduce((s, h) => s + h.taskPts + h.habitPts, 0);
  const activeDays = hist.filter((h) => h.taskPts + h.habitPts > 0).length;
  const avg = activeDays ? Math.round(weekTotal / activeDays) : 0;
  const allMaterials = state.materials;
  const readingNow = allMaterials.filter((m) => m.status === "reading").length;
  const doneMaterials = allMaterials.filter((m) => m.status === "done").length;
  // streak: count back from today across history+ current with any points
  let streak = 0;
  for (let k = state.todayIdx; k >= 0; k--) { if (hist[k].taskPts + hist[k].habitPts > 0) streak++; else break; }

  // ---- time aggregation (tasks + materials + courses) ----------
  const timeByDay = [0, 0, 0, 0, 0, 0, 0];
  const cat = { task: 0, material: 0, course: 0 };
  const addLogs = (arr, key) => arr.forEach((x) => (x.timeLog || []).forEach((e) => { const sec = window.entrySec(e); timeByDay[e.d] += sec; cat[key] += sec; }));
  addLogs(state.tasks, "task"); addLogs(state.materials, "material");
  state.courses.forEach((co) => (co.modules || []).forEach((m) => (m.timeLog || []).forEach((e) => { const sec = window.entrySec(e); timeByDay[e.d] += sec; cat.course += sec; })));
  const weekTime = timeByDay.reduce((s, v) => s + v, 0);
  const maxTime = Math.max(1, ...timeByDay);

  // ---- mood: today + week average ------------------------------
  const todayMood = state.moods[state.todayIdx] || {};
  const weekAvg = {};
  window.MOOD_QUESTIONS.forEach((q) => {
    const vals = Object.values(state.moods).map((m) => m[q.id]).filter((v) => v != null);
    weekAvg[q.id] = vals.length ? vals.reduce((s, v) => s + v, 0) / vals.length : null;
  });
  const tg = state.targets;

  return (
    <div className="page page--wide screen-enter">
      <div className="page-head">
        <div className="page-head__titles">
          <div className="kicker-row"><span className="eyebrow-mono">Прогресс</span><span className="date-stamp">Неделя · Июнь 2026</span></div>
          <h1 className="page-title">Статистика баллов</h1>
        </div>
      </div>

      <div className="stat-grid" style={{ marginBottom: "var(--s-6)" }}>
        <div className="stat stat--signal">
          <span className="stat__label">Сегодня</span>
          <span className="stat__num">{day.net}</span>
          <span className="stat__sub">из {day.target} · {Math.round((day.net / day.target) * 100)}%</span>
        </div>
        <div className="stat">
          <span className="stat__label">За неделю</span>
          <span className="stat__num">{weekTotal}</span>
          <span className="stat__sub">план {tg.week} · {Math.round((weekTotal / tg.week) * 100)}%</span>
        </div>
        <div className="stat">
          <span className="stat__label">Серия дней</span>
          <span className="stat__num">{streak}<Icon name="flame" size={26} style={{ display: "inline", color: "var(--signal)", verticalAlign: "0" }} /></span>
          <span className="stat__sub">подряд с баллами</span>
        </div>
        <div className="stat">
          <span className="stat__label">Читаю / прочитано</span>
          <span className="stat__num">{readingNow}<span style={{ fontSize: "0.45em", color: "var(--text-muted)" }}> / {doneMaterials}</span></span>
          <span className="stat__sub">материалов в работе</span>
        </div>
      </div>

      <div className="cols" style={{ gridTemplateColumns: "1.4fr 1fr", alignItems: "start" }}>
        <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
          <Cmp.SectionRule kicker="Динамика">Баллы по дням</Cmp.SectionRule>
          <div className="chart">
            {hist.map((h, idx) => {
              const posH = Math.max(h.habitPts, 0), negH = Math.min(h.habitPts, 0);
              const scale = 180 / maxStack;
              return (
                <div className="chart__col" key={idx}>
                  <span className="chart__val">{h.taskPts + h.habitPts || ""}</span>
                  <div className="chart__stack" style={{ height: Math.max((h.taskPts + posH) * scale, 2), opacity: idx === state.todayIdx ? 1 : 0.85, outline: idx === state.todayIdx ? "2px solid var(--signal)" : "none", outlineOffset: 2 }}>
                    <div className="chart__seg-task" style={{ height: h.taskPts * scale }} />
                    {posH > 0 && <div className="chart__seg-habit" style={{ height: posH * scale }} />}
                  </div>
                  <span className="chart__day">{h.day}</span>
                </div>
              );
            })}
          </div>
          <div className="row-3 gap-4" style={{ marginTop: 16 }}>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--ink-100)" }} />Задачи</span>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--signal)" }} />Привычки</span>
          </div>
        </div>

        <div className="stack-5">
          <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
            <Cmp.SectionRule kicker="Баланс">Источник баллов</Cmp.SectionRule>
            <div className="stack-3">
              <BalanceRow label="Задачи и курсы" value={hist.reduce((s, h) => s + h.taskPts, 0)} total={Math.abs(weekTotal) + 50} color="var(--ink-100)" />
              <BalanceRow label="Полезные привычки" value={hist.reduce((s, h) => s + Math.max(h.habitPts, 0), 0)} total={Math.abs(weekTotal) + 50} color="var(--signal)" />
              <BalanceRow label="Штрафы (вредные)" value={Math.abs(hist.reduce((s, h) => s + Math.min(h.habitPts, 0), 0))} total={Math.abs(weekTotal) + 50} color="var(--signal)" neg />
            </div>
          </div>
          <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
            <Cmp.SectionRule kicker="Полгода">Активность</Cmp.SectionRule>
            <HeatmapReal activityLog={state.activityLog || []} />
            <div className="muted" style={{ fontSize: "var(--t-small)", marginTop: 8 }}>Полгода. Темнее — больше баллов; красный — рекорд.</div>
          </div>
        </div>
      </div>

      {/* ---- Time + State row ---- */}
      <div className="cols" style={{ gridTemplateColumns: "1.4fr 1fr", alignItems: "start", marginTop: "var(--s-6)" }}>
        <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
          <Cmp.SectionRule kicker="Время" right={<span className="e-label">всего {window.fmtMin(weekTime)}</span>}>Время за неделю</Cmp.SectionRule>
          <div className="chart">
            {timeByDay.map((mins, idx) => (
              <div className="chart__col" key={idx}>
                <span className="chart__val">{mins ? window.fmtMin(mins) : ""}</span>
                <div className="chart__stack" style={{ height: Math.max((mins / maxTime) * 170, 2), border: "var(--bd-bold)", outline: idx === state.todayIdx ? "2px solid var(--signal)" : "none", outlineOffset: 2 }}>
                  <div style={{ height: "100%", width: "100%", background: "var(--ink-100)" }} />
                </div>
                <span className="chart__day">{window.DAY_NAMES[idx]}</span>
              </div>
            ))}
          </div>
          <div className="row-3 gap-4 wrap" style={{ marginTop: 16 }}>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--ink-100)" }} />Задачи {window.fmtMin(cat.task)}</span>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--ink-60)" }} />Чтение {window.fmtMin(cat.material)}</span>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--ink-40)" }} />Курсы {window.fmtMin(cat.course)}</span>
          </div>
        </div>

        <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
          <Cmp.SectionRule kicker="Состояние" right={<span className="task__link" onClick={() => nav({ screen: "today" })}>отметить<Icon name="arrow" size={13} /></span>}>Журнал состояния</Cmp.SectionRule>
          <Cmp.MoodBars mood={todayMood} weekAvg={weekAvg} />
          <div className="row-3 gap-4 wrap" style={{ marginTop: 14 }}>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--ink-100)" }} />Сегодня</span>
            <span className="legend-row" style={{ width: "auto" }}><span className="legend-swatch" style={{ background: "var(--warn)", width: 4 }} />Среднее за неделю</span>
          </div>
          <div className="muted" style={{ fontSize: "var(--t-meta)", marginTop: 8 }}>Шкала −5…+5 · на баллы не влияет</div>
        </div>
      </div>
    </div>
  );
}
function HeatmapReal({ activityLog }) {
  const totalDays = 26 * 7;
  const today = new Date();
  const dayMap = {};
  (activityLog || []).forEach((e) => { dayMap[e.date] = e.pts; });
  const cells = [];
  let maxPts = 0;
  for (let i = totalDays - 1; i >= 0; i--) {
    const d = new Date(today);
    d.setDate(d.getDate() - i);
    const key = d.toISOString().slice(0, 10);
    const pts = dayMap[key] || 0;
    if (pts > maxPts) maxPts = pts;
    cells.push({ key, pts });
  }
  return (
    <div className="heat">
      {cells.map((c) => {
        const ratio = maxPts > 0 ? c.pts / maxPts : 0;
        const bg = c.pts === 0 ? "var(--paper-10)" : c.pts === maxPts && maxPts > 0 ? "var(--signal)" : ratio > 0.66 ? "var(--ink-100)" : ratio > 0.33 ? "var(--ink-60)" : "var(--paper-30)";
        return <div key={c.key} className="heat__cell" style={{ background: bg }} title={c.key + ": " + c.pts + " PTS"} />;
      })}
    </div>
  );
}

function BalanceRow({ label, value, total, color, neg }) {
  return (
    <div>
      <div className="row-3" style={{ justifyContent: "space-between", marginBottom: 4 }}>
        <span style={{ fontSize: "var(--t-small)" }}>{label}</span>
        <span className="mono" style={{ fontWeight: 700, color: neg ? "var(--signal)" : "var(--ink-100)" }}>{neg && value > 0 ? "−" : ""}{value}</span>
      </div>
      <div className="pbar"><i style={{ width: Math.min((value / total) * 100, 100) + "%", background: color }} /></div>
    </div>
  );
}

window.Screens = Object.assign(window.Screens || {}, {
  calendar: CalendarScreen, courses: CoursesScreen, course: CourseScreen,
  notes: NotesScreen, stats: StatsScreen,
});
