// ── Admin: Student CRM ────────────────────────────────────────────────────────
// ── Reusable Modal shell ───────────────────────────────────────────────────────
const Modal = ({ title, onClose, children }) => (
  <div style={{ position:"fixed", inset:0, background:"rgba(0,0,0,.5)", display:"flex", alignItems:"center", justifyContent:"center", zIndex:9999, padding:16, boxSizing:"border-box" }}
       onClick={e => e.target === e.currentTarget && onClose()}>
    <div style={{ background:"var(--paper-card)", borderRadius:16, padding:24, width:460, maxWidth:"92vw", maxHeight:"90vh", display:"flex", flexDirection:"column", boxShadow:"0 24px 60px rgba(0,0,0,.3)", boxSizing:"border-box" }}>
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:16, flexShrink:0 }}>
        <div className="display" style={{ fontSize:18 }}>{title}</div>
        <button onClick={onClose} style={{ background:"none", border:"none", fontSize:20, cursor:"pointer", color:"var(--ink-mute)", lineHeight:1 }}>×</button>
      </div>
      <div style={{ overflowY:"auto", flex:1, minHeight:0, paddingRight:4 }}>
        {children}
      </div>
    </div>
  </div>
);

const FormField = ({ label, children }) => (
  <div style={{ marginBottom:14 }}>
    <div className="mono" style={{ fontSize:10, fontWeight:700, marginBottom:5, letterSpacing:".06em", color:"var(--ink-mute)" }}>{label}</div>
    {children}
  </div>
);

const inputStyle = { width:"100%", padding:"9px 12px", borderRadius:10, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", boxSizing:"border-box", outline:"none" };
const selectStyle = { ...inputStyle };

// ── Shared search utilities ──────────────────────────────────────────────────
const useDebounce = (val, delay = 150) => {
  const [debounced, setDebounced] = React.useState(val);
  React.useEffect(() => {
    const handler = setTimeout(() => setDebounced(val), delay);
    return () => clearTimeout(handler);
  }, [val, delay]);
  return debounced;
};

const SearchBox = ({ value, onChange, placeholder = "Search…", id, dataTestId, width = 230 }) => (
  <div className="card-flat" style={{ display:"flex", alignItems:"center", gap:6, padding:"5px 10px", background:"var(--paper-card)", borderRadius:8, border:"var(--border-thin)", width }}>
    {I.search({ size:13 })}
    <input
      id={id}
      data-testid={dataTestId || id}
      value={value}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder}
      style={{ border:"none", outline:"none", background:"transparent", fontSize:12, fontFamily:"var(--font-ui)", color:"var(--ink)", width:"100%" }}
    />
    {value && (
      <button
        type="button"
        onClick={() => onChange("")}
        style={{ border:"none", background:"transparent", cursor:"pointer", color:"var(--ink-mute)", fontSize:11, padding:0, lineHeight:1 }}
        title="Clear search"
      >
        ✕
      </button>
    )}
  </div>
);

const AdminStudents = ({ dark = true, go }) => {
  const { data: STUDENTS, loading } = useApi("/students");
  const { data: BATCHES } = useApi("/batches");
  const { data: TEACHERS } = useApi("/teachers");
  const [search, setSearch]     = React.useState("");
  const [selected, setSelected] = React.useState(null);
  const [showAdd, setShowAdd]   = React.useState(false);
  const [editStudent, setEditStudent] = React.useState(null);
  const { data: COURSES } = useApi("/courses/list");
  const [form, setForm]         = React.useState({ name:"", age:"", student_type:"batch", batch_id:"", course_id:"", teacher_id:"", student_email:"", student_password:"", parent_name:"", parent_email:"", parent_password:"" });
  const [editForm, setEditForm] = React.useState({ name:"", age:"", student_type:"batch", batch_id:"", course_id:"", teacher_id:"", status:"" });
  const [saving, setSaving]     = React.useState(false);
  const [error, setError]       = React.useState("");
  const [students, setStudents] = React.useState(null);
  const [resetOpen, setResetOpen] = React.useState(false);
  const [resetPw, setResetPw]   = React.useState("");
  const [resetMsg, setResetMsg] = React.useState("");
  const [msgOpen, setMsgOpen]   = React.useState(false);
  const [msgText, setMsgText]   = React.useState("");
  const [msgStatus, setMsgStatus] = React.useState("");
  const list = asArray(students ?? STUDENTS);

  const sendMessage = async (studentId) => {
    setMsgStatus("");
    if (!msgText.trim()) { setMsgStatus("Type a message."); return; }
    const res = await apiFetch("/admin/notify", { method:"POST", body: JSON.stringify({ student_id: studentId, text: msgText.trim() }) });
    const d = await res.json().catch(()=>({}));
    if (!res.ok) { setMsgStatus(d.error || "Failed to send."); return; }
    setMsgStatus("✓ Sent to student & parent."); setMsgText("");
    if (window.showToast) window.showToast({ title: "Message Sent", message: "In-app notification delivered to student & parent inbox.", type: "success" });
  };

  const toggleAccess = async (s) => {
    const next = !s.access_locked;
    const res = await apiFetch(`/students/${s.id}/access`, { method:"PATCH", body: JSON.stringify({ locked: next }) });
    if (!res.ok) return;
    setStudents(await apiList("/students"));
    if (window.showToast) window.showToast({ title: "Access Updated", message: `${s.name} account access ${next ? "locked" : "restored"}.`, type: "info" });
  };

  const resetLoginPassword = async (userId) => {
    setResetMsg("");
    if (resetPw.length < 8) { setResetMsg("Min 8 characters."); return; }
    const res = await apiFetch(`/admin/users/${userId}/password`, { method:"PATCH", body: JSON.stringify({ password: resetPw }) });
    const d = await res.json().catch(() => ({}));
    if (!res.ok) { setResetMsg(d.error || "Failed"); return; }
    setResetMsg("✓ Password reset. Share it with them."); setResetPw("");
    if (window.showToast) window.showToast({ title: "Password Reset", message: "User password updated successfully.", type: "success" });
  };

  const filtered = list.filter(s =>
    (s.name||"").toLowerCase().includes(search.toLowerCase()) ||
    (s.course||"").toLowerCase().includes(search.toLowerCase()) ||
    (s.batch||"").toLowerCase().includes(search.toLowerCase())
  );
  const student = selected ? list.find(s => s.id === selected) : null;

  const saveStudent = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch("/students", { method:"POST", body: JSON.stringify({
      name: form.name, age: parseInt(form.age)||null,
      student_type: form.student_type,
      batch_id: form.student_type === "batch" ? (form.batch_id||null) : null,
      course_id: form.student_type === "individual" ? (form.course_id||null) : null,
      teacher_id: form.teacher_id||null,
      student_email: form.student_email||null, student_password: form.student_password||null,
      parent_name: form.parent_name||null, parent_email: form.parent_email||null, parent_password: form.parent_password||null,
    })});
    const data = await res.json();
    if (!res.ok) { setError(data.error || "Failed"); setSaving(false); return; }
    setStudents(await apiList("/students"));
    const studentName = form.name;
    setForm({ name:"", age:"", student_type:"batch", batch_id:"", course_id:"", teacher_id:"", student_email:"", student_password:"", parent_name:"", parent_email:"", parent_password:"" });
    setShowAdd(false); setSaving(false);
    if (window.showToast) window.showToast({ title: "Student Added", message: `${studentName} enrolled successfully!`, type: "success" });
  };

  const openEdit = s => {
    setEditStudent(s);
    setEditForm({ name: s.name, age: s.age||"", student_type: s.student_type||"batch", batch_id: s.batch_id||"", course_id: "", teacher_id: s.teacher_id||"", status: s.status||"active" });
  };

  const saveEdit = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch(`/students/${editStudent.id}`, { method:"PATCH", body: JSON.stringify({
      name: editForm.name, age: parseInt(editForm.age)||null,
      student_type: editForm.student_type,
      batch_id: editForm.student_type === "batch" ? (editForm.batch_id||null) : null,
      course_id: editForm.student_type === "individual" ? (editForm.course_id||null) : null,
      teacher_id: editForm.teacher_id||null, status: editForm.status||null,
    })});
    const data = await res.json();
    if (!res.ok) { setError(data.error || "Failed"); setSaving(false); return; }
    setStudents(await apiList("/students"));
    const updatedName = editForm.name;
    setEditStudent(null); setSaving(false);
    if (window.showToast) window.showToast({ title: "Student Updated", message: `${updatedName} records updated.`, type: "success" });
  };

  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      {editStudent && (
        <Modal title="Edit student" onClose={() => setEditStudent(null)}>
          <form onSubmit={saveEdit}>
            <FormField label="FULL NAME">
              <input required style={inputStyle} value={editForm.name} onChange={e=>setEditForm(f=>({...f,name:e.target.value}))}/>
            </FormField>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <FormField label="AGE">
                <input type="number" min="5" max="18" style={inputStyle} value={editForm.age} onChange={e=>setEditForm(f=>({...f,age:e.target.value}))}/>
              </FormField>
              <FormField label="STATUS">
                <select style={selectStyle} value={editForm.status} onChange={e=>setEditForm(f=>({...f,status:e.target.value}))}>
                  {["active","at-risk","churning","inactive"].map(s=><option key={s} value={s}>{s}</option>)}
                </select>
              </FormField>
            </div>
            <FormField label="ENROLMENT TYPE">
              <div style={{ display:"flex", gap:8 }}>
                {["batch","individual"].map(t=>(
                  <button key={t} type="button" onClick={()=>setEditForm(f=>({...f,student_type:t}))}
                    style={{ flex:1, padding:"8px 0", borderRadius:8, border:"var(--border-thin)", fontSize:12,
                      background: editForm.student_type===t ? "var(--coral)" : "var(--paper-deep)",
                      color: editForm.student_type===t ? "white" : "var(--ink-soft)", cursor:"pointer", fontWeight:600 }}>
                    {t === "batch" ? "Batch" : "Individual"}
                  </button>
                ))}
              </div>
            </FormField>
            {editForm.student_type === "batch" ? (
              <FormField label="BATCH">
                <select style={selectStyle} value={editForm.batch_id} onChange={e=>setEditForm(f=>({...f,batch_id:e.target.value}))}>
                  <option value="">— no batch —</option>
                  {BATCHES.map(b=><option key={b.id} value={b.id}>{b.name} ({b.course})</option>)}
                </select>
              </FormField>
            ) : (
              <FormField label="COURSE">
                <select style={selectStyle} value={editForm.course_id} onChange={e=>setEditForm(f=>({...f,course_id:e.target.value}))}>
                  <option value="">— select course —</option>
                  {COURSES.map(c=><option key={c.id} value={c.id}>{c.name} · {c.level}</option>)}
                </select>
              </FormField>
            )}
            <FormField label="TEACHER">
              <select style={selectStyle} value={editForm.teacher_id} onChange={e=>setEditForm(f=>({...f,teacher_id:e.target.value}))}>
                <option value="">— no teacher —</option>
                {TEACHERS.map(t=><option key={t.id} value={t.id}>{t.name}</option>)}
              </select>
            </FormField>
            {error && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>{error}</div>}
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
              <button type="button" onClick={()=>setEditStudent(null)} className="btn btn-ghost">Cancel</button>
              <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Save changes"}</button>
            </div>
          </form>
        </Modal>
      )}
      {showAdd && (
        <Modal title="Add student" onClose={() => setShowAdd(false)}>
          <form onSubmit={saveStudent} style={{ maxHeight:"75vh", overflowY:"auto", paddingRight:4 }}>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginBottom:10, letterSpacing:".06em" }}>STUDENT INFO</div>
            <FormField label="FULL NAME">
              <input required style={inputStyle} value={form.name} onChange={e=>setForm(f=>({...f,name:e.target.value}))} placeholder="e.g. Arya Patel"/>
            </FormField>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <FormField label="AGE">
                <input type="number" min="5" max="18" style={inputStyle} value={form.age} onChange={e=>setForm(f=>({...f,age:e.target.value}))} placeholder="e.g. 10"/>
              </FormField>
              <FormField label="ENROLMENT TYPE">
                <select style={selectStyle} value={form.student_type} onChange={e=>setForm(f=>({...f,student_type:e.target.value}))}>
                  <option value="batch">Batch student</option>
                  <option value="individual">Individual student</option>
                </select>
              </FormField>
            </div>
            {form.student_type === "batch" ? (
              <FormField label="BATCH">
                <select style={selectStyle} value={form.batch_id} onChange={e=>setForm(f=>({...f,batch_id:e.target.value}))}>
                  <option value="">— select batch —</option>
                  {BATCHES.map(b=><option key={b.id} value={b.id}>{b.name} ({b.course})</option>)}
                </select>
              </FormField>
            ) : (
              <FormField label="COURSE">
                <select style={selectStyle} value={form.course_id} onChange={e=>setForm(f=>({...f,course_id:e.target.value}))}>
                  <option value="">— select course —</option>
                  {COURSES.map(c=><option key={c.id} value={c.id}>{c.name} · {c.level}</option>)}
                </select>
              </FormField>
            )}
            <FormField label="TEACHER">
              <select style={selectStyle} value={form.teacher_id} onChange={e=>setForm(f=>({...f,teacher_id:e.target.value}))}>
                <option value="">— select teacher —</option>
                {TEACHERS.map(t=><option key={t.id} value={t.id}>{t.name}</option>)}
              </select>
            </FormField>

            <div style={{ height:1, background:"var(--rule)", margin:"14px 0" }}/>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginBottom:10, letterSpacing:".06em" }}>STUDENT LOGIN <span style={{ color:"var(--ink-mute)", fontWeight:400 }}>(optional)</span></div>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <FormField label="EMAIL">
                <input type="email" style={inputStyle} value={form.student_email} onChange={e=>setForm(f=>({...f,student_email:e.target.value}))} placeholder="arya@gmail.com"/>
              </FormField>
              <FormField label="PASSWORD">
                <input type="password" style={inputStyle} value={form.student_password} onChange={e=>setForm(f=>({...f,student_password:e.target.value}))} placeholder="min 6 chars"/>
              </FormField>
            </div>

            <div style={{ height:1, background:"var(--rule)", margin:"14px 0" }}/>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginBottom:10, letterSpacing:".06em" }}>PARENT LOGIN <span style={{ color:"var(--ink-mute)", fontWeight:400 }}>(optional)</span></div>
            <FormField label="PARENT NAME">
              <input style={inputStyle} value={form.parent_name} onChange={e=>setForm(f=>({...f,parent_name:e.target.value}))} placeholder="e.g. Rajesh Patel"/>
            </FormField>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <FormField label="EMAIL">
                <input type="email" style={inputStyle} value={form.parent_email} onChange={e=>setForm(f=>({...f,parent_email:e.target.value}))} placeholder="parent@gmail.com"/>
              </FormField>
              <FormField label="PASSWORD">
                <input type="password" style={inputStyle} value={form.parent_password} onChange={e=>setForm(f=>({...f,parent_password:e.target.value}))} placeholder="min 6 chars"/>
              </FormField>
            </div>

            {error && <div style={{ color:"var(--coral)", fontSize:13, margin:"8px 0" }}>{error}</div>}
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:16 }}>
              <button type="button" onClick={()=>setShowAdd(false)} className="btn btn-ghost">Cancel</button>
              <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Add student"}</button>
            </div>
          </form>
        </Modal>
      )}
      <AdminSidebar active="/app/admin/students" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Student CRM</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>{list.length} enrolled · {list.filter(s=>s.status==="at-risk"||s.status==="churning").length} need attention</div>
          </div>
          <div style={{ flex:1 }}/>
          <div className="card-flat" style={{ display:"flex", alignItems:"center", gap:8, padding:"6px 10px", background:"var(--paper-deep)", width:220 }}>
            {I.search({ size:14 })}
            <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search students…" style={{ border:"none", outline:"none", background:"transparent", fontSize:13, fontFamily:"var(--font-ui)", color:"var(--ink)", width:"100%" }}/>
          </div>
          <button onClick={()=>setShowAdd(true)} className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add student</button>
        </div>
        <div style={{ flex:1, display:"flex", overflow:"hidden" }}>
          <div style={{ flex:1, overflow:"auto", padding:22 }}>
            <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
              <thead>
                <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                  {["Student","Course · Batch","Teacher","Attend.","XP","Status","Kit",""].map(h => (
                    <th key={h} style={{ padding:"8px 10px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {filtered.map((s, i) => (
                  <tr key={s.id} onClick={() => setSelected(selected === s.id ? null : s.id)} style={{ borderTop: i ? "var(--border-thin)" : "none", cursor:"pointer", background: selected === s.id ? "var(--paper-deep)" : "transparent" }}>
                    <td style={{ padding:"12px 10px" }}>
                      <div style={{ display:"flex", alignItems:"center", gap:8 }}>
                        <Avatar name={s.name[0]} color={s.color} size={30}/>
                        <div>
                          <div style={{ fontWeight:700 }}>{s.name}</div>
                          <div style={{ fontSize:11, color:"var(--ink-mute)" }}>Age {s.age}</div>
                        </div>
                      </div>
                    </td>
                    <td style={{ padding:"12px 10px" }}><div style={{ fontWeight:600 }}>{s.course}</div><div style={{ fontSize:11, color:"var(--ink-mute)" }}>{s.batch}</div></td>
                    <td style={{ padding:"12px 10px", color:"var(--ink-soft)" }}>{s.teacher}</td>
                    <td style={{ padding:"12px 10px", fontWeight:700, color: parseInt(s.attend) < 75 ? "var(--coral)" : parseInt(s.attend) >= 90 ? "var(--moss)" : "var(--ink)" }}>{s.attend}</td>
                    <td style={{ padding:"12px 10px", fontFamily:"var(--font-mono)", fontSize:12 }}>{s.xp}</td>
                    <td style={{ padding:"12px 10px" }}>
                      <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: s.status==="active" ? "var(--moss)" : s.status==="at-risk" ? "var(--gold)" : "var(--coral)", color:"white" }}>
                        {s.status}
                      </span>
                    </td>
                    <td style={{ padding:"12px 10px" }}>
                      <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: s.kit==="delivered" ? "var(--paper-deep)" : s.kit==="transit" ? "var(--sky-deep)" : "var(--gold)", color: s.kit==="transit" ? "white" : "var(--ink)" }}>
                        {s.kit}
                      </span>
                    </td>
                    <td style={{ padding:"12px 10px", display:"flex", gap:6 }}>
                      <button onClick={e=>{e.stopPropagation();openEdit(s);}} className="btn btn-ghost" style={{ padding:"4px 10px", fontSize:11 }}>Edit</button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          {student && (
            <div style={{ width:280, borderLeft:"var(--border-thin)", background:"var(--paper-card)", padding:20, overflow:"auto", flexShrink:0 }}>
              <div style={{ display:"flex", alignItems:"center", gap:10, marginBottom:16 }}>
                <Avatar name={student.name[0]} color={student.color} size={48}/>
                <div>
                  <div className="display" style={{ fontSize:18 }}>{student.name}</div>
                  <div style={{ fontSize:12, color:"var(--ink-mute)" }}>Age {student.age} · {student.batch}</div>
                </div>
              </div>
              {[["Course", student.course],["Teacher", student.teacher],["Attendance", student.attend],["XP", student.xp],["Status", student.status],["Kit", student.kit]].map(([k,v]) => (
                <div key={k} style={{ display:"flex", justifyContent:"space-between", padding:"8px 0", borderTop:"var(--border-thin)", fontSize:13 }}>
                  <span style={{ color:"var(--ink-mute)", fontWeight:600 }}>{k}</span>
                  <span style={{ fontWeight:700 }}>{v}</span>
                </div>
              ))}
              {/* Account / login details */}
              <div style={{ marginTop:14, paddingTop:10, borderTop:"2px solid var(--rule)" }}>
                <div className="mono" style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)", letterSpacing:".06em", marginBottom:8 }}>ACCOUNT</div>
                {[["Student login", student.login_email || "— no login —"],["Parent", student.parent_name || "—"],["Parent email", student.parent_email || "—"]].map(([k,v]) => (
                  <div key={k} style={{ display:"flex", justifyContent:"space-between", gap:8, padding:"6px 0", fontSize:12.5 }}>
                    <span style={{ color:"var(--ink-mute)", fontWeight:600, flexShrink:0 }}>{k}</span>
                    <span style={{ fontWeight:600, wordBreak:"break-all", textAlign:"right" }}>{v}</span>
                  </div>
                ))}
              </div>
              <div style={{ marginTop:16, display:"flex", flexDirection:"column", gap:8 }}>
                {student.login_user_id && (
                  resetOpen ? (
                    <div style={{ display:"flex", flexDirection:"column", gap:6, padding:10, background:"var(--paper-deep)", borderRadius:8 }}>
                      <div className="mono" style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)" }}>RESET STUDENT LOGIN PASSWORD</div>
                      <input type="password" value={resetPw} onChange={e=>setResetPw(e.target.value)} placeholder="New password (8+)" style={{ ...inputStyle, padding:"7px 10px", fontSize:13 }}/>
                      {resetMsg && <div style={{ fontSize:11.5, color: resetMsg.startsWith("✓") ? "var(--moss)" : "var(--coral)" }}>{resetMsg}</div>}
                      <div style={{ display:"flex", gap:6 }}>
                        <button onClick={()=>resetLoginPassword(student.login_user_id)} className="btn btn-primary" style={{ flex:1, fontSize:12, padding:"7px 0" }}>Save</button>
                        <button onClick={()=>{ setResetOpen(false); setResetPw(""); setResetMsg(""); }} className="btn btn-ghost" style={{ fontSize:12, padding:"7px 12px" }}>Cancel</button>
                      </div>
                    </div>
                  ) : (
                    <button onClick={()=>{ setResetOpen(true); setResetMsg(""); }} className="btn btn-ghost" style={{ fontSize:12, padding:"8px 0", width:"100%" }}>{I.lock ? I.lock({ size:14 }) : "🔒"} Reset login password</button>
                  )
                )}
                {msgOpen ? (
                  <div style={{ display:"flex", flexDirection:"column", gap:6, padding:10, background:"var(--paper-deep)", borderRadius:8 }}>
                    <div className="mono" style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)" }}>MESSAGE STUDENT & PARENT</div>
                    <textarea value={msgText} onChange={e=>setMsgText(e.target.value)} rows={3} placeholder="e.g. Reminder: your subscription expires on the 30th." style={{ ...inputStyle, padding:"7px 10px", fontSize:13, resize:"vertical" }}/>
                    {msgStatus && <div style={{ fontSize:11.5, color: msgStatus.startsWith("✓") ? "var(--moss)" : "var(--coral)" }}>{msgStatus}</div>}
                    <div style={{ display:"flex", gap:6 }}>
                      <button onClick={()=>sendMessage(student.id)} className="btn btn-primary" style={{ flex:1, fontSize:12, padding:"7px 0" }}>Send</button>
                      <button onClick={()=>{ setMsgOpen(false); setMsgText(""); setMsgStatus(""); }} className="btn btn-ghost" style={{ fontSize:12, padding:"7px 12px" }}>Close</button>
                    </div>
                  </div>
                ) : (
                  <button onClick={()=>{ setMsgOpen(true); setMsgStatus(""); }} className="btn btn-primary" style={{ fontSize:12, padding:"8px 0", width:"100%" }}>{I.send ? I.send({ size:14 }) : "✉️"} Message parent</button>
                )}
                <button onClick={()=>toggleAccess(student)} className="btn btn-ghost" style={{ fontSize:12, padding:"8px 0", width:"100%", color: student.access_locked ? "var(--moss)" : "var(--coral)" }}>
                  {student.access_locked ? "🔓 Unlock course access" : "🔒 Lock course access"}
                </button>
                <button onClick={()=>openEdit(student)} className="btn btn-ghost" style={{ fontSize:12, padding:"8px 0", width:"100%" }}>{I.edit ? I.edit({ size:14 }) : "✏️"} Edit student</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Teachers ───────────────────────────────────────────────────────────
