// Project Operations — cohort overview first, drill into a single project on click.
//
// Two instruments, two cadences:
//   • Team Health Survey (27 items) — taken TWICE per project: Baseline (kickoff) +
//     Post-Health (~6 months in). Stages: Baseline pending → Baseline complete →
//     Post-Health window open → Post-Health complete.
//   • Meeting Effectiveness Survey (12 items) — taken WEEKLY. This is the ongoing
//     pulse the PM watches.
//
// PM's #1 question on this page: "Are the surveys being filled?"
// We answer that with: Team Health stage status per project + Meeting Effectiveness
// weekly response rate.

// Stage helper — derived from team.preDone / team.postDone + project age
// Team Health is a 2-wave instrument: Baseline at kickoff, Post-Health ~6 months later.
// Stage progression depends on what's submitted AND how long the project has been in the field.
//   - baseline-pending:  kickoff survey not submitted yet
//   - baseline-complete: kickoff submitted; <6 months in, Post-Health window not open yet
//   - post-window:       ≥6 months in, Post-Health not yet submitted (action needed)
//   - complete:          both waves submitted
const POST_HEALTH_WEEKS = 26; // ~6 months

// Progress color: <50% red, 50-79% yellow, >=80% green
function progressColor(rate) {
  if (rate >= 0.80) return riskColor("healthy");
  if (rate >= 0.50) return riskColor("watch");
  return riskColor("critical");
}
function teamHealthStage(team) {
  if (team.postDone) return { id: "complete", label: "Post-Health complete", short: "Complete" };
  // age = how many weeks since this project's own kickoff (different per project)
  const age = team.weekInProject ?? team.weekly.length;
  const postWindowOpen = age >= POST_HEALTH_WEEKS;
  if (team.preDone && postWindowOpen) return { id: "post-window", label: "Post-Health window open", short: "Post-Health window" };
  if (team.preDone) return { id: "baseline-complete", label: "Baseline complete", short: "Baseline complete" };
  return { id: "baseline-pending", label: "Baseline pending", short: "Baseline pending" };
}
// stage colors — kept restrained, distinct from response-rate red/amber/green
function stageColor(id) {
  if (id === "complete") return "oklch(0.5 0.10 200)";        // muted blue — done
  if (id === "post-window") return "oklch(0.55 0.13 70)";     // amber — action needed
  if (id === "baseline-complete") return "oklch(0.5 0.07 145)"; // muted green — in field
  return "oklch(0.55 0.005 250)";                              // neutral — pending
}

const { useState: useStatePM, useMemo: useMemoPM } = React;

// ---------- Date helpers (plain-English week labels) ----------
function addDays(iso, days) {
  const d = new Date(iso + "T00:00:00");
  d.setDate(d.getDate() + days);
  return d;
}
function fmtMD(d) { return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); }
function fmtMDY(d) { return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }); }
function weekRange(studyStart, weekNum) {
  const start = addDays(studyStart, (weekNum - 1) * 7);
  const end = addDays(studyStart, (weekNum - 1) * 7 + 6);
  const now = new Date(); now.setHours(0, 0, 0, 0);
  const cap = end > now ? now : end;
  return { start, end: cap, rawEnd: end, label: `${fmtMD(start)} – ${fmtMD(cap)}`, shortLabel: fmtMD(start) };
}
function weekRelativeLabel(weekNum, currentWeek) {
  if (weekNum === currentWeek) return "This week";
  if (weekNum === currentWeek - 1) return "Last week";
  if (weekNum === currentWeek + 1) return "Next week";
  const diff = currentWeek - weekNum;
  if (diff > 0) return `${diff} weeks ago`;
  return `In ${-diff} weeks`;
}

