/* global React, Star, Icon */
const { useState: useStateStaff, useEffect: useEffectStaff } = React;

const SCHEDULE_WORKER_S = "https://ftw-schedule.brigham-freeth.workers.dev";
const MAGIC_WORKER_S    = "https://ftw-magic-link.brigham-freeth.workers.dev";

const SHOW_COLORS_S = {
  "Frozen":      { bg: "#dbeeff", border: "#2F86BC", text: "#1a5a8a" },
  "Butter Knife":{ bg: "#ede8ff", border: "#8A5BA6", text: "#5a3a8a" },
  "Both":        { bg: "#d4f4ee", border: "#4BA697", text: "#2a7a6a" },
};

// ── Helpers ───────────────────────────────────────────────────────────────────

// Parse free-text conflict dates ("June 15-19, July 4, 6/15-7/2, Aug 10") into
// a Set of "monthIndex-day" keys, expanding ranges (dashes/en-dashes, optional
// cross-month ends like "June 30 - July 2").
const CONFLICT_MONTHS = { jan:0, feb:1, mar:2, apr:3, may:4, jun:5, jul:6, aug:7, sep:8, oct:9, nov:10, dec:11 };
function expandConflictKeys(text) {
  const keys = new Set();
  const t = (text || "").toLowerCase();
  const addRange = (m1, d1, m2, d2) => {
    let m = m1, d = d1, guard = 0;
    while (guard++ < 120) { // safety cap: ranges longer than ~4 months are junk input
      keys.add(`${m}-${d}`);
      if (m === m2 && d === d2) break;
      d++;
      const daysInMonth = new Date(2026, m + 1, 0).getDate();
      if (d > daysInMonth) { d = 1; m = (m + 1) % 12; }
    }
  };
  const MONTH_RE = "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec";
  // "june 15", "june 15-19", "june 30 - july 2"
  const reNamed = new RegExp(`(${MONTH_RE})[a-z]*\\.?\\s+(\\d{1,2})(?:\\s*[-–—]\\s*(?:(${MONTH_RE})[a-z]*\\.?\\s*)?(\\d{1,2}))?`, "g");
  let m;
  while ((m = reNamed.exec(t))) {
    const m1 = CONFLICT_MONTHS[m[1]], d1 = parseInt(m[2], 10);
    const m2 = m[3] ? CONFLICT_MONTHS[m[3]] : m1, d2 = m[4] ? parseInt(m[4], 10) : d1;
    if (d1 >= 1 && d1 <= 31 && d2 >= 1 && d2 <= 31) addRange(m1, d1, m2, d2);
  }
  // "6/15", "6/15-19", "6/15-7/2"
  const reNumeric = /(\d{1,2})\/(\d{1,2})(?:\s*[-–—]\s*(?:(\d{1,2})\/)?(\d{1,2}))?/g;
  while ((m = reNumeric.exec(t))) {
    const m1 = parseInt(m[1], 10) - 1, d1 = parseInt(m[2], 10);
    const m2 = m[3] ? parseInt(m[3], 10) - 1 : m1, d2 = m[4] ? parseInt(m[4], 10) : d1;
    if (m1 >= 0 && m1 <= 11 && m2 >= 0 && m2 <= 11 && d1 >= 1 && d1 <= 31 && d2 >= 1 && d2 <= 31) addRange(m1, d1, m2, d2);
  }
  return keys;
}

function fmtDate(iso) {
  if (!iso) return null;
  // Append noon to prevent UTC midnight from shifting the date back one day in local time
  return new Date(iso + " 12:00").toLocaleDateString("en-US", { month: "short", day: "numeric" });
}

function SignedBadge({ date }) {
  if (!date) return <span style={{ color: "#c0392b", fontSize: 12, fontWeight: 700 }}>—</span>;
  return (
    <span style={{ fontSize: 12, color: "#2a7a4a", fontWeight: 700 }}>
      ✓ {fmtDate(date)}
    </span>
  );
}

// ── Full Calendar Tab ─────────────────────────────────────────────────────────

const DAY_NAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

// Parse date string safely — append noon to avoid UTC midnight TZ shifts
function parseDate(str) { return new Date(str + " 12:00"); }

// Mon=0 … Sat=5, Sun=6 (shows close on Sunday — never drop it from the grid)
function dayIndex(dateStr) {
  const d = parseDate(dateStr);
  if (isNaN(d)) return -1;
  const dow = d.getDay();
  return dow === 0 ? 6 : dow - 1;
}

// ISO date of the Monday of a given date's week (used as grouping key)
function weekKey(dateStr) {
  const d = parseDate(dateStr);
  if (isNaN(d)) return dateStr;
  const dow = d.getDay();
  const mon = new Date(d);
  mon.setDate(d.getDate() - (dow === 0 ? 6 : dow - 1));
  return mon.toISOString().slice(0, 10);
}

