// running/src/statusView.jsx — slice 16 of the module split.
//
// STATUS / TODAY — the cohesive landing surface (tier 5).
// Visual twin of the coach's CURRENT TRAINING STATE block: one hero
// (race readiness), a row of metric cards (volume · this week · execution
// · recovery · form · fitness/paces), and a "what to do" strip of
// suggested actions. Everything reads useData().trainingSnapshot — the
// server-computed tier-4 product — so it never disagrees with the coach
// or the drill-down pages.
// ─────────────────────────────────────────────────────────────────────────
    
// Extracted verbatim from running/index.html.

const { C, Card, EmptyState, MetricCard, MetricRow, OnboardingChecklist, RaceLogo, Sparkline, gradeColor, metricColor } = window.SharedUI;
const useData = () => (window.__appUseData ? window.__appUseData() : null);
const { useState, useEffect } = React;

    function StatusView({ activities, isOwner, onNavigate }) {
      // DataProvider already kicks an on-demand recompute when the persisted
      // snapshot is missing/stale, so we just consume it here.
      const { trainingSnapshot: snap, activePlan, healthToday, redsRisk, askCoach, userId, requestPlanRefresh, garminStats, healthEntries } = useData();

      // Live conditions for the heat-adjusted "today" target — summer
      // training at face-value plan paces over-cooks easy days and
      // false-fails quality ones. Same open-meteo source the race-week
      // pacing panel uses; null on any failure (card degrades silently).
      const [wxNow, setWxNow] = useState(null);
      useEffect(() => {
        let cancelled = false;
        fetch("https://api.open-meteo.com/v1/forecast?latitude=40.71&longitude=-74.01&current=temperature_2m,relative_humidity_2m,wind_speed_10m&temperature_unit=fahrenheit&wind_speed_unit=mph")
          .then(r => r.json())
          .then(j => { if (!cancelled && j?.current) setWxNow({ tempF: j.current.temperature_2m, humidity: j.current.relative_humidity_2m }); })
          .catch(() => {});
        return () => { cancelled = true; };
      }, []);

      // VO₂ max readout — Garmin snapshot (decimals, matches the watch)
      // with the daily-history fan-out as fallback / sparkline / trend.
      // Mirrors the Analytics → Performance tab so the two agree.
      const vo2 = (() => {
        const hist = (healthEntries || [])
          .filter(h => h && h.date && Number(h.garminVO2max) > 30)
          .sort((a, b) => a.date.localeCompare(b.date));
        const snapVal = garminStats?.vo2Max != null ? parseFloat(Number(garminStats.vo2Max).toFixed(1)) : null;
        const last = hist.length ? parseFloat(Number(hist[hist.length - 1].garminVO2max).toFixed(1)) : null;
        const value = snapVal != null ? snapVal : last;
        if (value == null) return null;
        const first = hist.length >= 2 ? parseFloat(Number(hist[0].garminVO2max).toFixed(1)) : null;
        const delta = (last != null && first != null) ? parseFloat((last - first).toFixed(1)) : null;
        return {
          value,
          spark: hist.slice(-12).map(h => parseFloat(Number(h.garminVO2max).toFixed(1))),
          delta,
          source: snapVal != null ? "Garmin" : "Garmin daily",
        };
      })();

      // Edit the active plan's goal time — the single source of truth
      // every surface reads. Writes the plan doc + kicks a snapshot
      // recompute so the projection/gap catch up.
      const [editingGoal, setEditingGoal] = useState(false);
      const [goalDraft, setGoalDraft] = useState("");
      const [savingGoal, setSavingGoal] = useState(false);
      const normalizeGoal = (raw) => {
        const m = String(raw || "").trim().replace(/^sub[- ]?/i, "")
          .match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
        if (!m) return null;
        const h = +m[1], mm = +m[2], ss = m[3] != null ? +m[3] : 0;
        if (mm > 59 || ss > 59) return null;
        return `${h}:${String(mm).padStart(2, "0")}:${String(ss).padStart(2, "0")}`;
      };
      const saveGoal = async () => {
        const g = normalizeGoal(goalDraft);
        if (!g || !userId || !activePlan?.id) return;
        setSavingGoal(true);
        try {
          await db.collection("users").doc(userId).collection("trainingPlans").doc(activePlan.id)
            .update({ goalTime: g, updatedAt: firebase.firestore.FieldValue.serverTimestamp() });
          functions.httpsCallable("recomputeTrainingSnapshot")()
            .catch(e => console.warn("[StatusView] snapshot recompute after goal edit failed:", e?.message || e));
          setEditingGoal(false);
          // The prescribed paces baked into each plan week were built
          // for the OLD goal — hand off to the Plan view to Smart-Refresh
          // every non-completed week against the new pace.
          if (requestPlanRefresh) requestPlanRefresh();
        } catch (e) {
          console.error("Goal update failed:", e);
        } finally {
          setSavingGoal(false);
        }
      };

      const fmtPaceSec = (sec) => (sec == null || !(sec > 0)) ? "--" : `${Math.floor(Math.round(sec) / 60)}:${String(Math.round(sec) % 60).padStart(2, "0")}`;
      const fmtGap = (sec) => { const a = Math.abs(sec); const h = Math.floor(a / 3600), m = Math.floor((a % 3600) / 60), s = Math.round(a % 60); return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}` : `${m}:${String(s).padStart(2, "0")}`; };
      // gradeColor / metricColor / MetricCard / MetricRow / Sparkline / OnboardingChecklist are module-level shared components.
      const showOnboarding = isOwner && !activePlan;

      const v = snap?.volume || null, f = snap?.fitness || null, pg = snap?.planProgress || null,
            rr = snap?.raceReadiness || null, ex = snap?.execution || null, fm = snap?.form || null, rc = snap?.recovery || null,
            ld = snap?.load || null;

      // The live plan doc updates instantly on edit; the server snapshot
      // (rr.goalTime / gap) lags until recompute. Prefer the live value
      // for the goal label, and flag the projection as stale meanwhile.
      const displayGoal = activePlan?.goalTime || pg?.goalTime || "";
      const projectionStale = !!(activePlan?.goalTime && rr?.goalTime && activePlan.goalTime !== rr.goalTime);

      // Today's prescribed workout from the active plan.
      const todayWorkout = (() => {
        if (!activePlan?.weeks?.length || !pg?.currentWeek) return null;
        const wk = activePlan.weeks[pg.currentWeek - 1];
        if (!wk?.days) return null;
        const todayName = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][new Date().getDay()];
        return wk.days.find(d => d.day === todayName) || null;
      })();

      // Suggested actions (tier 6, surfaced inline) — derived from the snapshot.
      const actions = (() => {
        const out = [];
        if (!activePlan) {
          out.push({ icon: "📅", label: "No active plan — generate one", color: C.cyan, to: "Training" });
        } else if (todayWorkout && todayWorkout.type !== "rest" && !todayWorkout.completed && !todayWorkout.skipped) {
          const bits = [todayWorkout.type?.replace("_", " ")];
          if (todayWorkout.distanceMi) bits.push(`${todayWorkout.distanceMi}mi`);
          if (todayWorkout.targetPace) bits.push(`@${todayWorkout.targetPace}`);
          out.push({ icon: "▸", label: `Today: ${bits.filter(Boolean).join(" ")}`, color: C.cyan, to: "Training" });
        } else if (todayWorkout?.type === "rest") {
          out.push({ icon: "😴", label: "Today is a rest day", color: C.textMuted });
        } else if (todayWorkout?.completed) {
          out.push({ icon: "✓", label: "Today's workout done", color: C.green, to: "Training" });
        }
        // Load warnings: prefer the intensity-weighted EWMA ACWR when the
        // snapshot carries it; fall back to the legacy minutes-only flag.
        if (ld?.ewmaAcwr?.flag?.startsWith("spike")) out.push({ icon: "⚠", label: `Load spike (EWMA ACWR ${ld.ewmaAcwr.ratio}) — keep tomorrow easy`, color: C.red, to: "Training" });
        else if (ld?.ewmaAcwr?.flag?.startsWith("detraining")) out.push({ icon: "↓", label: `Training load dropping (EWMA ACWR ${ld.ewmaAcwr.ratio})`, color: C.amber, to: "Training" });
        else if (v?.acwrFlag === "spike — injury risk") out.push({ icon: "⚠", label: `ACWR ${v.acwr} — load spike, keep tomorrow easy`, color: C.red, to: "Training" });
        else if (v?.acwrFlag === "detraining — load dropping") out.push({ icon: "↓", label: `ACWR ${v.acwr} — volume slipping`, color: C.amber, to: "Training" });
        if (ld?.formTsb != null && ld.formTsb < -30) out.push({ icon: "🪫", label: `Form ${ld.formTsb} — deeply fatigued, overreaching risk`, color: C.red, ask: `My form (TSB) is ${ld.formTsb} — deeply fatigued. Should I back off this week, and how?` });
        if (ld?.raceDayForm && !ld.raceDayForm.flag.startsWith("race-ready")) out.push({ icon: "📉", label: `Race-day form projects ${ld.raceDayForm.tsb} — ${ld.raceDayForm.flag}`, color: C.amber, ask: `My projected race-day form (TSB) is ${ld.raceDayForm.tsb} (${ld.raceDayForm.flag}). How should we adjust the remaining plan or taper?` });
        // HRV-guided daily call (server-computed, Kiviniemi/Javaloyes
        // protocol). When it has something to say it replaces the cruder
        // readiness-only chip below.
        const hg = rc?.hrvGuidance;
        if (hg && hg.action === "recovery_day") out.push({ icon: "🔋", label: `Recovery day — ${hg.reason}`, color: C.red, ask: `My training readiness and HRV say today should be a recovery day (${hg.reason}). What should today look like?` });
        else if (hg && hg.action === "swap_to_easy") out.push({ icon: "💤", label: `HRV suppressed — swap today's ${hg.plannedType || "quality"} to easy`, color: C.amber, ask: `My 7-day HRV is ${hg.rolling7}ms, below my band (${hg.band ? `${hg.band.low}–${hg.band.high}ms` : "baseline"}), and today is a ${hg.plannedType} day. Should I swap it to easy and where do we re-slot the quality session?` });
        else if (hg && hg.action === "caution") out.push({ icon: "🟡", label: `HRV caution — warm up, then decide`, color: C.amber, ask: `${hg.reason}. Today's plan is ${hg.plannedType || "unset"} — how should I approach it?` });
        else if (rc?.readinessLatest != null && rc.readinessLatest < 40) out.push({ icon: "🔋", label: `Readiness ${rc.readinessLatest} — recovery-first day`, color: C.red, to: "Health" });
        if (rc?.healthDataAgeDays != null && rc.healthDataAgeDays > 2) out.push({ icon: "📡", label: `Garmin health data ${rc.healthDataAgeDays}d stale — check the sync`, color: C.red, to: "Settings" });
        if (redsRisk?.severity && (redsRisk.severity === "high" || redsRisk.severity === "moderate")) out.push({ icon: "🍽", label: `RED-S risk: ${redsRisk.severity} — review fuelling`, color: redsRisk.severity === "high" ? C.red : C.amber, to: "Nutrition" });
        if (rr?.gapSec != null && rr.gapSec > 0 && (rr.daysToRace == null || rr.daysToRace < 70)) out.push({ icon: "🎯", label: `Projected ${fmtGap(rr.gapSec)} off goal — ask the coach what to prioritise`, color: C.amber, ask: `I'm projected to finish about ${fmtGap(rr.gapSec)} slower than my goal of ${rr.goalTime || "my target"}. What should I prioritise over the next few weeks to close the gap?` });
        if (isOwner) out.push({ icon: "🤖", label: "Ask the coach for a read", color: C.purple, ask: "Give me a quick read on my current training — where am I strong, where's the gap, and what's the priority for the next couple of weeks?" });
        return out;
      })();

      // ── Empty / loading states ──
      if (!isOwner && !snap) {
        return <EmptyState icon="📊" title="No status yet" sub="The athlete hasn't synced training data." />;
      }
      if (!snap) {
        return (
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            <div style={{ fontFamily: "'Space Grotesk', sans-serif", fontSize: 26, fontWeight: 800, color: C.text }}>Status<span style={{ color: C.green }}>.</span></div>
            {showOnboarding && <OnboardingChecklist activities={activities} />}
            <Card style={{ textAlign: "center", padding: 28 }}>
              <div style={{ fontSize: 14, color: C.textDim }}>Computing your training snapshot…</div>
              <div style={{ fontSize: 12, color: C.textMuted, marginTop: 6 }}>
                {activePlan ? "Refreshes after each sync." : "It fills in once you've synced runs and generated a plan."}
              </div>
            </Card>
          </div>
        );
      }

      const projGapColor = rr?.gapSec == null ? C.textMuted : rr.gapSec <= 0 ? C.green : rr.gapSec < 300 ? C.amber : C.red;

      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div>
            <div style={{ fontFamily: "'Space Grotesk', sans-serif", fontSize: 26, fontWeight: 800, color: C.text }}>
              Status<span style={{ color: C.green }}>.</span>
            </div>
            <div style={{ color: C.textMuted, fontSize: 12, marginTop: 4 }}>
              Where you are, and what to do next — {snap.computedAt ? `as of ${new Date(snap.computedAt).toLocaleString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" })}` : "live"}.
            </div>
          </div>

          {showOnboarding && <OnboardingChecklist activities={activities} />}

          {/* ── HERO: race readiness ── */}
          {(pg || rr) && (
            <Card style={{ padding: 20, display: "flex", flexWrap: "wrap", gap: 24, alignItems: "center" }}>
              {pg?.raceName && <RaceLogo name={pg.raceName} size={52} />}
              <div style={{ flex: "1 1 220px" }}>
                <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.08em" }}>Race Readiness</div>
                <div style={{ fontSize: 22, fontWeight: 800, color: C.text, fontFamily: "'Space Grotesk', sans-serif", marginTop: 2 }}>
                  {pg?.raceName || pg?.raceDistance || "No race set"}
                </div>
                <div style={{ fontSize: 12, color: C.textDim, marginTop: 2, display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
                  {editingGoal ? (
                    <React.Fragment>
                      <span>goal</span>
                      <input
                        type="text" autoFocus value={goalDraft}
                        onChange={e => setGoalDraft(e.target.value)}
                        onKeyDown={e => { if (e.key === "Enter") saveGoal(); if (e.key === "Escape") setEditingGoal(false); }}
                        placeholder="2:57:00"
                        style={{ width: 78, fontSize: 12, padding: "2px 6px", borderRadius: 4, border: `1px solid ${C.border}`, background: C.bg3, color: C.text, fontFamily: "'IBM Plex Mono', monospace" }}
                      />
                      <button onClick={saveGoal} disabled={savingGoal || !normalizeGoal(goalDraft)}
                        style={{ fontSize: 11, fontWeight: 700, color: normalizeGoal(goalDraft) ? C.green : C.textMuted, background: "none", border: "none", cursor: normalizeGoal(goalDraft) ? "pointer" : "default", padding: 0 }}>
                        {savingGoal ? "Saving…" : "Save"}
                      </button>
                      <button onClick={() => setEditingGoal(false)} disabled={savingGoal}
                        style={{ fontSize: 11, color: C.textMuted, background: "none", border: "none", cursor: "pointer", padding: 0 }}>Cancel</button>
                    </React.Fragment>
                  ) : (
                    <React.Fragment>
                      <span>
                        {displayGoal ? `goal ${displayGoal}` : ""}{displayGoal && pg?.daysToRace != null ? " · " : ""}{pg?.daysToRace != null ? `${pg.daysToRace} days out` : ""}
                      </span>
                      {isOwner && activePlan?.id && (
                        <button onClick={() => { setGoalDraft(displayGoal || ""); setEditingGoal(true); }}
                          style={{ fontSize: 11, color: C.cyan, background: "none", border: "none", cursor: "pointer", padding: 0, textDecoration: "underline" }}>
                          {displayGoal ? "edit" : "set goal"}
                        </button>
                      )}
                    </React.Fragment>
                  )}
                </div>
                {pg?.currentWeek != null && (
                  <div style={{ marginTop: 10 }}>
                    <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, color: C.textMuted, marginBottom: 4 }}>
                      <span>Week {pg.currentWeek} / {pg.totalWeeks}</span>
                      <span>{pg.pctPlanDaysCompleted != null ? `${pg.pctPlanDaysCompleted}% of plan days done` : ""}</span>
                    </div>
                    <div style={{ height: 6, background: C.bg3, borderRadius: 3, overflow: "hidden" }}>
                      <div style={{ width: `${Math.min(100, ((pg.currentWeek - 1) / Math.max(1, pg.totalWeeks - 1)) * 100)}%`, height: "100%", background: C.cyan, borderRadius: 3 }} />
                    </div>
                  </div>
                )}
              </div>
              {rr && (
                <div style={{ flex: "1 1 200px", textAlign: "right" }}>
                  <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.08em" }}>Projected {rr.raceDistance}</div>
                  <div style={{ fontSize: 30, fontWeight: 800, color: projGapColor, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1.1, marginTop: 2 }}>
                    {rr.projectedFinish || "--"}
                  </div>
                  <div style={{ fontSize: 12, color: C.textDim, marginTop: 2 }}>
                    {projectionStale
                      ? `vs goal ${displayGoal} · recalculating…`
                      : rr.gapSec == null ? (displayGoal ? `vs goal ${displayGoal}` : "")
                      : rr.gapSec <= 0 ? `${fmtGap(rr.gapSec)} ahead of goal ${displayGoal}`
                      : `${fmtGap(rr.gapSec)} off goal ${displayGoal}`}
                  </div>
                  {rr.basis && <div style={{ fontSize: 10, color: C.textMuted, marginTop: 4 }}>from {rr.basis}</div>}
                </div>
              )}
              {f?.effectiveVDOT != null && (
                <div style={{ flex: "0 0 auto", textAlign: "center", paddingLeft: 16, borderLeft: `1px solid ${C.border}`, maxWidth: 150 }}>
                  <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.08em" }}>Eff. VDOT/VO2</div>
                  <div style={{ fontSize: 26, fontWeight: 800, color: C.green, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1.1, marginTop: 2 }}>{f.effectiveVDOT}</div>
                  {f.effectiveVO2Source && <div style={{ fontSize: 10, color: C.textMuted, marginTop: 2 }}>via {f.effectiveVO2Source}</div>}
                  {f.garminVO2 != null && f.effectiveVO2Source !== "Garmin" && <div style={{ fontSize: 9, color: C.textMuted, marginTop: 1 }}>(Garmin reads {f.garminVO2})</div>}
                </div>
              )}
            </Card>
          )}

          {/* ── "What to do" strip ── */}
          {actions.length > 0 && (
            <Card style={{ padding: 14 }}>
              <div style={{ fontSize: 11, fontWeight: 700, color: C.textDim, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 10 }}>What to do</div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                {actions.map((a, i) => {
                  const handler = a.ask ? () => askCoach(a.ask) : a.to ? () => onNavigate(a.to) : undefined;
                  return (
                  <button key={i} onClick={handler}
                    style={{ display: "flex", alignItems: "center", gap: 7, background: a.color + "12", border: `1px solid ${a.color}33`, color: a.color, borderRadius: 8, padding: "7px 12px", fontSize: 12, fontWeight: 600, cursor: handler ? "pointer" : "default", fontFamily: "'IBM Plex Mono', monospace" }}>
                    <span>{a.icon}</span>{a.label}{(a.to || a.ask) && <span style={{ opacity: 0.5 }}>{a.ask ? "💬" : "→"}</span>}
                  </button>
                  );
                })}
              </div>
            </Card>
          )}

          {/* ── Metric card grid ── */}
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: 14 }}>
            {vo2 && (
              <MetricCard title="VO₂ Max" color={C.cyan} to="Analytics">
                <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between" }}>
                  <div style={{ fontSize: 26, fontWeight: 800, color: C.cyan, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1 }}>
                    {vo2.value.toFixed(1)}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>ml/kg/min</span>
                  </div>
                  {vo2.spark.length >= 2 && <Sparkline vals={vo2.spark} color={C.cyan} />}
                </div>
                {vo2.delta != null && (
                  <MetricRow label="Change (history)" value={`${vo2.delta > 0 ? "+" : ""}${vo2.delta.toFixed(1)}`} color={vo2.delta >= 0 ? C.green : C.amber} />
                )}
                <MetricRow label="Source" value={vo2.source} />
              </MetricCard>
            )}
            {v && (
              <MetricCard title="Volume" color={C.green} to="Analytics">
                <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between" }}>
                  <div>
                    <div style={{ fontSize: 26, fontWeight: 800, color: C.green, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1 }}>{v.last7Mi ?? "--"}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>mi this wk</span></div>
                  </div>
                  <Sparkline vals={[...(v.weeklyMilesTrailing || [])].reverse()} color={C.green} />
                </div>
                <MetricRow label="28-day avg" value={`${v.avgWeeklyMi28d ?? "--"} mi/wk`} />
                <MetricRow label="Longest run (30d)" value={`${v.longestRunMi30d ?? "--"} mi`} />
                {v.acwr != null && <MetricRow label="ACWR (acute:chronic)" value={`${v.acwr}`} color={metricColor(v.acwr, "acwr")} />}
                {v.acwrFlag && <div style={{ fontSize: 10, color: v.acwrFlag.startsWith("in range") ? C.textMuted : C.amber }}>{v.acwrFlag}</div>}
              </MetricCard>
            )}

            {ld && ld.formTsb != null && (
              <MetricCard title="Form (fitness − fatigue)" color={C.purple} to="Summary">
                <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between" }}>
                  <div style={{ fontSize: 26, fontWeight: 800, color: ld.formTsb >= 5 ? C.green : ld.formTsb >= -30 ? C.purple : C.red, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1 }}>
                    {ld.formTsb > 0 ? "+" : ""}{ld.formTsb}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>TSB</span>
                  </div>
                </div>
                {ld.formFlag && <div style={{ fontSize: 10, color: ld.formTsb < -30 ? C.red : C.textMuted }}>{ld.formFlag}</div>}
                <MetricRow label="Fitness (CTL)" value={`${ld.fitnessCtl ?? "--"}`} color={C.cyan} />
                <MetricRow label="Fatigue (ATL)" value={`${ld.fatigueAtl ?? "--"}`} color={C.amber} />
                {ld.ewmaAcwr && <MetricRow label="EWMA ACWR" value={`${ld.ewmaAcwr.ratio}`} color={metricColor(ld.ewmaAcwr.ratio, "acwr")} />}
                {ld.monotony7d && <MetricRow label="Monotony (7d)" value={`${ld.monotony7d.monotony}`} color={ld.monotony7d.monotony > 2 ? C.amber : undefined} />}
                {ld.raceDayForm && (
                  <div style={{ marginTop: 4, paddingTop: 8, borderTop: `1px solid ${C.border}` }}>
                    <MetricRow label="Race-day form (projected)" value={`${ld.raceDayForm.tsb > 0 ? "+" : ""}${ld.raceDayForm.tsb}`} color={ld.raceDayForm.flag.startsWith("race-ready") ? C.green : C.amber} />
                    <div style={{ fontSize: 10, color: ld.raceDayForm.flag.startsWith("race-ready") ? C.textMuted : C.amber }}>{ld.raceDayForm.flag}</div>
                    <div style={{ fontSize: 10, color: C.textMuted, marginTop: 2, lineHeight: 1.4 }}>
                      today's form rolled forward through every remaining planned workout — it answers "how fresh will I be on race morning if I run the plan as written", which is why it can be positive while today reads fatigued
                    </div>
                  </div>
                )}
              </MetricCard>
            )}

            <MetricCard title="This week" color={C.cyan} to="Training">
              {pg ? (
                <>
                  <div style={{ fontSize: 22, fontWeight: 800, color: C.cyan, fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1 }}>
                    {pg.currentWeekTargetMi != null ? `${pg.currentWeekTargetMi} mi` : "—"}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 6 }}>target</span>
                  </div>
                  {pg.currentWeekTheme && <div style={{ fontSize: 12, color: C.textDim }}>{pg.currentWeekTheme}</div>}
                </>
              ) : <div style={{ fontSize: 13, color: C.textMuted }}>No active plan</div>}
              {todayWorkout && (
                <div style={{ marginTop: 4, paddingTop: 8, borderTop: `1px solid ${C.border}` }}>
                  <div style={{ fontSize: 10, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 3 }}>Today</div>
                  <div style={{ fontSize: 13, color: todayWorkout.completed ? C.green : C.text, fontWeight: 600, textTransform: "capitalize", textDecoration: todayWorkout.completed ? "line-through" : "none" }}>
                    {todayWorkout.type?.replace("_", " ")}{todayWorkout.distanceMi ? ` · ${todayWorkout.distanceMi} mi` : ""}{todayWorkout.targetPace ? ` @ ${todayWorkout.targetPace}/mi` : ""}{todayWorkout.skipped ? " (skipped)" : ""}
                  </div>
                  {todayWorkout.description && <div style={{ fontSize: 11, color: C.textMuted, marginTop: 2, lineHeight: 1.4 }}>{todayWorkout.description}</div>}
                  {(() => {
                    // Heat-adjusted target for TODAY's conditions: the plan
                    // pace is the cool-weather intent; in heat the same
                    // effort runs slower, so chasing the printed number
                    // becomes a harder workout than prescribed.
                    if (!wxNow || !todayWorkout.targetPace || !window.WeatherPacing) return null;
                    const m = String(todayWorkout.targetPace).match(/^(\d+):(\d{2})/);
                    if (!m) return null;
                    const baseSec = (+m[1]) * 60 + (+m[2]);
                    const addSec = window.WeatherPacing.heatAdjustSec(wxNow.tempF)
                      + window.WeatherPacing.humidityAdjustSec(wxNow.tempF, wxNow.humidity);
                    if (addSec < 5) return null;
                    const adj = baseSec + addSec;
                    const fmtP = (s) => `${Math.floor(s / 60)}:${String(Math.round(s) % 60).padStart(2, "0")}`;
                    return (
                      <div style={{ fontSize: 11, color: C.amber, marginTop: 4, lineHeight: 1.4 }}>
                        🌡 {Math.round(wxNow.tempF)}°F / {Math.round(wxNow.humidity)}% — same effort ≈ <strong>{fmtP(adj)}/mi</strong> today (+{addSec}s heat). Run the effort, not the printed pace.
                      </div>
                    );
                  })()}
                </div>
              )}
            </MetricCard>

            {f && (f.modelledPaces || f.demonstratedEasyPaceMedian != null) && (
              <MetricCard title="Training paces" color={C.amber} to="Training">
                {f.modelledPaces && [["Recovery", f.modelledPaces.recovery], ["Easy", f.modelledPaces.easy], ["Long", f.modelledPaces.long], ["Marathon", f.modelledPaces.marathon], ["Threshold", f.modelledPaces.threshold], ["Interval", f.modelledPaces.interval], ["Strides", f.modelledPaces.strides]].filter(([, sec]) => sec != null).map(([k, sec]) => (
                  <MetricRow key={k} label={k} value={`${fmtPaceSec(sec)}/mi`} color={C.amber} />
                ))}
                {f.modelledPaces && f.paceAnchor && <div style={{ fontSize: 10, color: C.textMuted }}>anchored on {f.paceAnchor}</div>}
                {f.demonstratedEasyPaceMedian != null && <MetricRow label={`Recent easy median (n=${f.demonstratedEasyRunCount})`} value={`${fmtPaceSec(f.demonstratedEasyPaceMedian)}/mi`} />}
                {f.lthr != null && <MetricRow label="LT heart rate" value={`${Math.round(f.lthr)} bpm`} />}
              </MetricCard>
            )}

            {ex && ex.gradedQualitySessions > 0 && (
              <MetricCard title="Execution" color={C.purple} to="Summary">
                {ex.quality && <MetricRow label="Quality sessions on-pace" value={`${ex.quality.onTarget} / ${ex.quality.graded}`} color={metricColor(ex.quality.pct, "onTargetPct")} />}
                {ex.longRuns && <MetricRow label="Long runs in zone" value={`${ex.longRuns.inZone} / ${ex.longRuns.graded}`} color={metricColor(ex.longRuns.pct, "onTargetPct")} />}
                {!ex.quality && !ex.longRuns && <MetricRow label="On target (A/B)" value={`${ex.onTargetCount} / ${ex.gradedQualitySessions}`} color={metricColor(ex.onTargetPct, "onTargetPct")} />}
                {ex.gradeCounts && (() => {
                  const gc = ex.gradeCounts, total = gc.A + gc.B + gc.C + gc.D;
                  if (!total) return null;
                  const seg = (n, col) => n > 0 ? <div key={col} style={{ flex: n, background: col }} /> : null;
                  return (
                    <div>
                      <div style={{ display: "flex", height: 6, borderRadius: 3, overflow: "hidden", marginTop: 2, marginBottom: 4 }}>
                        {seg(gc.A, C.green)}{seg(gc.B, C.cyan)}{seg(gc.C, C.amber)}{seg(gc.D, C.red)}
                      </div>
                      <div style={{ display: "flex", gap: 12, fontSize: 10, color: C.textMuted }}>
                        {["A", "B", "C", "D"].filter(g => gc[g] > 0).map(g => <span key={g} style={{ color: gradeColor(g) }}>{gc[g]} {g}</span>)}
                        <span style={{ marginLeft: "auto" }}>{total} graded</span>
                      </div>
                    </div>
                  );
                })()}
                {ex.quality && ex.quality.pct === 0 && ex.quality.graded > 0 && <div style={{ fontSize: 10, color: C.amber, lineHeight: 1.4 }}>completing sessions but missing pace targets — open Recent Workouts for the why</div>}
                {(!ex.quality || ex.quality.pct > 0) && ex.longRuns && ex.longRuns.pct === 0 && <div style={{ fontSize: 10, color: C.amber, lineHeight: 1.4 }}>long runs are running above Z1 — back off the pace or recheck zones</div>}
                {ex.misses && ex.misses.onCompromisedRecovery > 0 && (
                  <div style={{ fontSize: 10, color: C.textDim, lineHeight: 1.4 }}>
                    {ex.misses.onCompromisedRecovery} of {ex.misses.total} miss{ex.misses.total > 1 ? "es" : ""} came on compromised recovery (low readiness / sleep / HRV) — a recovery signal, not an execution one
                  </div>
                )}
                {ex.lastFive?.length > 0 && (
                  <div style={{ display: "flex", gap: 4, flexWrap: "wrap" }}>
                    {ex.lastFive.map((g, i) => (
                      <span key={i} title={`${g.type}${g.date ? ` · ${g.date}` : ""}${g.compromisedRecovery ? " · compromised recovery that morning" : ""}`} style={{ width: 22, height: 22, borderRadius: 5, background: gradeColor(g.grade) + "22", border: `1px ${g.compromisedRecovery ? "dashed" : "solid"} ${gradeColor(g.grade)}${g.compromisedRecovery ? "88" : "44"}`, color: gradeColor(g.grade), fontSize: 11, fontWeight: 800, display: "flex", alignItems: "center", justifyContent: "center" }}>{g.grade}</span>
                    ))}
                  </div>
                )}
              </MetricCard>
            )}

            {rc && (
              <MetricCard title="Recovery" color={C.pink} to="Health">
                {rc.readinessAvg7d != null && (
                  <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
                    <div style={{ fontSize: 22, fontWeight: 800, color: metricColor(rc.readinessAvg7d, "readiness"), fontFamily: "'Space Grotesk', sans-serif", lineHeight: 1 }}>{rc.readinessAvg7d}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>/100 7d-avg</span></div>
                    {rc.readinessLatest != null && <span style={{ fontSize: 11, color: C.textMuted }}>(today {rc.readinessLatest})</span>}
                  </div>
                )}
                {rc.bodyBatteryStartAvg7d != null && <MetricRow label="Body battery (start, 7d)" value={`${rc.bodyBatteryStartAvg7d}`} />}
                {rc.sleepScoreAvg7d != null && <MetricRow label="Sleep score (7d)" value={`${rc.sleepScoreAvg7d}`} color={metricColor(rc.sleepScoreAvg7d, "sleepScore")} />}
                {(rc.hrvStatus || rc.hrvAvg7d != null) && <MetricRow label="HRV" value={`${[rc.hrvStatus, rc.hrvAvg7d != null ? `${rc.hrvAvg7d}ms` : null].filter(Boolean).join(" · ")}`} />}
                {rc.acuteLoad != null && rc.chronicLoad != null && <MetricRow label="Load (acute/chronic)" value={`${Math.round(rc.acuteLoad)} / ${Math.round(rc.chronicLoad)}`} />}
                {rc.wellnessSorenessAvg7d != null && <MetricRow label="Self-rating soreness (7d)" value={`${rc.wellnessSorenessAvg7d}/10`} />}
              </MetricCard>
            )}

            {fm && (
              <MetricCard title="Form" color={C.cyanDim} to="Training">
                {fm.cadenceSpmLatest != null && <MetricRow label="Cadence" value={`${fm.cadenceSpmLatest} spm${fm.cadenceSpmAvg8 != null ? ` (${fm.cadenceSpmAvg8} avg)` : ""}`} color={metricColor(fm.cadenceSpmLatest, "cadenceSpm")} />}
                {fm.gctMsLatest != null && <MetricRow label="Ground contact" value={`${fm.gctMsLatest} ms${fm.gctMsAvg8 != null ? ` (${fm.gctMsAvg8} avg)` : ""}`} color={metricColor(fm.gctMsLatest, "gctMs")} />}
                {fm.vertOscCmLatest != null && <MetricRow label="Vertical oscillation" value={`${fm.vertOscCmLatest} cm`} color={metricColor(fm.vertOscCmLatest, "vertOscCm")} />}
                {fm.vertRatioPctLatest != null && <MetricRow label="Vertical ratio" value={`${fm.vertRatioPctLatest}%`} />}
                {fm.lrBalanceLatest != null && <MetricRow label="L/R balance" value={`${fm.lrBalanceLatest}% / ${(100 - fm.lrBalanceLatest).toFixed(1)}%`} />}
                {fm.powerWLatest != null && <MetricRow label="Running power" value={`${fm.powerWLatest} W`} />}
                {fm.stepSpeedLossLatest != null && <MetricRow label="Step speed loss" value={`${fm.stepSpeedLossLatest}%`} />}
                <div style={{ fontSize: 10, color: C.textMuted }}>{fm.runsWithDynamics} runs with dynamics</div>
              </MetricCard>
            )}
          </div>
        </div>
      );
    }

window.AppViews = Object.assign(window.AppViews || {}, { StatusView });