const AdminTeachers = ({ dark = true, go }) => {
  const { data: initTeachers } = useApi("/teachers");
  const [teachers, setTeachers]   = React.useState(null);
  const [showAdd, setShowAdd]     = React.useState(false);
  const [editTeacher, setEditTeacher] = React.useState(null);
  const [searchQuery, setSearchQuery] = React.useState("");
  const debouncedSearch = useDebounce(searchQuery, 150);
  const [form, setForm]           = React.useState({ name:"", email:"", password:"" });
  const [editForm, setEditForm]   = React.useState({ name:"", email:"", password:"" });
  const [saving, setSaving]       = React.useState(false);
  const [error, setError]         = React.useState("");
  const list = teachers ?? initTeachers;

  const refresh = () => apiFetch("/teachers").then(r=>r.json()).then(setTeachers);

  const filteredList = (list || []).filter(t => {
    if (!debouncedSearch) return true;
    const q = debouncedSearch.toLowerCase().trim();
    return (t.name || "").toLowerCase().includes(q) || (t.email || "").toLowerCase().includes(q);
  });

  const save = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch("/teachers", { method:"POST", body: JSON.stringify(form) });
    const data = await res.json();
    if (!res.ok) { setError(data.error || "Failed"); setSaving(false); return; }
    await refresh();
    setForm({ name:"", email:"", password:"" }); setShowAdd(false); setSaving(false);
  };

  const openEdit = t => { setEditTeacher(t); setEditForm({ name:t.name, email:t.email, password:"" }); setError(""); };

  const saveEdit = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch(`/teachers/${editTeacher.id}`, { method:"PATCH", body: JSON.stringify({ name: editForm.name, email: editForm.email }) });
    if (!res.ok) { const d=await res.json(); setError(d.error||"Failed"); setSaving(false); return; }
    if (editForm.password) {
      await apiFetch(`/admin/users/${editTeacher.id}/password-by-email`, { method:"PATCH", body: JSON.stringify({ email: editForm.email, password: editForm.password }) });
    }
    await refresh(); setEditTeacher(null); setSaving(false);
  };

  const [deleteTarget, setDeleteTarget] = React.useState(null);
  const [deleteStep, setDeleteStep] = React.useState(1);
  const [deleteAck, setDeleteAck] = React.useState(false);
  const [confirmPassword, setConfirmPassword] = React.useState("");
  const [deleteSaving, setDeleteSaving] = React.useState(false);
  const [deleteError, setDeleteError] = React.useState("");

  const executeDelete = async e => {
    e.preventDefault();
    if (!confirmPassword) {
      setDeleteError("Password is required to confirm deletion.");
      return;
    }
    setDeleteSaving(true);
    setDeleteError("");
    try {
      const res = await apiFetch(`/teachers/${deleteTarget.id}`, {
        method: "DELETE",
        body: JSON.stringify({ password: confirmPassword }),
      });
      const d = await res.json().catch(() => ({}));
      if (!res.ok) {
        setDeleteError(d.error || (res.status === 401 ? "Session expired" : "Could not remove this teacher."));
        setDeleteSaving(false);
        return;
      }
      await refresh();
      setDeleteTarget(null);
      setConfirmPassword("");
      setDeleteSaving(false);
    } catch {
      setDeleteError("Something went wrong removing the teacher. Please try again.");
      setDeleteSaving(false);
    }
  };

  return (
    <Themed className={dark?"theme-dark":""} style={{ width:"100%", height:"100%", display:"flex" }}>
      {showAdd && (
        <Modal title="Add teacher" onClose={()=>setShowAdd(false)}>
          <form onSubmit={save}>
            <FormField label="FULL NAME">
              <input required style={inputStyle} value={form.name} onChange={e=>setForm(f=>({...f,name:e.target.value}))} placeholder="e.g. Ms. Priya Sharma"/>
            </FormField>
            <FormField label="EMAIL (used to log in)">
              <input required type="email" style={inputStyle} value={form.email} onChange={e=>setForm(f=>({...f,email:e.target.value}))} placeholder="priya@epiqminds.com"/>
            </FormField>
            <FormField label="PASSWORD">
              <input required type="password" style={inputStyle} value={form.password} onChange={e=>setForm(f=>({...f,password:e.target.value}))} placeholder="min 6 characters"/>
            </FormField>
            {error && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>{error}</div>}
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
              <button type="button" onClick={()=>setShowAdd(false)} className="btn btn-ghost">Cancel</button>
              <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Add teacher"}</button>
            </div>
          </form>
        </Modal>
      )}
      {editTeacher && (
        <Modal title="Edit teacher" onClose={()=>setEditTeacher(null)}>
          <form onSubmit={saveEdit}>
            <FormField label="FULL NAME">
              <input required style={inputStyle} value={editForm.name} onChange={e=>setEditForm(f=>({...f,name:e.target.value}))}/>
            </FormField>
            <FormField label="EMAIL">
              <input required type="email" style={inputStyle} value={editForm.email} onChange={e=>setEditForm(f=>({...f,email:e.target.value}))}/>
            </FormField>
            <FormField label="NEW PASSWORD (leave blank to keep current)">
              <input type="password" style={inputStyle} value={editForm.password} onChange={e=>setEditForm(f=>({...f,password:e.target.value}))} placeholder="leave blank to keep unchanged"/>
            </FormField>
            {error && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>{error}</div>}
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
              <button type="button" onClick={()=>setEditTeacher(null)} className="btn btn-ghost">Cancel</button>
              <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Save changes"}</button>
            </div>
          </form>
        </Modal>
      )}
      {deleteTarget && (
        <Modal
          title={deleteStep === 1 ? "Remove Teacher" : "Confirm Password"}
          onClose={() => { setDeleteTarget(null); setDeleteError(""); }}
        >
          {deleteStep === 1 ? (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, color: "var(--coral)", marginBottom: 6 }}>
                  Deactivating Teacher Account
                </div>
                <div style={{ color: "var(--ink-soft)", lineHeight: 1.5 }}>
                  You are about to remove <strong>{deleteTarget.name}</strong> ({deleteTarget.email}). Their teacher profile and linked user login will be deactivated. Historical teaching sessions, assignments, and attendance logs will be preserved.
                </div>
              </div>

              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, fontSize: 13 }}>
                <label style={{ display: "flex", alignItems: "flex-start", gap: 10, cursor: "pointer", color: "var(--ink)" }}>
                  <input
                    type="checkbox"
                    checked={deleteAck}
                    onChange={e => setDeleteAck(e.target.checked)}
                    style={{ marginTop: 2 }}
                  />
                  <span>Yes, I understand that this teacher account will be deactivated and historical records will be preserved.</span>
                </label>
              </div>

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}>
                <button
                  type="button"
                  onClick={() => { setDeleteTarget(null); setDeleteError(""); }}
                  className="btn btn-ghost"
                >
                  Cancel
                </button>
                <button
                  type="button"
                  disabled={!deleteAck}
                  onClick={() => { setDeleteStep(2); setDeleteError(""); }}
                  className="btn btn-primary"
                  style={{ background: deleteAck ? "var(--coral)" : "var(--paper-deep)", color: deleteAck ? "white" : "var(--ink-mute)" }}
                >
                  Proceed to Step 2 →
                </button>
              </div>
            </div>
          ) : (
            <form onSubmit={executeDelete}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 16, fontSize: 13 }}>
                <div style={{ color: "var(--ink-soft)", lineHeight: 1.5 }}>
                  To confirm removing <strong>{deleteTarget.name || deleteTarget.email}</strong>, please enter <strong>YOUR current password</strong> to authenticate this administrative action.
                </div>
              </div>

              <FormField label="YOUR PASSWORD *">
                <input
                  type="password"
                  required
                  style={{ width:"100%", padding:"9px 12px", borderRadius:10, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", boxSizing:"border-box", outline:"none" }}
                  value={confirmPassword}
                  onChange={e => setConfirmPassword(e.target.value)}
                  placeholder="Enter your current login password"
                  autoFocus
                />
              </FormField>

              {deleteError && (
                <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>
                  {deleteError}
                </div>
              )}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 18 }}>
                <button
                  type="button"
                  onClick={() => { setDeleteStep(1); setDeleteError(""); }}
                  className="btn btn-ghost"
                >
                  ← Back
                </button>
                <button
                  type="submit"
                  disabled={deleteSaving || !confirmPassword}
                  className="btn btn-primary"
                  style={{ background: "var(--coral)" }}
                >
                  {deleteSaving ? "Confirming…" : "Confirm Deletion"}
                </button>
              </div>
            </form>
          )}
        </Modal>
      )}
      <AdminSidebar active="/app/admin/teachers" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Teachers</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>
              {debouncedSearch ? `${filteredList.length} of ${list.length} teachers` : `${list.length} teachers`}
            </div>
          </div>
          <div style={{ flex:1 }}/>
          <SearchBox
            id="teachers-search-input"
            dataTestId="teachers-search-input"
            value={searchQuery}
            onChange={setSearchQuery}
            placeholder="Search name or email…"
          />
          <button onClick={()=>setShowAdd(true)} className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add teacher</button>
        </div>
        <div style={{ flex:1, overflow:"auto", padding:22 }}>
          {list.length === 0 ? (
            <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
              <div style={{ fontSize:32, marginBottom:12 }}>👩‍🏫</div>
              <div style={{ fontSize:16, fontWeight:700 }}>No teachers yet</div>
              <div style={{ fontSize:13, marginTop:4 }}>Add your first teacher to get started</div>
            </div>
          ) : filteredList.length === 0 ? (
            <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
              <div style={{ fontSize:32, marginBottom:12 }}>🔍</div>
              <div style={{ fontSize:16, fontWeight:700 }}>No teachers match "{debouncedSearch}"</div>
              <div style={{ fontSize:13, marginTop:4, marginBottom:16 }}>Check for typos or clear the search filter</div>
              <button onClick={()=>setSearchQuery("")} className="btn btn-ghost" style={{ border:"var(--border-thin)", padding:"6px 14px" }}>Clear search</button>
            </div>
          ) : (
            <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
              <thead>
                <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                  {["Name","Email",""].map(h=><th key={h} style={{ padding:"8px 10px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>)}
                </tr>
              </thead>
              <tbody>
                {filteredList.map((t,i) => (
                  <tr key={t.id} style={{ borderTop: i?"var(--border-thin)":"none" }}>
                    <td style={{ padding:"14px 10px", fontWeight:700 }}>{t.name}</td>
                    <td style={{ padding:"14px 10px", color:"var(--ink-soft)" }}>{t.email}</td>
                    <td style={{ padding:"14px 10px" }}>
                      <div style={{ display:"flex", gap:6 }}>
                        <button onClick={()=>openEdit(t)} className="btn btn-ghost" style={{ padding:"4px 10px", fontSize:11 }}>Edit</button>
                        <button
                          onClick={() => {
                            setDeleteTarget(t);
                            setDeleteStep(1);
                            setDeleteAck(false);
                            setConfirmPassword("");
                            setDeleteError("");
                          }}
                          className="btn btn-ghost"
                          style={{ padding:"4px 10px", fontSize:11, color:"var(--coral)" }}
                        >
                          Remove
                        </button>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Batches ────────────────────────────────────────────────────────────
const AdminBatches = ({ dark = true, go }) => {
  const { data: initBatches }  = useApi("/batches");
  const { data: coursesList }  = useApi("/courses/list");
  const [batches, setBatches]  = React.useState(null);
  const [showAdd, setShowAdd]  = React.useState(false);
  const [searchQuery, setSearchQuery] = React.useState("");
  const debouncedSearch = useDebounce(searchQuery, 150);
  const [form, setForm]        = React.useState({ name:"", course_id:"" });
  const [saving, setSaving]    = React.useState(false);
  const [error, setError]      = React.useState("");
  const list = batches ?? initBatches;

  const refresh = () => apiFetch("/batches").then(r=>r.json()).then(setBatches);

  const filteredList = (list || []).filter(b => {
    if (!debouncedSearch) return true;
    const q = debouncedSearch.toLowerCase().trim();
    return (b.name || "").toLowerCase().includes(q) || (b.course || "").toLowerCase().includes(q);
  });

  const save = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch("/batches", { method:"POST", body: JSON.stringify({ name: form.name, course_id: parseInt(form.course_id) }) });
    const data = await res.json();
    if (!res.ok) { setError(data.error || "Failed"); setSaving(false); return; }
    await refresh();
    setForm({ name:"", course_id:"" }); setShowAdd(false); setSaving(false);
  };

  const [deleteTarget, setDeleteTarget] = React.useState(null);
  const [deleteStep, setDeleteStep] = React.useState(1);
  const [deleteAck, setDeleteAck] = React.useState(false);
  const [confirmPassword, setConfirmPassword] = React.useState("");
  const [deleteSaving, setDeleteSaving] = React.useState(false);
  const [deleteError, setDeleteError] = React.useState("");

  const executeDelete = async e => {
    e.preventDefault();
    if (!confirmPassword) {
      setDeleteError("Password is required to confirm deletion.");
      return;
    }
    setDeleteSaving(true);
    setDeleteError("");
    try {
      const res = await apiFetch(`/batches/${deleteTarget.id}`, {
        method: "DELETE",
        body: JSON.stringify({ password: confirmPassword }),
      });
      const d = await res.json().catch(() => ({}));
      if (!res.ok) {
        setDeleteError(d.error || (res.status === 401 ? "Session expired" : "Could not remove this batch."));
        setDeleteSaving(false);
        return;
      }
      await refresh();
      setDeleteTarget(null);
      setConfirmPassword("");
      setDeleteSaving(false);
    } catch {
      setDeleteError("Something went wrong removing the batch. Please try again.");
      setDeleteSaving(false);
    }
  };

  return (
    <Themed className={dark?"theme-dark":""} style={{ width:"100%", height:"100%", display:"flex" }}>
      {showAdd && (
        <Modal title="Add batch" onClose={()=>setShowAdd(false)}>
          <form onSubmit={save}>
            <FormField label="BATCH NAME">
              <input required style={inputStyle} value={form.name} onChange={e=>setForm(f=>({...f,name:e.target.value}))} placeholder="e.g. Batch A"/>
            </FormField>
            <FormField label="COURSE">
              <select required style={selectStyle} value={form.course_id} onChange={e=>setForm(f=>({...f,course_id:e.target.value}))}>
                <option value="">— select course —</option>
                {coursesList.map(c=><option key={c.id} value={c.id}>{c.name} · {c.level}</option>)}
              </select>
            </FormField>
            {error && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>{error}</div>}
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
              <button type="button" onClick={()=>setShowAdd(false)} className="btn btn-ghost">Cancel</button>
              <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Add batch"}</button>
            </div>
          </form>
        </Modal>
      )}
      {deleteTarget && (
        <Modal
          title={deleteStep === 1 ? "Remove Batch" : "Confirm Password"}
          onClose={() => { setDeleteTarget(null); setDeleteError(""); }}
        >
          {deleteStep === 1 ? (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, color: "var(--coral)", marginBottom: 6 }}>
                  Removing Batch
                </div>
                <div style={{ color: "var(--ink-soft)", lineHeight: 1.5 }}>
                  You are about to permanently delete batch <strong>{deleteTarget.name}</strong> ({deleteTarget.course}). If this batch still has assigned students, historical sessions, quizzes, or attendance records, the deletion will be rejected by the server.
                </div>
              </div>

              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, fontSize: 13 }}>
                <label style={{ display: "flex", alignItems: "flex-start", gap: 10, cursor: "pointer", color: "var(--ink)" }}>
                  <input
                    type="checkbox"
                    checked={deleteAck}
                    onChange={e => setDeleteAck(e.target.checked)}
                    style={{ marginTop: 2 }}
                  />
                  <span>Yes, I understand that batch deletion is permanent and cannot be undone.</span>
                </label>
              </div>

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}>
                <button
                  type="button"
                  onClick={() => { setDeleteTarget(null); setDeleteError(""); }}
                  className="btn btn-ghost"
                >
                  Cancel
                </button>
                <button
                  type="button"
                  disabled={!deleteAck}
                  onClick={() => { setDeleteStep(2); setDeleteError(""); }}
                  className="btn btn-primary"
                  style={{ background: deleteAck ? "var(--coral)" : "var(--paper-deep)", color: deleteAck ? "white" : "var(--ink-mute)" }}
                >
                  Proceed to Step 2 →
                </button>
              </div>
            </div>
          ) : (
            <form onSubmit={executeDelete}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 16, fontSize: 13 }}>
                <div style={{ color: "var(--ink-soft)", lineHeight: 1.5 }}>
                  To confirm removing batch <strong>{deleteTarget.name}</strong>, please enter <strong>YOUR current password</strong> to authenticate this administrative action.
                </div>
              </div>

              <FormField label="YOUR PASSWORD *">
                <input
                  type="password"
                  required
                  style={{ width:"100%", padding:"9px 12px", borderRadius:10, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", boxSizing:"border-box", outline:"none" }}
                  value={confirmPassword}
                  onChange={e => setConfirmPassword(e.target.value)}
                  placeholder="Enter your current login password"
                  autoFocus
                />
              </FormField>

              {deleteError && (
                <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>
                  {deleteError}
                </div>
              )}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 18 }}>
                <button
                  type="button"
                  onClick={() => { setDeleteStep(1); setDeleteError(""); }}
                  className="btn btn-ghost"
                >
                  ← Back
                </button>
                <button
                  type="submit"
                  disabled={deleteSaving || !confirmPassword}
                  className="btn btn-primary"
                  style={{ background: "var(--coral)" }}
                >
                  {deleteSaving ? "Confirming…" : "Confirm Deletion"}
                </button>
              </div>
            </form>
          )}
        </Modal>
      )}
      <AdminSidebar active="/app/admin/batches" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Batches</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>
              {debouncedSearch ? `${filteredList.length} of ${list.length} batches` : `${list.length} batches`}
            </div>
          </div>
          <div style={{ flex:1 }}/>
          <SearchBox
            id="batches-search-input"
            dataTestId="batches-search-input"
            value={searchQuery}
            onChange={setSearchQuery}
            placeholder="Search name or course…"
          />
          <button onClick={()=>setShowAdd(true)} className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add batch</button>
        </div>
        <div style={{ flex:1, overflow:"auto", padding:22 }}>
          {list.length === 0 ? (
            <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
              <div style={{ fontSize:32, marginBottom:12 }}>📚</div>
              <div style={{ fontSize:16, fontWeight:700 }}>No batches yet</div>
              <div style={{ fontSize:13, marginTop:4 }}>Create a batch to start enrolling students</div>
            </div>
          ) : filteredList.length === 0 ? (
            <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
              <div style={{ fontSize:32, marginBottom:12 }}>🔍</div>
              <div style={{ fontSize:16, fontWeight:700 }}>No batches match "{debouncedSearch}"</div>
              <div style={{ fontSize:13, marginTop:4, marginBottom:16 }}>Check for typos or clear the search filter</div>
              <button onClick={()=>setSearchQuery("")} className="btn btn-ghost" style={{ border:"var(--border-thin)", padding:"6px 14px" }}>Clear search</button>
            </div>
          ) : (
            <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
              <thead>
                <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                  {["Batch","Course","Students",""].map(h=><th key={h} style={{ padding:"8px 10px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>)}
                </tr>
              </thead>
              <tbody>
                {filteredList.map((b,i) => (
                  <tr key={b.id} style={{ borderTop: i?"var(--border-thin)":"none" }}>
                    <td style={{ padding:"14px 10px", fontWeight:700 }}>{b.name}</td>
                    <td style={{ padding:"14px 10px", color:"var(--ink-soft)" }}>{b.course}</td>
                    <td style={{ padding:"14px 10px" }}>{b.students}</td>
                    <td style={{ padding:"14px 10px" }}>
                      <button
                        onClick={() => {
                          setDeleteTarget(b);
                          setDeleteStep(1);
                          setDeleteAck(false);
                          setConfirmPassword("");
                          setDeleteError("");
                        }}
                        className="btn btn-ghost"
                        style={{ padding:"4px 10px", fontSize:11, color:"var(--coral)" }}
                      >
                        Remove
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Broadcast / Notifications ─────────────────────────────────────────
const AdminBroadcast = ({ dark = true, go }) => {
  const [msg, setMsg] = React.useState("");
  const [channels, setChannels] = React.useState({ whatsapp:true, email:true, sms:false });
  const [target, setTarget] = React.useState("all");
  const [sent, setSent] = React.useState(false);
  const toggle = k => setChannels(c => ({ ...c, [k]: !c[k] }));
  const { data: history } = useApi("/broadcast/history");
  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/broadcast" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Broadcast</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>WhatsApp · Email · SMS — reach all families instantly</div>
          </div>
        </div>
        <div style={{ flex:1, display:"grid", gridTemplateColumns:"1.2fr 1fr", gap:22, padding:22, overflow:"auto" }}>
          <div style={{ display:"flex", flexDirection:"column", gap:16 }}>
            <div className="card-flat" style={{ padding:20 }}>
              <SectionHead eyebrow="COMPOSE" title="New broadcast"/>
              <textarea value={msg} onChange={e=>setMsg(e.target.value)} placeholder="Type your message here…" style={{ width:"100%", minHeight:120, padding:"12px 14px", border:"var(--border-thin)", borderRadius:10, background:"var(--paper-deep)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", resize:"vertical", outline:"none", boxSizing:"border-box" }}/>
              <div style={{ marginTop:14 }}>
                <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginBottom:8 }}>CHANNELS</div>
                <div style={{ display:"flex", gap:10 }}>
                  {[["whatsapp","WhatsApp","var(--moss)"],["email","Email","var(--sky)"],["sms","SMS","var(--gold)"]].map(([k,label,c]) => (
                    <button key={k} onClick={() => toggle(k)} style={{ display:"flex", alignItems:"center", gap:6, padding:"6px 14px", borderRadius:999, border:"var(--border-thin)", background: channels[k] ? c : "var(--paper-deep)", color: channels[k] ? "white" : "var(--ink-soft)", fontSize:12, fontWeight:700, cursor:"pointer" }}>
                      {channels[k] ? I.check({ size:12 }) : null} {label}
                    </button>
                  ))}
                </div>
              </div>
              <div style={{ marginTop:14 }}>
                <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginBottom:8 }}>AUDIENCE</div>
                <div style={{ display:"flex", gap:8 }}>
                  {[["all","All families (48)"],["batch","By batch"],["course","By course"]].map(([v,l]) => (
                    <button key={v} onClick={() => setTarget(v)} style={{ padding:"6px 12px", borderRadius:999, border:"var(--border-thin)", background: target===v ? "var(--ink)" : "var(--paper-deep)", color: target===v ? "var(--paper)" : "var(--ink-soft)", fontSize:12, fontWeight:700, cursor:"pointer" }}>{l}</button>
                  ))}
                </div>
                {target === "batch" && (
                  <select style={{ marginTop:8, padding:"6px 12px", borderRadius:8, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:12, color:"var(--ink)", fontFamily:"var(--font-ui)" }}>
                    {["Batch A · Scratch","Batch B · Python","Batch C · Python","Batch D · Web","Batch E · AI"].map(b => <option key={b}>{b}</option>)}
                  </select>
                )}
              </div>
              <div style={{ marginTop:18 }}>
                {sent ? (
                  <div style={{ display:"flex", alignItems:"center", gap:8, color:"var(--moss)", fontWeight:700 }}>{I.check({ size:18 })} Broadcast sent to {target==="all"?48:12} families!</div>
                ) : (
                  <button className="btn btn-primary" onClick={async () => {
                    if (msg.trim()) {
                      await apiFetch("/broadcast", { method:"POST", body: JSON.stringify({ text: msg.trim(), channels: Object.keys(channels).filter(k=>channels[k]), reach: target==="all"?48:12 }) }).catch(()=>{});
                      setSent(true);
                      if (window.showToast) window.showToast({ title: "Broadcast Sent", message: `Dispatched announcement to ${target==="all"?48:12} families across all channels!`, type: "success" });
                    }
                  }} style={{ padding:"10px 22px", fontSize:14 }}>{I.send({ size:16 })} Send broadcast</button>
                )}
              </div>
            </div>
            <div className="card-flat" style={{ padding:16 }}>
              <SectionHead eyebrow="INTEGRATIONS" title="Connected channels"/>
              {[
                { name:"WhatsApp Business", handle:"@epiqminds.com", status:"connected", color:"var(--moss)", note:"via Twilio" },
                { name:"Email (SendGrid)", handle:"noreply@epiqminds.com", status:"connected", color:"var(--sky)", note:"1,200 sends/mo" },
                { name:"SMS", handle:"+91 98765 00000", status:"not set up", color:"var(--ink-mute)", note:"Click to configure" },
              ].map((ch, i) => (
                <div key={i} style={{ display:"flex", alignItems:"center", gap:12, padding:"10px 0", borderTop: i ? "var(--border-thin)" : "none" }}>
                  <div style={{ width:8, height:32, borderRadius:4, background: ch.status==="connected" ? "var(--moss)" : "var(--rule)", flexShrink:0 }}/>
                  <div style={{ flex:1 }}>
                    <div style={{ fontWeight:700, fontSize:13 }}>{ch.name}</div>
                    <div style={{ fontSize:11, color:"var(--ink-mute)" }}>{ch.handle} · {ch.note}</div>
                  </div>
                  <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: ch.status==="connected" ? "var(--moss)" : "var(--paper-deep)", color: ch.status==="connected" ? "white" : "var(--ink-mute)" }}>{ch.status}</span>
                </div>
              ))}
            </div>
          </div>
          <div className="card-flat" style={{ padding:18, overflow:"auto" }}>
            <SectionHead eyebrow="HISTORY" title="Recent broadcasts"/>
            {history.map((h, i) => (
              <div key={i} style={{ padding:"12px 0", borderTop: i ? "var(--border-thin)" : "none" }}>
                <div style={{ fontSize:13, fontWeight:600, lineHeight:1.4, marginBottom:6 }}>{h.text}</div>
                <div style={{ display:"flex", alignItems:"center", gap:8 }}>
                  <span className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>{h.time}</span>
                  <span style={{ fontSize:11, color:"var(--ink-mute)" }}>· {h.reach} families</span>
                  <div style={{ flex:1 }}/>
                  {h.channels.map(c => <span key={c} className="chip flat" style={{ fontSize:10, padding:"1px 6px" }}>{c}</span>)}
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Class Schedule + Google Meet ───────────────────────────────────────
const DAYS = ["Mon","Tue","Wed","Thu","Fri","Sat"];

const fmt12 = t => {
  if (!t) return "";
  const [h,m] = t.split(":").map(Number);
  return `${h%12||12}:${m.toString().padStart(2,"0")} ${h>=12?"PM":"AM"}`;
};

const to24 = t => {
  if (!t) return "";
  const m = t.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)?$/i);
  if (!m) return t;
  let h = parseInt(m[1], 10);
  const min = m[2];
  const ampm = m[3] ? m[3].toUpperCase() : null;
  if (ampm === "PM" && h < 12) h += 12;
  if (ampm === "AM" && h === 12) h = 0;
  return `${h.toString().padStart(2, "0")}:${min}`;
};

// Weekday chips for the recurring-schedule builder (index = JS getUTCDay()).
const WEEKDAY_LABELS = [["Sunday","S"],["Monday","M"],["Tuesday","T"],["Wednesday","W"],["Thursday","T"],["Friday","F"],["Saturday","S"]];
// Generate ISO (YYYY-MM-DD) dates for a weekly recurrence. UTC calendar math so
// the browser's own timezone can never shift a date across midnight.
const genRecurringDates = (startISO, weekdays, endMode, count, untilISO) => {
  if (!startISO || !weekdays || !weekdays.length) return [];
  const d = new Date(startISO + "T00:00:00Z");
  if (isNaN(d.getTime())) return [];
  const until = (endMode === "until" && untilISO) ? new Date(untilISO + "T00:00:00Z") : null;
  const cap = endMode === "count" ? Math.min(Math.max(parseInt(count) || 0, 0), 200) : 200;
  const out = [];
  let guard = 0;
  while (guard++ < 1500) {
    if (until && d > until) break;
    if (weekdays.includes(d.getUTCDay())) {
      out.push(d.toISOString().slice(0, 10));
      if (endMode === "count" && out.length >= cap) break;
    }
    d.setUTCDate(d.getUTCDate() + 1);
  }
  return out;
};

// ISO date helpers for Day/Week/Month calendar filtering.
// Uses local calendar math so dates never shift across midnight due to UTC offsets.
const parseScheduleISO = (iso) => {
  if (!iso) return new Date();
  const [y, m, d] = iso.split("-").map(Number);
  return new Date(y, (m || 1) - 1, d || 1);
};

const toScheduleISO = (dt) => {
  const y = dt.getFullYear();
  const m = String(dt.getMonth() + 1).padStart(2, "0");
  const d = String(dt.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
};

// Sunday-Saturday week range (Sunday = start, Saturday = end)
const getSundaySaturdayWeekRange = (isoDate) => {
  const dt = parseScheduleISO(isoDate);
  const dayOfWeek = dt.getDay(); // 0 = Sun, ..., 6 = Sat
  const sunday = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() - dayOfWeek);
  const saturday = new Date(sunday.getFullYear(), sunday.getMonth(), sunday.getDate() + 6);
  return {
    start: toScheduleISO(sunday),
    end: toScheduleISO(saturday),
    sunday,
    saturday,
  };
};

const AdminSchedule = ({ dark = true, go }) => {
  const { data: initSessions, loading } = useApi("/schedule");
  const { data: BATCHES }  = useApi("/batches");
  const { data: TEACHERS } = useApi("/teachers");
  const { data: STUDENTS } = useApi("/students");
  const [view, setView]       = React.useState("week");
  const [showAdd, setShowAdd] = React.useState(false);
  const [sessions, setSessions] = React.useState(null);
  const [sessType, setSessType] = React.useState("batch");
  const [form, setForm] = React.useState({ batch_id:"", student_id:"", teacher_id:"", day:"", time_start:"", time_end:"", meet_link:"", timezone:"Asia/Kolkata" });
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState("");
  const [statusChanging, setStatusChanging] = React.useState(null);
  // Recurring-schedule builder state.
  const [repeat, setRepeat]     = React.useState(false);
  const [weekdays, setWeekdays] = React.useState([]);   // JS getUTCDay() indices
  const [endMode, setEndMode]   = React.useState("count"); // "count" | "until"
  const [count, setCount]       = React.useState("24");
  const [until, setUntil]       = React.useState("");
  const recurDates = repeat ? genRecurringDates(form.day, weekdays, endMode, count, until) : [];
  const list = asArray(sessions ?? initSessions);
  const teacherList = asArray(TEACHERS);
  const batchList = asArray(BATCHES);
  const studentList = asArray(STUDENTS);
  const studentMap = React.useMemo(() => new Map(studentList.map(s => [String(s.id), s.name])), [studentList]);

  // Schedule filters (Date range navigation, Batch dropdown, Debounced search bar)
  const [anchorDate, setAnchorDate]   = React.useState(() => toScheduleISO(new Date()));
  const [batchFilter, setBatchFilter] = React.useState("all"); // "all" | "1-on-1" | batch_id
  const [searchQuery, setSearchQuery] = React.useState("");
  const [debouncedSearch, setDebouncedSearch] = React.useState("");

  React.useEffect(() => {
    const h = setTimeout(() => setDebouncedSearch(searchQuery.trim().toLowerCase()), 150);
    return () => clearTimeout(h);
  }, [searchQuery]);

  const stepPeriod = (direction) => {
    const dt = parseScheduleISO(anchorDate);
    if (view === "day") {
      dt.setDate(dt.getDate() + direction);
    } else if (view === "week") {
      dt.setDate(dt.getDate() + (direction * 7));
    } else if (view === "month") {
      const y = dt.getFullYear();
      const m = dt.getMonth() + direction;
      dt.setFullYear(y);
      dt.setMonth(m, 1);
    }
    setAnchorDate(toScheduleISO(dt));
  };

  const periodLabel = React.useMemo(() => {
    const dt = parseScheduleISO(anchorDate);
    if (view === "day") {
      return dt.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", year: "numeric" });
    }
    if (view === "week") {
      const { sunday, saturday } = getSundaySaturdayWeekRange(anchorDate);
      const sameMonth = sunday.getMonth() === saturday.getMonth();
      const sameYear = sunday.getFullYear() === saturday.getFullYear();
      const m1 = sunday.toLocaleDateString("en-US", { month: "short" });
      const m2 = saturday.toLocaleDateString("en-US", { month: "short" });
      const d1 = sunday.getDate();
      const d2 = saturday.getDate();
      const y = saturday.getFullYear();
      if (sameMonth && sameYear) return `${m1} ${d1} – ${d2}, ${y}`;
      if (sameYear) return `${m1} ${d1} – ${m2} ${d2}, ${y}`;
      return `${m1} ${d1}, ${sunday.getFullYear()} – ${m2} ${d2}, ${y}`;
    }
    if (view === "month") {
      return dt.toLocaleDateString("en-US", { month: "long", year: "numeric" });
    }
    return "";
  }, [anchorDate, view]);

  const filteredSessions = React.useMemo(() => {
    return list.filter(s => {
      // 1. Date filter (Day / Week / Month)
      if (view === "day") {
        if (s.day !== anchorDate) return false;
      } else if (view === "week") {
        const { start, end } = getSundaySaturdayWeekRange(anchorDate);
        if (!s.day || s.day < start || s.day > end) return false;
      } else if (view === "month") {
        const prefix = anchorDate.slice(0, 7);
        if (!s.day || !s.day.startsWith(prefix)) return false;
      }

      // 2. Batch filter (All / 1-on-1 / specific batch)
      if (batchFilter === "1-on-1") {
        if (s.session_type !== "individual" && (s.batch_id || !s.student_id)) return false;
      } else if (batchFilter !== "all") {
        if (String(s.batch_id) !== String(batchFilter)) return false;
      }

      // 3. Search query filter (batch name, teacher name, student name)
      if (debouncedSearch) {
        const batchName = (s.batch || "").toLowerCase();
        const teacherName = (s.teacher || "").toLowerCase();
        const studentName = ((s.student_id && studentMap.get(String(s.student_id))) || "").toLowerCase();
        const matches = batchName.includes(debouncedSearch) ||
                        teacherName.includes(debouncedSearch) ||
                        studentName.includes(debouncedSearch);
        if (!matches) return false;
      }

      return true;
    });
  }, [list, view, anchorDate, batchFilter, debouncedSearch, studentMap]);

  const markStatus = async (id, status) => {
    setStatusChanging(id);
    await apiFetch(`/schedule/${id}/status`, { method:"PATCH", body: JSON.stringify({ status }) });
    setSessions(await apiList("/schedule"));
    setStatusChanging(null);
  };

  // Session edit state
  const [editingSession, setEditingSession] = React.useState(null);
  const [editSessType, setEditSessType]     = React.useState("batch");
  const [editForm, setEditForm]             = React.useState({ batch_id:"", student_id:"", teacher_id:"", day:"", time_start:"", time_end:"", meet_link:"", timezone:"Asia/Kolkata" });
  const [editSaving, setEditSaving]         = React.useState(false);
  const [editError, setEditError]           = React.useState("");

  const startEdit = s => {
    setEditingSession(s);
    setEditSessType(s.student_id || s.session_type === "individual" ? "individual" : "batch");
    setEditForm({
      batch_id: s.batch_id ? String(s.batch_id) : "",
      student_id: s.student_id ? String(s.student_id) : "",
      teacher_id: s.teacher_id ? String(s.teacher_id) : "",
      day: s.day || "",
      time_start: to24(s.time),
      time_end: to24(s.end),
      meet_link: s.meet || "",
      timezone: s.tz || "Asia/Kolkata",
    });
    setEditError("");
  };

  const saveEdit = async e => {
    e.preventDefault();
    setEditError("");
    if (!editForm.teacher_id) {
      setEditError(teacherList.length ? "Select a teacher." : "No teachers found.");
      return;
    }
    if (!editingSession.has_attendance) {
      if (editSessType === "batch" && !editForm.batch_id) { setEditError("Select a batch."); return; }
      if (editSessType === "individual" && !editForm.student_id) { setEditError("Select a student."); return; }
      if (!editForm.day) { setEditError("Enter a date."); return; }
    }
    setEditSaving(true);
    const payload = {
      teacher_id: parseInt(editForm.teacher_id) || null,
      time_start: fmt12(editForm.time_start),
      time_end: fmt12(editForm.time_end),
      timezone: editForm.timezone || "Asia/Kolkata",
      meet_link: editForm.meet_link || null,
    };
    if (!editingSession.has_attendance) {
      payload.day = editForm.day;
      payload.batch_id = editSessType === "batch" ? (parseInt(editForm.batch_id) || null) : null;
      payload.student_id = editSessType === "individual" ? (parseInt(editForm.student_id) || null) : null;
    }
    const res = await apiFetch(`/schedule/${editingSession.id}`, {
      method: "PATCH",
      body: JSON.stringify(payload),
    });
    if (!res.ok) {
      const d = await res.json().catch(() => ({}));
      setEditError(d.error || "Failed to update session.");
      setEditSaving(false);
      return;
    }
    setSessions(await apiList("/schedule"));
    setEditingSession(null);
    setEditSaving(false);
  };

  const deleteFromEdit = async () => {
    if (!window.confirm("Are you sure you want to delete this session?")) return;
    setEditSaving(true);
    const res = await apiFetch(`/schedule/${editingSession.id}`, { method: "DELETE" });
    if (!res.ok) {
      const d = await res.json().catch(() => ({}));
      setEditError(d.error || "Failed to delete session.");
      setEditSaving(false);
      return;
    }
    setSessions(await apiList("/schedule"));
    setEditingSession(null);
    setEditSaving(false);
  };

  // Not-conducted state
  const [ncSession, setNcSession] = React.useState(null);
  const [ncReason, setNcReason]   = React.useState("");
  const [ncSaving, setNcSaving]   = React.useState(false);
  const [ncError, setNcError]     = React.useState("");

  const submitNotConducted = async e => {
    e.preventDefault();
    setNcSaving(true);
    setNcError("");
    const res = await apiFetch(`/schedule/${ncSession.id}/not-conducted`, {
      method: "POST",
      body: JSON.stringify({ reason: ncReason || undefined }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      setNcError(data.error || "Failed to mark session not conducted.");
      setNcSaving(false);
      return;
    }
    setSessions(await apiList("/schedule"));
    setNcSession(null);
    setNcReason("");
    setNcSaving(false);
    if (data.message) {
      alert(data.message);
    }
  };

  // Session completion remarks state & handler
  const [doneSession, setDoneSession] = React.useState(null);
  const [doneRemarks, setDoneRemarks] = React.useState("");
  const [doneSaving, setDoneSaving]   = React.useState(false);
  const [doneError, setDoneError]     = React.useState("");
  const [viewRemarksSession, setViewRemarksSession] = React.useState(null);

  const submitCompleteSession = async e => {
    e.preventDefault();
    if (!doneRemarks.trim()) {
      setDoneError("Completion remarks are required.");
      return;
    }
    setDoneSaving(true);
    setDoneError("");
    const res = await apiFetch(`/schedule/${doneSession.id}/status`, {
      method: "PATCH",
      body: JSON.stringify({ status: "done", completion_remarks: doneRemarks.trim() }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      setDoneError(data.error || "Failed to mark session as done.");
      setDoneSaving(false);
      return;
    }
    setSessions(await apiList("/schedule"));
    setDoneSession(null);
    setDoneRemarks("");
    setDoneSaving(false);
  };

  // ── Session Requests state & handlers ──────────────────────────────────────
  const { data: initRequests } = useApi("/schedule-requests");
  const [requests, setRequests] = React.useState(null);
  const [reqFilter, setReqFilter] = React.useState("pending");
  const [approvingReq, setApprovingReq] = React.useState(null);
  const [appForm, setAppForm] = React.useState({ teacher_id:"", day:"", time_start:"", time_end:"", timezone:"Asia/Kolkata", meet_link:"", admin_response:"" });
  const [appSaving, setAppSaving] = React.useState(false);
  const [appError, setAppError] = React.useState("");
  const [appConflict, setAppConflict] = React.useState(null);
  const [rejectingReq, setRejectingReq] = React.useState(null);
  const [rejReason, setRejReason] = React.useState("");
  const [rejSaving, setRejSaving] = React.useState(false);
  const [rejError, setRejError] = React.useState("");

  const reqList = asArray(requests ?? initRequests);
  const pendingRequests = reqList.filter(r => r.status === "pending");
  const reqTabLabel = pendingRequests.length ? `Requests (${pendingRequests.length})` : "Requests";

  const startApprove = r => {
    setApprovingReq(r);
    setAppForm({
      teacher_id: r.teacher_id ? String(r.teacher_id) : "",
      day: r.day || "",
      time_start: to24(r.time_start),
      time_end: to24(r.time_end),
      timezone: r.timezone || "Asia/Kolkata",
      meet_link: "",
      admin_response: "",
    });
    setAppConflict(null);
    setAppError("");
  };

  const submitApprove = async (e, force = false) => {
    if (e && e.preventDefault) e.preventDefault();
    setAppSaving(true);
    setAppError("");
    setAppConflict(null);
    const payload = {
      teacher_id: parseInt(appForm.teacher_id) || undefined,
      day: appForm.day || undefined,
      time_start: fmt12(appForm.time_start),
      time_end: fmt12(appForm.time_end),
      timezone: appForm.timezone || "Asia/Kolkata",
      meet_link: appForm.meet_link || undefined,
      admin_response: appForm.admin_response || undefined,
      force: !!force,
    };
    const res = await apiFetch(`/schedule-requests/${approvingReq.id}/approve`, {
      method: "POST",
      body: JSON.stringify(payload),
    });
    const d = await res.json().catch(() => ({}));
    if (!res.ok) {
      if (res.status === 409 && d.conflict) {
        setAppConflict(d.error || "A scheduling conflict was detected.");
      } else {
        setAppError(d.error || "Failed to approve request.");
      }
      setAppSaving(false);
      return;
    }
    setRequests(await apiList("/schedule-requests"));
    setSessions(await apiList("/schedule"));
    setApprovingReq(null);
    setAppSaving(false);
  };

  const startReject = r => {
    setRejectingReq(r);
    setRejReason("");
    setRejError("");
  };

  const submitReject = async e => {
    e.preventDefault();
    setRejSaving(true);
    setRejError("");
    const res = await apiFetch(`/schedule-requests/${rejectingReq.id}/reject`, {
      method: "POST",
      body: JSON.stringify({ reason: rejReason || undefined }),
    });
    const d = await res.json().catch(() => ({}));
    if (!res.ok) {
      setRejError(d.error || "Failed to reject request.");
      setRejSaving(false);
      return;
    }
    setRequests(await apiList("/schedule-requests"));
    setRejectingReq(null);
    setRejSaving(false);
  };

  const saveSession = async e => {
    e.preventDefault(); setError("");
    if (!form.teacher_id) { setError(teacherList.length ? "Select a teacher." : "No teachers found — add a teacher first."); return; }
    if (sessType === "batch" && !form.batch_id) { setError(batchList.length ? "Select a batch." : "No batches found — create a batch first."); return; }
    if (sessType === "individual" && !form.student_id) { setError("Select a student."); return; }
    if (repeat && !recurDates.length) { setError("Pick a start date and at least one weekday."); return; }
    setSaving(true);
    const shared = {
      time_start: fmt12(form.time_start),
      time_end:   fmt12(form.time_end),
      timezone:   form.timezone || "Asia/Kolkata",
      meet_link:  form.meet_link || null,
      teacher_id: parseInt(form.teacher_id) || null,
      batch_id:   sessType === "batch"      ? (parseInt(form.batch_id)||null)   : null,
      student_id: sessType === "individual" ? (parseInt(form.student_id)||null) : null,
    };
    const res = repeat
      ? await apiFetch("/schedule/bulk", { method:"POST", body: JSON.stringify({ ...shared, days: recurDates }) })
      : await apiFetch("/schedule",      { method:"POST", body: JSON.stringify({ ...shared, day: form.day }) });
    if (!res.ok) {
      const d = await res.json().catch(() => ({}));
      setError(d.error || (repeat ? "Failed to create sessions." : "Failed to create session.")); setSaving(false); return;
    }
    setSessions(await apiList("/schedule"));
    setForm({ batch_id:"", student_id:"", teacher_id:"", day:"", time_start:"", time_end:"", meet_link:"", timezone:"Asia/Kolkata" });
    setRepeat(false); setWeekdays([]); setEndMode("count"); setCount("24"); setUntil("");
    setShowAdd(false); setSaving(false);
  };

  const statusColor = s => s==="live" ? "var(--coral)" : s==="done" ? "var(--ink-mute)" : s==="not_conducted" ? "var(--gold)" : "var(--moss)";
  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/schedule" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Class Schedule</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>
              {view === "requests"
                ? `${reqList.length} request${reqList.length === 1 ? "" : "s"}${pendingRequests.length ? ` · ${pendingRequests.length} pending` : ""}`
                : `${filteredSessions.length} of ${list.length} session${list.length === 1 ? "" : "s"}${pendingRequests.length ? ` · ${pendingRequests.length} pending request${pendingRequests.length===1?"":"s"}` : ""}`}
            </div>
          </div>
          <div style={{ flex:1 }}/>
          <div style={{ display:"flex", alignItems:"center", gap:6, background:"var(--paper-deep)", border:"var(--border-thin)", borderRadius:8, padding:"3px 8px" }}>
            <span style={{ fontSize:11, color:"var(--ink-mute)", fontWeight:600 }}>Date:</span>
            <input
              type="date"
              id="schedule-date-picker"
              data-testid="schedule-date-picker"
              value={anchorDate}
              onChange={e => {
                if (e.target.value) {
                  setAnchorDate(e.target.value);
                  setView("day");
                }
              }}
              style={{
                background: "transparent",
                border: "none",
                outline: "none",
                color: "var(--ink)",
                fontFamily: "var(--font-ui)",
                fontSize: 12,
                cursor: "pointer",
              }}
              title="Jump to a specific date"
            />
          </div>
          <Tabs items={["Week","Day","Month", reqTabLabel]} active={view==="week"?"Week":view==="day"?"Day":view==="month"?"Month":reqTabLabel} onChange={v => setView(v.startsWith("Requests") ? "requests" : v.toLowerCase())}/>
          <button className="btn btn-primary" onClick={() => { setForm(f => ({ ...f, day: anchorDate })); setShowAdd(true); }} style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add session</button>
        </div>

        {view !== "requests" && (
          <div style={{ display:"flex", flexWrap:"wrap", alignItems:"center", justifyContent:"space-between", gap:12, padding:"10px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-deep)" }}>
            <div style={{ display:"flex", alignItems:"center", gap:10 }}>
              <div style={{ display:"flex", alignItems:"center", background:"var(--paper-card)", borderRadius:8, border:"var(--border-thin)", padding:2 }}>
                <button
                  type="button"
                  onClick={() => stepPeriod(-1)}
                  className="btn btn-ghost"
                  style={{ padding:"4px 9px", fontSize:12, borderRadius:6, lineHeight:1 }}
                  title={`Previous ${view}`}
                >
                  ◀
                </button>
                <button
                  type="button"
                  onClick={() => setAnchorDate(toScheduleISO(new Date()))}
                  className="btn btn-ghost"
                  style={{ padding:"4px 10px", fontSize:11, fontWeight:600, borderRadius:6, lineHeight:1 }}
                  title="Jump to today"
                >
                  Today
                </button>
                <button
                  type="button"
                  onClick={() => stepPeriod(1)}
                  className="btn btn-ghost"
                  style={{ padding:"4px 9px", fontSize:12, borderRadius:6, lineHeight:1 }}
                  title={`Next ${view}`}
                >
                  ▶
                </button>
              </div>
              <div style={{ fontWeight:700, fontSize:13.5, color:"var(--ink)" }}>
                {periodLabel}
              </div>
            </div>

            <div style={{ display:"flex", alignItems:"center", gap:10 }}>
              {/* Batch filter (Item 3) */}
              <select
                id="schedule-batch-filter"
                data-testid="schedule-batch-filter"
                value={batchFilter}
                onChange={e => setBatchFilter(e.target.value)}
                style={{
                  padding: "6px 10px",
                  borderRadius: 8,
                  border: "var(--border-thin)",
                  background: "var(--paper-card)",
                  fontSize: 12,
                  fontFamily: "var(--font-ui)",
                  color: "var(--ink)",
                  outline: "none",
                  cursor: "pointer",
                }}
              >
                <option value="all">All Batches</option>
                <option value="1-on-1">1-on-1 Sessions Only</option>
                {batchList.length > 0 && (
                  <optgroup label="Batches">
                    {batchList.map(b => (
                      <option key={b.id} value={String(b.id)}>{b.name}</option>
                    ))}
                  </optgroup>
                )}
              </select>

              {/* Search bar (Item 1) */}
              <div className="card-flat" style={{ display:"flex", alignItems:"center", gap:6, padding:"5px 10px", background:"var(--paper-card)", borderRadius:8, border:"var(--border-thin)", width:230 }}>
                {I.search({ size:13 })}
                <input
                  id="schedule-search-input"
                  data-testid="schedule-search-input"
                  value={searchQuery}
                  onChange={e => setSearchQuery(e.target.value)}
                  placeholder="Search batch, teacher, student…"
                  style={{ border:"none", outline:"none", background:"transparent", fontSize:12, fontFamily:"var(--font-ui)", color:"var(--ink)", width:"100%" }}
                />
                {searchQuery && (
                  <button
                    type="button"
                    onClick={() => setSearchQuery("")}
                    style={{ border:"none", background:"transparent", cursor:"pointer", color:"var(--ink-mute)", fontSize:11, padding:0, lineHeight:1 }}
                    title="Clear search"
                  >
                    ✕
                  </button>
                )}
              </div>

              {(batchFilter !== "all" || searchQuery) && (
                <button
                  type="button"
                  onClick={() => { setBatchFilter("all"); setSearchQuery(""); }}
                  className="btn btn-ghost"
                  style={{ fontSize:11, padding:"4px 8px", color:"var(--coral)" }}
                  title="Reset batch and search filters"
                >
                  Clear filters
                </button>
              )}
            </div>
          </div>
        )}
        <div style={{ flex:1, overflow:"auto", padding:22 }}>
          {loading ? <Spinner/> : view === "requests" ? (
            <div>
              <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:18 }}>
                <div style={{ display:"flex", gap:8 }}>
                  {[
                    ["all", `All (${reqList.length})`],
                    ["pending", `Pending (${pendingRequests.length})`],
                    ["approved", `Approved (${reqList.filter(r => r.status === "approved").length})`],
                    ["rejected", `Rejected (${reqList.filter(r => r.status === "rejected").length})`],
                  ].map(([f, label]) => (
                    <button
                      key={f}
                      type="button"
                      onClick={() => setReqFilter(f)}
                      style={{
                        padding: "6px 14px",
                        borderRadius: 20,
                        fontSize: 12,
                        fontWeight: 600,
                        border: "var(--border-thin)",
                        background: reqFilter === f ? "var(--coral)" : "var(--paper-deep)",
                        color: reqFilter === f ? "white" : "var(--ink-soft)",
                        cursor: "pointer",
                      }}
                    >
                      {label}
                    </button>
                  ))}
                </div>
                <button
                  type="button"
                  onClick={async () => setRequests(await apiList("/schedule-requests"))}
                  className="btn btn-ghost"
                  style={{ fontSize: 12, padding: "5px 12px", border: "var(--border-thin)" }}
                >
                  ↻ Refresh
                </button>
              </div>

              {(() => {
                const filtered = reqList.filter(r => reqFilter === "all" || r.status === reqFilter);
                if (!filtered.length) {
                  return (
                    <div className="card-flat" style={{ padding: 36, textAlign: "center", color: "var(--ink-mute)" }}>
                      <div style={{ fontSize: 24, marginBottom: 8 }}>📋</div>
                      <div style={{ fontSize: 14, fontWeight: 600 }}>No {reqFilter !== "all" ? reqFilter : ""} session requests found</div>
                      <div style={{ fontSize: 12, marginTop: 4 }}>Teachers can submit session proposals from their My Schedule view.</div>
                    </div>
                  );
                }
                return (
                  <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                    {filtered.map(r => (
                      <div key={r.id} className="card-flat" style={{ padding: 18, borderLeft: `4px solid ${r.status === "approved" ? "var(--moss)" : r.status === "rejected" ? "var(--coral)" : "var(--gold)"}` }}>
                        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
                          <div style={{ flex: 1 }}>
                            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
                              <span style={{ fontWeight: 700, fontSize: 15 }}>
                                {r.day} · {r.time_start} – {r.time_end}
                              </span>
                              <span className="mono" style={{ fontSize: 11, color: "var(--ink-mute)" }}>({r.timezone || "Asia/Kolkata"})</span>
                              <span style={{
                                display: "inline-block",
                                padding: "2px 8px",
                                borderRadius: 12,
                                fontSize: 10,
                                fontWeight: 700,
                                textTransform: "uppercase",
                                letterSpacing: ".05em",
                                background: r.status === "approved" ? "rgba(46,125,50,0.15)" : r.status === "rejected" ? "rgba(211,47,47,0.15)" : "rgba(245,124,0,0.15)",
                                color: r.status === "approved" ? "var(--moss)" : r.status === "rejected" ? "var(--coral)" : "var(--gold)",
                              }}>
                                {r.status}
                              </span>
                            </div>
                            <div style={{ fontSize: 13, color: "var(--ink-soft)", marginBottom: 6 }}>
                              <strong>Teacher:</strong> {r.teacher_name || "Unknown"} · <strong>Target:</strong> {r.batch_name ? `Batch "${r.batch_name}"${r.batch_course_name ? ` (${r.batch_course_name})` : ""}` : r.student_name ? `1-on-1: ${r.student_name}${r.student_course_name ? ` (${r.student_course_name})` : ""}` : "Target deleted"}
                            </div>
                            <div style={{ fontSize: 13, background: "var(--paper-deep)", padding: "8px 12px", borderRadius: 8, marginTop: 6 }}>
                              <span className="mono" style={{ fontSize: 10, color: "var(--ink-mute)", textTransform: "uppercase", display: "block", marginBottom: 2 }}>Teacher Note / Reason</span>
                              {r.reason}
                            </div>
                            {r.admin_response && (
                              <div style={{ fontSize: 13, background: "var(--paper-deep)", padding: "8px 12px", borderRadius: 8, marginTop: 6, borderLeft: "3px solid var(--rule-bold)" }}>
                                <span className="mono" style={{ fontSize: 10, color: "var(--ink-mute)", textTransform: "uppercase", display: "block", marginBottom: 2 }}>Admin Note ({r.reviewer_name || "Admin"})</span>
                                {r.admin_response}
                              </div>
                            )}
                            {r.session_id && (
                              <div className="mono" style={{ fontSize: 11, color: "var(--moss)", marginTop: 6 }}>
                                ✓ Scheduled as Session #{r.session_id}
                              </div>
                            )}
                          </div>
                          {r.status === "pending" && (
                            <div style={{ display: "flex", gap: 8, flexShrink: 0 }}>
                              <button
                                type="button"
                                onClick={() => startApprove(r)}
                                className="btn btn-primary"
                                style={{ padding: "6px 14px", fontSize: 12, background: "var(--moss)" }}
                              >
                                Approve…
                              </button>
                              <button
                                type="button"
                                onClick={() => startReject(r)}
                                className="btn btn-ghost"
                                style={{ padding: "6px 12px", fontSize: 12, color: "var(--coral)", border: "1.5px solid var(--coral)" }}
                              >
                                Reject…
                              </button>
                            </div>
                          )}
                        </div>
                      </div>
                    ))}
                  </div>
                );
              })()}
            </div>
          ) : (() => {
            if (!list.length) {
              return (
                <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
                  <div style={{ fontSize:32, marginBottom:12 }}>📅</div>
                  <div style={{ fontSize:16, fontWeight:700 }}>No sessions yet</div>
                  <button onClick={() => { setForm(f => ({ ...f, day: anchorDate })); setShowAdd(true); }} className="btn btn-primary" style={{ marginTop:16 }}>
                    {I.plus({ size:14 })} Add first session
                  </button>
                </div>
              );
            }

            if (!filteredSessions.length) {
              const hasFilters = batchFilter !== "all" || debouncedSearch;
              return (
                <div className="card-flat" style={{ padding:40, textAlign:"center", color:"var(--ink-mute)", maxWidth:520, margin:"24px auto" }}>
                  <div style={{ fontSize:32, marginBottom:10 }}>📅</div>
                  <div className="display" style={{ fontSize:16, color:"var(--ink)", marginBottom:6 }}>
                    No sessions scheduled for {periodLabel}
                  </div>
                  <p style={{ fontSize:12.5, color:"var(--ink-soft)", margin:"0 0 16px 0", lineHeight:1.5 }}>
                    {hasFilters
                      ? `No sessions match ${batchFilter !== "all" ? `the selected batch filter` : ""}${batchFilter !== "all" && debouncedSearch ? " and " : ""}${debouncedSearch ? `search "${searchQuery}"` : ""} in this period.`
                      : `There are no sessions on the schedule for this ${view}.`}
                  </p>
                  <div style={{ display:"flex", gap:8, justifyContent:"center" }}>
                    {hasFilters && (
                      <button
                        type="button"
                        className="btn btn-ghost"
                        style={{ fontSize:12, padding:"6px 12px", border:"var(--border-thin)" }}
                        onClick={() => { setBatchFilter("all"); setSearchQuery(""); }}
                      >
                        Clear filters
                      </button>
                    )}
                    <button
                      type="button"
                      className="btn btn-primary"
                      style={{ fontSize:12, padding:"6px 14px" }}
                      onClick={() => {
                        setForm(f => ({ ...f, day: anchorDate }));
                        setShowAdd(true);
                      }}
                    >
                      {I.plus({ size:14 })} Schedule session
                    </button>
                  </div>
                </div>
              );
            }

            const sorted = [...filteredSessions].sort((a,b) => a.day < b.day ? -1 : a.day > b.day ? 1 : 0);
            const groups = [];
            sorted.forEach(s => {
              const last = groups[groups.length-1];
              if (last && last.day === s.day) last.sessions.push(s);
              else groups.push({ day: s.day, sessions: [s] });
            });
            const fmtDate = d => { try { const dt = new Date(d + "T00:00:00"); return dt.toLocaleDateString("en-GB",{weekday:"short",day:"numeric",month:"short"}).toUpperCase(); } catch { return d; } };
            return groups.map(g => (
              <div key={g.day} style={{ marginBottom:18 }}>
                <div className="mono" style={{ fontSize:11, color:"var(--ink-mute)", fontWeight:700, marginBottom:8, letterSpacing:".06em" }}>{fmtDate(g.day)}</div>
                <div style={{ display:"flex", flexDirection:"column", gap:8 }}>
                  {g.sessions.map(s => (
                    <div key={s.id} className="card-flat" style={{ padding:14, display:"grid", gridTemplateColumns:"120px 1fr 1fr auto auto auto auto auto auto", alignItems:"center", gap:14, borderLeft:`3px solid ${statusColor(s.status)}` }}>
                      <div>
                        <div style={{ fontWeight:700, fontSize:13 }}>{s.time} {s.tz ? tzAbbr(s.tz) : ""}</div>
                        <div style={{ fontSize:11, color:"var(--ink-mute)" }}>–{s.end}</div>
                        {s.tz && zonedMoment(s.day, s.time, s.tz) && localTzAbbr() !== tzAbbr(s.tz) && (
                          <div style={{ fontSize:10, color:"var(--sky)" }}>{fmtLocalTime(zonedMoment(s.day, s.time, s.tz))} your time</div>
                        )}
                        {s.rescheduled_from && (
                          <div style={{ fontSize:10, color:"var(--gold)", marginTop:3, fontWeight:600 }} title={s.reschedule_reason ? `Reason: ${s.reschedule_reason}` : ""}>
                            ↳ From {s.rescheduled_from}
                          </div>
                        )}
                      </div>
                      <div>
                        <div style={{ fontWeight:700, fontSize:13 }}>{s.batch}</div>
                        <div style={{ fontSize:11, color:"var(--ink-mute)" }}>{s.course}</div>
                      </div>
                      <div style={{ fontSize:12, color:"var(--ink-soft)" }}>
                        <div>{s.teacher}</div>
                        <div style={{ color:"var(--ink-mute)" }}>{s.session_type==="individual"?"1-on-1":s.students+" students"}</div>
                      </div>
                      <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: s.session_type==="individual"?"var(--plum-deep)":"var(--sky-deep)", color:"white" }}>{s.session_type==="individual"?"1-on-1":"batch"}</span>
                      <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: statusColor(s.status), color: s.status==="not_conducted"?"black":"white" }}>{s.status==="not_conducted"?"not conducted":s.status}</span>
                      {s.meet ? (
                        <a href={normalizeUrl(s.meet)} target="_blank" rel="noreferrer" className="btn btn-ghost" style={{ padding:"4px 10px", fontSize:11, textDecoration:"none", display:"flex", alignItems:"center", gap:4 }}>
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
                          Meet
                        </a>
                      ) : <span style={{ fontSize:11, color:"var(--ink-mute)", padding:"4px 10px" }}>No link</span>}
                      {/* Edit action */}
                      <button
                        type="button"
                        onClick={() => startEdit(s)}
                        className="btn btn-ghost"
                        style={{ padding:"4px 8px", fontSize:11, display:"flex", alignItems:"center", gap:4 }}
                        title="Edit session details"
                      >
                        {I.edit ? I.edit({ size:12 }) : "✏️"} Edit
                      </button>
                      {/* Not conducted / Remarks action */}
                      {s.status !== "done" && s.status !== "not_conducted" ? (
                        <button
                          type="button"
                          onClick={() => { setNcSession(s); setNcReason(""); setNcError(""); }}
                          className="btn btn-ghost"
                          style={{ padding:"4px 8px", fontSize:11, color:"var(--coral)" }}
                          title="Mark this session as not conducted"
                        >
                          Not conducted
                        </button>
                      ) : s.status === "done" && s.completion_remarks ? (
                        <button
                          type="button"
                          onClick={() => setViewRemarksSession(s)}
                          className="btn btn-ghost"
                          style={{ padding:"4px 8px", fontSize:11, display:"flex", alignItems:"center", gap:4 }}
                          title="View completion remarks"
                        >
                          {I.book ? I.book({ size:12 }) : "📝"} Remarks
                        </button>
                      ) : <div/>}
                      {/* Status control */}
                      <div style={{ display:"flex", gap:4 }}>
                        {s.status !== "done" && (
                          <button
                            disabled={statusChanging === s.id}
                            onClick={() => {
                              setDoneSession(s);
                              setDoneRemarks(s.completion_remarks || "");
                              setDoneError("");
                            }}
                            style={{ padding:"4px 10px", borderRadius:6, border:"1.5px solid var(--moss)", background:"transparent", color:"var(--moss)", cursor:"pointer", fontSize:11, fontWeight:600, opacity: statusChanging===s.id ? .5 : 1 }}
                          >
                            {statusChanging === s.id ? "…" : "✓ Complete"}
                          </button>
                        )}
                        {s.status === "done" && (
                          <button
                            disabled={statusChanging === s.id}
                            onClick={() => markStatus(s.id, "upcoming")}
                            style={{ padding:"4px 10px", borderRadius:6, border:"1.5px solid var(--rule-bold)", background:"transparent", color:"var(--ink-mute)", cursor:"pointer", fontSize:11, fontWeight:600 }}
                          >
                            Reopen
                          </button>
                        )}
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            ));
          })()}
        </div>
        {showAdd && (
          <Modal title="Add session" onClose={()=>setShowAdd(false)}>
            <form onSubmit={saveSession}>
              <div style={{ display:"flex", gap:8, marginBottom:16 }}>
                {[["batch","Batch class"],["individual","1-on-1 student"]].map(([t,l])=>(
                  <button key={t} type="button" onClick={()=>setSessType(t)} style={{ flex:1, padding:"8px 0", borderRadius:8, border:"var(--border-thin)", fontSize:12,
                    background: sessType===t?"var(--coral)":"var(--paper-deep)", color: sessType===t?"white":"var(--ink-soft)", cursor:"pointer", fontWeight:600 }}>{l}</button>
                ))}
              </div>
              {sessType === "batch" ? (
                <FormField label="BATCH">
                  <select required style={selectStyle} value={form.batch_id} onChange={e=>setForm(f=>({...f,batch_id:e.target.value}))}>
                    <option value="">— select batch —</option>
                    {BATCHES.map(b=><option key={b.id} value={b.id}>{b.name} ({b.course})</option>)}
                  </select>
                </FormField>
              ) : (
                <FormField label="STUDENT">
                  <select required style={selectStyle} value={form.student_id} onChange={e=>setForm(f=>({...f,student_id:e.target.value}))}>
                    <option value="">— select student —</option>
                    {STUDENTS.map(s=><option key={s.id} value={s.id}>{s.name} · {s.course||s.batch}</option>)}
                  </select>
                </FormField>
              )}
              <FormField label="TEACHER">
                <select style={selectStyle} value={form.teacher_id} onChange={e=>setForm(f=>({...f,teacher_id:e.target.value}))}>
                  <option value="">— no teacher —</option>
                  {TEACHERS.map(t=><option key={t.id} value={t.id}>{t.name}</option>)}
                </select>
              </FormField>
              <FormField label={repeat ? "START DATE" : "DATE"}>
                <input type="date" required style={inputStyle} value={form.day} onChange={e=>setForm(f=>({...f,day:e.target.value}))}/>
              </FormField>
              <label style={{ display:"flex", alignItems:"center", gap:8, margin:"2px 0 12px", cursor:"pointer", fontSize:13, color:"var(--ink-soft)" }}>
                <input type="checkbox" checked={repeat} onChange={e=>{
                  const on = e.target.checked; setRepeat(on);
                  if (on && !weekdays.length && form.day) { const wd = new Date(form.day+"T00:00:00Z").getUTCDay(); if (!isNaN(wd)) setWeekdays([wd]); }
                }}/>
                Repeat weekly — create multiple sessions at once
              </label>
              {repeat && (
                <div style={{ border:"var(--border-thin)", borderRadius:8, padding:12, marginBottom:12, background:"var(--paper-deep)", display:"flex", flexDirection:"column", gap:12 }}>
                  <div>
                    <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:6, fontFamily:"var(--font-mono)" }}>REPEAT ON</div>
                    <div style={{ display:"flex", gap:6 }}>
                      {WEEKDAY_LABELS.map(([full,short],idx)=>{
                        const on = weekdays.includes(idx);
                        return <button key={idx} type="button" title={full} onClick={()=>setWeekdays(w=> on ? w.filter(x=>x!==idx) : [...w, idx].sort((a,b)=>a-b))}
                          style={{ width:34, height:34, borderRadius:"50%", border:"var(--border-thin)", cursor:"pointer", fontWeight:700, fontSize:12,
                            background: on?"var(--coral)":"var(--paper-card)", color: on?"white":"var(--ink-soft)" }}>{short}</button>;
                      })}
                    </div>
                  </div>
                  <div>
                    <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:6, fontFamily:"var(--font-mono)" }}>ENDS</div>
                    <div style={{ display:"flex", gap:14, alignItems:"center", flexWrap:"wrap" }}>
                      <label style={{ display:"flex", alignItems:"center", gap:6, fontSize:13, cursor:"pointer" }}>
                        <input type="radio" name="endmode" checked={endMode==="count"} onChange={()=>setEndMode("count")}/> After
                        <input type="number" min="1" max="200" value={count} onChange={e=>setCount(e.target.value)} disabled={endMode!=="count"}
                          style={{ width:60, padding:"4px 8px", border:"var(--border-thin)", borderRadius:6, background:"var(--paper-card)", color:"var(--ink)", fontSize:13 }}/> sessions
                      </label>
                      <label style={{ display:"flex", alignItems:"center", gap:6, fontSize:13, cursor:"pointer" }}>
                        <input type="radio" name="endmode" checked={endMode==="until"} onChange={()=>setEndMode("until")}/> Until
                        <input type="date" value={until} onChange={e=>setUntil(e.target.value)} disabled={endMode!=="until"}
                          style={{ padding:"4px 8px", border:"var(--border-thin)", borderRadius:6, background:"var(--paper-card)", color:"var(--ink)", fontSize:13 }}/>
                      </label>
                    </div>
                  </div>
                  <div style={{ fontSize:12, color: recurDates.length ? "var(--moss)" : "var(--gold)", fontWeight:600 }}>
                    {recurDates.length
                      ? `Will create ${recurDates.length} session${recurDates.length===1?"":"s"} · ${recurDates[0]} → ${recurDates[recurDates.length-1]}`
                      : "Pick a start date and at least one weekday."}
                  </div>
                </div>
              )}
              <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
                <FormField label="START TIME">
                  <input type="time" required style={inputStyle} value={form.time_start} onChange={e=>setForm(f=>({...f,time_start:e.target.value}))}/>
                </FormField>
                <FormField label="END TIME">
                  <input type="time" required style={inputStyle} value={form.time_end} onChange={e=>setForm(f=>({...f,time_end:e.target.value}))}/>
                </FormField>
              </div>
              <FormField label="TIMEZONE (TIMES ARE IN THIS ZONE)">
                <TimezoneSelect
                  id="add-session-tz"
                  value={form.timezone || "Asia/Kolkata"}
                  onChange={e => setForm(f => ({ ...f, timezone: e.target.value }))}
                />
              </FormField>
              <FormField label="GOOGLE MEET LINK">
                <input style={inputStyle} value={form.meet_link} onChange={e=>setForm(f=>({...f,meet_link:e.target.value}))} placeholder="https://meet.google.com/xxx-xxxx-xxx"/>
              </FormField>
              {(!teacherList.length || (sessType === "batch" && !batchList.length)) && (
                <div style={{ color:"var(--gold)", fontSize:12, background:"var(--paper-deep)", border:"var(--border-thin)", borderRadius:8, padding:"8px 12px" }}>
                  {!teacherList.length ? "⚠ No teachers exist yet — add a teacher before scheduling." : "⚠ No batches exist yet — create a batch first."}
                </div>
              )}
              {error && <div style={{ color:"var(--coral)", fontSize:13, margin:"4px 0" }}>{error}</div>}
              <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:16 }}>
                <button type="button" onClick={()=>{ setShowAdd(false); setError(""); }} className="btn btn-ghost">Cancel</button>
                <button type="submit" disabled={saving} className="btn btn-primary">{saving ? "Saving…" : repeat ? `Create ${recurDates.length||""} session${recurDates.length===1?"":"s"}`.replace("  "," ") : "Save session"}</button>
              </div>
            </form>
          </Modal>
        )}
        {editingSession && (
          <Modal title="Edit session" onClose={() => { setEditingSession(null); setEditError(""); }}>
            <form onSubmit={saveEdit}>
              {editingSession.has_attendance && (
                <div style={{ background: "var(--paper-deep)", border: "1.5px solid var(--gold)", borderRadius: 8, padding: "8px 12px", marginBottom: 14, fontSize: 12, color: "var(--gold)" }}>
                  🔒 Attendance has already been taken for this session. The date, batch, and student are locked to protect attendance records, but you can still update the time, teacher, timezone, and Meet link.
                </div>
              )}
              <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
                {[["batch", "Batch class"], ["individual", "1-on-1 student"]].map(([t, l]) => (
                  <button
                    key={t}
                    type="button"
                    disabled={editingSession.has_attendance}
                    onClick={() => setEditSessType(t)}
                    style={{
                      flex: 1, padding: "8px 0", borderRadius: 8, border: "var(--border-thin)", fontSize: 12,
                      background: editSessType === t ? "var(--coral)" : "var(--paper-deep)",
                      color: editSessType === t ? "white" : "var(--ink-soft)",
                      cursor: editingSession.has_attendance ? "not-allowed" : "pointer",
                      opacity: editingSession.has_attendance && editSessType !== t ? 0.5 : 1,
                      fontWeight: 600
                    }}
                  >
                    {l}
                  </button>
                ))}
              </div>

              {editSessType === "batch" ? (
                <FormField label="BATCH">
                  <select
                    required
                    disabled={editingSession.has_attendance}
                    style={{ ...selectStyle, opacity: editingSession.has_attendance ? 0.6 : 1, cursor: editingSession.has_attendance ? "not-allowed" : "pointer" }}
                    value={editForm.batch_id}
                    onChange={e => setEditForm(f => ({ ...f, batch_id: e.target.value }))}
                  >
                    <option value="">— select batch —</option>
                    {BATCHES.map(b => <option key={b.id} value={b.id}>{b.name} ({b.course})</option>)}
                  </select>
                </FormField>
              ) : (
                <FormField label="STUDENT">
                  <select
                    required
                    disabled={editingSession.has_attendance}
                    style={{ ...selectStyle, opacity: editingSession.has_attendance ? 0.6 : 1, cursor: editingSession.has_attendance ? "not-allowed" : "pointer" }}
                    value={editForm.student_id}
                    onChange={e => setEditForm(f => ({ ...f, student_id: e.target.value }))}
                  >
                    <option value="">— select student —</option>
                    {STUDENTS.map(s => <option key={s.id} value={s.id}>{s.name} · {s.course || s.batch}</option>)}
                  </select>
                </FormField>
              )}

              <FormField label="TEACHER">
                <select style={selectStyle} value={editForm.teacher_id} onChange={e => setEditForm(f => ({ ...f, teacher_id: e.target.value }))}>
                  <option value="">— select teacher —</option>
                  {TEACHERS.map(t => <option key={t.id} value={t.id}>{t.name}</option>)}
                </select>
              </FormField>

              <FormField label="DATE">
                <input
                  type="date"
                  required
                  disabled={editingSession.has_attendance}
                  style={{ ...inputStyle, opacity: editingSession.has_attendance ? 0.6 : 1, cursor: editingSession.has_attendance ? "not-allowed" : "text" }}
                  value={editForm.day}
                  onChange={e => setEditForm(f => ({ ...f, day: e.target.value }))}
                />
              </FormField>

              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
                <FormField label="START TIME">
                  <input type="time" required style={inputStyle} value={editForm.time_start} onChange={e => setEditForm(f => ({ ...f, time_start: e.target.value }))}/>
                </FormField>
                <FormField label="END TIME">
                  <input type="time" required style={inputStyle} value={editForm.time_end} onChange={e => setEditForm(f => ({ ...f, time_end: e.target.value }))}/>
                </FormField>
              </div>

              <FormField label="TIMEZONE (TIMES ARE IN THIS ZONE)">
                <TimezoneSelect
                  id="edit-session-tz"
                  value={editForm.timezone || "Asia/Kolkata"}
                  onChange={e => setEditForm(f => ({ ...f, timezone: e.target.value }))}
                />
              </FormField>

              <FormField label="GOOGLE MEET LINK">
                <input style={inputStyle} value={editForm.meet_link} onChange={e => setEditForm(f => ({ ...f, meet_link: e.target.value }))} placeholder="https://meet.google.com/xxx-xxxx-xxx"/>
              </FormField>

              {editError && <div style={{ color: "var(--coral)", fontSize: 13, margin: "4px 0" }}>{editError}</div>}

              <div style={{ display: "flex", gap: 10, justifyContent: "space-between", alignItems: "center", marginTop: 16 }}>
                <button type="button" onClick={deleteFromEdit} disabled={editSaving} className="btn btn-ghost" style={{ color: "var(--coral)", fontSize: 12 }}>
                  Delete session
                </button>
                <div style={{ display: "flex", gap: 10 }}>
                  <button type="button" onClick={() => { setEditingSession(null); setEditError(""); }} className="btn btn-ghost">Cancel</button>
                  <button type="submit" disabled={editSaving} className="btn btn-primary">{editSaving ? "Saving…" : "Save changes"}</button>
                </div>
              </div>
            </form>
          </Modal>
        )}
        {ncSession && (
          <Modal title="Mark session not conducted" onClose={() => { setNcSession(null); setNcError(""); }}>
            <form onSubmit={submitNotConducted}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, marginBottom: 4 }}>
                  {ncSession.batch || "Class"} · {ncSession.day} ({ncSession.time})
                </div>
                {ncSession.series_id ? (
                  <div style={{ color: "var(--ink-soft)", fontSize: 12, lineHeight: 1.5 }}>
                    This session is part of a recurring series. Marking it not conducted will shift this session forward by 1 interval to serve as the make-up class, along with all subsequent sessions in the series. <strong>Total session count will remain constant.</strong>
                  </div>
                ) : (
                  <div style={{ color: "var(--ink-soft)", fontSize: 12, lineHeight: 1.5 }}>
                    This is a single standalone session (not part of a recurring series). It will be marked as not conducted without shifting any other sessions.
                  </div>
                )}
              </div>

              <FormField label="REASON (OPTIONAL)">
                <input
                  style={inputStyle}
                  value={ncReason}
                  onChange={e => setNcReason(e.target.value)}
                  placeholder="e.g. Teacher unwell, holiday, technical outage"
                  autoFocus
                />
              </FormField>

              {ncError && <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>{ncError}</div>}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 16 }}>
                <button type="button" onClick={() => { setNcSession(null); setNcError(""); }} className="btn btn-ghost">
                  Cancel
                </button>
                <button type="submit" disabled={ncSaving} className="btn btn-primary" style={{ background: "var(--coral)" }}>
                  {ncSaving ? "Updating…" : ncSession.series_id ? "Reschedule series" : "Mark not conducted"}
                </button>
              </div>
            </form>
          </Modal>
        )}
        {doneSession && (
          <Modal title="Complete session" onClose={() => { setDoneSession(null); setDoneError(""); }}>
            <form onSubmit={submitCompleteSession}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, marginBottom: 4 }}>
                  {doneSession.batch || "Class"} · {doneSession.day} ({doneSession.time})
                </div>
                <div style={{ color: "var(--ink-soft)", fontSize: 12, lineHeight: 1.5 }}>
                  Please provide session completion remarks or a summary of topics covered before marking this session as done.
                </div>
              </div>

              <FormField label="COMPLETION REMARKS *">
                <textarea
                  required
                  rows={4}
                  style={{ width: "100%", padding: "8px 12px", border: "var(--border-thin)", borderRadius: 6, background: "var(--paper-card)", color: "var(--ink)", fontSize: 13, resize: "vertical", boxSizing: "border-box" }}
                  value={doneRemarks}
                  onChange={e => setDoneRemarks(e.target.value)}
                  placeholder="e.g. Completed Chapter 4 exercises, introduced loops. Students completed mini-project."
                  autoFocus
                />
              </FormField>

              {doneError && <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>{doneError}</div>}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 16 }}>
                <button type="button" onClick={() => { setDoneSession(null); setDoneError(""); }} className="btn btn-ghost">
                  Cancel
                </button>
                <button type="submit" disabled={doneSaving || !doneRemarks.trim()} className="btn btn-primary" style={{ background: "var(--moss)" }}>
                  {doneSaving ? "Saving…" : "Mark as done"}
                </button>
              </div>
            </form>
          </Modal>
        )}
        {viewRemarksSession && (
          <Modal title="Session completion remarks" onClose={() => setViewRemarksSession(null)}>
            <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 14, fontSize: 13 }}>
              <div style={{ fontWeight: 700, marginBottom: 4 }}>
                {viewRemarksSession.batch || "Class"} · {viewRemarksSession.day} ({viewRemarksSession.time})
              </div>
              <div style={{ color: "var(--ink-soft)", fontSize: 12, lineHeight: 1.5 }}>
                {viewRemarksSession.course} · {viewRemarksSession.teacher} {viewRemarksSession.session_type === "individual" ? "(1-on-1)" : `(${viewRemarksSession.students || 0} students)`}
              </div>
            </div>

            <FormField label="COMPLETION REMARKS">
              <div style={{
                width: "100%",
                minHeight: 80,
                padding: "10px 12px",
                border: "var(--border-thin)",
                borderRadius: 6,
                background: "var(--paper-card)",
                color: "var(--ink)",
                fontSize: 13,
                lineHeight: 1.5,
                whiteSpace: "pre-wrap",
                wordBreak: "break-word",
                boxSizing: "border-box",
              }}>
                {viewRemarksSession.completion_remarks}
              </div>
            </FormField>

            <div style={{ display: "flex", justifyContent: "flex-end", marginTop: 16 }}>
              <button type="button" onClick={() => setViewRemarksSession(null)} className="btn btn-ghost">
                Close
              </button>
            </div>
          </Modal>
        )}
        {approvingReq && (
          <Modal title="Approve Session Request" onClose={() => { setApprovingReq(null); setAppConflict(null); setAppError(""); }}>
            <form onSubmit={e => submitApprove(e, false)}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, marginBottom: 4 }}>
                  {approvingReq.batch_name ? `Batch: ${approvingReq.batch_name}` : approvingReq.student_name ? `1-on-1: ${approvingReq.student_name}` : "Session"} · Proposed: {approvingReq.day} ({approvingReq.time_start} – {approvingReq.time_end})
                </div>
                <div style={{ color: "var(--ink-soft)", fontSize: 12 }}>
                  <strong>Requested by:</strong> {approvingReq.teacher_name} <br/>
                  <strong>Reason:</strong> {approvingReq.reason}
                </div>
              </div>

              <FormField label="DATE">
                <input
                  type="date"
                  required
                  style={inputStyle}
                  value={appForm.day}
                  onChange={e => setAppForm(f => ({ ...f, day: e.target.value }))}
                />
              </FormField>

              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
                <FormField label="START TIME">
                  <input
                    type="time"
                    required
                    style={inputStyle}
                    value={appForm.time_start}
                    onChange={e => setAppForm(f => ({ ...f, time_start: e.target.value }))}
                  />
                </FormField>
                <FormField label="END TIME">
                  <input
                    type="time"
                    required
                    style={inputStyle}
                    value={appForm.time_end}
                    onChange={e => setAppForm(f => ({ ...f, time_end: e.target.value }))}
                  />
                </FormField>
              </div>

              <FormField label="ASSIGN TEACHER">
                <select
                  required
                  style={selectStyle}
                  value={appForm.teacher_id}
                  onChange={e => setAppForm(f => ({ ...f, teacher_id: e.target.value }))}
                >
                  <option value="">— select teacher —</option>
                  {teacherList.map(t => <option key={t.id} value={t.id}>{t.name}</option>)}
                </select>
              </FormField>

              <FormField label="GOOGLE MEET LINK (OPTIONAL)">
                <input
                  style={inputStyle}
                  value={appForm.meet_link}
                  onChange={e => setAppForm(f => ({ ...f, meet_link: e.target.value }))}
                  placeholder="https://meet.google.com/xxx-xxxx-xxx"
                />
              </FormField>

              <FormField label="ADMIN RESPONSE NOTE (OPTIONAL)">
                <input
                  style={inputStyle}
                  value={appForm.admin_response}
                  onChange={e => setAppForm(f => ({ ...f, admin_response: e.target.value }))}
                  placeholder="Visible to teacher upon approval"
                />
              </FormField>

              {appConflict && (
                <div style={{ background: "rgba(245,124,0,0.1)", border: "1.5px solid var(--gold)", borderRadius: 8, padding: "10px 14px", margin: "12px 0" }}>
                  <div style={{ color: "var(--gold)", fontWeight: 700, fontSize: 13, marginBottom: 4 }}>
                    ⚠️ Scheduling Conflict Detected
                  </div>
                  <div style={{ color: "var(--ink-soft)", fontSize: 12, marginBottom: 10 }}>
                    {appConflict}
                  </div>
                  <button
                    type="button"
                    disabled={appSaving}
                    onClick={() => submitApprove(null, true)}
                    className="btn btn-primary"
                    style={{ background: "var(--gold)", color: "black", width: "100%", fontSize: 12 }}
                  >
                    {appSaving ? "Approving…" : "Override & Schedule Anyway"}
                  </button>
                </div>
              )}

              {appError && <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>{appError}</div>}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 16 }}>
                <button
                  type="button"
                  onClick={() => { setApprovingReq(null); setAppConflict(null); setAppError(""); }}
                  className="btn btn-ghost"
                >
                  Cancel
                </button>
                <button
                  type="submit"
                  disabled={appSaving}
                  className="btn btn-primary"
                  style={{ background: "var(--moss)" }}
                >
                  {appSaving ? "Approving…" : "Approve & Schedule"}
                </button>
              </div>
            </form>
          </Modal>
        )}
        {rejectingReq && (
          <Modal title="Reject Session Request" onClose={() => { setRejectingReq(null); setRejError(""); }}>
            <form onSubmit={submitReject}>
              <div style={{ background: "var(--paper-deep)", border: "var(--border-thin)", borderRadius: 8, padding: 12, marginBottom: 14, fontSize: 13 }}>
                <div style={{ fontWeight: 700, marginBottom: 4 }}>
                  {rejectingReq.batch_name ? `Batch: ${rejectingReq.batch_name}` : rejectingReq.student_name ? `1-on-1: ${rejectingReq.student_name}` : "Session"} · {rejectingReq.day} ({rejectingReq.time_start} – {rejectingReq.time_end})
                </div>
                <div style={{ color: "var(--ink-soft)", fontSize: 12 }}>
                  <strong>Requested by:</strong> {rejectingReq.teacher_name} <br/>
                  <strong>Reason:</strong> {rejectingReq.reason}
                </div>
              </div>

              <FormField label="REASON FOR REJECTION (OPTIONAL)">
                <textarea
                  style={{ ...inputStyle, minHeight: 80, resize: "vertical" }}
                  value={rejReason}
                  onChange={e => setRejReason(e.target.value)}
                  placeholder="Explain why this request cannot be accommodated (visible to teacher)"
                  autoFocus
                />
              </FormField>

              {rejError && <div style={{ color: "var(--coral)", fontSize: 13, margin: "8px 0" }}>{rejError}</div>}

              <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 16 }}>
                <button
                  type="button"
                  onClick={() => { setRejectingReq(null); setRejError(""); }}
                  className="btn btn-ghost"
                >
                  Cancel
                </button>
                <button
                  type="submit"
                  disabled={rejSaving}
                  className="btn btn-primary"
                  style={{ background: "var(--coral)" }}
                >
                  {rejSaving ? "Rejecting…" : "Reject Request"}
                </button>
              </div>
            </form>
          </Modal>
        )}
      </div>
    </Themed>
  );
};

