// running/src/health.jsx — slice 10 of the module split.
//
// HEALTH view (Garmin metrics): HRV, readiness, sleep, body battery,
// stress, weight — trends and day detail. Extracted verbatim from
// running/index.html. Pure presentation over useData: no main-block
// helpers at all (the cleanest big view in the app).

const { C, Card, Stat, Badge, Btn, TabBar, EmptyState, ChartTooltip } = window.SharedUI;
const useData = () => (window.__appUseData ? window.__appUseData() : null);
const { useState, useEffect, useMemo } = React;
const {
  AreaChart, Area, LineChart, Line, Bar, ComposedChart,
  XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
  ReferenceLine,
} = Recharts;

    function Health({ userId, activities, isOwner }) {
      const { healthEntries: entries, healthToday: todayEntry, healthYesterday: yesterdayEntry,
              todayNutrition, nutritionHistory,
              weightGoal, updateWeightGoal,
              supplements, saveSupplements,
              macroTargets, updateMacroTargets, activePlan, trainingSnapshot } = useData();
      // Race day comes from the active training plan (single source of
      // truth) — the weight trend projects to it.
      const raceTargetDate = activePlan?.raceDate || "2026-11-01";
      const raceTargetLabel = (() => {
        const d = new Date(raceTargetDate);
        return isNaN(d) ? raceTargetDate
          : d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
      })();
      const [tab, setTab] = useState("Today");
      const [editing, setEditing] = useState(false);
      const [form, setForm] = useState({
        hrv: "", restingHR: "", bodyBattery: "", sleepScore: "", sleepHours: "",
        stress: "", trainingReadiness: "", spo2: "", respiration: "", steps: "", weight: "",
      });

      // ── Weight Goal state (data from DataProvider) ──
      const [goalForm, setGoalForm] = useState({ goalWeight: "", weeklyRate: "0.75" });
      const [editingGoal, setEditingGoal] = useState(false);
      const [weightViewMode, setWeightViewMode] = useState("full"); // "detail" | "full"

      // ── Nutrition state (nutritionHistory + macroTargets from DataProvider) ──
      const [nutritionData, setNutritionData] = useState({});
      const [macroForm, setMacroForm] = useState({ calories: "", protein: "", carbs: "", fat: "", fiber: "" });
      const [editingMacros, setEditingMacros] = useState(false);
      const [mealForm, setMealForm] = useState({ name: "Snack", description: "", calories: "", protein: "", carbs: "", fat: "" });
      const [addingMeal, setAddingMeal] = useState(false);
      const [editingTargets, setEditingTargets] = useState(false);

      // ── Hunger state ──
      const [hungerEntries, setHungerEntries] = useState([]);
      const [allHunger, setAllHunger] = useState([]);
      const [loggingHunger, setLoggingHunger] = useState(false);
      const [hungerForm, setHungerForm] = useState({ level: 3, note: "" });

      // ── AI Coach state ──
      const [coaching, setCoaching] = useState(null);
      const [loadingCoaching, setLoadingCoaching] = useState(false);

      // ── Nutrition Plan state (supplements now from DataProvider) ──
      const [loadingPlan, setLoadingPlan] = useState(false);
      const [plan, setPlan] = useState(null);

      // ── Daily Summary Email state ──
      const [emailAddr, setEmailAddr] = useState("");
      const [emailEnabled, setEmailEnabled] = useState(false);
      const [emailTime, setEmailTime] = useState("06:30");
      const [emailLoaded, setEmailLoaded] = useState(false);
      const [emailSending, setEmailSending] = useState(false);
      const [emailMsg, setEmailMsg] = useState(null); // { type: "ok"|"err", text }
      const [smtpStatus, setSmtpStatus] = useState(null); // { configured, emailHint } | { checkFailed, error }
      const [smtpChecking, setSmtpChecking] = useState(false);

      const today = new Date().toISOString().split("T")[0];

      // ── Day navigation ──
      const [selectedDate, setSelectedDate] = useState(today);
      const isToday = selectedDate === today;

      const navBack = () => setSelectedDate(d => {
        const dt = new Date(d + "T12:00:00");
        dt.setDate(dt.getDate() - 1);
        return dt.toISOString().split("T")[0];
      });
      const navForward = () => setSelectedDate(d => {
        const dt = new Date(d + "T12:00:00");
        dt.setDate(dt.getDate() + 1);
        const next = dt.toISOString().split("T")[0];
        return next > today ? today : next;
      });

      const prevDateStr = useMemo(() => {
        const dt = new Date(selectedDate + "T12:00:00");
        dt.setDate(dt.getDate() - 1);
        return dt.toISOString().split("T")[0];
      }, [selectedDate]);


      // ── Sync DataProvider data into local forms ──
      useEffect(() => {
        if (weightGoal) setGoalForm({ goalWeight: weightGoal.goalWeight?.toString() || "", weeklyRate: weightGoal.weeklyRate?.toString() || "0.75" });
      }, [weightGoal]);

      useEffect(() => {
        // Show nutrition for the currently viewed date, not just today
        const dateNut = nutritionHistory?.find(n => n.date === selectedDate) || todayNutrition || null;
        if (dateNut) {
          setNutritionData(dateNut);
          if (selectedDate === today) {
            setMacroForm({
              calories: dateNut.calories?.toString() || "",
              protein: dateNut.protein?.toString() || "",
              carbs: dateNut.carbs?.toString() || "",
              fat: dateNut.fat?.toString() || "",
              fiber: dateNut.fiber?.toString() || "",
            });
          }
        } else {
          setNutritionData({});
        }
      }, [todayNutrition, nutritionHistory, selectedDate]);

      // ── Load hunger entries (last 14 days) ──
      useEffect(() => {
        if (!userId) return;
        const cutoff14 = new Date();
        cutoff14.setDate(cutoff14.getDate() - 14);
        const unsub = db.collection("users").doc(userId).collection("hunger")
          .where("date", ">=", cutoff14.toISOString().split("T")[0])
          .orderBy("date", "asc")
          .onSnapshot(snap => {
            const all = snap.docs.map(d => ({ id: d.id, ...d.data() }));
            setAllHunger(all);
          });
        return unsub;
      }, [userId]);

      // Filter hunger entries for selected date reactively
      useEffect(() => {
        setHungerEntries(allHunger.filter(h => h.date === selectedDate));
      }, [allHunger, selectedDate]);

      // ── Save health entry ──
      const saveEntry = async () => {
        if (!isOwner) return;
        const data = {
          date: selectedDate,
          hrv: form.hrv ? parseInt(form.hrv) : null,
          restingHR: form.restingHR ? parseInt(form.restingHR) : null,
          bodyBattery: form.bodyBattery ? parseInt(form.bodyBattery) : null,
          sleepScore: form.sleepScore ? parseInt(form.sleepScore) : null,
          sleepHours: form.sleepHours ? parseFloat(form.sleepHours) : null,
          stress: form.stress ? parseInt(form.stress) : null,
          trainingReadiness: form.trainingReadiness ? parseInt(form.trainingReadiness) : null,
          spo2: form.spo2 ? parseInt(form.spo2) : null,
          respiration: form.respiration ? parseInt(form.respiration) : null,
          steps: form.steps ? parseInt(form.steps) : null,
          weight: form.weight ? parseFloat(form.weight) : null,
          updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
        };
        await db.collection("users").doc(userId).collection("health").doc(selectedDate).set(data, { merge: true });
        setEditing(false);
      };

      // ── Save weight goal ──
      const saveWeightGoal = async () => {
        if (!isOwner) return;
        const latestWeight = entries.filter(e => e.weight != null && e.weight >= 100 && !WEIGHT_EXCLUDE.has(e.id)).slice(-1)[0]?.weight || 175;
        const gw = parseFloat(goalForm.goalWeight);
        const rate = parseFloat(goalForm.weeklyRate);
        if (!gw || !rate) return;
        const weeksToGoal = Math.abs(latestWeight - gw) / rate;
        const targetDate = new Date();
        targetDate.setDate(targetDate.getDate() + Math.ceil(weeksToGoal * 7));
        const data = {
          goalWeight: gw,
          weeklyRate: rate,
          startWeight: latestWeight,
          startDate: today,
          targetDate: targetDate.toISOString().split("T")[0],
          updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
        };
        updateWeightGoal(data);
        setEditingGoal(false);
      };

      // ── Save daily macros ──
      const saveMacros = async () => {
        if (!isOwner) return;
        const data = {
          date: today,
          calories: macroForm.calories ? parseInt(macroForm.calories) : null,
          protein: macroForm.protein ? parseInt(macroForm.protein) : null,
          carbs: macroForm.carbs ? parseInt(macroForm.carbs) : null,
          fat: macroForm.fat ? parseInt(macroForm.fat) : null,
          fiber: macroForm.fiber ? parseInt(macroForm.fiber) : null,
          meals: nutritionData.meals || [],
          updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
        };
        await db.collection("users").doc(userId).collection("nutrition").doc(today).set(data, { merge: true });
        setNutritionData(data);
        setEditingMacros(false);
      };

      // ── Save macro targets ──
      const saveMacroTargets = () => {
        if (!isOwner) return;
        updateMacroTargets(macroTargets); // persists to Firestore + updates DataProvider
        setEditingTargets(false);
      };

      // ── Add meal entry ──
      const addMeal = async () => {
        if (!isOwner) return;
        const meal = {
          name: mealForm.name,
          description: mealForm.description,
          time: new Date().toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" }),
          calories: parseInt(mealForm.calories) || 0,
          protein: parseInt(mealForm.protein) || 0,
          carbs: parseInt(mealForm.carbs) || 0,
          fat: parseInt(mealForm.fat) || 0,
        };
        const meals = [...(nutritionData.meals || []), meal];
        // Sum macros from all meals
        const totals = meals.reduce((acc, m) => ({
          calories: acc.calories + (m.calories || 0),
          protein: acc.protein + (m.protein || 0),
          carbs: acc.carbs + (m.carbs || 0),
          fat: acc.fat + (m.fat || 0),
        }), { calories: 0, protein: 0, carbs: 0, fat: 0 });
        const data = { date: today, ...totals, fiber: nutritionData.fiber || null, meals, updatedAt: firebase.firestore.FieldValue.serverTimestamp() };
        await db.collection("users").doc(userId).collection("nutrition").doc(today).set(data, { merge: true });
        setNutritionData(data);
        setMacroForm({ calories: totals.calories.toString(), protein: totals.protein.toString(), carbs: totals.carbs.toString(), fat: totals.fat.toString(), fiber: macroForm.fiber });
        setMealForm({ name: "Snack", description: "", calories: "", protein: "", carbs: "", fat: "" });
        setAddingMeal(false);
      };

      // ── Log hunger ──
      const logHunger = async () => {
        const entry = {
          date: today,
          time: new Date().toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" }),
          level: hungerForm.level,
          note: hungerForm.note || "",
          createdAt: firebase.firestore.FieldValue.serverTimestamp(),
        };
        await db.collection("users").doc(userId).collection("hunger").add(entry);
        setHungerForm({ level: 3, note: "" });
        setLoggingHunger(false);
      };

      // ── AI Weight Coaching ──
      const getCoaching = async () => {
        setLoadingCoaching(true);
        try {
          const weightHistory = entries.filter(e => e.weight != null && !WEIGHT_EXCLUDE.has(e.id)).map(e => ({ date: e.id, weight: e.weight }));
          const recentRuns = (activities || [])
            .filter(a => (a.type === "Run" || a.type === "VirtualRun"))
            .slice(0, 7)
            .map(a => ({
              date: a.start_date?.toDate ? a.start_date.toDate().toISOString().split("T")[0] : "",
              distance: a.distance ? (a.distance / 1609.34).toFixed(1) : 0,
              calories: a.calories || 0,
            }));
          const recentNutrition = nutritionHistory.map(n => ({
            date: n.date, calories: n.calories, protein: n.protein, carbs: n.carbs, fat: n.fat, fiber: n.fiber,
          }));
          const hungerData = allHunger.map(h => ({ date: h.date, time: h.time, level: h.level }));
          const latestWeight = weightHistory.slice(-1)[0]?.weight;

          const fn = functions.httpsCallable("generateWeightCoaching");
          const result = await fn({
            weightHistory, weightGoal, recentNutrition, hungerEntries: hungerData, recentRuns, currentWeight: latestWeight,
          });
          setCoaching(result.data);
        } catch (err) {
          console.error(err);
          setCoaching({ error: "Failed to generate coaching. Please try again." });
        }
        setLoadingCoaching(false);
      };

      // ── Generate nutrition plan (migrated from Nutrition component) ──
      const getTodaysPlan = async () => {
        setLoadingPlan(true);
        try {
          const nextRun = (activities || [])
            .filter(a => {
              const d = a.start_date?.toDate ? a.start_date.toDate() : new Date(a.start_date);
              return d >= new Date() && (a.type==="Run"||a.type==="VirtualRun");
            })
            .sort((a,b) => a.start_date?.seconds - b.start_date?.seconds)[0];
          const lastRun = (activities || [])
            .filter(a => {
              const d = a.start_date?.toDate ? a.start_date.toDate() : new Date(a.start_date);
              return d < new Date() && (a.type==="Run"||a.type==="VirtualRun");
            })
            .sort((a,b) => b.start_date?.seconds - a.start_date?.seconds)[0];
          const generateNutritionPlan = functions.httpsCallable("generateNutritionPlan");
          const result = await generateNutritionPlan({
            date: today, nutritionLog: nutritionData,
            nextRun: nextRun ? { distance: nextRun.distance, name: nextRun.name } : null,
            lastRun: lastRun ? { distance: lastRun.distance, calories: lastRun.calories } : null,
            supplements,
          });
          setPlan(result.data);
        } catch (err) {
          console.error(err);
          setPlan({ error: "Failed to generate plan. Please try again." });
        }
        setLoadingPlan(false);
      };

      // ── Daily Summary Email ──
      const recheckSmtp = () => {
        setSmtpChecking(true);
        setSmtpStatus(null);
        functions.httpsCallable("checkSmtpStatus")({})
          .then(r => { setSmtpStatus(r.data); setSmtpChecking(false); })
          .catch(err => { setSmtpStatus({ checkFailed: true, error: err.message || "Unknown error" }); setSmtpChecking(false); });
      };

      useEffect(() => {
        if (!userId) return;
        db.collection("users").doc(userId).collection("settings").doc("notifications")
          .get().then(doc => {
            if (doc.exists) {
              const d = doc.data();
              if (d.dailySummaryEmail) setEmailAddr(d.dailySummaryEmail);
              if (d.dailySummaryEnabled != null) setEmailEnabled(d.dailySummaryEnabled);
              if (d.dailySummaryTime) setEmailTime(d.dailySummaryTime);
            }
            setEmailLoaded(true);
          });
        recheckSmtp();
      }, [userId]);

      useEffect(() => {
        if (!userId || !emailLoaded) return;
        db.collection("users").doc(userId).collection("settings").doc("notifications")
          .set({ dailySummaryEmail: emailAddr, dailySummaryEnabled: emailEnabled, dailySummaryTime: emailTime,
            updatedAt: firebase.firestore.FieldValue.serverTimestamp() }, { merge: true });
        db.collection("users").doc(userId).collection("settings").doc("dailySummary")
          .set({ dailySummaryEmail: emailEnabled ? emailAddr : "", dailySummaryEnabled: emailEnabled,
            updatedAt: firebase.firestore.FieldValue.serverTimestamp() }, { merge: true });
      }, [emailAddr, emailEnabled, emailTime, userId, emailLoaded]);

      const sendDailyTest = async () => {
        if (!emailAddr) { setEmailMsg({ type: "err", text: "Enter an email address first" }); return; }
        setEmailSending(true); setEmailMsg(null);
        try {
          // sendSimpleTestEmail just tests SMTP without heavy summary computation
          const result = await functions.httpsCallable("sendSimpleTestEmail")({ email: emailAddr });
          setEmailMsg({ type: "ok", text: result.data.message || "Test email sent!" });
          // Re-check SMTP status after a successful send
          functions.httpsCallable("checkSmtpStatus")({}).then(r => setSmtpStatus(r.data)).catch(() => {});
        } catch (err) {
          setEmailMsg({ type: "err", text: err.message || "Failed to send" });
        }
        setEmailSending(false);
      };

      const sendDailySummary = async () => {
        if (!emailAddr) { setEmailMsg({ type: "err", text: "Enter an email address first" }); return; }
        setEmailSending(true); setEmailMsg(null);
        try {
          const result = await functions.httpsCallable("sendDailySummaryNow")({ email: emailAddr });
          setEmailMsg({ type: "ok", text: result.data.message || "Daily summary sent!" });
        } catch (err) {
          setEmailMsg({ type: "err", text: err.message || "Failed to send daily summary" });
        }
        setEmailSending(false);
      };

      const sendWeeklyTest = async () => {
        if (!emailAddr) { setEmailMsg({ type: "err", text: "Enter an email address first" }); return; }
        setEmailSending(true); setEmailMsg(null);
        try {
          await functions.httpsCallable("sendWeeklySummaryNow")({ email: emailAddr });
          setEmailMsg({ type: "ok", text: "Weekly summary sent!" });
        } catch (err) {
          setEmailMsg({ type: "err", text: err.message || "Failed to send weekly email" });
        }
        setEmailSending(false);
      };

      // RHR and sleep metrics are computed from last night's sleep → the previous day's
      // finalized value is more accurate (Garmin doesn't finalize until mid-morning).
      const YESTERDAY_PREFERRED = new Set(["hrv", "restingHR", "sleepScore", "sleepHours"]);
      // Return null for forward-filled metrics when the entry IS the selected date (a real doc
      // exists but the value was carried forward from an earlier date). When entry.date !== selectedDate
      // (nearest-prior fallback), always show — those are the last known real values.
      const isFilled = (entry, key) => entry?.[key + "_filled"] === true;
      const entryMatchesDate = (entry) => entry?.date === selectedDate;
      const getMetricValue = (key) => {
        if (YESTERDAY_PREFERRED.has(key)) {
          const prevVal = prevEntry?.[key];
          if (prevVal != null && !isFilled(prevEntry, key)) return prevVal;
        }
        const val = effectiveTodayEntry?.[key];
        if (val == null) {
          // Body battery fallback chain: start-of-day → daily max → end-of-day.
          // bodyBatteryCharged is a delta (overnight gain like "+19"), NOT a level —
          // using it here made the card display "19%" when battery actually peaked at 61%.
          if (key === "bodyBattery") {
            const src = effectiveTodayEntry || prevEntry;
            return src?.bodyBatteryStartOfDay ?? src?.bodyBatteryMax ?? src?.bodyBatteryEndOfDay ?? null;
          }
          return null;
        }
        if (entryMatchesDate(effectiveTodayEntry) && isFilled(effectiveTodayEntry, key)) {
          // Forward-filled — try day-specific alternatives
          if (key === "bodyBattery") {
            const src = effectiveTodayEntry;
            return src?.bodyBatteryStartOfDay ?? src?.bodyBatteryMax ?? src?.bodyBatteryEndOfDay ?? null;
          }
          return null;
        }
        return val;
      };

      // ── Metric definitions ──
      const metrics = [
        { key: "hrv", label: "HRV", unit: "ms", color: C.cyan, icon: "💓", range: [0, 120], good: "higher" },
        { key: "restingHR", label: "Resting HR", unit: "bpm", color: C.pink, icon: "❤️", range: [40, 100], good: "lower" },
        { key: "bodyBattery", label: "Body Battery", unit: "%", color: C.green, icon: "🔋", range: [0, 100], good: "higher" },
        { key: "sleepScore", label: "Sleep Score", unit: "", color: C.purple, icon: "😴", range: [0, 100], good: "higher" },
        { key: "sleepHours", label: "Sleep", unit: "hrs", color: C.purple, icon: "🌙", range: [4, 10], good: "higher" },
        { key: "stress", label: "Stress", unit: "", color: C.amber, icon: "😤", range: [0, 100], good: "lower" },
        { key: "trainingReadiness", label: "Train. Readiness", unit: "", color: C.green, icon: "🏋️", range: [0, 100], good: "higher" },
        { key: "spo2", label: "SpO2", unit: "%", color: C.cyanDim, icon: "🫁", range: [90, 100], good: "higher" },
        { key: "respiration", label: "Respiration", unit: "brpm", color: C.textDim, icon: "🌬️", range: [10, 25], good: "lower" },
        { key: "steps", label: "Steps", unit: "", color: C.amber, icon: "👟", range: [0, 20000], good: "higher" },
        { key: "intensityMinutes", label: "Intensity Mins", unit: "min", color: C.cyan, icon: "⚡", range: [0, 120], good: "higher" },
        { key: "floorsAscended", label: "Floors", unit: "", color: C.textDim, icon: "🏢", range: [0, 30], good: "higher" },
        { key: "totalKilocalories", label: "TDEE", unit: "kcal", color: C.amber, icon: "🔥", range: [1500, 4000], good: null },
        { key: "weight", label: "Weight", unit: "lbs", color: C.textDim, icon: "⚖️", range: [120, 220], good: null },
      ];

      const getStatusColor = (metric, value) => {
        if (value == null) return C.textMuted;
        const { range, good } = metric;
        const [lo, hi] = range;
        const pct = (value - lo) / (hi - lo);
        if (good === "higher") return pct > 0.7 ? C.green : pct > 0.4 ? C.amber : C.red;
        if (good === "lower") return pct < 0.3 ? C.green : pct < 0.6 ? C.amber : C.red;
        return C.textDim;
      };

      // Track recording start date per metric (first non-null entry)
      const recordingStart = useMemo(() => {
        const starts = {};
        metrics.forEach(m => {
          const first = entries.find(e => e[m.key] != null);
          if (first) starts[m.key] = first.date;
        });
        return starts;
      }, [entries]);

      // Forward-fill: for days with no data, carry forward the prior value
      const filledEntries = useMemo(() => {
        if (!entries.length) return [];
        const filled = [...entries];
        const lastKnown = {};
        return filled.map(e => {
          const out = { ...e };
          metrics.forEach(m => {
            if (out[m.key] != null) {
              lastKnown[m.key] = out[m.key];
            } else if (lastKnown[m.key] != null && recordingStart[m.key] && e.date >= recordingStart[m.key]) {
              out[m.key] = lastKnown[m.key];
              out[m.key + "_filled"] = true; // flag as forward-filled
            }
          });
          return out;
        });
      }, [entries, recordingStart]);

      // Selected date's entry — use forward-filled entries so cards are consistent
      // with the data table. Forward-filled values carry the most recent known value
      // for each metric rather than showing "--".
      // filledEntries must be declared before this.
      // For any date (today or past) with no exact Firestore doc, fall back to the nearest
      // prior entry so metric cards show last-known values rather than blank "--" everywhere.
      const selectedEntry = useMemo(() => {
        const exact = filledEntries.find(e => e.date === selectedDate);
        if (exact) return exact;
        if (!filledEntries.length) return null;
        for (let i = filledEntries.length - 1; i >= 0; i--) {
          if (filledEntries[i].date <= selectedDate) return filledEntries[i];
        }
        return null;
      }, [filledEntries, selectedDate]);

      const prevEntry = useMemo(() =>
        filledEntries.find(e => e.date === prevDateStr) || null,
      [filledEntries, prevDateStr]);

      // Average only from recording start date
      const weekAvg = (key) => {
        const startDate = recordingStart[key];
        if (!startDate) return null;
        const last7 = filledEntries.slice(-7).filter(e => e[key] != null && e.date >= startDate);
        if (!last7.length) return null;
        return (last7.reduce((s, e) => s + e[key], 0) / last7.length).toFixed(key === "sleepHours" || key === "weight" ? 1 : 0);
      };

      // Data table modal state
      const [showDataTable, setShowDataTable] = useState(false);
      const [dataTableEditing, setDataTableEditing] = useState(null); // { date, key, value }

      const saveDataTableEdit = async (date, key, value) => {
        const numVal = parseFloat(value);
        if (isNaN(numVal)) return;
        await db.collection("users").doc(userId).collection("health").doc(date)
          .set({ [key]: numVal, date, manualEdit: true, editedAt: firebase.firestore.FieldValue.serverTimestamp() }, { merge: true });
        setDataTableEditing(null);
      };

      // Parse YYYY-MM-DD date strings without UTC timezone offset (avoids off-by-one day in Eastern time)
      const fmtChartDate = (dateStr) => {
        if (!dateStr || typeof dateStr !== "string") return dateStr;
        const [y, m, d] = dateStr.split("-").map(Number);
        return new Date(y, m - 1, d).toLocaleDateString("en-US", { month: "short", day: "numeric" });
      };

      // selectedEntry already uses filledEntries, so it always carries the most recent
      // known value for each field. effectiveTodayEntry is a direct alias.
      const effectiveTodayEntry = selectedEntry;

      // (Moved below selectedEntry's declaration — referencing it in the deps
      // array above the const was a TDZ ReferenceError in the esbuild build.)
      // ── Populate form when selected entry changes ──
      useEffect(() => {
        const entry = selectedEntry;
        if (entry) {
          setForm({
            hrv: entry.hrv?.toString() || "",
            restingHR: entry.restingHR?.toString() || "",
            bodyBattery: entry.bodyBattery?.toString() || "",
            sleepScore: entry.sleepScore?.toString() || "",
            sleepHours: entry.sleepHours?.toString() || "",
            stress: entry.stress?.toString() || "",
            trainingReadiness: entry.trainingReadiness?.toString() || "",
            spo2: entry.spo2?.toString() || "",
            respiration: entry.respiration?.toString() || "",
            steps: entry.steps?.toString() || "",
            weight: entry.weight?.toString() || "",
          });
        } else {
          setForm({ hrv:"", restingHR:"", bodyBattery:"", sleepScore:"", sleepHours:"", stress:"", trainingReadiness:"", spo2:"", respiration:"", steps:"", weight:"" });
        }
      }, [selectedEntry?.date]);
      // Show banner:
      //   (a) Entry is from a different date (no doc for selectedDate) → "nearest available"
      //   (b) Doc exists for selectedDate but all core metrics are forward-filled → "no sync"
      const coreKeys = ["hrv", "restingHR", "bodyBattery", "sleepScore", "steps"];
      const allCoreFilled = selectedEntry && selectedEntry.date === selectedDate
        && coreKeys.every(k => selectedEntry[k] == null || selectedEntry[k + "_filled"] === true)
        && coreKeys.some(k => selectedEntry[k] != null);
      const effectiveTodayLabel = selectedEntry
        ? selectedEntry.date !== selectedDate
          ? `Showing ${fmtChartDate(selectedEntry.date)} — no Garmin data for ${isToday ? "today" : fmtChartDate(selectedDate)}`
          : (!isToday && allCoreFilled)
            ? "No Garmin data synced for this date"
            : null
        : null;

      // Recovery headline. Garmin's Training Readiness IS a validated
      // composite (HRV + sleep + body battery + recovery time), so when
      // present it is the score — the old homemade average re-mixed those
      // same inputs (double-counting) and could contradict both Garmin
      // and the HRV guidance. The average survives only as a fallback for
      // days with no readiness reading.
      const recoveryScore = useMemo(() => {
        const get = (key) => effectiveTodayEntry?.[key];
        if (get("trainingReadiness") != null) return Math.round(get("trainingReadiness"));
        if (!effectiveTodayEntry && !entries.length) return null;
        const components = [];
        if (get("hrv") != null) components.push(Math.min(100, (get("hrv") / 80) * 100));
        if (get("bodyBattery") != null) components.push(get("bodyBattery"));
        if (get("sleepScore") != null) components.push(get("sleepScore"));
        if (get("stress") != null) components.push(100 - get("stress"));
        if (!components.length) return null;
        return Math.round(components.reduce((s, v) => s + v, 0) / components.length);
      }, [effectiveTodayEntry, entries]);
      const recoveryIsGarmin = effectiveTodayEntry?.trainingReadiness != null;

      // Today's HRV-guided call (server snapshot) is the actionable label
      // when available — it already weighs readiness, the baseline band,
      // and today's planned workout.
      const hrvCall = trainingSnapshot?.recovery?.hrvGuidance || null;
      const HRV_ACTION_LABEL = { proceed: "Proceed as planned", caution: "Caution — warm up, then decide", swap_to_easy: "Swap today's quality to easy", keep_easy: "Keep today easy", recovery_day: "Recovery day" };
      const recoveryLabel = (hrvCall && HRV_ACTION_LABEL[hrvCall.action])
        ? HRV_ACTION_LABEL[hrvCall.action]
        : recoveryScore == null ? "No data" :
          recoveryScore >= 75 ? "Excellent — ready to push" :
          recoveryScore >= 55 ? "Good — normal training" :
          recoveryScore >= 35 ? "Fair — consider easy day" : "Low — prioritize recovery";

      const recoveryColor = recoveryScore == null ? C.textMuted :
        recoveryScore >= 75 ? C.green : recoveryScore >= 55 ? C.cyan : recoveryScore >= 35 ? C.amber : C.red;

      const trendData = useMemo(() => {
        return filledEntries.map(e => ({
          ...e,
          date: fmtChartDate(e.id), // set AFTER spread so it isn't overwritten by raw date field
        }));
      }, [filledEntries]);

      // Trim leading null entries per chart — show from first date with actual data
      const trimChartData = (keys) => {
        const firstIdx = filledEntries.findIndex(e => keys.some(k => e[k] != null));
        return firstIdx >= 0 ? trendData.slice(firstIdx) : trendData;
      };
      // Keep only the last `days` of chart rows, measured back from the most
      // recent data point. Used so the "Last 90 Days" chart honours its title
      // instead of stretching to wherever the longest-lived metric (resting
      // HR) first appeared — which made shorter-history metrics (HRV) look
      // like a sliver of missing data on a year-wide axis.
      const windowChartData = (data, days) => {
        if (!Array.isArray(data) || data.length === 0) return data;
        const lastId = data[data.length - 1].id;
        if (!lastId || typeof lastId !== "string") return data;
        const [y, m, d] = lastId.split("-").map(Number);
        const c = new Date(y, m - 1, d);
        c.setDate(c.getDate() - days);
        const pad = (n) => String(n).padStart(2, "0");
        const cutoff = `${c.getFullYear()}-${pad(c.getMonth() + 1)}-${pad(c.getDate())}`;
        return data.filter(e => (e.id || "") >= cutoff);
      };
      // Overlay a least-squares linear fit. Adds `${key}Trend` to every
      // row (so the line spans the full window) computed only from that
      // metric's finite points. A key is skipped when it has <2 points
      // or no x-variance, so the dashed line just doesn't render.
      const withTrend = (data, keys) => {
        if (!Array.isArray(data) || data.length < 2) return data;
        const out = data.map(d => ({ ...d }));
        for (const key of keys) {
          let n = 0, sx = 0, sy = 0, sxx = 0, sxy = 0;
          for (let i = 0; i < out.length; i++) {
            const y = Number(out[i][key]);
            if (!Number.isFinite(y)) continue;
            n++; sx += i; sy += y; sxx += i * i; sxy += i * y;
          }
          if (n < 2) continue;
          const denom = n * sxx - sx * sx;
          if (denom === 0) continue;
          const slope = (n * sxy - sx * sy) / denom;
          const intercept = (sy - slope * sx) / n;
          for (let i = 0; i < out.length; i++) {
            out[i][key + "Trend"] = +(slope * i + intercept).toFixed(2);
          }
        }
        return out;
      };
      // Weight-related charts floor at 2026-03-26 (first reliable data; Mar 25 was outlier)
      const WEIGHT_CUTOFF = "2026-03-26";
      // Dates to exclude from weight chart and averages (bad data points)
      const WEIGHT_EXCLUDE = new Set(["2026-03-25"]);
      const trimWeightChart = (keys) => {
        const firstData = filledEntries.find(e => keys.some(k => e[k] != null) && e.id >= WEIGHT_CUTOFF);
        const cutoff = firstData ? firstData.id : WEIGHT_CUTOFF;
        return trendData.filter(d => d.id >= cutoff && !WEIGHT_EXCLUDE.has(d.id));
      };

      // ── Weight computed data ──
      const weightData = useMemo(() => entries.filter(e => e.weight != null && e.weight >= 100 && e.id >= WEIGHT_CUTOFF && !WEIGHT_EXCLUDE.has(e.id)), [entries]);
      const latestWeight = weightData.slice(-1)[0]?.weight;
      const prevWeight = weightData.slice(-2, -1)[0]?.weight;
      const weightDelta = latestWeight && prevWeight ? (latestWeight - prevWeight).toFixed(1) : null;
      const goalDelta = latestWeight && weightGoal ? (latestWeight - weightGoal.goalWeight).toFixed(1) : null;

      // 7-day moving average for weight
      const weightTrendWithMA = useMemo(() => {
        const wData = entries.filter(e => e.weight != null && e.weight >= 100 && e.id >= WEIGHT_CUTOFF && !WEIGHT_EXCLUDE.has(e.id)).map(e => ({
          date: fmtChartDate(e.id),
          rawDate: e.id,
          weight: e.weight,
        }));
        return wData.map((d, i) => {
          const window = wData.slice(Math.max(0, i - 6), i + 1);
          const ma = (window.reduce((s, w) => s + w.weight, 0) / window.length).toFixed(1);
          return { ...d, ma: parseFloat(ma) };
        });
      }, [entries]);

      // Hunger colors
      const hungerColor = (level) => {
        if (level <= 1) return C.green;
        if (level <= 2) return C.cyan;
        if (level <= 3) return C.amber;
        if (level <= 4) return "#f97316";
        return C.red;
      };

      // Average hunger per day for correlation
      const hungerMacroCorrelation = useMemo(() => {
        const byDate = {};
        allHunger.forEach(h => {
          if (!byDate[h.date]) byDate[h.date] = [];
          byDate[h.date].push(h.level);
        });
        return nutritionHistory.filter(n => byDate[n.date]).map(n => ({
          date: new Date(n.date).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
          avgHunger: (byDate[n.date].reduce((s, v) => s + v, 0) / byDate[n.date].length).toFixed(1),
          calories: n.calories || 0,
          protein: n.protein || 0,
        }));
      }, [allHunger, nutritionHistory]);

      // Macro target colors
      const macroColors = { calories: C.pink, protein: C.purple, carbs: C.amber, fat: C.cyan, fiber: C.green };

      // Input style reused
      const inputStyle = {
        width: "100%", background: C.bg2, border: `1px solid ${C.border}`, borderRadius: 6,
        padding: "8px 10px", color: C.text, fontSize: 14, fontFamily: "'IBM Plex Mono',monospace",
      };

      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <div>
              <div style={{ fontFamily: "'Space Grotesk', sans-serif", fontSize: 26, fontWeight: 800, color: C.text, marginBottom: 4 }}>Health</div>
              <div style={{ color: C.textMuted, fontSize: 13 }}>Body composition, nutrition, recovery & coaching</div>
            </div>
            <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4 }}>
              <Badge label="Garmin Connect" color={C.green} />
              {(() => {
                const raw = todayEntry?.syncedAt || yesterdayEntry?.syncedAt;
                if (!raw) return null;
                const ts = raw?.toDate ? raw.toDate() : (raw?.seconds ? new Date(raw.seconds * 1000) : null);
                if (!ts) return null;
                const ageHours = (Date.now() - ts.getTime()) / 3600000;
                const label = ageHours < 1 ? "synced just now"
                  : ageHours < 24 ? `synced ${Math.round(ageHours)}h ago`
                  : `synced ${Math.round(ageHours / 24)}d ago`;
                const color = ageHours < 6 ? C.green : ageHours < 24 ? C.amber : C.red;
                return (
                  <span style={{ fontSize: 10, color, fontFamily: "'IBM Plex Mono', monospace" }}>
                    {ageHours >= 24 ? "⚠ " : ""}{label}
                  </span>
                );
              })()}
            </div>
          </div>

          <div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}>
            <TabBar tabs={["Today", "Body Comp", "Nutrition", "Trends", "Recovery", "AI Coach"]} active={tab} onChange={setTab} />
            <button onClick={() => setShowDataTable(true)} style={{
              background:"none",border:`1px solid ${C.border}`,borderRadius:6,padding:"4px 10px",
              color:C.textMuted,cursor:"pointer",fontSize:10,fontFamily:"'IBM Plex Mono',monospace",whiteSpace:"nowrap",
            }}>📊 Data Table</button>
          </div>

          {/* Data table modal */}
          {showDataTable && (
            <div style={{position:"fixed",top:0,left:0,right:0,bottom:0,background:"rgba(0,0,0,0.8)",zIndex:9999,display:"flex",alignItems:"center",justifyContent:"center",padding:20}} onClick={() => setShowDataTable(false)}>
              <div onClick={e => e.stopPropagation()} style={{background:C.bg,border:`1px solid ${C.border}`,borderRadius:12,maxWidth:900,width:"100%",maxHeight:"80vh",overflow:"auto",padding:20}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:16}}>
                  <div style={{fontSize:16,fontWeight:700,color:C.text}}>Health Data Table</div>
                  <div style={{display:"flex",gap:8,alignItems:"center"}}>
                    <span style={{fontSize:10,color:C.textMuted}}>Click any cell to edit · Forward-filled values shown in italic</span>
                    <button onClick={() => setShowDataTable(false)} style={{background:"none",border:"none",color:C.textMuted,cursor:"pointer",fontSize:18}}>×</button>
                  </div>
                </div>
                <div style={{overflowX:"auto"}}>
                  <table style={{width:"100%",borderCollapse:"collapse",fontSize:11}}>
                    <thead>
                      <tr style={{borderBottom:`1px solid ${C.border}`}}>
                        <th style={{padding:"6px 8px",textAlign:"left",color:C.textMuted,fontWeight:600,position:"sticky",left:0,background:C.bg}}>Date</th>
                        {metrics.map(m => <th key={m.key} style={{padding:"6px 8px",textAlign:"right",color:m.color,fontWeight:600,whiteSpace:"nowrap"}}>{m.icon} {m.label}</th>)}
                      </tr>
                    </thead>
                    <tbody>
                      {[...filledEntries].reverse().slice(0, 30).map(e => (
                        <tr key={e.date} style={{borderBottom:`1px solid ${C.border}20`}}>
                          <td style={{padding:"5px 8px",color:C.textDim,fontWeight:600,position:"sticky",left:0,background:C.bg,whiteSpace:"nowrap"}}>
                            {new Date(e.date + "T12:00:00").toLocaleDateString("en-US",{month:"short",day:"numeric",weekday:"short"})}
                          </td>
                          {metrics.map(m => {
                            const val = e[m.key];
                            const isFilled = e[m.key + "_filled"];
                            const isEditing = dataTableEditing?.date === e.date && dataTableEditing?.key === m.key;
                            return (
                              <td key={m.key} style={{padding:"5px 8px",textAlign:"right",cursor:"pointer"}}
                                onClick={() => !isEditing && setDataTableEditing({ date: e.date, key: m.key, value: val != null ? String(val) : "" })}>
                                {isEditing ? (
                                  <input autoFocus value={dataTableEditing.value}
                                    onChange={ev => setDataTableEditing(prev => ({...prev, value: ev.target.value}))}
                                    onKeyDown={ev => { if (ev.key === "Enter") saveDataTableEdit(e.date, m.key, dataTableEditing.value); if (ev.key === "Escape") setDataTableEditing(null); }}
                                    onBlur={() => saveDataTableEdit(e.date, m.key, dataTableEditing.value)}
                                    style={{width:60,textAlign:"right",fontSize:11,padding:"2px 4px"}} />
                                ) : (
                                  <span style={{color: val != null ? (isFilled ? C.textMuted : getStatusColor(m, val)) : C.border, fontStyle: isFilled ? "italic" : "normal"}}>
                                    {val != null ? (m.key === "sleepHours" || m.key === "weight" ? parseFloat(val).toFixed(1) : Math.round(val)) : "—"}
                                  </span>
                                )}
                              </td>
                            );
                          })}
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <div style={{marginTop:12,fontSize:10,color:C.textMuted}}>
                  {Object.entries(recordingStart).map(([key, date]) => {
                    const m = metrics.find(x => x.key === key);
                    return m ? <span key={key} style={{marginRight:12}}>{m.icon} Recording since {new Date(date).toLocaleDateString("en-US",{month:"short",day:"numeric"})}</span> : null;
                  })}
                </div>
              </div>
            </div>
          )}

          {/* ═══════════════════════ TODAY TAB ═══════════════════════ */}
          {tab === "Today" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

              {/* Day navigator */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 12 }}>
                <button onClick={navBack} style={{
                  width: 32, height: 32, borderRadius: "50%", border: `1px solid ${C.border}`,
                  background: C.bg2, color: C.text, fontSize: 16, cursor: "pointer", display: "flex",
                  alignItems: "center", justifyContent: "center", lineHeight: 1,
                }}>‹</button>

                <div style={{ textAlign: "center", minWidth: 160 }}>
                  <div style={{ fontSize: 15, fontWeight: 700, color: C.text, fontFamily: "'IBM Plex Mono', monospace" }}>
                    {isToday ? "Today" : new Date(selectedDate + "T12:00:00").toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" })}
                  </div>
                  {!isToday && (
                    <button onClick={() => setSelectedDate(today)} style={{
                      marginTop: 2, fontSize: 10, color: C.cyan, background: "none",
                      border: "none", cursor: "pointer", fontFamily: "'IBM Plex Mono', monospace",
                      padding: 0, textDecoration: "underline",
                    }}>back to today</button>
                  )}
                </div>

                <button onClick={navForward} disabled={isToday} style={{
                  width: 32, height: 32, borderRadius: "50%", border: `1px solid ${isToday ? C.bg3 : C.border}`,
                  background: isToday ? C.bg1 : C.bg2, color: isToday ? C.textMuted : C.text,
                  fontSize: 16, cursor: isToday ? "not-allowed" : "pointer", display: "flex",
                  alignItems: "center", justifyContent: "center", lineHeight: 1,
                }}>›</button>
              </div>

              {/* Recovery score card */}
              <Card style={{ borderColor: recoveryColor + "60", background: recoveryColor + "08" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <div>
                    <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6 }}>Recovery {recoveryIsGarmin ? "(Garmin readiness)" : "(estimated)"}</div>
                    <div style={{ fontSize: 42, fontWeight: 900, fontFamily: "'Space Grotesk', sans-serif", color: recoveryColor, lineHeight: 1 }}>
                      {recoveryScore ?? "--"}
                    </div>
                    <div style={{ fontSize: 12, color: recoveryColor, marginTop: 8 }}>{recoveryLabel}</div>
                    {hrvCall && hrvCall.reason && hrvCall.action !== "proceed" && (
                      <div style={{ fontSize: 10, color: C.textMuted, marginTop: 4, maxWidth: 220, lineHeight: 1.4 }}>{hrvCall.reason}</div>
                    )}
                  </div>
                  <div style={{
                    width: 80, height: 80, borderRadius: "50%",
                    border: `4px solid ${recoveryColor}40`,
                    background: `conic-gradient(${recoveryColor} ${(recoveryScore || 0) * 3.6}deg, ${C.bg3} 0deg)`,
                    display: "flex", alignItems: "center", justifyContent: "center",
                  }}>
                    <div style={{
                      width: 64, height: 64, borderRadius: "50%", background: C.bg1,
                      display: "flex", alignItems: "center", justifyContent: "center", fontSize: 24,
                    }}>
                      {recoveryScore >= 75 ? "💪" : recoveryScore >= 55 ? "👍" : recoveryScore >= 35 ? "😐" : recoveryScore != null ? "😴" : "—"}
                    </div>
                  </div>
                </div>
              </Card>

              {/* Weight + Macros + Hunger summary row */}
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
                {/* Weight snapshot */}
                <Card style={{ padding: 16 }}>
                  <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>Weight</div>
                  <div style={{ fontSize: 28, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.text, lineHeight: 1 }}>
                    {latestWeight ?? "--"}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>lbs</span>
                  </div>
                  {weightDelta && (
                    <div style={{ fontSize: 11, color: parseFloat(weightDelta) <= 0 ? C.green : C.amber, marginTop: 6 }}>
                      {parseFloat(weightDelta) > 0 ? "+" : ""}{weightDelta} from yesterday
                    </div>
                  )}
                  {goalDelta && (
                    <div style={{ fontSize: 11, color: C.textMuted, marginTop: 2 }}>
                      {Math.abs(goalDelta)} lbs to goal
                    </div>
                  )}
                </Card>

                {/* Macro snapshot */}
                <Card style={{ padding: 16 }}>
                  <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>Calories</div>
                  <div style={{ fontSize: 28, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.pink, lineHeight: 1 }}>
                    {nutritionData.calories || "--"}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>kcal</span>
                  </div>
                  <div style={{ fontSize: 11, color: C.textMuted, marginTop: 6 }}>
                    P:{nutritionData.protein || 0}g C:{nutritionData.carbs || 0}g F:{nutritionData.fat || 0}g
                  </div>
                  <div style={{ background: C.bg3, borderRadius: 3, height: 4, marginTop: 6, overflow: "hidden" }}>
                    <div style={{ width: `${Math.min(100, Math.round(((nutritionData.calories || 0) / macroTargets.calories) * 100))}%`, height: "100%", background: C.pink, borderRadius: 3 }} />
                  </div>
                </Card>

                {/* Hunger snapshot */}
                <Card style={{ padding: 16 }}>
                  <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>Hunger Today</div>
                  {hungerEntries.length > 0 ? (
                    <div>
                      <div style={{ fontSize: 28, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: hungerColor(hungerEntries[hungerEntries.length - 1].level), lineHeight: 1 }}>
                        {hungerEntries[hungerEntries.length - 1].level}<span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>/5</span>
                      </div>
                      <div style={{ display: "flex", gap: 4, marginTop: 8 }}>
                        {hungerEntries.map((h, i) => (
                          <div key={i} title={`${h.time}: ${h.level}/5 ${h.note || ""}`}
                            style={{ width: 12, height: 12, borderRadius: "50%", background: hungerColor(h.level) }} />
                        ))}
                      </div>
                    </div>
                  ) : (
                    <div style={{ fontSize: 13, color: C.textMuted }}>No entries yet</div>
                  )}
                  <div style={{ marginTop: 8 }}>
                    <Btn onClick={() => setLoggingHunger(!loggingHunger)} variant="ghost" small>
                      {loggingHunger ? "Cancel" : "+ Log"}
                    </Btn>
                  </div>
                  {loggingHunger && (
                    <div style={{ marginTop: 8 }}>
                      <div style={{ display: "flex", gap: 6, marginBottom: 6 }}>
                        {[1,2,3,4,5].map(l => (
                          <button key={l} onClick={() => setHungerForm({ ...hungerForm, level: l })}
                            style={{
                              width: 28, height: 28, borderRadius: "50%", border: hungerForm.level === l ? `2px solid ${hungerColor(l)}` : `1px solid ${C.border}`,
                              background: hungerForm.level === l ? hungerColor(l) + "30" : C.bg2,
                              color: hungerColor(l), fontSize: 12, fontWeight: 700, cursor: "pointer",
                            }}>{l}</button>
                        ))}
                      </div>
                      <input placeholder="Note (optional)" value={hungerForm.note}
                        onChange={e => setHungerForm({ ...hungerForm, note: e.target.value })}
                        style={{ ...inputStyle, fontSize: 11, padding: "4px 8px", marginBottom: 6 }} />
                      <Btn onClick={logHunger} small>Log</Btn>
                    </div>
                  )}
                </Card>
              </div>

              {/* Metric grid */}
              {effectiveTodayLabel && (
                <div style={{ fontSize: 11, color: C.textMuted, textAlign: "center", marginBottom: -4 }}>
                  {effectiveTodayLabel}
                </div>
              )}
              <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 12 }}>
                {metrics.map(m => {
                  const val = getMetricValue(m.key);
                  const avg = weekAvg(m.key);
                  const isYesterday = YESTERDAY_PREFERRED.has(m.key) && yesterdayEntry?.[m.key] != null && yesterdayEntry?.[m.key] === val;
                  // Extra detail line for specific metrics
                  const srcEntry = YESTERDAY_PREFERRED.has(m.key) ? (prevEntry || effectiveTodayEntry) : effectiveTodayEntry;
                  const extraDetail = m.key === "hrv"
                    ? (() => {
                        const parts = [];
                        if (srcEntry?.hrvHighestNight != null) parts.push(`Highest: ${srcEntry.hrvHighestNight}ms`);
                        if (srcEntry?.hrvWeeklyAvg != null) parts.push(`7d avg: ${srcEntry.hrvWeeklyAvg}ms`);
                        if (srcEntry?.hrvStatus) parts.push(srcEntry.hrvStatus.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, c => c.toUpperCase()));
                        return parts.length ? parts.join(" · ") : null;
                      })()
                    : m.key === "bodyBattery"
                    ? (() => {
                        const parts = [];
                        if (srcEntry?.bodyBatteryStartOfDay != null) parts.push(`↑${srcEntry.bodyBatteryStartOfDay}% start`);
                        if (srcEntry?.bodyBatteryEndOfDay != null) parts.push(`↓${srcEntry.bodyBatteryEndOfDay}% end`);
                        if (srcEntry?.bodyBatteryCharged != null) parts.push(`+${srcEntry.bodyBatteryCharged} charged`);
                        if (srcEntry?.bodyBatteryDrained != null) parts.push(`-${srcEntry.bodyBatteryDrained} used`);
                        return parts.length ? parts.join(" · ") : null;
                      })()
                    : m.key === "trainingReadiness" && srcEntry?.trainingReadinessFeedback
                    ? srcEntry.trainingReadinessFeedback.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, c => c.toUpperCase())
                    : null;
                  return (
                    <Card key={m.key} style={{ padding: 16 }}>
                      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
                        <div style={{ fontSize: 11, color: C.textMuted, textTransform: "uppercase", letterSpacing: "0.06em" }}>{m.label}</div>
                        <span style={{ fontSize: 16 }}>{m.icon}</span>
                      </div>
                      <div style={{ fontSize: 26, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: getStatusColor(m, val), lineHeight: 1 }}>
                        {val != null ? val : "--"}
                        <span style={{ fontSize: 12, color: C.textMuted, marginLeft: 4 }}>{val != null ? m.unit : ""}</span>
                      </div>
                      {/* 7d avg — suppress for HRV since extraDetail already shows Garmin's hrvWeeklyAvg */}
                      {avg && m.key !== "hrv" && <div style={{ fontSize: 11, color: C.textMuted, marginTop: 6 }}>7d avg: {avg} {m.unit}</div>}
                      {extraDetail && <div style={{ fontSize: 10, color: C.textDim, marginTop: 4 }}>{extraDetail}</div>}
                      {isYesterday && <div style={{ fontSize: 9, color: C.textMuted, marginTop: 2, fontStyle: "italic" }}>last night</div>}
                    </Card>
                  );
                })}
              </div>

              {/* Log entry form */}
              <Card style={{ borderColor: editing ? C.cyan + "60" : C.border }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: editing ? 16 : 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>{todayEntry ? "Today's Entry" : "Log Today's Metrics"}</div>
                  {!editing ? (
                    <Btn onClick={() => setEditing(true)} variant="secondary" small>{todayEntry ? "Edit" : "Add Entry"}</Btn>
                  ) : (
                    <div style={{ display: "flex", gap: 8 }}>
                      <Btn onClick={saveEntry} small>Save</Btn>
                      <Btn onClick={() => setEditing(false)} variant="ghost" small>Cancel</Btn>
                    </div>
                  )}
                </div>
                {editing && (
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 12 }}>
                    {metrics.map(m => (
                      <div key={m.key}>
                        <div style={{ fontSize: 11, color: C.textMuted, marginBottom: 4 }}>{m.icon} {m.label}</div>
                        <input type="number" step={m.key === "sleepHours" || m.key === "weight" ? "0.1" : "1"}
                          placeholder={m.unit || "0"} value={form[m.key]}
                          onChange={e => setForm({ ...form, [m.key]: e.target.value })}
                          style={inputStyle} />
                      </div>
                    ))}
                  </div>
                )}
                {!editing && todayEntry && (
                  <div style={{ fontSize: 11, color: C.textMuted, marginTop: 8 }}>
                    Last updated: {todayEntry.updatedAt ? new Date(todayEntry.updatedAt.seconds * 1000).toLocaleTimeString() : "just now"}
                  </div>
                )}
                {!editing && !todayEntry && (
                  <div style={{ fontSize: 12, color: C.textMuted, marginTop: 8 }}>Log your Garmin stats from today — HRV, Body Battery, sleep, stress, and more.</div>
                )}
              </Card>
            </div>
          )}

          {/* ═══════════════════════ BODY COMP TAB ═══════════════════════ */}
          {tab === "Body Comp" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              {/* Weight Goal Configuration */}
              <Card style={{ borderColor: editingGoal ? C.green + "60" : C.border }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: editingGoal ? 16 : 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>Weight Goal</div>
                  {!editingGoal ? (
                    <Btn onClick={() => setEditingGoal(true)} variant="secondary" small>{weightGoal ? "Edit Goal" : "Set Goal"}</Btn>
                  ) : (
                    <div style={{ display: "flex", gap: 8 }}>
                      <Btn onClick={saveWeightGoal} small>Save</Btn>
                      <Btn onClick={() => setEditingGoal(false)} variant="ghost" small>Cancel</Btn>
                    </div>
                  )}
                </div>
                {editingGoal ? (
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                    <div>
                      <div style={{ fontSize: 11, color: C.textMuted, marginBottom: 4 }}>Goal Weight (lbs)</div>
                      <input type="number" step="0.1" value={goalForm.goalWeight}
                        onChange={e => setGoalForm({ ...goalForm, goalWeight: e.target.value })}
                        placeholder="e.g. 165" style={inputStyle} />
                    </div>
                    <div>
                      <div style={{ fontSize: 11, color: C.textMuted, marginBottom: 4 }}>Weekly Rate (lbs/week)</div>
                      <select value={goalForm.weeklyRate}
                        onChange={e => setGoalForm({ ...goalForm, weeklyRate: e.target.value })}
                        style={{ ...inputStyle, cursor: "pointer" }}>
                        <option value="0.25">0.25 lbs/week (gentle)</option>
                        <option value="0.5">0.5 lbs/week (moderate)</option>
                        <option value="0.75">0.75 lbs/week (steady)</option>
                        <option value="1.0">1.0 lbs/week (aggressive)</option>
                      </select>
                    </div>
                    <div style={{ gridColumn: "1/-1", fontSize: 12, color: C.textMuted, padding: "8px 12px", background: C.bg2, borderRadius: 8 }}>
                      Current weight: <strong style={{ color: C.text }}>{latestWeight || "—"} lbs</strong>
                      {goalForm.goalWeight && latestWeight ? (
                        <span> · {Math.abs(latestWeight - parseFloat(goalForm.goalWeight)).toFixed(1)} lbs to lose ·
                        ~{Math.ceil(Math.abs(latestWeight - parseFloat(goalForm.goalWeight)) / parseFloat(goalForm.weeklyRate))} weeks</span>
                      ) : null}
                    </div>
                  </div>
                ) : weightGoal ? (
                  <div style={{ marginTop: 12 }}>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
                      <div style={{ textAlign: "center", padding: 12, background: C.bg2, borderRadius: 8 }}>
                        <div style={{ fontSize: 22, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.text }}>{latestWeight || "—"}</div>
                        <div style={{ fontSize: 11, color: C.textMuted }}>Current</div>
                      </div>
                      <div style={{ textAlign: "center", padding: 12, background: C.bg2, borderRadius: 8 }}>
                        <div style={{ fontSize: 22, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.green }}>{weightGoal.goalWeight}</div>
                        <div style={{ fontSize: 11, color: C.textMuted }}>Goal</div>
                      </div>
                      <div style={{ textAlign: "center", padding: 12, background: C.bg2, borderRadius: 8 }}>
                        <div style={{ fontSize: 22, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.amber }}>{weightGoal.weeklyRate}</div>
                        <div style={{ fontSize: 11, color: C.textMuted }}>lbs/week</div>
                      </div>
                      <div style={{ textAlign: "center", padding: 12, background: C.bg2, borderRadius: 8 }}>
                        <div style={{ fontSize: 22, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: C.cyan }}>
                          {weightGoal.targetDate ? new Date(weightGoal.targetDate).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"}
                        </div>
                        <div style={{ fontSize: 11, color: C.textMuted }}>Target Date</div>
                      </div>
                    </div>
                    {/* Progress bar — tracks from first recorded weight to goal */}
                    {latestWeight && weightGoal.goalWeight && (
                      <div style={{ marginTop: 16 }}>
                        {(() => {
                          const firstWeight = weightData.length > 0 ? weightData[0].weight : (weightGoal.startWeight || latestWeight);
                          const toGo = Math.abs(latestWeight - weightGoal.goalWeight);
                          const totalRange = Math.abs(firstWeight - weightGoal.goalWeight);
                          const progressPct = totalRange > 0 ? Math.min(100, Math.max(0, ((totalRange - toGo) / totalRange) * 100)) : 0;
                          const weeksRemaining = Math.ceil(toGo / (weightGoal.weeklyRate || 1));
                          return (
                            <>
                              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, color: C.textMuted, marginBottom: 6 }}>
                                <span>Start: {firstWeight} lbs</span>
                                <span>Now: {latestWeight} lbs</span>
                                <span>Goal: {weightGoal.goalWeight} lbs</span>
                              </div>
                              <div style={{ background: C.bg3, borderRadius: 6, height: 12, overflow: "hidden", position: "relative" }}>
                                <div style={{
                                  width: `${progressPct}%`,
                                  height: "100%", background: `linear-gradient(90deg, ${C.cyan}, ${C.green})`, borderRadius: 6, transition: "width 0.5s",
                                }} />
                              </div>
                              <div style={{ display: "flex", justifyContent: "space-between", marginTop: 6, fontSize: 11 }}>
                                <span style={{ color: C.green }}>{progressPct.toFixed(0)}% to goal</span>
                                <span style={{ color: C.textMuted }}>{toGo.toFixed(1)} lbs to go · ~{weeksRemaining} weeks</span>
                              </div>
                            </>
                          );
                        })()}
                      </div>
                    )}
                  </div>
                ) : (
                  <div style={{ fontSize: 12, color: C.textMuted, marginTop: 8 }}>Set a weight goal to track your progress with projected timeline.</div>
                )}
              </Card>

              {/* Weight trend chart — detail or full timeline */}
              <Card>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>
                    {weightViewMode === "detail" ? "Weight Trend — Detail" : `Weight Trend — To ${raceTargetLabel}`}
                  </div>
                  <div style={{ display: "flex", gap: 4 }}>
                    <Btn onClick={() => setWeightViewMode("detail")} variant={weightViewMode === "detail" ? "primary" : "ghost"} small>Detail</Btn>
                    <Btn onClick={() => setWeightViewMode("full")} variant={weightViewMode === "full" ? "primary" : "ghost"} small>Full</Btn>
                  </div>
                </div>
                {weightTrendWithMA.length < 3 ? (
                  <EmptyState icon="⚖️" title="Not enough weight data" sub="Log weight for at least 3 days to see trends" />
                ) : (
                  <ResponsiveContainer width="100%" height={300}>
                    {(() => {
                      const WEIGHT_START = "2026-03-26";
                      const TARGET_DATE = raceTargetDate;
                      const t0 = new Date(WEIGHT_START).getTime();
                      const tEnd = new Date(TARGET_DATE).getTime();

                      const wtFiltered = entries
                        .filter(e => e.weight != null && e.weight >= 100 && e.id >= WEIGHT_START && !WEIGHT_EXCLUDE.has(e.id))
                        .map(e => ({ rawDate: e.id, ts: new Date(e.id).getTime(), weight: e.weight }));
                      const wtData = wtFiltered.map((d, i) => {
                        const win = wtFiltered.slice(Math.max(0, i - 6), i + 1);
                        return { ...d, ma: parseFloat((win.reduce((s, w) => s + w.weight, 0) / win.length).toFixed(1)) };
                      });

                      // Trend line — anchored at the first recorded weight
                      // and fit through that fixed point. Plain OLS centers on
                      // the data mean, which means daily water-weight noise
                      // pulls the slope shallower than the actual fat-loss
                      // trajectory: the line just slides down with you instead
                      // of projecting from where you started. Anchoring keeps
                      // the start fixed so the slope reflects the realized
                      // rate of change since day one.
                      const anchorTs = wtData[0].ts;
                      const anchorWeight = wtData[0].weight;
                      const xs = wtData.map(d => (d.ts - anchorTs) / 86400000); // days since start
                      const dys = wtData.map(d => d.weight - anchorWeight);     // weight delta from anchor
                      // Regression through the origin: slope = Σxy / Σx²
                      const sxx = xs.reduce((s, x) => s + x * x, 0);
                      const sxy = xs.reduce((s, x, i) => s + x * dys[i], 0);
                      const regSlope = sxx > 0 ? sxy / sxx : 0;
                      const trendAt = (ts) => parseFloat((anchorWeight + regSlope * (ts - anchorTs) / 86400000).toFixed(1));

                      const lastTs = wtData[wtData.length - 1]?.ts || Date.now();

                      // Historical data with trend values
                      const wtDataWithTrend = wtData.map(d => ({ ts: d.ts, weight: d.weight, ma: d.ma, trend: trendAt(d.ts) }));

                      // Future projection points (full view only) — weekly steps for performance
                      const futurePoints = [];
                      if (weightViewMode === "full") {
                        const d = new Date(lastTs); d.setDate(d.getDate() + 7);
                        while (d.getTime() <= tEnd) {
                          futurePoints.push({ ts: d.getTime(), trend: trendAt(d.getTime()) });
                          d.setDate(d.getDate() + 7);
                        }
                        if (!futurePoints.length || futurePoints[futurePoints.length - 1].ts < tEnd) {
                          futurePoints.push({ ts: tEnd, trend: trendAt(tEnd) });
                        }
                      }

                      const fullData = [...wtDataWithTrend, ...futurePoints];

                      const goalWeight = weightGoal?.goalWeight || 170;
                      const allWeights = wtData.map(d => d.weight);
                      const yMin = Math.floor(Math.min(165, goalWeight) / 5) * 5;
                      const yMax = Math.ceil(Math.max(202, Math.max(...allWeights)) / 5) * 5;

                      // Evenly-spaced time ticks
                      const ticks = [];
                      if (weightViewMode === "full") {
                        ticks.push(t0);
                        const d = new Date(WEIGHT_START); d.setDate(1); d.setMonth(d.getMonth() + 1);
                        while (d.getTime() <= tEnd) { ticks.push(d.getTime()); d.setMonth(d.getMonth() + 1); }
                        if (ticks[ticks.length - 1] < tEnd) ticks.push(tEnd);
                      } else {
                        const d = new Date(WEIGHT_START);
                        while (d.getTime() <= lastTs) { ticks.push(d.getTime()); d.setDate(d.getDate() + 7); }
                        if (!ticks.length || ticks[ticks.length - 1] < lastTs) ticks.push(lastTs);
                      }

                      const xDomain = weightViewMode === "full" ? [t0, tEnd] : [t0, lastTs];
                      const tickFmt = (ts) => new Date(ts).toLocaleDateString("en-US", { month: "short", day: "numeric" });

                      return (
                        <ComposedChart data={fullData}>
                          <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                          <XAxis dataKey="ts" type="number" scale="time" domain={xDomain}
                            ticks={ticks} tickFormatter={tickFmt}
                            tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} />
                          <YAxis tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false}
                            domain={[yMin, yMax]} allowDataOverflow />
                          <Tooltip content={<ChartTooltip formatter={(v) => `${v} lbs`} labelFormatter={tickFmt} />} />
                          <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                          <Line type="monotone" dataKey="weight" stroke={C.textDim} strokeWidth={1.5}
                            dot={{ fill: C.textDim, r: 2.5 }} name="Daily Weight" connectNulls />
                          <Line type="monotone" dataKey="ma" stroke={C.cyan} strokeWidth={2}
                            dot={false} name="7-Day Avg" connectNulls />
                          <Line type="linear" dataKey="trend" stroke={C.amber} strokeWidth={1.5}
                            strokeDasharray="5 3" dot={false} name="Trend" connectNulls />
                          {weightGoal && (
                            <ReferenceLine y={weightGoal.goalWeight} stroke={C.green} strokeDasharray="6 4"
                              label={{ value: `Goal: ${weightGoal.goalWeight}`, fill: C.green, fontSize: 11 }} />
                          )}
                        </ComposedChart>
                      );
                    })()}
                  </ResponsiveContainer>
                )}
              </Card>

              {/* Weight stats */}
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Weight Stats</div>
                <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 12 }}>
                  {[
                    { label: "Current", value: latestWeight ? `${latestWeight}` : "—", unit: "lbs", color: C.text },
                    { label: "7-Day Avg", value: weekAvg("weight") || "—", unit: "lbs", color: C.cyan },
                    { label: "30-Day Change", value: (() => {
                      const w30 = weightData.slice(0, 1)[0]?.weight;
                      return w30 && latestWeight ? `${(latestWeight - w30) > 0 ? "+" : ""}${(latestWeight - w30).toFixed(1)}` : "—";
                    })(), unit: "lbs", color: C.amber },
                    { label: "Weekly Rate", value: (() => {
                      if (weightData.length < 7) return "—";
                      const w7 = weightData.slice(-8, -1)[0]?.weight;
                      return w7 && latestWeight ? `${(latestWeight - w7) > 0 ? "+" : ""}${(latestWeight - w7).toFixed(1)}` : "—";
                    })(), unit: "lbs/wk", color: C.green },
                  ].map(s => (
                    <div key={s.label} style={{ padding: 12, background: C.bg2, borderRadius: 8, textAlign: "center" }}>
                      <div style={{ fontSize: 20, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: s.color }}>{s.value}</div>
                      <div style={{ fontSize: 11, color: C.textMuted }}>{s.label} <span style={{ color: C.textMuted }}>{s.unit}</span></div>
                    </div>
                  ))}
                </div>
              </Card>

              {/* Body Composition from Garmin Scale */}
              {(() => {
                const compEntries = entries.filter(e => e.bodyFat != null || e.muscleMass != null).sort((a, b) => a.date.localeCompare(b.date));
                if (compEntries.length === 0) return (
                  <Card><EmptyState icon="⚖️" title="No body composition data" sub="Weigh in on your Garmin scale to see composition metrics" /></Card>
                );
                const latest = compEntries[compEntries.length - 1];
                const prev = compEntries.length > 1 ? compEntries[compEntries.length - 2] : null;
                const delta = (curr, old) => {
                  if (curr == null || old == null) return null;
                  const d = curr - old;
                  return `${d > 0 ? "+" : ""}${d.toFixed(1)}`;
                };
                const wKg = latest.weight ? (latest.weight * 0.453592) : null;
                const fatMassLbs = (latest.bodyFat != null && latest.weight) ? (latest.weight * latest.bodyFat / 100).toFixed(1) : null;
                const fatMassKg = fatMassLbs ? (fatMassLbs * 0.453592).toFixed(1) : null;
                const muscleKg = latest.muscleMass ? (latest.muscleMass * 0.453592).toFixed(1) : null;
                const boneKg = latest.boneMass ? (latest.boneMass * 0.453592).toFixed(1) : null;
                const compStats = [
                  { label: "Body Fat", value: latest.bodyFat != null ? latest.bodyFat.toFixed(1) : null, unit: "%", color: C.amber,
                    sub: fatMassLbs ? `${fatMassLbs} lbs / ${fatMassKg} kg` : null, delta: delta(latest.bodyFat, prev?.bodyFat) },
                  { label: "Muscle Mass", value: latest.muscleMass != null ? latest.muscleMass.toFixed(1) : null, unit: "lbs", color: C.cyan,
                    sub: muscleKg ? `${muscleKg} kg` : null, delta: delta(latest.muscleMass, prev?.muscleMass) },
                  { label: "Bone Mass", value: latest.boneMass != null ? latest.boneMass.toFixed(1) : null, unit: "lbs", color: C.purple,
                    sub: boneKg ? `${boneKg} kg` : null, delta: delta(latest.boneMass, prev?.boneMass) },
                  { label: "Body Water", value: latest.bodyWater != null ? latest.bodyWater.toFixed(1) : null, unit: "%", color: C.blue || "#60a5fa",
                    sub: wKg ? `~${(latest.bodyWater * wKg / 100).toFixed(1)} kg` : null, delta: delta(latest.bodyWater, prev?.bodyWater) },
                  { label: "BMI", value: latest.bmi != null ? latest.bmi.toFixed(1) : null, unit: "", color: C.text,
                    sub: latest.bmi < 18.5 ? "Underweight" : latest.bmi < 25 ? "Normal" : latest.bmi < 30 ? "Overweight" : "Obese",
                    delta: delta(latest.bmi, prev?.bmi) },
                ].filter(s => s.value != null);

                // Trend chart data
                const compChartData = compEntries.map(e => ({
                  date: new Date(e.date).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
                  bodyFat: e.bodyFat != null ? parseFloat(e.bodyFat.toFixed(1)) : null,
                  musclePct: (e.muscleMass != null && e.weight) ? parseFloat((e.muscleMass / e.weight * 100).toFixed(1)) : null,
                  bodyWater: e.bodyWater != null ? parseFloat(e.bodyWater.toFixed(1)) : null,
                }));

                return (<>
                  <Card>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>Body Composition</div>
                      <div style={{ fontSize: 10, color: C.textMuted }}>Garmin Scale · {latest.date}</div>
                    </div>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(130px, 1fr))", gap: 12 }}>
                      {compStats.map(s => (
                        <div key={s.label} style={{ padding: 12, background: C.bg2, borderRadius: 8, textAlign: "center" }}>
                          <div style={{ fontSize: 22, fontWeight: 800, fontFamily: "'Space Grotesk', sans-serif", color: s.color }}>
                            {s.value}<span style={{ fontSize: 12, fontWeight: 400, color: C.textMuted }}> {s.unit}</span>
                          </div>
                          <div style={{ fontSize: 11, color: C.textMuted, marginTop: 2 }}>{s.label}</div>
                          {s.sub && <div style={{ fontSize: 10, color: C.textMuted, marginTop: 2 }}>{s.sub}</div>}
                          {s.delta && <div style={{ fontSize: 10, marginTop: 2, color: s.delta.startsWith("+") ? C.green : s.delta.startsWith("-") ? C.red : C.textMuted }}>{s.delta} vs prev</div>}
                        </div>
                      ))}
                    </div>
                  </Card>

                  {compChartData.length >= 3 && (
                    <Card>
                      <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Composition Trends</div>
                      <ResponsiveContainer width="100%" height={220}>
                        <ComposedChart data={compChartData}>
                          <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                          <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false}
                            interval={Math.max(1, Math.floor(compChartData.length / 8))} />
                          <YAxis tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} domain={["dataMin - 1", "dataMax + 1"]} tickFormatter={v => `${v}%`} />
                          <Tooltip contentStyle={{ background: C.bg2, border: `1px solid ${C.border}`, borderRadius: 8, fontSize: 11, color: C.text }} formatter={v => `${v}%`} />
                          <Legend wrapperStyle={{ fontSize: 11, color: C.textMuted }} />
                          <Line type="monotone" dataKey="bodyFat" stroke={C.amber} strokeWidth={2} dot={{ r: 2.5 }} name="Body Fat %" connectNulls />
                          <Line type="monotone" dataKey="musclePct" stroke={C.cyan} strokeWidth={2} dot={{ r: 2.5 }} name="Muscle Mass %" connectNulls />
                          {compChartData.some(d => d.bodyWater != null) && (
                            <Line type="monotone" dataKey="bodyWater" stroke={C.blue || "#60a5fa"} strokeWidth={2} dot={{ r: 2.5 }} name="Body Water %" connectNulls />
                          )}
                        </ComposedChart>
                      </ResponsiveContainer>
                    </Card>
                  )}
                </>);
              })()}
            </div>
          )}

          {/* ═══════════════════════ NUTRITION TAB ═══════════════════════ */}
          {tab === "Nutrition" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              {/* Macro Targets + Progress */}
              <Card>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>Today's Macros</div>
                  <div style={{ display: "flex", gap: 8 }}>
                    {!editingMacros ? (
                      <Btn onClick={() => setEditingMacros(true)} variant="secondary" small>
                        {nutritionData.calories ? "Edit" : "Log Macros"}
                      </Btn>
                    ) : (
                      <div style={{ display: "flex", gap: 8 }}>
                        <Btn onClick={saveMacros} small>Save</Btn>
                        <Btn onClick={() => setEditingMacros(false)} variant="ghost" small>Cancel</Btn>
                      </div>
                    )}
                    <Btn onClick={() => setEditingTargets(!editingTargets)} variant="ghost" small>Targets</Btn>
                  </div>
                </div>

                {editingTargets && (
                  <div style={{ marginBottom: 16, padding: 12, background: C.bg2, borderRadius: 8 }}>
                    <div style={{ fontSize: 11, color: C.textMuted, marginBottom: 8 }}>Daily Macro Targets</div>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 8 }}>
                      {["calories", "protein", "carbs", "fat", "fiber"].map(k => (
                        <div key={k}>
                          <div style={{ fontSize: 10, color: macroColors[k], marginBottom: 2, textTransform: "capitalize" }}>{k}</div>
                          <input type="number" value={macroTargets[k]}
                            onChange={e => updateMacroTargets({ ...macroTargets, [k]: parseInt(e.target.value) || 0 })}
                            style={{ ...inputStyle, fontSize: 12, padding: "4px 6px" }} />
                        </div>
                      ))}
                    </div>
                    <Btn onClick={saveMacroTargets} small style={{ marginTop: 8 }}>Save Targets</Btn>
                  </div>
                )}

                {editingMacros ? (
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 12 }}>
                    {[
                      { key: "calories", label: "Calories", unit: "kcal" },
                      { key: "protein", label: "Protein", unit: "g" },
                      { key: "carbs", label: "Carbs", unit: "g" },
                      { key: "fat", label: "Fat", unit: "g" },
                      { key: "fiber", label: "Fiber", unit: "g" },
                    ].map(m => (
                      <div key={m.key}>
                        <div style={{ fontSize: 11, color: macroColors[m.key], marginBottom: 4 }}>{m.label}</div>
                        <input type="number" placeholder={m.unit} value={macroForm[m.key]}
                          onChange={e => setMacroForm({ ...macroForm, [m.key]: e.target.value })}
                          style={inputStyle} />
                      </div>
                    ))}
                  </div>
                ) : (
                  <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                    {[
                      { key: "calories", label: "Calories", value: nutritionData.calories || 0, target: macroTargets.calories, unit: "kcal", color: C.pink },
                      { key: "protein", label: "Protein", value: nutritionData.protein || 0, target: macroTargets.protein, unit: "g", color: C.purple },
                      { key: "carbs", label: "Carbs", value: nutritionData.carbs || 0, target: macroTargets.carbs, unit: "g", color: C.amber },
                      { key: "fat", label: "Fat", value: nutritionData.fat || 0, target: macroTargets.fat, unit: "g", color: C.cyan },
                      { key: "fiber", label: "Fiber", value: nutritionData.fiber || 0, target: macroTargets.fiber, unit: "g", color: C.green },
                    ].map(m => {
                      const over = m.target > 0 && m.value > m.target;
                      const pct = m.target > 0 ? Math.min(100, Math.round((m.value / m.target) * 100)) : 0;
                      const barColor = over ? C.red : m.color;
                      return (
                        <div key={m.key}>
                          <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                            <span style={{ fontSize: 12, color: C.textDim }}>{m.label}</span>
                            <span style={{ fontSize: 12, color: over ? C.red : m.color }}>
                              {m.value} / {m.target} {m.unit}{over ? " ▲" : ""}
                            </span>
                          </div>
                          <div style={{ background: C.bg3, borderRadius: 4, height: 8, overflow: "hidden" }}>
                            <div style={{ width: `${pct}%`, height: "100%", background: barColor, borderRadius: 4, transition: "width 0.5s" }} />
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </Card>

              {/* Food Log */}
              <Card>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>Food Log</div>
                  <Btn onClick={() => setAddingMeal(!addingMeal)} variant="secondary" small>
                    {addingMeal ? "Cancel" : "+ Add Meal"}
                  </Btn>
                </div>
                {addingMeal && (
                  <div style={{ marginBottom: 16, padding: 12, background: C.bg2, borderRadius: 8 }}>
                    <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 8, marginBottom: 8 }}>
                      <div>
                        <div style={{ fontSize: 10, color: C.textMuted, marginBottom: 2 }}>Meal</div>
                        <select value={mealForm.name} onChange={e => setMealForm({ ...mealForm, name: e.target.value })}
                          style={{ ...inputStyle, fontSize: 12, padding: "4px 6px" }}>
                          {["Breakfast", "Lunch", "Dinner", "Snack", "Pre-Run", "Post-Run"].map(m => (
                            <option key={m} value={m}>{m}</option>
                          ))}
                        </select>
                      </div>
                      <div>
                        <div style={{ fontSize: 10, color: C.textMuted, marginBottom: 2 }}>Description</div>
                        <input placeholder="e.g. Oatmeal with berries" value={mealForm.description}
                          onChange={e => setMealForm({ ...mealForm, description: e.target.value })}
                          style={{ ...inputStyle, fontSize: 12, padding: "4px 6px" }} />
                      </div>
                    </div>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 8, marginBottom: 8 }}>
                      {["calories", "protein", "carbs", "fat"].map(k => (
                        <div key={k}>
                          <div style={{ fontSize: 10, color: macroColors[k] || C.textMuted, marginBottom: 2, textTransform: "capitalize" }}>{k}</div>
                          <input type="number" placeholder="0" value={mealForm[k]}
                            onChange={e => setMealForm({ ...mealForm, [k]: e.target.value })}
                            style={{ ...inputStyle, fontSize: 12, padding: "4px 6px" }} />
                        </div>
                      ))}
                    </div>
                    <Btn onClick={addMeal} small>Add</Btn>
                  </div>
                )}
                {(nutritionData.meals || []).length > 0 ? (
                  <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                    {nutritionData.meals.map((m, i) => (
                      <div key={i} style={{ padding: "10px 14px", background: C.bg2, borderRadius: 8, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                        <div>
                          <div style={{ fontSize: 12, fontWeight: 700, color: C.text }}>{m.name}</div>
                          <div style={{ fontSize: 11, color: C.textMuted }}>{m.description}</div>
                          <div style={{ fontSize: 10, color: C.textMuted, marginTop: 2 }}>{m.time}</div>
                        </div>
                        <div style={{ textAlign: "right", fontSize: 11 }}>
                          <div style={{ color: C.pink, fontWeight: 600 }}>{m.calories} kcal</div>
                          <div style={{ color: C.textMuted }}>P:{m.protein}g C:{m.carbs}g F:{m.fat}g</div>
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div style={{ fontSize: 12, color: C.textMuted }}>No meals logged today. Add individual meals or enter daily totals above.</div>
                )}
              </Card>

              {/* Hunger Log */}
              <Card>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>Hunger Log</div>
                  <Btn onClick={() => setLoggingHunger(!loggingHunger)} variant="secondary" small>
                    {loggingHunger ? "Cancel" : "+ Log Hunger"}
                  </Btn>
                </div>
                {loggingHunger && (
                  <div style={{ marginBottom: 16, padding: 12, background: C.bg2, borderRadius: 8 }}>
                    <div style={{ fontSize: 11, color: C.textMuted, marginBottom: 8 }}>How hungry are you? (1=satisfied, 5=ravenous)</div>
                    <div style={{ display: "flex", gap: 8, marginBottom: 8 }}>
                      {[1,2,3,4,5].map(l => (
                        <button key={l} onClick={() => setHungerForm({ ...hungerForm, level: l })}
                          style={{
                            flex: 1, padding: "8px 0", borderRadius: 8, cursor: "pointer",
                            border: hungerForm.level === l ? `2px solid ${hungerColor(l)}` : `1px solid ${C.border}`,
                            background: hungerForm.level === l ? hungerColor(l) + "20" : C.bg3,
                            color: hungerColor(l), fontSize: 14, fontWeight: 700,
                          }}>
                          {l} {["", "😊", "🙂", "😐", "😋", "🤤"][l]}
                        </button>
                      ))}
                    </div>
                    <input placeholder="Note (optional, e.g. 'post-run', 'mid-afternoon')" value={hungerForm.note}
                      onChange={e => setHungerForm({ ...hungerForm, note: e.target.value })}
                      style={{ ...inputStyle, marginBottom: 8 }} />
                    <Btn onClick={logHunger} small>Log Hunger</Btn>
                  </div>
                )}
                {hungerEntries.length > 0 ? (
                  <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                    {hungerEntries.map((h, i) => (
                      <div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "8px 12px", background: C.bg2, borderRadius: 8 }}>
                        <div style={{
                          width: 32, height: 32, borderRadius: "50%", background: hungerColor(h.level) + "20",
                          border: `2px solid ${hungerColor(h.level)}`, display: "flex", alignItems: "center", justifyContent: "center",
                          fontSize: 14, fontWeight: 700, color: hungerColor(h.level),
                        }}>{h.level}</div>
                        <div>
                          <div style={{ fontSize: 12, color: C.text, fontWeight: 600 }}>{h.time}</div>
                          {h.note && <div style={{ fontSize: 11, color: C.textMuted }}>{h.note}</div>}
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div style={{ fontSize: 12, color: C.textMuted }}>No hunger entries today. Track hunger levels to optimize your nutrition timing.</div>
                )}
              </Card>

              {/* Macro Trends */}
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Macro Trends — Last 30 Days</div>
                {nutritionHistory.length < 3 ? (
                  <EmptyState icon="📊" title="Not enough nutrition data" sub="Log macros for at least 3 days to see trends" />
                ) : (
                  <ResponsiveContainer width="100%" height={240}>
                    <ComposedChart data={nutritionHistory.map(n => ({
                      date: new Date(n.date).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
                      calories: (n.calories > 0 && n.calories < 6000) ? n.calories : null,
                      protein: (n.protein > 0 && n.protein < 400) ? n.protein : null,
                      carbs: (n.carbs > 0 && n.carbs < 700) ? n.carbs : null,
                      fat: (n.fat > 0 && n.fat < 250) ? n.fat : null,
                    }))}>
                      <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                      <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false}
                        interval={Math.max(1, Math.floor(nutritionHistory.length / 8))} />
                      <YAxis yAxisId="cal" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} />
                      <YAxis yAxisId="macro" orientation="right" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} />
                      <Tooltip content={<ChartTooltip />} />
                      <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                      <Bar yAxisId="cal" dataKey="calories" fill={C.pink} fillOpacity={0.3} name="Calories" barSize={8} />
                      <Line yAxisId="macro" type="monotone" dataKey="protein" stroke={C.purple} strokeWidth={2} dot={false} name="Protein (g)" connectNulls />
                      <Line yAxisId="macro" type="monotone" dataKey="carbs" stroke={C.amber} strokeWidth={2} dot={false} name="Carbs (g)" connectNulls />
                    </ComposedChart>
                  </ResponsiveContainer>
                )}
              </Card>

              {/* Pre/Post Run Fueling (migrated) */}
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.green, marginBottom: 16 }}>Pre-Run Fueling</div>
                <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                  {[
                    { time: "2-3 hrs before", rec: "Full meal: oats, banana, toast with nut butter. 60-90g carbs, moderate protein, low fat.", color: C.cyan },
                    { time: "30-60 min before", rec: "Light snack: banana, energy bar, or toast. 30-40g simple carbs. Avoid high fiber/fat.", color: C.amber },
                    { time: "0-15 min before", rec: "Optional: energy gel or 100-200ml sports drink if run > 60 min.", color: C.green },
                  ].map(item => (
                    <div key={item.time} style={{ padding: "12px 16px", background: C.bg2, borderRadius: 8, borderLeft: `3px solid ${item.color}` }}>
                      <div style={{ fontSize: 11, color: item.color, marginBottom: 4, fontWeight: 600 }}>{item.time}</div>
                      <div style={{ fontSize: 12, color: C.textDim, lineHeight: 1.6 }}>{item.rec}</div>
                    </div>
                  ))}
                </div>
              </Card>

              {/* Supplements (migrated) */}
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Supplement Stack</div>
                {supplements.length === 0 ? (
                  <div style={{ fontSize: 12, color: C.textMuted }}>No supplements added yet. Go to Nutrition → Supplements to add.</div>
                ) : (
                  <div>
                    {["AM", "PM"].map(group => {
                      const items = supplements.filter(s => (s.timing || "AM") === group);
                      if (items.length === 0) return null;
                      return (
                        <div key={group} style={{ marginBottom: 12 }}>
                          <div style={{ fontSize: 10, fontWeight: 700, color: group === "AM" ? C.amber : C.purple,
                            textTransform: "uppercase", letterSpacing: 1, marginBottom: 6 }}>{group}</div>
                          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                            {items.map((s, i) => (
                              <div key={i} style={{ padding: "6px 10px", background: C.bg2, borderRadius: 6, fontSize: 12 }}>
                                <span style={{ color: C.text, fontWeight: 600 }}>{s.name}</span>
                                <span style={{ color: C.textMuted }}> ×{s.pills || 1}</span>
                                {s.dose && <span style={{ color: C.textMuted, fontSize: 10 }}> ({s.dose})</span>}
                              </div>
                            ))}
                          </div>
                        </div>
                      );
                    })}
                    {(() => {
                      const other = supplements.filter(s => s.timing !== "AM" && s.timing !== "PM");
                      if (other.length === 0) return null;
                      return (
                        <div>
                          <div style={{ fontSize: 10, fontWeight: 700, color: C.cyan, textTransform: "uppercase", letterSpacing: 1, marginBottom: 6 }}>Other</div>
                          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                            {other.map((s, i) => (
                              <div key={i} style={{ padding: "6px 10px", background: C.bg2, borderRadius: 6, fontSize: 12 }}>
                                <span style={{ color: C.text, fontWeight: 600 }}>{s.name}</span>
                                <span style={{ color: C.textMuted }}> ×{s.pills || 1} · {s.timing}</span>
                              </div>
                            ))}
                          </div>
                        </div>
                      );
                    })()}
                    <div style={{ marginTop: 10, fontSize: 11, color: C.textMuted }}>
                      {supplements.reduce((s, x) => s + (parseInt(x.pills) || 1), 0)} pills/day
                    </div>
                  </div>
                )}
              </Card>
            </div>
          )}

          {/* ═══════════════════════ TRENDS TAB ═══════════════════════ */}
          {tab === "Trends" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>HRV & Resting HR — Last 90 Days</div>
                {trendData.filter(d => d.hrv != null).length < 3 ? (
                  <EmptyState icon="💓" title="Not enough data" sub="Log at least 3 days of HRV data to see trends" />
                ) : (
                  <ResponsiveContainer width="100%" height={220}>
                    {(() => { const cd = withTrend(windowChartData(trimChartData(['hrv','restingHR']), 90), ['hrv','restingHR']); return (
                    <ComposedChart data={cd}>
                      <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                      <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} interval={Math.max(1, Math.floor(cd.length / 8))} />
                      <YAxis yAxisId="hrv" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} />
                      <YAxis yAxisId="hr" orientation="right" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} />
                      <Tooltip content={<ChartTooltip formatter={(v, n) => n === "hrv" ? `${v} ms` : `${v} bpm`} />} />
                      <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                      <Area yAxisId="hrv" type="monotone" dataKey="hrv" stroke={C.cyan} fill={C.cyan + "20"} strokeWidth={2} name="HRV" connectNulls />
                      <Line yAxisId="hr" type="monotone" dataKey="restingHR" stroke={C.pink} strokeWidth={2} dot={false} name="Resting HR" connectNulls />
                      <Line yAxisId="hrv" type="linear" dataKey="hrvTrend" stroke={C.cyan} strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="HRV trend" isAnimationActive={false} />
                      <Line yAxisId="hr" type="linear" dataKey="restingHRTrend" stroke={C.pink} strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="Resting HR trend" isAnimationActive={false} />
                    </ComposedChart>
                    ); })()}
                  </ResponsiveContainer>
                )}
              </Card>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Body Battery & Stress</div>
                {trendData.filter(d => d.bodyBattery != null).length < 3 ? (
                  <EmptyState icon="🔋" title="Not enough data" sub="Log at least 3 days of Body Battery data" />
                ) : (
                  <ResponsiveContainer width="100%" height={220}>
                    {(() => {
                      // Null out forward-filled values so a gap appears instead of a flat line
                      const cd = withTrend(trimChartData(['bodyBattery','stress']).map(e => ({
                        ...e,
                        bodyBattery: e.bodyBattery_filled ? null : e.bodyBattery,
                        stress: e.stress_filled ? null : e.stress,
                      })), ['bodyBattery','stress']);
                      return (
                    <ComposedChart data={cd}>
                      <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                      <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} interval={Math.max(1, Math.floor(cd.length / 8))} />
                      <YAxis tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[0, 100]} />
                      <Tooltip content={<ChartTooltip />} />
                      <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                      <Area type="monotone" dataKey="bodyBattery" stroke={C.green} fill={C.green + "20"} strokeWidth={2} name="Body Battery" connectNulls={false} />
                      <Line type="monotone" dataKey="stress" stroke={C.amber} strokeWidth={2} dot={false} name="Stress" connectNulls={false} />
                      <Line type="linear" dataKey="bodyBatteryTrend" stroke={C.green} strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="Body Battery trend" isAnimationActive={false} />
                      <Line type="linear" dataKey="stressTrend" stroke={C.amber} strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="Stress trend" isAnimationActive={false} />
                    </ComposedChart>
                      );
                    })()}
                  </ResponsiveContainer>
                )}
              </Card>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Sleep Score & Duration</div>
                {trendData.filter(d => d.sleepScore != null || d.sleepHours != null).length < 3 ? (
                  <EmptyState icon="😴" title="Not enough data" sub="Log at least 3 days of sleep data" />
                ) : (
                  <ResponsiveContainer width="100%" height={220}>
                    {(() => { const cd = withTrend(trimChartData(['sleepScore','sleepHours']), ['sleepScore','sleepHours']); return (
                    <ComposedChart data={cd}>
                      <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                      <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} interval={Math.max(1, Math.floor(cd.length / 8))} />
                      <YAxis yAxisId="score" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[0, 100]} />
                      <YAxis yAxisId="hours" orientation="right" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[4, 10]} />
                      <Tooltip content={<ChartTooltip formatter={(v, n) => n === "sleepHours" ? `${v} hrs` : v} />} />
                      <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                      <Line yAxisId="score" type="monotone" dataKey="sleepScore" stroke={C.purple} strokeWidth={2} dot={false} name="Sleep Score" connectNulls />
                      <Bar yAxisId="hours" dataKey="sleepHours" fill={C.purple} fillOpacity={0.3} name="Sleep Hours" barSize={8} />
                      <Line yAxisId="score" type="linear" dataKey="sleepScoreTrend" stroke={C.purple} strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="Sleep Score trend" isAnimationActive={false} />
                      <Line yAxisId="hours" type="linear" dataKey="sleepHoursTrend" stroke="#c4b5fd" strokeWidth={1.5} strokeDasharray="6 4" dot={false} activeDot={false} legendType="none" name="Sleep Hours trend" isAnimationActive={false} />
                    </ComposedChart>
                    ); })()}
                  </ResponsiveContainer>
                )}
              </Card>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Training Readiness & Weight</div>
                {(() => {
                  const hasData = trendData.filter(d => d.trainingReadiness != null || d.weight != null).length >= 3;
                  if (!hasData) return <EmptyState icon="🏋️" title="Not enough data" sub="Log at least 3 days of data" />;
                  // Build chart data with 7-day weight MA and 4-week projection — floor at March 24 (weight tracking start)
                  const baseTrendData = trimWeightChart(['trainingReadiness','weight']);
                  const weightPts = baseTrendData.filter(d => d.weight != null);
                  const chartData = baseTrendData.map((d, i) => {
                    const window = baseTrendData.slice(Math.max(0, i - 6), i + 1).filter(x => x.weight != null);
                    const weightMA = window.length >= 2 ? parseFloat((window.reduce((s, w) => s + w.weight, 0) / window.length).toFixed(1)) : null;
                    return { ...d, weightMA };
                  });
                  // Add 4-week projection points
                  const lastWeight = weightPts.length > 0 ? weightPts[weightPts.length - 1].weight : null;
                  const weeklyRate = weightGoal?.weeklyRate || 0;
                  const projData = [];
                  if (lastWeight && weeklyRate > 0) {
                    for (let w = 1; w <= 4; w++) {
                      const projDate = new Date(); projDate.setDate(projDate.getDate() + w * 7);
                      projData.push({
                        date: projDate.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
                        projectedWeight: parseFloat((lastWeight - weeklyRate * w).toFixed(1)),
                      });
                    }
                  }
                  const fullData = [...chartData, ...projData];
                  return (
                    <ResponsiveContainer width="100%" height={250}>
                      <ComposedChart data={fullData}>
                        <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                        <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} interval={Math.max(1, Math.floor(fullData.length / 8))} />
                        <YAxis yAxisId="readiness" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[0, 100]} />
                        <YAxis yAxisId="weight" orientation="right" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[160, 200]} allowDataOverflow />
                        <Tooltip content={<ChartTooltip formatter={(v, n) => n.includes("eight") ? `${v} lbs` : v} />} />
                        <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                        <Area yAxisId="readiness" type="monotone" dataKey="trainingReadiness" stroke={C.green} fill={C.green + "20"} strokeWidth={2} name="Training Readiness" connectNulls />
                        <Line yAxisId="weight" type="monotone" dataKey="weight" stroke={C.textDim} strokeWidth={2} dot={{ fill: C.textDim, r: 2 }} name="Weight" connectNulls />
                        <Line yAxisId="weight" type="monotone" dataKey="weightMA" stroke={C.cyan} strokeWidth={2} dot={false} name="7-Day Avg" connectNulls />
                        <Line yAxisId="weight" type="monotone" dataKey="projectedWeight" stroke={C.cyan} strokeWidth={2} strokeDasharray="6 4" dot={{ fill: C.cyan, r: 3, strokeDasharray: "0" }} name="Projected" connectNulls />
                        {weightGoal?.goalWeight && (
                          <ReferenceLine yAxisId="weight" y={weightGoal.goalWeight} stroke={C.green} strokeDasharray="4 4" label={{ value: `Goal: ${weightGoal.goalWeight}`, fill: C.green, fontSize: 10, position: "right" }} />
                        )}
                      </ComposedChart>
                    </ResponsiveContainer>
                  );
                })()}
              </Card>
            </div>
          )}

          {/* ═══════════════════════ RECOVERY TAB ═══════════════════════ */}
          {tab === "Recovery" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Recovery Score Trend</div>
                {(() => {
                  const recoveryTrend = trendData.map(d => {
                    const comps = [];
                    if (d.hrv != null) comps.push(Math.min(100, (d.hrv / 80) * 100));
                    if (d.bodyBattery != null) comps.push(d.bodyBattery);
                    if (d.sleepScore != null) comps.push(d.sleepScore);
                    if (d.stress != null) comps.push(100 - d.stress);
                    if (d.trainingReadiness != null) comps.push(d.trainingReadiness);
                    return { ...d, recovery: comps.length ? Math.round(comps.reduce((s, v) => s + v, 0) / comps.length) : null };
                  }).filter(d => d.recovery != null);
                  return recoveryTrend.length < 3 ? (
                    <EmptyState icon="📈" title="Not enough data" sub="Log health metrics for at least 3 days" />
                  ) : (
                    <ResponsiveContainer width="100%" height={240}>
                      <AreaChart data={recoveryTrend}>
                        <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                        <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} interval={Math.max(1, Math.floor(recoveryTrend.length / 8))} />
                        <YAxis tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[0, 100]} />
                        <Tooltip content={<ChartTooltip formatter={(v) => `${v}/100`} />} />
                        <defs>
                          <linearGradient id="recoveryGrad" x1="0" y1="0" x2="0" y2="1">
                            <stop offset="5%" stopColor={C.green} stopOpacity={0.3} />
                            <stop offset="95%" stopColor={C.green} stopOpacity={0} />
                          </linearGradient>
                        </defs>
                        <Area type="monotone" dataKey="recovery" stroke={C.green} fill="url(#recoveryGrad)" strokeWidth={2} name="Recovery" />
                        <ReferenceLine y={75} stroke={C.green + "40"} strokeDasharray="4 4" label={{ value: "Excellent", fill: C.green, fontSize: 10 }} />
                        <ReferenceLine y={55} stroke={C.cyan + "40"} strokeDasharray="4 4" label={{ value: "Good", fill: C.cyan, fontSize: 10 }} />
                        <ReferenceLine y={35} stroke={C.amber + "40"} strokeDasharray="4 4" label={{ value: "Fair", fill: C.amber, fontSize: 10 }} />
                      </AreaChart>
                    </ResponsiveContainer>
                  );
                })()}
              </Card>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Recovery Factor Breakdown</div>
                <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                  {[
                    { label: "HRV Status", key: "hrv", baseline: 80, unit: "ms", color: C.cyan, desc: "Higher = better parasympathetic recovery" },
                    { label: "Body Battery", key: "bodyBattery", baseline: 100, unit: "%", color: C.green, desc: "Energy reserve from Garmin's algorithm" },
                    { label: "Sleep Quality", key: "sleepScore", baseline: 100, unit: "/100", color: C.purple, desc: "Composite of deep, REM, and total sleep" },
                    { label: "Stress (inverted)", key: "stress", baseline: 100, unit: "", color: C.amber, desc: "Lower stress = better recovery", invert: true },
                    { label: "Training Readiness", key: "trainingReadiness", baseline: 100, unit: "/100", color: C.green, desc: "Garmin's readiness assessment" },
                  ].map(f => {
                    // Fall back to yesterday's value if today's hasn't synced yet
                    const yesterdayEntry = entries[entries.length - 2] || null;
                    const val = todayEntry?.[f.key];
                    const fallbackVal = val == null ? yesterdayEntry?.[f.key] : null;
                    const activeVal = val ?? fallbackVal;
                    const isYesterday = val == null && fallbackVal != null;
                    const displayVal = activeVal != null ? (f.invert ? 100 - activeVal : activeVal) : null;
                    const pct = displayVal != null ? Math.min(100, Math.round((displayVal / f.baseline) * 100)) : 0;
                    return (
                      <div key={f.key}>
                        <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                          <div>
                            <span style={{ fontSize: 12, color: C.textDim }}>{f.label}</span>
                            <span style={{ fontSize: 11, color: C.textMuted, marginLeft: 8 }}>{f.desc}</span>
                            {isYesterday && <span style={{ fontSize: 10, color: C.textMuted, marginLeft: 6, fontStyle: "italic" }}>yesterday</span>}
                          </div>
                          <span style={{ fontSize: 13, fontWeight: 700, color: isYesterday ? C.textMuted : f.color }}>
                            {activeVal != null ? `${Math.round(activeVal)}${f.unit}` : "--"}
                          </span>
                        </div>
                        <div style={{ background: C.bg3, borderRadius: 4, height: 8, overflow: "hidden" }}>
                          <div style={{ width: `${pct}%`, height: "100%", background: isYesterday ? C.textMuted : f.color, borderRadius: 4, transition: "width 0.5s", opacity: isYesterday ? 0.5 : 1 }} />
                        </div>
                      </div>
                    );
                  })}
                </div>
              </Card>
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Recovery Guidelines</div>
                <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                  {[
                    { score: "75-100", label: "Excellent", color: C.green, tip: "Green light for hard workouts, intervals, or long runs. Your body is fully recovered." },
                    { score: "55-74", label: "Good", color: C.cyan, tip: "Normal training is fine. Moderate effort — tempo runs, steady state." },
                    { score: "35-54", label: "Fair", color: C.amber, tip: "Consider an easy day or active recovery. Avoid high-intensity work." },
                    { score: "0-34", label: "Low", color: C.red, tip: "Rest day recommended. Focus on sleep, hydration, and nutrition. Listen to your body." },
                  ].map(g => (
                    <div key={g.label} style={{ padding: "12px 16px", background: C.bg2, borderRadius: 8, borderLeft: `3px solid ${g.color}` }}>
                      <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 4 }}>
                        <Badge label={g.score} color={g.color} />
                        <span style={{ fontSize: 12, fontWeight: 700, color: g.color }}>{g.label}</span>
                      </div>
                      <div style={{ fontSize: 12, color: C.textDim, lineHeight: 1.6 }}>{g.tip}</div>
                    </div>
                  ))}
                </div>
              </Card>
            </div>
          )}

          {/* ═══════════════════════ AI COACH TAB ═══════════════════════ */}
          {tab === "AI Coach" && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              {/* Generate coaching */}
              <Card style={{ borderColor: C.purple + "40" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>AI Weight & Nutrition Coach</div>
                    <div style={{ fontSize: 11, color: C.textMuted, marginTop: 4 }}>Analyzes your weight trend, macros, hunger patterns & training load</div>
                  </div>
                  <Btn onClick={getCoaching} disabled={loadingCoaching} small>
                    {loadingCoaching ? "Analyzing..." : coaching ? "Refresh" : "Get Insights"}
                  </Btn>
                </div>

                {coaching && !coaching.error && (
                  <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
                    {/* Summary */}
                    <div style={{ padding: "14px 18px", background: C.bg2, borderRadius: 10, borderLeft: `3px solid ${C.purple}` }}>
                      <div style={{ fontSize: 13, color: C.text, lineHeight: 1.7 }}>{coaching.summary}</div>
                    </div>

                    {/* Weight Analysis */}
                    {coaching.weightAnalysis && (
                      <div>
                        <div style={{ fontSize: 12, fontWeight: 700, color: C.cyan, marginBottom: 8 }}>WEIGHT ANALYSIS</div>
                        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10 }}>
                          <div style={{ padding: 10, background: C.bg2, borderRadius: 8, textAlign: "center" }}>
                            <div style={{ fontSize: 16, fontWeight: 800, color: coaching.weightAnalysis.onTrack ? C.green : C.amber }}>
                              {coaching.weightAnalysis.trend}
                            </div>
                            <div style={{ fontSize: 10, color: C.textMuted }}>Trend</div>
                          </div>
                          <div style={{ padding: 10, background: C.bg2, borderRadius: 8, textAlign: "center" }}>
                            <div style={{ fontSize: 16, fontWeight: 800, color: C.text }}>
                              {coaching.weightAnalysis.actualWeeklyRate} lbs/wk
                            </div>
                            <div style={{ fontSize: 10, color: C.textMuted }}>Actual Rate</div>
                          </div>
                          <div style={{ padding: 10, background: C.bg2, borderRadius: 8, textAlign: "center" }}>
                            <div style={{ fontSize: 16, fontWeight: 800, color: coaching.weightAnalysis.onTrack ? C.green : C.amber }}>
                              {coaching.weightAnalysis.onTrack ? "On Track" : "Off Track"}
                            </div>
                            <div style={{ fontSize: 10, color: C.textMuted }}>Status</div>
                          </div>
                        </div>
                        {coaching.weightAnalysis.insight && (
                          <div style={{ fontSize: 12, color: C.textDim, marginTop: 8, lineHeight: 1.6 }}>{coaching.weightAnalysis.insight}</div>
                        )}
                      </div>
                    )}

                    {/* Nutrition Adjustments */}
                    {coaching.nutritionAdjustments && coaching.nutritionAdjustments.length > 0 && (
                      <div>
                        <div style={{ fontSize: 12, fontWeight: 700, color: C.amber, marginBottom: 8 }}>MACRO ADJUSTMENTS</div>
                        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                          {coaching.nutritionAdjustments.map((adj, i) => (
                            <div key={i} style={{ padding: "10px 14px", background: C.bg2, borderRadius: 8, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                              <div>
                                <div style={{ fontSize: 12, fontWeight: 600, color: macroColors[adj.macro] || C.text, textTransform: "capitalize" }}>{adj.macro}</div>
                                <div style={{ fontSize: 11, color: C.textMuted }}>{adj.reason}</div>
                              </div>
                              <div style={{ textAlign: "right" }}>
                                <div style={{ fontSize: 11, color: C.textMuted }}>{adj.currentAvg} → <span style={{ color: C.green, fontWeight: 700 }}>{adj.suggested}</span> {adj.unit}</div>
                              </div>
                            </div>
                          ))}
                        </div>
                      </div>
                    )}

                    {/* Hunger Insights */}
                    {coaching.hungerInsights && (
                      <div>
                        <div style={{ fontSize: 12, fontWeight: 700, color: "#f97316", marginBottom: 8 }}>HUNGER INSIGHTS</div>
                        <div style={{ padding: "12px 16px", background: C.bg2, borderRadius: 8, fontSize: 12, color: C.textDim, lineHeight: 1.7 }}>
                          {coaching.hungerInsights}
                        </div>
                      </div>
                    )}

                    {/* Action Items */}
                    {coaching.actionItems && coaching.actionItems.length > 0 && (
                      <div>
                        <div style={{ fontSize: 12, fontWeight: 700, color: C.green, marginBottom: 8 }}>ACTION ITEMS</div>
                        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                          {coaching.actionItems.map((item, i) => (
                            <div key={i} style={{ padding: "10px 14px", background: C.bg2, borderRadius: 8, borderLeft: `3px solid ${C.green}`, fontSize: 12, color: C.textDim, lineHeight: 1.6 }}>
                              {item}
                            </div>
                          ))}
                        </div>
                      </div>
                    )}

                    {/* Meal Timing */}
                    {coaching.mealTiming && (
                      <div style={{ padding: "12px 16px", background: C.bg2, borderRadius: 8 }}>
                        <div style={{ fontSize: 12, fontWeight: 700, color: C.cyan, marginBottom: 4 }}>MEAL TIMING</div>
                        <div style={{ fontSize: 12, color: C.textDim, lineHeight: 1.7 }}>{coaching.mealTiming}</div>
                      </div>
                    )}
                  </div>
                )}

                {coaching && coaching.error && (
                  <div style={{ color: C.red, fontSize: 13 }}>{coaching.error}</div>
                )}

                {!coaching && !loadingCoaching && (
                  <div style={{ fontSize: 12, color: C.textMuted }}>
                    Get personalized AI coaching based on your weight trend, macro intake, hunger patterns, and training load. Log a few days of data first for best results.
                  </div>
                )}
              </Card>

              {/* Hunger-Macro Correlation */}
              <Card>
                <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim, marginBottom: 16 }}>Hunger vs. Nutrition — Last 14 Days</div>
                {hungerMacroCorrelation.length < 3 ? (
                  <EmptyState icon="📉" title="Not enough data" sub="Log both hunger and nutrition for at least 3 days to see correlations" />
                ) : (
                  <ResponsiveContainer width="100%" height={220}>
                    <ComposedChart data={hungerMacroCorrelation}>
                      <CartesianGrid strokeDasharray="3 3" stroke={C.border} vertical={false} />
                      <XAxis dataKey="date" tick={{ fill: C.textMuted, fontSize: 10 }} axisLine={false} tickLine={false} />
                      <YAxis yAxisId="hunger" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} domain={[1, 5]} />
                      <YAxis yAxisId="cal" orientation="right" tick={{ fill: C.textMuted, fontSize: 11 }} axisLine={false} tickLine={false} />
                      <Tooltip content={<ChartTooltip />} />
                      <Legend wrapperStyle={{ fontSize: 12, color: C.textMuted }} />
                      <Bar yAxisId="cal" dataKey="calories" fill={C.pink} fillOpacity={0.3} name="Calories" barSize={10} />
                      <Line yAxisId="hunger" type="monotone" dataKey="avgHunger" stroke="#f97316" strokeWidth={2.5} dot={{ fill: "#f97316", r: 3 }} name="Avg Hunger" />
                      <Line yAxisId="cal" type="monotone" dataKey="protein" stroke={C.purple} strokeWidth={2} dot={false} name="Protein (g)" />
                    </ComposedChart>
                  </ResponsiveContainer>
                )}
                <div style={{ fontSize: 11, color: C.textMuted, marginTop: 8 }}>
                  Higher protein and calorie intake typically correlates with lower hunger. If hunger stays high (4-5), consider increasing protein or fiber.
                </div>
              </Card>

              {/* AI Nutrition Plan (migrated) */}
              <Card>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>AI Meal Plan</div>
                  <Btn onClick={getTodaysPlan} disabled={loadingPlan} small>
                    {loadingPlan ? "Generating..." : plan ? "Refresh" : "Generate Plan"}
                  </Btn>
                </div>
                {plan ? (
                  plan.error ? <div style={{ color: C.red, fontSize: 13 }}>{plan.error}</div> : (
                    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                      {plan.summary && <div style={{ fontSize: 13, color: C.text, lineHeight: 1.6 }}>{plan.summary}</div>}
                      {plan.targets && (
                        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10 }}>
                          {Object.entries(plan.targets).map(([k, v]) => (
                            <div key={k} style={{ textAlign: "center", padding: 10, background: C.bg2, borderRadius: 8 }}>
                              <div style={{ fontSize: 16, fontWeight: 700, color: macroColors[k] || C.cyan }}>{v}</div>
                              <div style={{ fontSize: 11, color: C.textMuted, textTransform: "capitalize" }}>{k}</div>
                            </div>
                          ))}
                        </div>
                      )}
                      {plan.meals && plan.meals.map((m, i) => (
                        <div key={i} style={{ padding: "12px 16px", background: C.bg2, borderRadius: 8 }}>
                          <div style={{ fontSize: 12, fontWeight: 700, color: C.cyan, marginBottom: 4 }}>{m.name}</div>
                          <div style={{ fontSize: 12, color: C.textDim, lineHeight: 1.6 }}>{m.description}</div>
                        </div>
                      ))}
                    </div>
                  )
                ) : (
                  <div style={{ color: C.textMuted, fontSize: 13 }}>Generate a personalized meal plan based on your training and goals.</div>
                )}
              </Card>

              {/* Daily Summary Email */}
              <Card style={{ borderColor: C.cyanMuted + "60" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600, color: C.textDim }}>✉️ Daily Summary Email</div>
                    <div style={{ fontSize: 11, color: C.textMuted, marginTop: 4 }}>
                      Coach briefing, today's workout & health metrics delivered every morning
                    </div>
                  </div>
                  <button onClick={() => setEmailEnabled(!emailEnabled)} style={{
                    width: 44, height: 24, borderRadius: 12, border: "none",
                    background: emailEnabled ? C.cyan : C.bg3,
                    cursor: "pointer", position: "relative", flexShrink: 0,
                  }}>
                    <div style={{
                      width: 18, height: 18, borderRadius: 9, background: "#fff",
                      position: "absolute", top: 3,
                      left: emailEnabled ? 23 : 3, transition: "left 0.2s",
                    }} />
                  </button>
                </div>

                {/* SMTP status banner */}
                {smtpChecking && (
                  <div style={{ padding: "10px 14px", background: C.bg3, border: `1px solid ${C.border}`, borderRadius: 8, marginBottom: 12, fontSize: 12, color: C.textMuted }}>
                    Checking SMTP status...
                  </div>
                )}
                {!smtpChecking && smtpStatus && smtpStatus.checkFailed && (
                  <div style={{ padding: "10px 14px", background: C.red + "15", border: `1px solid ${C.red}40`, borderRadius: 8, marginBottom: 12, fontSize: 12, color: C.red }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
                      <span>✗ SMTP status check failed: {smtpStatus.error}</span>
                      <button onClick={recheckSmtp} style={{ marginLeft: 8, fontSize: 10, padding: "2px 8px", borderRadius: 4, border: `1px solid ${C.red}60`, background: "transparent", color: C.red, cursor: "pointer", whiteSpace: "nowrap" }}>Recheck</button>
                    </div>
                    <div style={{ marginTop: 4, opacity: 0.8 }}>The <code>checkSmtpStatus</code> function may not be deployed. Check Firebase Functions in the console.</div>
                  </div>
                )}
                {!smtpChecking && smtpStatus && !smtpStatus.checkFailed && !smtpStatus.configured && (
                  <div style={{ padding: "10px 14px", background: C.amber + "15", border: `1px solid ${C.amber}40`, borderRadius: 8, marginBottom: 12, fontSize: 12, color: C.amber }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                      <span>⚠️ SMTP not configured — add <strong>SMTP_EMAIL</strong> and <strong>SMTP_APP_PASSWORD</strong> as GitHub Secrets, then redeploy.</span>
                      <button onClick={recheckSmtp} style={{ marginLeft: 8, fontSize: 10, padding: "2px 8px", borderRadius: 4, border: `1px solid ${C.amber}60`, background: "transparent", color: C.amber, cursor: "pointer", whiteSpace: "nowrap" }}>Recheck</button>
                    </div>
                  </div>
                )}
                {!smtpChecking && smtpStatus && smtpStatus.configured && smtpStatus.verified && (
                  <div style={{ padding: "10px 14px", background: C.green + "15", border: `1px solid ${C.green}40`, borderRadius: 8, marginBottom: 12, fontSize: 12, color: C.green }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                      <span>✓ SMTP verified — sending from {smtpStatus.emailHint}</span>
                      <button onClick={recheckSmtp} style={{ marginLeft: 8, fontSize: 10, padding: "2px 8px", borderRadius: 4, border: `1px solid ${C.green}60`, background: "transparent", color: C.green, cursor: "pointer", whiteSpace: "nowrap" }}>Recheck</button>
                    </div>
                  </div>
                )}
                {!smtpChecking && smtpStatus && smtpStatus.configured && !smtpStatus.verified && (
                  <div style={{ padding: "10px 14px", background: C.red + "15", border: `1px solid ${C.red}40`, borderRadius: 8, marginBottom: 12, fontSize: 12, color: C.red }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
                      <span>✗ SMTP credentials set but connection failed: {smtpStatus.error}</span>
                      <button onClick={recheckSmtp} style={{ marginLeft: 8, fontSize: 10, padding: "2px 8px", borderRadius: 4, border: `1px solid ${C.red}60`, background: "transparent", color: C.red, cursor: "pointer", whiteSpace: "nowrap" }}>Recheck</button>
                    </div>
                    <div style={{ marginTop: 4, opacity: 0.8 }}>For Gmail: use a 16-character App Password (not your regular password). Requires 2-Step Verification — generate one at myaccount.google.com/apppasswords.</div>
                  </div>
                )}

                <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                  <div>
                    <label style={{ fontSize: 12, color: C.textMuted, display: "block", marginBottom: 6 }}>Recipient Email</label>
                    <input type="email" value={emailAddr} onChange={e => setEmailAddr(e.target.value)}
                      placeholder="your@email.com"
                      style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: `1px solid ${C.border}`,
                        background: C.bg2, color: C.text, fontSize: 13, fontFamily: "'IBM Plex Mono',monospace",
                        outline: "none", boxSizing: "border-box" }} />
                  </div>

                  <div style={{ display: "flex", gap: 10, alignItems: "flex-end" }}>
                    <div style={{ flex: 1 }}>
                      <label style={{ fontSize: 12, color: C.textMuted, display: "block", marginBottom: 6 }}>Send Time (ET)</label>
                      <input type="time" value={emailTime} onChange={e => setEmailTime(e.target.value)}
                        style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: `1px solid ${C.border}`,
                          background: C.bg2, color: C.text, fontSize: 13, fontFamily: "'IBM Plex Mono',monospace",
                          outline: "none", boxSizing: "border-box" }} />
                    </div>
                    <button onClick={sendDailyTest} disabled={emailSending || !emailAddr} style={{
                      padding: "9px 14px", borderRadius: 8, border: "none",
                      background: emailAddr ? C.cyanMuted : C.bg3,
                      color: emailAddr ? "#fff" : C.textMuted,
                      fontSize: 11, fontWeight: 600, cursor: emailAddr ? "pointer" : "not-allowed",
                      fontFamily: "'IBM Plex Mono',monospace", whiteSpace: "nowrap",
                    }} title="Send a plain test email to verify SMTP works">{emailSending ? "..." : "SMTP Test"}</button>
                    <button onClick={sendDailySummary} disabled={emailSending || !emailAddr} style={{
                      padding: "9px 14px", borderRadius: 8, border: "none",
                      background: emailAddr ? C.green : C.bg3,
                      color: emailAddr ? "#fff" : C.textMuted,
                      fontSize: 11, fontWeight: 600, cursor: emailAddr ? "pointer" : "not-allowed",
                      fontFamily: "'IBM Plex Mono',monospace", whiteSpace: "nowrap",
                    }} title="Send full daily summary email">{emailSending ? "..." : "Daily"}</button>
                    <button onClick={sendWeeklyTest} disabled={emailSending || !emailAddr} style={{
                      padding: "9px 14px", borderRadius: 8, border: "none",
                      background: emailAddr ? "#7c3aed" : C.bg3,
                      color: emailAddr ? "#fff" : C.textMuted,
                      fontSize: 11, fontWeight: 600, cursor: emailAddr ? "pointer" : "not-allowed",
                      fontFamily: "'IBM Plex Mono',monospace", whiteSpace: "nowrap",
                    }} title="Send full weekly summary email">{emailSending ? "..." : "Weekly"}</button>
                  </div>

                  {emailMsg && (
                    <div style={{ padding: "9px 12px", borderRadius: 8, fontSize: 12,
                      background: emailMsg.type === "ok" ? C.green + "15" : C.red + "15",
                      color: emailMsg.type === "ok" ? C.green : C.red,
                      border: `1px solid ${emailMsg.type === "ok" ? C.green : C.red}40`,
                    }}>{emailMsg.type === "ok" ? "✓ " : "✗ "}{emailMsg.text}</div>
                  )}
                </div>
              </Card>

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

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