// ---------- Subtle construction motif (used very sparingly) ----------
function HardHatMark({ size = 14, color = "currentColor", className = "" }) {
  // Minimalist hard-hat silhouette — used as a tiny eyebrow icon, not decoration.
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" className={className}>
      <path d="M2 11.5h12M3.5 11.5V9.5a4.5 4.5 0 0 1 9 0v2M7 5V3.5h2V5" stroke={color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// ============================================================
// MAIN ROUTER
// ============================================================
function PMView({ data }) {
  const { teams } = data;
  const [selectedId, setSelectedId] = useStatePM(null); // null = cohort overview
  // currentWeek = last week in the array (from weeksElapsed in backend)
  const latestWeek = teams[0].weekly[teams[0].weekly.length - 1].week;
  // Default selected week to the most recent week with any cohort responses
  const mostRecentActiveWeek = (() => {
    for (let w = latestWeek; w >= 1; w--) {
      const total = teams.reduce((s, t) => s + ((t.weekly.find(x => x.week === w) || {}).responses || 0), 0);
      if (total > 0) return w;
    }
    return latestWeek;
  })();
  const [week, setWeek] = useStatePM(mostRecentActiveWeek);
  const [toast, setToast] = useStatePM(null);
  React.useEffect(() => {
    const handler = (e) => {
      setToast(e.detail);
      const t = setTimeout(() => setToast(null), 2200);
      return () => clearTimeout(t);
    };
    window.addEventListener("pm-toast", handler);
    return () => window.removeEventListener("pm-toast", handler);
  }, []);

  if (selectedId) {
    const team = teams.find(t => t.id === selectedId);
    return (
      <>
        <PMProjectDetail team={team} studyStart={data.studyStart} currentWeek={latestWeek} week={week} setWeek={setWeek} onBack={() => setSelectedId(null)}/>
        <Toast msg={toast}/>
      </>
    );
  }
  return (
    <>
      <PMCohortOverview teams={teams} studyStart={data.studyStart} currentWeek={latestWeek} week={week} setWeek={setWeek} onPickProject={setSelectedId}/>
      <Toast msg={toast}/>
    </>
  );
}

// Global helper for Copy/Send actions — dispatches toast via window event
function pmCopyLink(label, msg = "Survey link copied") {
  const url = `https://survey.r-o.com/${label || "team"}`;
  if (navigator.clipboard && navigator.clipboard.writeText) {
    navigator.clipboard.writeText(url).catch(() => {});
  }
  window.dispatchEvent(new CustomEvent("pm-toast", { detail: msg }));
}
function pmSendReminder(msg = "Reminder sent to team") {
  window.dispatchEvent(new CustomEvent("pm-toast", { detail: msg }));
}
function pmDownload(msg = "QR poster downloaded") {
  window.dispatchEvent(new CustomEvent("pm-toast", { detail: msg }));
}

// Tiny floating toast for confirming Copy / Send actions
function Toast({ msg }) {
  if (!msg) return null;
  return (
    <div className="fixed bottom-8 left-1/2 -translate-x-1/2 z-50 px-4 py-2.5 rounded-full text-[13px] font-medium shadow-lg flex items-center gap-2 animate-[fadein_0.2s_ease-out]"
         style={{background: INK, color: "white"}}>
      <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3.5 8.5l3 3 6-6" strokeLinecap="round" strokeLinejoin="round"/></svg>
      {msg}
    </div>
  );
}

// ============================================================
// COHORT OVERVIEW — landing screen
// ============================================================
// Period picker — Entire study + one option per week (most recent first)
function PMDateRangeScope({ value, onChange, currentWeek, studyStart }) {
  const opts = [
    { v: "all", label: "Entire study", sub: `Wk 1 – Wk ${currentWeek} · ${currentWeek} week${currentWeek > 1 ? "s" : ""}` },
    ...Array.from({length: currentWeek}, (_, i) => {
      const wk = currentWeek - i;
      const r = weekRange(studyStart, wk);
      return { v: wk, label: `Week ${wk}`, sub: r.label + (wk === currentWeek ? " · current" : "") };
    }),
  ];
  const [open, setOpen] = useStatePM(false);
  const cur = opts.find(o => o.v === value) || opts[0];
  const INK_C = "oklch(0.22 0.02 250)";
  const SUBINK_C = "oklch(0.45 0.015 250)";
  const RULE_C = "oklch(0.88 0.005 250)";
  const PAPER2_C = "oklch(0.97 0.006 80)";
  return (
    <div className="relative">
      <button onClick={() => setOpen(o => !o)}
        className="inline-flex items-center gap-2 px-3 py-1.5 border rounded-full text-[12px] hover:border-stone-400 transition"
        style={{borderColor: RULE_C, background: "white", color: INK_C}}>
        <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke={SUBINK_C} strokeWidth="1.5"><rect x="2" y="3" width="12" height="11" rx="1.5"/><path d="M2 6h12M5 1.5v3M11 1.5v3"/></svg>
        <span style={{color: SUBINK_C}}>Period:</span>
        <span className="font-medium">{cur.label}</span>
        <svg width="9" height="9" viewBox="0 0 10 10" fill="none" stroke={SUBINK_C} strokeWidth="1.5" style={{transform: open ? "rotate(180deg)" : "none", transition: "transform 0.15s"}}><path d="M2 4l3 3 3-3"/></svg>
      </button>
      {open && (
        <>
          <div className="fixed inset-0 z-30" onClick={() => setOpen(false)}/>
          <div className="absolute right-0 mt-2 z-40 rounded-2xl bg-white border shadow-xl overflow-hidden" style={{borderColor: RULE_C, width: 280}}>
            <div className="px-4 py-2.5 border-b text-[10.5px] tracking-[0.16em] uppercase" style={{borderColor: RULE_C, color: SUBINK_C, background: PAPER2_C}}>Select period</div>
            <div className="max-h-[320px] overflow-y-auto">
              {opts.map(o => (
                <button key={String(o.v)}
                  onClick={() => { onChange(o.v); setOpen(false); }}
                  className="w-full text-left px-4 py-2.5 flex items-center gap-3 border-b last:border-b-0 hover:bg-stone-50 transition"
                  style={{borderColor: RULE_C, background: o.v === value ? PAPER2_C : "transparent"}}>
                  <span className="size-1.5 rounded-full shrink-0" style={{background: o.v === value ? INK_C : "transparent", border: o.v === value ? "none" : `1px solid ${SUBINK_C}`}}/>
                  <div className="flex-1">
                    <div className="text-[12.5px] font-medium" style={{color: INK_C}}>{o.label}</div>
                    <div className="text-[11px] font-mono tabular-nums" style={{color: SUBINK_C}}>{o.sub}</div>
                  </div>
                </button>
              ))}
            </div>
          </div>
        </>
      )}
    </div>
  );
}

function PMCohortOverview({ teams, studyStart, currentWeek, week, setWeek, onPickProject }) {
  const totalPeople = teams.reduce((s, t) => s + t.size, 0);

  // Period scope — "all" (entire study) or a specific week number
  const [scope, setScope] = useStatePM("all");
  const scopeWeeks = useMemoPM(() => {
    if (scope === "all") return Array.from({length: currentWeek}, (_, i) => i + 1);
    return [scope]; // scope is a week number
  }, [scope, currentWeek]);
  // Sync sparkline selection when a specific week is picked
  React.useEffect(() => {
    if (typeof scope === "number") setWeek(scope);
  }, [scope]);
  const scopeStartWk = scopeWeeks[0];
  const scopeEndWk = scopeWeeks[scopeWeeks.length - 1];
  const scopeStartDate = weekRange(studyStart, scopeStartWk).start;
  const scopeEndDate = weekRange(studyStart, scopeEndWk).end;

  // Meeting Effectiveness — averaged across scoped weeks
  const scopedResponses = teams.reduce((s, t) => s + scopeWeeks.reduce((w, wk) => w + (t.weekly.find(x => x.week === wk)?.responses || 0), 0), 0);
  const scopedDenom = totalPeople;  // per-week denominator
  const scopedRate = scopedDenom && scopeWeeks.length ? scopedResponses / (totalPeople * scopeWeeks.length) : 0;
  // Comparison: prior equivalent window
  const priorWeeks = scopeWeeks.map(w => w - scopeWeeks.length).filter(w => w >= 1);
  const priorResponses = teams.reduce((s, t) => s + priorWeeks.reduce((w, wk) => w + (t.weekly.find(x => x.week === wk)?.responses || 0), 0), 0);
  const priorDenom = totalPeople;  // per-week denominator
  const priorRate = priorDenom && priorWeeks.length ? priorResponses / (totalPeople * priorWeeks.length) : 0;
  const isCurrent = week === currentWeek;
  const range = weekRange(studyStart, week);

  // Team Health — 2-wave stages
  const stageBuckets = teams.reduce((acc, t) => {
    const id = teamHealthStage(t).id;
    acc[id] = (acc[id] || 0) + 1;
    return acc;
  }, {});
  const baselinePending  = stageBuckets["baseline-pending"]  || 0;
  const baselineComplete = stageBuckets["baseline-complete"] || 0;
  const postWindow       = stageBuckets["post-window"]       || 0;
  const completeCount    = stageBuckets["complete"]          || 0;
  // Counts of completed Baseline / Post-Health surveys submitted across the cohort
  const baselineDoneCount = teams.filter(t => t.preDone).length;
  const postDoneCount     = teams.filter(t => t.postDone).length;
  // People-level totals (denominator: every individual in the study)
  const baselinePeopleSubmitted = teams.reduce((s, t) => s + (t.baselineSubmitted || 0), 0);
  const postHealthPeopleSubmitted = teams.reduce((s, t) => s + (t.postHealthSubmitted || 0), 0);
  // Next Post-Health window opening date across the cohort
  const nextPostOpens = teams
    .filter(t => !t.postDone)
    .map(t => t.postHealthOpenDate)
    .sort()[0];

  return (
    <div className="space-y-10">
      {/* Hero */}
      <section>
        <div className="flex items-start justify-between gap-6 flex-wrap">
          <div>
            <h1 className="text-[40px] tracking-[-0.025em] font-semibold leading-[1.05]" style={{color: INK, maxWidth: 820}}>
              {teams.length} active projects
            </h1>
          </div>
          <div className="flex flex-col items-end gap-2 pt-2">
            <PMDateRangeScope value={scope} onChange={setScope} currentWeek={currentWeek} studyStart={studyStart}/>
            <div className="text-[10.5px] tracking-[0.14em] uppercase" style={{color: SUBINK}}>
              {scope === "all"
                ? `${fmtMD(scopeStartDate)} – ${fmtMDY(scopeEndDate)}`
                : weekRange(studyStart, scope).label}
            </div>
          </div>
        </div>

        {/* At-a-glance counts — directly under the headline */}
        <div className="mt-5 rounded-[20px] border bg-white grid grid-cols-3 divide-x" style={{borderColor: RULE}}>
          <BottomStat label="People in study" value={totalPeople} hint="across all projects"/>
          <BottomStat label="Baseline submitted" value={`${baselinePeopleSubmitted} / ${totalPeople}`} hint="Team Health · wave 1"/>
          <BottomStat label="Meeting responses" value={teams.reduce((s, t) => s + t.weekly.reduce((a, w) => a + w.responses, 0), 0).toLocaleString()} hint="study to date"/>
        </div>

        <div className="mt-8 space-y-4">
          {/* MEETING EFFECTIVENESS — primary tracker, full-width */}
          <div className="rounded-[28px] bg-white border p-7" style={{borderColor: RULE}}>
            <div className="flex items-baseline justify-between gap-3 flex-wrap">
              <div>
                <h3 className="text-[20px] tracking-tight font-semibold" style={{color: INK}}>Meeting Effectiveness · {scope === "all" ? "entire study" : `Week ${scope}`}</h3>
                <p className="text-[13px] mt-1" style={{color: SUBINK}}>12 questions · weekly · {scope === "all" ? `Wk 1–${scopeEndWk}` : weekRange(studyStart, scope).label}</p>
              </div>
            </div>
            <div className="mt-6 grid grid-cols-12 gap-8 items-end">
              <div className="col-span-3">
                <div className="text-[88px] tracking-[-0.04em] font-semibold leading-none tabular-nums" style={{color: INK}}>
                  {Math.round(scopedRate * 100)}<span className="text-[36px]" style={{color: SUBINK}}>%</span>
                </div>
                <div className="mt-3 text-[14px] font-medium" style={{color: INK}}>
                  {scope !== "all"
                    ? <>{scopedResponses} of {totalPeople} responded</>
                    : <>{scopedResponses} submissions · {totalPeople} people</>}
                </div>
                <div className="text-[12px] mt-0.5" style={{color: SUBINK}}>
                  {scope !== "all"
                    ? (priorWeeks.length ? `Prior: Wk ${priorWeeks[0]} was ${Math.round(priorRate * 100)}% · ${priorResponses} submissions` : "No prior week data")
                    : `avg ${Math.round(scopedRate * 100)}%/wk · ${scopeWeeks.length} week${scopeWeeks.length > 1 ? "s" : ""}`}
                </div>
              </div>
              <div className="col-span-9">
                <CohortSparkline teams={teams} totalPeople={totalPeople} currentWeek={currentWeek} studyStart={studyStart} selected={week}
                  onPick={(w) => { setWeek(w); setScope(w); }}
                  highlightWeeks={scopeWeeks}/>
              </div>
            </div>
          </div>

          {/* TEAM HEALTH — Pre→Post 2-bullet timeline */}
          <TeamHealthCohortTimeline
            teams={teams}
            totalPeople={totalPeople}
            baselinePeopleSubmitted={baselinePeopleSubmitted}
            postHealthPeopleSubmitted={postHealthPeopleSubmitted}
            nextPostOpens={nextPostOpens}
          />
        </div>
      </section>

      {/* Projects grid */}
      <section>
        <div className="flex items-end justify-between mb-5 gap-4 flex-wrap">
          <div>
            <h2 className="text-[22px] tracking-[-0.015em] font-semibold" style={{color: INK}}>Projects <span className="font-normal tabular-nums" style={{color: SUBINK}}>· {teams.length}</span></h2>
            <p className="text-[14px] mt-1" style={{color: SUBINK}}>
              Each card shows the Team Health stage and the Meeting Effectiveness response rate for{" "}
              <span style={{color: INK, fontWeight: 500}}>
                {scope === "all"
                  ? `the entire study (Wk 1\u2013${currentWeek}, ${currentWeek} week${currentWeek > 1 ? "s" : ""})`
                  : scope === currentWeek
                    ? "this week"
                    : `Wk ${scope}`}
              </span>
              . Open a project for QR codes and outstanding people.
            </p>
          </div>
          <div className="text-[11.5px] flex items-center gap-4" style={{color: SUBINK}}>
            <span className="tracking-[0.14em] uppercase text-[10px]">Meeting response</span>
            <LegendDot color={riskColor("healthy")} label="≥ 80%"/>
            <LegendDot color={riskColor("watch")} label="50–79%"/>
            <LegendDot color={riskColor("critical")} label="Below 50%"/>
          </div>
        </div>
        <div className="grid grid-cols-3 gap-4">
          {teams.map(t => (
            <ProjectCard key={t.id} team={t} currentWeek={currentWeek} scopeWeeks={scopeWeeks} onClick={() => onPickProject(t.id)}/>
          ))}
        </div>
      </section>

      {/* Response activity log */}
      <section>
        <div className="mb-5 flex items-end justify-between gap-4 flex-wrap">
          <div>
            <h2 className="text-[22px] tracking-[-0.015em] font-semibold" style={{color: INK}}>Response activity</h2>
            <p className="text-[14px] mt-1" style={{color: SUBINK}}>Submissions in the selected range — {fmtMD(scopeStartDate)} – {fmtMDY(scopeEndDate)}. Anonymous — we never see who submitted.</p>
          </div>
          <span className="px-3 py-1.5 border rounded-full text-[11.5px] tabular-nums" style={{borderColor: RULE, color: SUBINK, background: "white"}}>
            {scope === "all" ? "All study" : `Week ${scope}`}
          </span>
        </div>
        <div className="rounded-[20px] bg-white border overflow-hidden" style={{borderColor: RULE}}>
          <PMResponseLog teams={teams} scope={scope} scopeWeeks={scopeWeeks} studyStart={studyStart}/>
        </div>
      </section>

      {/* Footer note */}
      <section className="pt-6 border-t" style={{borderColor: RULE}}>
        <p className="text-[12px] leading-relaxed" style={{color: SUBINK, maxWidth: 720}}>
          Every survey is anonymous. We only see counts and team-level summaries — never an individual's answers.
          Health scores and qualitative findings are reviewed by the TAMU research team and shared back at study milestones.
        </p>
      </section>
    </div>
  );
}

// ---------- Team Health cohort timeline ----------
// Two data points per project: Baseline (kickoff) and Post-Health (~6mo in).
// Renders one row per project with two milestones — done dot vs open ring,
// connected by a horizontal time rail. People-level submission count on the right.
function TeamHealthCohortTimeline({ teams, totalPeople, baselinePeopleSubmitted, postHealthPeopleSubmitted, nextPostOpens }) {
  const fmt = (iso) => {
    if (!iso) return "";
    const d = new Date(iso + "T00:00:00");
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
  };
  const fmtLong = (iso) => {
    if (!iso) return "";
    const d = new Date(iso + "T00:00:00");
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
  };
  // Sort: baseline-pending first, then by kickoff date
  const ordered = [...teams].sort((a, b) => {
    if (a.preDone !== b.preDone) return a.preDone ? 1 : -1;
    return a.kickoffDate.localeCompare(b.kickoffDate);
  });
  const baselineDone = teams.filter(t => t.preDone).length;
  const postDone     = teams.filter(t => t.postDone).length;

  const [expanded, setExpanded] = useStatePM(false);
  const baselinePct = totalPeople ? Math.round((baselinePeopleSubmitted / totalPeople) * 100) : 0;
  const postPct = totalPeople ? Math.round((postHealthPeopleSubmitted / totalPeople) * 100) : 0;

  return (
    <div className="rounded-[28px] bg-white border" style={{borderColor: RULE}}>
      {/* HEADER — always visible (expansion no longer needed; detail is always open) */}
      <div className="w-full px-7 py-5 flex items-center gap-6">
        <div className="shrink-0">
          <h3 className="text-[18px] tracking-tight font-semibold" style={{color: INK}}>Team Health · Pre &rarr; Post</h3>
          <p className="text-[12px] mt-0.5" style={{color: SUBINK}}>{teams.length} projects · two waves each</p>
        </div>
        {/* Baseline progress bar only */}
        <div className="flex-1 min-w-0">
          <div className="flex items-baseline justify-between mb-1.5">
            <div className="flex items-center gap-2">
              <MilestoneDot done size={8}/>
              <span className="text-[11px] tracking-[0.12em] uppercase" style={{color: SUBINK}}>Baseline</span>
            </div>
            <div className="text-[12px] tabular-nums" style={{color: INK}}>
              <span className="font-semibold">{baselinePeopleSubmitted}</span><span style={{color: SUBINK}}> / {totalPeople}</span>
            </div>
          </div>
          <div className="h-1.5 rounded-full overflow-hidden" style={{background: "oklch(0.93 0.005 80)"}}>
            <div className="h-full" style={{width: `${baselinePct}%`, background: "oklch(0.45 0.11 145)"}}/>
          </div>
          <div className="text-[10.5px] mt-1 tabular-nums" style={{color: SUBINK}}>{baselineDone} of {teams.length} projects complete</div>
        </div>
        {/* Per-project status pip strip — at-a-glance health of all 11 */}
        <div className="shrink-0 flex items-center gap-2 pl-2 border-l" style={{borderColor: RULE}}>
          <div className="flex flex-col gap-1">
            <div className="flex gap-[3px]">
              {ordered.map(t => (
                <span key={`b-${t.id}`} className="w-1.5 h-3 rounded-sm" title={`${t.short} · Baseline ${t.preDone ? "submitted" : "pending"}`}
                  style={{background: t.preDone ? "oklch(0.45 0.11 145)" : "oklch(0.88 0.005 250)"}}/>
              ))}
            </div>

          </div>
        </div>
      </div>

      {/* DETAIL — full per-project timeline (always shown) */}
      <div className="px-7 pb-6 border-t pt-4" style={{borderColor: RULE}}>
        {/* Header rail */}
        <div className="grid gap-x-8 items-center pb-3 mb-2 border-b" style={{borderColor: RULE, gridTemplateColumns: "1fr 1fr auto"}}>
          <div className="text-[10px] tracking-[0.16em] uppercase" style={{color: SUBINK}}>Project</div>
          <div className="text-[10px] tracking-[0.16em] uppercase" style={{color: SUBINK}}>Baseline</div>
          <div className="text-[10px] tracking-[0.16em] uppercase text-right" style={{color: SUBINK}}>Submissions</div>
        </div>

        <ul className="divide-y" style={{borderColor: RULE}}>
          {ordered.map(t => {
            return (
              <li key={t.id} className="grid gap-x-8 items-center py-2.5" style={{gridTemplateColumns: "1fr 1fr auto"}}>
                <div className="min-w-0">
                  <div className="text-[13px] tracking-tight font-semibold truncate" style={{color: INK}}>{t.short}</div>
                  <div className="text-[10.5px] tabular-nums" style={{color: SUBINK}}>{t.code} · {t.size} ppl</div>
                </div>
                <div className="flex items-center gap-2.5">
                  <MilestoneDot done={t.preDone} size={12}/>
                  <div className="min-w-0">
                    <div className="text-[12px] tracking-tight font-medium leading-none" style={{color: t.preDone ? INK : SUBINK}}>{t.preDone ? "Submitted" : "Pending"}</div>
                  </div>
                </div>
                <div className="text-right">
                  <div className="text-[13px] tabular-nums font-semibold" style={{color: INK}}>{t.baselineSubmitted} <span className="font-normal" style={{color: SUBINK}}>/ {t.size}</span></div>
                  <div className="text-[10.5px]" style={{color: SUBINK}}>people</div>
                </div>
              </li>
            );
          })}
        </ul>

      </div>
    </div>
  );
}

// Milestone dot: filled = submitted, outlined = pending/upcoming
function MilestoneDot({ done, size = 12, pending = false }) {
  const s = `${size}px`;
  if (done) {
    return <span className="rounded-full inline-block shrink-0" style={{width: s, height: s, background: "oklch(0.45 0.11 145)"}}/>;
  }
  return (
    <span className="rounded-full inline-block shrink-0 border-[1.5px]" style={{width: s, height: s, borderColor: pending ? "oklch(0.65 0.04 250)" : RULE, background: "white"}}/>
  );
}

// ---------- Response activity log (PM view) ----------
// Operations-friendly: shows who submitted what & when, anonymized.
// No scores, no durations — just project / instrument / wave / time / status.
function PMResponseLog({ teams, scope = "1w", scopeWeeks = [], studyStart }) {
  const all = [];
  const today = new Date();
  const studyStartMs = new Date((studyStart || "2026-04-26") + "T00:00:00").getTime();
  teams.forEach((t, ti) => {
    (t.recentSubmissions || []).forEach((s, i) => {
      const submitted = new Date(s.date);
      const minsAgo = Math.round((today.getTime() - submitted.getTime()) / 60000);
      // Compute the study week number from the actual submission date
      const daysDiff = Math.floor((submitted.getTime() - studyStartMs) / (24 * 60 * 60 * 1000));
      const wkNum = daysDiff >= 0 ? Math.max(1, Math.floor(daysDiff / 7) + 1) : 0;
      all.push({
        id: `${t.id}-${s.type}-${i}`,
        team: t,
        instrument: s.type === "health" ? "Team Health" : "Meeting Effectiveness",
        wave: s.type === "health" ? "Baseline" : `Week ${wkNum}`,
        wkNum,
        submitted,
        minsAgo,
        complete: true,
      });
    });
  });
  // Filter by scope: use week-number matching, not elapsed minutes
  const filtered = all.filter(r => {
    if (scope === "all") return true;
    return scopeWeeks.includes(r.wkNum);
  });
  filtered.sort((a, b) => b.submitted - a.submitted);
  const rowCap = scope === "all" ? 30 : 14;
  const rows = filtered.slice(0, rowCap);
  const fmtAgo = (m) => {
    if (m < 60) return `${m}m ago`;
    if (m < 60 * 24) return `${Math.floor(m/60)}h ${m%60}m ago`;
    return `${Math.floor(m/1440)}d ago`;
  };
  const fmtTime = (d) => d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
  const fmtDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" });

  return (
    <div>
      <div className="grid grid-cols-12 gap-3 text-[10.5px] tracking-[0.14em] uppercase px-6 py-3 border-b" style={{borderColor: RULE, background: PAPER_2, color: SUBINK}}>
        <div className="col-span-4">Project</div>
        <div className="col-span-3">Instrument</div>
        <div className="col-span-2">Wave</div>
        <div className="col-span-2">Submitted</div>
        <div className="col-span-1 text-right">Status</div>
      </div>
      {rows.map(r => (
        <div key={r.id} className="grid grid-cols-12 gap-3 px-6 py-2.5 border-b last:border-b-0 text-[12.5px] hover:bg-stone-50/60 items-center" style={{borderColor: RULE}}>
          <div className="col-span-4 truncate" style={{color: INK}}>
            <span className="font-medium">{r.team.short}</span>
            <span className="ml-2 text-[11px] tabular-nums" style={{color: SUBINK}}>{r.team.code}</span>
          </div>
          <div className="col-span-3 truncate" style={{color: SUBINK}}>{r.instrument}</div>
          <div className="col-span-2 font-mono tabular-nums text-[12px]" style={{color: INK}}>{r.wave}</div>
          <div className="col-span-2 font-mono tabular-nums text-[11.5px] whitespace-nowrap" style={{color: SUBINK}}>
            {r.minsAgo < 60 * 24 ? `${fmtTime(r.submitted)} · ${fmtAgo(r.minsAgo)}` : `${fmtDate(r.submitted)} · ${fmtAgo(r.minsAgo)}`}
          </div>
          <div className="col-span-1 text-right">
            {r.complete ? (
              <span className="inline-flex items-center gap-1 text-[11px] font-medium" style={{color: "oklch(0.42 0.12 145)"}}>
                <span className="size-1.5 rounded-full" style={{background: "oklch(0.55 0.13 145)"}}/>
                Complete
              </span>
            ) : (
              <span className="inline-flex items-center gap-1 text-[11px] font-medium" style={{color: "oklch(0.5 0.10 80)"}}>
                <span className="size-1.5 rounded-full" style={{background: "oklch(0.7 0.12 80)"}}/>
                Partial
              </span>
            )}
          </div>
        </div>
      ))}
      <div className="px-6 py-3 text-[11px]" style={{color: SUBINK, background: PAPER_2}}>
        Showing latest {rows.length} · all submissions are anonymous.
      </div>
    </div>
  );
}

function TrendChip({ trend }) {
  const pts = Math.round(trend * 100);
  if (Math.abs(pts) < 1) {
    return (
      <div className="text-[12px] px-2.5 py-1 rounded-full border inline-flex items-center gap-1.5" style={{borderColor: RULE, color: SUBINK}}>
        <span>Steady vs last week</span>
      </div>
    );
  }
  const up = pts > 0;
  const color = up ? "oklch(0.42 0.12 145)" : "oklch(0.5 0.14 28)";
  const bg = up ? "oklch(0.96 0.04 145)" : "oklch(0.97 0.03 28)";
  return (
    <div className="text-[12px] px-2.5 py-1 rounded-full inline-flex items-center gap-1.5 font-medium" style={{background: bg, color}}>
      <svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2">
        {up ? <path d="M3 8l3-4 3 4" strokeLinecap="round" strokeLinejoin="round"/> : <path d="M3 4l3 4 3-4" strokeLinecap="round" strokeLinejoin="round"/>}
      </svg>
      <span>{up ? "+" : ""}{pts} pts vs last week</span>
    </div>
  );
}

// Compact stage pill — used in the cohort slim status strip
function StagePill({ count, label, color }) {
  return (
    <div className="flex items-center gap-2.5">
      <span className="size-2 rounded-full shrink-0" style={{background: color}}/>
      <div className="min-w-0">
        <div className="flex items-baseline gap-1.5">
          <span className="text-[18px] tracking-tight font-semibold leading-none tabular-nums" style={{color: INK}}>{count}</span>
          <span className="text-[10.5px] font-medium tracking-tight leading-tight" style={{color: SUBINK}}>{label}</span>
        </div>
      </div>
    </div>
  );
}

// Stage funnel cell — used in the cohort Team Health card
function StageCell({ count, total, label, hint, color, last }) {
  const pct = total ? Math.round((count / total) * 100) : 0;
  return (
    <div className={"px-4 py-4 flex flex-col gap-1 relative " + (last ? "" : "border-r")} style={{borderColor: RULE}}>
      {/* color rail */}
      <span className="absolute left-0 top-3 bottom-3 w-[3px] rounded-r" style={{background: color}}/>
      <div className="pl-2">
        <div className="text-[28px] tracking-[-0.02em] font-semibold leading-none tabular-nums" style={{color: INK}}>
          {count}<span className="text-[12px] ml-1 font-normal" style={{color: SUBINK}}>of {total}</span>
        </div>
        <div className="text-[12px] tracking-tight font-medium mt-2" style={{color: INK}}>{label}</div>
        <div className="text-[10.5px] mt-0.5 leading-snug" style={{color: SUBINK}}>{hint}</div>
      </div>
    </div>
  );
}

// Bottom strip stat (cohort hero footer)
function BottomStat({ label, value, hint }) {
  return (
    <div className="px-5 py-4" style={{borderColor: RULE}}>
      <div className="text-[10px] tracking-[0.16em] uppercase" style={{color: SUBINK}}>{label}</div>
      <div className="text-[22px] tracking-tight font-semibold tabular-nums mt-1" style={{color: INK}}>{value}</div>
      {hint && <div className="text-[11px] mt-0.5" style={{color: SUBINK}}>{hint}</div>}
    </div>
  );
}

function StatusRow({ count, total, label, hint, color, last }) {
  return (
    <div className={"px-6 py-3.5 flex items-center gap-4 " + (last ? "" : "border-b")} style={{borderColor: RULE}}>
      <span className="size-2.5 rounded-full shrink-0" style={{background: color}}/>
      <div className="flex-1 min-w-0">
        <div className="text-[14px] tracking-tight font-medium" style={{color: INK}}>{label}</div>
        <div className="text-[12px] mt-0.5" style={{color: SUBINK}}>{hint}</div>
      </div>
      <div className="text-right tabular-nums">
        <span className="text-[24px] tracking-tight font-semibold" style={{color: INK}}>{count}</span>
        <span className="text-[13px] ml-1" style={{color: SUBINK}}>/ {total}</span>
      </div>
    </div>
  );
}

function LegendDot({ color, label }) {
  return (
    <span className="inline-flex items-center gap-1.5">
      <span className="size-2 rounded-full" style={{background: color}}/>{label}
    </span>
  );
}

// 8-week cohort response-rate sparkline — clickable: each week is selectable
function CohortSparkline({ teams, totalPeople, currentWeek, studyStart, selected, onPick, highlightWeeks = [] }) {
  const hi = new Set(highlightWeeks);
  const weeks = teams[0].weekly.map(w => {
    const responses = teams.reduce((s, t) => s + (t.weekly.find(x => x.week === w.week)?.responses || 0), 0);
    return { week: w.week, rate: totalPeople ? responses / totalPeople : 0, responses };
  });
  const width = 760, height = 160;
  const padL = 36, padR = 24, padT = 22, padB = 36;
  const w = width - padL - padR, h = height - padT - padB;
  const xs = i => weeks.length <= 1 ? padL + w / 2 : padL + (i / (weeks.length - 1)) * w;
  const ys = v => padT + h - v * h;
  const path = weeks.map((d, i) => `${i ? "L" : "M"}${xs(i)},${ys(d.rate)}`).join(" ");
  const area = path + ` L${xs(weeks.length - 1)},${padT + h} L${xs(0)},${padT + h} Z`;

  return (
    <div className="-mx-2">
      <div className="text-[11px] tracking-[0.16em] uppercase mb-2 px-1" style={{color: SUBINK}}>Weekly response rate · click any week</div>
      <svg width="100%" height={height} viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" style={{display: "block"}}>
        {/* gridline at 100% */}
        <line x1={padL} x2={width - padR} y1={ys(1)} y2={ys(1)} stroke={RULE} strokeDasharray="2 4"/>
        <text x={padL - 4} y={ys(1) + 3} fontSize="9.5" textAnchor="end" fill={SUBINK} fontFamily="JetBrains Mono, monospace">100%</text>
        <path d={area} fill="oklch(0.55 0.08 200 / 0.06)"/>
        {hi.size > 0 && hi.size < weeks.length && (() => {
          const idxs = weeks.map((d, i) => hi.has(d.week) ? i : -1).filter(i => i >= 0);
          if (idxs.length === 0) return null;
          const x0 = xs(idxs[0]) - 10;
          const x1 = xs(idxs[idxs.length - 1]) + 10;
          return <rect x={x0} y={padT - 4} width={x1 - x0} height={h + 8} rx="8" fill="oklch(0.55 0.08 200 / 0.07)" stroke="oklch(0.55 0.08 200 / 0.25)" strokeDasharray="3 3"/>;
        })()}
        <path d={path} fill="none" stroke="oklch(0.5 0.09 200)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke"/>
        {weeks.map((d, i) => {
          const isSel = d.week === selected;
          const isCur = d.week === currentWeek;
          const showLabel = isSel || isCur;
          return (
            <g key={i} style={{cursor: "pointer"}} onClick={() => onPick && onPick(d.week)}>
              {/* hit area */}
              <rect x={xs(i) - 22} y={padT - 4} width="44" height={h + 8} fill="transparent"/>
              {isSel && <rect x={xs(i) - 18} y={padT - 4} width="36" height={h + 8} rx="6" fill="oklch(0.5 0.09 200 / 0.08)"/>}
              <circle cx={xs(i)} cy={ys(d.rate)} r={isSel ? 5.5 : isCur ? 4.5 : 4}
                      fill={isSel ? "oklch(0.5 0.09 200)" : "white"}
                      stroke="oklch(0.5 0.09 200)" strokeWidth={isSel ? 2 : 1.5}/>
              {showLabel && (
                <text x={xs(i)} y={ys(d.rate) - 10} fontSize="12" fontWeight={isSel || isCur ? 600 : 500} textAnchor="middle" fill={isSel || isCur ? INK : SUBINK} fontFamily="JetBrains Mono, monospace">
                  {Math.round(d.rate * 100)}%
                </text>
              )}
              <text x={xs(i)} y={padT + h + 16} fontSize="11" textAnchor="middle"
                    fill={isSel || isCur ? INK : SUBINK} fontWeight={isSel || isCur ? 600 : 400}
                    fontFamily="JetBrains Mono, monospace">
                Wk {d.week}
              </text>
              {isCur && (
                <text x={xs(i)} y={padT + h + 30} fontSize="9" textAnchor="middle" fill={SUBINK} fontFamily="JetBrains Mono, monospace" letterSpacing="0.12em" fontWeight="600">
                  NOW
                </text>
              )}
            </g>
          );
        })}
      </svg>
    </div>
  );
}

// Compact dropdown picker for the hero — calendar-style list of weeks
function CohortWeekPicker({ teams, studyStart, currentWeek, selected, onPick }) {
  const [open, setOpen] = useStatePM(false);
  const weeks = teams[0].weekly;
  const totalPeople = teams.reduce((s, t) => s + t.size, 0);
  const range = weekRange(studyStart, selected);
  const isCurrent = selected === currentWeek;
  return (
    <div className="relative">
      <button
        onClick={() => setOpen(o => !o)}
        className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full border bg-white hover:border-stone-400 transition-colors"
        style={{borderColor: RULE}}
      >
        <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke={SUBINK} strokeWidth="1.5"><rect x="2" y="3" width="12" height="11" rx="1.5"/><path d="M2 6h12M5 1.5v3M11 1.5v3"/></svg>
        <span className="text-[12.5px] font-medium tabular-nums" style={{color: INK}}>{range.label}</span>
        {isCurrent && <span className="text-[10px] tracking-[0.14em] uppercase px-1.5 py-0.5 rounded-sm" style={{background: PAPER_2, color: SUBINK}}>Now</span>}
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke={SUBINK} strokeWidth="1.5" style={{transform: open ? "rotate(180deg)" : "none", transition: "transform 0.15s"}}><path d="M2 4l3 3 3-3"/></svg>
      </button>
      {open && (
        <>
          <div className="fixed inset-0 z-30" onClick={() => setOpen(false)}/>
          <div className="absolute right-0 mt-2 z-40 rounded-2xl bg-white border shadow-xl overflow-hidden" style={{borderColor: RULE, width: 320}}>
            <div className="px-4 py-3 border-b text-[10.5px] tracking-[0.16em] uppercase" style={{borderColor: RULE, color: SUBINK, background: PAPER_2}}>Pick a week</div>
            <div className="max-h-[320px] overflow-y-auto">
              {weeks.slice().reverse().map(w => {
                const r = weekRange(studyStart, w.week);
                const responses = teams.reduce((s, t) => s + (t.weekly.find(x => x.week === w.week)?.responses || 0), 0);
                const rate = totalPeople ? responses / totalPeople : 0;
                const sel = w.week === selected;
                const cur = w.week === currentWeek;
                const c = progressColor(rate);
                return (
                  <button key={w.week}
                    onClick={() => { onPick(w.week); setOpen(false); }}
                    className="w-full text-left px-4 py-2.5 flex items-center gap-3 border-b last:border-b-0 hover:bg-stone-50 transition-colors"
                    style={{borderColor: RULE, background: sel ? PAPER_2 : "transparent"}}>
                    <span className="size-2 rounded-full shrink-0" style={{background: c}}/>
                    <div className="flex-1 min-w-0">
                      <div className="text-[12.5px] font-medium tabular-nums" style={{color: INK}}>{r.label}</div>
                      <div className="text-[11px] tabular-nums" style={{color: SUBINK}}>Week {w.week}{cur ? " · This week" : ""}</div>
                    </div>
                    <div className="text-[12.5px] font-mono tabular-nums shrink-0" style={{color: INK}}>{Math.round(rate * 100)}%</div>
                  </button>
                );
              })}
            </div>
          </div>
        </>
      )}
    </div>
  );
}

// Project card — updates with selected scope (specific week or entire study)
function ProjectCard({ team, currentWeek, scopeWeeks, onClick }) {
  const isAll = !scopeWeeks || scopeWeeks.length > 1;

  let pct, responses, denom, diff, scopeLabel, footerText;

  if (isAll) {
    // Multi-week / entire study: total responses ÷ (team size × number of weeks in scope)
    const weeks = scopeWeeks ? scopeWeeks : Array.from({length: currentWeek}, (_, i) => i + 1);
    const totalResp = weeks.reduce((s, wk) => s + (team.weekly.find(w => w.week === wk)?.responses || 0), 0);
    denom = team.size * weeks.length;
    const avgRate = denom ? totalResp / denom : 0;
    pct = Math.round(avgRate * 100);
    responses = totalResp;
    diff = null;
    scopeLabel = `${weeks.length}-wk avg`;
    footerText = `${responses} of ${denom} possible (${team.size} ppl × ${weeks.length} wk${weeks.length > 1 ? "s" : ""})`;
  } else {
    // Single week
    const wkNum = scopeWeeks[0];
    const entry = team.weekly.find(w => w.week === wkNum) || { responses: 0, rate: 0, week: wkNum };
    const prevEntry = wkNum > 1 ? team.weekly.find(w => w.week === wkNum - 1) : null;
    pct = Math.round(entry.rate * 100);
    responses = entry.responses;
    denom = team.size;
    const prevPct = prevEntry ? Math.round(prevEntry.rate * 100) : null;
    diff = prevPct !== null ? pct - prevPct : null;
    scopeLabel = wkNum === currentWeek ? "this week" : wkNum === currentWeek - 1 ? "last week" : `Wk ${wkNum}`;
    const pending = denom - responses;
    footerText = responses === denom
      ? "Everyone responded"
      : wkNum < currentWeek
        ? `${responses} of ${denom} responded`
        : `${pending} pending`;
  }

  const status = pct >= 80 ? "healthy" : pct >= 50 ? "watch" : "critical";
  const accent = riskColor(status);
  const stage = teamHealthStage(team);
  const stageC = stageColor(stage.id);

  return (
    <button onClick={onClick}
      className="text-left rounded-[20px] bg-white border p-5 transition-all duration-200 group hover:shadow-[0_8px_24px_rgba(0,0,0,0.06)] hover:-translate-y-0.5 hover:border-[oklch(0.78_0.005_250)]"
      style={{borderColor: RULE}}>
      {/* Header */}
      <div className="flex items-start justify-between gap-3 mb-3">
        <div className="min-w-0 flex-1">
          <div className="text-[10px] font-mono tracking-[0.16em] uppercase" style={{color: SUBINK}}>{team.code} · {team.region}</div>
          <div className="text-[15px] tracking-tight font-semibold leading-tight mt-1.5 truncate" style={{color: INK}}>{team.short}</div>
          <div className="text-[12px] mt-1" style={{color: SUBINK}}>{team.sector} · {team.size} people</div>
        </div>
      </div>

      {/* Team Health row — always current stage, unaffected by scope */}
      <div className="rounded-[12px] border px-3 py-2.5 flex items-center gap-3" style={{borderColor: RULE, background: PAPER_2}}>
        <span className="size-2 rounded-full shrink-0" style={{background: stageC}}/>
        <div className="flex-1 min-w-0">
          <div className="text-[10px] tracking-[0.14em] uppercase" style={{color: SUBINK}}>Team Health</div>
          <div className="text-[12.5px] font-medium tracking-tight truncate" style={{color: INK}}>{stage.short}</div>
        </div>
        <div className="text-[10.5px] font-mono tabular-nums shrink-0" style={{color: SUBINK}}>
          {team.preDone ? "✓" : "·"} Baseline · {team.postDone ? "✓" : "·"} Post
        </div>
      </div>

      {/* Meeting Effectiveness — scoped */}
      <div className="mt-4">
        <div className="flex items-baseline justify-between gap-2">
          <div className="text-[10px] tracking-[0.14em] uppercase" style={{color: SUBINK}}>
            Meeting Effectiveness · <span style={{color: scopeLabel === "this week" ? INK : "oklch(0.55 0.13 70)"}}>{scopeLabel}</span>
          </div>
          {diff !== null && diff !== 0 && (
            <span className="inline-flex items-center gap-0.5 text-[11px] font-mono tabular-nums px-1.5 py-0.5 rounded" style={{
              background: diff > 0 ? "oklch(0.96 0.04 145)" : "oklch(0.97 0.03 28)",
              color: diff > 0 ? "oklch(0.42 0.12 145)" : "oklch(0.5 0.14 28)"
            }}>
              <span>{diff > 0 ? "↑" : "↓"}</span>{Math.abs(diff)}
            </span>
          )}
        </div>
        <div className="flex items-baseline gap-2 mt-1.5">
          <span className="text-[44px] tracking-[-0.03em] font-semibold leading-none tabular-nums" style={{color: accent}}>{pct}</span>
          <span className="text-[16px]" style={{color: SUBINK}}>%</span>
          <span className="text-[12.5px] ml-auto tabular-nums" style={{color: SUBINK}}>
            <span style={{color: INK, fontWeight: 500}}>{responses}</span> / {denom}
          </span>
        </div>
        <div className="mt-3 w-full rounded-full h-[6px]" style={{background: "oklch(0.92 0.005 250)"}}>
          <div className="h-full rounded-full transition-all" style={{width: `${Math.min(pct, 100)}%`, background: progressColor(pct / 100)}}/>
        </div>
      </div>

      {/* Footer */}
      <div className="mt-3 pt-3 border-t flex items-center justify-between text-[12px]" style={{borderColor: RULE}}>
        <span style={{color: SUBINK}}>{footerText}</span>
        <span className="inline-flex items-center gap-1 font-medium transition-all group-hover:gap-1.5" style={{color: INK}}>
          Open<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M6 3l5 5-5 5" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </span>
      </div>
    </button>
  );
}

// ============================================================
// PROJECT DETAIL — drill-in
// ============================================================
function PMProjectDetail({ team, studyStart, currentWeek, week: parentWeek, setWeek: parentSetWeek, onBack }) {
  const [localWeek, setLocalWeek] = useStatePM(parentWeek ?? currentWeek);
  const week = parentWeek ?? localWeek;
  const setWeek = parentSetWeek ?? setLocalWeek;
  const wk = team.weekly.find(w => w.week === week) || team.weekly[team.weekly.length - 1];
  const lastWk = team.weekly.find(w => w.week === week - 1);
  const pct = Math.round(wk.rate * 100);
  const pending = team.size - wk.responses;
  const status = wk.rate >= 0.80 ? "healthy" : wk.rate >= 0.50 ? "watch" : "critical";
  const range = weekRange(studyStart, week);
  const relLabel = weekRelativeLabel(week, currentWeek);

  return (
    <div className="space-y-8">
      {/* Back */}
      <button onClick={onBack} className="inline-flex items-center gap-2 text-[13px] hover:opacity-70 transition" style={{color: SUBINK}}>
        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M10 3l-5 5 5 5" strokeLinecap="round" strokeLinejoin="round"/></svg>
        All projects
      </button>

      {/* Project header */}
      <header>
        <div className="flex items-center gap-2 mb-3">
          <HardHatMark size={12} color="oklch(0.45 0.015 250)"/>
          <span className="text-[11px] tracking-[0.2em] uppercase" style={{color: SUBINK}}>{team.code} · {team.region} · {team.sector}</span>
        </div>
        <h1 className="text-[36px] tracking-[-0.02em] font-semibold leading-[1.1]" style={{color: INK}}>{team.name}</h1>
        <p className="text-[15px] mt-2" style={{color: SUBINK}}>{team.size} team members · {team.phase}</p>
      </header>

      {/* HERO — QR codes + Team Health stage panel */}
      <section className="grid grid-cols-12 gap-5">
        {/* QR hero — 7 cols */}
        <div className="col-span-7 rounded-[28px] border overflow-hidden" style={{borderColor: RULE, background: "white"}}>
          <div className="px-7 pt-6 pb-4 border-b flex items-baseline justify-between gap-3" style={{borderColor: RULE}}>
            <div>
              <div className="text-[11px] tracking-[0.18em] uppercase" style={{color: SUBINK}}>Survey access</div>
              <h3 className="text-[18px] tracking-tight font-semibold mt-1" style={{color: INK}}>QR codes for this project</h3>
              <p className="text-[13px] mt-1" style={{color: SUBINK}}>Print on a sign, post in the trailer, or hand out at the next huddle. Scans open Qualtrics.</p>
            </div>
          </div>
          <div className="grid grid-cols-2 divide-x" style={{borderColor: RULE}}>
            <QRHero slug={team.qrSlug} kind="health" label="Team Health" sub="Twice per project · Baseline + Post-Health · 27 questions · ~5 min"/>
            <QRHero slug={team.qrSlug} kind="effectiveness" label="Meeting Effectiveness" sub="Weekly pulse · 12 questions · ~2 min"/>
          </div>
        </div>

        {/* Team Health stage — 5 cols */}
        <TeamHealthStagePanel team={team}/>
      </section>

      {/* Meeting Effectiveness — weekly response history */}
      <section className="rounded-[24px] border bg-white p-7" style={{borderColor: RULE}}>
        <div className="flex items-baseline justify-between mb-1 gap-3 flex-wrap">
          <div>
            <h3 className="text-[17px] tracking-tight font-semibold" style={{color: INK}}>Meeting Effectiveness · weekly response history</h3>
            <p className="text-[13px] mt-1" style={{color: SUBINK}}>Click any week to see how many of the {team.size} team members submitted that week's pulse.</p>
          </div>
          <div className="inline-flex items-baseline gap-2">
            <span className="text-[36px] tracking-[-0.03em] font-semibold leading-none tabular-nums" style={{color: riskColor(status)}}>{pct}</span>
            <span className="text-[14px]" style={{color: SUBINK}}>% this week</span>
          </div>
        </div>
        <ResponseHistoryChart team={team} selected={week} onPick={setWeek} studyStart={studyStart} currentWeek={currentWeek}/>
        <div className="mt-5 pt-5 border-t grid grid-cols-3 gap-6" style={{borderColor: RULE}}>
          <MiniStat label="Average weekly response" value={`${Math.round(avg(team.weekly.map(w=>w.rate))*100)}%`}/>
          <MiniStat label="Meeting responses (total)" value={team.weekly.reduce((s,w)=>s+w.responses,0).toLocaleString()}/>
          <MiniStat label="Best week" value={`${Math.round(Math.max(...team.weekly.map(w=>w.rate))*100)}%`} hint={(() => {
            const best = team.weekly.reduce((a,b)=>b.rate>a.rate?b:a);
            return weekRange(studyStart, best.week).label;
          })()}/>
        </div>
      </section>

      {/* What to do next */}
      <section className="rounded-[24px] border bg-white p-7" style={{borderColor: RULE}}>
        <div className="flex items-baseline justify-between gap-3 flex-wrap">
          <div>
            <h3 className="text-[17px] tracking-tight font-semibold" style={{color: INK}}>What to do next</h3>
            <p className="text-[13px] mt-1" style={{color: SUBINK}}>Suggestions based on Team Health stage and Meeting Effectiveness response trend.</p>
          </div>
        </div>
        <PMSimpleNotes team={team} currentWeek={currentWeek} studyStart={studyStart}/>
      </section>

      {/* Privacy footer */}
      <p className="text-[12px] leading-relaxed pt-2" style={{color: SUBINK, maxWidth: 720}}>
        Survey responses are anonymous. We only see counts and team-level averages — never who said what.
        Health scores and qualitative findings are reviewed by the TAMU research team and shared back at study milestones.
      </p>
    </div>
  );
}

// Team Health stage panel — right column on the project detail.
// Shows: current stage, Baseline progress, Post-Health window, what to share via QR.
function TeamHealthStagePanel({ team }) {
  const stage = teamHealthStage(team);
  const stageC = stageColor(stage.id);
  // Use real submission counts from backend
  const baselineSubmitted = team.baselineSubmitted || 0;
  const postSubmitted     = team.postHealthSubmitted || 0;
  const stages = [
    { id: "baseline-pending", label: "Baseline pending" },
    { id: "baseline-complete", label: "Baseline complete" },
    { id: "post-window", label: "Post-Health window" },
    { id: "complete", label: "Complete" },
  ];
  // current step index: post-window also implies baseline complete
  const currentIdx = stage.id === "complete" ? 3 : stage.id === "post-window" ? 2 : (team.preDone ? 1 : 0);

  return (
    <div className="col-span-5 rounded-[28px] border overflow-hidden flex flex-col" style={{borderColor: RULE, background: "white"}}>
      <div className="px-6 pt-5 pb-4 border-b" style={{borderColor: RULE}}>
        <div className="text-[16px] tracking-tight font-semibold" style={{color: INK}}>Team Health · stage</div>
        <div className="mt-3 inline-flex items-center gap-2 px-2.5 py-1 rounded-full text-[12px] font-medium" style={{background: `${stageC}1f`, color: stageC}}>
          <span className="size-1.5 rounded-full" style={{background: stageC}}/>{stage.label}
        </div>
      </div>

      {/* 4-step progress strip */}
      <div className="px-6 pt-5">
        <div className="relative">
          <div className="absolute left-0 right-0 top-[7px] h-[2px]" style={{background: RULE}}/>
          <div className="absolute left-0 top-[7px] h-[2px] transition-all" style={{background: stageC, width: `${(currentIdx / (stages.length - 1)) * 100}%`}}/>
          <div className="relative flex justify-between">
            {stages.map((s, i) => {
              const done = i <= currentIdx;
              return (
                <div key={s.id} className="flex flex-col items-center gap-1.5" style={{maxWidth: 72}}>
                  <span className="size-4 rounded-full border-2" style={{background: done ? stageC : "white", borderColor: done ? stageC : RULE}}/>
                  <div className="text-[10px] text-center leading-tight" style={{color: done ? INK : SUBINK, fontWeight: done && i === currentIdx ? 600 : 400}}>{s.label}</div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      {/* Baseline / Post-Health submission rows */}
      <div className="px-6 pt-6 pb-2 space-y-3">
        <SurveyWaveRow
          waveLabel="Baseline"
          sublabel="Wave 1 · at kickoff"
          done={team.preDone}
          submitted={baselineSubmitted}
          total={team.size}
          color={stageC}
        />
        <SurveyWaveRow
          waveLabel="Post-Health"
          sublabel="Wave 2 · ~6 months after kickoff"
          done={team.postDone}
          locked={stage.id === "baseline-pending"}
          submitted={postSubmitted}
          total={team.size}
          color={stageC}
        />
      </div>

      {/* What to do */}
      <div className="mt-auto px-6 py-4 border-t text-[12px] leading-relaxed" style={{borderColor: RULE, background: PAPER_2, color: SUBINK}}>
        {stage.id === "baseline-pending" && (
          <>Share the <strong style={{color: INK, fontWeight: 600}}>Team Health QR</strong> at the next huddle. Goal: every team member submits the kickoff survey within the first two weeks.</>
        )}
        {stage.id === "post-window" && (
          <>The 6-month window has opened. Re-share the <strong style={{color: INK, fontWeight: 600}}>Team Health QR</strong> with your team to capture the Post-Health wave.</>
        )}
        {stage.id === "complete" && (
          <>Both Team Health waves are submitted. Continue running Meeting Effectiveness weekly until the project closes.</>
        )}
      </div>
    </div>
  );
}

function SurveyWaveRow({ waveLabel, sublabel, done, locked, submitted, total, color }) {
  const pct = total ? Math.round((submitted / total) * 100) : 0;
  return (
    <div className="rounded-[14px] border px-4 py-3" style={{borderColor: RULE, background: locked ? PAPER_2 : "white", opacity: locked ? 0.65 : 1}}>
      <div className="flex items-baseline justify-between gap-2">
        <div>
          <div className="text-[13px] tracking-tight font-semibold" style={{color: INK}}>{waveLabel}</div>
          <div className="text-[11px] mt-0.5" style={{color: SUBINK}}>{sublabel}</div>
        </div>
        <div className="text-right">
          {locked ? (
            <span className="text-[11px]" style={{color: SUBINK}}>Opens after Baseline</span>
          ) : (
            <>
              <div className="text-[18px] tracking-tight font-semibold leading-none tabular-nums" style={{color: INK}}>{submitted}<span className="text-[12px] font-normal" style={{color: SUBINK}}>/{total}</span></div>
              <div className="text-[10.5px] mt-0.5 tabular-nums" style={{color: done ? color : SUBINK, fontWeight: done ? 600 : 400}}>{done ? "Submitted" : `${pct}% submitted`}</div>
            </>
          )}
        </div>
      </div>
      {!locked && (
        <div className="mt-2.5 h-1.5 rounded-full overflow-hidden" style={{background: PAPER_2}}>
          <div className="h-full rounded-full transition-all" style={{width: `${pct}%`, background: done ? color : progressColor(pct/100)}}/>
        </div>
      )}
    </div>
  );
}

function QRHero({ slug, kind, label, sub }) {
  return (
    <div className="px-7 py-6">
      <div className="text-[18px] tracking-tight font-semibold" style={{color: INK}}>{label}</div>
      <div className="text-[12px] mt-1" style={{color: SUBINK}}>{sub}</div>

      <div className="mt-5 rounded-2xl border bg-white p-4 flex items-center justify-center mx-auto" style={{borderColor: RULE, width: 200, height: 200}}>
        <img src={`assets/qr/${slug}-${kind}.png`} alt={`${label} QR code`}
             style={{width: "100%", height: "100%", display: "block", imageRendering: "pixelated"}}/>
      </div>

      <div className="mt-4 flex items-center justify-center">
        <button onClick={() => pmDownload(`${label} QR poster downloaded`)} className="text-[12px] px-4 py-2 rounded-full border bg-white hover:shadow-sm transition whitespace-nowrap inline-flex items-center justify-center gap-1.5" style={{borderColor: RULE, color: INK}}>
          <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M8 2v8m0 0l-3-3m3 3l3-3M3 13h10" strokeLinecap="round" strokeLinejoin="round"/></svg>
          Download QR poster
        </button>
      </div>
    </div>
  );
}

// Response history chart — 8 weeks, plain English labels
function ResponseHistoryChart({ team, selected, onPick, studyStart, currentWeek }) {
  const padL = 36, padR = 16, padT = 28, padB = 68;
  const slot = 110;
  const width = padL + padR + slot * team.weekly.length;
  const height = 240;
  const w = width - padL - padR, h = height - padT - padB;
  const barW = Math.min(slot - 22, 56);

  return (
    <div className="mt-4 overflow-x-auto -mx-2 px-2">
      <svg width={width} height={height} className="block" style={{minWidth: width}}>
        {/* gridlines: 0%, 50%, 100% */}
        {[0, 0.5, 1].map(p => (
          <g key={p}>
            <line x1={padL} x2={width - padR} y1={padT + h - h * p} y2={padT + h - h * p} stroke={RULE} strokeDasharray={p === 0 ? "" : "2 4"}/>
            <text x={padL - 8} y={padT + h - h * p + 4} fontSize="10" fill={SUBINK} fontFamily="JetBrains Mono, monospace" textAnchor="end">{Math.round(p * 100)}%</text>
          </g>
        ))}
        {team.weekly.map((d, i) => {
          const cx = padL + i * slot + slot / 2;
          const bh = d.rate * h;
          const y = padT + h - bh;
          const sel = selected === d.week;
          const isCurrent = d.week === currentWeek;
          const c = progressColor(d.rate);
          const range = weekRange(studyStart, d.week);
          const isPast = d.week < currentWeek;
          const showRel = sel || isCurrent;
          return (
            <g key={i} className="cursor-pointer" onClick={() => onPick && onPick(d.week)}>
              {sel && <rect x={cx - barW / 2 - 10} y={padT - 12} width={barW + 20} height={h + 20} rx="10" fill="oklch(0.96 0.005 80)"/>}
              <rect x={cx - barW / 2} y={padT} width={barW} height={h} rx="6" fill="oklch(0.96 0.005 80)"/>
              <rect x={cx - barW / 2} y={y} width={barW} height={Math.max(bh, 2)} rx="6" fill={c} opacity={isPast || isCurrent ? 1 : 0.4}/>
              <text x={cx} y={y - 8} fontSize="12" textAnchor="middle" fill={INK} fontFamily="JetBrains Mono, monospace" fontWeight={sel || isCurrent ? 600 : 500}>
                {Math.round(d.rate * 100)}%
              </text>
              <text x={cx} y={padT + h + 17} fontSize="11.5" textAnchor="middle" fill={sel || isCurrent ? INK : SUBINK} fontWeight={sel || isCurrent ? 700 : 500} fontFamily="JetBrains Mono, monospace">
                Wk {d.week}
              </text>
              <text x={cx} y={padT + h + 32} fontSize="10" textAnchor="middle" fill={SUBINK} fontFamily="JetBrains Mono, monospace">
                {`${d.responses}/${team.size}`}
              </text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

function MiniStat({ label, value, hint }) {
  return (
    <div>
      <div className="text-[10.5px] tracking-[0.16em] uppercase" style={{color: SUBINK}}>{label}</div>
      <div className="text-[22px] tracking-tight font-semibold tabular-nums mt-1" style={{color: INK}}>{value}</div>
      {hint && <div className="text-[11.5px] mt-0.5" style={{color: SUBINK}}>{hint}</div>}
    </div>
  );
}

// Prioritized action cards — covers BOTH instruments:
//   Team Health (Baseline + Post-Health, 2 waves) and Meeting Effectiveness (weekly).
// No "send reminder" buttons — the PM's lever is sharing the QR code at huddles.
function PMSimpleNotes({ team, currentWeek, studyStart }) {
  const wk = team.weekly.find(w => w.week === currentWeek) || team.weekly[team.weekly.length - 1];
  const lastWk = team.weekly.find(w => w.week === currentWeek - 1);
  const trend = lastWk ? wk.rate - lastWk.rate : 0;
  const allWeeksTrend = team.weekly[team.weekly.length - 1].rate - team.weekly[0].rate;
  const avgRate = avg(team.weekly.map(w => w.rate));
  const stage = teamHealthStage(team);

  const items = [];

  // ─── Team Health (2-wave) priorities ─────────────────────────────────────
  if (stage.id === "baseline-pending") {
    items.push({
      kind: "alert",
      title: "Baseline survey hasn't been completed yet",
      body: `Team Health runs only twice per project — Baseline at kickoff and Post-Health ~6 months later. Share the Team Health QR with the team this week so we have a starting point for the study.`,
    });
  } else if (stage.id === "post-window") {
    items.push({
      kind: "neutral",
      title: "Post-Health window is open",
      body: `It's been ~6 months since kickoff. Re-share the Team Health QR with the team to capture the second wave. Once submitted, Team Health is complete for this project.`,
    });
  } else if (stage.id === "complete") {
    items.push({
      kind: "good",
      title: "Both Team Health waves are complete",
      body: `Baseline and Post-Health are both submitted. The TAMU research team will share the comparison findings at the next milestone review.`,
    });
  }

  // ─── Meeting Effectiveness (weekly) priorities ──────────────────────────
  if (wk.rate < 0.9) {
    items.push({
      kind: "alert",
      title: `Meeting Effectiveness response is ${Math.round(wk.rate * 100)}% this week`,
      body: `${wk.responses} of ${team.size} submitted this week's pulse. Posting the Meeting Effectiveness QR at the next huddle usually closes the gap.`,
    });
  } else if (trend < -0.15) {
    items.push({
      kind: "alert",
      title: `Meeting response dropped ${Math.abs(Math.round(trend * 100))} points week-over-week`,
      body: `Down from ${Math.round(lastWk.rate * 100)}% last week to ${Math.round(wk.rate * 100)}% this week. Worth a quick check-in to see if anything's changed for the team.`,
    });
  }

  // Trend insights — Meeting Effectiveness
  if (trend > 0.1) {
    items.push({
      kind: "good",
      title: `Meeting response up ${Math.round(trend * 100)} points week-over-week`,
      body: `Whatever you did, keep it going.`,
    });
  }
  if (allWeeksTrend > 0.15) {
    items.push({
      kind: "good",
      title: "Meeting Effectiveness participation has steadily improved",
      body: `Up ${Math.round(allWeeksTrend * 100)} points since week 1. The team is building the weekly habit.`,
    });
  }
  if (allWeeksTrend < -0.15 && wk.rate >= 0.9) {
    items.push({
      kind: "alert",
      title: "Meeting response trending down across the study",
      body: `Down ${Math.abs(Math.round(allWeeksTrend * 100))} points since week 1. Consider a team huddle on why.`,
    });
  }
  if (wk.responses === team.size) {
    items.push({
      kind: "good",
      title: "Everyone submitted this week's Meeting pulse",
      body: `Full weekly participation — that's the bar. This week's data will be most reliable.`,
    });
  }

  // Fallback
  if (items.length === 0) {
    items.push({
      kind: "good",
      title: "On track on both surveys",
      body: `Meeting Effectiveness averaging ${Math.round(avgRate * 100)}% across the study, and Team Health is ${stage.label.toLowerCase()}.`,
    });
  }

  return (
    <div className="mt-5 space-y-3">
      {items.map((it, i) => (
        <ActionCard key={i} {...it}/>
      ))}
    </div>
  );
}

function ActionCard({ kind, title, body, action, onAction }) {
  const palette = kind === "good"
    ? { bar: riskColor("healthy"), bg: "oklch(0.97 0.025 145)", icon: "✓" }
    : kind === "alert"
    ? { bar: riskColor("critical"), bg: "oklch(0.98 0.018 28)", icon: "!" }
    : { bar: SUBINK, bg: PAPER_2, icon: "→" };
  return (
    <div className="rounded-[16px] border p-4 flex items-start gap-4" style={{borderColor: RULE, background: palette.bg}}>
      <div className="size-8 rounded-full flex items-center justify-center text-[14px] font-semibold shrink-0" style={{background: "white", color: palette.bar, border: `1px solid ${palette.bar}40`}}>
        {palette.icon}
      </div>
      <div className="flex-1 min-w-0">
        <div className="text-[14px] tracking-tight font-semibold" style={{color: INK}}>{title}</div>
        <div className="text-[13px] mt-1 leading-relaxed" style={{color: SUBINK}}>{body}</div>
      </div>
      {action && (
        <button onClick={onAction} className="text-[12px] px-3 py-1.5 rounded-full border bg-white hover:shadow-sm transition shrink-0 whitespace-nowrap font-medium" style={{borderColor: RULE, color: INK}}>{action}</button>
      )}
    </div>
  );
}

Object.assign(window, { PMView });