// ── Admin: Attendance / Session Reports ───────────────────────────────────────
const AdminAttendance = ({ dark = true, go }) => {
  const { data: ATTENDANCE_DATA, loading } = useApi("/attendance");
  const [expand, setExpand] = React.useState(null);
  const avg = ATTENDANCE_DATA.length
    ? Math.round(ATTENDANCE_DATA.reduce((a,r) => a + parseInt(r.rate), 0) / ATTENDANCE_DATA.length)
    : 0;
  const perfect = ATTENDANCE_DATA.filter(r => parseInt(r.rate) === 100).length;
  const needFollowUp = ATTENDANCE_DATA.filter(r => parseInt(r.rate) < 75).length;
  if (loading) return <Spinner />;
  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/attendance" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Session Reports</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>{ATTENDANCE_DATA.length} sessions recorded</div>
          </div>
          <div style={{ flex:1 }}/>
          <button className="btn btn-ghost" style={{ padding:"6px 12px", fontSize:12 }}>{I.upload({ size:14 })} Export CSV</button>
        </div>
        <div style={{ padding:22, overflow:"auto", flex:1 }}>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:14, marginBottom:22 }}>
            {[
              { label:"AVG ATTENDANCE", value: ATTENDANCE_DATA.length ? `${avg}%` : "—", color: avg >= 90 ? "var(--moss)" : avg >= 75 ? "var(--gold)" : "var(--coral)" },
              { label:"TOTAL SESSIONS",  value: ATTENDANCE_DATA.length, color:"var(--sky)" },
              { label:"PERFECT SESSIONS", value: perfect, color:"var(--moss)" },
              { label:"FOLLOW-UPS NEEDED", value: needFollowUp, color: needFollowUp > 0 ? "var(--coral)" : "var(--moss)" },
            ].map(k => (
              <div key={k.label} className="card-flat" style={{ padding:14 }}>
                <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", letterSpacing:".06em" }}>{k.label}</div>
                <div className="display" style={{ fontSize:28, marginTop:4, color:k.color }}>{k.value}</div>
              </div>
            ))}
          </div>
          {ATTENDANCE_DATA.length === 0 ? (
            <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
              <div style={{ fontSize:32, marginBottom:12 }}>📋</div>
              <div style={{ fontSize:16, fontWeight:700 }}>No attendance records yet</div>
              <div style={{ fontSize:13, marginTop:4 }}>Attendance is recorded when teachers mark sessions</div>
            </div>
          ) : (
            <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
              <thead>
                <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                  {["Date","Batch · Course","Teacher","Present","Rate","Notes"].map(h => (
                    <th key={h} style={{ padding:"8px 12px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {ATTENDANCE_DATA.map((r,i) => (
                  <tr key={i} style={{ borderTop: i ? "var(--border-thin)" : "none" }}>
                    <td style={{ padding:"12px" }}><span className="mono" style={{ fontSize:12 }}>{r.date}</span></td>
                    <td style={{ padding:"12px", fontWeight:700 }}>{r.batch}</td>
                    <td style={{ padding:"12px", color:"var(--ink-soft)" }}>{r.teacher}</td>
                    <td style={{ padding:"12px" }}>{r.present}/{r.total}</td>
                    <td style={{ padding:"12px", fontWeight:700, color: parseInt(r.rate)<75?"var(--coral)":parseInt(r.rate)===100?"var(--moss)":"var(--ink)" }}>{r.rate}</td>
                    <td style={{ padding:"12px", fontSize:12, color:"var(--ink-mute)" }}>{r.notes || "—"}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Accounts & Invoice ─────────────────────────────────────────────────
const AdminBilling = ({ dark = true, go }) => {
  const { data: INVOICES, loading } = useApi("/invoices");
  const { data: STATS } = useApi("/billing/stats", {});
  const inv = STATS.invoices || {};
  const overdue = INVOICES.filter(i=>i.status==="overdue");
  const plural = (n, word) => `${n ?? 0} ${word}${n === 1 ? "" : "s"}`;
  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/billing" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>Accounts & Invoices</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>{INVOICES.length} invoices · {overdue.length} overdue</div>
          </div>
          <div style={{ flex:1 }}/>
          <button onClick={() => go && go("/app/admin/payments")} className="btn btn-ghost" style={{ padding:"6px 12px", fontSize:12 }}>{I.coin({ size:14 })} Payment gateway</button>
          <button className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} New invoice</button>
        </div>
        <div style={{ flex:1, overflow:"auto", padding:22 }}>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:14, marginBottom:22 }}>
            {[
              // MRR is deliberately not here: nothing in this schema records a
              // billing period per student, so any "monthly recurring" figure
              // would be a guess dressed up as a number.
              { label:"BILLED", value:fmtMoney(inv.billed), delta:plural(inv.count, "invoice") },
              { label:"COLLECTED", value:fmtMoney(inv.collected), delta:plural(inv.paid_count, "invoice") + " paid" },
              { label:"PENDING", value:fmtMoney(inv.pending), delta:plural(inv.pending_count, "invoice") },
              { label:"OVERDUE", value:fmtMoney(inv.overdue), delta:plural(inv.overdue_count, "invoice") },
            ].map(k => (
              <div key={k.label} className="card-flat" style={{ padding:14 }}>
                <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", letterSpacing:".06em" }}>{k.label}</div>
                <div className="display" style={{ fontSize:26, marginTop:4 }}>{k.value}</div>
                <div style={{ fontSize:11, color:"var(--ink-mute)", marginTop:2 }}>{k.delta}</div>
              </div>
            ))}
          </div>
          {overdue.length > 0 && (
            <div className="card-flat" style={{ padding:14, marginBottom:16, borderLeft:"3px solid var(--coral)" }}>
              <div style={{ display:"flex", alignItems:"center", gap:8, marginBottom:8 }}>
                {I.bell({ size:14 })}
                <span style={{ fontWeight:700, fontSize:13 }}>Overdue invoices — send reminders</span>
              </div>
              <div style={{ display:"flex", gap:8 }}>
                {overdue.map(inv => (
                  <span key={inv.id} className="chip flat" style={{ fontSize:11 }}>{inv.student} · {fmtMoney(inv.amount)}</span>
                ))}
                <button className="btn btn-primary" style={{ padding:"4px 12px", fontSize:11, marginLeft:"auto" }}>{I.send({ size:12 })} Send reminders</button>
              </div>
            </div>
          )}
          <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
            <thead>
              <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                {["Invoice","Student","Plan","Amount","Issued","Due","Status",""].map(h => (
                  <th key={h} style={{ padding:"8px 12px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {INVOICES.map((inv,i) => (
                <tr key={inv.id} style={{ borderTop: i ? "var(--border-thin)" : "none" }}>
                  <td style={{ padding:"12px" }}><span className="mono" style={{ fontSize:12 }}>{inv.id}</span></td>
                  <td style={{ padding:"12px", fontWeight:700 }}>{inv.student}</td>
                  <td style={{ padding:"12px", color:"var(--ink-soft)" }}>{inv.plan}</td>
                  <td style={{ padding:"12px", fontWeight:700 }}>{fmtMoney(inv.amount)}</td>
                  <td style={{ padding:"12px" }}><span className="mono" style={{ fontSize:11, color:"var(--ink-mute)" }}>{inv.date}</span></td>
                  <td style={{ padding:"12px" }}><span className="mono" style={{ fontSize:11, color: inv.status==="overdue"?"var(--coral)":"var(--ink-mute)" }}>{inv.due}</span></td>
                  <td style={{ padding:"12px" }}>
                    <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: inv.status==="paid"?"var(--moss)":inv.status==="overdue"?"var(--coral)":"var(--gold)", color:"white" }}>
                      {inv.status}
                    </span>
                  </td>
                  <td style={{ padding:"12px", display:"flex", gap:6 }}>
                    <button className="btn btn-ghost" style={{ padding:"2px 8px", fontSize:11 }}>View</button>
                    {inv.status !== "paid" && <button className="btn btn-ghost" style={{ padding:"2px 8px", fontSize:11, color:"var(--moss)" }}>Mark paid</button>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </Themed>
  );
};

// ── Admin: Payment Gateway ────────────────────────────────────────────────────
const AdminPayments = ({ dark = true, go }) => {
  const { data: TRANSACTIONS } = useApi("/transactions");
  const { data: STATS } = useApi("/billing/stats", {});
  const txn = STATS.transactions || {};
  const methods = STATS.methods || [];
  // Fixed colours in the old mock; keep the palette but assign by rank so the
  // biggest method always reads as the primary one whatever it happens to be.
  const METHOD_COLORS = ["var(--coral)", "var(--sky)", "var(--moss)", "var(--gold)", "var(--plum)"];
  return (
  <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
    <AdminSidebar active="/app/admin/payments" go={go}/>
    <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
      <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
        <div>
          <div className="display" style={{ fontSize:20 }}>Payment Gateway</div>
          <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>Razorpay integration · live mode</div>
        </div>
        <div style={{ flex:1 }}/>
        <div style={{ display:"flex", alignItems:"center", gap:6, padding:"4px 12px", background:"var(--moss)", borderRadius:999 }}>
          <div style={{ width:6, height:6, borderRadius:"50%", background:"white" }}/>
          <span style={{ color:"white", fontSize:11, fontWeight:700 }}>Razorpay live</span>
        </div>
        <button className="btn btn-ghost" onClick={() => go && go("/app/admin/billing")} style={{ padding:"6px 12px", fontSize:12 }}>View invoices</button>
      </div>
      <div style={{ flex:1, overflow:"auto", padding:22 }}>
        <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:14, marginBottom:22 }}>
          {[
            { label:"COLLECTED TODAY", value:fmtMoney(txn.collected_today), color:"var(--moss)" },
            // "—" rather than 0% when nothing has been attempted yet.
            { label:"SUCCESS RATE", value:txn.success_rate == null ? "—" : `${txn.success_rate}%`, color:"var(--moss)" },
            { label:"PENDING", value:fmtMoney(txn.pending), color:"var(--gold)" },
            { label:"FAILED (RETRY)", value:fmtMoney(txn.failed), color:"var(--coral)" },
          ].map(k => (
            <div key={k.label} className="card-flat" style={{ padding:14 }}>
              <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", letterSpacing:".06em" }}>{k.label}</div>
              <div className="display" style={{ fontSize:26, marginTop:4, color:k.color }}>{k.value}</div>
            </div>
          ))}
        </div>
        <div className="card-flat" style={{ padding:18, marginBottom:18 }}>
          <SectionHead eyebrow="PAYMENT METHODS" title="Acceptance breakdown"/>
          <div style={{ display:"flex", gap:14 }}>
            {methods.length === 0 ? (
              <div style={{ fontSize:13, color:"var(--ink-mute)", padding:"6px 2px" }}>No settled payments yet.</div>
            ) : methods.map((m, idx) => {
              const c = METHOD_COLORS[idx % METHOD_COLORS.length];
              return (
                <div key={m.method} style={{ flex:1, padding:12, background:"var(--paper-deep)", borderRadius:10, border:"var(--border-thin)" }}>
                  <div style={{ fontWeight:700, fontSize:14 }}>{m.method}</div>
                  <div className="display" style={{ fontSize:28, color:c, marginTop:4 }}>{m.share}%</div>
                  <div className="progress" style={{ marginTop:8, height:6 }}><i style={{ width:`${m.share}%`, background:c }}/></div>
                  <div style={{ fontSize:11, color:"var(--ink-mute)", marginTop:6 }}>{fmtMoney(m.total)} · {m.count} txn{m.count === 1 ? "" : "s"}</div>
                </div>
              );
            })}
          </div>
        </div>
        <div className="card-flat" style={{ padding:18 }}>
          <SectionHead eyebrow="TRANSACTIONS" title="Recent payments"/>
          <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
            <thead>
              <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                {["Txn ID","Student","Amount","Method","Time","Status",""].map(h => (
                  <th key={h} style={{ padding:"8px 10px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {TRANSACTIONS.map((t,i) => (
                <tr key={t.id} style={{ borderTop: i ? "var(--border-thin)":"none" }}>
                  <td style={{ padding:"10px" }}><span className="mono" style={{ fontSize:11 }}>{t.id}</span></td>
                  <td style={{ padding:"10px", fontWeight:700 }}>{t.student}</td>
                  <td style={{ padding:"10px", fontWeight:700 }}>{fmtMoney(t.amount)}</td>
                  <td style={{ padding:"10px", color:"var(--ink-soft)" }}>{t.method}</td>
                  <td style={{ padding:"10px" }}><span className="mono" style={{ fontSize:11, color:"var(--ink-mute)" }}>{t.time}</span></td>
                  <td style={{ padding:"10px" }}>
                    <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: t.status==="success"?"var(--moss)":t.status==="pending"?"var(--gold)":"var(--coral)", color:"white" }}>
                      {t.status}
                    </span>
                  </td>
                  <td style={{ padding:"10px" }}>
                    {t.status === "failed" && <button className="btn btn-ghost" style={{ padding:"2px 8px", fontSize:11, color:"var(--coral)" }}>Retry</button>}
                    {t.status !== "failed" && <button className="btn btn-ghost" style={{ padding:"2px 8px", fontSize:11 }}>Receipt</button>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </Themed>
  );
};

// ── Admin: Kit Delivery Tracking ──────────────────────────────────────────────
const AdminKits = ({ dark = true, go }) => {
  const { data: initKits } = useApi("/kits");
  const { data: STUDENTS }  = useApi("/students");
  const [kits, setKits]     = React.useState(null);
  const [statusFilter, setStatusFilter] = React.useState("all");
  const [showAdd, setShowAdd] = React.useState(false);
  const [form, setForm]       = React.useState({ student_id:"", contents:"", tracking:"" });
  const [saving, setSaving]   = React.useState(false);
  const [error, setError]     = React.useState("");
  const list = kits ?? initKits ?? [];

  const refresh = () => apiFetch("/kits").then(r=>r.json()).then(setKits);

  const filteredList = list.filter(k => {
    if (statusFilter === "all") return true;
    return k.status === statusFilter;
  });

  const dispatch = async e => {
    e.preventDefault(); setError(""); setSaving(true);
    const res = await apiFetch("/kits", { method:"POST", body: JSON.stringify(form) });
    const data = await res.json();
    if (!res.ok) { setError(data.error||"Failed"); setSaving(false); return; }
    await refresh(); setForm({ student_id:"", contents:"", tracking:"" }); setShowAdd(false); setSaving(false);
  };

  const updateStatus = async (id, status) => {
    await apiFetch(`/kits/${id}`, { method:"PATCH", body: JSON.stringify({ status }) });
    await refresh();
  };

  const statusTabLabels = {
    all: "All",
    pending: "Pending",
    transit: "In Transit",
    delivered: "Delivered"
  };

  return (
  <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
    {showAdd && (
      <Modal title="Log kit dispatch" onClose={()=>setShowAdd(false)}>
        <form onSubmit={dispatch}>
          <FormField label="STUDENT">
            <select required style={selectStyle} value={form.student_id} onChange={e=>setForm(f=>({...f,student_id:e.target.value}))}>
              <option value="">— select student —</option>
              {STUDENTS.map(s=><option key={s.id} value={s.id}>{s.name}</option>)}
            </select>
          </FormField>
          <FormField label="KIT CONTENTS">
            <input style={inputStyle} value={form.contents} onChange={e=>setForm(f=>({...f,contents:e.target.value}))} placeholder="e.g. Arduino, USB cable, booklet"/>
          </FormField>
          <FormField label="TRACKING NUMBER (optional)">
            <input style={inputStyle} value={form.tracking} onChange={e=>setForm(f=>({...f,tracking:e.target.value}))} placeholder="e.g. DTDC1234567"/>
          </FormField>
          {error && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>{error}</div>}
          <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
            <button type="button" onClick={()=>setShowAdd(false)} className="btn btn-ghost">Cancel</button>
            <button type="submit" disabled={saving} className="btn btn-primary">{saving?"Saving…":"Log dispatch"}</button>
          </div>
        </form>
      </Modal>
    )}
    <AdminSidebar active="/app/admin/kits" go={go}/>
    <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>
      <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
        <div>
          <div className="display" style={{ fontSize:20 }}>Kit Delivery Tracking</div>
          <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>
            {statusFilter === "all"
              ? `${list.filter(k=>k.status==="transit").length} in transit · ${list.filter(k=>k.status==="pending").length} pending`
              : `Showing ${filteredList.length} ${statusFilter === "transit" ? "in transit" : statusFilter} of ${list.length} total`}
          </div>
        </div>
        <div style={{ flex:1 }}/>
        <Tabs
          items={["All", "Pending", "In Transit", "Delivered"]}
          active={statusTabLabels[statusFilter] || "All"}
          onChange={tab => setStatusFilter(tab === "All" ? "all" : tab === "Pending" ? "pending" : tab === "In Transit" ? "transit" : "delivered")}
        />
        <button onClick={()=>setShowAdd(true)} className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Log dispatch</button>
      </div>
      <div style={{ flex:1, overflow:"auto", padding:22 }}>
        <div style={{ display:"grid", gridTemplateColumns:"repeat(3,1fr)", gap:14, marginBottom:22 }}>
          {[
            { label:"DELIVERED",  status:"delivered", value:list.filter(k=>k.status==="delivered").length, color:"var(--moss)" },
            { label:"IN TRANSIT", status:"transit",   value:list.filter(k=>k.status==="transit").length,   color:"var(--sky)" },
            { label:"PENDING",    status:"pending",   value:list.filter(k=>k.status==="pending").length,    color:"var(--gold)" },
          ].map(k => {
            const isActive = statusFilter === k.status;
            return (
              <div
                key={k.label}
                id={`kit-card-${k.status}`}
                data-testid={`kit-card-${k.status}`}
                onClick={() => setStatusFilter(prev => prev === k.status ? "all" : k.status)}
                className="card-flat"
                style={{
                  padding: 14,
                  cursor: "pointer",
                  border: isActive ? `2px solid ${k.color}` : "var(--border-thin)",
                  background: isActive ? "var(--paper-card)" : undefined,
                  boxShadow: isActive ? `0 0 0 1px ${k.color}44` : "none",
                  transition: "all .15s ease",
                  userSelect: "none"
                }}
                title={isActive ? "Click to show all kits" : `Filter by ${k.label.toLowerCase()}`}
              >
                <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center" }}>
                  <div className="mono" style={{ fontSize:10, color: isActive ? k.color : "var(--ink-mute)", fontWeight: isActive ? 700 : 500, letterSpacing:".06em" }}>{k.label}</div>
                  {isActive && <span className="chip flat" style={{ fontSize:9, padding:"1px 6px", background:k.color, color:"white" }}>active</span>}
                </div>
                <div className="display" style={{ fontSize:32, marginTop:4, color:k.color }}>{k.value}</div>
              </div>
            );
          })}
        </div>
        {list.length === 0 ? (
          <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
            <div style={{ fontSize:32, marginBottom:12 }}>📦</div>
            <div style={{ fontSize:16, fontWeight:700 }}>No kits logged yet</div>
            <div style={{ fontSize:13, marginTop:4, marginBottom:20 }}>Log your first dispatch to start tracking</div>
            <button onClick={()=>setShowAdd(true)} className="btn btn-primary">{I.plus({ size:14 })} Log dispatch</button>
          </div>
        ) : filteredList.length === 0 ? (
          <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
            <div style={{ fontSize:32, marginBottom:12 }}>🔍</div>
            <div style={{ fontSize:16, fontWeight:700 }}>No kits with status "{statusTabLabels[statusFilter] || statusFilter}"</div>
            <div style={{ fontSize:13, marginTop:4, marginBottom:16 }}>Try selecting a different status filter or view all kits.</div>
            <button onClick={()=>setStatusFilter("all")} className="btn btn-ghost" style={{ border:"var(--border-thin)", padding:"6px 14px" }}>Show all kits</button>
          </div>
        ) : (
          <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
            <thead>
              <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                {["Kit ID","Student","Course","Contents","Ordered","Status","Tracking",""].map(h => (
                  <th key={h} style={{ padding:"8px 10px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filteredList.map((k,i) => (
                <tr key={k.id} style={{ borderTop: i?"var(--border-thin)":"none" }}>
                  <td style={{ padding:"12px 10px" }}><span className="mono" style={{ fontSize:11 }}>{k.id}</span></td>
                  <td style={{ padding:"12px 10px", fontWeight:700 }}>{k.student}</td>
                  <td style={{ padding:"12px 10px", color:"var(--ink-soft)", fontSize:12 }}>{k.course}</td>
                  <td style={{ padding:"12px 10px", fontSize:11, color:"var(--ink-mute)", maxWidth:160 }}>{k.contents||"—"}</td>
                  <td style={{ padding:"12px 10px" }}><span className="mono" style={{ fontSize:11, color:"var(--ink-mute)" }}>{k.ordered}</span></td>
                  <td style={{ padding:"12px 10px" }}>
                    <span className="chip flat" style={{ fontSize:10, padding:"2px 8px", background: k.status==="delivered"?"var(--moss)":k.status==="transit"?"var(--sky-deep)":"var(--gold)", color: k.status==="delivered"||k.status==="transit"?"white":"var(--ink)" }}>
                      {k.status}
                    </span>
                  </td>
                  <td style={{ padding:"12px 10px" }}><span className="mono" style={{ fontSize:11, color:"var(--ink-mute)" }}>{k.tracking||"—"}</span></td>
                  <td style={{ padding:"12px 10px" }}>
                    <select value={k.status} onChange={e=>updateStatus(k.id,e.target.value)}
                      style={{ padding:"3px 8px", borderRadius:8, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:11, fontFamily:"var(--font-ui)", color:"var(--ink)", cursor:"pointer" }}>
                      <option value="pending">pending</option>
                      <option value="transit">transit</option>
                      <option value="delivered">delivered</option>
                    </select>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  </Themed>
  );
};

// ── Teacher: Content Management + YouTube Embed ───────────────────────────────
const TeacherContent = ({ dark = false, go, session }) => {
  const tid = session?.teacherId;
  const { data: dash } = useApi(tid ? `/teacher/dashboard/${tid}` : "/teacher/dashboard/0", {});
  const batches = dash.batches || [];
  const [selectedBatch, setSelectedBatch] = React.useState(null);
  const activeBatch = batches.find(b => b.id === selectedBatch) || batches[0] || null;
  const courseId = activeBatch ? (activeBatch.course_id || null) : null;
  const { data: COURSE_CONTENT } = useApi(courseId ? `/content/${courseId}` : "/content/0");
  const { data: courseFiles } = useApi(courseId ? `/library-assets/${courseId}` : null);
  const lessonFiles = (courseFiles || []).filter(f => !!f.lesson_file_id);
  const [openUnit, setOpenUnit] = React.useState(null);
  const [showAdd, setShowAdd] = React.useState(false);
  const [addForm, setAddForm] = React.useState({ title:"", unit_id:"", type:"video", youtube_url:"", duration:"", file_id:"", body:"" });
  // Bumped after each save so the (uncontrolled) rich text editor re-seeds itself.
  const [addDocKey, setAddDocKey] = React.useState(0);
  // When on, lessons this teacher hid from their own view are shown again so
  // they can be restored. Hiding never touches the Content LMS.
  const [showHidden, setShowHidden] = React.useState(false);
  const [hiddenIds, setHiddenIds] = React.useState([]);
  const [addSaving, setAddSaving] = React.useState(false);
  const [addError, setAddError] = React.useState("");
  const [showAddUnit, setShowAddUnit] = React.useState(false);
  const [unitTitle, setUnitTitle] = React.useState("");
  const [unitSaving, setUnitSaving] = React.useState(false);
  const [unitError, setUnitError] = React.useState("");
  const [ytInput, setYtInput] = React.useState("");
  const [preview, setPreview] = React.useState(null);
  const [content, setContent] = React.useState(null);
  // In-app file preview (PDF/image/text inline, download otherwise) + txt editor.
  const [fileView, setFileView] = React.useState(null);
  const [textView, setTextView] = React.useState(null);   // read a text lesson
  const [editTextFile, setEditTextFile] = React.useState(null);
  const [editTextValue, setEditTextValue] = React.useState("");
  const [editTextLoading, setEditTextLoading] = React.useState(false);
  const [editTextSaving, setEditTextSaving] = React.useState(false);
  const b64ToText = (b64) => { try { return decodeURIComponent(escape(atob(b64))); } catch { return atob(b64); } };
  const textToB64 = (text) => btoa(unescape(encodeURIComponent(text)));
  const openTextEditor = async (f) => {
    setEditTextFile(f); setEditTextValue(""); setEditTextLoading(true);
    const r = await apiFetch(`/library-assets/${courseId}/${encodeURIComponent(f.id)}/data`);
    if (!r.ok) { setEditTextLoading(false); setEditTextFile(null); alert("Could not open file."); return; }
    const { file_data } = await r.json();
    setEditTextValue(b64ToText(file_data || "")); setEditTextLoading(false);
  };
  const saveTextEditor = async () => {
    setEditTextSaving(true);
    const r = await apiFetch(`/library-assets/${courseId}/${encodeURIComponent(editTextFile.id)}/data`, { method:"PUT", body: JSON.stringify({ file_data: textToB64(editTextValue) }) });
    setEditTextSaving(false);
    if (!r.ok) { const d = await r.json().catch(()=>({})); alert(d.error || "Could not save file"); return; }
    setEditTextFile(null);
  };
  const downloadLibFile = async (f) => {
    const r = await apiFetch(`/library-assets/${courseId}/${encodeURIComponent(f.id)}/data`);
    if (!r.ok) { alert("Could not download file."); return; }
    const { file_data, file_type } = await r.json();
    const bin = atob(file_data || ""), bytes = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
    const url = URL.createObjectURL(new Blob([bytes], { type: fileMimeType(file_type) }));
    const a = document.createElement("a"); a.href = url; a.download = f.title; a.click();
    setTimeout(() => URL.revokeObjectURL(url), 60000);
  };
  const CC = content ?? COURSE_CONTENT;
  React.useEffect(() => { if (CC.length && !openUnit) setOpenUnit(CC[0].id); }, [CC.length]);
  const refreshContent = () => courseId && apiFetch(`/content/${courseId}${showHidden ? "?include_hidden=1" : ""}`).then(r=>r.json()).then(setContent);
  const refreshHidden = () => apiFetch("/hidden-items").then(r=>r.ok?r.json():[])
    .then(rows => setHiddenIds((Array.isArray(rows)?rows:[]).filter(r=>r.item_type==="lesson").map(r=>r.item_id)))
    .catch(()=>{});
  React.useEffect(() => { refreshHidden(); }, []);
  // Drop the locally-cached tree when the batch (and so the course) changes, so
  // the previous course's modules never linger while the refetch is in flight.
  React.useEffect(() => { setContent(null); if (courseId) refreshContent(); }, [showHidden, courseId]);

  const getYtId = url => {
    if (!url) return null;
    const m = String(url).match(/(?:v=|\/embed\/|\/shorts\/|\/live\/|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
    return m ? m[1] : /^[a-zA-Z0-9_-]{11}$/.test(url) ? url : null;
  };

  // ── Edit / delete / reorder / publish (trainers have equal authoring power) ──
  const ctrlBtn = { background:"none", border:"none", cursor:"pointer", fontSize:13, padding:"2px 5px", borderRadius:6, lineHeight:1 };
  const renameUnit = async (u) => { const t = prompt("Rename module", u.unit); if (t==null || !t.trim()) return; await apiFetch(`/units/${u.id}`, { method:"PATCH", body: JSON.stringify({ title: t.trim() }) }); refreshContent(); };
  const moveUnit = async (u, direction) => { await apiFetch(`/units/${u.id}/move`, { method:"POST", body: JSON.stringify({ direction }) }); refreshContent(); };
  const deleteUnit = async (u) => { const n=(u.lessons||[]).length; if (!confirm(`Delete module "${u.unit}"${n?` and its ${n} lesson${n>1?"s":""}`:""}? This cannot be undone.`)) return; await apiFetch(`/units/${u.id}`, { method:"DELETE" }); refreshContent(); };
  const moveLesson = async (l, direction) => { await apiFetch(`/lessons/${l.id}/move`, { method:"POST", body: JSON.stringify({ direction }) }); refreshContent(); };
  // A teacher only ever hard-deletes lessons they authored. Anything the Content
  // LMS owns is hidden from this teacher's view instead, so the content library
  // (and every other teacher) is untouched.
  const ownsLesson = (l) => l.created_by != null && l.created_by === session?.id;
  const deleteLessonT = async (l) => {
    if (!confirm(`Delete lesson "${l.title}"? You created it, so this removes it everywhere.`)) return;
    const r = await apiFetch(`/lessons/${l.id}`, { method:"DELETE" });
    if (!r.ok) { const d = await r.json().catch(()=>({})); alert(d.error || "Could not delete this lesson."); return; }
    refreshContent();
  };
  const unhideLessonT = async (l) => {
    await apiFetch(`/hidden-items/lesson/${l.id}`, { method:"DELETE" });
    await refreshHidden(); refreshContent();
  };
  const togglePublish = async (l) => { await apiFetch(`/lessons/${l.id}`, { method:"PATCH", body: JSON.stringify({ status: l.status==="published"?"draft":"published" }) }); refreshContent(); };
  const [editLesson, setEditLesson] = React.useState(null);
  const [editLForm, setEditLForm] = React.useState({});
  const [editLSaving, setEditLSaving] = React.useState(false);
  const openEditLesson = (l) => { setEditLesson(l); setEditLForm({ title:l.title, type:l.type, youtube_url: l.youtube?`https://youtu.be/${l.youtube}`:"", duration:l.duration||"", file_id:l.file_id||"", status:l.status }); };
  const saveEditLesson = async () => {
    if (!editLForm.title.trim()) return;
    setEditLSaving(true);
    const body = { title:editLForm.title, type:editLForm.type, duration:editLForm.duration, status:editLForm.status };
    if (editLForm.type==="video") body.youtube_url = editLForm.youtube_url;
    if (editLForm.type==="file") body.file_id = editLForm.file_id || null;
    const res = await apiFetch(`/lessons/${editLesson.id}`, { method:"PATCH", body: JSON.stringify(body) });
    setEditLSaving(false);
    if (!res.ok) { const d=await res.json().catch(()=>({})); alert(d.error||"Could not save lesson"); return; }
    setEditLesson(null); refreshContent();
  };
  const editInput = { width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", boxSizing:"border-box", outline:"none" };

  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      {fileView && (
        <FileViewer courseId={fileView.course_id || courseId} fileId={fileView.file_id} title={fileView.title} fileType={fileView.file_type} kind={fileView.kind || "course"} onClose={() => setFileView(null)}/>
      )}
      {textView && (
        <Modal title={textView.title} onClose={()=>setTextView(null)}>
          <RichTextView html={textView.body} style={{ maxHeight:"60vh", overflow:"auto" }}/>
        </Modal>
      )}
      {editTextFile && (
        <Modal title={`Edit · ${editTextFile.title}`} onClose={()=>setEditTextFile(null)}>
          <div style={{ display:"flex", flexDirection:"column", gap:10 }}>
            {editTextLoading ? <Spinner/> : (
              <textarea value={editTextValue} onChange={e=>setEditTextValue(e.target.value)} spellCheck={false}
                style={{ width:"100%", minHeight:340, padding:"10px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-mono, monospace)", boxSizing:"border-box", outline:"none", resize:"vertical", lineHeight:1.5 }}/>
            )}
            <div style={{ display:"flex", gap:8, justifyContent:"flex-end" }}>
              <button onClick={()=>setEditTextFile(null)} className="btn btn-ghost">Cancel</button>
              <button onClick={saveTextEditor} disabled={editTextSaving || editTextLoading} className="btn btn-primary">{editTextSaving?"Saving…":"Save"}</button>
            </div>
          </div>
        </Modal>
      )}
      <TeacherSidebar active="/app/teacher/content" go={go} session={session}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0 }}>
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:22 }}>Content Management</div>
            <div className="mono" style={{ fontSize:11, color:"var(--ink-mute)" }}>{activeBatch ? `${activeBatch.name}${activeBatch.course ? " · " + activeBatch.course : " · no course assigned"}` : "Select a batch"}</div>
          </div>
          <div style={{ flex:1 }}/>
          {batches.length > 0 ? (
            <select
              value={activeBatch?.id || ""}
              onChange={e => setSelectedBatch(Number(e.target.value))}
              style={{ padding:"7px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", minWidth:180 }}>
              {batches.map(b => <option key={b.id} value={b.id}>{b.name}{b.course ? ` · ${b.course}` : " · (no course)"}</option>)}
            </select>
          ) : (
            <span style={{ fontSize:12, color:"var(--coral)" }}>No batches assigned to you yet — ask an admin.</span>
          )}
          {hiddenIds.length > 0 && (
            <button className="btn btn-ghost" onClick={() => setShowHidden(v=>!v)} style={{ padding:"6px 14px", fontSize:12 }}
              title="Lessons you hid from your own view — the Content LMS still has them">
              {showHidden ? "Hide hidden" : `Show hidden (${hiddenIds.length})`}
            </button>
          )}
          <button className="btn btn-ghost" onClick={() => { setShowAddUnit(true); setUnitError(""); }} style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add unit</button>
          <button className="btn btn-primary" onClick={() => setShowAdd(true)} style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} Add lesson</button>
        </div>
        <div style={{ flex:1, display:"grid", gridTemplateColumns:"1fr 1.4fr", overflow:"hidden" }}>
          <div style={{ borderRight:"var(--border-thin)", overflow:"auto", padding:18, background:"var(--paper)" }}>
            {CC.map((unit, ui) => {
              const lessons = unit.lessons || [];
              const pubCount = lessons.filter(l=>l.status==="published").length;
              return (
              <div key={unit.id} style={{ marginBottom:10 }}>
                <div style={{ display:"flex", alignItems:"center", gap:4, padding:"8px 10px", borderRadius:10, background: openUnit===unit.id ? "var(--paper-deep)" : "transparent" }}>
                  <div onClick={() => setOpenUnit(openUnit===unit.id?null:unit.id)} style={{ flex:1, minWidth:0, cursor:"pointer", display:"flex", alignItems:"center", justifyContent:"space-between", gap:8 }}>
                    <span style={{ fontWeight:700, fontSize:13 }}>{unit.unit}</span>
                    <span style={{ fontSize:11, color:"var(--ink-mute)" }}>{pubCount}/{lessons.length} published</span>
                  </div>
                  <button title="Move up" onClick={()=>moveUnit(unit,"up")} disabled={ui===0} style={{...ctrlBtn, opacity: ui===0?.3:1}}>↑</button>
                  <button title="Move down" onClick={()=>moveUnit(unit,"down")} disabled={ui===CC.length-1} style={{...ctrlBtn, opacity: ui===CC.length-1?.3:1}}>↓</button>
                  <button title="Rename module" onClick={()=>renameUnit(unit)} style={ctrlBtn}>✏️</button>
                  {hasPerm("administer_courses") && <button title="Delete module" onClick={()=>deleteUnit(unit)} style={{...ctrlBtn, color:"var(--coral)"}}>🗑</button>}
                </div>
                {openUnit === unit.id && (
                  <div style={{ paddingLeft:12, marginTop:4 }}>
                    {lessons.length === 0 && <div style={{ fontSize:12, color:"var(--ink-mute)", padding:"6px 10px" }}>No lessons yet.</div>}
                    {lessons.map((l, li) => {
                      const hidden = hiddenIds.includes(l.id);
                      return (
                      <div key={l.id||li} style={{ display:"flex", alignItems:"center", gap:6, padding:"8px 10px", borderRadius:8, marginBottom:2, opacity: hidden ? .5 : 1 }}>
                        <div onClick={() => l.youtube && setPreview(l.youtube)} title={l.youtube?"Preview":l.type} style={{ width:28, height:28, borderRadius:8, background: LESSON_TYPE_COLOR[l.type] || "var(--plum)", color:"white", display:"grid", placeItems:"center", flexShrink:0, cursor: l.youtube?"pointer":"default", fontSize:12 }}>
                          {l.type==="video" ? I.play({ size:12 }) : l.type==="quiz" ? I.puzzle({ size:12 }) : l.type==="text" ? "¶" : I.book({ size:12 })}
                        </div>
                        <div style={{ flex:1, minWidth:0 }}>
                          <div style={{ fontSize:13, fontWeight:600, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{l.title}</div>
                          {l.duration && <div style={{ fontSize:11, color:"var(--ink-mute)" }}>{l.duration}</div>}
                        </div>
                        {hidden && <span className="chip flat" style={{ fontSize:9, padding:"1px 6px", background:"var(--ink-mute)", color:"white", flexShrink:0 }}>hidden for you</span>}
                        <span className="chip flat" style={{ fontSize:9, padding:"1px 6px", background: l.status==="published" ? "var(--moss)" : "var(--gold)", color:"white", flexShrink:0 }}>{l.status==="published"?"published":"draft"}</span>
                        {l.type==="file" && l.file_id && (
                          <button title="Open / preview file" onClick={()=>setFileView({ file_id:l.file_id, title:l.title, file_type:l.file_type, kind:"course", course_id: l.file_course_id || courseId })} style={ctrlBtn}>🔍</button>
                        )}
                        {l.type==="text" && l.body && (
                          <button title="Read this lesson" onClick={()=>setTextView(l)} style={ctrlBtn}>🔍</button>
                        )}
                        <button title={l.status==="published"?"Unpublish (hide from students)":"Publish (show to students)"} onClick={()=>togglePublish(l)} style={ctrlBtn}>{l.status==="published"?"🔒 Unpublish":"🌐 Publish"}</button>
                        <button title="Move up" onClick={()=>moveLesson(l,"up")} disabled={li===0} style={{...ctrlBtn, opacity: li===0?.3:1}}>↑</button>
                        <button title="Move down" onClick={()=>moveLesson(l,"down")} disabled={li===lessons.length-1} style={{...ctrlBtn, opacity: li===lessons.length-1?.3:1}}>↓</button>
                        <button title="Edit lesson" onClick={()=>openEditLesson(l)} style={ctrlBtn}>✏️</button>
                        {hidden ? (
                          <button title="Restore to my view" onClick={()=>unhideLessonT(l)} style={{...ctrlBtn, color:"var(--moss)"}}>↩</button>
                        ) : ownsLesson(l) ? (
                          <button title="Delete lesson (you created it)" onClick={()=>deleteLessonT(l)} style={{...ctrlBtn, color:"var(--coral)"}}>🗑</button>
                        ) : null}
                      </div>
                    );})}
                  </div>
                )}
              </div>
            )})}
          </div>
          <div style={{ overflow:"auto", padding:22, background:"var(--paper-card)", display:"flex", flexDirection:"column", gap:16 }}>
            {preview ? (
              <div>
                <SectionHead eyebrow="YOUTUBE PREVIEW" title="Embedded video"/>
                <SafeYouTube videoId={getYtId(preview)} title="Lesson video"/>
                <button className="btn btn-ghost" onClick={() => setPreview(null)} style={{ marginTop:10, fontSize:12 }}>← Back to overview</button>
              </div>
            ) : (
              <>
                <div className="card-flat" style={{ padding:18 }}>
                  <SectionHead eyebrow="YOUTUBE INTEGRATION" title="Add video lesson"/>
                  <div style={{ display:"flex", gap:8, marginBottom:12 }}>
                    <input value={ytInput} onChange={e => setYtInput(e.target.value)} placeholder="Paste YouTube URL or video ID…" style={{ flex:1, padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, fontFamily:"var(--font-ui)", color:"var(--ink)", outline:"none" }}/>
                    <button className="btn btn-primary" onClick={() => { const id = getYtId(ytInput); if(id) setPreview(id); }} style={{ padding:"8px 14px", fontSize:12 }}>Preview</button>
                  </div>
                  {ytInput && getYtId(ytInput) && <SafeYouTube videoId={getYtId(ytInput)} title="Preview"/>}
                  {ytInput && !getYtId(ytInput) && <div style={{ fontSize:12, color:"var(--coral)", marginTop:4 }}>Invalid YouTube URL</div>}
                </div>
                <div className="card-flat" style={{ padding:18 }}>
                  <SectionHead eyebrow="OVERVIEW" title="Content stats"/>
                  <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
                    {[
                      ["Units",    CC.length],
                      ["Lessons",  CC.reduce((a,u)=>a+(u.lessons||[]).length,0)],
                      ["Published",CC.reduce((a,u)=>a+(u.lessons||[]).filter(l=>l.status==="published").length,0)],
                      ["Videos",   CC.reduce((a,u)=>a+(u.lessons||[]).filter(l=>l.type==="video").length,0)],
                    ].map(([l,v]) => (
                      <div key={l} style={{ padding:12, background:"var(--paper-deep)", borderRadius:8, border:"var(--border-thin)" }}>
                        <div style={{ fontSize:11, color:"var(--ink-mute)" }}>{l}</div>
                        <div className="display" style={{ fontSize:24, marginTop:2 }}>{v}</div>
                      </div>
                    ))}
                  </div>
                </div>
                <div className="card-flat" style={{ padding:18 }}>
                  <SectionHead eyebrow="COURSE FILES" title="Preview & edit"/>
                  {(courseFiles || []).length === 0 ? (
                    <div style={{ fontSize:13, color:"var(--ink-mute)", padding:"6px 0" }}>No files uploaded for this course yet.</div>
                  ) : (
                    <div style={{ display:"flex", flexDirection:"column", gap:8 }}>
                      {(courseFiles || []).map(f => (
                        <div key={f.id} style={{ display:"flex", alignItems:"center", gap:10, padding:"10px 12px", borderRadius:10, border:"var(--border-thin)", background:"var(--paper-deep)" }}>
                          <span style={{ fontSize:22, flexShrink:0 }}>{MIME_ICONS[String(f.file_type||"").toLowerCase()] || "📁"}</span>
                          <div style={{ flex:1, minWidth:0 }}>
                            <div style={{ fontWeight:700, fontSize:13, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{f.title}</div>
                            <div style={{ fontSize:11, color:"var(--ink-mute)", marginTop:2 }}><span style={{ textTransform:"uppercase", fontWeight:700 }}>{f.file_type}</span></div>
                          </div>
                          {String(f.file_type||"").toLowerCase() === "txt" && (
                            <button onClick={() => openTextEditor(f)} style={{ padding:"5px 11px", borderRadius:6, border:"none", background:"var(--gold)", color:"white", cursor:"pointer", fontSize:12, fontWeight:600, flexShrink:0 }}>Edit</button>
                          )}
                          <button onClick={() => setFileView({ file_id:f.id, title:f.title, file_type:f.file_type, kind:"library" })} style={{ padding:"5px 11px", borderRadius:6, border:"none", background:"var(--sky)", color:"white", cursor:"pointer", fontSize:12, fontWeight:600, flexShrink:0 }}>Preview</button>
                          <button onClick={() => downloadLibFile(f)} style={{ padding:"5px 11px", borderRadius:6, border:"none", background:"var(--moss)", color:"white", cursor:"pointer", fontSize:12, fontWeight:600, flexShrink:0 }}>Download</button>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              </>
            )}
          </div>
        </div>
      </div>
      {showAddUnit && (
        <div style={{ position:"fixed", inset:0, background:"rgba(0,0,0,.5)", display:"flex", alignItems:"center", justifyContent:"center", zIndex:50 }} onClick={() => { setShowAddUnit(false); setUnitError(""); }}>
          <div className="codeland" onClick={e => e.stopPropagation()} style={{ background:"var(--paper-card)", borderRadius:16, padding:28, width:400, boxShadow:"var(--sh-soft)" }}>
            <div className="display" style={{ fontSize:20, marginBottom:18 }}>Add unit</div>
            {!courseId && (
              <div style={{ color:"var(--coral)", fontSize:13, marginBottom:12 }}>Please select a batch with a course first.</div>
            )}
            <div style={{ marginBottom:12 }}>
              <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>UNIT TITLE</div>
              <input
                value={unitTitle}
                onChange={e=>setUnitTitle(e.target.value)}
                placeholder="e.g. Unit 1 · Getting Started"
                style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", boxSizing:"border-box", outline:"none" }}
              />
            </div>
            {unitError && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:10 }}>{unitError}</div>}
            <div style={{ display:"flex", gap:10, marginTop:4 }}>
              <button className="btn btn-primary" disabled={unitSaving || !courseId} onClick={async () => {
                if (!unitTitle.trim()) { setUnitError("Title required"); return; }
                setUnitError(""); setUnitSaving(true);
                const res = await apiFetch(`/courses/${courseId}/units`, { method:"POST", body: JSON.stringify({ title: unitTitle.trim() }) });
                if (!res.ok) { const d=await res.json(); setUnitError(d.error||"Failed"); setUnitSaving(false); return; }
                setUnitTitle(""); setShowAddUnit(false); setUnitSaving(false);
                await refreshContent();
              }} style={{ flex:1, padding:"10px 0", fontSize:14 }}>{unitSaving ? "Saving…" : "Add unit"}</button>
              <button className="btn btn-ghost" onClick={() => { setShowAddUnit(false); setUnitError(""); }} style={{ padding:"10px 14px", fontSize:14 }}>Cancel</button>
            </div>
          </div>
        </div>
      )}
      {showAdd && (
        <div style={{ position:"fixed", inset:0, background:"rgba(0,0,0,.5)", display:"flex", alignItems:"center", justifyContent:"center", zIndex:50 }} onClick={() => { setShowAdd(false); setAddError(""); }}>
          <div className="codeland" onClick={e => e.stopPropagation()} style={{ background:"var(--paper-card)", borderRadius:16, padding:28, width:440, boxShadow:"var(--sh-soft)" }}>
            <div className="display" style={{ fontSize:20, marginBottom:18 }}>Add lesson</div>

            <div style={{ marginBottom:12 }}>
              <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>TITLE</div>
              <input value={addForm.title} onChange={e=>setAddForm(f=>({...f,title:e.target.value}))} placeholder="e.g. Functions intro"
                style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", boxSizing:"border-box", outline:"none" }}/>
            </div>

            <div style={{ marginBottom:12 }}>
              <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>UNIT</div>
              <select value={addForm.unit_id} onChange={e=>setAddForm(f=>({...f,unit_id:e.target.value}))}
                style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)" }}>
                <option value="">— select unit —</option>
                {CC.map(u => <option key={u.id} value={u.id}>{u.unit}</option>)}
              </select>
            </div>

            <div style={{ marginBottom:12 }}>
              <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>TYPE</div>
              <select value={addForm.type} onChange={e=>setAddForm(f=>({...f,type:e.target.value}))}
                style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)" }}>
                {LESSON_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
              </select>
            </div>

            {addForm.type === "text" && (
              <div style={{ marginBottom:12 }}>
                <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>CONTENT</div>
                <RichTextEditor docKey={`t-new-${addDocKey}`} value={addForm.body} minHeight={200}
                  onChange={v=>setAddForm(f=>({...f,body:v}))}
                  placeholder="Write the lesson — headings, lists, quotes and code blocks are all supported."/>
              </div>
            )}

            {addForm.type === "video" && (
              <div style={{ marginBottom:12 }}>
                <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>YOUTUBE LINK</div>
                <input value={addForm.youtube_url} onChange={e=>setAddForm(f=>({...f,youtube_url:e.target.value}))} placeholder="watch, youtu.be, embed or shorts link"
                  style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", boxSizing:"border-box", outline:"none" }}/>
              </div>
            )}

            {addForm.type === "file" && (
              <div style={{ marginBottom:12 }}>
                <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>FILE</div>
                {(lessonFiles && lessonFiles.length) ? (
                  <select value={addForm.file_id} onChange={e=>setAddForm(f=>({...f,file_id:e.target.value}))}
                    style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)" }}>
                    <option value="">— select an uploaded file —</option>
                    {lessonFiles.map(f => <option key={f.id} value={f.lesson_file_id}>{f.title}</option>)}
                  </select>
                ) : (
                  <div style={{ fontSize:12, color:"var(--coral)" }}>No files uploaded for this course yet. A content manager can upload them under Content → Files.</div>
                )}
              </div>
            )}

            <div style={{ marginBottom:12 }}>
              <div style={{ fontSize:11, fontWeight:700, color:"var(--ink-mute)", marginBottom:4, fontFamily:"var(--font-mono)", textTransform:"uppercase" }}>DURATION <span style={{ fontWeight:400 }}>(optional)</span></div>
              <input value={addForm.duration} onChange={e=>setAddForm(f=>({...f,duration:e.target.value}))} placeholder="e.g. 8:22"
                style={{ width:"100%", padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, color:"var(--ink)", fontFamily:"var(--font-ui)", boxSizing:"border-box", outline:"none" }}/>
            </div>

            {addError && <div style={{ color:"var(--coral)", fontSize:13, marginBottom:10 }}>{addError}</div>}

            <div style={{ display:"flex", gap:10, marginTop:18 }}>
              <button className="btn btn-primary" disabled={addSaving} onClick={async () => {
                setAddError("");
                if (!addForm.title.trim()) { setAddError("Title is required"); return; }
                if (!addForm.unit_id) { setAddError("Please select a unit"); return; }
                if (addForm.type==="file" && !addForm.file_id) { setAddError("Please pick an uploaded file"); return; }
                if (addForm.type==="text" && !stripHtml(addForm.body)) { setAddError("Write some content for this text lesson"); return; }
                setAddSaving(true);
                const res = await apiFetch(`/units/${addForm.unit_id}/lessons`, { method:"POST", body: JSON.stringify({ title:addForm.title, type:addForm.type, youtube_url:addForm.youtube_url, duration:addForm.duration, file_id: addForm.file_id||null, body: addForm.type==="text" ? addForm.body : null }) });
                if (!res.ok) { const d=await res.json(); setAddError(d.error||"Failed"); setAddSaving(false); return; }
                setAddForm({ title:"", unit_id:"", type:"video", youtube_url:"", duration:"", file_id:"", body:"" });
                setAddDocKey(k => k + 1);
                setShowAdd(false); setAddSaving(false);
                await refreshContent();
              }} style={{ flex:1, padding:"10px 0", fontSize:14 }}>{addSaving ? "Saving…" : "Add lesson"}</button>
              <button className="btn btn-ghost" onClick={() => { setShowAdd(false); setAddError(""); }} style={{ padding:"10px 14px", fontSize:14 }}>Cancel</button>
            </div>
          </div>
        </div>
      )}
      {editLesson && (
        <div style={{ position:"fixed", inset:0, background:"rgba(0,0,0,.5)", display:"flex", alignItems:"center", justifyContent:"center", zIndex:50 }} onClick={() => setEditLesson(null)}>
          <div className="codeland" onClick={e => e.stopPropagation()} style={{ background:"var(--paper-card)", borderRadius:16, padding:28, width:440, boxShadow:"var(--sh-soft)" }}>
            <div className="display" style={{ fontSize:20, marginBottom:18 }}>Edit lesson</div>
            <div style={{ display:"flex", flexDirection:"column", gap:10 }}>
              <input value={editLForm.title} onChange={e=>setEditLForm(f=>({...f,title:e.target.value}))} placeholder="Lesson title" style={editInput}/>
              <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:8 }}>
                <select value={editLForm.type} onChange={e=>setEditLForm(f=>({...f,type:e.target.value}))} style={editInput}>
                  {LESSON_TYPES.map(t=><option key={t} value={t}>{t}</option>)}
                </select>
                <select value={editLForm.status} onChange={e=>setEditLForm(f=>({...f,status:e.target.value}))} style={editInput}>
                  {["draft","published"].map(s=><option key={s} value={s}>{s}</option>)}
                </select>
              </div>
              {editLForm.type==="video" && <input value={editLForm.youtube_url} onChange={e=>setEditLForm(f=>({...f,youtube_url:e.target.value}))} placeholder="YouTube link (watch, youtu.be, embed or shorts)" style={editInput}/>}
              {/* Library-backed text lessons are owned by the Content LMS
                  document, so show them read-only here rather than an editor
                  whose changes the API would (correctly) ignore. */}
              {editLForm.type==="text" && (editLesson.text_doc_id ? (
                <div className="card-flat" style={{ padding:12, display:"flex", flexDirection:"column", gap:8 }}>
                  <div style={{ fontSize:12.5, color:"var(--ink)" }}>
                    📝 From the Text Library: <strong>{editLesson.text_doc_title || "—"}</strong> — managed by the Content LMS.
                  </div>
                  <RichTextView html={editLForm.body} style={{ maxHeight:220, overflow:"auto", fontSize:13 }}/>
                </div>
              ) : (
                <RichTextEditor docKey={`t-edit-${editLesson.id}`} value={editLForm.body} minHeight={200}
                  onChange={v=>setEditLForm(f=>({...f,body:v}))}/>
              ))}
              {editLForm.type==="file" && ((lessonFiles&&lessonFiles.length) ? (
                <select value={editLForm.file_id} onChange={e=>setEditLForm(f=>({...f,file_id:e.target.value}))} style={editInput}>
                  <option value="">— select an uploaded file —</option>
                  {lessonFiles.map(f=><option key={f.id} value={f.lesson_file_id}>{f.title}</option>)}
                </select>
              ) : <div style={{ fontSize:12, color:"var(--coral)" }}>No files uploaded for this course yet.</div>)}
              <input value={editLForm.duration} onChange={e=>setEditLForm(f=>({...f,duration:e.target.value}))} placeholder="Duration (optional, e.g. 8:22)" style={editInput}/>
              <div style={{ display:"flex", gap:8, justifyContent:"flex-end", marginTop:4 }}>
                <button onClick={()=>setEditLesson(null)} className="btn btn-ghost" style={{ padding:"10px 14px", fontSize:14 }}>Cancel</button>
                <button onClick={saveEditLesson} disabled={editLSaving} className="btn btn-primary" style={{ padding:"10px 18px", fontSize:14 }}>{editLSaving?"Saving…":"Save"}</button>
              </div>
            </div>
          </div>
        </div>
      )}
    </Themed>
  );
};

// ── Reusable Quiz Review Modal / View ──────────────────────────────────────────
const QuizReviewModal = ({ quizId, studentId, studentName, onClose, theme = "" }) => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    if (!quizId) return;
    setLoading(true);
    setError("");
    const url = studentId ? `/quizzes/${quizId}/results/${studentId}` : `/quizzes/${quizId}/results`;
    apiFetch(url)
      .then(async r => {
        const d = await r.json().catch(() => null);
        if (!r.ok) {
          setError(d?.error || "Unable to load quiz review");
        } else {
          setData(d);
        }
        setLoading(false);
      })
      .catch(err => {
        setError(err.message || "Failed to load quiz review");
        setLoading(false);
      });
  }, [quizId, studentId]);

  const quiz = data?.quiz;
  const student = data?.student;
  const result = data?.result;
  const questions = data?.questions || [];

  const pct = result?.score ?? 0;
  const timeTaken = result?.time_taken ?? null;
  const isLate = result?.is_late ?? false;

  const scoreColor = pct >= 80 ? "var(--moss)" : pct >= 60 ? "var(--gold)" : "var(--coral)";
  const scoreLbl = pct >= 80 ? "Excellent!" : pct >= 60 ? "Good effort!" : "Keep practising!";
  const scoreEmoji = pct >= 80 ? "🏆" : pct >= 60 ? "👍" : "💪";

  // Build answer map if stored answers exist
  const storedAnswers = result?.answers;
  const hasDetailedAnswers = Array.isArray(storedAnswers);
  const ansMap = {};
  if (hasDetailedAnswers) {
    storedAnswers.forEach((a, idx) => {
      if (a && a.question_id != null) {
        ansMap[a.question_id] = a.answer;
      } else if (a && a.answer != null) {
        ansMap[idx] = a.answer;
      }
    });
  }

  let correctCount = 0;
  let wrongCount = 0;
  let gradedCount = 0;

  if (hasDetailedAnswers) {
    questions.forEach((qItem, i) => {
      const studentAns = ansMap[qItem.id] ?? (storedAnswers[i]?.answer ?? null);
      const isMcq = !qItem.type || qItem.type === "mcq";
      if (isMcq) {
        gradedCount++;
        const isAnswered = studentAns != null && studentAns !== "";
        if (isAnswered && Number(studentAns) === Number(qItem.ans)) {
          correctCount++;
        } else if (isAnswered) {
          wrongCount++;
        }
      }
    });
  }

  const isTeacherView = Boolean(studentName || (student && student.name));
  const displayName = studentName || student?.name;

  return (
    <div
      style={{
        position: "fixed",
        inset: 0,
        background: "rgba(0,0,0,.6)",
        backdropFilter: "blur(4px)",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        zIndex: 9999,
        padding: 16,
        boxSizing: "border-box",
      }}
      onClick={e => e.target === e.currentTarget && onClose?.()}
    >
      <Themed
        theme={theme}
        style={{
          background: "var(--paper-card)",
          borderRadius: 20,
          width: 720,
          maxWidth: "96vw",
          maxHeight: "92vh",
          display: "flex",
          flexDirection: "column",
          boxShadow: "0 24px 70px rgba(0,0,0,.35)",
          border: "var(--border-thin)",
          overflow: "hidden",
          boxSizing: "border-box",
        }}
      >
        {/* Header */}
        <div
          style={{
            padding: "16px 22px",
            borderBottom: "var(--border-thin)",
            background: "var(--paper-card)",
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            gap: 12,
            flexShrink: 0,
          }}
        >
          <div>
            <div className="display" style={{ fontSize: 18, lineHeight: 1.2 }}>
              Quiz Review · {quiz?.title || "Quiz"}
            </div>
            <div style={{ fontSize: 12, color: "var(--ink-mute)", marginTop: 2 }}>
              {displayName ? (
                <span>Student: <strong style={{ color: "var(--ink)" }}>{displayName}</strong> · </span>
              ) : null}
              {quiz?.course || "General"}{quiz?.batch ? ` · ${quiz.batch}` : ""}
            </div>
          </div>
          <button
            onClick={onClose}
            className="btn btn-ghost"
            style={{
              padding: "6px 12px",
              fontSize: 13,
              fontWeight: 700,
              borderRadius: 8,
            }}
          >
            ✕ Close
          </button>
        </div>

        {/* Body */}
        <div style={{ flex: 1, overflowY: "auto", padding: "24px 20px" }}>
          {loading ? (
            <div style={{ padding: "60px 0", textAlign: "center" }}>
              <Spinner />
              <div style={{ marginTop: 16, fontSize: 13, color: "var(--ink-mute)" }}>Loading quiz review...</div>
            </div>
          ) : error ? (
            <div style={{ textAlign: "center", padding: "40px 20px" }}>
              <div style={{ fontSize: 48, marginBottom: 12 }}>🔒</div>
              <div className="display" style={{ fontSize: 20, marginBottom: 6 }}>Review Unavailable</div>
              <div style={{ color: "var(--coral)", fontSize: 14, marginBottom: 20 }}>{error}</div>
              <button className="btn btn-ghost" onClick={onClose} style={{ padding: "8px 18px" }}>
                Close
              </button>
            </div>
          ) : (
            <div style={{ maxWidth: 660, margin: "0 auto" }}>
              {/* Score Hero Card */}
              <div
                style={{
                  background: "var(--paper-card)",
                  borderRadius: 18,
                  padding: "26px 24px 22px",
                  marginBottom: 22,
                  border: "var(--border-thin)",
                  boxShadow: "var(--sh-2)",
                  textAlign: "center",
                  position: "relative",
                  overflow: "hidden",
                }}
              >
                <div
                  style={{
                    position: "absolute",
                    top: -40,
                    right: -40,
                    width: 150,
                    height: 150,
                    borderRadius: "50%",
                    background: scoreColor,
                    opacity: 0.08,
                    pointerEvents: "none",
                  }}
                />
                <div style={{ position: "relative" }}>
                  {/* Score ring */}
                  <div
                    style={{
                      width: 100,
                      height: 100,
                      borderRadius: "50%",
                      background: scoreColor,
                      color: "white",
                      display: "grid",
                      placeItems: "center",
                      margin: "0 auto 14px",
                      boxShadow: `0 0 0 6px ${scoreColor}22, var(--sh-3)`,
                    }}
                  >
                    <div>
                      <div className="display" style={{ fontSize: 30, lineHeight: 1 }}>{pct}%</div>
                      <div style={{ fontSize: 10, opacity: 0.85, letterSpacing: ".04em", marginTop: 2 }}>SCORE</div>
                    </div>
                  </div>
                  <div className="display" style={{ fontSize: 24, marginBottom: 4 }}>
                    {scoreEmoji} {scoreLbl}
                  </div>

                  {/* Stats row if graded MCQ exists */}
                  {hasDetailedAnswers && gradedCount > 0 ? (
                    <div style={{ display: "flex", justifyContent: "center", gap: 28, marginTop: 14, flexWrap: "wrap" }}>
                      <div style={{ textAlign: "center" }}>
                        <div style={{ fontSize: 20, fontWeight: 800, color: "var(--moss)" }}>{correctCount}</div>
                        <div style={{ fontSize: 11, color: "var(--ink-mute)", fontWeight: 700 }}>CORRECT</div>
                      </div>
                      <div style={{ textAlign: "center" }}>
                        <div style={{ fontSize: 20, fontWeight: 800, color: "var(--coral)" }}>{wrongCount}</div>
                        <div style={{ fontSize: 11, color: "var(--ink-mute)", fontWeight: 700 }}>WRONG</div>
                      </div>
                      <div style={{ textAlign: "center" }}>
                        <div style={{ fontSize: 20, fontWeight: 800, color: "var(--plum)" }}>{gradedCount}</div>
                        <div style={{ fontSize: 11, color: "var(--ink-mute)", fontWeight: 700 }}>TOTAL MCQ</div>
                      </div>
                    </div>
                  ) : null}

                  {/* Meta row */}
                  <div style={{ display: "flex", justifyContent: "center", gap: 16, marginTop: 12, flexWrap: "wrap" }}>
                    {timeTaken && (
                      <span style={{ fontSize: 12, color: "var(--ink-mute)", display: "flex", alignItems: "center", gap: 4 }}>
                        🕐 Completed in: <strong>{timeTaken}</strong>
                      </span>
                    )}
                    {isLate && (
                      <span style={{ fontSize: 12, color: "var(--coral)", fontWeight: 700, display: "flex", alignItems: "center", gap: 4 }}>
                        ⚠️ Submitted late
                      </span>
                    )}
                  </div>
                </div>
              </div>

              {/* Graceful Legacy Handling: NULL answers */}
              {!hasDetailedAnswers ? (
                <div
                  style={{
                    background: "var(--paper-deep)",
                    border: "var(--border-thin)",
                    borderRadius: 14,
                    padding: 24,
                    textAlign: "center",
                    marginTop: 16,
                  }}
                >
                  <div style={{ fontSize: 32, marginBottom: 8 }}>📋</div>
                  <div style={{ fontWeight: 700, fontSize: 15, marginBottom: 6 }}>
                    Detailed Review Not Available
                  </div>
                  <div style={{ fontSize: 13, color: "var(--ink-soft)", lineHeight: 1.5, maxWidth: 480, margin: "0 auto" }}>
                    Detailed question-by-question review is not available for this attempt.
                    Quiz attempts submitted prior to detailed answer logging store aggregate score and completion time only.
                  </div>
                </div>
              ) : (
                <>
                  {/* Section label */}
                  <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".08em", color: "var(--ink-mute)", marginBottom: 12 }}>
                    QUESTION REVIEW ({questions.length} questions)
                  </div>

                  {/* Per-question review cards */}
                  <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                    {questions.map((qItem, i) => {
                      const studentAns = ansMap[qItem.id] ?? (storedAnswers[i]?.answer ?? null);
                      const correctAns = qItem.ans;
                      const isMcq = !qItem.type || qItem.type === "mcq";
                      const isAnswered = studentAns != null && studentAns !== "";
                      const isCorrect = isMcq && isAnswered && Number(studentAns) === Number(correctAns);
                      const isWrong = isMcq && isAnswered && Number(studentAns) !== Number(correctAns);
                      const isSkipped = !isAnswered;

                      const borderColor = isCorrect ? "var(--moss)" : isWrong ? "var(--coral)" : "var(--rule)";
                      const bgBadge = isCorrect ? "var(--moss)" : isWrong ? "var(--coral)" : "var(--paper-deep)";
                      const lblBadge = isCorrect ? "✓ Correct" : isWrong ? "✗ Wrong" : "— Skipped";

                      return (
                        <div
                          key={qItem.id || i}
                          style={{
                            background: "var(--paper-card)",
                            borderRadius: 14,
                            border: `1.5px solid ${borderColor}`,
                            overflow: "hidden",
                          }}
                        >
                          {/* Question header strip */}
                          <div
                            style={{
                              display: "flex",
                              alignItems: "center",
                              justifyContent: "space-between",
                              padding: "10px 16px",
                              borderBottom: "var(--border-thin)",
                              background: "var(--paper-deep)",
                            }}
                          >
                            <span style={{ fontSize: 12, fontWeight: 700, color: "var(--ink-mute)" }}>
                              Q{i + 1}
                            </span>
                            <span
                              style={{
                                fontSize: 11,
                                fontWeight: 700,
                                padding: "3px 10px",
                                borderRadius: 999,
                                background: bgBadge,
                                color: isSkipped ? "var(--ink-mute)" : "white",
                              }}
                            >
                              {lblBadge}
                            </span>
                          </div>

                          <div style={{ padding: "14px 16px" }}>
                            {/* Question video if present */}
                            {qItem.video_url && (
                              <div style={{ marginBottom: 12 }}>
                                <SafeYouTube url={qItem.video_url} title="Question video" />
                              </div>
                            )}

                            {/* Question image if present */}
                            {qItem.image_ref && window.QuizQImage && (
                              <div style={{ marginBottom: 12 }}>
                                <window.QuizQImage
                                  qid={qItem.id}
                                  style={{ maxWidth: "100%", maxHeight: 240, borderRadius: 12, display: "block" }}
                                />
                              </div>
                            )}

                            {/* Question text */}
                            <div style={{ fontWeight: 600, fontSize: 14, lineHeight: 1.5, marginBottom: 14 }}>
                              {qItem.q}
                            </div>

                            {/* MCQ options */}
                            {isMcq && qItem.opts && (
                              <div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
                                {qItem.opts.map((opt, oi) => {
                                  const isStudentChoice = isAnswered && Number(studentAns) === oi;
                                  const isCorrectOpt = correctAns != null && oi === Number(correctAns);
                                  let optBg = "var(--paper-deep)";
                                  let optBorder = "var(--rule)";
                                  let optColor = "var(--ink-soft)";
                                  let optWeight = 500;
                                  let badge = null;

                                  const userAnsLabel = isTeacherView ? `${displayName || "Student"}'s answer` : "Your answer";

                                  if (isCorrectOpt) {
                                    optBg = "rgba(var(--moss-rgb,60,180,120),.12)";
                                    optBorder = "var(--moss)";
                                    optColor = "var(--moss)";
                                    optWeight = 700;
                                    badge = (
                                      <span style={{ fontSize: 10, fontWeight: 800, marginLeft: 6, padding: "1px 7px", borderRadius: 999, background: "var(--moss)", color: "white" }}>
                                        Correct
                                      </span>
                                    );
                                  }
                                  if (isStudentChoice && !isCorrectOpt) {
                                    optBg = "rgba(var(--coral-rgb,255,90,90),.10)";
                                    optBorder = "var(--coral)";
                                    optColor = "var(--coral)";
                                    optWeight = 700;
                                    badge = (
                                      <span style={{ fontSize: 10, fontWeight: 800, marginLeft: 6, padding: "1px 7px", borderRadius: 999, background: "var(--coral)", color: "white" }}>
                                        {userAnsLabel}
                                      </span>
                                    );
                                  }
                                  if (isStudentChoice && isCorrectOpt) {
                                    optBg = "rgba(var(--moss-rgb,60,180,120),.18)";
                                    optBorder = "var(--moss)";
                                    optColor = "var(--moss)";
                                    optWeight = 800;
                                    badge = (
                                      <span style={{ fontSize: 10, fontWeight: 800, marginLeft: 6, padding: "1px 7px", borderRadius: 999, background: "var(--moss)", color: "white" }}>
                                        ✓ {userAnsLabel}
                                      </span>
                                    );
                                  }
                                  return (
                                    <div
                                      key={oi}
                                      style={{
                                        display: "flex",
                                        alignItems: "center",
                                        gap: 10,
                                        padding: "9px 12px",
                                        borderRadius: 9,
                                        background: optBg,
                                        border: `1.5px solid ${optBorder}`,
                                        fontSize: 13,
                                        color: optColor,
                                        fontWeight: optWeight,
                                      }}
                                    >
                                      <span
                                        style={{
                                          width: 22,
                                          height: 22,
                                          borderRadius: "50%",
                                          border: `1.5px solid ${optBorder}`,
                                          display: "grid",
                                          placeItems: "center",
                                          flexShrink: 0,
                                          fontSize: 11,
                                          fontWeight: 800,
                                        }}
                                      >
                                        {String.fromCharCode(65 + oi)}
                                      </span>
                                      <span style={{ flex: 1 }}>{opt}</span>
                                      {badge}
                                    </div>
                                  );
                                })}
                              </div>
                            )}

                            {/* Non-MCQ type: show answer */}
                            {!isMcq && (
                              <div
                                style={{
                                  marginTop: 8,
                                  padding: "10px 13px",
                                  borderRadius: 9,
                                  background: "var(--paper-deep)",
                                  border: "var(--border-thin)",
                                  fontSize: 13,
                                  color: "var(--ink-soft)",
                                  fontStyle: isSkipped ? "italic" : "normal",
                                }}
                              >
                                {isSkipped ? (
                                  "No answer given"
                                ) : (
                                  <span>
                                    <strong>{isTeacherView ? `${displayName || "Student"}'s answer:` : "Your answer:"}</strong> {studentAns}
                                  </span>
                                )}
                              </div>
                            )}

                            {/* Hint callout */}
                            {qItem.hint && (
                              <div
                                style={{
                                  marginTop: 10,
                                  padding: "8px 12px",
                                  background: "var(--paper-deep)",
                                  borderRadius: 8,
                                  fontSize: 12,
                                  color: "var(--ink-soft)",
                                  borderLeft: "3px solid var(--rule)",
                                }}
                              >
                                <span style={{ fontWeight: 700, color: "var(--ink-mute)" }}>🔍 Hint: </span>
                                {qItem.hint}
                              </div>
                            )}

                            {/* Explanation callout */}
                            {qItem.explanation && (
                              <div
                                style={{
                                  marginTop: 12,
                                  padding: "10px 13px",
                                  background: "rgba(var(--plum-rgb,130,100,255),.08)",
                                  borderRadius: 9,
                                  fontSize: 13,
                                  color: "var(--ink-soft)",
                                  borderLeft: "3px solid var(--plum)",
                                }}
                              >
                                <span style={{ fontWeight: 700, color: "var(--plum)" }}>💡 Explanation: </span>
                                {qItem.explanation}
                              </div>
                            )}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </>
              )}
            </div>
          )}
        </div>

        {/* Footer */}
        <div
          style={{
            padding: "12px 22px",
            borderTop: "var(--border-thin)",
            background: "var(--paper-card)",
            display: "flex",
            justifyContent: "flex-end",
            gap: 10,
            flexShrink: 0,
          }}
        >
          <button className="btn btn-ghost" onClick={onClose} style={{ padding: "8px 20px", fontSize: 13 }}>
            Close Review
          </button>
        </div>
      </Themed>
    </div>
  );
};
window.QuizReviewModal = QuizReviewModal;

// ── Student: Quiz ─────────────────────────────────────────────────────────────
const StudentQuiz = ({ theme = "", go, session }) => {
  const sid = session?.studentId;
  const [quizList, setQuizList] = React.useState([]);
  const [quizListLoading, setQuizListLoading] = React.useState(true);
  const [activeQuizId, setActiveQuizId] = React.useState(null);
  const [takingQuiz, setTakingQuiz] = React.useState(false);
  const [reviewQuizId, setReviewQuizId] = React.useState(null);

  const loadQuizList = React.useCallback(() => {
    if (!sid) { setQuizListLoading(false); return; }
    apiFetch(`/quizzes?student=${sid}`)
      .then(r => r.ok ? r.json() : [])
      .then(d => {
        setQuizList(Array.isArray(d) ? d : []);
        setQuizListLoading(false);
      })
      .catch(() => setQuizListLoading(false));
  }, [sid]);

  React.useEffect(() => {
    loadQuizList();
  }, [loadQuizList]);

  const activeQuiz = activeQuizId ? quizList.find(q => q.id === activeQuizId) : null;

  const [questions, setQuestions] = React.useState([]);
  const [questionsLoading, setQuestionsLoading] = React.useState(false);
  const [curr, setCurr] = React.useState(0);
  const [answers, setAnswers] = React.useState({});
  const [submitted, setSubmitted] = React.useState(false);
  const [submitting, setSubmitting] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [timing, setTiming] = React.useState(null);
  const [timeLeft, setTimeLeft] = React.useState(null);
  const [quizError, setQuizError] = React.useState("");
  const [preStartQuiz, setPreStartQuiz] = React.useState(null);
  const [showHint, setShowHint] = React.useState(false);

  const q = questions?.[curr];

  const startQuizAttempt = (qz) => {
    setActiveQuizId(qz.id);
    setTakingQuiz(true);
    setCurr(0);
    setAnswers({});
    setSubmitted(false);
    setResult(null);
    setQuizError("");
    setTiming(null);
    setTimeLeft(null);
    setShowHint(false);
    setQuestionsLoading(true);

    // Fetch questions
    apiFetch(`/quizzes/${qz.id}/questions`)
      .then(r => r.ok ? r.json() : [])
      .then(d => {
        setQuestions(Array.isArray(d) ? d : []);
        setQuestionsLoading(false);
      })
      .catch(() => setQuestionsLoading(false));

    // Call start endpoint to register start time and receive deadline
    apiFetch(`/quizzes/${qz.id}/start`, { method: "POST" })
      .then(async r => {
        const d = await r.json().catch(() => null);
        if (!r.ok) {
          setQuizError(d?.error || "Could not start quiz");
        } else if (d) {
          setTiming(d);
          if (d.deadline) {
            const rem = Math.max(0, Math.floor((new Date(d.deadline).getTime() - Date.now()) / 1000));
            setTimeLeft(rem);
          } else {
            setTimeLeft(null);
          }
          loadQuizList();
        }
      })
      .catch(() => {});
  };

  const submitRef = React.useRef(null);

  const submit = async () => {
    if (submitting || !activeQuiz || submitted) return;
    setSubmitting(true);
    const payload = {
      quiz_id: activeQuiz.id,
      answers: (questions || [])
        .map((qq, i) => ({ question_id: qq.id, answer: answers[i] }))
        .filter(a => a.answer != null && a.answer !== ""),
    };
    try {
      const r = await apiFetch("/quiz-results", { method: "POST", body: JSON.stringify(payload) });
      const d = await r.json().catch(() => null);
      if (r.ok && d) setResult(d);
      // Reload questions so explanations (unlocked post-quiz) are retrieved
      const qRes = await apiFetch(`/quizzes/${activeQuiz.id}/questions`);
      if (qRes.ok) {
        const qData = await qRes.json();
        if (Array.isArray(qData)) setQuestions(qData);
      }
      loadQuizList();
    } catch { /* fall through to results screen */ }
    setSubmitted(true);
    setSubmitting(false);
  };
  submitRef.current = submit;

  React.useEffect(() => {
    if (timeLeft == null || submitted || !takingQuiz) return;
    if (timeLeft <= 0) {
      submitRef.current?.();
      return;
    }
    const timer = setInterval(() => {
      setTimeLeft(prev => {
        if (prev <= 1) {
          clearInterval(timer);
          submitRef.current?.();
          return 0;
        }
        return prev - 1;
      });
    }, 1000);
    return () => clearInterval(timer);
  }, [timeLeft != null, submitted, takingQuiz]);

  const fmtTime = sec => {
    if (sec == null) return null;
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}:${s < 10 ? "0" : ""}${s}`;
  };

  if (quizListLoading) return <Spinner/>;

  // ── LOBBY VIEW (Card list) ──────────────────────────────────────────────────
  if (!takingQuiz || !activeQuiz) {
    if (preStartQuiz) {
      return (
        <Themed theme={theme} style={{ width:"100%", height:"100%", display:"flex", flexDirection:"column", background:"var(--paper)", overflow:"auto" }}>
          <div style={{ padding:"16px 24px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
            <button className="btn btn-ghost" onClick={() => setPreStartQuiz(null)} style={{ padding:"6px 14px", fontSize:12 }}>
              ← All Quizzes
            </button>
            <div className="display" style={{ fontSize:18 }}>Quiz Instructions</div>
          </div>
          <div style={{ flex:1, display:"flex", alignItems:"center", justifyContent:"center", padding:24 }}>
            <div className="card" style={{ maxWidth:540, width:"100%", padding:32 }}>
              <div style={{ fontSize:32, marginBottom:12 }}>📋</div>
              <div className="display" style={{ fontSize:26, marginBottom:6 }}>{preStartQuiz.title}</div>
              <div style={{ fontSize:13, color:"var(--ink-mute)", marginBottom:20 }}>
                {preStartQuiz.course || "General"} {preStartQuiz.batch ? `· ${preStartQuiz.batch}` : ""}
              </div>

              <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:12, padding:14, background:"var(--paper-deep)", borderRadius:12, marginBottom:20 }}>
                <div>
                  <div style={{ fontSize:11, color:"var(--ink-mute)", fontWeight:700 }}>QUESTIONS</div>
                  <div style={{ fontSize:16, fontWeight:800, marginTop:2 }}>{preStartQuiz.questions || "—"} questions</div>
                </div>
                <div>
                  <div style={{ fontSize:11, color:"var(--ink-mute)", fontWeight:700 }}>TIME LIMIT</div>
                  <div style={{ fontSize:16, fontWeight:800, marginTop:2 }}>
                    {preStartQuiz.timer_enabled === false ? "Untimed (No limit)" : (preStartQuiz.timeLimit || "20 minutes")}
                  </div>
                </div>
              </div>

              <div style={{ marginBottom:24 }}>
                <div style={{ fontSize:12, fontWeight:700, color:"var(--ink-mute)", marginBottom:8, letterSpacing:".05em" }}>INSTRUCTIONS</div>
                <div style={{ fontSize:14, lineHeight:1.6, color:"var(--ink-soft)", whiteSpace:"pre-wrap", background:"var(--paper-card)", padding:16, borderRadius:10, border:"var(--border-thin)" }}>
                  {preStartQuiz.instructions || "Please read each question carefully before answering. Once you start, answer all questions and click Submit when finished."}
                </div>
              </div>

              <div style={{ display:"flex", gap:12, justifyContent:"flex-end" }}>
                <button className="btn btn-ghost" onClick={() => setPreStartQuiz(null)} style={{ padding:"10px 20px" }}>
                  Cancel
                </button>
                <button className="btn btn-primary" onClick={() => { const qz = preStartQuiz; setPreStartQuiz(null); startQuizAttempt(qz); }} style={{ padding:"10px 24px", fontWeight:700 }}>
                  Start Quiz Now →
                </button>
              </div>
            </div>
          </div>
        </Themed>
      );
    }

    return (
      <Themed theme={theme} style={{ width:"100%", height:"100%", display:"flex", flexDirection:"column", background:"var(--paper)", overflow:"auto" }}>
        <div style={{ padding:"16px 24px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
          <div>
            <div className="display" style={{ fontSize:22 }}>My Quizzes</div>
            <div style={{ fontSize:12, color:"var(--ink-mute)" }}>{quizList.length} assigned {quizList.length === 1 ? "quiz" : "quizzes"}</div>
          </div>
          <div style={{ flex:1 }}/>
          <button className="btn btn-ghost" onClick={() => go && go("/app/student")} style={{ padding:"6px 14px", fontSize:12 }}>
            ← Dashboard
          </button>
        </div>

        <div style={{ flex:1, padding:24, maxWidth:900, width:"100%", margin:"0 auto", boxSizing:"border-box" }}>
          {quizList.length === 0 ? (
            <div style={{ textAlign:"center", padding:"60px 20px" }}>
              <div style={{ fontSize:56, marginBottom:16 }}>🧩</div>
              <div className="display" style={{ fontSize:28, marginBottom:8 }}>You're all caught up!</div>
              <div style={{ color:"var(--ink-soft)", fontSize:14 }}>No quizzes assigned yet. Check back after your next class.</div>
            </div>
          ) : (
            <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(280px, 1fr))", gap:16 }}>
              {quizList.map(qz => {
                const isCompleted = qz.status === "completed";
                const isInProgress = qz.status === "in_progress";
                const isDeadlinePassed = qz.closes_at && new Date(qz.closes_at) < new Date();
                const isLateMissed = !isCompleted && isDeadlinePassed;

                return (
                  <div key={qz.id} className="card-flat" style={{
                    padding:20,
                    borderRadius:14,
                    display:"flex",
                    flexDirection:"column",
                    justifyContent:"space-between",
                    gap:14,
                    border: isCompleted ? "1.5px solid var(--moss)" : isInProgress ? "1.5px solid var(--gold)" : "var(--border-thin)",
                    background:"var(--paper-card)",
                    position:"relative",
                  }}>
                    <div>
                      <div style={{ display:"flex", alignItems:"flex-start", justifyContent:"space-between", gap:8, marginBottom:8 }}>
                        <div style={{ fontWeight:800, fontSize:16, lineHeight:1.3 }}>{qz.title}</div>
                        {isCompleted ? (
                          <span style={{ fontSize:11, fontWeight:800, padding:"3px 8px", borderRadius:999, background:"var(--moss)", color:"white", whiteSpace:"nowrap" }}>
                            ✓ {qz.score != null ? `${qz.score}%` : "Done"}
                          </span>
                        ) : isInProgress ? (
                          <span style={{ fontSize:11, fontWeight:800, padding:"3px 8px", borderRadius:999, background:"var(--gold)", color:"white", whiteSpace:"nowrap" }}>
                            ● In Progress
                          </span>
                        ) : isLateMissed ? (
                          <span style={{ fontSize:11, fontWeight:800, padding:"3px 8px", borderRadius:999, background:"var(--coral)", color:"white", whiteSpace:"nowrap" }}>
                            🔒 Closed
                          </span>
                        ) : (
                          <span style={{ fontSize:11, fontWeight:700, padding:"3px 8px", borderRadius:999, background:"var(--paper-deep)", color:"var(--ink-mute)", whiteSpace:"nowrap" }}>
                            ⏳ Not Started
                          </span>
                        )}
                      </div>

                      <div style={{ fontSize:12, color:"var(--ink-mute)", marginBottom:12 }}>
                        {qz.course || "General"} {qz.batch ? `· ${qz.batch}` : ""}
                      </div>

                      <div style={{ display:"flex", flexDirection:"column", gap:6, fontSize:12, color:"var(--ink-soft)" }}>
                        <div style={{ display:"flex", alignItems:"center", gap:6 }}>
                          <span>⏱️</span>
                          <span>Time Limit: <strong>{qz.timer_enabled === false ? "Untimed" : (qz.timeLimit || "20 minutes")}</strong></span>
                        </div>
                        <div style={{ display:"flex", alignItems:"center", gap:6 }}>
                          <span>📝</span>
                          <span>{qz.questions || 5} Questions</span>
                        </div>
                        {qz.closes_at && (
                          <div style={{ display:"flex", alignItems:"center", gap:6, color: isLateMissed ? "var(--coral)" : "var(--ink-soft)" }}>
                            <span>📅</span>
                            <span>Deadline: <strong>{new Date(qz.closes_at).toLocaleString("en-IN", { day:"numeric", month:"short", hour:"2-digit", minute:"2-digit" })}</strong></span>
                          </div>
                        )}
                        {isCompleted && qz.timeTaken && (
                          <div style={{ display:"flex", alignItems:"center", gap:6, fontSize:11, color:"var(--ink-mute)" }}>
                            <span>🏁</span>
                            <span>Completed in: {qz.timeTaken}</span>
                          </div>
                        )}
                      </div>
                    </div>

                    <div style={{ marginTop:4 }}>
                      {isCompleted ? (
                        <div style={{ display:"flex", flexDirection:"column", gap:8 }}>
                          <button
                            onClick={() => setReviewQuizId(qz.id)}
                            className="btn btn-primary"
                            style={{ width:"100%", padding:"9px 0", fontSize:13, fontWeight:700, borderRadius:10 }}
                          >
                            👁 Review Answers
                          </button>
                          {qz.allow_retakes && (
                            <button
                              onClick={() => setPreStartQuiz(qz)}
                              className="btn btn-ghost"
                              style={{ width:"100%", padding:"8px 0", fontSize:12, fontWeight:700, borderRadius:10 }}
                            >
                              ♻ Retake Quiz
                            </button>
                          )}
                        </div>
                      ) : isLateMissed ? (
                        <button
                          disabled
                          style={{
                            width:"100%",
                            padding:"10px 0",
                            fontSize:13,
                            fontWeight:700,
                            borderRadius:10,
                            background:"var(--paper-deep)",
                            color:"var(--coral)",
                            border:"none",
                            cursor:"not-allowed",
                            opacity:0.7,
                          }}
                        >
                          Deadline Passed
                        </button>
                      ) : isInProgress ? (
                        <button
                          onClick={() => startQuizAttempt(qz)}
                          className="btn btn-primary"
                          style={{ width:"100%", padding:"10px 0", fontSize:13, fontWeight:700, borderRadius:10 }}
                        >
                          Resume Quiz →
                        </button>
                      ) : (
                        <button
                          onClick={() => setPreStartQuiz(qz)}
                          className="btn btn-primary"
                          style={{ width:"100%", padding:"10px 0", fontSize:13, fontWeight:700, borderRadius:10 }}
                        >
                          Open & Give Quiz →
                        </button>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        {reviewQuizId && (
          <QuizReviewModal
            quizId={reviewQuizId}
            studentId={sid}
            onClose={() => { setReviewQuizId(null); loadQuizList(); }}
            theme={theme}
          />
        )}
      </Themed>
    );
  }

  // ── QUIZ-TAKING HEADER ──────────────────────────────────────────────────────
  const QuizHeader = () => (
    <div style={{ padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
      <button
        onClick={() => { setTakingQuiz(false); loadQuizList(); }}
        className="btn btn-ghost"
        style={{ padding:"5px 12px", fontSize:12 }}
      >
        ← All Quizzes
      </button>
      <div>
        <div className="display" style={{ fontSize:18 }}>Quiz · {activeQuiz?.title || "Quiz"}</div>
        <div style={{ fontSize:12, color:"var(--ink-mute)" }}>{activeQuiz?.course || ""} {activeQuiz?.batch ? `· ${activeQuiz.batch}` : ""}</div>
      </div>
      <div style={{ flex:1 }}/>
      {activeQuiz?.timer_enabled === false && !submitted ? (
        <span className="chip" style={{ background:"var(--paper-deep)", color:"var(--ink-mute)", fontWeight:700, fontSize:12 }}>
          ⏱️ Untimed
        </span>
      ) : timeLeft != null && !submitted ? (
        <span className="chip" style={{ background: timeLeft < 120 ? "var(--coral)" : "var(--plum)", color:"white", fontWeight:700, fontSize:12 }}>
          ⏱️ {fmtTime(timeLeft)}
        </span>
      ) : null}
      {!submitted && (questions || []).length > 0 && (
        <span className="mono" style={{ fontSize:12, color:"var(--ink-mute)" }}>Q {curr+1} / {questions.length}</span>
      )}
    </div>
  );

  if (quizError) return (
    <Themed theme={theme} style={{ width:"100%", height:"100%", display:"flex", flexDirection:"column", background:"var(--paper)" }}>
      <QuizHeader/>
      <div style={{ flex:1, display:"flex", alignItems:"center", justifyContent:"center" }}>
        <div style={{ textAlign:"center", maxWidth:420, padding:24 }}>
          <div style={{ fontSize:56, marginBottom:16 }}>🔒</div>
          <div className="display" style={{ fontSize:24, marginBottom:8 }}>Quiz Unavailable</div>
          <div style={{ color:"var(--coral)", fontSize:14, marginBottom:16 }}>{quizError}</div>
          <button className="btn btn-ghost" onClick={() => { setTakingQuiz(false); loadQuizList(); }}>← Back to Quizzes</button>
        </div>
      </div>
    </Themed>
  );

  if (questionsLoading) return <Spinner/>;

  if (!q && !submitted) return (
    <Themed theme={theme} style={{ width:"100%", height:"100%", display:"flex", flexDirection:"column", background:"var(--paper)" }}>
      <QuizHeader/>
      <div style={{ flex:1, display:"flex", alignItems:"center", justifyContent:"center" }}>
        <div style={{ textAlign:"center", maxWidth:360 }}>
          <div style={{ fontSize:56, marginBottom:16 }}>🧩</div>
          <div className="display" style={{ fontSize:28, marginBottom:8 }}>No questions yet</div>
          <div style={{ color:"var(--ink-soft)", fontSize:14, marginBottom:16 }}>This quiz has no questions added yet. Check back later.</div>
          <button className="btn btn-ghost" onClick={() => { setTakingQuiz(false); loadQuizList(); }}>← Back to Quizzes</button>
        </div>
      </div>
    </Themed>
  );

  // ── SUBMISSION RESULT SCREEN ───────────────────────────────────────────────
  if (submitted) {
    return (
      <QuizReviewModal
        quizId={activeQuiz?.id}
        studentId={sid}
        onClose={() => {
          setTakingQuiz(false);
          setSubmitted(false);
          setActiveQuizId(null);
          loadQuizList();
        }}
        theme={theme}
      />
    );
  }


  // ── ACTIVE QUIZ-TAKING INTERFACE ────────────────────────────────────────────
  return (
    <Themed theme={theme} style={{ width:"100%", height:"100%", display:"flex", flexDirection:"column", background:"var(--paper)" }}>
      <QuizHeader/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", padding:32, overflow:"auto" }}>
        <div style={{ width:"100%", maxWidth:560 }}>
          <div style={{ display:"flex", gap:4, marginBottom:20 }}>
            {(questions || []).map((_,i) => (
              <div key={i} style={{ flex:1, height:4, borderRadius:2, background: i < curr ? "var(--moss)" : i===curr ? "var(--coral)" : "var(--paper-deep)", border:"1px solid var(--rule)" }}/>
            ))}
          </div>
          <div className="card" style={{ padding:28 }}>
            {q.video_url && (
              <div style={{ marginBottom:16 }}>
                <SafeYouTube url={q.video_url} title="Question video"/>
              </div>
            )}
            {q.image_ref && window.QuizQImage && (
              <div style={{ marginBottom:16 }}>
                <window.QuizQImage qid={q.id} style={{ maxWidth:"100%", maxHeight:240, borderRadius:12, display:"block" }}/>
              </div>
            )}
            <div className="display" style={{ fontSize:22, lineHeight:1.3, marginBottom:22 }}>{q.q}</div>
            {q.hint && (
              <div style={{ marginBottom:18 }}>
                <button
                  type="button"
                  onClick={() => setShowHint(h => !h)}
                  className="btn btn-ghost"
                  style={{ fontSize:12, padding:"4px 10px", borderRadius:8, color:"var(--gold)", border:"1px dashed var(--gold)", display:"inline-flex", alignItems:"center", gap:6 }}
                >
                  💡 {showHint ? "Hide Hint" : "Show Hint"}
                </button>
                {showHint && (
                  <div style={{ marginTop:8, padding:"10px 14px", background:"var(--paper-deep)", borderRadius:8, borderLeft:"3px solid var(--gold)", fontSize:13, color:"var(--ink-soft)" }}>
                    <strong>Hint:</strong> {q.hint}
                  </div>
                )}
              </div>
            )}
            {(!q.type || q.type === "mcq") && (
              <div style={{ display:"flex", flexDirection:"column", gap:10 }}>
                {q.opts && q.opts.map((opt,oi) => (
                  <button key={oi} onClick={() => setAnswers(a => ({ ...a, [curr]: oi }))} style={{
                    padding:"14px 18px", borderRadius:12, border:"var(--border)", textAlign:"left",
                    background: answers[curr]===oi ? "var(--coral)" : "var(--paper-card)",
                    color: answers[curr]===oi ? "white" : "var(--ink)",
                    fontWeight: answers[curr]===oi ? 700 : 500, fontSize:14, cursor:"pointer",
                  }}>{opt}</button>
                ))}
              </div>
            )}
            {(q.type === "paragraph" || q.type === "video") && (
              <textarea
                value={answers[curr] || ""}
                onChange={e => setAnswers(a => ({ ...a, [curr]: e.target.value }))}
                placeholder="Write your answer here…"
                style={{ width:"100%", minHeight:100, padding:"12px 14px", border:"var(--border-thin)", borderRadius:12, background:"var(--paper-card)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", resize:"vertical", outline:"none", boxSizing:"border-box" }}
              />
            )}
            <div style={{ display:"flex", justifyContent:"space-between", marginTop:22 }}>
              <button className="btn btn-ghost" onClick={() => { setShowHint(false); setCurr(c => Math.max(0,c-1)); }} disabled={curr===0} style={{ padding:"10px 18px", fontSize:13 }}>← Back</button>
              {curr < (questions || []).length-1
                ? <button className="btn btn-primary" onClick={() => { setShowHint(false); setCurr(c => c+1); }} disabled={answers[curr]==null || answers[curr]===""} style={{ padding:"10px 22px", fontSize:13 }}>Next →</button>
                : <button className="btn btn-primary" onClick={submit} disabled={submitting || answers[curr]==null || answers[curr]===""} style={{ padding:"10px 22px", fontSize:13 }}>{submitting ? "Submitting…" : "Submit quiz"}</button>}
            </div>
          </div>
        </div>
      </div>
    </Themed>
  );
};

// ── Student: Certificates ─────────────────────────────────────────────────────
const StudentCertificates = ({ theme = "", go, session }) => {
  const sid = session?.studentId;
  const { data: CERTIFICATES } = useApi(sid ? `/certificates/${sid}` : "/certificates/0");
  return (
  <Themed theme={theme} style={{ width:"100%", height:"100%", background:"var(--paper)" }}>
    <div style={{ padding:"14px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
      <div className="display" style={{ fontSize:20 }}>My Certificates</div>
      <div style={{ flex:1 }}/>
      <span style={{ fontSize:12, color:"var(--ink-mute)" }}>{CERTIFICATES.length} earned</span>
    </div>
    <div style={{ padding:28, display:"grid", gridTemplateColumns:"repeat(auto-fit, minmax(300px, 1fr))", gap:20 }}>
      {CERTIFICATES.map((c,i) => (
        <div key={i} className="card" style={{ padding:0, overflow:"hidden", position:"relative" }}>
          <div style={{ background:c.color, padding:"28px 28px 18px", color:"white", position:"relative", overflow:"hidden" }}>
            <div style={{ position:"absolute", top:-30, right:-30, width:120, height:120, borderRadius:"50%", background:"rgba(255,255,255,.1)" }}/>
            <div style={{ position:"absolute", bottom:-20, left:-10, width:80, height:80, borderRadius:"50%", background:"rgba(255,255,255,.08)" }}/>
            <div style={{ position:"relative" }}>
              <div style={{ width:44, height:44, borderRadius:12, background:"rgba(255,255,255,.25)", border:"1.5px solid rgba(255,255,255,.4)", display:"grid", placeItems:"center", marginBottom:12 }}>
                {I.trophy({ size:22 })}
              </div>
              <div className="display" style={{ fontSize:24, lineHeight:1.1 }}>{c.title}</div>
              <div style={{ fontSize:13, opacity:0.9, marginTop:4 }}>{c.course}</div>
            </div>
          </div>
          <div style={{ padding:"16px 28px", display:"flex", alignItems:"center", justifyContent:"space-between" }}>
            <div>
              <div style={{ fontSize:11, color:"var(--ink-mute)", fontFamily:"var(--font-mono)" }}>ISSUED {c.issued}</div>
              <a href={`#/verify/${c.id}`} title="Public verification page" style={{ fontSize:11, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", marginTop:2, display:"inline-block", textDecoration:"underline" }}>{c.id}</a>
            </div>
            <button onClick={()=>downloadCertificate({ ...c, name: session?.name })} className="btn btn-ghost" style={{ padding:"6px 12px", fontSize:12 }}>{I.upload({ size:12 })} Download</button>
          </div>
        </div>
      ))}
      <div className="card" style={{ padding:28, display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", border:"2px dashed var(--rule)", background:"transparent", minHeight:160, gap:12 }}>
        <div style={{ width:44, height:44, borderRadius:12, background:"var(--paper-deep)", display:"grid", placeItems:"center", color:"var(--ink-mute)" }}>{I.lock({ size:22 })}</div>
        <div style={{ textAlign:"center" }}>
          <div style={{ fontWeight:700, fontSize:14 }}>Next: Web Developer</div>
          <div style={{ fontSize:12, color:"var(--ink-mute)", marginTop:4 }}>Complete Web · Intermediate to unlock</div>
        </div>
      </div>
    </div>
  </Themed>
  );
};

// ── Student: Discussion Forum ─────────────────────────────────────────────────
const StudentForum = ({ theme = "", go, session }) => {
  const { data: initThreads, loading } = useApi("/forum/threads");
  const [threads, setThreads] = React.useState(null);
  const [active, setActive]   = React.useState(null);
  const [replies, setReplies] = React.useState([]);
  const [replyText, setReplyText] = React.useState("");
  const [sending, setSending] = React.useState(false);
  const [showNew, setShowNew] = React.useState(false);
  const [newTitle, setNewTitle] = React.useState("");
  const [newTag, setNewTag]   = React.useState("question");
  const FORUM_THREADS = threads ?? initThreads;
  const refreshThreads = () => apiFetch("/forum/threads").then(r=>r.json()).then(setThreads).catch(()=>{});
  const loadReplies = (id) => apiFetch(`/forum/threads/${id}/replies`).then(r=>r.json()).then(setReplies).catch(()=>{});
  React.useEffect(() => {
    if (!active) { setReplies([]); return; }
    loadReplies(active);
  }, [active]);
  const sendReply = async () => {
    if (!replyText.trim() || !active || sending) return;
    setSending(true);
    // Author is derived server-side from the session; we only send the text.
    await apiFetch(`/forum/threads/${active}/replies`, { method:"POST", body: JSON.stringify({ text: replyText }) });
    setReplyText("");
    await loadReplies(active);
    await refreshThreads(); // keep reply counts current
    setSending(false);
  };
  const createThread = async e => {
    e.preventDefault();
    if (!newTitle.trim()) return;
    const res = await apiFetch("/forum/threads", { method:"POST", body: JSON.stringify({ title: newTitle, tag: newTag }) });
    const created = await res.json().catch(()=>null);
    setNewTitle(""); setShowNew(false);
    await refreshThreads();
    if (created && created.id) setActive(created.id);
  };
  const thread = active ? FORUM_THREADS.find(t => t.id === active) : null;
  if (loading) return <Spinner/>;
  return (
    <Themed theme={theme} style={{ width:"100%", height:"100%", background:"var(--paper)", display:"flex", flexDirection:"column" }}>
      {showNew && (
        <Modal title="New thread" onClose={()=>setShowNew(false)}>
          <form onSubmit={createThread}>
            <FormField label="TITLE / QUESTION">
              <input required style={inputStyle} value={newTitle} onChange={e=>setNewTitle(e.target.value)} placeholder="e.g. How do I use a for loop?"/>
            </FormField>
            <FormField label="TAG">
              <select style={selectStyle} value={newTag} onChange={e=>setNewTag(e.target.value)}>
                {["question","help","idea","showcase"].map(t=><option key={t} value={t}>{t}</option>)}
              </select>
            </FormField>
            <div style={{ display:"flex", gap:10, justifyContent:"flex-end", marginTop:4 }}>
              <button type="button" onClick={()=>setShowNew(false)} className="btn btn-ghost">Cancel</button>
              <button type="submit" className="btn btn-primary">Post thread</button>
            </div>
          </form>
        </Modal>
      )}
      <div style={{ padding:"14px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
        <div className="display" style={{ fontSize:20 }}>Community Forum</div>
        <div style={{ flex:1 }}/>
        <button onClick={()=>setShowNew(true)} className="btn btn-primary" style={{ padding:"6px 14px", fontSize:12 }}>{I.plus({ size:14 })} New thread</button>
      </div>
      <div style={{ flex:1, display:"grid", gridTemplateColumns: active ? "1fr 1.4fr" : "1fr", overflow:"hidden" }}>
        <div style={{ overflow:"auto", padding:20, display:"flex", flexDirection:"column", gap:10 }}>
          {FORUM_THREADS.map(t => (
            <div key={t.id} onClick={() => setActive(active===t.id?null:t.id)} className="card" style={{ padding:16, cursor:"pointer", border: active===t.id ? "2px solid var(--coral)" : "var(--border)" }}>
              <div style={{ display:"flex", alignItems:"flex-start", gap:10 }}>
                <Avatar name={(t.author||"?")[0]} color={t.color||"var(--sky)"} size={32}/>
                <div style={{ flex:1, minWidth:0 }}>
                  <div style={{ fontWeight:700, fontSize:14, lineHeight:1.3 }}>{t.title}</div>
                  <div style={{ display:"flex", gap:8, marginTop:6, alignItems:"center" }}>
                    <span style={{ fontSize:11, color:"var(--ink-mute)" }}>{t.author} · {t.time}</span>
                    <span className="chip flat" style={{ fontSize:10, padding:"1px 6px" }}>{t.tag}</span>
                    {t.solved && <span className="chip flat" style={{ fontSize:10, padding:"1px 6px", background:"var(--moss)", color:"white" }}>solved</span>}
                    <span style={{ marginLeft:"auto", fontSize:11, color:"var(--ink-mute)" }}>{t.replies} replies</span>
                  </div>
                </div>
              </div>
            </div>
          ))}
        </div>
        {thread && (
          <div style={{ borderLeft:"var(--border-thin)", overflow:"auto", padding:20, background:"var(--paper-card)" }}>
            <div style={{ marginBottom:16 }}>
              <div className="display" style={{ fontSize:20, lineHeight:1.3 }}>{thread.title}</div>
              <div style={{ display:"flex", gap:8, marginTop:8, alignItems:"center" }}>
                <Avatar name={(thread.author||"?")[0]} color={thread.color||"var(--sky)"} size={24}/>
                <span style={{ fontSize:12, color:"var(--ink-mute)" }}>{thread.author || "Staff"} · {thread.time} ago</span>
                <span className="chip flat" style={{ fontSize:10, padding:"1px 6px" }}>{thread.tag}</span>
              </div>
            </div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", letterSpacing:".06em", marginBottom:12 }}>
              {replies.length} {replies.length === 1 ? "REPLY" : "REPLIES"}
            </div>
            {replies.length === 0 && (
              <div style={{ padding:14, background:"var(--paper-deep)", borderRadius:10, border:"var(--border-thin)", fontSize:13, color:"var(--ink-mute)", marginBottom:14 }}>
                No replies yet — be the first to help out!
              </div>
            )}
            {replies.map((r,i) => (
              <div key={i} style={{ display:"flex", gap:8, marginBottom:12 }}>
                <Avatar name={(r.author||"?")[0]} color={ r.teacher ? "var(--moss)" : "var(--sky)"} size={28}/>
                <div style={{ flex:1 }}>
                  <div style={{ display:"flex", alignItems:"center", gap:6, marginBottom:4 }}>
                    <span style={{ fontWeight:700, fontSize:13 }}>{r.author}</span>
                    {r.teacher && <span className="chip flat" style={{ fontSize:9, padding:"1px 5px", background:"var(--moss)", color:"white" }}>Teacher</span>}
                  </div>
                  <div style={{ padding:"10px 12px", background:"var(--paper-deep)", borderRadius:10, fontSize:13, lineHeight:1.5 }}>{r.text}</div>
                </div>
              </div>
            ))}
            <div style={{ display:"flex", gap:8, marginTop:8 }}>
              <input value={replyText} onChange={e=>setReplyText(e.target.value)} onKeyDown={e=>e.key==="Enter"&&sendReply()} placeholder="Write a reply…" style={{ flex:1, padding:"8px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-deep)", fontSize:13, fontFamily:"var(--font-ui)", color:"var(--ink)", outline:"none" }}/>
              <button onClick={sendReply} disabled={sending} className="btn btn-primary" style={{ padding:"8px 14px", fontSize:12, opacity: sending ? 0.6 : 1 }}>{I.send({ size:14 })}</button>
            </div>
          </div>
        )}
      </div>
    </Themed>
  );
};

// ── Student: Homework Submission ──────────────────────────────────────────────
const StudentHomework = ({ theme = "", go, session }) => {
  const sid = session?.studentId;
  const { data: initHomework } = useApi(sid ? `/homework?student=${sid}` : "/homework?student=0");
  const [homework, setHomework] = React.useState(null);
  const HOMEWORK = homework ?? initHomework;
  const [active, setActive]     = React.useState(null);
  const [answers, setAnswers]   = React.useState({});   // { [hw_id]: { code, drive_link } }
  const [subFiles, setSubFiles] = React.useState({});   // { [hw_id]: { id, title } } uploaded answer file
  const [uploadingId, setUploadingId] = React.useState(null);
  const [submitting, setSubmitting] = React.useState(false);

  // Upload a file as the answer. Stored via the student-safe endpoint, which
  // returns a course_files id we then attach to the submission.
  const uploadSubFile = (hw, file) => {
    if (!file || !sid) return;
    setUploadingId(hw.id);
    const ext = (file.name.split(".").pop() || "").toLowerCase();
    const reader = new FileReader();
    reader.onload = async () => {
      const base64 = String(reader.result).split(",")[1] || "";
      const res = await apiFetch("/homework/submission-file", { method:"POST", body: JSON.stringify({ student_id: sid, title: file.name, file_type: ext, file_data: base64 }) });
      const d = await res.json().catch(()=>({}));
      setUploadingId(null);
      if (!res.ok) { alert(d.error || "Upload failed"); return; }
      setSubFiles(m => ({ ...m, [hw.id]: { id: d.id, title: d.title } }));
    };
    reader.onerror = () => setUploadingId(null);
    reader.readAsDataURL(file);
  };

  const submitHw = async hw => {
    if (!sid) return;
    setSubmitting(true);
    const a = answers[hw.id] || {};
    await apiFetch("/hw-submissions", { method:"POST", body: JSON.stringify({
      homework_id: hw.id, student_id: sid,
      code: a.code || null, drive_link: a.drive_link || null,
      file_id: (subFiles[hw.id] || {}).id || null,
    })});
    const fresh = await apiFetch(`/homework?student=${sid}`).then(r=>r.json());
    setHomework(fresh);
    setSubFiles(m => { const n = { ...m }; delete n[hw.id]; return n; });
    setActive(null); setSubmitting(false);
  };

  const openFile = async (courseId, fileId) => {
    if (!fileId) return;
    const cid = courseId || 1;
    const r = await apiFetch(`/course-files/${cid}/${fileId}/data`);
    if (!r.ok) { alert("Could not open this file."); return; }
    const { file_data, file_type } = await r.json();
    const bin = atob(file_data), bytes = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
    const mime = typeof fileMimeType === "function" ? fileMimeType(file_type) : "application/octet-stream";
    const url = URL.createObjectURL(new Blob([bytes], { type: mime }));
    window.open(url, "_blank");
  };

  return (
    <Themed theme={theme} style={{ width:"100%", height:"100%", background:"var(--paper)" }}>
      <div style={{ padding:"14px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)", display:"flex", alignItems:"center", gap:12 }}>
        <div className="display" style={{ fontSize:20 }}>Homework</div>
        <div style={{ flex:1 }}/>
        <span style={{ fontSize:12, color:"var(--ink-mute)" }}>{HOMEWORK.filter(h=>h.status==="pending").length} pending</span>
      </div>
      <div style={{ padding:22, display:"flex", flexDirection:"column", gap:12 }}>
        {HOMEWORK.length === 0 && (
          <div style={{ textAlign:"center", padding:60, color:"var(--ink-mute)" }}>
            <div style={{ fontSize:56, marginBottom:16 }}>✅</div>
            <div className="display" style={{ fontSize:28, marginBottom:8 }}>You're all caught up!</div>
            <div style={{ fontSize:14 }}>No homework assigned yet. Enjoy your free time!</div>
          </div>
        )}
        {HOMEWORK.map(hw => {
          const isPending   = hw.status === "pending";
          const isSubmitted = hw.status === "submitted";
          const isGraded    = hw.status === "graded";
          const isExpanded  = active === hw.id;

          return (
            <div key={hw.id} className="card" style={{ padding:18, border: isExpanded ? "1.5px solid var(--coral)" : "var(--border-thin)" }}>
              <div style={{ display:"flex", alignItems:"center", gap:14, flexWrap:"wrap" }}>
                <div style={{ width:44, height:44, borderRadius:12, background: isPending?"var(--coral)":isSubmitted?"var(--gold)":"var(--moss)", color:"white", border:"var(--border)", display:"grid", placeItems:"center", flexShrink:0 }}>
                  {isGraded ? I.check({ size:20 }) : isSubmitted ? I.clock({ size:20 }) : I.book({ size:20 })}
                </div>
                <div style={{ flex:1, minWidth:200 }}>
                  <div style={{ display:"flex", alignItems:"center", gap:8, flexWrap:"wrap" }}>
                    <span style={{ fontWeight:700, fontSize:15 }}>{hw.title}</span>
                    {hw.type && hw.type !== "paragraph" && (
                      <span style={{ fontSize:10, fontWeight:700, padding:"2px 7px", borderRadius:999, background: hw.type==="video"?"var(--sky-deep)":hw.type==="mcq"?"var(--plum-deep)":"var(--moss-deep)", color:"white" }}>{hw.type.toUpperCase()}</span>
                    )}
                    {isGraded && hw.score && (
                      <span style={{ fontSize:11, fontWeight:800, padding:"2px 9px", borderRadius:999, background: hw.score==="Needs redo" ? "var(--coral)" : "rgba(var(--moss-rgb,60,180,120),.15)", color: hw.score==="Needs redo" ? "white" : "var(--moss)", border:`1px solid ${hw.score==="Needs redo"?"var(--coral)":"var(--moss)"}` }}>
                        Grade: {hw.score}
                      </span>
                    )}
                  </div>
                  <div style={{ fontSize:12, color:"var(--ink-mute)", marginTop:3 }}>
                    {hw.course} · Due {hw.due}
                    {hw.is_late && <span style={{ color:"var(--coral)", fontWeight:700, marginLeft:6 }}>· Late</span>}
                  </div>
                  {/* Short feedback preview when collapsed */}
                  {isGraded && hw.feedback && !isExpanded && (
                    <div style={{ fontSize:12, color:"var(--ink-soft)", marginTop:4, display:"flex", alignItems:"center", gap:6 }}>
                      <span style={{ color:"var(--plum)", fontWeight:700 }}>💬 Feedback:</span>
                      <span style={{ overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap", maxWidth:400 }}>{hw.feedback}</span>
                    </div>
                  )}
                </div>

                <div style={{ display:"flex", alignItems:"center", gap:10, flexWrap:"wrap" }}>
                  <span className="chip flat" style={{ fontSize:11, padding:"3px 10px", background: isPending?"var(--coral)":isSubmitted?"var(--gold)":"var(--moss)", color:"white" }}>
                    {hw.status}
                  </span>
                  <span className="chip" style={{ background:"var(--gold)", fontSize:11 }}>
                    {I.bolt({ size:12 })} +{hw.xp} XP
                  </span>

                  {isPending && (
                    <button className="btn btn-primary" onClick={() => setActive(isExpanded ? null : hw.id)} style={{ padding:"6px 14px", fontSize:12 }}>
                      {isExpanded ? "Cancel" : "Submit"}
                    </button>
                  )}
                  {isSubmitted && (
                    <button className="btn btn-ghost" onClick={() => setActive(isExpanded ? null : hw.id)} style={{ padding:"6px 12px", fontSize:12 }}>
                      {isExpanded ? "Hide submission" : "View submission"}
                    </button>
                  )}
                  {isGraded && (
                    <button className="btn btn-ghost" onClick={() => setActive(isExpanded ? null : hw.id)} style={{ padding:"6px 12px", fontSize:12, fontWeight:600, color:"var(--plum)" }}>
                      {isExpanded ? "Hide feedback" : "View feedback"}
                    </button>
                  )}
                </div>
              </div>

              {/* ── EXPANDED PANELS ── */}
              {isExpanded && (
                <div style={{ marginTop:14, padding:16, background:"var(--paper-deep)", borderRadius:10, border:"var(--border-thin)" }}>

                  {/* 1. Graded Panel */}
                  {isGraded && (
                    <div>
                      {/* Teacher Feedback Callout */}
                      <div style={{ padding:"14px 16px", background:"rgba(var(--plum-rgb,130,100,255),.08)", borderRadius:10, borderLeft:"4px solid var(--plum)", marginBottom:14 }}>
                        <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:6, flexWrap:"wrap", gap:6 }}>
                          <span style={{ fontSize:11, fontWeight:800, color:"var(--plum)", letterSpacing:".06em", textTransform:"uppercase" }}>💬 Teacher Feedback</span>
                          <span style={{ fontSize:12, fontWeight:800, color: hw.score === "Needs redo" ? "var(--coral)" : "var(--moss)", background:"var(--paper-card)", padding:"2px 10px", borderRadius:999, border:"var(--border-thin)" }}>
                            Grade: {hw.score}
                          </span>
                        </div>
                        <div style={{ fontSize:13, color:"var(--ink)", lineHeight:1.6, whiteSpace:"pre-wrap" }}>
                          {hw.feedback ? hw.feedback : <span style={{ color:"var(--ink-mute)", fontStyle:"italic" }}>No written feedback was left for this submission.</span>}
                        </div>
                      </div>

                      {/* Student's Submission Content */}
                      <div style={{ padding:"12px 14px", background:"var(--paper-card)", borderRadius:10, border:"var(--border-thin)", marginBottom:12 }}>
                        <div style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)", letterSpacing:".06em", textTransform:"uppercase", marginBottom:6 }}>
                          Your Submission {hw.submitted_at && `· Submitted ${hw.submitted_at}`} {hw.is_late && <span style={{ color:"var(--coral)", fontWeight:700 }}>(Late)</span>}
                        </div>
                        {hw.submission_code && (
                          <pre style={{ margin:"6px 0 0", padding:12, background:"oklch(0.18 0.02 250)", color:"oklch(0.92 0.01 250)", borderRadius:8, fontSize:13, lineHeight:1.6, overflowX:"auto", whiteSpace:"pre-wrap" }}>
                            {hw.submission_code}
                          </pre>
                        )}
                        {hw.submission_drive_link && (
                          <div style={{ marginTop:8 }}>
                            <a href={hw.submission_drive_link} target="_blank" rel="noreferrer" style={{ display:"inline-flex", alignItems:"center", gap:6, fontSize:13, color:"var(--sky)", fontWeight:600 }}>
                              🔗 {hw.submission_drive_link}
                            </a>
                          </div>
                        )}
                        {hw.submission_file_id && (
                          <div style={{ marginTop:8 }}>
                            <button type="button" onClick={()=>openFile(hw.course_id || hw.file_course_id, hw.submission_file_id)} className="btn btn-ghost" style={{ padding:"4px 10px", fontSize:12, display:"inline-flex", alignItems:"center", gap:6 }}>
                              📎 {hw.submission_file_name || "Download submitted file"}
                            </button>
                          </div>
                        )}
                        {!hw.submission_code && !hw.submission_drive_link && !hw.submission_file_id && (
                          <div style={{ fontSize:12, color:"var(--ink-mute)", fontStyle:"italic" }}>Submission confirmed.</div>
                        )}
                      </div>

                      <button className="btn btn-ghost" onClick={() => setActive(null)} style={{ padding:"6px 14px", fontSize:12 }}>
                        Close details
                      </button>
                    </div>
                  )}

                  {/* 2. Submitted (Under Review) Panel */}
                  {isSubmitted && (
                    <div>
                      <div style={{ padding:"12px 14px", background:"rgba(var(--gold-rgb,220,160,40),.10)", borderRadius:10, borderLeft:"4px solid var(--gold)", marginBottom:14 }}>
                        <div style={{ fontSize:12, fontWeight:700, color:"var(--gold)", marginBottom:2 }}>⏳ Submission Received</div>
                        <div style={{ fontSize:13, color:"var(--ink-soft)" }}>
                          Your assignment is pending teacher review. {hw.submitted_at && `Submitted ${hw.submitted_at}.`}
                        </div>
                      </div>

                      <div style={{ padding:"12px 14px", background:"var(--paper-card)", borderRadius:10, border:"var(--border-thin)", marginBottom:12 }}>
                        <div style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)", letterSpacing:".06em", textTransform:"uppercase", marginBottom:6 }}>
                          Submitted Content {hw.is_late && <span style={{ color:"var(--coral)", fontWeight:700 }}>(Late)</span>}
                        </div>
                        {hw.submission_code && (
                          <pre style={{ margin:"6px 0 0", padding:12, background:"oklch(0.18 0.02 250)", color:"oklch(0.92 0.01 250)", borderRadius:8, fontSize:13, lineHeight:1.6, overflowX:"auto", whiteSpace:"pre-wrap" }}>
                            {hw.submission_code}
                          </pre>
                        )}
                        {hw.submission_drive_link && (
                          <div style={{ marginTop:8 }}>
                            <a href={hw.submission_drive_link} target="_blank" rel="noreferrer" style={{ display:"inline-flex", alignItems:"center", gap:6, fontSize:13, color:"var(--sky)", fontWeight:600 }}>
                              🔗 {hw.submission_drive_link}
                            </a>
                          </div>
                        )}
                        {hw.submission_file_id && (
                          <div style={{ marginTop:8 }}>
                            <button type="button" onClick={()=>openFile(hw.course_id || hw.file_course_id, hw.submission_file_id)} className="btn btn-ghost" style={{ padding:"4px 10px", fontSize:12, display:"inline-flex", alignItems:"center", gap:6 }}>
                              📎 {hw.submission_file_name || "Download submitted file"}
                            </button>
                          </div>
                        )}
                        {!hw.submission_code && !hw.submission_drive_link && !hw.submission_file_id && (
                          <div style={{ fontSize:12, color:"var(--ink-mute)", fontStyle:"italic" }}>Submission confirmed.</div>
                        )}
                      </div>

                      <button className="btn btn-ghost" onClick={() => setActive(null)} style={{ padding:"6px 14px", fontSize:12 }}>
                        Close details
                      </button>
                    </div>
                  )}

                  {/* 3. Pending Submission Form */}
                  {isPending && (
                    <div>
                      {hw.description && (
                        <div style={{ fontSize:13, color:"var(--ink-soft)", marginBottom:10, padding:"8px 12px", background:"var(--paper-card)", borderRadius:8, borderLeft:"3px solid var(--coral)" }}>
                          {hw.description}
                        </div>
                      )}
                      {hw.file_id && (
                        <button onClick={()=>openFile(hw.file_course_id, hw.file_id)} className="btn btn-ghost" style={{ marginBottom:10, padding:"7px 12px", fontSize:12, display:"inline-flex", alignItems:"center", gap:6 }}>
                          📎 {hw.file_name || "Download worksheet"}
                        </button>
                      )}
                      {(!hw.type || hw.type === "paragraph") && (
                        <div style={{ marginBottom:10 }}>
                          <div style={{ fontSize:12, color:"var(--ink-mute)", marginBottom:6 }}>Write your response:</div>
                          <textarea value={(answers[hw.id]||{}).code||""} onChange={e=>setAnswers(a=>({...a,[hw.id]:{...(a[hw.id]||{}),code:e.target.value}}))}
                            placeholder="Type your answer here…" style={{ width:"100%", minHeight:100, padding:"10px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-card)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", resize:"vertical", outline:"none", boxSizing:"border-box" }}/>
                        </div>
                      )}
                      {hw.type === "video" && hw.video_url && (
                        <div style={{ marginBottom:10 }}>
                          <SafeYouTube url={hw.video_url} title={hw.title}/>
                          <textarea value={(answers[hw.id]||{}).code||""} onChange={e=>setAnswers(a=>({...a,[hw.id]:{...(a[hw.id]||{}),code:e.target.value}}))}
                            placeholder="Your response after watching…" style={{ width:"100%", minHeight:80, padding:"10px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-card)", fontSize:14, fontFamily:"var(--font-ui)", color:"var(--ink)", resize:"vertical", outline:"none", boxSizing:"border-box", marginTop:8 }}/>
                        </div>
                      )}
                      {hw.type === "mcq" && (
                        <div style={{ padding:"12px 14px", background:"var(--paper-card)", borderRadius:8, fontSize:13, color:"var(--ink-mute)", marginBottom:10 }}>
                          📋 Your teacher will provide MCQ questions during class. Submit to confirm you've seen this assignment.
                        </div>
                      )}
                      <div style={{ marginBottom:10 }}>
                        <div style={{ fontSize:12, color:"var(--ink-mute)", marginBottom:6 }}>Upload a file <span style={{ color:"var(--ink-mute)", fontWeight:400 }}>(optional — image, PDF, doc, etc.)</span></div>
                        {subFiles[hw.id] ? (
                          <div style={{ display:"flex", alignItems:"center", gap:8, padding:"8px 10px", borderRadius:8, border:"var(--border-thin)", background:"var(--paper-card)" }}>
                            <span style={{ fontSize:16 }}>📎</span>
                            <span style={{ flex:1, fontSize:13, fontWeight:600, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{subFiles[hw.id].title}</span>
                            <button type="button" onClick={()=>setSubFiles(m=>{ const n={...m}; delete n[hw.id]; return n; })} className="btn btn-ghost" style={{ padding:"3px 10px", fontSize:11, color:"var(--coral)" }}>Remove</button>
                          </div>
                        ) : (
                          <label style={{ display:"flex", alignItems:"center", gap:8, padding:"9px 12px", borderRadius:8, border:"1.5px dashed var(--rule-bold)", cursor: uploadingId===hw.id?"default":"pointer", fontSize:13, color:"var(--ink-mute)", background:"var(--paper-card)" }}>
                            {I.plus({ size:14 })} {uploadingId===hw.id ? "Uploading…" : "Choose a file to upload"}
                            <input type="file" disabled={uploadingId===hw.id} style={{ display:"none" }} onChange={e=>{ uploadSubFile(hw, e.target.files[0]); e.target.value=""; }}/>
                          </label>
                        )}
                      </div>
                      <div style={{ marginBottom:10 }}>
                        <div style={{ fontSize:12, color:"var(--ink-mute)", marginBottom:6 }}>…or a Google Drive link <span style={{ color:"var(--ink-mute)", fontWeight:400 }}>(optional)</span></div>
                        <input value={(answers[hw.id]||{}).drive_link||""} onChange={e=>setAnswers(a=>({...a,[hw.id]:{...(a[hw.id]||{}),drive_link:e.target.value}}))}
                          placeholder="https://drive.google.com/file/…"
                          style={{ width:"100%", padding:"9px 12px", border:"var(--border-thin)", borderRadius:8, background:"var(--paper-card)", fontSize:13, fontFamily:"var(--font-ui)", color:"var(--ink)", outline:"none", boxSizing:"border-box" }}/>
                      </div>
                      <div style={{ display:"flex", gap:8, marginTop:12 }}>
                        <button className="btn btn-primary" disabled={submitting} onClick={() => submitHw(hw)} style={{ padding:"8px 18px", fontSize:12 }}>{submitting?"Submitting…":"Submit"}</button>
                        <button className="btn btn-ghost" onClick={() => setActive(null)} style={{ padding:"8px 14px", fontSize:12 }}>Cancel</button>
                      </div>
                    </div>
                  )}

                </div>
              )}
            </div>
          );
        })}
      </div>
    </Themed>
  );
};

// ── Floating Chatbot Widget ───────────────────────────────────────────────────
const ChatbotWidget = () => {
  const [open, setOpen] = React.useState(false);
  const [msgs, setMsgs] = React.useState([{ from:"bot", text:"Hi! I'm Cody 🤖 How can I help you today?" }]);
  const [input, setInput] = React.useState("");
  const RESPONSES = ["That's a great question! Your teacher Ms. Priya can help with that in your next class.","I see! Try checking the Library section for related videos.","Your next class is today at 7:00 PM. Don't forget to join the Google Meet link!","You can reach support at support@epiqminds.com — they typically respond within 2 hours."];
  const send = () => {
    if (!input.trim()) return;
    const userMsg = input;
    setMsgs(m => [...m, { from:"user", text:userMsg }]);
    setInput("");
    setTimeout(() => setMsgs(m => [...m, { from:"bot", text:RESPONSES[Math.floor(Math.random()*RESPONSES.length)] }]), 700);
  };
  return (
    <div style={{ position:"fixed", bottom:20, right:20, zIndex:999, fontFamily:"var(--font-ui)" }}>
      {open && (
        <div style={{ position:"absolute", bottom:60, right:0, width:300, background:"white", borderRadius:16, boxShadow:"0 8px 32px rgba(0,0,0,.18)", border:"1px solid rgba(0,0,0,.08)", overflow:"hidden" }}>
          <div style={{ padding:"12px 16px", background:"var(--coral)", color:"white", display:"flex", alignItems:"center", gap:8 }}>
            <div style={{ width:28, height:28, borderRadius:"50%", background:"rgba(255,255,255,.25)", display:"grid", placeItems:"center", fontSize:16 }}>🤖</div>
            <div>
              <div style={{ fontWeight:700, fontSize:13 }}>Cody · Support</div>
              <div style={{ fontSize:10, opacity:.85 }}>Always here to help</div>
            </div>
            <button onClick={() => setOpen(false)} style={{ marginLeft:"auto", border:"none", background:"transparent", color:"white", fontSize:18, cursor:"pointer", lineHeight:1 }}>×</button>
          </div>
          <div style={{ height:200, overflow:"auto", padding:12, display:"flex", flexDirection:"column", gap:8 }}>
            {msgs.map((m,i) => (
              <div key={i} style={{ display:"flex", justifyContent: m.from==="user" ? "flex-end" : "flex-start" }}>
                <div style={{ maxWidth:"80%", padding:"8px 12px", borderRadius:12, background: m.from==="user" ? "var(--coral)" : "#f0f0f0", color: m.from==="user" ? "white" : "#222", fontSize:13, lineHeight:1.4 }}>{m.text}</div>
              </div>
            ))}
          </div>
          <div style={{ padding:"8px 12px", borderTop:"1px solid #eee", display:"flex", gap:8 }}>
            <input value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => e.key==="Enter" && send()} placeholder="Ask anything…" style={{ flex:1, padding:"6px 10px", border:"1px solid #ddd", borderRadius:8, fontSize:13, outline:"none" }}/>
            <button onClick={send} style={{ padding:"6px 12px", background:"var(--coral)", color:"white", border:"none", borderRadius:8, fontSize:13, cursor:"pointer", fontWeight:700 }}>→</button>
          </div>
        </div>
      )}
      <button onClick={() => setOpen(o => !o)} style={{ width:48, height:48, borderRadius:"50%", background:"var(--coral)", color:"white", border:"2px solid white", boxShadow:"0 4px 16px rgba(0,0,0,.2)", fontSize:22, cursor:"pointer", display:"grid", placeItems:"center" }}>
        {open ? "×" : "💬"}
      </button>
    </div>
  );
};

// ── Admin: XP / Points Criteria ───────────────────────────────────────────────
const CATEGORY_ORDER = ["LMS Actions","Exploring","Hands-on","Session Tasks","Progress","Teacher Remarks"];
const CATEGORY_COLOR = {
  "LMS Actions": "var(--sky)", "Exploring": "var(--plum)", "Hands-on": "var(--moss)",
  "Session Tasks": "var(--gold)", "Progress": "var(--coral)", "Teacher Remarks": "var(--ink-soft)",
};

const AdminXPCriteria = ({ dark = true, go }) => {
  const { data: initCriteria, loading: loadC } = useApi("/admin/xp-criteria");
  const { data: initAwards,   loading: loadA } = useApi("/admin/xp-awards");
  const { data: STUDENTS } = useApi("/students");

  const [criteria, setCriteria]   = React.useState(null);
  const [awards, setAwards]       = React.useState(null);
  const [editId, setEditId]       = React.useState(null);
  const [editPts, setEditPts]     = React.useState("");
  const [saving, setSaving]       = React.useState(false);

  // Award form state
  const [awardForm, setAwardForm] = React.useState({ student_id:"", mode:"criteria", criteria_id:"", custom_reason:"", custom_pts:"", note:"" });
  const [rubric, setRubric]       = React.useState({}); // tierKey -> bool / count / seq
  const [awarding, setAwarding]   = React.useState(false);
  const [awardMsg, setAwardMsg]   = React.useState("");

  // Compute the point total for a variable (teacher-evaluated) criterion from the
  // teacher's rubric inputs. Shapes: per_unit/per_question (× count), increment
  // (base + step×(n-1)), or a set of additive/choice tiers (sum of selected).
  const computeVariable = (crit, rub) => {
    if (!crit) return 0;
    const t = crit.tiers || null;
    if (!t || crit.scaling !== "variable") return crit.points;
    if (t.per_unit != null)     return (parseInt(rub.count) || 0) * t.per_unit;
    if (t.per_question != null) return (parseInt(rub.count) || 0) * t.per_question;
    if (t.increment != null)    return crit.points + t.increment * Math.max(0, (parseInt(rub.seq) || 1) - 1);
    return Object.keys(t).reduce((sum, k) => sum + (rub[k] ? t[k] : 0), 0);
  };

  const list     = criteria ?? initCriteria;
  const awardLog = awards   ?? initAwards;

  const refresh = () => {
    apiFetch("/admin/xp-criteria").then(r=>r.json()).then(setCriteria);
    apiFetch("/admin/xp-awards").then(r=>r.json()).then(setAwards);
  };

  const startEdit = (row) => { setEditId(row.id); setEditPts(String(row.points)); };

  const saveEdit = async (row) => {
    setSaving(true);
    await apiFetch(`/admin/xp-criteria/${row.id}`, { method:"PATCH", body: JSON.stringify({ points: parseInt(editPts) }) });
    setEditId(null); setSaving(false);
    refresh();
  };

  const toggleEnabled = async (row) => {
    await apiFetch(`/admin/xp-criteria/${row.id}`, { method:"PATCH", body: JSON.stringify({ enabled: !row.enabled }) });
    refresh();
  };

  const submitAward = async e => {
    e.preventDefault();
    setAwardMsg(""); setAwarding(true);
    if (!awardForm.student_id) { setAwardMsg("Select a student."); setAwarding(false); return; }
    const student_id = parseInt(awardForm.student_id);

    if (awardForm.mode === "custom") {
      const points = parseInt(awardForm.custom_pts);
      if (!points || !awardForm.custom_reason) { setAwardMsg("Enter a reason and points."); setAwarding(false); return; }
      const res = await apiFetch("/admin/xp-award", { method:"POST", body: JSON.stringify({ student_id, points, reason: awardForm.custom_reason, criteria_id: null }) });
      if (!res.ok) { const d=await res.json().catch(()=>({})); setAwardMsg(d.error||"Failed"); setAwarding(false); return; }
      setAwardMsg(`+${points} XP awarded!`);
      setAwardForm({ student_id:"", mode:"criteria", criteria_id:"", custom_reason:"", custom_pts:"", note:"" }); setRubric({});
      setAwarding(false); refresh(); return;
    }

    // Criteria mode — fixed criteria award their base; variable ones use the rubric.
    const crit = selectedCrit;
    if (!crit) { setAwardMsg("Select a criterion."); setAwarding(false); return; }
    const points = computeVariable(crit, rubric);
    if (!points) { setAwardMsg("Set the rubric so points are greater than 0."); setAwarding(false); return; }
    const res = await apiFetch("/admin/xp-evaluate", { method:"POST", body: JSON.stringify({
      student_id, code: crit.code, points, note: awardForm.note || undefined,
    })});
    if (!res.ok) { const d=await res.json().catch(()=>({})); setAwardMsg(d.error||"Failed"); setAwarding(false); return; }
    const d = await res.json().catch(()=>({ awarded: points }));
    setAwardMsg(d.awarded ? `+${d.awarded} XP awarded!` : "Already awarded / disabled.");
    setAwardForm({ student_id:"", mode:"criteria", criteria_id:"", custom_reason:"", custom_pts:"", note:"" }); setRubric({});
    setAwarding(false); refresh();
  };

  const grouped = CATEGORY_ORDER.map(cat => ({
    cat, rows: list.filter(r => r.category === cat),
  })).filter(g => g.rows.length > 0);

  const selectedCrit = awardForm.criteria_id ? list.find(c => c.id === parseInt(awardForm.criteria_id)) : null;

  const fmtTime = ts => {
    try { return new Date(ts).toLocaleDateString("en-GB",{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"}); }
    catch { return ts; }
  };

  if (loadC) return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/xp-criteria" go={go}/>
      <div style={{ flex:1, display:"flex", alignItems:"center", justifyContent:"center" }}><Spinner/></div>
    </Themed>
  );

  return (
    <Themed className={dark ? "theme-dark" : ""} style={{ width:"100%", height:"100%", display:"flex" }}>
      <AdminSidebar active="/app/admin/xp-criteria" go={go}/>
      <div style={{ flex:1, display:"flex", flexDirection:"column", minWidth:0, background:"var(--paper)" }}>

        {/* Header */}
        <div style={{ display:"flex", alignItems:"center", gap:12, padding:"12px 22px", borderBottom:"var(--border-thin)", background:"var(--paper-card)" }}>
          <div>
            <div className="display" style={{ fontSize:20 }}>XP Criteria</div>
            <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)" }}>{list.filter(r=>r.enabled).length} active rules · award points manually or via criteria</div>
          </div>
        </div>

        <div style={{ flex:1, overflow:"auto", padding:22, display:"grid", gridTemplateColumns:"1fr 320px", gap:20, alignItems:"start" }}>

          {/* Left: criteria table */}
          <div style={{ display:"flex", flexDirection:"column", gap:16 }}>
            {grouped.map(({ cat, rows }) => (
              <div key={cat} className="card-flat" style={{ padding:0, overflow:"hidden" }}>
                <div style={{ padding:"10px 16px", background: CATEGORY_COLOR[cat] + "22", borderBottom:"var(--border-thin)", display:"flex", alignItems:"center", gap:8 }}>
                  <div style={{ width:8, height:8, borderRadius:"50%", background: CATEGORY_COLOR[cat] }}/>
                  <span className="mono" style={{ fontSize:11, fontWeight:700, letterSpacing:".06em", color:"var(--ink)" }}>{cat.toUpperCase()}</span>
                  {cat === "Difficulty" && (
                    <span style={{ fontSize:11, color:"var(--ink-mute)", marginLeft:4 }}>— bonus XP added on top of completion points</span>
                  )}
                </div>
                <table style={{ width:"100%", borderCollapse:"collapse", fontSize:13 }}>
                  <thead>
                    <tr style={{ textAlign:"left", color:"var(--ink-mute)" }}>
                      {["Criteria","Points","Enabled",""].map(h => (
                        <th key={h} style={{ padding:"8px 14px", fontWeight:600, fontSize:11, borderBottom:"var(--border-thin)" }}>{h}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {rows.map((row, i) => (
                      <tr key={row.id} style={{ borderTop: i ? "var(--border-thin)" : "none", opacity: row.enabled ? 1 : 0.45 }}>
                        <td style={{ padding:"11px 14px", fontWeight:600 }}>
                          <div style={{ display:"flex", alignItems:"center", gap:6, flexWrap:"wrap" }}>
                            <span>{row.label}</span>
                            {row.auto
                              ? <span style={{ fontSize:9, fontWeight:700, padding:"1px 6px", borderRadius:999, background:"var(--moss)", color:"white" }}>AUTO</span>
                              : <span style={{ fontSize:9, fontWeight:700, padding:"1px 6px", borderRadius:999, background:"var(--paper-deep)", color:"var(--ink-mute)", border:"var(--border-thin)" }}>{(row.scaling||"fixed").toUpperCase()}</span>}
                            {row.min_points > 0 && <span style={{ fontSize:9, color:"var(--ink-mute)" }}>min {row.min_points}</span>}
                          </div>
                          {row.notes && <div style={{ fontSize:10.5, color:"var(--ink-mute)", marginTop:3 }}>{row.notes}</div>}
                        </td>
                        <td style={{ padding:"11px 14px", fontFamily:"var(--font-mono)" }}>
                          {editId === row.id ? (
                            <div style={{ display:"flex", gap:6, alignItems:"center" }}>
                              <input
                                type="number" min="1" max="500"
                                value={editPts}
                                onChange={e => setEditPts(e.target.value)}
                                style={{ width:72, padding:"4px 8px", borderRadius:6, border:"var(--border-thin)", background:"var(--paper-deep)", fontSize:13, fontFamily:"var(--font-mono)", color:"var(--ink)", outline:"none" }}
                                autoFocus
                              />
                              <span style={{ color:"var(--ink-mute)", fontSize:12 }}>XP</span>
                              <button onClick={() => saveEdit(row)} disabled={saving} className="btn btn-primary" style={{ padding:"3px 10px", fontSize:11 }}>{saving?"…":"Save"}</button>
                              <button onClick={() => setEditId(null)} className="btn btn-ghost" style={{ padding:"3px 8px", fontSize:11 }}>Cancel</button>
                            </div>
                          ) : (
                            <span style={{ color: CATEGORY_COLOR[cat], fontWeight:700 }}>+{row.points} XP</span>
                          )}
                        </td>
                        <td style={{ padding:"11px 14px" }}>
                          <button
                            onClick={() => toggleEnabled(row)}
                            style={{ width:36, height:20, borderRadius:10, border:"none", cursor:"pointer", position:"relative", padding:0,
                              background: row.enabled ? "var(--moss)" : "var(--rule-bold)", transition:"background .2s" }}>
                            <span style={{ position:"absolute", top:2, left: row.enabled ? 18 : 2, width:16, height:16, borderRadius:"50%", background:"white", transition:"left .2s" }}/>
                          </button>
                        </td>
                        <td style={{ padding:"11px 14px" }}>
                          {editId !== row.id && (
                            <button onClick={() => startEdit(row)} className="btn btn-ghost" style={{ padding:"3px 10px", fontSize:11 }}>Edit pts</button>
                          )}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            ))}
          </div>

          {/* Right: Award panel + log */}
          <div style={{ display:"flex", flexDirection:"column", gap:16 }}>

            {/* Award form */}
            <div className="card-flat" style={{ padding:20 }}>
              <SectionHead eyebrow="AWARD XP" title="Give points"/>
              <form onSubmit={submitAward}>
                <FormField label="STUDENT">
                  <select required style={selectStyle} value={awardForm.student_id} onChange={e=>setAwardForm(f=>({...f,student_id:e.target.value}))}>
                    <option value="">— select student —</option>
                    {STUDENTS.map(s => <option key={s.id} value={s.id}>{s.name} · {s.xp} XP</option>)}
                  </select>
                </FormField>

                <FormField label="METHOD">
                  <div style={{ display:"flex", gap:8 }}>
                    {[["criteria","From criteria"],["custom","Custom"]].map(([v,l]) => (
                      <button key={v} type="button" onClick={() => setAwardForm(f=>({...f,mode:v,criteria_id:"",custom_reason:"",custom_pts:""}))}
                        style={{ flex:1, padding:"7px 0", borderRadius:8, border:"var(--border-thin)", fontSize:12,
                          background: awardForm.mode===v ? "var(--coral)" : "var(--paper-deep)",
                          color: awardForm.mode===v ? "white" : "var(--ink-soft)", cursor:"pointer", fontWeight:600 }}>
                        {l}
                      </button>
                    ))}
                  </div>
                </FormField>

                {awardForm.mode === "criteria" ? (
                  <>
                    <FormField label="CRITERIA">
                      <select required style={selectStyle} value={awardForm.criteria_id} onChange={e=>{ setAwardForm(f=>({...f,criteria_id:e.target.value})); setRubric({}); }}>
                        <option value="">— select criteria —</option>
                        {CATEGORY_ORDER.map(cat => {
                          const rows = list.filter(r => r.category === cat && r.enabled);
                          if (!rows.length) return null;
                          return (
                            <optgroup key={cat} label={cat}>
                              {rows.map(r => <option key={r.id} value={r.id}>{r.label}</option>)}
                            </optgroup>
                          );
                        })}
                      </select>
                    </FormField>
                    {selectedCrit && selectedCrit.scaling === "variable" && selectedCrit.tiers && (
                      <div style={{ padding:"10px 12px", borderRadius:8, background:"var(--paper-deep)", marginBottom:12, display:"flex", flexDirection:"column", gap:8 }}>
                        <div className="mono" style={{ fontSize:10, fontWeight:700, color:"var(--ink-mute)", letterSpacing:".06em" }}>TEACHER EVALUATION</div>
                        {(selectedCrit.tiers.per_unit != null || selectedCrit.tiers.per_question != null) ? (
                          <label style={{ fontSize:12, display:"flex", alignItems:"center", gap:8 }}>
                            <span>{selectedCrit.tiers.per_unit != null ? "Experiments completed" : "Correct answers"}:</span>
                            <input type="number" min="0" max="100" value={rubric.count||""} onChange={e=>setRubric(r=>({...r,count:e.target.value}))}
                              style={{ width:64, padding:"4px 8px", borderRadius:6, border:"var(--border-thin)", background:"var(--paper-card)", color:"var(--ink)", fontSize:13, outline:"none" }}/>
                            <span style={{ color:"var(--ink-mute)" }}>× {selectedCrit.tiers.per_unit ?? selectedCrit.tiers.per_question} pts</span>
                          </label>
                        ) : selectedCrit.tiers.increment != null ? (
                          <label style={{ fontSize:12, display:"flex", alignItems:"center", gap:8 }}>
                            <span>Which one (1st, 2nd…)?</span>
                            <input type="number" min="1" max="50" value={rubric.seq||""} onChange={e=>setRubric(r=>({...r,seq:e.target.value}))}
                              style={{ width:64, padding:"4px 8px", borderRadius:6, border:"var(--border-thin)", background:"var(--paper-card)", color:"var(--ink)", fontSize:13, outline:"none" }}/>
                            <span style={{ color:"var(--ink-mute)" }}>base {selectedCrit.points} +{selectedCrit.tiers.increment}/step</span>
                          </label>
                        ) : (
                          Object.keys(selectedCrit.tiers).map(k => (
                            <label key={k} style={{ fontSize:12, display:"flex", alignItems:"center", gap:8, cursor:"pointer" }}>
                              <input type="checkbox" checked={!!rubric[k]} onChange={e=>setRubric(r=>({...r,[k]:e.target.checked}))} style={{ accentColor:"var(--moss)" }}/>
                              <span style={{ textTransform:"capitalize" }}>{k.replace(/_/g," ")}</span>
                              <span style={{ color:"var(--ink-mute)", marginLeft:"auto" }}>+{selectedCrit.tiers[k]}</span>
                            </label>
                          ))
                        )}
                        <div style={{ borderTop:"var(--border-thin)", paddingTop:6, display:"flex", alignItems:"center", gap:8 }}>
                          <span style={{ fontWeight:700, color:"var(--moss)", fontFamily:"var(--font-mono)" }}>+{computeVariable(selectedCrit, rubric)} XP</span>
                          <span style={{ fontSize:11, color:"var(--ink-mute)" }}>{selectedCrit.min_points>0?`(min ${selectedCrit.min_points})`:""}</span>
                        </div>
                      </div>
                    )}
                    {selectedCrit && selectedCrit.scaling !== "variable" && (
                      <div style={{ padding:"8px 12px", borderRadius:8, background:"var(--paper-deep)", marginBottom:12, display:"flex", alignItems:"center", gap:8 }}>
                        <span style={{ fontWeight:700, color:"var(--moss)", fontFamily:"var(--font-mono)" }}>+{selectedCrit.points} XP</span>
                        <span style={{ fontSize:12, color:"var(--ink-mute)" }}>will be awarded</span>
                      </div>
                    )}
                    {selectedCrit && (
                      <FormField label="NOTE (OPTIONAL)">
                        <input style={inputStyle} value={awardForm.note} onChange={e=>setAwardForm(f=>({...f,note:e.target.value}))} placeholder="e.g. great teamwork on the circuit"/>
                      </FormField>
                    )}
                  </>
                ) : (
                  <>
                    <FormField label="REASON">
                      <input required style={inputStyle} value={awardForm.custom_reason} onChange={e=>setAwardForm(f=>({...f,custom_reason:e.target.value}))} placeholder="e.g. Exceptional effort in class"/>
                    </FormField>
                    <FormField label="POINTS">
                      <input required type="number" min="1" max="500" style={inputStyle} value={awardForm.custom_pts} onChange={e=>setAwardForm(f=>({...f,custom_pts:e.target.value}))} placeholder="e.g. 20"/>
                    </FormField>
                  </>
                )}

                {awardMsg && (
                  <div style={{ color: awardMsg.startsWith("+") ? "var(--moss)" : "var(--coral)", fontSize:13, marginBottom:10, fontWeight:700 }}>{awardMsg}</div>
                )}
                <button type="submit" disabled={awarding} className="btn btn-primary" style={{ width:"100%", padding:"10px 0", fontSize:13 }}>
                  {awarding ? "Awarding…" : "Award XP"}
                </button>
              </form>
            </div>

            {/* Award log */}
            <div className="card-flat" style={{ padding:18 }}>
              <SectionHead eyebrow="RECENT" title="Award log"/>
              {loadA ? <Spinner/> : awardLog.length === 0 ? (
                <div style={{ fontSize:12, color:"var(--ink-mute)", padding:"8px 0" }}>No awards yet.</div>
              ) : (
                <div style={{ display:"flex", flexDirection:"column" }}>
                  {awardLog.slice(0,15).map((a,i) => (
                    <div key={a.id} style={{ display:"flex", alignItems:"flex-start", gap:10, padding:"9px 0", borderTop: i ? "var(--border-thin)" : "none" }}>
                      <div style={{ width:34, height:34, borderRadius:8, background:"var(--moss)", display:"grid", placeItems:"center", flexShrink:0 }}>
                        <span style={{ color:"white", fontSize:11, fontWeight:800, fontFamily:"var(--font-mono)" }}>+{a.points}</span>
                      </div>
                      <div style={{ flex:1, minWidth:0 }}>
                        <div style={{ fontWeight:700, fontSize:13, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{a.student}</div>
                        <div style={{ fontSize:11, color:"var(--ink-mute)", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{a.reason}</div>
                        <div className="mono" style={{ fontSize:10, color:"var(--ink-mute)", marginTop:2 }}>{fmtTime(a.awarded_at)} · by {a.awarded_by || "system"}</div>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </Themed>
  );
};

window.AdminXPCriteria = AdminXPCriteria;
