// ================= Rendering functions =================
    function loadingScreen() {
      return `<section class="screen active">
        <div class="auth-shell">
          <div class="hero"><div class="hero-brand-mark"><img src="assets/leaner-logo.png" alt=""></div><p class="eyebrow">Leaner Dashboard</p><h1>Getting your dashboard ready.</h1><p class="subhead">One moment while we load your Leaner experience.</p></div>
        </div>
      </section>`;
    }

    function login() {
      return `<section class="screen active">
        <div class="auth-shell">
          <div class="hero"><div class="hero-brand-mark"><img src="assets/leaner-logo.png" alt=""></div><p class="eyebrow">Leaner Dashboard</p><h1>Welcome back.</h1><p class="subhead">Sign in to continue to your Leaner dashboard.</p></div>
          <section class="auth-card">
          <form class="form" id="loginForm">
            <label>Email <input name="email" type="email" autocomplete="email" required placeholder="you@example.com"></label>
            <label>Password <input name="password" type="password" autocomplete="current-password" required placeholder="Password"></label>
            ${state.authError ? `<p class="notice">${escapeHtml(state.authError)}</p>` : ""}
            <button class="primary">Sign In</button>
          </form>
          ${!isFirebaseMode() ? `<p class="notice" style="margin-top:12px">Prototype mode: use any email. Include "admin" in the email to preview staff access.</p>` : ""}
          </section>
        </div>
      </section>`;
    }

    function metric(label, value) {
      return `<div class="card"><div class="metric-label">${label}</div><div class="metric-value">${value}</div></div>`;
    }

    function miniStat(label, value) {
      return `<div class="mini-stat mini-stat-${label.toLowerCase()}"><div class="metric-label">${label}</div><div class="metric-value">${value}</div></div>`;
    }

    function icon(name) {
      const paths = {
        spark: '<path d="M12 3l1.7 5.1L19 10l-5.3 1.9L12 17l-1.7-5.1L5 10l5.3-1.9L12 3z"></path>',
        calendar: '<path d="M7 3v4M17 3v4M4 8h16M5 5h14v15H5z"></path><path d="M9 14l2 2 4-5"></path>',
        trend: '<path d="M4 17l6-6 4 4 6-8"></path><path d="M15 7h5v5"></path>',
        star: '<path d="M12 3l2.8 5.7 6.2.9-4.5 4.4 1.1 6.2L12 17.2 6.4 20.2 7.5 14 3 9.6l6.2-.9L12 3z"></path>',
        heart: '<path d="M20 8.5c0 5.5-8 9.5-8 9.5s-8-4-8-9.5A4.5 4.5 0 0112 5a4.5 4.5 0 018 3.5z"></path>',
        users: '<path d="M16 19c0-2-1.8-3.5-4-3.5S8 17 8 19"></path><circle cx="12" cy="9" r="3"></circle><path d="M20 18c0-1.5-1.2-2.7-2.8-3M17 6.5a2.5 2.5 0 010 5"></path><path d="M4 18c0-1.5 1.2-2.7 2.8-3M7 6.5a2.5 2.5 0 000 5"></path>',
        tip: '<path d="M9 18h6"></path><path d="M10 22h4"></path><path d="M8 14c-1.3-1-2-2.5-2-4a6 6 0 1112 0c0 1.5-.7 3-2 4-.8.7-1 1.3-1 2H9c0-.7-.2-1.3-1-2z"></path>',
        fork: '<path d="M7 3v8"></path><path d="M5 3v4c0 2 1 4 2 4s2-2 2-4V3"></path><path d="M17 3v18"></path><path d="M15 3h4v8h-4z"></path>',
        message: '<path d="M5 5h14v10H8l-3 3z"></path><path d="M9 10h6"></path>',
        gift: '<path d="M4 10h16v10H4z"></path><path d="M4 10h16M12 10v10M7 6c0-1.1.9-2 2-2 2 0 3 4 3 4H9a2 2 0 01-2-2z"></path><path d="M17 6c0-1.1-.9-2-2-2-2 0-3 4-3 4h3a2 2 0 002-2z"></path>',
        flame: '<path d="M12 22c4 0 7-2.7 7-6.7 0-3-1.8-5.2-3.8-7.2-.6 2-1.8 3.1-3.2 4.1.2-3.2-1.2-6-4-8.2.2 3.6-3 5.8-3 10.4C5 18.8 8 22 12 22z"></path>',
        lock: '<rect x="5" y="10" width="14" height="10" rx="2"></rect><path d="M8 10V7a4 4 0 018 0v3"></path>'
      };
      return `<span class="icon-badge"><svg viewBox="0 0 24 24" aria-hidden="true">${paths[name] || paths.spark}</svg></span>`;
    }

    function momentumSummary(compact = false) {
      const next = nextReward();
      const until = Math.max(0, next.pointsCost - state.pointsBalance);
      const progress = Math.min(100, Math.round((state.pointsBalance / next.pointsCost) * 100));
      return `<section class="momentum-card ${compact ? "home-momentum-strip" : ""}">
        <div>
          <p class="eyebrow momentum-eyebrow">Momentum Points</p>
          <div class="points-number">${state.pointsBalance}</div>
          <h2>Momentum Points</h2>
          <p style="margin:0">Momentum Points are Leaner's way of celebrating your consistency. Check in, log wins, and support the community to unlock Leaner perks.</p>
        </div>
        <div class="next-reward-block">
          <p class="metric-label">Next reward</p>
          <h3>${escapeHtml(next.title)}</h3>
          <div class="reward-countdown">${until} points to go</div>
          <div class="progress-track"><div class="progress-fill" style="--progress:${progress}%"></div></div>
          <p style="margin:8px 0 0">${state.pointsBalance} / ${next.pointsCost} points</p>
        </div>
        <button class="secondary momentum-cta" data-route="momentum">View rewards →</button>
      </section>`;
    }

    function home() {
      const weeklySupport = currentWeeklySupport();
      const localWins = visibleWins().slice(0, 3);
      const previewWins = visibleWinsForMap(visibleWins());
      return `
        <section class="screen active">
          <div class="hero home-hero">
            <p class="eyebrow">Welcome back, ${patient.firstName}</p>
            <h1><span class="home-progress-number">${patient.totalLost} lbs down.</span> Momentum building.</h1>
            <p class="subhead">Stay on track with your weekly check-in, next visit, and real wins from the Leaner community.</p>
          </div>
          <section class="progress-hero-card progress-hero-card-energized" aria-label="My program snapshot">
            <div class="progress-hero-main">
              <div class="progress-topline">
                <div>
                  <span class="momentum-badge">${icon("trend")} Momentum is building</span>
                  <p class="eyebrow">My Progress</p>
                  <h2 class="progress-main-title">Down ${patient.totalLost} lbs</h2>
                  <p style="margin-bottom:0">Week ${patient.currentWeek} of your physician-supervised Leaner program.</p>
                </div>
                <div class="progress-ring" aria-label="${patient.totalLost} pounds lost">
                  <div class="ring-value"><strong>${patient.totalLost}</strong><span>lbs lost</span></div>
                </div>
              </div>
              <div class="hero-stats">
                ${miniStat("Starting", `${patient.startingWeight} lbs`)}
                ${miniStat("Current", `${patient.currentWeight} lbs`)}
                ${miniStat("Streak", `${patient.checkInStreak} weeks`)}
              </div>
            </div>
            <div class="next-step next-step-featured">
              <div>
                <div class="metric-label">Next best step</div>
                <h3 style="margin:2px 0 4px">Complete your weekly check-in</h3>
                <p style="margin:0">Next visit: ${patient.nextVisitDate}. This week's focus: ${patient.weeklyFocus}.</p>
              </div>
            </div>
            <button class="primary checkin-cta" data-route="checkin">Check in now</button>
          </section>
          <section class="today-actions" aria-label="Today's actions">
            <div class="section-heading compact-heading"><div><p class="eyebrow">Today</p><h2>Today's actions</h2></div></div>
            <button class="action-row action-row-progress" data-route="checkin">${icon("trend")}<span><strong>Check in</strong><em>Log how the week is going.</em></span><span class="tool-arrow">›</span></button>
            <button class="action-row action-row-wins" data-route="submit">${icon("spark")}<span><strong>Share a win</strong><em>Post publicly, anonymously, or privately.</em></span><span class="tool-arrow">›</span></button>
            <button class="action-row action-row-support" data-route="support">${icon("message")}<span><strong>Get support</strong><em>Find this week's reminders and clinic help.</em></span><span class="tool-arrow">›</span></button>
          </section>
          ${momentumSummary(true)}
          ${featuredPerkCard(true)}
          <section class="panel home-wins-preview-panel">
            <div class="section-heading home-wins-preview-heading">
              <div>
                <p class="eyebrow">Community momentum</p>
                <h2>Wins Board</h2>
                <p>A glimpse of shared wins from the Leaner community. Patients choose what to share.</p>
              </div>
              <div class="button-row"><button class="ghost" data-route="wins">View Wins Board</button><button class="secondary" data-route="submit">Share your win</button></div>
            </div>
            <div class="wins-board preview" id="previewBoard" aria-label="Preview of the Leaner Wins Board">
              ${bubbleMarkup(previewWins, true)}
              <button class="wins-preview-map-cta" data-route="wins">Explore community wins <span aria-hidden="true">›</span></button>
            </div>
          </section>
          <section class="panel local-wins-panel">
            <div class="section-heading">
              <div>
                <p class="eyebrow">Community momentum</p>
                <h2>Local wins this week</h2>
                <p>Small, real progress from Leaner patients nearby.</p>
              </div>
            </div>
            <div class="local-win-list">${localWins.map(win => `<article class="local-win-card"><div>${icon(win.isFeatured ? "star" : "spark")}</div><div><h3>${escapeHtml(win.headline)}</h3><p>${escapeHtml(win.isAnonymous ? "Anonymous" : win.displayName)} &middot; ${win.cheers} cheers</p></div></article>`).join("")}</div>
          </section>
          <section class="panel">
            <div class="section-heading">
              <div>
                <p class="eyebrow">This week's support</p>
                <h2>Your weekly support</h2>
                <p>Simple help for the week ahead.</p>
              </div>
            </div>
            <div class="quick-tools">
              <button class="tool-tile" data-route="meals">${icon(weeklySupport.meal_idea.icon || "fork")}<span><h3>${escapeHtml(weeklySupport.meal_idea.title)}</h3><p>${escapeHtml(weeklySupport.meal_idea.shortDescription)}</p></span><span class="tool-arrow">›</span></button>
              <button class="tool-tile" data-route="support">${icon(weeklySupport.coach_tip.icon || "tip")}<span><h3>${escapeHtml(weeklySupport.coach_tip.title)}</h3><p>${escapeHtml(weeklySupport.coach_tip.shortDescription)}</p></span><span class="tool-arrow">›</span></button>
              <button class="tool-tile" data-route="support">${icon(weeklySupport.clinic_support.icon || "message")}<span><h3>${escapeHtml(weeklySupport.clinic_support.title)}</h3><p>${escapeHtml(weeklySupport.clinic_support.shortDescription)}</p></span><span class="tool-arrow">›</span></button>
            </div>
          </section>
          <p class="notice">This dashboard supports your Leaner journey but does not replace medical advice. Contact Leaner for medical questions, dose changes, or concerning symptoms.</p>
        </section>`;
    }

    function winMapRegion(category) {
      const regions = {
        "Pounds Lost": { x: 440, y: 550, accent: "green", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(198, 221, 215, .24)", sheen: "rgba(136, 237, 184, .16)", icon: "trend" },
        "Non-Scale Victory": { x: 585, y: 520, accent: "purple", bg: "#C6C1E2", ink: "#3F3B57", highlight: "rgba(198, 193, 226, .24)", sheen: "rgba(198, 193, 226, .15)", icon: "spark" },
        "Protein Win": { x: 660, y: 730, accent: "gold", bg: "#F9F871", ink: "#3F3B57", highlight: "rgba(253, 251, 226, .24)", sheen: "rgba(249, 248, 113, .15)", icon: "fork" },
        "Meal Hack": { x: 600, y: 830, accent: "gold", bg: "#F9F871", ink: "#3F3B57", highlight: "rgba(253, 251, 226, .23)", sheen: "rgba(249, 248, 113, .15)", icon: "fork" },
        "Movement": { x: 410, y: 805, accent: "blue", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .23)", sheen: "rgba(159, 184, 197, .15)", icon: "trend" },
        "Water Win": { x: 405, y: 670, accent: "teal", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .23)", sheen: "rgba(136, 237, 184, .15)", icon: "heart" },
        "First Month": { x: 500, y: 630, accent: "teal", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .22)", sheen: "rgba(136, 237, 184, .14)", icon: "star" },
        "Motivation": { x: 555, y: 610, accent: "purple", bg: "#C6C1E2", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .23)", sheen: "rgba(198, 193, 226, .15)", icon: "heart" },
        "Maintenance": { x: 435, y: 625, accent: "green", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(198, 221, 215, .23)", sheen: "rgba(136, 237, 184, .15)", icon: "star" },
        "Getting Started": { x: 470, y: 720, accent: "teal", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .20)", sheen: "rgba(136, 237, 184, .13)", icon: "spark" }
      };
      return regions[category] || { x: 520, y: 660, accent: "teal", bg: "#C6DDD7", ink: "#3F3B57", highlight: "rgba(241, 238, 228, .20)", sheen: "rgba(136, 237, 184, .13)", icon: "spark" };
    }

    const defaultWinAvatars = [
      "assets/avatars/win-avatar-01.png",
      "assets/avatars/win-avatar-02.png",
      "assets/avatars/win-avatar-03.png",
      "assets/avatars/win-avatar-04.png",
      "assets/avatars/win-avatar-05.png",
      "assets/avatars/win-avatar-06.png",
      "assets/avatars/win-avatar-07.png",
      "assets/avatars/win-avatar-08.png",
      "assets/avatars/win-avatar-09.png",
      "assets/avatars/win-avatar-10.png",
      "assets/avatars/win-avatar-11.png",
      "assets/avatars/win-avatar-12.png",
      "assets/avatars/win-avatar-13.png",
      "assets/avatars/win-avatar-14.png"
    ];

    function winAvatarUrl(win) {
      if (isUsableImageUrl(win?.avatarUrl)) return win.avatarUrl;
      if (isUsableImageUrl(win?.userImageUrl)) return win.userImageUrl;
      const key = `${win?.displayName || "anonymous"}-${win?.id || win?.headline || "win"}`;
      return defaultWinAvatars[stableWinHash(key) % defaultWinAvatars.length];
    }

    function winCategoryShortLabel(category) {
      return ({
        "Pounds Lost": "Progress",
        "Non-Scale Victory": "Victory",
        "Protein Win": "Protein",
        "Meal Hack": "Meal",
        "Water Win": "Hydration",
        "Movement": "Movement",
        "First Month": "Week",
        "Motivation": "Mindset",
        "Maintenance": "Consistency",
        "Getting Started": "Start"
      })[category] || "Win";
    }

    function winCategoryFilterLabel(category) {
      return ({
        "All": "All",
        "Pounds Lost": "Lbs Lost",
        "Non-Scale Victory": "NSV",
        "Protein Win": "Protein",
        "Water Win": "Water",
        "Movement": "Move",
        "Meal Hack": "Meals",
        "First Month": "Month 1",
        "Motivation": "Mindset",
        "Maintenance": "Maintain",
        "Getting Started": "Start"
      })[category] || category;
    }

    const mapPrototypeTargetPerCategory = 4;
    const communityMapFillerBank = [
      { id: "map-filler-pounds-clothes", headline: "Clothes fit better", category: "Pounds Lost", weekNumber: 5, cheers: 18, isVisualOnly: true },
      { id: "map-filler-pounds-jeans", headline: "Jeans fit easier", category: "Pounds Lost", weekNumber: 8, cheers: 23, isVisualOnly: true },
      { id: "map-filler-pounds-waist", headline: "Waist feels looser", category: "Pounds Lost", weekNumber: 7, cheers: 20, isVisualOnly: true },
      { id: "map-filler-pounds-progress", headline: "Progress showing", category: "Pounds Lost", weekNumber: 6, cheers: 21, isVisualOnly: true },
      { id: "map-filler-nsv-sleep", headline: "Better sleep", category: "Non-Scale Victory", weekNumber: 7, cheers: 22, isVisualOnly: true },
      { id: "map-filler-nsv-energy", headline: "More energy", category: "Non-Scale Victory", weekNumber: 6, cheers: 16, isVisualOnly: true },
      { id: "map-filler-nsv-mood", headline: "Lifted mood", category: "Non-Scale Victory", weekNumber: 4, cheers: 17, isVisualOnly: true },
      { id: "map-filler-nsv-confident", headline: "More confident", category: "Non-Scale Victory", weekNumber: 8, cheers: 24, isVisualOnly: true },
      { id: "map-filler-protein-breakfast", headline: "Protein breakfast", category: "Protein Win", weekNumber: 2, cheers: 17, isVisualOnly: true },
      { id: "map-filler-protein-high", headline: "Kept protein high", category: "Protein Win", weekNumber: 5, cheers: 20, isVisualOnly: true },
      { id: "map-filler-protein-snack", headline: "Protein snack", category: "Protein Win", weekNumber: 3, cheers: 14, isVisualOnly: true },
      { id: "map-filler-protein-first", headline: "Protein first", category: "Protein Win", weekNumber: 4, cheers: 16, isVisualOnly: true },
      { id: "map-filler-water-no-soda", headline: "No soda", category: "Water Win", weekNumber: 2, cheers: 16, isVisualOnly: true },
      { id: "map-filler-water-hydration", headline: "Hydration wins", category: "Water Win", weekNumber: 4, cheers: 13, isVisualOnly: true },
      { id: "map-filler-water-less-soda", headline: "Less soda", category: "Water Win", weekNumber: 4, cheers: 13, isVisualOnly: true },
      { id: "map-filler-water-first", headline: "Water first", category: "Water Win", weekNumber: 2, cheers: 12, isVisualOnly: true },
      { id: "map-filler-move-steps", headline: "Hit my steps", category: "Movement", weekNumber: 3, cheers: 15, isVisualOnly: true },
      { id: "map-filler-move-walks", headline: "Morning walks", category: "Movement", weekNumber: 6, cheers: 19, isVisualOnly: true },
      { id: "map-filler-move-dinner", headline: "Walked after dinner", category: "Movement", weekNumber: 5, cheers: 17, isVisualOnly: true },
      { id: "map-filler-move-streak", headline: "Step streak", category: "Movement", weekNumber: 8, cheers: 19, isVisualOnly: true },
      { id: "map-filler-meal-rollups", headline: "Turkey roll-ups", category: "Meal Hack", weekNumber: 7, cheers: 14, isVisualOnly: true },
      { id: "map-filler-meal-prep", headline: "Meal prep", category: "Meal Hack", weekNumber: 6, cheers: 15, isVisualOnly: true },
      { id: "map-filler-meal-lunch", headline: "Easy lunch", category: "Meal Hack", weekNumber: 5, cheers: 18, isVisualOnly: true },
      { id: "map-filler-meal-plan", headline: "Planned dinner", category: "Meal Hack", weekNumber: 4, cheers: 12, isVisualOnly: true },
      { id: "map-filler-month-week4", headline: "Week 4", category: "First Month", weekNumber: 4, cheers: 11, isVisualOnly: true },
      { id: "map-filler-month-showed", headline: "Kept showing up", category: "First Month", weekNumber: 4, cheers: 19, isVisualOnly: true },
      { id: "map-filler-month-checkin", headline: "Checked in", category: "First Month", weekNumber: 3, cheers: 15, isVisualOnly: true },
      { id: "map-filler-month-start", headline: "First month", category: "First Month", weekNumber: 4, cheers: 18, isVisualOnly: true },
      { id: "map-filler-motivation-working", headline: "This is working", category: "Motivation", weekNumber: 4, cheers: 21, isVisualOnly: true },
      { id: "map-filler-motivation-patient", headline: "Stayed patient", category: "Motivation", weekNumber: 7, cheers: 20, isVisualOnly: true },
      { id: "map-filler-motivation-focused", headline: "Stayed focused", category: "Motivation", weekNumber: 3, cheers: 12, isVisualOnly: true },
      { id: "map-filler-motivation-belief", headline: "Kept believing", category: "Motivation", weekNumber: 6, cheers: 22, isVisualOnly: true },
      { id: "map-filler-maint-showing", headline: "Kept showing up", category: "Maintenance", weekNumber: 9, cheers: 25, isVisualOnly: true },
      { id: "map-filler-maint-consistent", headline: "Stayed consistent", category: "Maintenance", weekNumber: 6, cheers: 23, isVisualOnly: true },
      { id: "map-filler-maint-lunch", headline: "Consistent lunch", category: "Maintenance", weekNumber: 5, cheers: 18, isVisualOnly: true },
      { id: "map-filler-maint-routine", headline: "Kept routine", category: "Maintenance", weekNumber: 8, cheers: 21, isVisualOnly: true },
      { id: "map-filler-start-momentum", headline: "Small moments", category: "Getting Started", weekNumber: 1, cheers: 10, isVisualOnly: true },
      { id: "map-filler-start-checkin", headline: "Checked in", category: "Getting Started", weekNumber: 1, cheers: 9, isVisualOnly: true },
      { id: "map-filler-start-focused", headline: "Stayed focused", category: "Getting Started", weekNumber: 3, cheers: 12, isVisualOnly: true },
      { id: "map-filler-start-first-step", headline: "First step", category: "Getting Started", weekNumber: 1, cheers: 11, isVisualOnly: true }
    ];

    function realWinCategories() {
      return categories.filter(category => category !== "All");
    }

    function balancedCommunityMapWins(wins, compact = false) {
      if (compact) return wins;
      const allowedCategories = realWinCategories();
      const visibleCategories = state.filter === "All" ? allowedCategories : [state.filter].filter(category => allowedCategories.includes(category));
      if (!visibleCategories.length) return wins;
      const counts = Object.fromEntries(visibleCategories.map(category => [category, wins.filter(win => win.category === category).length]));
      const target = Math.max(mapPrototypeTargetPerCategory, ...Object.values(counts));
      const fillers = visibleCategories.flatMap(category => {
        const needed = Math.max(0, target - (counts[category] || 0));
        return communityMapFillerBank
          .filter(win => win.category === category)
          .slice(0, needed);
      });
      return [...wins, ...fillers];
    }

    function stableWinHash(value) {
      return String(value || "").split("").reduce((sum, char) => ((sum * 31) + char.charCodeAt(0)) % 997, 17);
    }

    function clampNumber(value, min, max) {
      return Math.max(min, Math.min(max, value));
    }

    function winMapBaseWeight(win, index, compact) {
      const hash = stableWinHash(`${win.id}-${win.category}`);
      if (compact) return 7 + ((hash + index) % 3);
      const heroBoost = win.id === "w1" ? 48 : 0;
      const featuredBoost = win.isFeatured ? 20 : 0;
      const visualOnlyTrim = win.isVisualOnly ? -2 : 0;
      return Math.max(4, 8 + ((hash + index) % 4) * 1.4 + featuredBoost / 10 + heroBoost / 10 + visualOnlyTrim);
    }

    function winMapCategoryCenter(category, compact = false) {
      const region = winMapRegion(category);
      if (!compact) return { x: region.x, y: region.y };
      return {
        x: 360 + (region.x - 520) * 1.08,
        y: 360 + (region.y - 670) * 1.02
      };
    }

    function winMapBubbleSize(basePercentage, compact) {
      const radius = WinsBubbleMath.calculateBubbleRadius(basePercentage, compact ? 25 : 34, compact ? 56 : 108);
      return Math.round(radius * 2);
    }

    function winMapBaseCenter(win, index, compact) {
      const region = winMapCategoryCenter(win.category, compact);
      const hash = stableWinHash(`${win.id}-${win.headline}`);
      const ring = compact ? 34 + ((hash + index) % 36) : 18 + ((hash + index) % 34);
      const angle = ((hash * 37) % 360) * Math.PI / 180;
      return {
        x: region.x + Math.cos(angle) * ring + ((index % 3) - 1) * (compact ? 10 : 14),
        y: region.y + Math.sin(angle) * ring + ((index % 4) - 1.5) * (compact ? 9 : 12)
      };
    }

    function winMapLayout(wins, compact = false) {
      const world = compact
        ? { minX: 0, minY: 0, maxX: 720, maxY: 720 }
        : { minX: 245, minY: 330, maxX: 790, maxY: 980 };
      const categoryCenters = Object.fromEntries(categories.filter(category => category !== "All").map(category => {
        const region = winMapCategoryCenter(category, compact);
        return [category, { x: region.x, y: region.y }];
      }));
      const input = wins.map((win, index) => {
        const base = winMapBaseCenter(win, index, compact);
        return {
          id: win.id,
          win,
          category: win.category,
          baseWeight: winMapBaseWeight(win, index, compact),
          minPercentage: compact ? 6.5 : 2.55,
          maxPercentage: win.id === "w1" ? 28 : 18,
          x: base.x,
          y: base.y,
          anchorX: base.x,
          anchorY: base.y,
          relationshipWeights: win.relationshipWeights,
          label: winMapLabel(win)
        };
      });
      const packed = WinsBubbleMath.derivePackedBubbleLayout(input, compact ? { width: 360, height: 360 } : { width: 390, height: 720 }, {
        world,
        categoryCenters,
        minRadius: compact ? 27 : 38,
        sizeRange: compact ? 60 : 92,
        maxSizeRangeMultiplier: compact ? 1.38 : 1.18,
        targetFillRatio: compact ? 0.66 : 0.86,
        desiredGap: compact ? 4 : 4,
        minGap: compact ? 1.5 : 4,
        relationshipTightening: compact ? 8 : 18,
        sameCategoryAttraction: compact ? 0.16 : 0.2,
        globalAttraction: compact ? 0 : 0.055,
        attractionStrength: compact ? 0.012 : 0.045,
        attractionRange: compact ? 190 : 620,
        anchorStrength: compact ? 0.05 : 0.008,
        separationStrength: compact ? 0.54 : 0.92,
        overlapSeparationStrength: compact ? 0.7 : 0.9,
        cropAllowance: compact ? 8 : 215,
        iterations: compact ? 8 : 48,
        overlapIterations: compact ? 8 : 76,
        overlapTolerance: compact ? 0.5 : 0.08
      });
      return packed.map(item => {
        const size = Math.round(item.radius * 2);
        return {
          win: item.win,
          size,
          basePercentage: item.currentPercentage,
          x: Math.round(item.x - size / 2),
          y: Math.round(item.y - size / 2)
        };
      });
    }

    function winMapLabel(win) {
      const headline = String(win.headline || win.category || "Win").replace(/[!.]/g, "").trim();
      const compactLabels = {
        "Protein coffee hack": "Protein coffee",
        "First month complete": "First month",
        "My easy lunch idea": "Easy lunch",
        "Walked 4 days": "Short walks",
        "No soda this week": "No soda",
        "Back in my jeans": "Jeans fit",
        "Down 10 lbs": "Down 10 lbs",
        "Kept protein high": "Protein high",
        "Kept showing up": "Showing up",
        "Stayed consistent": "Consistent",
        "Progress showing": "Progress",
        "Hydration wins": "Hydration",
        "Checked in": "Checked in"
      };
      if (compactLabels[headline]) return compactLabels[headline];
      if (headline.length <= 20) return headline;
      const words = headline.split(/\s+/).slice(0, 3).join(" ");
      return words.length > 20 ? words.slice(0, 18).trim() : words;
    }

    function visibleWinsForMap(wins, compact = false) {
      return balancedCommunityMapWins(wins, compact);
    }

    function findCommunityMapWin(id) {
      return communityMapFillerBank.find(win => win.id === id);
    }

    function bubbleMarkup(wins, compact = false) {
      const mapWins = visibleWinsForMap(wins, compact);
      if (!mapWins.length) return `<div class="empty">No wins match this category yet.</div>`;
      const worldClass = compact ? "wins-map-world compact" : "wins-map-world";
      const mapOffset = compact ? (state.winPreviewMapOffset || { x: 0, y: 0 }) : (state.winMapOffset || { x: 0, y: 0 });
      const offsetStyle = ` style="--map-x:${Number(mapOffset.x) || 0}px;--map-y:${Number(mapOffset.y) || 0}px"`;
      const layout = winMapLayout(mapWins, compact);
      return `<div class="${worldClass}"${offsetStyle}>${layout.map(({ win: w, size, basePercentage, x, y }, i) => {
        const region = winMapRegion(w.category);
        const hasUploadedPhoto = isUsableImageUrl(w.imageUrl);
        const usesHumanSurface = hasUploadedPhoto || !w.isVisualOnly;
        const label = winMapLabel(w);
        const categoryShortLabel = winCategoryShortLabel(w.category);
        const surfaceImageUrl = hasUploadedPhoto ? w.imageUrl : winAvatarUrl(w);
        const meta = w.isVisualOnly ? (w.weekNumber ? `Week ${w.weekNumber}` : categoryShortLabel) : `${Number(w.cheers) || 0} cheers`;
        const visual = usesHumanSurface
          ? `<img class="win-map-photo" src="${escapeAttr(surfaceImageUrl)}" alt=""><span class="win-map-photo-content"><span class="win-map-label">${escapeHtml(label)}</span></span>`
          : `<span class="win-map-content"><span class="win-map-label">${escapeHtml(label)}</span><span class="win-map-text-mark" aria-hidden="true">${icon(region.icon)}</span></span>`;
        const mapId = escapeAttr(w.id || `map-${i}`);
        const sizeClass = size < 96 ? "micro" : size < 108 ? "small" : "";
        const commonAttrs = `class="win-map-bubble win-map-${region.accent} ${usesHumanSurface ? "photo" : "text"} ${sizeClass} ${w.isVisualOnly ? "prototype-win" : ""} ${w.isHidden ? "hidden-post" : ""}" data-map-id="${mapId}" data-base-percentage="${basePercentage.toFixed(4)}" style="--size:${size}px;--x:${x}px;--y:${y}px;--bubble-bg:${region.bg};--bubble-ink:${region.ink};--bubble-highlight:${region.highlight};--bubble-sheen:${region.sheen}"`;
        if (w.isVisualOnly) {
          return `<button ${commonAttrs} data-win="${w.id}" aria-label="${escapeAttr(`${w.headline}. ${w.category}. ${w.cheers} cheers. Prototype community win.`)}">
          ${visual}
          <span class="win-map-meta">${escapeHtml(meta)}</span>
        </button>`;
        }
        return `<button ${commonAttrs} data-win="${w.id}" aria-label="${escapeAttr(`${w.headline}. ${w.category}. ${w.cheers} cheers.`)}">
          ${visual}
          <span class="win-map-meta">${escapeHtml(meta)}</span>
        </button>`;
      }).join("")}</div>`;
    }

    function wins() {
      return `
        <section class="screen active wins-map-screen">
          <div class="wins-map-shell">
            <div class="wins-map-controls">
              <div class="wins-map-title">
                <span class="wins-title-mark" aria-hidden="true"><img src="assets/leaner-logo.png" alt=""></span>
                <span>
                <p class="eyebrow">Community momentum</p>
                <h1>Leaner Wins</h1>
                </span>
              </div>
              <button class="secondary wins-share" data-route="submit">Share your win</button>
              <div class="filters wins-map-filters" aria-label="Filter wins by category">${categories.map(c => `<button class="chip ${state.filter === c ? "active" : ""}" data-filter="${escapeAttr(c)}" aria-label="${escapeAttr(c)}" title="${escapeAttr(c)}">${escapeHtml(winCategoryFilterLabel(c))}</button>`).join("")}</div>
              <p class="wins-helper">${icon("spark")} Drag to explore. Tap to read.</p>
            </div>
            <div class="wins-board wins-map" id="fullBoard">${bubbleMarkup(visibleWins())}</div>
          </div>
        </section>`;
    }

    function submitWin(prefill = {}) {
      return `
        <section class="screen active">
          <div class="hero">
            <p class="eyebrow">Share encouragement</p>
            <h1>Share a Win</h1>
            <p class="subhead">Post automatically to the Leaner Wins Board. Admin can remove posts afterward if needed.</p>
          </div>
          <section class="panel">
            <p class="notice">Please do not share private medical details, dose instructions, or urgent symptoms. Your post may be visible to other Leaner patients.</p>
            <form class="form" id="winForm">
              <label>Headline <input required name="headline" maxlength="48" value="${escapeAttr(prefill.headline || "")}" placeholder="Down 5 lbs!"></label>
              <label>Short details <textarea required name="details" maxlength="220" placeholder="What made this feel like a win?">${escapeHtml(prefill.details || "")}</textarea></label>
              <label>Category <select name="category">${categories.filter(c => c !== "All").map(c => `<option ${prefill.category === c ? "selected" : ""}>${c}</option>`).join("")}</select></label>
              <div class="choice-row">
                <label class="choice"><input type="radio" name="display" value="anonymous" checked> Post anonymously</label>
                <label class="choice"><input type="radio" name="display" value="first"> Use first name</label>
                <label class="choice"><input type="radio" name="display" value="private"> Keep private</label>
              </div>
              <label>Optional week number <input name="weekNumber" type="number" min="1" max="104" value="${prefill.weekNumber || patient.currentWeek}"></label>
              <label>Optional photo <input name="photo" type="file" accept="image/*"></label>
              <label class="checkline"><input required name="consent" type="checkbox"> I understand this win may be shared with the Leaner community unless I choose to keep it private.</label>
              <div class="button-row"><button class="primary" type="submit">Post Win</button><button class="ghost" type="button" data-route="wins">Cancel</button></div>
            </form>
          </section>
        </section>`;
    }

    function checkin() {
      const suggestion = state.suggestedWin;
      const choice = (name, value, emoji, label, checked = false) => `
        <label class="checkin-choice">
          <input type="radio" name="${name}" value="${value}" ${checked ? "checked" : ""}>
          <span class="checkin-choice-emoji" aria-hidden="true">${emoji}</span>
          <span>${label}</span>
        </label>`;
      return `
        <section class="screen active">
          <div class="hero checkin-hero">
            <p class="eyebrow">Weekly rhythm</p>
            <h1>Weekly Check-In</h1>
            <p class="subhead">Quick update for your Leaner team. Takes about 30 seconds.</p>
          </div>
          <section class="panel checkin-panel">
            ${suggestion ? shareSuggestion(suggestion) : `
            <form class="form" id="checkinForm">
              <section class="checkin-section">
                <div>
                  <p class="eyebrow">Your progress</p>
                  <h2>Progress update</h2>
                </div>
                <label class="weight-field">Current weight
                  <span class="weight-input-wrap"><input required name="weight" type="number" step="0.1" placeholder="207"><span>lbs</span></span>
                  <small>Use your most recent weigh-in.</small>
                </label>
              </section>

              <section class="checkin-section">
                <div>
                  <p class="eyebrow">This week</p>
                  <h2>Tap what fits best</h2>
                </div>
                <fieldset class="checkin-choice-group">
                  <legend>Overall, I&apos;m feeling...</legend>
                  <div class="checkin-choice-grid">
                    ${choice("feeling", "good", "&#128522;", "Good", true)}
                    ${choice("feeling", "okay", "&#128528;", "Okay")}
                    ${choice("feeling", "struggling", "&#128533;", "Struggling")}
                    ${choice("feeling", "need_support", "&#128172;", "Need support")}
                  </div>
                </fieldset>
                <fieldset class="checkin-choice-group">
                  <legend>How was your hunger this week?</legend>
                  <div class="checkin-choice-grid">
                    ${choice("hunger", "1", "&#128578;", "Low")}
                    ${choice("hunger", "2", "&#128524;", "Manageable", true)}
                    ${choice("hunger", "3", "&#128556;", "Strong")}
                    ${choice("hunger", "4", "&#127384;", "Hard to control")}
                  </div>
                </fieldset>
                <fieldset class="checkin-choice-group">
                  <legend>How was your energy?</legend>
                  <div class="checkin-choice-grid">
                    ${choice("energy", "1", "&#128267;", "Low")}
                    ${choice("energy", "2", "&#128578;", "Okay")}
                    ${choice("energy", "3", "&#10024;", "Good")}
                    ${choice("energy", "4", "&#9889;", "Great", true)}
                  </div>
                </fieldset>
                <fieldset class="checkin-choice-group side-effect-group">
                  <legend>Any side effects this week?</legend>
                  <div class="checkin-choice-grid side-effect-grid">
                    ${choice("sideEffects", "no", "&#9989;", "No", true)}
                    ${choice("sideEffects", "mild", "&#127807;", "Mild")}
                    ${choice("sideEffects", "needs_help", "&#9888;", "Yes, I need help")}
                  </div>
                </fieldset>
                <label class="side-effect-note">Tell us what you noticed <small>Optional</small><textarea name="sideEffectsNote" placeholder="A quick note for your Leaner team..."></textarea></label>
              </section>

              <section class="checkin-section checkin-notes-section">
                <div>
                  <p class="eyebrow">Optional notes</p>
                  <h2>Want to share anything?</h2>
                  <p>Skip these if there is nothing to add.</p>
                </div>
                <label>Share a win <small>Optional</small><textarea name="weeklyWin" placeholder="Meal prep, walking, water, cravings, scale victory..."></textarea></label>
                <label>Need anything from Leaner? <small>Optional</small><textarea name="helpNeeded" placeholder="Question, concern, refill timing, appointment help..."></textarea></label>
              </section>

              <button class="primary checkin-submit" type="submit">Submit my check-in</button>
              <p class="notice checkin-notice">This check-in helps your Leaner team follow your progress. It does not replace medical advice or provide dose-change guidance. Please contact Leaner directly for medical questions or concerning symptoms.</p>
            </form>`}
          </section>
        </section>`;
    }

    function shareSuggestion(s) {
      return `
        <h2>Check-in submitted</h2>
        <p>You are down ${s.lost} lbs since starting. Want to share this win with the Leaner community?</p>
        <div class="card" style="margin-bottom:14px"><div class="metric-label">Suggested headline</div><div class="metric-value">${escapeHtml(s.headline)}</div></div>
        <div class="button-row">
          <button class="secondary" id="shareAnon">Share anonymously</button>
          <button class="ghost" id="editSuggestion">Edit before sharing</button>
          <button class="ghost" id="skipSuggestion">Skip</button>
        </div>`;
    }

    function progress() {
      const milestoneGoal = 10;
      const milestoneRemaining = Math.max(0, milestoneGoal - patient.totalLost);
      const milestonePercent = Math.min(100, Math.round((patient.totalLost / milestoneGoal) * 100));
      const earnedBadges = [
        ["calendar", "First Check-In", "earned"],
        ["star", "First 5 lbs", "earned"],
        ["flame", "4-Week Streak", "earned"]
      ];
      const nextBadges = [
        ["spark", "First 10 lbs", "locked"],
        ["tip", "Protein Win", "locked"],
        ["trend", "Movement Win", "locked"]
      ];
      const timeline = [
        { week: `Week ${patient.currentWeek}`, weight: `${patient.currentWeight} lbs`, note: `Focus: ${patient.weeklyFocus}` },
        { week: "Week 3", weight: "209 lbs", note: "Note: Better water week" },
        { week: "Week 2", weight: "211 lbs", note: "Note: First routine started" }
      ];
      return `
        <section class="screen active">
          <div class="hero"><p class="eyebrow">My Progress</p><h1>Clear, steady progress.</h1><p class="subhead">Simple trends, check-in streaks, and milestones without turning the app into a calorie tracker.</p></div>
          <section class="progress-story-hero">
            <div class="progress-story-copy">
              <p class="eyebrow">Current momentum</p>
              <h2>${patient.totalLost} lbs down</h2>
              <p class="milestone-hook">${milestoneRemaining} lbs from your first 10 lb milestone.</p>
              <div class="program-status-row">
                <span>${icon("calendar")} Week ${patient.currentWeek}</span>
                <span>${icon("calendar")} Next visit ${patient.nextVisitDate}</span>
                <span>${icon("tip")} ${patient.weeklyFocus}</span>
              </div>
            </div>
            <div class="milestone-bar-block" style="--milestone:${milestonePercent}%">
              <div class="milestone-bar-copy">
                <span>First 10 lb milestone</span>
                <strong>${patient.totalLost} of ${milestoneGoal} lbs complete</strong>
                <em>${milestoneRemaining} lbs to go</em>
              </div>
              <div class="milestone-progress-track"><div></div></div>
            </div>
          </section>
          <section class="progress-snapshot-section">
            <div class="section-heading"><div><p class="eyebrow">Snapshot</p><h2>Progress snapshot</h2></div></div>
          <section class="progress-stat-strip">
            <div class="progress-stat baseline"><span>Starting Weight</span><strong>${patient.startingWeight} lbs</strong></div>
            <div class="progress-stat current"><span>Current Weight</span><strong>${patient.currentWeight} lbs</strong></div>
            <div class="progress-stat achievement"><span>Total Lost</span><strong>${patient.totalLost} lbs</strong></div>
            <div class="progress-stat streak"><span>Check-In Streak</span><strong>${patient.checkInStreak} weeks</strong></div>
          </section>
          </section>
          <section class="panel">
            <div class="section-heading"><div><p class="eyebrow">Journey</p><h2>Progress journey</h2><p>Milestone-based progress without turning the page into a weigh-in tracker.</p></div></div>
            <div class="progress-journey-card" style="--journey-progress:${milestonePercent}%">
              <div class="journey-summary">
                <strong>${patient.startingWeight} lbs starting &rarr; ${patient.currentWeight} lbs current</strong>
                <span>You're ${milestoneRemaining} lbs from your first 10 lb milestone.</span>
              </div>
              <div class="journey-path" aria-label="${patient.totalLost} of ${milestoneGoal} pounds complete toward first 10 pound milestone">
                <div class="journey-track"><span></span></div>
                <div class="journey-point start">
                  <i></i>
                  <strong>Start</strong>
                  <span>${patient.startingWeight} lbs</span>
                </div>
                <div class="journey-point current">
                  <em>${patient.totalLost} lbs down</em>
                  <i></i>
                  <strong>Current</strong>
                  <span>${patient.currentWeight} lbs</span>
                </div>
                <div class="journey-point milestone">
                  <em>${milestoneRemaining} lbs to go</em>
                  <i></i>
                  <strong>First 10 lb milestone</strong>
                  <span>${milestoneGoal} lbs</span>
                </div>
              </div>
            </div>
            <div class="progress-note">
              <h3>Progress note</h3>
              <p>Steady progress is still progress. Keep this week simple: check in, prioritize protein, and stay consistent before your next visit.</p>
            </div>
          </section>
          <section class="panel">
            <div class="section-heading"><div><p class="eyebrow">Milestones</p><h2>Milestone badges</h2></div></div>
            <h3 class="badge-section-title">Earned badges</h3>
            <div class="achievement-grid">${earnedBadges.map(([iconName, label, stateName]) => `<article class="achievement-badge ${stateName}">${icon(iconName)}<div><strong>${label}</strong><span>Earned</span></div></article>`).join("")}</div>
            <h3 class="badge-section-title">Coming up next</h3>
            <div class="achievement-grid">${nextBadges.map(([iconName, label, stateName]) => `<article class="achievement-badge ${stateName}">${icon(iconName)}<div><strong>${label}</strong><span>Coming up</span></div></article>`).join("")}</div>
          </section>
          <section class="panel">
            <div class="section-heading"><div><p class="eyebrow">Check-ins</p><h2>Recent check-ins</h2></div></div>
            <div class="checkin-timeline">${timeline.map(item => `<article><div class="timeline-dot"></div><div><h3>${item.week} &mdash; ${item.weight}</h3><p>${escapeHtml(item.note)}</p></div></article>`).join("")}</div>
          </section>
        </section>`;
    }

    function earningRows() {
      const rows = [
        ["calendar", "checkin", POINT_RULES.weekly_check_in],
        ["trend", "progress", POINT_RULES.progress_update],
        ["heart", "private", POINT_RULES.private_win],
        ["users", "share", POINT_RULES.shared_win],
        ["heart", "celebrate", POINT_RULES.celebrate_win],
        ["tip", "save", POINT_RULES.save_tip]
      ];
      return rows.map(([iconName, tone, rule], index) => `<div class="momentum-row momentum-step momentum-${tone} ${index < 2 ? "complete" : ""}">${icon(iconName)}<div><h3>${rule.label}</h3><p style="margin:0">${rule.limitLabel}</p></div><span class="points-pill">+${rule.points}</span></div>`).join("");
    }

    function weeklyMomentumStatus() {
      return `<section class="weekly-momentum-status">
        <p class="eyebrow">This week's momentum</p>
        <h2>2 of 5 actions complete</h2>
        <p>You can still earn 70 points this week.</p>
      </section>`;
    }

    function rewardsAheadPreview() {
      const previews = [
        ["$10 Leaner Credit", "250 pts"],
        ["Product discount", "400 pts"],
        ["Bonus support perk", "600 pts"]
      ];
      return `<section class="rewards-ahead">
        <div class="section-heading"><div><p class="eyebrow">Rewards ahead</p><h2>Keep building toward perks</h2></div></div>
        <div class="rewards-preview-list">${previews.map(([title, points]) => `<article><span>${escapeHtml(title)}</span><strong>${escapeHtml(points)}</strong></article>`).join("")}</div>
      </section>`;
    }

    function rewardRow(reward) {
      const status = rewardStatus(reward);
      const requested = status === REWARD_STATUSES.REQUESTED;
      const redeemed = status === REWARD_STATUSES.REDEEMED;
      const available = status === REWARD_STATUSES.AVAILABLE;
      return `<article class="reward-row">
        ${icon(rewardIcon(reward.icon))}
        <div>
          <h3>${escapeHtml(reward.title)}</h3>
          <p style="margin-bottom:8px">${escapeHtml(reward.description)}</p>
          <div class="status-row"><span class="status-pill">${tierLabel(reward.tier)}</span><span class="status-pill">${reward.pointsCost} points</span><span class="status-pill ${available ? "" : requested ? "warn" : redeemed ? "" : "danger"}">${rewardStatusLabel(status)}</span></div>
        </div>
        <div class="reward-actions">
          ${available ? `<button class="secondary" data-request-reward="${reward.id}">Request Reward</button>` : ""}
          ${status === REWARD_STATUSES.LOCKED ? `<button class="ghost" disabled>${Math.max(0, reward.pointsCost - state.pointsBalance)} points to go</button>` : ""}
        </div>
      </article>`;
    }

    function featuredPerkCard(compact = false) {
      const perk = featuredReward();
      if (!perk) return "";
      const status = rewardStatus(perk);
      return `<section class="featured-perk ${compact ? "home-featured-perk" : ""}">
        <div class="momentum-row" style="border-bottom:0;padding-top:0">
          ${icon(rewardIcon(perk.icon))}
          <div>
            <p class="eyebrow">This Month's Featured Perk</p>
            <h2>${escapeHtml(perk.title)}</h2>
            <p>${escapeHtml(perk.description)}</p>
            <div class="status-row"><span class="status-pill">${perk.pointsCost} points</span><span class="status-pill">${rewardStatusLabel(status)}</span></div>
          </div>
        </div>
        ${status === REWARD_STATUSES.AVAILABLE ? `<button class="secondary" data-request-reward="${perk.id}" style="margin-top:10px">Request Featured Perk</button>` : ""}
      </section>`;
    }

    function supportOptions(type, selectedId) {
      return state.supportContent
        .filter(item => item.type === type && item.status !== CONTENT_STATUSES.ARCHIVED && item.status !== CONTENT_STATUSES.DRAFT)
        .map(item => `<option value="${item.id}" ${item.id === selectedId ? "selected" : ""}>${escapeHtml(item.title)} (${item.status})</option>`)
        .join("");
    }

    function supportQueueCard(type) {
      const count = unusedApprovedCount(type);
      const [label, tone] = queueHealth(count);
      return `<article class="admin-record">
        <div>
          <h3>${supportLabel(type)}</h3>
          <div class="record-meta">${count} weeks remaining</div>
        </div>
        <span class="status-pill ${tone}">${label}</span>
      </article>`;
    }

    function csvImportPanel() {
      const result = state.csvImport;
      const summary = result ? {
        valid: result.validRows?.length || 0,
        warnings: result.rows?.filter(row => row.warnings.length).length || 0,
        errors: (result.rows?.filter(row => row.errors.length).length || 0) + (result.errors?.length || 0)
      } : null;
      return `<section class="csv-panel">
        <div>
          <h3>Bulk upload support content</h3>
          <p>Upload meal ideas, coach tips, and clinic support messages in bulk. Use pipe-separated tags like <strong>high-protein|easy-meal</strong>. Only approved items rotate into the patient dashboard.</p>
        </div>
        <div class="csv-actions">
          <button class="ghost" type="button" id="downloadCsvTemplate">Download Template</button>
          <label class="secondary" for="supportCsvFile" style="width:auto">Upload CSV</label>
          <input class="csv-file" id="supportCsvFile" type="file" accept=".csv,text/csv">
        </div>
        ${result ? `<div class="admin-record">
          <h3>${result.imported ? "Content imported successfully." : summary.errors ? "Some rows need attention before they can be imported." : "CSV ready to import."}</h3>
          <div class="csv-summary">
            ${metric("Rows found", result.totalRows || 0)}
            ${metric("Valid rows", summary.valid)}
            ${metric("Warnings", summary.warnings)}
            ${metric("Errors", summary.errors)}
          </div>
          ${result.imported ? `<p class="notice">${result.importedCount} support content items imported into the local content library.</p>` : ""}
          ${result.errors?.length ? result.errors.map(error => `<p class="notice">${escapeHtml(error)}</p>`).join("") : ""}
          ${result.rows?.length ? `<div class="admin-list" style="margin-top:12px">${result.rows.slice(0, 12).map(row => `<article class="admin-record">
            <div>
              <h3>Row ${row.rowNumber}: ${escapeHtml(row.data.title || "Untitled")}</h3>
              <div class="record-meta">${escapeHtml(row.data.type || "Missing type")} &middot; ${escapeHtml(row.data.status || "Missing status")}</div>
            </div>
            <div class="status-row">
              <span class="status-pill ${row.isValid ? "" : "danger"}">${row.isValid ? "Valid" : "Error"}</span>
              ${row.warnings.length ? `<span class="status-pill warn">${row.warnings.length} warning${row.warnings.length === 1 ? "" : "s"}</span>` : ""}
            </div>
            ${row.errors.concat(row.warnings).map(message => `<p style="margin:0">${escapeHtml(message)}</p>`).join("")}
          </article>`).join("")}</div>` : ""}
          ${summary.valid && !result.imported ? `<button class="secondary" id="importCsvRows" style="margin-top:12px">Import Valid Rows</button>` : ""}
        </div>` : ""}
      </section>`;
    }

    function rewardPackageEditor(reward) {
      const tiers = Object.values(REWARD_TIERS);
      const icons = ["gift", "ticket", "badge", "star", "trophy", "spark"];
      return `<article class="admin-record">
        <form class="reward-editor" data-reward-form="${reward.id}">
          <div>
            <h3>${escapeHtml(tierLabel(reward.tier))}</h3>
            <p class="record-meta">${escapeHtml(reward.id)} &middot; Updated ${escapeHtml(reward.updatedAt || "Not set")}</p>
          </div>
          <div class="reward-editor-grid">
            <label>Tier <select name="tier">${tiers.map(tier => `<option value="${tier}" ${reward.tier === tier ? "selected" : ""}>${tierLabel(tier)}</option>`).join("")}</select></label>
            <label>Points required <input name="pointsCost" type="number" min="1" value="${Number(reward.pointsCost) || 1}"></label>
          </div>
          <label>Title <input name="title" required maxlength="80" value="${escapeAttr(reward.title)}"></label>
          <label>Description <textarea name="description" required maxlength="240">${escapeHtml(reward.description)}</textarea></label>
          <div class="reward-editor-grid">
            <label>Icon <select name="icon">${icons.map(value => `<option value="${value}" ${reward.icon === value ? "selected" : ""}>${value}</option>`).join("")}</select></label>
            <label>Fine print / internal note <input name="finePrint" value="${escapeAttr(reward.finePrint || "")}"></label>
          </div>
          <div class="choice-row">
            <label class="choice"><input type="checkbox" name="isActive" ${reward.isActive ? "checked" : ""}> Active</label>
            <label class="choice"><input type="checkbox" name="isFeatured" ${reward.isFeatured ? "checked" : ""}> Featured</label>
          </div>
          <button class="secondary">Save Reward Package</button>
        </form>
      </article>`;
    }

    function rewardAdminPanel() {
      const requests = state.redemptions.length ? state.redemptions.map(item => {
        const status = normalizeRewardStatus(item.status);
        return `<article class="admin-record">
        <div>
          <h3>${escapeHtml(item.rewardTitle)}</h3>
          <div class="record-meta">${item.pointsCost} points &middot; Requested ${item.requestedAt}</div>
        </div>
        <div class="status-row"><span class="status-pill ${status === REWARD_STATUSES.REQUESTED ? "warn" : ""}">${rewardStatusLabel(status)}</span></div>
        ${status === REWARD_STATUSES.REQUESTED ? `<button class="secondary" data-redeem="${item.id}">Mark Redeemed</button>` : ""}
      </article>`;
      }).join("") : `<div class="empty">No reward requests yet.</div>`;
      return `<h2>Momentum Rewards</h2>
        <p class="notice">Edit reward package details while keeping the simple Momentum Points tier system stable. Staff still applies requested rewards manually.</p>
        <div class="admin-list">${state.rewards.map(rewardPackageEditor).join("")}</div>
        <h2 style="margin-top:22px">Reward Requests</h2>
        <div class="admin-list">${requests}</div>`;
    }

    function momentum() {
      return `
        <section class="screen active">
          <div class="hero">
            <p class="eyebrow">Momentum Points</p>
            <h1>Build momentum, one steady step at a time.</h1>
            <p class="subhead">Leaner recognizes consistency, check-ins, private wins, and supportive community actions. Points are not based on pounds lost or speed of weight loss.</p>
          </div>
          ${momentumSummary()}
          <section class="panel">
            ${weeklyMomentumStatus()}
            <div class="section-heading"><div><p class="eyebrow">This week</p><h2>Build momentum this week</h2><p>Healthy engagement earns points, with simple weekly caps to keep it fair.</p></div></div>
            <div class="earn-list">${earningRows()}</div>
          </section>
          ${rewardsAheadPreview()}
          <section class="panel">
            ${featuredPerkCard()}
          </section>
          <section class="panel">
            <div class="section-heading"><div><p class="eyebrow">Rewards</p><h2>Leaner perks</h2><p>Request a reward when it is available. Staff manually applies it outside the app for now.</p></div></div>
            <div class="reward-list">${activeRewardTiers().map(rewardRow).join("")}</div>
          </section>
          <section class="panel">
            <div class="section-heading"><div><p class="eyebrow">Recent activity</p><h2>Momentum activity</h2></div></div>
            <div class="activity-list">${state.pointEvents.slice(0, 8).map(event => `<div class="momentum-row">${icon(event.points < 0 ? "gift" : "spark")}<div><h3>${escapeHtml(event.description)}</h3><p style="margin:0">${event.createdAt}</p></div><span class="points-pill">${event.points > 0 ? "+" : ""}${event.points}</span></div>`).join("")}</div>
          </section>
        </section>`;
    }

    function mealIdeaRow(idea) {
      const isSaved = state.savedMealIdeas.includes(idea.id);
      const isExpanded = state.expandedMealWhy === idea.id;
      const showToast = state.mealSaveToast === idea.id;
      return `<article class="meal-idea-row ${isExpanded ? "open" : ""}">
        <div class="meal-row-main">
          <div>
            <h3>${escapeHtml(idea.name)}</h3>
            <p>${escapeHtml(idea.description)}</p>
            <div class="meal-tag-row"><span class="protein-badge">${escapeHtml(idea.protein)}</span>${idea.tags.map(tag => `<span>${escapeHtml(tag)}</span>`).join("")}</div>
          </div>
          <button class="save-meal-icon ${isSaved ? "saved" : ""}" data-save-meal="${idea.id}" aria-label="${isSaved ? "Saved" : "Save"} ${escapeHtml(idea.name)}">
            <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 4h12v17l-6-4-6 4z"></path></svg>
          </button>
        </div>
        <button class="why-toggle" data-meal-why="${idea.id}">${isExpanded ? "Hide why this works" : "Why this works"}</button>
        ${isExpanded ? `<p class="why-copy">${escapeHtml(idea.why)}</p>` : ""}
        ${showToast ? `<div class="save-toast">Saved +5 pts</div>` : ""}
      </article>`;
    }

    function mealDeck(deck, index) {
      const isOpen = state.mealDeckOpen === deck.id;
      return `<article class="meal-deck meal-deck-${deck.accent} ${isOpen ? "open" : ""}" style="--deck-index:${index}">
        <button class="meal-deck-cover" data-meal-deck="${deck.id}" aria-expanded="${isOpen}">
          ${icon(deck.icon)}
          <span>
            <strong>${escapeHtml(deck.title)}</strong>
            <em>${escapeHtml(deck.description)}</em>
          </span>
          <span class="deck-meta">${deck.ideas.length} ideas</span>
          <span class="deck-chevron">${isOpen ? "Close" : "Tap to open"} ›</span>
        </button>
        <div class="meal-deck-body">
          ${deck.ideas.slice(0, 3).map(mealIdeaRow).join("")}
        </div>
      </article>`;
    }

    function mealSnapshotPhoto() {
      if (state.mealSnapshotPhoto) {
        return `<img class="meal-snapshot-photo" src="${state.mealSnapshotPhoto}" alt="Uploaded meal preview">`;
      }
      return `<div class="meal-snapshot-fallback">${icon("fork")}<span>Sample meal preview</span></div>`;
    }

    function mealSnapshotUpload() {
      return `<section class="meal-snapshot-stage">
        <button class="snapshot-back-link" data-route="meals">&larr; Back to Meal Ideas</button>
        <div class="snapshot-intro">
          <p class="eyebrow">Meal Snapshot</p>
          <h1>Snap a meal. Get a simple estimate.</h1>
          <p>Use a photo from your camera or library. No photo is required to preview this mock experience.</p>
        </div>
        <label class="snapshot-uploader" for="mealSnapshotFile">
          <input id="mealSnapshotFile" type="file" accept="image/*" capture="environment">
          ${state.mealSnapshotPhoto ? mealSnapshotPhoto() : `${icon("fork")}<strong>Take or upload a meal photo</strong><span>Tap to choose a photo</span>`}
        </label>
        <p class="snapshot-disclaimer">Nutrition estimates are approximate. Use this as a simple guide, not a strict tracker.</p>
        <button class="primary snapshot-primary" id="buildMealSnapshot">Build my snapshot</button>
      </section>`;
    }

    function mealSnapshotConfirm() {
      const ingredients = state.mealSnapshotIngredients.length ? state.mealSnapshotIngredients : mockMealSnapshotResult.ingredients;
      return `<section class="meal-snapshot-stage">
        <button class="snapshot-back-link" data-snapshot-step="upload">&larr; Back</button>
        <div class="snapshot-intro compact">
          <p class="eyebrow">Meal Snapshot</p>
          <h1>Review your meal</h1>
          <p>Adjust anything that looks off before we estimate.</p>
        </div>
        <div class="snapshot-confirm-layout">
          <div class="snapshot-photo-compact">${mealSnapshotPhoto()}</div>
          <form id="mealSnapshotIngredientsForm" class="snapshot-ingredient-form">
            <div class="snapshot-meal-name"><strong>${escapeHtml(mockMealSnapshotResult.title)}</strong><span>Mock detected meal</span></div>
            <div class="snapshot-servings"><span>Serving(s)</span><strong>1</strong></div>
            <div class="snapshot-list-heading"><span>Detected ingredients</span><em>Portions are estimated</em></div>
            ${ingredients.map((item, index) => `<div class="snapshot-ingredient-row">
              <span class="ingredient-dot"></span>
              <label><span>Ingredient</span><input name="ingredient-${index}" value="${escapeHtml(item.name)}"></label>
              <label><span>Portion</span><input name="amount-${index}" value="${escapeHtml(item.amount)}"></label>
              <button type="button" class="snapshot-remove" data-remove-snapshot-ingredient="${index}" aria-label="Remove ${escapeHtml(item.name)}">&times;</button>
            </div>`).join("")}
            <button type="button" class="snapshot-add" id="addSnapshotIngredient">+ Add ingredient</button>
            <div class="snapshot-actions snapshot-confirm-actions">
              <button class="primary snapshot-primary" type="submit">Confirm meal</button>
              <button class="ghost" type="button" data-snapshot-step="upload">Back</button>
            </div>
          </form>
        </div>
      </section>`;
    }

    function mealSnapshotAnalyzing() {
      return `<section class="meal-snapshot-stage snapshot-analyzing" aria-live="polite">
        <button class="snapshot-close" data-snapshot-step="confirm" aria-label="Return to meal review">&times;</button>
        <div class="snapshot-analysis-visual">
          <div class="snapshot-meal-ring">${mealSnapshotPhoto()}<span class="snapshot-ring-check">&#10003;</span></div>
        </div>
        <h1>Hmm, something tasty...</h1>
        <p>Building your meal snapshot. You can adjust anything that looks off.</p>
        <img class="snapshot-leaner-logo" src="assets/leaner-logo.png" alt="Leaner Wellness">
      </section>`;
    }

    function mealSnapshotResult() {
      const result = state.mealSnapshotResult || mockMealSnapshotResult;
      const ingredients = state.mealSnapshotIngredients.length ? state.mealSnapshotIngredients : result.ingredients;
      return `<section class="meal-snapshot-stage">
        <button class="snapshot-back-link" data-route="meals">&larr; Back to Meal Ideas</button>
        <div class="snapshot-result-shell">
          <div class="snapshot-result-hero">
            <div class="snapshot-result-heading">
              <p class="eyebrow">Meal Snapshot</p>
              <h1>${escapeHtml(result.title)}</h1>
            </div>
            <div class="snapshot-result-photo">${mealSnapshotPhoto()}</div>
          </div>
          <section class="snapshot-nutrition-card">
            <div class="snapshot-card-topline"><span>Calories &amp; macros</span><button class="snapshot-edit-control" data-snapshot-step="confirm">Edit</button></div>
            <div class="snapshot-calorie-line"><strong>${result.calories}</strong><span>kcal</span><em>${escapeHtml(result.confidence)}</em></div>
            <div class="snapshot-macro-bar" aria-label="Estimated macro balance"><span class="carbs"></span><span class="fat"></span><span class="protein"></span></div>
            <div class="snapshot-macro-section">
              <div class="snapshot-macro carbs"><span>Carbs</span><strong>${result.carbs}g</strong></div>
              <div class="snapshot-macro fat"><span>Fat</span><strong>${result.fat}g</strong></div>
              <div class="snapshot-macro protein"><span>Protein</span><strong>${result.protein}g</strong></div>
            </div>
            <div class="snapshot-balance-message"><strong>Protein-forward meal</strong><span>A steady protein anchor with a balanced mix of carbs and fats.</span></div>
          </section>
        </div>
        <section class="snapshot-note">
          <p class="eyebrow">Leaner note</p>
          <p>${escapeHtml(result.note)}</p>
          <strong>This is an estimate, not a grade. Use it as a quick guide and keep following your Leaner plan.</strong>
        </section>
        <section class="snapshot-detected-list snapshot-ingredients-card">
          <div class="section-heading"><div><p class="eyebrow">Meal details</p><h2>Ingredients</h2></div></div>
          ${ingredients.map(item => `<div><strong>${escapeHtml(item.name)}</strong><span>${escapeHtml(item.amount)}</span></div>`).join("")}
        </section>
        ${state.mealSnapshotNotice ? `<div class="snapshot-save-confirmation">${escapeHtml(state.mealSnapshotNotice)}</div>` : ""}
        <div class="snapshot-actions result-actions">
          <button class="secondary" data-snapshot-step="confirm">Edit ingredients</button>
          <button class="primary snapshot-primary" id="saveMealSnapshot">Save snapshot</button>
          <button class="ghost" id="discardMealSnapshot">Discard</button>
        </div>
      </section>`;
    }

    function mealSnapshot() {
      const betaConfig = APP_CONFIG.features?.mealSnapshotBeta;
      if (betaConfig?.enabled === true) {
        return `<section class="screen active meal-snapshot-screen"><div id="mealSnapshotBetaRoot" class="meal-snapshot-beta-root"></div></section>`;
      }
      const screens = {
        upload: mealSnapshotUpload,
        confirm: mealSnapshotConfirm,
        analyzing: mealSnapshotAnalyzing,
        result: mealSnapshotResult
      };
      return `<section class="screen active meal-snapshot-screen">${(screens[state.mealSnapshotStep] || mealSnapshotUpload)()}</section>`;
    }

    function mountMealSnapshotBeta() {
      const betaConfig = APP_CONFIG.features?.mealSnapshotBeta;
      if (state.route !== ROUTES.MEAL_SNAPSHOT || betaConfig?.enabled !== true) return false;
      const container = document.getElementById("mealSnapshotBetaRoot");
      if (!container
        || typeof MealSnapshotService === "undefined"
        || typeof MealSnapshotUiState === "undefined"
        || typeof MealSnapshotUiRenderer === "undefined"
        || typeof MealSnapshotMockEstimate === "undefined"
        || typeof MealSnapshotReviewRenderer === "undefined"
        || typeof MealSnapshotReviewedDraft === "undefined"
        || typeof MealSnapshotFallbackRenderer === "undefined"
        || typeof MealSnapshotUiController === "undefined") return false;

      return MealSnapshotUiController.mountMealSnapshotBetaController({
        container,
        featureConfig: betaConfig,
        uiStateApi: MealSnapshotUiState,
        rendererApi: MealSnapshotUiRenderer,
        mockEstimateApi: MealSnapshotMockEstimate,
        reviewRendererApi: MealSnapshotReviewRenderer,
        reviewedDraftApi: MealSnapshotReviewedDraft,
        fallbackRendererApi: MealSnapshotFallbackRenderer,
        validateFile: MealSnapshotService.validateFile,
        maxImageBytes: MealSnapshotService.DEFAULT_MAX_IMAGE_BYTES,
        documentRef: document
      }).mounted;
    }

    function mealIdeas() {
      return `
        <section class="screen active">
          <div class="hero"><p class="eyebrow">Meal Ideas</p><h1>Simple support, not tracking.</h1><p class="subhead">Curated Leaner-friendly ideas for small appetite days, busy nights, and practical protein wins.</p></div>
          <section class="meal-snapshot-entry">
            ${icon("spark")}
            <div><p class="eyebrow">New tool</p><h2>Meal Snapshot</h2><p>Snap a meal and get a simple nutrition estimate.</p></div>
            <button class="secondary" data-route="mealSnapshot">Take a Meal Snapshot</button>
          </section>
          <section class="meal-deck-panel">
            <div class="section-heading meal-lane-heading"><div><p class="eyebrow">Meal lanes</p><h2>Choose a meal lane</h2></div></div>
            <div class="meal-deck-stack">${mealDecks.map(mealDeck).join("")}</div>
          </section>
        </section>`;
    }

    function support() {
      return `
        <section class="screen active">
          <div class="hero"><p class="eyebrow">Support</p><h1>Local help is the point.</h1><p class="subhead">The dashboard keeps patients connected to Leaner's brick-and-mortar care team and weekly support.</p></div>
          <section class="panel">
            <div class="button-row"><button class="primary">Contact Leaner</button><button class="ghost">Appointment: ${patient.nextVisitDate}</button></div>
          </section>
          <section class="panel">
            <h2>FAQ</h2>
            <div class="grid">
              <div class="tile"><h3>When should I contact the clinic?</h3><p>For medical questions, dose changes, concerning symptoms, or anything that feels urgent.</p></div>
              <div class="tile"><h3>What about side effects?</h3><p>Track how you feel and contact Leaner if symptoms concern you or do not improve.</p><button class="ghost" data-save-tip="side-effects">Save tip +5</button></div>
              <div class="tile"><h3>Can this dashboard change my plan?</h3><p>No. It supports accountability and education but does not replace clinic guidance.</p></div>
            </div>
          </section>
          <p class="notice">This dashboard supports your Leaner journey but does not replace medical advice. Contact Leaner for medical questions, dose changes, or concerning symptoms.</p>
        </section>`;
    }

    function admin() {
      const hidden = state.wins.filter(w => w.isHidden).length;
      const flagged = state.wins.filter(w => w.isFlagged).length;
      const modeNote = isAuthRequired() ? "Firebase fake-user testing is active. Use this area to review wins, rewards, check-ins, and weekly support content." : "Prototype admin mock. Use this area to moderate wins and manage prototype content.";
      return `
        <section class="screen active">
          <div class="hero"><p class="eyebrow">Leaner staff</p><h1>Admin Dashboard</h1><p class="subhead">${modeNote}</p></div>
          <div class="admin-shell">
            <div class="admin-menu">${["dashboard","wins","weeklySupport","rewards","activity","meals","tips","checkins"].map(t => `<button class="${state.adminTab === t ? "active" : ""}" data-admin-tab="${t}">${labelTab(t)}</button>`).join("")}</div>
            <section class="panel">${adminTab(hidden, flagged)}</section>
          </div>
        </section>`;
    }

    function labelTab(t) {
      return ({ dashboard: "Dashboard", wins: "Wins Management", weeklySupport: "Weekly Support", rewards: "Momentum Rewards", activity: "Point Activity", meals: "Meal Ideas", tips: "Coach Tips", checkins: "Patient Check-Ins" })[t];
    }

    function adminTab(hidden, flagged) {
      if (state.adminTab === "dashboard") {
        const cheers = state.wins.reduce((sum, w) => sum + w.cheers, 0);
        const requested = state.redemptions.filter(item => normalizeRewardStatus(item.status) === REWARD_STATUSES.REQUESTED).length;
        const followups = state.checkIns.filter(item => item.needsClinicFollowup).length;
        const lowQueues = SUPPORT_TYPE_LIST.filter(type => unusedApprovedCount(type) < 4).length;
        return `<h2>Today at a glance</h2>
          <div class="admin-attention">
            <article class="attention-tile"><div class="metric-label">Needs review</div><div class="attention-value">${flagged}</div><p>Flagged wins waiting for staff review.</p></article>
            <article class="attention-tile"><div class="metric-label">Reward requests</div><div class="attention-value">${requested}</div><p>Patients waiting for manual reward follow-up.</p></article>
            <article class="attention-tile"><div class="metric-label">Clinic follow-up</div><div class="attention-value">${followups}</div><p>Check-ins asking for Leaner support.</p></article>
            <article class="attention-tile"><div class="metric-label">Content queues</div><div class="attention-value">${lowQueues}</div><p>Weekly support categories below refill threshold.</p></article>
          </div>
          <h2>Overview</h2><div class="grid admin-grid">${metric("All wins", state.wins.length)}${metric("Total cheers", cheers)}${metric("Points balance", state.pointsBalance)}${metric("Reward requests", requested)}${metric("Flagged", flagged)}${metric("Hidden", hidden)}${metric("Meal ideas", state.meals.length)}${metric("Coach tips", state.tips.length)}</div>`;
      }
      if (state.adminTab === "wins") {
        return `<h2>Wins Management</h2><div class="admin-list">${state.wins.map(w => `<article class="admin-record">
          <div>
            <h3>${escapeHtml(w.headline)}</h3>
            <div class="record-meta">${escapeHtml(w.category)} &middot; ${escapeHtml(w.displayName)} &middot; Week ${w.weekNumber || "?"}</div>
          </div>
          <div class="status-row">
            <span class="status-pill ${w.isHidden ? "danger" : ""}">${w.isHidden ? "Hidden" : "Visible"}</span>
            ${w.isFeatured ? `<span class="status-pill">Featured</span>` : ""}
            ${w.isFlagged ? `<span class="status-pill warn">Flagged</span>` : ""}
            <span class="status-pill">${w.cheers} cheers</span>
          </div>
          <div class="button-row"><button class="ghost" data-toggle-feature="${w.id}">${w.isFeatured ? "Unfeature" : "Feature"}</button><button class="danger" data-toggle-hide="${w.id}">${w.isHidden ? "Restore" : "Hide"}</button></div>
        </article>`).join("")}</div>`;
      }
      if (state.adminTab === "weeklySupport") {
        const weekly = currentWeeklySupport();
        const selection = weekly.selection;
        return `<h2>Weekly Support</h2>
          <p class="notice">Approved content rotates automatically each week. Staff can override this week's selection without needing to upload content every week.</p>
          ${csvImportPanel()}
          <div class="admin-list" style="margin:14px 0">
            <article class="admin-record"><h3>Current week</h3><p class="record-meta">Week of ${selection.weekStartDate} &middot; ${selection.mode === "manual" ? "Manual selection" : "Auto-selected"}</p></article>
            <article class="admin-record"><h3>${escapeHtml(weekly.meal_idea.title)}</h3><p>${escapeHtml(weekly.meal_idea.shortDescription)}</p><span class="status-pill">Meal Idea</span></article>
            <article class="admin-record"><h3>${escapeHtml(weekly.coach_tip.title)}</h3><p>${escapeHtml(weekly.coach_tip.shortDescription)}</p><span class="status-pill">Coach Tip</span></article>
            <article class="admin-record"><h3>${escapeHtml(weekly.clinic_support.title)}</h3><p>${escapeHtml(weekly.clinic_support.shortDescription)}</p><span class="status-pill">Clinic Support</span></article>
          </div>
          <h3>Content bank status</h3>
          <div class="grid admin-grid" style="margin-bottom:16px">${SUPPORT_TYPE_LIST.map(supportQueueCard).join("")}</div>
          <h3>Manual override for this week</h3>
          <form class="form" id="supportOverrideForm">
            <label>Meal Idea <select name="${SUPPORT_TYPES.MEAL_IDEA}">${supportOptions(SUPPORT_TYPES.MEAL_IDEA, selection.mealIdeaId)}</select></label>
            <label>Coach Tip <select name="${SUPPORT_TYPES.COACH_TIP}">${supportOptions(SUPPORT_TYPES.COACH_TIP, selection.coachTipId)}</select></label>
            <label>Clinic Support <select name="${SUPPORT_TYPES.CLINIC_SUPPORT}">${supportOptions(SUPPORT_TYPES.CLINIC_SUPPORT, selection.clinicSupportId)}</select></label>
            <button class="secondary">Save Weekly Selection</button>
          </form>`;
      }
      if (state.adminTab === "rewards") {
        return rewardAdminPanel();
      }
      if (state.adminTab === "activity") {
        return `<h2>Point Activity</h2><div class="admin-list">${state.pointEvents.map(event => `<article class="admin-record">
          <div>
            <h3>${escapeHtml(event.description)}</h3>
            <div class="record-meta">${event.type} &middot; ${event.createdAt}</div>
          </div>
          <span class="points-pill">${event.points > 0 ? "+" : ""}${event.points}</span>
        </article>`).join("")}</div>`;
      }
      if (state.adminTab === "meals") {
        return `<h2>Meal Ideas Management</h2><div class="grid">${state.meals.map((m, i) => `<div class="tile"><h3>${escapeHtml(m[0])}</h3><p>${escapeHtml(m[1])} &middot; ${m[3]}</p><p>${escapeHtml(m[2])}</p><button class="ghost" data-edit-meal="${i}">Edit placeholder</button></div>`).join("")}</div><form class="form" id="mealForm" style="margin-top:14px"><label>Add meal idea <input name="title" placeholder="New meal title"></label><button class="secondary">Add Meal Idea</button></form>`;
      }
      if (state.adminTab === "tips") {
        return `<h2>Coach Tips Management</h2><div class="grid">${state.tips.map(t => `<div class="tile"><h3>${escapeHtml(t.title)}</h3><p>${escapeHtml(t.body)}</p><p>Week ${t.weekNumber} &middot; ${escapeHtml(t.category)}</p></div>`).join("")}</div><form class="form" id="tipForm" style="margin-top:14px"><label>Add coach tip <input name="title" placeholder="Tip title"></label><label>Body <textarea name="body"></textarea></label><button class="secondary">Add Coach Tip</button></form>`;
      }
      return `<h2>Patient Check-Ins</h2><div class="admin-list">${state.checkIns.map(c => `<article class="admin-record">
        <div>
          <h3>${c.date}</h3>
          <div class="record-meta">${c.weight} lbs &middot; Hunger ${c.hungerLevel}/4 &middot; Energy ${c.energyLevel}/4</div>
        </div>
        <p>${escapeHtml(c.weeklyWin || "No weekly win entered.")}</p>
        <span class="status-pill ${c.needsClinicFollowup ? "warn" : ""}">${c.needsClinicFollowup ? "Clinic follow-up requested" : "No follow-up requested"}</span>
      </article>`).join("")}</div>`;
    }

    function render() {
      const screens = document.getElementById("screens");
      const map = { [ROUTES.HOME]: home, [ROUTES.WINS]: wins, [ROUTES.MOMENTUM]: momentum, [ROUTES.SUBMIT]: () => submitWin(), [ROUTES.CHECKIN]: checkin, [ROUTES.PROGRESS]: progress, [ROUTES.MEALS]: mealIdeas, [ROUTES.MEAL_SNAPSHOT]: mealSnapshot, [ROUTES.SUPPORT]: support, [ROUTES.LOGIN]: login, [ROUTES.ADMIN]: admin };
      if (isAuthRequired() && !state.authReady) {
        screens.innerHTML = loadingScreen();
        syncAuthControls();
        return;
      }
      if (isAuthRequired() && !state.currentUser && state.route !== ROUTES.LOGIN) {
        state.route = ROUTES.LOGIN;
      }
      if (!canAccessRoute(state.route)) {
        state.route = state.currentUser ? ROUTES.HOME : ROUTES.LOGIN;
      }
      document.body.classList.toggle("wins-immersive", state.route === ROUTES.WINS);
      screens.innerHTML = (map[state.route] || home)();
      mountMealSnapshotBeta();
      document.querySelectorAll("[data-route]").forEach(btn => btn.addEventListener("click", () => routeTo(btn.dataset.route)));
      const activeNavRoute = state.route === ROUTES.MEAL_SNAPSHOT ? ROUTES.MEALS : state.route;
      document.querySelectorAll(".nav-btn").forEach(btn => btn.classList.toggle("active", btn.dataset.route === activeNavRoute));
      document.querySelector(".bottom-nav").style.display = state.route === ROUTES.ADMIN || state.route === ROUTES.LOGIN ? "none" : "grid";
      syncAuthControls();
      bind();
    }

    function syncAuthControls() {
      const logoutButton = document.getElementById("logoutButton");
      if (logoutButton) logoutButton.hidden = !(isAuthRequired() && state.currentUser);
    }
