// running/src/overview.jsx — slice 18 of the module split.
//
// OVERVIEW: the in-app architecture/features/data-layer documentation
// page (createElement-based, no JSX). Extracted verbatim from
// running/index.html.

const { C } = window.SharedUI;
const { useState } = React;

    function Overview() {
      const [activeSection, setActiveSection] = useState("architecture");

      const sections = [
        { id: "architecture", label: "Architecture" },
        { id: "data", label: "Data Layer" },
        { id: "features", label: "Features" },
        { id: "integrations", label: "Integrations" },
      ];

      const Box = ({ children, style }) => React.createElement("div", { style: { background: C.bg1, border: `1px solid ${C.border}`, borderRadius: 12, padding: 20, ...style } }, children);
      const H2 = ({ children }) => React.createElement("div", { style: { fontSize: 16, fontWeight: 700, color: C.text, marginBottom: 12, fontFamily: "'Space Grotesk', sans-serif" } }, children);
      const H3 = ({ children, color }) => React.createElement("div", { style: { fontSize: 13, fontWeight: 700, color: color || C.cyan, marginBottom: 6 } }, children);
      const P = ({ children }) => React.createElement("div", { style: { fontSize: 12, color: C.textMuted, lineHeight: 1.7 } }, children);
      const Tag = ({ label, color }) => React.createElement("span", { style: { background: (color||C.cyan)+"22", color: color||C.cyan, border: `1px solid ${color||C.cyan}44`, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 600, fontFamily: "'IBM Plex Mono', monospace" } }, label);

      // ── Architecture diagram (SVG) ──
      const ArchDiagram = () => {
        const layers = [
          { y: 20,  label: "1 · Raw — Data Sources", color: C.green,  items: ["Garmin Connect", "Strava (OAuth + Webhooks)", "MyFitnessPal", "Manual Entry"] },
          { y: 130, label: "2 · Ingest — Cloud Functions", color: C.amber, items: ["garminImport", "syncStravaActivities", "syncGarminDynamics", "appendRunHistory", "recomputeTrainingSnapshot"] },
          { y: 240, label: "3 · Conformed — Firestore (source of truth)", color: C.purple, items: ["health/{date}", "activities/{id}+dyn", "mfpDiary/{date}", "history/timeseries", "stats/performance", "derived/trainingSnapshot"] },
          { y: 350, label: "4 · Consumer + Insight products", color: C.cyan, items: ["DataProvider (web normalize)", "running/lib/* (web calc)", "trainingSnapshot.js (server)", "deficit/planMath/pacing (shared)"] },
          { y: 460, label: "5 · Actionable insights → 6 · Suggested actions", color: "#a78bfa", items: ["UI Pages (Summary · Training · …)", "Coach (Claude) — training-state block", "Plan gen · Smart-Refresh · Suggest"] },
        ];
        return React.createElement("svg", { viewBox: "0 0 760 560", style: { width: "100%", maxWidth: 760, display: "block" } },
          // Connector lines
          ...layers.slice(0, -1).map((layer, i) =>
            React.createElement("line", { key: `line-${i}`, x1: 380, y1: layer.y + 68, x2: 380, y2: layers[i+1].y + 2, stroke: C.border, strokeWidth: 2, strokeDasharray: "4 3" })
          ),
          // Layer boxes
          ...layers.map(layer =>
            React.createElement("g", { key: layer.label },
              React.createElement("rect", { x: 10, y: layer.y, width: 740, height: 66, rx: 10, fill: layer.color + "14", stroke: layer.color + "55", strokeWidth: 1.5 }),
              React.createElement("text", { x: 22, y: layer.y + 17, fill: layer.color, fontSize: 10, fontWeight: 700, fontFamily: "IBM Plex Mono, monospace" }, layer.label),
              ...layer.items.map((item, i) =>
                React.createElement("g", { key: item },
                  React.createElement("rect", { x: 22 + i * (720 / layer.items.length), y: layer.y + 26, width: (720 / layer.items.length) - 6, height: 28, rx: 5, fill: layer.color + "22", stroke: layer.color + "44", strokeWidth: 1 }),
                  React.createElement("text", { x: 22 + i * (720 / layer.items.length) + (720 / layer.items.length - 6) / 2, y: layer.y + 44, fill: layer.color, fontSize: 9.5, textAnchor: "middle", fontFamily: "IBM Plex Mono, monospace", dominantBaseline: "middle" }, item)
                )
              )
            )
          )
        );
      };

      // ── Data flow diagram ──
      const DataFlowDiagram = () => {
        const nodes = [
          { x: 60,  y: 40,  w: 140, h: 36, label: "Garmin Scale", color: C.green, sub: "weight + body comp" },
          { x: 250, y: 40,  w: 140, h: 36, label: "Garmin Connect", color: C.green, sub: "HRV · sleep · HR · steps" },
          { x: 440, y: 40,  w: 140, h: 36, label: "Strava", color: C.amber, sub: "activities · HR zones" },
          { x: 630, y: 40,  w: 130, h: 36, label: "MyFitnessPal", color: "#f97316", sub: "calories · macros" },
          { x: 155, y: 160, w: 200, h: 36, label: "garminImport()", color: C.cyan, sub: "normalise · convert units" },
          { x: 415, y: 160, w: 200, h: 36, label: "mfpBookmarkletSync()", color: C.cyan, sub: "merge · sanitize macros" },
          { x: 155, y: 280, w: 200, h: 36, label: "health/{date}", color: C.purple, sub: "Firestore" },
          { x: 415, y: 280, w: 200, h: 36, label: "nutrition + mfpDiary", color: C.purple, sub: "Firestore" },
          { x: 255, y: 400, w: 300, h: 36, label: "DataProvider", color: "#a78bfa", sub: "normalizeHealthEntry · mergeNutritionDay · redsRisk" },
          { x: 255, y: 500, w: 300, h: 36, label: "useData() → All Pages", color: C.text, sub: "Status · Summary · Training · Health · Nutrition · Coach" },
        ];
        const arrows = [
          [130, 76, 230, 160], [320, 76, 270, 160], [510, 76, 390, 160], [695, 76, 560, 160],
          [255, 196, 255, 280], [515, 196, 515, 280],
          [255, 316, 360, 400], [515, 316, 450, 400],
          [405, 436, 405, 500],
        ];
        return React.createElement("svg", { viewBox: "0 0 790 560", style: { width: "100%", maxWidth: 790, display: "block" } },
          React.createElement("defs", null,
            React.createElement("marker", { id: "arr", markerWidth: 8, markerHeight: 8, refX: 6, refY: 3, orient: "auto" },
              React.createElement("path", { d: "M0,0 L0,6 L8,3 z", fill: C.border })
            )
          ),
          ...arrows.map(([x1,y1,x2,y2], i) =>
            React.createElement("line", { key: i, x1, y1, x2, y2, stroke: C.border, strokeWidth: 1.5, strokeDasharray: "4 3", markerEnd: "url(#arr)" })
          ),
          ...nodes.map(n =>
            React.createElement("g", { key: n.label },
              React.createElement("rect", { x: n.x, y: n.y, width: n.w, height: n.h, rx: 7, fill: n.color + "18", stroke: n.color + "66", strokeWidth: 1.5 }),
              React.createElement("text", { x: n.x + n.w/2, y: n.y + 13, fill: n.color, fontSize: 10, fontWeight: 700, textAnchor: "middle", fontFamily: "IBM Plex Mono, monospace" }, n.label),
              React.createElement("text", { x: n.x + n.w/2, y: n.y + 26, fill: n.color + "aa", fontSize: 9, textAnchor: "middle", fontFamily: "IBM Plex Mono, monospace" }, n.sub)
            )
          )
        );
      };

      const features = [
        { name: "Status", icon: "🧭", color: C.cyan, tags: ["AI","Garmin","Strava"], desc: "Mission control. One glance tells you today's readiness, your live training state and the single next action — the home surface every other page and the coach agree with." },
        { name: "Summary", icon: "⚡", color: C.cyan, tags: ["Strava","Garmin","AI"], desc: "Your performance cockpit: effective VO₂max, CTL/ATL/TSB load, blended race predictions, HRV-guided readiness, RED-S risk flags and Claude's daily read — the science, distilled." },
        { name: "Training", icon: "🏃", color: C.green, tags: ["Strava","Garmin","AI"], desc: "The work, end to end — activity log with maps and Garmin dynamics, AI periodized plans, race projections, the multi-year History tab and deep Analytics, all under one roof." },
        { name: "Training → Plan", icon: "📅", color: C.cyan, tags: ["AI"], desc: "An AI-built, fully periodized race plan tailored to your goal, current fitness and schedule — then Smart-Refresh regenerates any week against where your fitness actually is." },
        { name: "Training → Analytics", icon: "📈", color: C.purple, tags: ["Strava","Garmin"], desc: "The trends that matter, across your entire log: the Fitness Arc, efficiency-factor progression, tempo/threshold pace tracking, heat- and hill-adjusted reads and per-rep workout pace." },
        { name: "Marathons", icon: "🏆", color: C.amber, tags: ["Strava","AI"], desc: "Race-day intelligence — course-specific pacing, elevation and bridge strategy, and projected finish times anchored to your current fitness and build." },
        { name: "Health", icon: "❤️", color: "#f43f5e", tags: ["Garmin"], desc: "Recovery you can trust — daily HRV, resting HR, sleep, Body Battery, SpO₂ and respiration, plus full body composition from the Garmin Index scale, all trended over time." },
        { name: "Nutrition", icon: "🥗", color: "#f97316", tags: ["MFP","AI"], desc: "Fuel matched to the work — calories and macros from MyFitnessPal weighed against training load, glycogen status and energy availability, with AI-generated nutrition targets." },
        { name: "Shoes", icon: "👟", color: C.green, tags: ["Strava"], desc: "Rotation management with mileage and wear tracking, per-shoe running-economy comparison and data-driven recommendations on what to lace up next." },
        { name: "Coach", icon: "🤖", color: "#a78bfa", tags: ["AI"], desc: "A conversational coach powered by Claude that reads your live training snapshot, health and nutrition — grounded in your numbers, on web and Telegram. It quotes the data, it doesn't guess." },
      ];

      const dataDomains = [
        { name: "health/{date}", color: C.green, fields: ["hrv", "restingHR", "sleepScore", "sleepHours", "bodyBattery", "stress", "trainingReadiness", "spo2", "respiration", "steps", "weight", "bodyFat", "muscleMass", "boneMass", "bodyWater", "bmi"], source: "Garmin Connect (bookmarklet + API)" },
        { name: "nutrition/{date}", color: "#f97316", fields: ["calories", "protein", "carbs", "fat", "fiber"], source: "MyFitnessPal scraper (legacy)" },
        { name: "mfpDiary/{date}", color: "#f97316", fields: ["totals.calories", "totals.protein", "totals.carbs", "totals.fat", "meals[]", "items[]"], source: "MFP bookmarklet (preferred)" },
        { name: "activities/{id}", color: C.amber, fields: ["distance", "movingTime", "averageHR", "maxHR", "averagePower", "cadence", "elevGain", "type", "garminDynamics"], source: "Strava API + Garmin dynamics enrichment" },
        { name: "history/timeseries", color: C.amber, fields: ["runs[]", "weekly[]", "monthly[]", "racePredictions[]", "metrics.endurance", "metrics.hill", "metrics.vo2max", "totalRuns", "dateRange"], source: "appendActivityToUserHistory (per-sync) + rebuildRunHistory (full replay); score metrics from the Garmin userscript capture" },
        { name: "profile/weightGoals", color: C.purple, fields: ["targetWeight", "weeklyRateLbs", "targetDate"], source: "User settings" },
        { name: "profile/nutritionTargets", color: C.purple, fields: ["calories", "protein", "carbs", "fat"], source: "User settings" },
        { name: "trainingPlans/{id}", color: C.cyan, fields: ["raceName", "raceDate", "weeks[]", "phases[]", "active"], source: "AI-generated (Claude)" },
        { name: "stats/performance", color: "#a78bfa", fields: ["vo2max", "lactateThreshold", "fitnessScore", "racePredictions"], source: "Garmin Connect metrics" },
        { name: "derived/trainingSnapshot", color: C.cyan, fields: ["volume (7d/28d, ACWR)", "fitness (effective VDOT, paces)", "planProgress", "raceReadiness", "execution", "form", "recovery", "computedAt"], source: "functions/lib/trainingSnapshot.js — recomputeTrainingSnapshotFor() rebuilds it after every Strava / Garmin-dynamics sync, a nightly backstop cron, and an on-demand callable; DataProvider subscribes to it (useData().trainingSnapshot) and the coach context renders it. One number everywhere." },
      ];

      return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 24, padding: "0 0 40px" } },
        // ── Hero ──
        React.createElement("div", { style: { background: `linear-gradient(135deg, ${C.cyan}14, ${C.bg1} 55%)`, border: `1px solid ${C.cyan}33`, borderRadius: 16, padding: "28px 26px" } },
          React.createElement("div", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, fontWeight: 700, letterSpacing: 2.5, color: C.cyan, textTransform: "uppercase", marginBottom: 10 } }, "Personal AI Running Coach · Analytics PWA"),
          React.createElement("div", { style: { fontFamily: "'Space Grotesk', sans-serif", fontSize: 30, fontWeight: 800, color: C.text, lineHeight: 1.15, maxWidth: 760 } }, "Every signal from your training, reasoned into one answer: what to run today."),
          React.createElement("div", { style: { color: C.textMuted, fontSize: 14, marginTop: 12, maxWidth: 740, lineHeight: 1.65 } },
            "chris.run unifies Garmin, Strava and MyFitnessPal into a single sports-science engine — VO₂max, training load, HRV-guided readiness and race projections — then hands the ",
            React.createElement("span", { style: { color: C.text, fontWeight: 600 } }, "exact same numbers"),
            " to an AI coach that knows your whole history. No two dashboards that disagree. No guesswork."
          )
        ),

        // ── Value pillars ──
        React.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(210px, 1fr))", gap: 12 } },
          [
            { k: "10", color: C.cyan, t: "integrated surfaces", d: "Status, Training, Health, Nutrition, Coach & more — every page reads the same context." },
            { k: "4+ yrs", color: C.green, t: "of fitness modelled", d: "Banister CTL/ATL/TSB and the Fitness Arc run across your entire run log, not a 90-day window." },
            { k: "1", color: "#a78bfa", t: "source of truth", d: "A derived training snapshot every surface and the coach quote — never re-derived, never in conflict." },
            { k: "3", color: C.amber, t: "data feeds, unified", d: "Garmin health, Strava activities and MyFitnessPal macros, normalised into one schema." },
          ].map(p =>
            React.createElement("div", { key: p.t, style: { background: C.bg1, border: `1px solid ${p.color}33`, borderRadius: 12, padding: "16px 18px" } },
              React.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 8, marginBottom: 6 } },
                React.createElement("span", { style: { fontFamily: "'Space Grotesk', sans-serif", fontSize: 26, fontWeight: 800, color: p.color } }, p.k),
                React.createElement("span", { style: { fontSize: 12, fontWeight: 700, color: C.text } }, p.t)
              ),
              React.createElement("div", { style: { fontSize: 11, color: C.textMuted, lineHeight: 1.55 } }, p.d)
            )
          )
        ),


        // Section tabs
        React.createElement("div", { style: { display: "flex", gap: 4, background: C.bg1, padding: 4, borderRadius: 10, border: `1px solid ${C.border}`, width: "fit-content" } },
          sections.map(s =>
            React.createElement("button", {
              key: s.id,
              onClick: () => setActiveSection(s.id),
              style: { padding: "6px 16px", borderRadius: 7, border: "none", background: activeSection === s.id ? C.bg2 : "transparent", color: activeSection === s.id ? C.cyan : C.textMuted, fontSize: 12, fontWeight: activeSection === s.id ? 700 : 400, cursor: "pointer", transition: "all 0.15s", fontFamily: "'IBM Plex Mono', monospace" }
            }, s.label)
          )
        ),

        // ── Architecture section ──
        activeSection === "architecture" && React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 16 } },
          React.createElement(Box, null,
            React.createElement(H2, null, "System Architecture"),
            React.createElement(P, null, "chris.run is a single-page application on Firebase hosting with Cloud Functions for backend logic. Data moves through a layered product hierarchy — raw source feeds → conformed records in Firestore → derived consumer/insight products → actionable insights and suggested actions — so every surface (web pages and the AI coach) reasons off the same numbers."),
            React.createElement("div", { style: { marginTop: 16 } }, React.createElement(ArchDiagram))
          ),
          React.createElement(Box, null,
            React.createElement(H2, null, "Data Product Hierarchy"),
            React.createElement(P, null, "Each tier consumes the one above it. The point of the hierarchy is that aggregated reasoning happens once, in a shared layer, instead of being re-derived (inconsistently) by every consumer — the bug that used to make the coach quote stale baselines."),
            React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8, marginTop: 12 } },
              [
                { n: "1", t: "Raw", color: C.green, d: "Untouched source payloads — Strava activities & webhooks, the Garmin Connect SPA fetch intercepts (wellness, body comp, performance metrics), MFP diary scrapes, manual log entries." },
                { n: "2", t: "Ingest / normalise", color: C.amber, d: "Cloud Functions that unit-convert and remap field-name variants on the way in: garminImport, syncStravaActivities, syncGarminDynamics (merges run-dynamics onto the matching activity), mfpBookmarkletSync — and appendActivityToUserHistory, which folds every new run into the long-term trend store (rebuildRunHistory replays the whole log on demand)." },
                { n: "3", t: "Conformed", color: C.purple, d: "Canonical Firestore docs — health/{date}, activities/{id} (with dynamics merged), mfpDiary/{date}, trainingPlans/{id}, stats/performance, history/timeseries (the multi-year run-trend series behind the Volume + Fitness Arc charts), and derived/trainingSnapshot (the persisted tier-4 product, rebuilt on every sync + a nightly cron). One shape, one source of truth." },
                { n: "4", t: "Consumer + insight products", color: C.cyan, d: "Aggregations and derived metrics. Web-side: running/lib/* (effective VO2 / training paces / gait profile / scoring / goal confidence / long-run quality / form-vs-pace) and DataProvider's normalize + redsRisk. Server-side: functions/lib/trainingSnapshot.js — volume & ACWR, demonstrated VDOT (Garmin = floor) + Daniels paces, plan progress, Riegel race-readiness projection, execution scorecard from stored grades, form & recovery rollups — persisted to derived/trainingSnapshot after every sync (+ nightly cron + on-demand callable) so the web UI (useData().trainingSnapshot) and the coach context read identical numbers; plus the shared deficitAnalysis / planMath / pacingStrategy modules." },
                { n: "5", t: "Actionable insights", color: "#a78bfa", d: "Surfaces that interpret tier-4 products for the athlete: the Status home (readiness + what-to-do-today hero), the Summary / Training / Health / Nutrition pages, the weekly TRAINING DIMENSIONS + persistent-deficit read, and the coach's CURRENT TRAINING STATE prompt block (rendered straight from trainingSnapshot — the coach is told to quote it, not re-derive)." },
                { n: "6", t: "Suggested actions", color: "#f97316", d: "Concrete recommendations generated off the insights: AI plan generation, Smart-Refresh (regenerate a week against current fitness), Suggest-harder-session, structured-workout push to Garmin, and the coach's day-to-day prescriptions." },
              ].map(tier =>
                React.createElement("div", { key: tier.n, style: { display: "flex", gap: 12, alignItems: "flex-start", padding: "10px 12px", background: C.bg0, borderRadius: 8, border: `1px solid ${tier.color}33` } },
                  React.createElement("div", { style: { minWidth: 28, height: 28, borderRadius: 6, background: tier.color + "22", color: tier.color, display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 800, fontSize: 13, fontFamily: "'IBM Plex Mono', monospace", flexShrink: 0 } }, tier.n),
                  React.createElement("div", { style: { flex: 1 } },
                    React.createElement("div", { style: { fontSize: 12, fontWeight: 700, color: tier.color, marginBottom: 3 } }, tier.t),
                    React.createElement("div", { style: { fontSize: 11, color: C.textMuted, lineHeight: 1.6 } }, tier.d)
                  )
                )
              )
            )
          ),
          React.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: 12 } },
            [
              { label: "Frontend", color: C.cyan, items: ["React 18 (no build step)", "Firebase JS SDK v9", "Recharts for visualisation", "Inter + Space Grotesk + IBM Plex Mono fonts"] },
              { label: "Backend", color: C.amber, items: ["Firebase Cloud Functions (Node 20)", "Firestore (NoSQL)", "Firebase Hosting", "Firebase Auth (Google)"] },
              { label: "External APIs", color: C.green, items: ["Strava API (OAuth 2.0 + webhooks)", "Garmin Connect (userscript capture)", "MyFitnessPal (userscript DOM)", "Anthropic Claude API"] },
              { label: "CI/CD", color: C.purple, items: ["GitHub Actions → Firebase deploy", "Push to main auto-deploys", "Functions + Hosting in parallel", "Secrets via GitHub Secrets"] },
            ].map(card =>
              React.createElement(Box, { key: card.label },
                React.createElement(H3, { color: card.color }, card.label),
                React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 4 } },
                  card.items.map(item => React.createElement("div", { key: item, style: { fontSize: 11, color: C.textMuted, display: "flex", alignItems: "center", gap: 6 } },
                    React.createElement("span", { style: { color: card.color, fontSize: 10 } }, "▸"),
                    item
                  ))
                )
              )
            )
          )
        ),

        // ── Data layer section ──
        activeSection === "data" && React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 16 } },
          React.createElement(Box, null,
            React.createElement(H2, null, "Data Flow"),
            React.createElement(P, null, "Raw data from external sources is ingested via Cloud Functions, normalised into canonical schemas, and stored in Firestore. The DataProvider layer applies a second normalisation pass before exposing data to UI components via useData()."),
            React.createElement("div", { style: { marginTop: 16 } }, React.createElement(DataFlowDiagram))
          ),
          React.createElement(Box, null,
            React.createElement(H2, null, "Key Data Transforms"),
            React.createElement("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 } },
              [
                { fn: "normalizeHealthEntry()", color: C.cyan, desc: "Remaps Garmin field name variants (restingHeartRate→restingHR, bodyBatteryHigh→bodyBattery, etc.), extracts nested sleep objects, coerces all numeric fields. Applied to every health document before use." },
                { fn: "mergeNutritionDay()", color: "#f97316", desc: "Merges nutrition + mfpDiary for a date. Always prefers mfpDiary macros (most accurate). Math.max for calories. Fixes 100x inflation from old scraper. Physiological clamping prevents outliers." },
                { fn: "calcRedsRisk()", color: "#f43f5e", desc: "Computed once in DataProvider from health + nutrition + activities. Scores energy availability, weight velocity, HRV, sleep, training load. Returns severity + actionable flags." },
                { fn: "garminImport()", color: C.green, desc: "Intercepts Garmin Connect SPA fetch calls via Tampermonkey. Captures dailyWeightSummaries (body comp), wellness data (sleep/HRV/stress), and performance metrics. Converts all units (g→lbs, etc.)." },
                { fn: "buildTrainingSnapshot()", color: "#a78bfa", desc: "functions/lib/trainingSnapshot.js — pure function over the conformed layer (activities + plan + health + perf), built on functions/lib/raceMath.js (the shared race-math: recency-weighted effective VO2max with Garmin as a floor, the Daniels+Riegel race-time blend, MP-anchored training paces — the same algorithms the web app's panels run). Computes the tier-4 data products: 7d/28d volume + ACWR flag, fitness + paces, plan progress, race-readiness projection, execution scorecard from stored grades, form & recovery rollups. recomputeTrainingSnapshotFor() persists it to derived/trainingSnapshot after each Strava / Garmin-dynamics sync, a nightly cron, and an on-demand callable; DataProvider subscribes (useData().trainingSnapshot) and the coach renders it as the CURRENT TRAINING STATE block." },
              ].map(t =>
                React.createElement("div", { key: t.fn, style: { background: C.bg0, border: `1px solid ${C.border}`, borderRadius: 8, padding: 14 } },
                  React.createElement("div", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, fontWeight: 700, color: t.color, marginBottom: 6 } }, t.fn),
                  React.createElement(P, null, t.desc)
                )
              )
            )
          ),
          React.createElement(Box, null,
            React.createElement(H2, null, "Firestore Collections"),
            React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 10 } },
              dataDomains.map(domain =>
                React.createElement("div", { key: domain.name, style: { display: "flex", gap: 12, alignItems: "flex-start", padding: "10px 12px", background: C.bg0, borderRadius: 8, border: `1px solid ${C.border}` } },
                  React.createElement("div", { style: { minWidth: 180, fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, fontWeight: 700, color: domain.color, paddingTop: 2 } }, domain.name),
                  React.createElement("div", { style: { flex: 1 } },
                    React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 4 } },
                      domain.fields.map(f => React.createElement(Tag, { key: f, label: f, color: domain.color }))
                    ),
                    React.createElement("div", { style: { fontSize: 11, color: C.textDim, marginTop: 4 } }, domain.source)
                  )
                )
              )
            )
          )
        ),

        // ── Features section ──
        activeSection === "features" && React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 12 } },
          React.createElement(Box, null,
            React.createElement(H2, null, "Pages & Features"),
            React.createElement(P, null, "Ten surfaces covering the entire training–recovery–nutrition loop, plus the deep sub-tabs inside Training (Plan · Roadmap · Races · History · Performance · Analytics). Every page reads from one shared DataProvider context — so the number you see on Status is the number the coach sees, everywhere.")
          ),
          React.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 12 } },
            features.map(f =>
              React.createElement(Box, { key: f.name },
                React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 } },
                  React.createElement("span", { style: { fontSize: 20 } }, f.icon),
                  React.createElement("div", { style: { fontSize: 14, fontWeight: 700, color: f.color, fontFamily: "'Space Grotesk', sans-serif" } }, f.name),
                  React.createElement("div", { style: { display: "flex", gap: 4, marginLeft: "auto" } },
                    f.tags.map(t => React.createElement(Tag, { key: t, label: t, color: t === "AI" ? "#a78bfa" : t === "Strava" ? C.amber : t === "Garmin" ? C.green : "#f97316" }))
                  )
                ),
                React.createElement(P, null, f.desc)
              )
            )
          )
        ),

        // ── Integrations section ──
        activeSection === "integrations" && React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 12 } },
          [
            { name: "Garmin Connect", color: C.green, icon: "⌚", method: "Tampermonkey Userscript", how: "A userscript injects a sync button on connect.garmin.com. It intercepts the page's own fetch calls to capture weight/body comp (dailyWeightSummaries), wellness (HRV, sleep, Body Battery, stress, SpO2) and the performance-score charts (Endurance & Hill Score, captured when you open them), then POSTs everything to the garminImport Cloud Function. For deep gaps, an official Garmin \"Export Your Data\" ZIP can be imported directly.", fields: ["HRV", "Resting HR", "Sleep score/hours", "Body Battery", "Stress", "SpO2", "Respiration", "Steps", "Weight", "Body Fat %", "Muscle Mass", "Bone Mass", "Body Water", "BMI", "Training Readiness", "VO2max", "Endurance Score", "Hill Score", "Race Predictions"] },
            { name: "Strava", color: C.amber, icon: "🚴", method: "OAuth 2.0 + Webhooks", how: "Standard OAuth flow stores access/refresh tokens in Firestore. A scheduled function refreshes all tokens daily. Strava webhooks trigger real-time activity sync. syncGarminDynamics enriches activities with Garmin running dynamics (cadence, ground contact, power, vertical oscillation).", fields: ["Distance", "Moving time", "Avg/max HR", "Avg power", "Cadence", "Elevation", "Pace", "HR zones", "Garmin dynamics"] },
            { name: "MyFitnessPal", color: "#f97316", icon: "🥗", method: "Tampermonkey Bookmarklet", how: "A userscript on MFP diary pages scrapes the daily food log DOM and POSTs structured data to mfpBookmarkletSync. Supports multi-day historical sync (7 days). Data is stored in mfpDiary collection and takes precedence over the older nutrition collection for macros.", fields: ["Calories", "Protein", "Carbohydrates", "Fat", "Fiber", "Per-meal breakdown", "Food items"] },
            { name: "Claude AI", color: "#a78bfa", icon: "🤖", method: "Anthropic API", how: "Three AI features: (1) Daily coaching insights summarise training load, recovery, and nutrition into actionable text. (2) Nutrition plan generation creates personalised macro targets and meal timing. (3) Conversational coach in the Coach tab has full context of your health, training, and nutrition data.", fields: ["Coaching insights", "Nutrition plans", "Weight coaching", "Conversational coach"] },
          ].map(intg =>
            React.createElement(Box, { key: intg.name },
              React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 12 } },
                React.createElement("span", { style: { fontSize: 24 } }, intg.icon),
                React.createElement("div", null,
                  React.createElement("div", { style: { fontSize: 15, fontWeight: 700, color: intg.color, fontFamily: "'Space Grotesk', sans-serif" } }, intg.name),
                  React.createElement(Tag, { label: intg.method, color: intg.color })
                )
              ),
              React.createElement(P, null, intg.how),
              React.createElement("div", { style: { marginTop: 12, display: "flex", flexWrap: "wrap", gap: 4 } },
                intg.fields.map(f => React.createElement(Tag, { key: f, label: f, color: intg.color }))
              )
            )
          )
        )
      );
    }

    // ─────────────────────────────────────────────────────────────────────────
    // SHOES — extracted to src/shoes.jsx (module-split slice 5)
    // ─────────────────────────────────────────────────────────────────────────

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