function ScheduleTab({ schedule, students }) {
  const [expandedCell, setExpandedCell] = useStateStaff(null);

  // Group by actual calendar week, preserving order
  const weekMap = {};   // weekKey → { [dateStr]: [rows] }
  const weekOrder = []; // ordered list of weekKeys
  schedule.forEach(row => {
    const wk = weekKey(row.date);
    if (!weekMap[wk]) { weekMap[wk] = {}; weekOrder.push(wk); }
    const date = row.date || "";
    if (!weekMap[wk][date]) weekMap[wk][date] = [];
    weekMap[wk][date].push(row);
  });

  // Conflict lookup: dateStr → [student names].
  // Conflict text is free-form ("June 15-19 VBS, July 11-14") so it must be
  // parsed into concrete dates. (Substring matching caused false positives —
  // "July 1" matched inside "July 11-14" — and never expanded ranges.)
  const conflictsByDate = {};
  students.forEach(s => {
    if (!s.conflictDates) return;
    const keys = expandConflictKeys(s.conflictDates);
    if (!keys.size) return;
    schedule.forEach(row => {
      const d = parseDate(row.date);
      if (isNaN(d)) return;
      if (keys.has(`${d.getMonth()}-${d.getDate()}`)) {
        if (!conflictsByDate[row.date]) conflictsByDate[row.date] = [];
        if (!conflictsByDate[row.date].includes(s.name)) conflictsByDate[row.date].push(s.name);
      }
    });
  });

  if (weekOrder.length === 0) {
    return (
      <div style={{ padding: "48px 24px", textAlign: "center", color: "var(--ink-muted)" }}>
        Schedule not loaded yet — check back once the Google Sheet is populated.
      </div>
    );
  }

  return (
    <div style={{ padding: "24px", overflowX: "auto" }}>
      {weekOrder.map(wk => {
        const days = weekMap[wk];

        // Build 7-column grid (Mon–Sun)
        const grid = Array(7).fill(null).map(() => []);
        Object.entries(days).forEach(([date, rows]) => {
          const idx = dayIndex(date);
          if (idx >= 0) grid[idx] = rows;
        });

        if (!grid.some(col => col.length > 0)) return null;

        // Week label: "June 16–18" or "June 30 – July 2"
        const activeDates = Object.keys(days).sort((a, b) => parseDate(a) - parseDate(b));
        const first = parseDate(activeDates[0]);
        const last  = parseDate(activeDates[activeDates.length - 1]);
        const fmtFull = d => d.toLocaleDateString("en-US", { month: "long", day: "numeric" });
        const label = first.getMonth() === last.getMonth()
          ? `${first.toLocaleDateString("en-US", { month: "long" })} ${first.getDate()}–${last.getDate()}`
          : `${fmtFull(first)} – ${fmtFull(last)}`;

        return (
          <div key={wk} style={{ marginBottom: 32 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
              <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 15,
                textTransform: "uppercase", letterSpacing: ".06em", color: "var(--gold-deep)" }}>
                {label}
              </span>
              <div style={{ flex: 1, height: 2, background: "var(--paper-2)", borderRadius: 2 }} />
            </div>

            {/* Day header */}
            <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 6, marginBottom: 6 }}>
              {DAY_NAMES.map(d => (
                <div key={d} style={{ textAlign: "center", fontSize: 11, fontWeight: 700,
                  textTransform: "uppercase", letterSpacing: ".06em", color: "var(--ink-muted)", padding: "4px 0" }}>
                  {d}
                </div>
              ))}
            </div>

            {/* Day cells */}
            <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 6 }}>
              {grid.map((rows, colIdx) => {
                if (rows.length === 0) {
                  return <div key={colIdx} style={{ minHeight: 80, borderRadius: 10,
                    background: "var(--paper)", border: "1.5px solid var(--paper-2)", opacity: 0.4 }} />;
                }

                const dateStr = rows[0]?.date || "";
                const conflicts = conflictsByDate[dateStr] || [];
                const calls = [...new Set(rows.flatMap(r => r.called || []))];
                const hasBK     = calls.some(c => c.toUpperCase().startsWith("BK"));
                const hasFrozen = calls.some(c => c.toLowerCase().startsWith("frozen"));
                const hasAll    = calls.some(c => c.toUpperCase() === "ALL");
                const cellBg = (hasAll || (hasBK && hasFrozen)) ? "#d4f4ee"
                  : hasFrozen ? "#dbeeff" : hasBK ? "#ede8ff" : "var(--gold-tint)";

                const cellKey   = `${wk}-${colIdx}`;
                const isExpanded = expandedCell === cellKey;
                const dayNum    = parseDate(dateStr).getDate();

                return (
                  <div key={colIdx}
                    onClick={() => setExpandedCell(isExpanded ? null : cellKey)}
                    style={{ borderRadius: 10, border: "2px solid var(--ink)", cursor: "pointer",
                      background: cellBg, padding: "10px 10px 8px", position: "relative",
                      boxShadow: isExpanded ? "3px 3px 0 var(--ink)" : "2px 2px 0 rgba(33,29,23,.15)" }}>

                    <div style={{ fontSize: 18, fontFamily: "var(--display)", fontWeight: 700,
                      lineHeight: 1, marginBottom: 4 }}>{dayNum}</div>

                    {/* Show pills */}
                    <div style={{ display: "flex", gap: 3, flexWrap: "wrap", marginBottom: 4 }}>
                      {(hasAll ? ["BK", "Frozen"] : [
                        ...(hasBK ? ["BK"] : []),
                        ...(hasFrozen ? ["Frozen"] : []),
                      ]).map(label => {
                        const c = label === "BK" ? SHOW_COLORS_S["Butter Knife"] : SHOW_COLORS_S["Frozen"];
                        return (
                          <span key={label} style={{ fontSize: 9, fontWeight: 700, padding: "1px 5px",
                            borderRadius: 999, background: c.bg, border: `1.5px solid ${c.border}`,
                            color: c.text, whiteSpace: "nowrap" }}>
                            {label}
                          </span>
                        );
                      })}
                    </div>

                    <div style={{ fontSize: 11, color: "var(--ink-muted)", marginBottom: conflicts.length ? 4 : 0 }}>
                      {rows[0]?.start}–{rows[rows.length - 1]?.end}
                    </div>

                    {conflicts.length > 0 && (
                      <div style={{ fontSize: 10, fontWeight: 700, padding: "2px 6px",
                        background: "#fdf0ee", border: "1.5px solid #e8c5c0", borderRadius: 999,
                        color: "#c0392b", marginTop: 2, display: "inline-block" }}>
                        ⚠ {conflicts.length} conflict{conflicts.length > 1 ? "s" : ""}
                      </div>
                    )}

                    {isExpanded && (
                      <div style={{ marginTop: 8, paddingTop: 8, borderTop: "1.5px solid rgba(33,29,23,.15)" }}>
                        {rows.map((r, i) => (
                          <div key={i} style={{ fontSize: 11, marginBottom: 6 }}>
                            <div style={{ fontWeight: 600 }}>{r.notes || "Rehearsal"}</div>
                            <div style={{ color: "var(--ink-muted)" }}>
                              {r.start}–{r.end} · {(r.called || []).join(", ") || "All"}
                            </div>
                          </div>
                        ))}
                        {conflicts.length > 0 && (
                          <div style={{ marginTop: 4, fontSize: 11 }}>
                            <div style={{ fontWeight: 600, color: "#c0392b" }}>Conflicts:</div>
                            {conflicts.map(n => <div key={n} style={{ color: "#c0392b" }}>• {n}</div>)}
                          </div>
                        )}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ── Medical form viewer (emergency access) ────────────────────────────────────

const MEDICAL_LABELS_S = {
  asthma: "Asthma / respiratory issues", heartDisease: "Heart disease / irregular heartbeat",
  diabetes: "Diabetes", epilepsy: "Epilepsy / seizures", heatRelated: "Heat-related illness",
  rashes: "Skin rashes / eczema", bee: "Bee / insect sting allergy", latex: "Latex allergy",
  bleeding: "Bleeding disorders", anemia: "Anemia / blood disorders", fainting: "Fainting / dizziness spells",
  jointPain: "Joint pain / physical limitations", anxiety: "Anxiety / panic attacks",
  adhd: "ADHD / attention / behavioral", surgeries: "Recent surgeries or injuries",
  other: "Other ongoing medical condition",
};

function MedSection({ title, children, danger }) {
  return (
    <div style={{ marginBottom: 16, border: `2px solid ${danger ? "#c0392b" : "var(--paper-2)"}`,
      borderRadius: 12, overflow: "hidden" }}>
      <div style={{ padding: "8px 14px", background: danger ? "#fdf0ee" : "var(--paper-2)",
        fontFamily: "var(--display)", fontWeight: 700, fontSize: 13, textTransform: "uppercase",
        letterSpacing: ".05em", color: danger ? "#c0392b" : "var(--ink)" }}>
        {title}
      </div>
      <div style={{ padding: "12px 14px", fontSize: 14, lineHeight: 1.6 }}>{children}</div>
    </div>
  );
}

function MedRow({ label, value, tel }) {
  if (!value) return null;
  return (
    <div style={{ display: "flex", gap: 8 }}>
      <span style={{ color: "var(--ink-muted)", minWidth: 110, fontSize: 13, flexShrink: 0 }}>{label}</span>
      {tel
        ? <a href={`tel:${String(value).replace(/[^\d+]/g, "")}`} style={{ fontWeight: 600, color: "var(--ink)" }}>{value}</a>
        : <span style={{ fontWeight: 500 }}>{value}</span>}
    </div>
  );
}

function MedicalModal({ studentId, user, onClose }) {
  const [info, setInfo] = useStateStaff(null);
  const [error, setError] = useStateStaff(null);

  useEffectStaff(() => {
    fetch(`${MAGIC_WORKER_S}/medical?token=${encodeURIComponent(user.sessionToken)}&studentId=${encodeURIComponent(studentId)}`)
      .then(r => r.json())
      .then(d => { d.ok ? setInfo(d) : setError(d.error || "Could not load the form."); })
      .catch(() => setError("Network error — please try again."));
  }, [studentId]);

  const m = info?.medical;
  const yesConditions = m ? Object.keys(MEDICAL_LABELS_S).filter(k => m[k] === "Yes") : [];

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(33,29,23,.75)", zIndex: 9999,
      overflowY: "auto", padding: "24px 16px", display: "flex", alignItems: "flex-start", justifyContent: "center" }}>
      <div onClick={e => e.stopPropagation()} style={{ width: "100%", maxWidth: 640, background: "var(--white)",
        borderRadius: 16, border: "2.5px solid var(--ink)", marginBottom: 24 }}>

        {/* Header */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start",
          padding: "16px 22px", borderBottom: "2px solid var(--paper-2)" }}>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".08em",
              color: "#c0392b", fontFamily: "var(--display)", marginBottom: 2 }}>
              Emergency Medical Info
            </div>
            <h2 style={{ fontSize: 21, margin: 0 }}>{info?.name || "Loading…"}</h2>
            {info && (
              <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>
                {info.age ? `Age ${info.age} · ` : ""}
                {info.medicalSigned
                  ? `Medical release signed ${fmtDate(info.medicalSigned)}`
                  : "Medical release NOT signed"}
              </div>
            )}
          </div>
          <button onClick={onClose}
            style={{ background: "none", border: "none", fontSize: 22, cursor: "pointer", lineHeight: 1, padding: 4, color: "var(--ink-muted)" }}>
            ✕
          </button>
        </div>

        <div style={{ padding: "18px 22px" }}>
          {error && <div style={{ color: "#c0392b", fontSize: 14 }}>{error}</div>}
          {!info && !error && <div className="muted" style={{ fontSize: 14 }}>Loading…</div>}

          {info && !m && !error && (
            <div style={{ background: "#fdf0ee", border: "1.5px solid #e8c5c0", borderRadius: 10,
              padding: "12px 16px", fontSize: 14, color: "#c0392b" }}>
              No medical form on file for this student yet. Parent contact:
              {info.phone ? ` ${info.phone}` : ""} {info.parentEmail ? ` · ${info.parentEmail}` : ""}
            </div>
          )}

          {m && (
            <>
              <MedSection title="Emergency Contact (non-parent)" danger>
                <MedRow label="Name" value={m.emergencyName} />
                <MedRow label="Relationship" value={m.emergencyRel} />
                <MedRow label="Phone" value={m.emergencyPhone} tel />
                <MedRow label="Address" value={m.emergencyAddr} />
              </MedSection>

              <MedSection title="Parents / Guardians">
                <MedRow label="Guardian 1" value={m.motherName} />
                <MedRow label="Cell" value={m.motherCell} tel />
                <MedRow label="Guardian 2" value={m.fatherName} />
                <MedRow label="Cell" value={m.fatherCell} tel />
                <MedRow label="Family phone" value={info.phone} tel />
                <MedRow label="Email" value={m.parentEmail || info.parentEmail} />
              </MedSection>

              <MedSection title="Medical Conditions" danger={yesConditions.length > 0}>
                {yesConditions.length === 0
                  ? <span className="muted">No conditions reported.</span>
                  : yesConditions.map(k => (
                      <div key={k} style={{ fontWeight: 600, color: "#c0392b" }}>• {MEDICAL_LABELS_S[k]}</div>
                    ))}
              </MedSection>

              <MedSection title="Allergies & Medications"
                danger={m.foodAllergy === "Yes" || !!m.allergies || !!m.medications}>
                <MedRow label="Food allergies" value={m.foodAllergy === "Yes" ? (m.foodAllergyDesc || "Yes — see parent") : "None reported"} />
                <MedRow label="Other allergies" value={m.allergies || "None reported"} />
                <MedRow label="Medications" value={m.medications || "None reported"} />
                {m.otherNotes && <MedRow label="Notes for staff" value={m.otherNotes} />}
              </MedSection>

              <MedSection title="Insurance & Physician">
                <MedRow label="Carrier" value={m.insCarrier} />
                <MedRow label="Group #" value={m.insGroup} />
                <MedRow label="Ins. phone" value={m.insPhone} tel />
                <MedRow label="Physician" value={m.physicianName} />
                <MedRow label="Phys. phone" value={m.physicianPhone} tel />
                <MedRow label="Phys. address" value={m.physicianAddr} />
              </MedSection>

              <div className="muted" style={{ fontSize: 12, lineHeight: 1.5 }}>
                Emergency treatment authorized by {m.signature || "parent/guardian"}
                {m.signedDate ? ` on ${fmtDate(m.signedDate)}` : ""}. Staff will make a reasonable
                effort to contact parents before seeking medical treatment.
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

// ── Students Tab ──────────────────────────────────────────────────────────────

function StudentsTab({ students, user, onStudentsUpdate }) {
  const [sub, setSub] = useStateStaff("forms");
  const [editingConflict, setEditingConflict] = useStateStaff(null);
  const [conflictText, setConflictText] = useStateStaff("");
  const [saving, setSaving] = useStateStaff(false);
  const [medicalView, setMedicalView] = useStateStaff(null); // studentId

  const saveConflict = async (studentId) => {
    setSaving(true);
    try {
      await fetch(`${MAGIC_WORKER_S}/update-student`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ token: user.sessionToken, studentId, fields: { "Conflict Dates": conflictText } }),
      });
      onStudentsUpdate(students.map(s => s.id === studentId ? { ...s, conflictDates: conflictText } : s));
      setEditingConflict(null);
    } catch {}
    setSaving(false);
  };

  const SUB_TABS = [
    { id: "forms", label: "Forms Status" },
    { id: "sizes", label: "Clothing Sizes" },
    { id: "conflicts", label: "Conflicts" },
    ...(user.showFinancials ? [{ id: "balance", label: "Balance" }] : []),
  ];

  // Summary counts
  const formCount = { conduct: 0, photo: 0, medical: 0 };
  students.forEach(s => {
    if (s.conductSigned) formCount.conduct++;
    if (s.photoSigned) formCount.photo++;
    if (s.medicalSigned) formCount.medical++;
  });
  const total = students.length;
  const sizesComplete = students.filter(s => s.tshirt && s.pants && s.shoe).length;
  const hasConflicts = students.filter(s => s.conflictDates).length;

  return (
    <div style={{ padding: "24px" }}>
      {/* Summary chips */}
      <div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginBottom: 20 }}>
        {[
          { label: "Rules of Conduct", count: formCount.conduct, total, color: "var(--sky)" },
          { label: "Photo Release", count: formCount.photo, total, color: "var(--sky)" },
          { label: "Medical Release", count: formCount.medical, total, color: "var(--coral)" },
          { label: "Sizes complete", count: sizesComplete, total, color: "var(--mint)" },
          { label: "Have conflicts", count: hasConflicts, total, color: "var(--gold)" },
        ].map(({ label, count, color }) => (
          <div key={label} style={{ background: "var(--white)", border: "2px solid var(--ink)",
            borderRadius: 999, padding: "6px 14px", fontSize: 13, display: "flex", gap: 8, alignItems: "center" }}>
            <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 16,
              background: color, padding: "0 6px", borderRadius: 4 }}>{count}</span>
            <span className="muted">{label}</span>
            <span className="muted">/ {total}</span>
          </div>
        ))}
      </div>

      {/* Sub-tabs */}
      <div style={{ display: "flex", gap: 4, background: "var(--paper-2)", borderRadius: 999,
        padding: 4, width: "fit-content", marginBottom: 20 }}>
        {SUB_TABS.map(t => (
          <button key={t.id} onClick={() => setSub(t.id)}
            style={{ padding: "7px 16px", borderRadius: 999, border: "none", cursor: "pointer",
              fontFamily: "var(--display)", fontWeight: 600, fontSize: 13,
              background: sub === t.id ? "var(--ink)" : "transparent",
              color: sub === t.id ? "var(--paper)" : "var(--ink)" }}>
            {t.label}
          </button>
        ))}
      </div>

      {/* ── FORMS TABLE ── */}
      {sub === "forms" && (
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13.5 }}>
            <thead>
              <tr style={{ borderBottom: "2px solid var(--ink)" }}>
                {["Student", "Show", "Rules of Conduct", "Photo Release", "Medical Release"].map(h => (
                  <th key={h} style={{ textAlign: "left", padding: "8px 12px", fontFamily: "var(--display)",
                    fontWeight: 600, fontSize: 12, textTransform: "uppercase", letterSpacing: ".04em",
                    whiteSpace: "nowrap" }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {students.map((s, i) => (
                <tr key={s.id} style={{ borderBottom: "1px solid var(--paper-2)",
                  background: i % 2 === 0 ? "var(--white)" : "var(--paper)" }}>
                  <td style={{ padding: "10px 12px", fontWeight: 500 }}>{s.name}</td>
                  <td style={{ padding: "10px 12px" }}>
                    {s.show && (
                      <span style={{ fontSize: 11, fontWeight: 700, padding: "2px 8px", borderRadius: 999,
                        ...(SHOW_COLORS_S[s.show] || { bg: "#eee", border: "#999", text: "#333" }),
                        background: (SHOW_COLORS_S[s.show] || {}).bg,
                        border: `1.5px solid ${(SHOW_COLORS_S[s.show] || {}).border}`,
                        color: (SHOW_COLORS_S[s.show] || {}).text }}>
                        {s.show}
                      </span>
                    )}
                  </td>
                  <td style={{ padding: "10px 12px" }}><SignedBadge date={s.conductSigned} /></td>
                  <td style={{ padding: "10px 12px" }}><SignedBadge date={s.photoSigned} /></td>
                  <td style={{ padding: "10px 12px", whiteSpace: "nowrap" }}>
                    <SignedBadge date={s.medicalSigned} />
                    {s.medicalSigned && (
                      <button onClick={() => setMedicalView(s.id)}
                        style={{ marginLeft: 10, padding: "3px 11px", borderRadius: 999, background: "var(--paper)",
                          border: "1.5px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 600,
                          fontSize: 11.5, cursor: "pointer" }}>
                        View
                      </button>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* ── SIZES TABLE ── */}
      {sub === "sizes" && (
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13.5 }}>
            <thead>
              <tr style={{ borderBottom: "2px solid var(--ink)" }}>
                {["Student", "Show", "T-Shirt", "Pants / Waist", "Shoe"].map(h => (
                  <th key={h} style={{ textAlign: "left", padding: "8px 12px", fontFamily: "var(--display)",
                    fontWeight: 600, fontSize: 12, textTransform: "uppercase", letterSpacing: ".04em" }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {students.map((s, i) => {
                const missing = !s.tshirt || !s.pants || !s.shoe;
                return (
                  <tr key={s.id} style={{ borderBottom: "1px solid var(--paper-2)",
                    background: missing ? "#fffbf0" : i % 2 === 0 ? "var(--white)" : "var(--paper)" }}>
                    <td style={{ padding: "10px 12px", fontWeight: 500 }}>{s.name}</td>
                    <td style={{ padding: "10px 12px", fontSize: 12, color: "var(--ink-muted)" }}>{s.show || "—"}</td>
                    <td style={{ padding: "10px 12px" }}>
                      {s.tshirt || <span style={{ color: "#c0392b", fontSize: 12 }}>Missing</span>}
                    </td>
                    <td style={{ padding: "10px 12px" }}>
                      {s.pants || <span style={{ color: "#c0392b", fontSize: 12 }}>Missing</span>}
                    </td>
                    <td style={{ padding: "10px 12px" }}>
                      {s.shoe || <span style={{ color: "#c0392b", fontSize: 12 }}>Missing</span>}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {/* ── CONFLICTS ── */}
      {sub === "conflicts" && (
        <div style={{ display: "grid", gap: 10 }}>
          <p className="muted" style={{ fontSize: 13, marginBottom: 4 }}>
            Parents enter conflict dates in their Family Hub. You can also edit them here.
            Conflicts show as warnings on the calendar when the date matches.
          </p>
          {students.map(s => (
            <div key={s.id} style={{ background: "var(--white)", border: "2px solid var(--ink)",
              borderRadius: 12, padding: "14px 16px" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontFamily: "var(--display)", fontWeight: 600, fontSize: 15 }}>{s.name}</div>
                  {editingConflict === s.id ? (
                    <div style={{ marginTop: 8 }}>
                      <textarea value={conflictText} onChange={e => setConflictText(e.target.value)}
                        rows={2} placeholder="e.g. June 15, July 4-6, Aug 10"
                        style={{ width: "100%", boxSizing: "border-box", padding: "8px 10px",
                          border: "2px solid var(--ink)", borderRadius: 8, fontSize: 13,
                          fontFamily: "var(--sans)", resize: "vertical" }} />
                      <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
                        <button onClick={() => saveConflict(s.id)} disabled={saving}
                          style={{ padding: "6px 16px", borderRadius: 999, background: "var(--gold)",
                            border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 600,
                            fontSize: 13, cursor: "pointer" }}>
                          {saving ? "Saving…" : "Save"}
                        </button>
                        <button onClick={() => setEditingConflict(null)}
                          style={{ padding: "6px 16px", borderRadius: 999, background: "var(--white)",
                            border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 600,
                            fontSize: 13, cursor: "pointer" }}>
                          Cancel
                        </button>
                      </div>
                    </div>
                  ) : (
                    <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>
                      {s.conflictDates || <em>No conflicts entered</em>}
                    </div>
                  )}
                </div>
                {editingConflict !== s.id && (
                  <button onClick={() => { setEditingConflict(s.id); setConflictText(s.conflictDates || ""); }}
                    style={{ padding: "4px 12px", borderRadius: 999, background: "var(--paper)",
                      border: "1.5px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 500,
                      fontSize: 12, cursor: "pointer", flexShrink: 0 }}>
                    Edit
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      {/* ── BALANCE (financial access only) ── */}
      {sub === "balance" && user.showFinancials && (
        <BalanceTab students={students} user={user} />
      )}

      {/* Medical form viewer */}
      {medicalView && (
        <MedicalModal studentId={medicalView} user={user} onClose={() => setMedicalView(null)} />
      )}
    </div>
  );
}

// ── Balance Tab — per-payment ledger + manual cash/check entry ────────────────

function ptTodayStaff() {
  return new Date().toLocaleDateString("en-CA", { timeZone: "America/Los_Angeles" });
}

function BalanceTab({ students, user }) {
  const [payments, setPayments] = useStateStaff(null); // null = loading
  const [expanded, setExpanded] = useStateStaff(null); // studentId with history open
  const [paying, setPaying] = useStateStaff(null);     // studentId with payment form open
  const [pf, setPf] = useStateStaff({ amount: "", date: "", method: "Cash", note: "" });
  const [saving, setSaving] = useStateStaff(false);
  const [error, setError] = useStateStaff(null);
  const [localPaid, setLocalPaid] = useStateStaff({}); // payments recorded this session (rollup not refetched)

  const loadPayments = () => {
    fetch(`${MAGIC_WORKER_S}/payments?token=${encodeURIComponent(user.sessionToken)}`)
      .then(r => r.json())
      .then(d => setPayments(d.ok ? d.payments : []))
      .catch(() => setPayments([]));
  };
  useEffectStaff(() => { loadPayments(); }, []);

  // Group payments by student record id
  const byStudent = {};
  (payments || []).forEach(p => (p.studentIds || []).forEach(id => {
    (byStudent[id] = byStudent[id] || []).push(p);
  }));

  const openPayForm = (sid) => {
    setPaying(sid);
    setPf({ amount: "", date: ptTodayStaff(), method: "Cash", note: "" });
    setError(null);
  };

  const submitPayment = async (sid) => {
    const amt = Number(pf.amount);
    if (!isFinite(amt) || amt <= 0) { setError("Enter a valid dollar amount."); return; }
    setSaving(true); setError(null);
    try {
      const res = await fetch(`${MAGIC_WORKER_S}/add-payment`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: user.sessionToken, studentId: sid,
          amount: amt, date: pf.date, method: pf.method, note: pf.note,
        }),
      });
      const d = await res.json();
      if (!d.ok) { setError(d.error || "Could not record the payment — try again."); setSaving(false); return; }
      setLocalPaid(p => ({ ...p, [sid]: (p[sid] || 0) + amt }));
      setPaying(null);
      setExpanded(sid);
      loadPayments();
    } catch {
      setError("Network error — please try again.");
    }
    setSaving(false);
  };

  const paidFor = (s) => (s.paid || 0) + (localPaid[s.id] || 0);
  const inputStyle = { boxSizing: "border-box", padding: "7px 9px", fontSize: 13.5,
    border: "2px solid var(--ink)", borderRadius: 8, fontFamily: "var(--sans)", width: "100%" };

  return (
    <div>
      <p className="muted" style={{ fontSize: 13, marginBottom: 14 }}>
        Click a student to see their payment history. Use <b>+ Payment</b> to record cash or check
        payments — they're logged to FTW_Payments_2026 and the balance updates automatically.
      </p>
      <div style={{ overflowX: "auto" }}>
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13.5 }}>
          <thead>
            <tr style={{ borderBottom: "2px solid var(--ink)" }}>
              {["Student", "Show", "Tuition", "Paid", "Balance Due", ""].map((h, i) => (
                <th key={i} style={{ textAlign: ["Student", "Show", ""].includes(h) ? "left" : "right",
                  padding: "8px 12px", fontFamily: "var(--display)", fontWeight: 600,
                  fontSize: 12, textTransform: "uppercase", letterSpacing: ".04em", whiteSpace: "nowrap" }}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {students.map((s, i) => {
              const paid = paidFor(s);
              const balance = Math.max(0, (s.tuition || 0) - paid);
              const hasBalance = balance > 0;
              const history = (byStudent[s.id] || []);
              const isOpen = expanded === s.id;
              return (
                <React.Fragment key={s.id}>
                  <tr onClick={() => setExpanded(isOpen ? null : s.id)}
                    style={{ borderBottom: "1px solid var(--paper-2)", cursor: "pointer",
                      background: isOpen ? "var(--gold-tint)" : hasBalance ? "#fffbf0" : i % 2 === 0 ? "var(--white)" : "var(--paper)" }}>
                    <td style={{ padding: "10px 12px", fontWeight: 500 }}>
                      <span style={{ display: "inline-block", width: 14, color: "var(--ink-muted)" }}>{isOpen ? "▾" : "▸"}</span>
                      {s.name}
                    </td>
                    <td style={{ padding: "10px 12px" }}>
                      {s.show && (
                        <span style={{ fontSize: 11, fontWeight: 700, padding: "2px 8px", borderRadius: 999,
                          background: (SHOW_COLORS_S[s.show] || {}).bg,
                          border: `1.5px solid ${(SHOW_COLORS_S[s.show] || {}).border || "#999"}`,
                          color: (SHOW_COLORS_S[s.show] || {}).text }}>
                          {s.show}
                        </span>
                      )}
                    </td>
                    <td style={{ padding: "10px 12px", textAlign: "right", color: "var(--ink-muted)" }}>
                      ${(s.tuition || 0).toLocaleString()}
                    </td>
                    <td style={{ padding: "10px 12px", textAlign: "right", color: "#2a7a4a", fontWeight: 500 }}>
                      ${paid.toLocaleString()}
                    </td>
                    <td style={{ padding: "10px 12px", textAlign: "right",
                      fontWeight: 700, color: hasBalance ? "#c0392b" : "#2a7a4a" }}>
                      ${balance.toLocaleString()}
                    </td>
                    <td style={{ padding: "10px 12px", textAlign: "right", whiteSpace: "nowrap" }}>
                      <button onClick={(e) => { e.stopPropagation(); openPayForm(s.id); }}
                        style={{ padding: "4px 12px", borderRadius: 999, background: "var(--gold)",
                          border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 600,
                          fontSize: 12, cursor: "pointer" }}>
                        + Payment
                      </button>
                    </td>
                  </tr>

                  {/* Payment entry form */}
                  {paying === s.id && (
                    <tr style={{ background: "var(--paper-2)" }}>
                      <td colSpan={6} style={{ padding: "14px 16px", borderBottom: "1px solid var(--paper-2)" }}>
                        <div style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, marginBottom: 10 }}>
                          Record payment — {s.name}
                        </div>
                        <div style={{ display: "grid", gridTemplateColumns: "120px 150px 130px 1fr", gap: 10, alignItems: "end", maxWidth: 720 }}>
                          <div>
                            <label style={{ fontSize: 11, fontWeight: 700, display: "block", marginBottom: 4 }}>Amount ($)</label>
                            <input type="number" min="1" step="0.01" value={pf.amount} autoFocus
                              onChange={e => setPf(p => ({ ...p, amount: e.target.value }))} style={inputStyle} />
                          </div>
                          <div>
                            <label style={{ fontSize: 11, fontWeight: 700, display: "block", marginBottom: 4 }}>Date</label>
                            <input type="date" value={pf.date}
                              onChange={e => setPf(p => ({ ...p, date: e.target.value }))} style={inputStyle} />
                          </div>
                          <div>
                            <label style={{ fontSize: 11, fontWeight: 700, display: "block", marginBottom: 4 }}>Method</label>
                            <select value={pf.method} onChange={e => setPf(p => ({ ...p, method: e.target.value }))}
                              style={{ ...inputStyle, background: "var(--white)" }}>
                              {["Cash", "Check", "Waived"].map(m => <option key={m} value={m}>{m}</option>)}
                            </select>
                          </div>
                          <div>
                            <label style={{ fontSize: 11, fontWeight: 700, display: "block", marginBottom: 4 }}>Note (e.g. check #)</label>
                            <input type="text" value={pf.note} placeholder="optional"
                              onChange={e => setPf(p => ({ ...p, note: e.target.value }))} style={inputStyle} />
                          </div>
                        </div>
                        {error && <div style={{ color: "#c0392b", fontSize: 13, marginTop: 8 }}>{error}</div>}
                        <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
                          <button onClick={() => submitPayment(s.id)} disabled={saving}
                            style={{ padding: "7px 18px", borderRadius: 999, background: "var(--gold)",
                              border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 700,
                              fontSize: 13, cursor: "pointer" }}>
                            {saving ? "Saving…" : "Save payment"}
                          </button>
                          <button onClick={() => setPaying(null)}
                            style={{ padding: "7px 16px", borderRadius: 999, background: "var(--white)",
                              border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 600,
                              fontSize: 13, cursor: "pointer" }}>
                            Cancel
                          </button>
                        </div>
                      </td>
                    </tr>
                  )}

                  {/* Payment history */}
                  {isOpen && (
                    <tr style={{ background: "var(--white)" }}>
                      <td colSpan={6} style={{ padding: "10px 16px 16px 38px", borderBottom: "1px solid var(--paper-2)" }}>
                        {payments === null ? (
                          <span className="muted" style={{ fontSize: 13 }}>Loading payments…</span>
                        ) : history.length === 0 ? (
                          <span className="muted" style={{ fontSize: 13 }}>No payments recorded yet.</span>
                        ) : (
                          <table style={{ borderCollapse: "collapse", fontSize: 13, minWidth: 420 }}>
                            <thead>
                              <tr>
                                {["Date", "Amount", "Method", "Status", "Note"].map(h => (
                                  <th key={h} style={{ textAlign: h === "Amount" ? "right" : "left", padding: "4px 14px 4px 0",
                                    fontSize: 11, textTransform: "uppercase", letterSpacing: ".04em",
                                    color: "var(--ink-muted)", fontFamily: "var(--display)" }}>{h}</th>
                                ))}
                              </tr>
                            </thead>
                            <tbody>
                              {history.map(p => (
                                <tr key={p.id} style={{ borderTop: "1px solid var(--paper-2)" }}>
                                  <td style={{ padding: "6px 14px 6px 0", whiteSpace: "nowrap" }}>{fmtDate(p.date) || "—"}</td>
                                  <td style={{ padding: "6px 14px 6px 0", textAlign: "right", fontWeight: 600,
                                    color: p.status === "Refunded" ? "#c0392b" : "#2a7a4a" }}>
                                    ${p.amount.toLocaleString()}
                                  </td>
                                  <td style={{ padding: "6px 14px 6px 0" }}>{p.method || "—"}</td>
                                  <td style={{ padding: "6px 14px 6px 0" }}>{p.status || "—"}</td>
                                  <td style={{ padding: "6px 0", color: "var(--ink-muted)", maxWidth: 320 }}>{p.note}</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        )}
                      </td>
                    </tr>
                  )}
                </React.Fragment>
              );
            })}
          </tbody>
          <tfoot>
            <tr style={{ borderTop: "2px solid var(--ink)", background: "var(--paper-2)" }}>
              <td colSpan={2} style={{ padding: "10px 12px", fontFamily: "var(--display)", fontWeight: 700 }}>Total</td>
              <td style={{ padding: "10px 12px", textAlign: "right", color: "var(--ink-muted)", fontWeight: 600 }}>
                ${students.reduce((sum, s) => sum + (s.tuition || 0), 0).toLocaleString()}
              </td>
              <td style={{ padding: "10px 12px", textAlign: "right", color: "#2a7a4a", fontWeight: 700 }}>
                ${students.reduce((sum, s) => sum + paidFor(s), 0).toLocaleString()}
              </td>
              <td style={{ padding: "10px 12px", textAlign: "right", fontWeight: 700,
                color: students.reduce((sum, s) => sum + Math.max(0, (s.tuition||0)-paidFor(s)), 0) > 0 ? "#c0392b" : "#2a7a4a" }}>
                ${students.reduce((sum, s) => sum + Math.max(0, (s.tuition||0)-paidFor(s)), 0).toLocaleString()}
              </td>
              <td />
            </tr>
          </tfoot>
        </table>
      </div>
    </div>
  );
}

// ── Attendance Tab ────────────────────────────────────────────────────────────

// Same call-group filtering the Family Hub uses, applied to a day's Called list
function isCalledStaff(calls, student) {
  const cg   = (student.callGroup || "").trim();
  const show = (student.show     || "").trim().toLowerCase();
  if (cg === "All") return true;
  if (show === "both") return true;
  const isBK     = show === "butter knife" || cg.toUpperCase().startsWith("BK");
  const isFrozen = show === "frozen"       || cg.toLowerCase().startsWith("frozen");
  if (isBK) return calls.some(c => c.toUpperCase().startsWith("BK"));
  if (isFrozen) {
    const bkOnly = calls.length && calls.every(c => c.toUpperCase().startsWith("BK"));
    if (bkOnly) return false;
    return calls.some(c => c.toLowerCase().startsWith("frozen")) || calls.some(c => c.toUpperCase() === "ALL");
  }
  return true;
}

function AttendanceTab({ students, schedule, user }) {
  // Rehearsal days from the schedule, keyed by ISO date
  const days = {};
  schedule.forEach(row => {
    const d = parseDate(row.date);
    if (isNaN(d)) return;
    const iso = d.toISOString().slice(0, 10);
    if (!days[iso]) days[iso] = { iso, label: row.date, calls: [] };
    days[iso].calls.push(...(row.called || []));
  });
  const dayList = Object.values(days).sort((a, b) => a.iso.localeCompare(b.iso));

  const todayISO = ptTodayStaff();
  const defaultDay = (days[todayISO] && todayISO)
    || dayList.find(d => d.iso >= todayISO)?.iso
    || dayList[dayList.length - 1]?.iso
    || "";

  const [selected, setSelected] = useStateStaff(defaultDay);
  const [present, setPresent] = useStateStaff({});   // iso → Set of student ids
  const [loaded, setLoaded] = useStateStaff(false);
  const [showAll, setShowAll] = useStateStaff(false);
  const [saving, setSaving] = useStateStaff(false);
  const [savedAt, setSavedAt] = useStateStaff(null); // iso of last save
  const [dirty, setDirty] = useStateStaff(false);
  const [error, setError] = useStateStaff(null);

  useEffectStaff(() => {
    fetch(`${MAGIC_WORKER_S}/attendance?token=${encodeURIComponent(user.sessionToken)}`)
      .then(r => r.json())
      .then(d => {
        if (d.ok) {
          const map = {};
          (d.attendance || []).forEach(rec => { map[rec.date] = new Set(rec.presentIds); });
          setPresent(map);
        }
      })
      .catch(() => {})
      .finally(() => setLoaded(true));
  }, []);

  const day = days[selected];
  const calls = [...new Set(day?.calls || [])];
  const roster = students
    .filter(s => showAll || !calls.length || isCalledStaff(calls, s))
    .sort((a, b) => a.name.localeCompare(b.name));
  const presentSet = present[selected] || new Set();

  const toggle = (sid) => {
    setPresent(prev => {
      const next = new Set(prev[selected] || []);
      next.has(sid) ? next.delete(sid) : next.add(sid);
      return { ...prev, [selected]: next };
    });
    setDirty(true);
    setSavedAt(null);
  };

  const save = async () => {
    setSaving(true); setError(null);
    try {
      const res = await fetch(`${MAGIC_WORKER_S}/save-attendance`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: user.sessionToken,
          date: selected,
          presentIds: [...(present[selected] || [])],
        }),
      });
      const d = await res.json();
      if (!d.ok) setError(d.error || "Could not save — try again.");
      else { setDirty(false); setSavedAt(selected); }
    } catch {
      setError("Network error — please try again.");
    }
    setSaving(false);
  };

  if (!dayList.length) {
    return (
      <div style={{ padding: "48px 24px", textAlign: "center", color: "var(--ink-muted)" }}>
        No rehearsal days yet — attendance unlocks once the schedule is in the Google Sheet.
      </div>
    );
  }

  return (
    <div style={{ padding: "24px", maxWidth: 680 }}>
      {/* Day picker */}
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 18 }}>
        {dayList.map(d => {
          const sel = d.iso === selected;
          const isToday = d.iso === todayISO;
          return (
            <button key={d.iso} onClick={() => { setSelected(d.iso); setDirty(false); setSavedAt(null); setError(null); }}
              style={{ padding: "7px 13px", borderRadius: 999, cursor: "pointer",
                border: `2px solid ${sel ? "var(--ink)" : isToday ? "var(--gold-deep)" : "var(--paper-2)"}`,
                background: sel ? "var(--ink)" : isToday ? "var(--gold-tint)" : "var(--white)",
                color: sel ? "var(--paper)" : "var(--ink)",
                fontFamily: "var(--display)", fontWeight: 600, fontSize: 13, whiteSpace: "nowrap" }}>
              {parseDate(d.iso).toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" })}
              {isToday ? " · today" : ""}
            </button>
          );
        })}
      </div>

      {/* Header row: counts + show-all toggle */}
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center",
        gap: 12, flexWrap: "wrap", marginBottom: 12 }}>
        <div style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: 17 }}>
          {[...presentSet].filter(id => roster.some(s => s.id === id)).length} / {roster.length} present
        </div>
        <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, cursor: "pointer" }}>
          <input type="checkbox" checked={showAll} onChange={e => setShowAll(e.target.checked)}
            style={{ width: 15, height: 15 }} />
          Show all students (not just those called)
        </label>
      </div>

      {/* Roster checklist */}
      {!loaded ? (
        <div style={{ padding: "32px 0", textAlign: "center", color: "var(--ink-muted)", fontSize: 14 }}>
          Loading attendance…
        </div>
      ) : (
        <div style={{ display: "grid", gap: 6, marginBottom: 18 }}>
          {roster.map(s => {
            const isPresent = presentSet.has(s.id);
            const showC = SHOW_COLORS_S[s.show] || {};
            return (
              <button key={s.id} onClick={() => toggle(s.id)}
                style={{ display: "flex", alignItems: "center", gap: 12, textAlign: "left",
                  padding: "11px 14px", borderRadius: 12, cursor: "pointer",
                  border: `2px solid ${isPresent ? "var(--ink)" : "var(--paper-2)"}`,
                  background: isPresent ? "var(--mint)" : "var(--white)" }}>
                <span style={{ width: 22, height: 22, borderRadius: 6, flexShrink: 0,
                  border: "2px solid var(--ink)", display: "grid", placeItems: "center",
                  background: isPresent ? "var(--ink)" : "var(--white)",
                  color: "var(--paper)", fontSize: 14, fontWeight: 800 }}>
                  {isPresent ? "✓" : ""}
                </span>
                <span style={{ flex: 1, fontFamily: "var(--display)", fontWeight: 600, fontSize: 15 }}>
                  {s.name}
                </span>
                {s.show && (
                  <span style={{ fontSize: 10, fontWeight: 700, padding: "2px 8px", borderRadius: 999,
                    background: showC.bg, border: `1.5px solid ${showC.border || "#999"}`,
                    color: showC.text, whiteSpace: "nowrap" }}>
                    {s.show}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      )}

      {error && <div style={{ color: "#c0392b", fontSize: 13.5, marginBottom: 10 }}>{error}</div>}

      {/* Sticky save bar */}
      <div style={{ position: "sticky", bottom: 12, display: "flex", gap: 10, alignItems: "center" }}>
        <button onClick={save} disabled={saving || !dirty}
          style={{ padding: "12px 28px", borderRadius: 999, cursor: dirty ? "pointer" : "default",
            background: savedAt === selected ? "var(--mint)" : dirty ? "var(--gold)" : "var(--paper-2)",
            border: "2px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 700,
            fontSize: 15, boxShadow: dirty ? "3px 3px 0 var(--ink)" : "none" }}>
          {saving ? "Saving…" : savedAt === selected ? "✓ Saved" : "Save attendance"}
        </button>
        {dirty && <span className="muted" style={{ fontSize: 13 }}>Unsaved changes</span>}
      </div>
    </div>
  );
}

// ── Announcements Tab ─────────────────────────────────────────────────────────

function AnnouncementsTab({ announcements, user, onUpdate }) {
  const [editing, setEditing] = useStateStaff(null);
  const [form, setForm] = useStateStaff({ title: "", bodyText: "", tag: "", active: true, priority: 0 });
  const [saving, setSaving] = useStateStaff(false);
  const [confirmDelete, setConfirmDelete] = useStateStaff(null);

  const openNew = () => {
    setForm({ title: "", bodyText: "", tag: "", active: true, priority: announcements.length + 1 });
    setEditing("new");
  };

  const openEdit = (a) => {
    setForm({ title: a.title, bodyText: a.body, tag: a.tag, active: a.active, priority: a.priority });
    setEditing(a.id);
  };

  const save = async () => {
    if (!form.title.trim()) return;
    setSaving(true);
    try {
      await fetch(`${MAGIC_WORKER_S}/save-announcement`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ token: user.sessionToken, id: editing === "new" ? null : editing, ...form }),
      });
      // Refresh announcements
      const r = await fetch(`${MAGIC_WORKER_S}/staff-data?token=${user.sessionToken}`);
      const d = await r.json();
      if (d.ok) onUpdate(d.announcements);
      setEditing(null);
    } catch {}
    setSaving(false);
  };

  const del = async (id) => {
    try {
      await fetch(`${MAGIC_WORKER_S}/delete-announcement`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ token: user.sessionToken, id }),
      });
      onUpdate(announcements.filter(a => a.id !== id));
    } catch {}
    setConfirmDelete(null);
  };

  const TAG_OPTIONS = ["Important", "Schedule", "Costumes", "Tickets", "General", ""];

  return (
    <div style={{ padding: "24px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20 }}>
        <div>
          <h3 style={{ margin: 0 }}>Announcements</h3>
          <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>
            These appear in every family's Family Hub. Active announcements show immediately.
          </p>
        </div>
        <button onClick={openNew}
          style={{ padding: "10px 20px", borderRadius: 999, background: "var(--gold)", border: "2px solid var(--ink)",
            fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, cursor: "pointer" }}>
          + New announcement
        </button>
      </div>

      {/* Edit / new form */}
      {editing && (
        <div style={{ background: "var(--paper-2)", border: "2px solid var(--ink)", borderRadius: 14,
          padding: 20, marginBottom: 20 }}>
          <h4 style={{ margin: "0 0 16px" }}>{editing === "new" ? "New announcement" : "Edit announcement"}</h4>
          <div style={{ display: "grid", gap: 12 }}>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4 }}>Title *</label>
              <input value={form.title} onChange={e => setForm(f => ({ ...f, title: e.target.value }))}
                placeholder="e.g. Costume fitting this Saturday"
                style={{ width: "100%", boxSizing: "border-box", padding: "8px 10px", fontSize: 14,
                  border: "2px solid var(--ink)", borderRadius: 8, fontFamily: "var(--sans)" }} />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4 }}>Body text</label>
              <textarea value={form.bodyText} onChange={e => setForm(f => ({ ...f, bodyText: e.target.value }))}
                rows={3} placeholder="Details, instructions, or information for families…"
                style={{ width: "100%", boxSizing: "border-box", padding: "8px 10px", fontSize: 14,
                  border: "2px solid var(--ink)", borderRadius: 8, fontFamily: "var(--sans)", resize: "vertical" }} />
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
              <div>
                <label style={{ fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4 }}>Tag</label>
                <select value={form.tag} onChange={e => setForm(f => ({ ...f, tag: e.target.value }))}
                  style={{ width: "100%", padding: "8px 10px", border: "2px solid var(--ink)", borderRadius: 8,
                    fontSize: 14, fontFamily: "var(--sans)", background: "var(--white)" }}>
                  {TAG_OPTIONS.map(t => <option key={t} value={t}>{t || "— no tag —"}</option>)}
                </select>
              </div>
              <div>
                <label style={{ fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4 }}>Priority (1 = top)</label>
                <input type="number" min="0" value={form.priority}
                  onChange={e => setForm(f => ({ ...f, priority: Number(e.target.value) }))}
                  style={{ width: "100%", boxSizing: "border-box", padding: "8px 10px", fontSize: 14,
                    border: "2px solid var(--ink)", borderRadius: 8, fontFamily: "var(--sans)" }} />
              </div>
              <div style={{ display: "flex", flexDirection: "column", justifyContent: "flex-end" }}>
                <label style={{ fontSize: 12, fontWeight: 600, display: "flex", alignItems: "center", gap: 8, cursor: "pointer" }}>
                  <input type="checkbox" checked={form.active}
                    onChange={e => setForm(f => ({ ...f, active: e.target.checked }))}
                    style={{ width: 16, height: 16 }} />
                  Active (visible to families)
                </label>
              </div>
            </div>
          </div>
          <div style={{ display: "flex", gap: 10, marginTop: 16 }}>
            <button onClick={save} disabled={saving || !form.title.trim()}
              style={{ padding: "10px 24px", borderRadius: 999, background: "var(--gold)", border: "2px solid var(--ink)",
                fontFamily: "var(--display)", fontWeight: 700, fontSize: 14, cursor: "pointer" }}>
              {saving ? "Saving…" : "Save"}
            </button>
            <button onClick={() => setEditing(null)}
              style={{ padding: "10px 20px", borderRadius: 999, background: "var(--white)", border: "2px solid var(--ink)",
                fontFamily: "var(--display)", fontWeight: 600, fontSize: 14, cursor: "pointer" }}>
              Cancel
            </button>
          </div>
        </div>
      )}

      {/* Announcement list */}
      {announcements.length === 0 && !editing && (
        <div style={{ textAlign: "center", padding: "48px 24px", color: "var(--ink-muted)", fontSize: 14 }}>
          No announcements yet. Create one to broadcast a message to all families.
        </div>
      )}
      <div style={{ display: "grid", gap: 10 }}>
        {announcements.map(a => (
          <div key={a.id} style={{ background: a.active ? "var(--white)" : "var(--paper)",
            border: `2px solid ${a.active ? "var(--ink)" : "var(--paper-2)"}`,
            borderRadius: 12, padding: "14px 16px", opacity: a.active ? 1 : 0.6 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
              <div style={{ flex: 1 }}>
                <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 4 }}>
                  {a.tag && (
                    <span style={{ fontSize: 10, fontWeight: 700, padding: "2px 7px", borderRadius: 999,
                      background: "var(--paper-2)", fontFamily: "var(--display)", letterSpacing: ".04em",
                      textTransform: "uppercase" }}>{a.tag}</span>
                  )}
                  {!a.active && (
                    <span style={{ fontSize: 10, fontWeight: 700, padding: "2px 7px", borderRadius: 999,
                      background: "#fdf0ee", color: "#c0392b", fontFamily: "var(--display)" }}>INACTIVE</span>
                  )}
                  <span style={{ fontSize: 11, color: "var(--ink-muted)" }}>Priority {a.priority}</span>
                </div>
                <div style={{ fontFamily: "var(--display)", fontWeight: 600, fontSize: 15 }}>{a.title}</div>
                {a.body && <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>{a.body}</div>}
              </div>
              <div style={{ display: "flex", gap: 6, flexShrink: 0 }}>
                <button onClick={() => openEdit(a)}
                  style={{ padding: "5px 12px", borderRadius: 999, background: "var(--paper)",
                    border: "1.5px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 500,
                    fontSize: 12, cursor: "pointer" }}>Edit</button>
                {confirmDelete === a.id ? (
                  <>
                    <button onClick={() => del(a.id)}
                      style={{ padding: "5px 12px", borderRadius: 999, background: "#fdf0ee",
                        border: "1.5px solid #c0392b", fontFamily: "var(--display)", fontWeight: 600,
                        fontSize: 12, cursor: "pointer", color: "#c0392b" }}>Confirm delete</button>
                    <button onClick={() => setConfirmDelete(null)}
                      style={{ padding: "5px 10px", borderRadius: 999, background: "var(--paper)",
                        border: "1.5px solid var(--ink)", fontFamily: "var(--display)", fontSize: 12, cursor: "pointer" }}>✕</button>
                  </>
                ) : (
                  <button onClick={() => setConfirmDelete(a.id)}
                    style={{ padding: "5px 12px", borderRadius: 999, background: "var(--paper)",
                      border: "1.5px solid var(--ink)", fontFamily: "var(--display)", fontWeight: 500,
                      fontSize: 12, cursor: "pointer" }}>Delete</button>
                )}
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Main StaffPage ────────────────────────────────────────────────────────────

function StaffPage({ user, navigate, onLogout }) {
  const [tab, setTab] = useStateStaff("schedule");
  const [students, setStudents] = useStateStaff([]);
  const [schedule, setSchedule] = useStateStaff([]);
  const [announcements, setAnnouncements] = useStateStaff([]);
  const [loading, setLoading] = useStateStaff(true);

  useEffectStaff(() => {
    Promise.all([
      fetch(`${SCHEDULE_WORKER_S}/schedule`).then(r => r.json()).catch(() => ({ schedule: [] })),
      fetch(`${MAGIC_WORKER_S}/staff-data?token=${user.sessionToken}`).then(r => r.json()).catch(() => ({ students: [], announcements: [] })),
    ]).then(([sched, staffData]) => {
      setSchedule(sched.schedule || []);
      setStudents(staffData.students || []);
      setAnnouncements(staffData.announcements || []);
    }).finally(() => setLoading(false));
  }, []);

  const TABS = [
    { id: "schedule", label: "Schedule", icon: "calendar" },
    { id: "attendance", label: "Attendance", icon: "check" },
    { id: "students", label: "Students", icon: "user" },
    { id: "announcements", label: "Announcements", icon: "bell" },
  ];

  // Stats for tab badges
  const formsIncomplete = students.filter(s => !s.conductSigned || !s.photoSigned || !s.medicalSigned).length;
  const sizesIncomplete = students.filter(s => !s.tshirt || !s.pants || !s.shoe).length;

  return (
    <div style={{ minHeight: "100vh", background: "var(--paper-2)" }}>
      {/* Header */}
      <div style={{ background: "var(--ink)", color: "var(--paper)", position: "sticky", top: 0, zIndex: 100 }}>
        <div style={{ maxWidth: 1200, margin: "0 auto", padding: "0 24px" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center",
            paddingBlock: "14px", borderBottom: "1px solid rgba(255,255,255,.1)" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
              <img src="assets/logo.png" alt="FTW" style={{ height: 24, filter: "brightness(10)" }} />
              <div>
                <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase",
                  letterSpacing: ".08em", color: "var(--gold)", fontFamily: "var(--display)" }}>
                  Staff Dashboard
                </div>
                <div style={{ fontSize: 14, color: "rgba(255,255,255,.8)", marginTop: 1 }}>
                  {user.staffName} · {user.staffRole}
                </div>
              </div>
            </div>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
              {user.isParent && (
                <button onClick={() => navigate("hub")}
                  style={{ padding: "7px 14px", borderRadius: 999, background: "rgba(255,255,255,.12)",
                    border: "1.5px solid rgba(255,255,255,.3)", color: "var(--paper)", fontSize: 13,
                    fontFamily: "var(--display)", fontWeight: 500, cursor: "pointer" }}>
                  Family Hub →
                </button>
              )}
              <button onClick={onLogout}
                style={{ padding: "7px 14px", borderRadius: 999, background: "transparent",
                  border: "1.5px solid rgba(255,255,255,.3)", color: "rgba(255,255,255,.7)", fontSize: 13,
                  fontFamily: "var(--display)", cursor: "pointer" }}>
                Sign out
              </button>
            </div>
          </div>

          {/* Tabs */}
          <div style={{ display: "flex", gap: 2, paddingTop: 4 }}>
            {TABS.map(t => (
              <button key={t.id} onClick={() => setTab(t.id)}
                style={{ padding: "10px 20px", background: tab === t.id ? "var(--gold)" : "transparent",
                  border: "none", borderRadius: "10px 10px 0 0", cursor: "pointer",
                  fontFamily: "var(--display)", fontWeight: tab === t.id ? 700 : 500,
                  fontSize: 14, color: tab === t.id ? "var(--ink)" : "rgba(255,255,255,.7)",
                  display: "flex", alignItems: "center", gap: 8, position: "relative" }}>
                <Icon name={t.icon} size={15} />
                {t.label}
                {t.id === "students" && (formsIncomplete + sizesIncomplete) > 0 && !loading && (
                  <span style={{ fontSize: 10, fontWeight: 800, background: "var(--coral)",
                    color: "white", borderRadius: 999, padding: "1px 5px",
                    position: "absolute", top: 6, right: 6 }}>
                    {formsIncomplete + sizesIncomplete}
                  </span>
                )}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* Content */}
      <div style={{ maxWidth: 1200, margin: "0 auto" }}>
        {loading ? (
          <div style={{ padding: "64px 24px", textAlign: "center", color: "var(--ink-muted)" }}>
            Loading student data…
          </div>
        ) : (
          <>
            {tab === "schedule" && <ScheduleTab schedule={schedule} students={students} />}
            {tab === "attendance" && <AttendanceTab students={students} schedule={schedule} user={user} />}
            {tab === "students" && <StudentsTab students={students} user={user} onStudentsUpdate={setStudents} />}
            {tab === "announcements" && <AnnouncementsTab announcements={announcements} user={user} onUpdate={setAnnouncements} />}
          </>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { StaffPage });
