/* nutri-calories.jsx — Full Diet Progress screens
   Covers: CaloriesHome, CaloriesCalendar, CaloriesStats,
   MacroGoalEditorSheet, LogFoodSheet, AddLocalItemSheet,
   LocalLibraryTab, FoodLibraryTab, DayDetailPanel,
   DuplicateEntryDialog, and all supporting components. */

// ─────────────────────────────────────────────────────────────
// CALORIES HOME — main dashboard
// ─────────────────────────────────────────────────────────────
function CaloriesHome({
  entries, goals, localLibrary,
  selectedDate, setSelectedDate,
  onAdd,
  onEditGoals, onLogFood, onLogAgain, onOpenMeal,
  onAddLocalItem, onEditLocalItem, onDeleteLocalItem,
}) {
  const [libTab, setLibTab] = React.useState('food'); // 'food' | 'local'
  const todayTotals = nutriDayTotals(entries, selectedDate);

  // Recent meals — last 20 entries, newest first
  const recentEntries = React.useMemo(() => {
    return [...entries]
      .sort((a, b) => {
        const dc = (b.date || '').localeCompare(a.date || '');
        if (dc !== 0) return dc;
        return (b.time || '').localeCompare(a.time || '');
      })
      .slice(0, 20);
  }, [entries]);

  return (
    <div style={{ padding: '12px 16px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingTop: 4 }}>
        <div>
          <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>
            {selectedDate === todayISO() ? 'Today' : prettyDateShort(selectedDate)}
          </div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2, fontWeight: 500 }}>
            {new Date(selectedDate + 'T00:00:00').toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })}
          </div>
        </div>
        {onAdd && (
          <button onClick={onAdd} style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '7px 14px', borderRadius: 999,
            background: 'var(--accent)', color: 'var(--on-accent)',
            border: '1px solid var(--accent)', font: 'inherit', fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
          }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
              <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
            </svg>
            Meal
          </button>
        )}
      </div>

      {/* Day strip */}
      <DayStrip selected={selectedDate} onSelect={setSelectedDate} days={7}/>

      {/* Today Progress Card — clickable to edit goals */}
      <TodayProgressCard totals={todayTotals} goals={goals} onClick={onEditGoals}/>

      {/* Recent meals section */}
      <CalRecentMeals
        entries={recentEntries}
        selectedDate={selectedDate}
        onOpen={onOpenMeal}
        onLogAgain={onLogAgain}/>

      {/* Library tabs */}
      <div style={{ display: 'flex', gap: 4, background: 'var(--surface-2)', borderRadius: 12, padding: 4, border: '1px solid var(--border)' }}>
        {[{ id: 'food', label: '📚 Food Library' }, { id: 'local', label: '⭐ Local Library' }].map(t => (
          <button key={t.id} onClick={() => setLibTab(t.id)} style={{
            flex: 1, padding: '9px 0', borderRadius: 9, border: 0,
            background: libTab === t.id ? 'var(--surface)' : 'transparent',
            color: libTab === t.id ? 'var(--text)' : 'var(--muted)',
            fontSize: 13, fontWeight: 600, cursor: 'pointer', font: 'inherit',
            boxShadow: libTab === t.id ? 'var(--shadow-sm)' : 'none',
          }}>{t.label}</button>
        ))}
      </div>

      {libTab === 'food' && (
        <FoodLibraryTab onLogFood={onLogFood}/>
      )}
      {libTab === 'local' && (
        <LocalLibraryTab
          items={localLibrary}
          onLogFood={onLogFood}
          onAdd={onAddLocalItem}
          onEdit={onEditLocalItem}
          onDelete={onDeleteLocalItem}/>
      )}

      <div style={{ height: 60 }}/>
    </div>
  );
}

function prettyDateShort(iso) {
  const d = new Date(iso + 'T00:00:00');
  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
}

// ─────────────────────────────────────────────────────────────
// TODAY PROGRESS CARD — clickable → opens goal editor
// ─────────────────────────────────────────────────────────────
function TodayProgressCard({ totals, goals, onClick }) {
  const calPct  = goals.calories  ? Math.min(1, totals.calories  / goals.calories)  : 0;
  const protPct = goals.protein_g ? Math.min(1, totals.protein_g / goals.protein_g) : 0;
  const carbPct = goals.carbs_g   ? Math.min(1, totals.carbs_g   / goals.carbs_g)   : 0;
  const fatPct  = goals.fat_g     ? Math.min(1, totals.fat_g     / goals.fat_g)     : 0;
  const calLeft = Math.max(0, goals.calories - totals.calories);

  return (
    <button onClick={onClick} style={{
      width: '100%', textAlign: 'left',
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 18, padding: 16, cursor: 'pointer',
      boxShadow: 'var(--shadow-md)',
    }}>
      {/* Calories row */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
            <span style={{ fontSize: 32, fontWeight: 700, letterSpacing: '-0.03em' }}>
              {totals.calories.toLocaleString()}
            </span>
            <span style={{ fontSize: 13, color: 'var(--muted)' }}>/ {goals.calories.toLocaleString()} kcal</span>
          </div>
          <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>
            {calLeft > 0 ? `${calLeft.toLocaleString()} kcal left` : 'Goal reached! 🎉'}
            {' '}·{' '}
            <span style={{ color: 'var(--accent)', fontWeight: 600 }}>Tap to edit goals</span>
          </div>
        </div>
        <CalorieRing value={totals.calories} goal={goals.calories} size={72} stroke={8}/>
      </div>

      {/* Macro bars */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
        {[
          { label: 'Protein', val: totals.protein_g, goal: goals.protein_g, pct: protPct, color: 'var(--c-protein)' },
          { label: 'Carbs',   val: totals.carbs_g,   goal: goals.carbs_g,   pct: carbPct, color: 'var(--c-carbs)' },
          { label: 'Fat',     val: totals.fat_g,     goal: goals.fat_g,     pct: fatPct,  color: 'var(--c-fat)' },
        ].map(m => (
          <div key={m.label}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
              <span style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 600 }}>{m.label}</span>
              <span style={{ fontSize: 11, fontWeight: 600 }}>{Math.round(m.val)}g</span>
            </div>
            <div style={{ height: 5, borderRadius: 99, background: 'var(--border-2)', overflow: 'hidden' }}>
              <div style={{ width: `${m.pct * 100}%`, height: '100%', background: m.color, borderRadius: 99, transition: 'width .4s ease' }}/>
            </div>
            <div style={{ fontSize: 10, color: 'var(--muted)', marginTop: 3 }}>{Math.round(m.pct * 100)}% · goal {m.goal}g</div>
          </div>
        ))}
      </div>
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// MACRO GOAL EDITOR SHEET
// ─────────────────────────────────────────────────────────────
function MacroGoalEditorSheet({ goals, onSave, onClose }) {
  const [cal,  setCal]  = React.useState(String(goals.calories  || 2400));
  const [prot, setProt] = React.useState(String(goals.protein_g || 165));
  const [carb, setCarb] = React.useState(String(goals.carbs_g   || 280));
  const [fat,  setFat]  = React.useState(String(goals.fat_g     || 80));

  function submit() {
    onSave({
      calories:  +cal  || 2400,
      protein_g: +prot || 165,
      carbs_g:   +carb || 280,
      fat_g:     +fat  || 80,
    });
  }

  return (
    <SheetShell title="Edit Goals" onClose={onClose} onSave={submit} canSave={true}>
      <div style={{ padding: 12, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', marginBottom: 4 }}>
          Set your daily targets. These affect all progress calculations.
        </div>
        <NumberField label="Daily Calories" value={cal}  onChange={setCal}  suffix="kcal"/>
        <NumberField label="Protein"        value={prot} onChange={setProt} suffix="g"/>
        <NumberField label="Carbs"          value={carb} onChange={setCarb} suffix="g"/>
        <NumberField label="Fat"            value={fat}  onChange={setFat}  suffix="g"/>

        {/* Macro preview */}
        {(+cal > 0) && (
          <div style={{
            marginTop: 6, padding: '10px 12px', borderRadius: 10,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
            fontSize: 12, color: 'var(--muted)',
          }}>
            From macros: {Math.round((+prot||0)*4 + (+carb||0)*4 + (+fat||0)*9)} kcal
            {' '}vs goal {+cal} kcal
          </div>
        )}
      </div>
    </SheetShell>
  );
}

// ─────────────────────────────────────────────────────────────
// RECENT MEALS SECTION
// ─────────────────────────────────────────────────────────────
function CalRecentMeals({ entries, selectedDate, onOpen, onLogAgain }) {
  const dayEntries = entries.filter(e => e.date === selectedDate)
    .sort((a, b) => (a.time || '').localeCompare(b.time || ''));

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10 }}>
        <div style={{ fontSize: 16, fontWeight: 600, letterSpacing: '-0.01em' }}>
          {selectedDate === todayISO() ? "Today's Meals" : prettyDateShort(selectedDate)}
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)' }}>{dayEntries.length} logged</div>
      </div>

      {dayEntries.length === 0 ? (
        <div style={{ ...nutriStyles.card, padding: '22px 18px', textAlign: 'center' }}>
          <div style={{ fontSize: 28, marginBottom: 6 }}>🍽️</div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Nothing logged yet</div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 4 }}>
            Browse the library below and tap Add to log food.
          </div>
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {dayEntries.map(e => (
            <RecentMealCard key={e.id} entry={e} onOpen={onOpen} onLogAgain={onLogAgain}/>
          ))}
        </div>
      )}
    </div>
  );
}

function RecentMealCard({ entry, onOpen, onLogAgain }) {
  const mealColor = NUTRI_MEAL_COLOR[entry.meal] || '#D0CDB8';
  return (
    <div style={{
      ...nutriStyles.card, padding: 0, overflow: 'hidden',
      display: 'flex',
    }}>
      {/* color accent */}
      <div style={{ width: 4, flexShrink: 0, background: mealColor }}/>
      <button onClick={() => onOpen && onOpen(entry)} style={{
        flex: 1, textAlign: 'left', padding: '11px 12px',
        background: 'transparent', border: 0, cursor: 'pointer', font: 'inherit',
        display: 'flex', alignItems: 'center', gap: 10, minWidth: 0,
      }}>
        <div style={{ fontSize: 28, flexShrink: 0 }}>{entry.emoji || '🍽️'}</div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {entry.name || 'Meal'}
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 2 }}>
            {NUTRI_MEAL_LABEL[entry.meal] || entry.meal}
            {entry.time ? ` · ${entry.time}` : ''}
            {' · '}{entry.calories} kcal
            {entry.protein_g > 0 ? ` · P ${Math.round(entry.protein_g)}g` : ''}
            {entry.carbs_g   > 0 ? ` · C ${Math.round(entry.carbs_g)}g`   : ''}
            {entry.fat_g     > 0 ? ` · F ${Math.round(entry.fat_g)}g`     : ''}
          </div>
          <div style={{ fontSize: 10.5, color: 'var(--muted-2)', marginTop: 1 }}>
            {entry.date !== NUTRI_TODAY ? entry.date + ' · ' : ''}
            Source: {entry.source || 'manual'}
          </div>
        </div>
      </button>
      <button onClick={(e) => { e.stopPropagation(); onLogAgain && onLogAgain(entry); }} style={{
        flexShrink: 0, padding: '0 12px', background: 'transparent',
        border: 0, borderLeft: '1px solid var(--border)', cursor: 'pointer',
        color: 'var(--accent)', fontSize: 11.5, fontWeight: 600, font: 'inherit',
      }}>
        Log<br/>Again
      </button>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// FOOD LIBRARY TAB — built-in 85+ foods
// ─────────────────────────────────────────────────────────────
function FoodLibraryTab({ onLogFood }) {
  const [q, setQ]         = React.useState('');
  const [cat, setCat]     = React.useState('all');

  const filtered = React.useMemo(() => {
    const lq = q.toLowerCase();
    return NUTRI_FOODS.filter(f => {
      const matchCat = cat === 'all' || f.category === cat;
      const matchQ   = !q || f.name.toLowerCase().includes(lq)
                          || (f.nameAr && f.nameAr.includes(q))
                          || f.category.toLowerCase().includes(lq);
      return matchCat && matchQ;
    });
  }, [q, cat]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      {/* Search */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10,
        background: 'var(--surface)', border: '1px solid var(--border-2)',
        borderRadius: 12, padding: '10px 14px',
      }}>
        <SearchIcon size={15}/>
        <input value={q} onChange={e => setQ(e.target.value)}
          placeholder="Search foods… بحث"
          style={{ flex: 1, border: 0, background: 'transparent', outline: 'none', font: 'inherit', fontSize: 14, color: 'var(--text)' }}/>
        {q && <button onClick={() => setQ('')} style={{ background: 'none', border: 0, cursor: 'pointer', color: 'var(--muted)', fontSize: 16, lineHeight: 1 }}>×</button>}
      </div>

      {/* Category chips */}
      <div style={{ display: 'flex', gap: 6, overflowX: 'auto', paddingBottom: 2, margin: '0 -16px', padding: '0 16px 4px' }} className="nutri-scroll-x">
        {NUTRI_FOOD_CATEGORIES.map(c => {
          const active = cat === c.id;
          return (
            <button key={c.id} onClick={() => setCat(c.id)} style={{
              flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 5,
              padding: '6px 11px', borderRadius: 999,
              background: active ? 'var(--text)' : 'var(--surface)',
              color: active ? 'var(--bg)' : 'var(--text)',
              border: active ? '1px solid var(--text)' : '1px solid var(--border-2)',
              fontSize: 12, fontWeight: 500, cursor: 'pointer', font: 'inherit',
              whiteSpace: 'nowrap',
            }}>
              <span>{c.emoji}</span>{c.label}
            </button>
          );
        })}
      </div>

      {/* Results count */}
      <div style={{ fontSize: 12.5, color: 'var(--muted)', fontWeight: 500 }}>
        {filtered.length} {filtered.length === 1 ? 'item' : 'items'}
        {cat !== 'all' ? ` in ${NUTRI_FOOD_CATEGORIES.find(c=>c.id===cat)?.label}` : ''}
      </div>

      {/* Food rows */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
        {filtered.length === 0 && (
          <div style={{ ...nutriStyles.card, padding: 20, textAlign: 'center', color: 'var(--muted)', fontSize: 13 }}>
            No foods match "{q}". Try a different name.
          </div>
        )}
        {filtered.map(f => (
          <BuiltinFoodRow key={f.id} food={f} onAdd={() => onLogFood && onLogFood(f)}/>
        ))}
      </div>
    </div>
  );
}

function BuiltinFoodRow({ food, onAdd }) {
  return (
    <div style={{
      ...nutriStyles.card, display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px',
    }}>
      <div style={{ fontSize: 26, flexShrink: 0, width: 36, textAlign: 'center' }}>{food.emoji}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13.5, fontWeight: 600 }}>{food.name}</div>
        <div style={{ fontSize: 11.5, color: 'var(--muted)' }}>
          {food.cal} kcal · {food.qty}
        </div>
        <div style={{ fontSize: 11, color: 'var(--muted-2)', marginTop: 1 }}>
          P <span style={{ color: 'var(--c-protein)', fontWeight: 600 }}>{food.protein_g}g</span>
          {' '}C <span style={{ color: 'var(--c-carbs)', fontWeight: 600 }}>{food.carbs_g}g</span>
          {' '}F <span style={{ color: 'var(--c-fat)', fontWeight: 600 }}>{food.fat_g}g</span>
        </div>
      </div>
      <button onClick={onAdd} style={{
        flexShrink: 0, width: 34, height: 34, borderRadius: '50%',
        background: 'var(--accent)', color: 'var(--on-accent)',
        border: 0, display: 'grid', placeItems: 'center', cursor: 'pointer',
      }}>
        <PlusIcon size={16}/>
      </button>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// LOCAL LIBRARY TAB — user's saved items
// ─────────────────────────────────────────────────────────────
function LocalLibraryTab({ items, onLogFood, onAdd, onEdit, onDelete }) {
  const [q, setQ] = React.useState('');

  const filtered = React.useMemo(() => {
    const lq = q.toLowerCase();
    return items.filter(i => {
      if (!q) return true;
      return i.name.toLowerCase().includes(lq)
          || (i.nameAr && i.nameAr.includes(q))
          || (i.category && i.category.toLowerCase().includes(lq))
          || (Array.isArray(i.tags) && i.tags.some(t => t.toLowerCase().includes(lq)));
    });
  }, [items, q]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      {/* Search + Add button */}
      <div style={{ display: 'flex', gap: 8 }}>
        <div style={{
          flex: 1, display: 'flex', alignItems: 'center', gap: 8,
          background: 'var(--surface)', border: '1px solid var(--border-2)',
          borderRadius: 12, padding: '10px 14px',
        }}>
          <SearchIcon size={15}/>
          <input value={q} onChange={e => setQ(e.target.value)}
            placeholder="Search your items…"
            style={{ flex: 1, border: 0, background: 'transparent', outline: 'none', font: 'inherit', fontSize: 14, color: 'var(--text)' }}/>
        </div>
        <button onClick={onAdd} style={{
          flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '0 14px', borderRadius: 12,
          background: 'var(--accent)', color: 'var(--on-accent)',
          border: 0, fontSize: 13, fontWeight: 600, cursor: 'pointer', font: 'inherit',
        }}>
          <PlusIcon size={16}/> Add
        </button>
      </div>

      {items.length === 0 ? (
        <div style={{ ...nutriStyles.card, padding: '24px 18px', textAlign: 'center' }}>
          <div style={{ fontSize: 32, marginBottom: 8 }}>⭐</div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Your library is empty</div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 4, maxWidth: 220, margin: '4px auto 0' }}>
            Save your own foods, yogurt brands, homemade meals, and more.
          </div>
          <button onClick={onAdd} style={{
            marginTop: 14, padding: '10px 20px', borderRadius: 999,
            background: 'var(--accent)', color: 'var(--on-accent)',
            border: 0, fontSize: 13, fontWeight: 600, cursor: 'pointer', font: 'inherit',
          }}>
            Add your first item
          </button>
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
          {filtered.length === 0 && (
            <div style={{ ...nutriStyles.card, padding: 16, textAlign: 'center', color: 'var(--muted)', fontSize: 13 }}>
              No items match "{q}".
            </div>
          )}
          {filtered.map(item => (
            <LocalItemCard key={item.id} item={item}
              onLog={() => onLogFood && onLogFood(item)}
              onEdit={() => onEdit && onEdit(item)}
              onDelete={() => onDelete && onDelete(item.id)}/>
          ))}
        </div>
      )}
    </div>
  );
}

function LocalItemCard({ item, onLog, onEdit, onDelete }) {
  const [menuOpen, setMenuOpen] = React.useState(false);
  return (
    <div style={{ ...nutriStyles.card, padding: 0, overflow: 'visible' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '11px 12px' }}>
        <div style={{
          width: 40, height: 40, borderRadius: 10, flexShrink: 0,
          background: 'var(--surface-2)', border: '1px solid var(--border)',
          display: 'grid', placeItems: 'center', fontSize: 22,
        }}>
          {item.emoji || '⭐'}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>{item.name}</div>
          <div style={{ fontSize: 11.5, color: 'var(--muted)' }}>
            {item.cal} kcal · {item.serving}{item.unit}
            {item.category ? ` · ${item.category}` : ''}
          </div>
          <div style={{ fontSize: 11, color: 'var(--muted-2)', marginTop: 1 }}>
            P <span style={{ color: 'var(--c-protein)', fontWeight: 600 }}>{item.protein_g}g</span>
            {' '}C <span style={{ color: 'var(--c-carbs)', fontWeight: 600 }}>{item.carbs_g}g</span>
            {' '}F <span style={{ color: 'var(--c-fat)', fontWeight: 600 }}>{item.fat_g}g</span>
          </div>
          {Array.isArray(item.tags) && item.tags.length > 0 && (
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', marginTop: 4 }}>
              {item.tags.slice(0, 3).map(t => (
                <span key={t} style={{
                  fontSize: 10, padding: '2px 7px', borderRadius: 99,
                  background: 'var(--surface-2)', border: '1px solid var(--border-2)',
                  color: 'var(--muted)',
                }}>{t}</span>
              ))}
            </div>
          )}
        </div>
        <div style={{ display: 'flex', gap: 6, flexShrink: 0 }}>
          <button onClick={onLog} style={{
            width: 34, height: 34, borderRadius: '50%',
            background: 'var(--accent)', color: 'var(--on-accent)',
            border: 0, display: 'grid', placeItems: 'center', cursor: 'pointer',
          }}>
            <PlusIcon size={16}/>
          </button>
          <div style={{ position: 'relative' }}>
            <button onClick={() => setMenuOpen(v => !v)} style={{
              width: 34, height: 34, borderRadius: '50%',
              background: 'var(--surface-2)', color: 'var(--text)',
              border: '1px solid var(--border)', cursor: 'pointer',
              display: 'grid', placeItems: 'center', fontSize: 18,
            }}>⋯</button>
            {menuOpen && (
              <div onClick={() => setMenuOpen(false)} style={{
                position: 'absolute', right: 0, top: 38, zIndex: 20,
                background: 'var(--surface)', border: '1px solid var(--border)',
                borderRadius: 12, boxShadow: 'var(--shadow-md)',
                minWidth: 120, padding: 6,
              }}>
                <button onClick={onEdit} style={menuItemStyle}>✏️ Edit</button>
                <button onClick={onDelete} style={{ ...menuItemStyle, color: '#A33' }}>🗑️ Delete</button>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
const menuItemStyle = {
  width: '100%', textAlign: 'left', padding: '9px 12px',
  background: 'transparent', border: 0, borderRadius: 8,
  font: 'inherit', fontSize: 13, cursor: 'pointer', color: 'var(--text)',
  display: 'block',
};

// ─────────────────────────────────────────────────────────────
// ADD LOCAL ITEM SHEET — manual / text template
// ─────────────────────────────────────────────────────────────
function AddLocalItemSheet({ existing, onSave, onClose }) {
  const isEdit = !!existing;
  const [mode, setMode]       = React.useState('manual'); // 'manual' | 'text'
  const [name, setName]       = React.useState(existing?.name || '');
  const [nameAr, setNameAr]   = React.useState(existing?.nameAr || '');
  const [category, setCategory] = React.useState(existing?.category || 'dairy');
  const [emoji, setEmoji]     = React.useState(existing?.emoji || '⭐');
  const [serving, setServing] = React.useState(String(existing?.serving || '100'));
  const [unit, setUnit]       = React.useState(existing?.unit || 'g');
  const [cal, setCal]         = React.useState(String(existing?.cal || ''));
  const [protein, setProtein] = React.useState(String(existing?.protein_g || ''));
  const [carbs, setCarbs]     = React.useState(String(existing?.carbs_g || ''));
  const [fat, setFat]         = React.useState(String(existing?.fat_g || ''));
  const [tagsStr, setTagsStr] = React.useState((existing?.tags || []).join(', '));
  const [note, setNote]       = React.useState(existing?.note || '');

  // Text template parser state
  const [pasteText, setPasteText] = React.useState('');
  const [parsed, setParsed]       = React.useState(null);

  function parseText() {
    const t = pasteText;
    // Try structured format
    const extract = (regex, txt) => { const m = (txt||t).match(regex); return m ? m[1].trim() : ''; };
    const nameMatch = extract(/(?:Local Food|Food|Item):\s*(.+)/i) || extract(/^([^\n—]+)/m);
    const calMatch  = t.match(/(\d+(?:\.\d+)?)\s*(?:kcal|cal|كالوري)/i);
    const carbMatch = t.match(/carbs?\s*[:\-—]\s*(\d+(?:\.\d+)?)\s*g/i) || t.match(/(\d+(?:\.\d+)?)\s*g\s*(?:carbs?|كارب)/i);
    const protMatch = t.match(/protein\s*[:\-—]\s*(\d+(?:\.\d+)?)\s*g/i) || t.match(/(\d+(?:\.\d+)?)\s*g\s*(?:protein|بروتين)/i);
    const fatMatch  = t.match(/fat\s*[:\-—]\s*(\d+(?:\.\d+)?)\s*g/i) || t.match(/(\d+(?:\.\d+)?)\s*g\s*(?:fat|دهون)/i);
    const servMatch = t.match(/(?:amount|serving|حجم|양)?\s*[:\-—]?\s*(\d+(?:\.\d+)?)\s*(g|ml|kg|piece|tbsp|cup)/i);
    const catMatch  = t.match(/(?:category|نوع|تصنيف)\s*[:\-—]?\s*(.+)/i);
    const tagsMatch = t.match(/(?:tags?|وسوم|تاج)\s*[:\-—]?\s*(.+)/i);
    const noteMatch = t.match(/(?:note|ملاحظة|حاشية)\s*[:\-—]?\s*([\s\S]+)/i);

    // Simple inline format: Name — 170g — 120 kcal | carbs 8g | protein 15g | fat 3g
    const inlineMatch = t.match(/^(.+?)\s*[—\-–]\s*(\d+)\s*(g|ml)\s*[—\-–]\s*(\d+(?:\.\d+)?)\s*(?:kcal|cal)/im);

    const result = {};
    if (inlineMatch) {
      result.name     = inlineMatch[1].trim();
      result.serving  = +inlineMatch[2];
      result.unit     = inlineMatch[3];
      result.cal      = +inlineMatch[4];
      result.carbs_g  = carbMatch  ? +carbMatch[1]  : 0;
      result.protein_g= protMatch  ? +protMatch[1]  : 0;
      result.fat_g    = fatMatch   ? +fatMatch[1]   : 0;
    } else {
      result.name     = nameMatch;
      result.serving  = servMatch ? +servMatch[1] : 100;
      result.unit     = servMatch ? servMatch[2]  : 'g';
      result.cal      = calMatch  ? +calMatch[1]  : 0;
      result.carbs_g  = carbMatch ? +carbMatch[1] : 0;
      result.protein_g= protMatch ? +protMatch[1] : 0;
      result.fat_g    = fatMatch  ? +fatMatch[1]  : 0;
    }
    result.category = catMatch  ? catMatch[1].trim().toLowerCase()  : '';
    result.tags     = tagsMatch ? tagsMatch[1].split(/,\s*/).filter(Boolean) : [];
    result.note     = noteMatch ? noteMatch[1].trim() : '';

    setParsed(result);
    // Pre-fill form fields
    if (result.name)     setName(result.name);
    if (result.serving)  setServing(String(result.serving));
    if (result.unit)     setUnit(result.unit);
    if (result.cal)      setCal(String(result.cal));
    if (result.protein_g)setProtein(String(result.protein_g));
    if (result.carbs_g)  setCarbs(String(result.carbs_g));
    if (result.fat_g)    setFat(String(result.fat_g));
    if (result.category) setCategory(result.category);
    if (result.tags?.length) setTagsStr(result.tags.join(', '));
    if (result.note)     setNote(result.note);
    setMode('manual');
  }

  function submit() {
    if (!name.trim()) return;
    const id = existing?.id || ('loc_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 5));
    onSave({
      id, name: name.trim(), nameAr: nameAr.trim(),
      category, emoji,
      serving: +serving || 100, unit,
      cal: +cal || 0,
      protein_g: +protein || 0,
      carbs_g:   +carbs   || 0,
      fat_g:     +fat     || 0,
      p: +protein || 0, c: +carbs || 0, f: +fat || 0,
      qty: `${serving}${unit}`,
      tags: tagsStr.split(',').map(t => t.trim()).filter(Boolean),
      note: note.trim(),
      source: 'local',
      createdAt: existing?.createdAt || new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    });
  }

  const UNIT_OPTIONS   = ['g', 'ml', 'piece', 'tbsp', 'tsp', 'cup', 'slice'];
  const CAT_OPTIONS    = NUTRI_FOOD_CATEGORIES.filter(c => c.id !== 'all');
  const EMOJI_OPTIONS  = ['⭐','🥛','🧀','🍞','🥚','🍗','🥩','🐟','🥗','🍲','🥜','🍫','🍮','🥤','🫙','🍎','🥗','🌾'];

  return (
    <SheetShell title={isEdit ? 'Edit Item' : 'Add Local Item'} onClose={onClose} onSave={submit} canSave={!!name.trim()}>
      {/* Mode toggle */}
      {!isEdit && (
        <div style={{
          display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4,
          background: 'var(--surface-2)', borderRadius: 12, padding: 4,
          border: '1px solid var(--border)', marginBottom: 14,
        }}>
          {[{ id: 'manual', label: '📝 Manual' }, { id: 'text', label: '📋 Paste Text' }].map(m => (
            <button key={m.id} onClick={() => setMode(m.id)} style={{
              padding: '9px 0', borderRadius: 9, border: 0,
              background: mode === m.id ? 'var(--surface)' : 'transparent',
              color: mode === m.id ? 'var(--text)' : 'var(--muted)',
              fontSize: 13, fontWeight: 600, cursor: 'pointer', font: 'inherit',
            }}>{m.label}</button>
          ))}
        </div>
      )}

      {/* Text paste mode */}
      {mode === 'text' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontSize: 12.5, color: 'var(--muted)' }}>
            Paste a product label, recipe, or text like:<br/>
            <span style={{ fontFamily: 'monospace', fontSize: 11, color: 'var(--text)' }}>
              Greek Yogurt — 170g — 120 kcal | carbs 8g | protein 15g | fat 3g
            </span>
          </div>
          <textarea value={pasteText} onChange={e => setPasteText(e.target.value)}
            rows={5} placeholder="Paste food info here…"
            style={{ ...inputStyle, resize: 'vertical', lineHeight: 1.5 }}/>
          <button onClick={parseText} disabled={!pasteText.trim()} style={{
            padding: '11px', borderRadius: 12,
            background: pasteText.trim() ? 'var(--accent)' : 'var(--surface-2)',
            color: pasteText.trim() ? 'var(--on-accent)' : 'var(--muted)',
            border: 0, fontSize: 14, fontWeight: 600, cursor: pasteText.trim() ? 'pointer' : 'default',
            font: 'inherit',
          }}>
            Parse &amp; Review →
          </button>
        </div>
      )}

      {/* Manual form */}
      {mode === 'manual' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {parsed && (
            <div style={{
              padding: '10px 12px', borderRadius: 10,
              background: 'rgba(79,168,98,0.12)', border: '1px solid var(--c-protein)',
              fontSize: 12.5, color: 'var(--c-protein)', fontWeight: 500,
            }}>
              ✓ Fields pre-filled from pasted text. Review and edit before saving.
            </div>
          )}

          <div style={{ padding: 12, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
            <FormRow label="Item Name">
              <input value={name} onChange={e => setName(e.target.value)} placeholder="e.g. Greek Yogurt Brand X" style={inputStyle}/>
            </FormRow>
            <FormRow label="Arabic Name (optional)">
              <input value={nameAr} onChange={e => setNameAr(e.target.value)} placeholder="الاسم بالعربية" dir="auto" style={inputStyle}/>
            </FormRow>

            {/* Emoji picker */}
            <FormRow label="Icon">
              <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap' }}>
                {EMOJI_OPTIONS.map(em => (
                  <button key={em} onClick={() => setEmoji(em)} style={{
                    width: 36, height: 36, borderRadius: 9, fontSize: 18,
                    background: emoji === em ? 'var(--text)' : 'var(--surface-2)',
                    border: '1px solid var(--border)', cursor: 'pointer', font: 'inherit',
                  }}>{em}</button>
                ))}
              </div>
            </FormRow>

            {/* Category */}
            <FormRow label="Category">
              <select value={category} onChange={e => setCategory(e.target.value)} style={inputStyle}>
                {CAT_OPTIONS.map(c => <option key={c.id} value={c.id}>{c.emoji} {c.label}</option>)}
              </select>
            </FormRow>

            {/* Serving */}
            <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 0.8fr', gap: 8 }}>
              <NumberField label="Serving Amount" value={serving} onChange={setServing}/>
              <FormRow label="Unit">
                <select value={unit} onChange={e => setUnit(e.target.value)} style={inputStyle}>
                  {UNIT_OPTIONS.map(u => <option key={u} value={u}>{u}</option>)}
                </select>
              </FormRow>
            </div>
          </div>

          {/* Macros */}
          <div style={{ padding: 12, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <NumberField label="Calories"  value={cal}     onChange={setCal}     suffix="kcal"/>
            <NumberField label="Protein"   value={protein} onChange={setProtein} suffix="g"/>
            <NumberField label="Carbs"     value={carbs}   onChange={setCarbs}   suffix="g"/>
            <NumberField label="Fat"       value={fat}     onChange={setFat}     suffix="g"/>
          </div>

          {/* Tags & Note */}
          <div style={{ padding: 12, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
            <FormRow label="Tags (comma separated)">
              <input value={tagsStr} onChange={e => setTagsStr(e.target.value)} placeholder="yogurt, dairy, high protein" style={inputStyle}/>
            </FormRow>
            <FormRow label="Note (optional)">
              <input value={note} onChange={e => setNote(e.target.value)} placeholder="My usual yogurt brand" style={inputStyle}/>
            </FormRow>
          </div>
        </div>
      )}
    </SheetShell>
  );
}

// ─────────────────────────────────────────────────────────────
// LOG FOOD SHEET — adjust amount + meal type + date + note
// ─────────────────────────────────────────────────────────────
function LogFoodSheet({ food, defaultDate, defaultMeal, onSave, onClose }) {
  // food can be a built-in, local item, or a recent meal entry
  const [meal, setMeal]     = React.useState(defaultMeal || 'breakfast');
  const [date, setDate]     = React.useState(defaultDate || NUTRI_TODAY);
  const [amount, setAmount] = React.useState(String(food.serving || food.amount || 1));
  const [note, setNote]     = React.useState(food.note || '');
  const [time, setTime]     = React.useState(new Date().toTimeString().slice(0, 5));

  // Scale macros based on amount input
  const baseServing = food.serving || food.amount || 1;
  const scaled = React.useMemo(() => {
    const ratio = (+amount || baseServing) / baseServing;
    return {
      cal:       Math.round((food.cal      || food.calories      || 0) * ratio),
      protein_g: +((food.protein_g         || 0) * ratio).toFixed(1),
      carbs_g:   +((food.carbs_g           || 0) * ratio).toFixed(1),
      fat_g:     +((food.fat_g             || 0) * ratio).toFixed(1),
    };
  }, [amount, food, baseServing]);

  function submit() {
    onSave({
      date, meal, time, note: note.trim(),
      name:      food.name  || 'Meal',
      emoji:     food.emoji || NUTRI_MEAL_ICON[meal] || '🍽️',
      calories:  scaled.cal,
      protein_g: scaled.protein_g,
      carbs_g:   scaled.carbs_g,
      fat_g:     scaled.fat_g,
      amount:    +amount || baseServing,
      unit:      food.unit || 'g',
      source:    food.source || 'builtin',
      sourceId:  food.id || null,
    });
  }

  return (
    <SheetShell title="Log Food" onClose={onClose} onSave={submit} canSave={true}>
      {/* Food info header */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: '12px 14px', background: 'var(--surface)',
        border: '1px solid var(--border)', borderRadius: 14, marginBottom: 14,
      }}>
        <div style={{ fontSize: 36 }}>{food.emoji || '🍽️'}</div>
        <div>
          <div style={{ fontSize: 16, fontWeight: 600 }}>{food.name}</div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)' }}>
            {food.cal || food.calories || 0} kcal per {food.serving || food.amount || 1}{food.unit || 'g'}
          </div>
        </div>
      </div>

      <Segment options={['breakfast','lunch','dinner','snacks']} value={meal} onChange={setMeal}/>

      <div style={{ marginTop: 14, padding: 12, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14, display: 'flex', flexDirection: 'column', gap: 10 }}>
        <FormRow label={`Amount (${food.unit || 'g'})`}>
          <div style={{ position: 'relative' }}>
            <input type="number" inputMode="decimal" value={amount} onChange={e => setAmount(e.target.value)}
              style={{ ...inputStyle, paddingRight: 36 }}/>
            <span style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', fontSize: 12, color: 'var(--muted)' }}>
              {food.unit || 'g'}
            </span>
          </div>
        </FormRow>
        <FormRow label="Date">
          <input type="date" value={date} onChange={e => setDate(e.target.value)} style={inputStyle}/>
        </FormRow>
        <FormRow label="Time">
          <input type="time" value={time} onChange={e => setTime(e.target.value)} style={inputStyle}/>
        </FormRow>
        <FormRow label="Note (optional)">
          <input value={note} onChange={e => setNote(e.target.value)} placeholder="Add a note…" style={inputStyle}/>
        </FormRow>
      </div>

      {/* Scaled macros preview */}
      <div style={{
        marginTop: 12, padding: '12px 14px',
        background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 14,
        display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 8, textAlign: 'center',
      }}>
        {[
          { label: 'Calories', val: scaled.cal, unit: 'kcal', color: 'var(--text)' },
          { label: 'Protein',  val: scaled.protein_g, unit: 'g', color: 'var(--c-protein)' },
          { label: 'Carbs',    val: scaled.carbs_g,   unit: 'g', color: 'var(--c-carbs)' },
          { label: 'Fat',      val: scaled.fat_g,     unit: 'g', color: 'var(--c-fat)' },
        ].map(m => (
          <div key={m.label}>
            <div style={{ fontSize: 18, fontWeight: 700, color: m.color }}>{m.val}</div>
            <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{m.label}</div>
            <div style={{ fontSize: 9.5, color: 'var(--muted-2)' }}>{m.unit}</div>
          </div>
        ))}
      </div>
    </SheetShell>
  );
}

// ─────────────────────────────────────────────────────────────
// DELETE DAY CONFIRM DIALOG
// ─────────────────────────────────────────────────────────────
function DeleteDayConfirmDialog({ date, onConfirm, onCancel }) {
  const label = (() => {
    try { return new Date(date + 'T00:00:00').toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' }); }
    catch { return date; }
  })();
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(0,0,0,0.55)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24,
    }}>
      <div style={{
        background: 'var(--bg)', borderRadius: 20,
        padding: 22, width: '100%', maxWidth: 340,
        boxShadow: 'var(--shadow-lg)',
      }}>
        <div style={{ fontSize: 16, fontWeight: 700, marginBottom: 8 }}>Delete Day?</div>
        <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 20, lineHeight: 1.55 }}>
          This will remove all meals, food items, macros, and notes logged for <strong>{label}</strong>.
          This cannot be undone.
        </div>
        <button onClick={onConfirm} style={{
          width: '100%', padding: '12px 0', borderRadius: 12, marginBottom: 8,
          background: '#d9534f', border: 'none',
          color: '#fff', fontSize: 14, fontWeight: 700, cursor: 'pointer',
          font: 'inherit',
        }}>Delete Day's Entry</button>
        <button onClick={onCancel} style={{
          width: '100%', padding: '11px 0', borderRadius: 12,
          background: 'transparent', border: '1px solid var(--border)',
          color: 'var(--text)', fontSize: 13, cursor: 'pointer', font: 'inherit',
        }}>Cancel</button>
      </div>
    </div>
  );
}

// DUPLICATE ENTRY DIALOG
// ─────────────────────────────────────────────────────────────
function DuplicateEntryDialog({ date, existingCount, onReplace, onMerge, onKeep, onClose }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 60,
      background: 'rgba(0,0,0,0.5)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24,
      animation: 'fadeIn .2s ease',
    }}>
      <div style={{
        background: 'var(--bg)', borderRadius: 20,
        padding: 22, width: '100%', maxWidth: 360,
        boxShadow: 'var(--shadow-lg)',
      }}>
        <div style={{ fontSize: 16, fontWeight: 700, marginBottom: 8 }}>Duplicate Date Detected</div>
        <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 16 }}>
          You already have <strong>{existingCount} meal{existingCount !== 1 ? 's' : ''}</strong> logged on <strong>{date}</strong>.
          How would you like to proceed?
        </div>

        {[
          { label: '🔄 Replace Existing', sub: 'Delete all existing meals for this date and use the new data.', action: onReplace, primary: false },
          { label: '➕ Merge New Items', sub: 'Keep existing meals and add new ones (may create duplicates).', action: onMerge, primary: true },
          { label: '🚫 Keep Existing', sub: 'Discard the new data for this date.', action: onKeep, primary: false },
        ].map(opt => (
          <button key={opt.label} onClick={opt.action} style={{
            width: '100%', textAlign: 'left', padding: '12px 14px',
            background: opt.primary ? 'var(--accent)' : 'var(--surface)',
            color: opt.primary ? 'var(--on-accent)' : 'var(--text)',
            border: '1px solid ' + (opt.primary ? 'var(--accent)' : 'var(--border)'),
            borderRadius: 12, cursor: 'pointer', font: 'inherit', marginBottom: 8,
          }}>
            <div style={{ fontSize: 14, fontWeight: 600 }}>{opt.label}</div>
            <div style={{ fontSize: 11.5, opacity: 0.75, marginTop: 2 }}>{opt.sub}</div>
          </button>
        ))}

        <button onClick={onClose} style={{
          width: '100%', padding: '11px', borderRadius: 12, marginTop: 2,
          background: 'transparent', border: '1px solid var(--border-2)',
          color: 'var(--muted)', font: 'inherit', fontSize: 13, cursor: 'pointer',
        }}>Cancel</button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CALORIES CALENDAR — enhanced with meal sections + notes
// ─────────────────────────────────────────────────────────────
function CaloriesCalendar({ entries, goals, notes, onLogFood, onOpenMeal }) {
  const today = new Date();
  const [yr, setYr] = React.useState(today.getFullYear());
  const [mo, setMo] = React.useState(today.getMonth());
  const todayISO = isoOf(today);
  const [selected, setSelected] = React.useState(todayISO);
  const [confirmDelete, setConfirmDelete] = React.useState(false);

  const totalsByDay = React.useMemo(() => {
    const m = {};
    entries.forEach(e => { m[e.date] = (m[e.date] || 0) + (+e.calories || 0); });
    return m;
  }, [entries]);

  const monthName  = new Date(yr, mo, 1).toLocaleString(undefined, { month: 'long', year: 'numeric' });
  const firstDay   = new Date(yr, mo, 1).getDay();
  const daysInMonth= new Date(yr, mo + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < firstDay; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) cells.push(d);

  function shiftMonth(delta) {
    let nm = mo + delta, ny = yr;
    if (nm < 0)  { nm = 11; ny -= 1; }
    if (nm > 11) { nm = 0;  ny += 1; }
    setMo(nm); setYr(ny);
  }

  // Navigate selected day
  function shiftDay(delta) {
    const d = new Date(selected + 'T00:00:00');
    d.setDate(d.getDate() + delta);
    const iso = isoOf(d);
    setSelected(iso);
    const newMo = d.getMonth(), newYr = d.getFullYear();
    if (newMo !== mo || newYr !== yr) { setMo(newMo); setYr(newYr); }
  }

  const monthAvg = (() => {
    const monthEs = entries.filter(e => {
      const [y, m] = e.date.split('-').map(Number);
      return y === yr && m - 1 === mo;
    });
    const days = new Set(monthEs.map(e => e.date));
    if (!days.size) return 0;
    return Math.round(monthEs.reduce((s, e) => s + (+e.calories || 0), 0) / days.size);
  })();

  return (
    <div style={{ padding: '12px 16px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ paddingTop: 4 }}>
        <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>Calendar</div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2 }}>
          Avg this month · <strong>{monthAvg.toLocaleString()} kcal</strong>
        </div>
      </div>

      {/* Month grid */}
      <div style={{ ...nutriStyles.card, padding: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <button onClick={() => shiftMonth(-1)} style={iconBtnGhost}>‹</button>
          <div style={{ fontSize: 14, fontWeight: 600 }}>{monthName}</div>
          <button onClick={() => shiftMonth(+1)} style={iconBtnGhost}>›</button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 2, marginBottom: 6 }}>
          {['S','M','T','W','T','F','S'].map((d, i) => (
            <div key={i} style={{ textAlign: 'center', fontSize: 10, color: 'var(--muted)', fontWeight: 600, letterSpacing: '0.04em' }}>{d}</div>
          ))}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 3 }}>
          {cells.map((d, i) => {
            if (!d) return <div key={i}/>;
            const iso = `${yr}-${String(mo+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
            const total = totalsByDay[iso] || 0;
            const isToday = iso === todayISO;
            const isSel   = iso === selected;
            const intensity = total ? Math.min(1, total / goals.calories) : 0;
            return (
              <button key={i} onClick={() => setSelected(iso)} style={{
                aspectRatio: '1/1', display: 'flex', flexDirection: 'column',
                alignItems: 'center', justifyContent: 'center', borderRadius: 8,
                border: isSel ? '2px solid var(--text)' : '1px solid var(--border)',
                background: total
                  ? `color-mix(in oklch, var(--c-protein) ${intensity * 28}%, var(--surface-2))`
                  : 'var(--surface-2)',
                color: 'var(--text)', cursor: 'pointer', font: 'inherit', gap: 1,
              }}>
                <div style={{ fontSize: 11.5, fontWeight: isToday ? 700 : 500 }}>{d}</div>
                {total > 0 && (
                  <div style={{ fontSize: 8, color: 'var(--muted)', fontWeight: 500 }}>
                    {total >= 1000 ? (total / 1000).toFixed(1) + 'k' : total}
                  </div>
                )}
              </button>
            );
          })}
        </div>
      </div>

      {/* Day navigation bar */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <button onClick={() => shiftDay(-1)} style={iconBtnGhost}>‹</button>
        <div style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-0.01em' }}>
          {selected === todayISO ? 'Today · ' : ''}{prettyDateShort(selected)}
          {', '}
          {new Date(selected + 'T00:00:00').getFullYear()}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 2 }}>
          {entries.some(e => e.date === selected) && (
            <button
              onClick={() => setConfirmDelete(true)}
              title="Delete this day's entries"
              style={{
                ...iconBtnGhost,
                color: '#d9534f',
                opacity: 0.75,
              }}>
              🗑
            </button>
          )}
          <button onClick={() => shiftDay(+1)} style={iconBtnGhost}>›</button>
        </div>
      </div>

      {/* Day detail */}
      <DayDetailPanel
        entries={entries.filter(e => e.date === selected)}
        goals={goals}
        note={notes && notes[selected]}
        date={selected}/>

      <div style={{ height: 60 }}/>

      {confirmDelete && (
        <DeleteDayConfirmDialog
          date={selected}
          onConfirm={() => {
            window.Store.replaceMealsForDate(selected, []);
            window.Store.setDayNote(selected, '');
            setConfirmDelete(false);
          }}
          onCancel={() => setConfirmDelete(false)}
        />
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// DAY DETAIL PANEL — meal sections, item tables, note, donut
// ─────────────────────────────────────────────────────────────
function DayDetailPanel({ entries, goals, note, date }) {
  const totals = entries.reduce((a, e) => ({
    calories: a.calories + (+e.calories || 0),
    protein_g: a.protein_g + (+e.protein_g || 0),
    carbs_g:   a.carbs_g   + (+e.carbs_g   || 0),
    fat_g:     a.fat_g     + (+e.fat_g     || 0),
  }), { calories: 0, protein_g: 0, carbs_g: 0, fat_g: 0 });

  // Group by meal
  const byMeal = { breakfast: [], lunch: [], dinner: [], snacks: [] };
  entries.forEach(e => {
    const m = e.meal === 'snack' ? 'snacks' : (e.meal || 'snacks');
    if (byMeal[m]) byMeal[m].push(e);
    else byMeal.snacks.push(e);
  });

  if (entries.length === 0) {
    return (
      <div style={{ ...nutriStyles.card, padding: '22px 18px', textAlign: 'center', color: 'var(--muted)' }}>
        <div style={{ fontSize: 28, marginBottom: 6 }}>📅</div>
        <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>No meals on this day</div>
        <div style={{ fontSize: 12.5, marginTop: 4 }}>Use + to log food for any date.</div>
      </div>
    );
  }

  // Donut chart data
  const donutSlices = Object.entries(byMeal)
    .map(([meal, es]) => ({
      meal,
      label: NUTRI_MEAL_LABEL[meal] || meal,
      cal: es.reduce((s, e) => s + (+e.calories || 0), 0),
      color: NUTRI_MEAL_COLOR[meal] || '#D0CDB8',
    }))
    .filter(s => s.cal > 0);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {/* Day totals summary card */}
      <div style={{ ...nutriStyles.card, padding: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <span style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.03em' }}>
                {totals.calories.toLocaleString()}
              </span>
              <span style={{ fontSize: 12.5, color: 'var(--muted)' }}>
                / {goals.calories.toLocaleString()} kcal
              </span>
            </div>
            <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 2 }}>
              {Math.round((totals.calories / goals.calories) * 100)}% of daily goal
            </div>
          </div>
          <MealDonutChart slices={donutSlices} size={72}/>
        </div>

        {/* Macro grid */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10, marginTop: 6 }}>
          {[
            { label: 'Protein', val: totals.protein_g, goal: goals.protein_g, color: 'var(--c-protein)' },
            { label: 'Carbs',   val: totals.carbs_g,   goal: goals.carbs_g,   color: 'var(--c-carbs)' },
            { label: 'Fat',     val: totals.fat_g,     goal: goals.fat_g,     color: 'var(--c-fat)' },
          ].map(m => (
            <div key={m.label}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                <span style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 600 }}>{m.label}</span>
                <span style={{ fontSize: 12, fontWeight: 600 }}>{Math.round(m.val)}g</span>
              </div>
              <div style={{ height: 4, borderRadius: 99, background: 'var(--border-2)', overflow: 'hidden', marginTop: 4 }}>
                <div style={{ width: `${Math.min(1, m.val / (m.goal || 1)) * 100}%`, height: '100%', background: m.color, borderRadius: 99 }}/>
              </div>
              <div style={{ fontSize: 10, color: 'var(--muted)', marginTop: 2 }}>goal {m.goal}g</div>
            </div>
          ))}
        </div>

        {/* Donut legend */}
        {donutSlices.length > 0 && (
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 10 }}>
            {donutSlices.map(s => (
              <div key={s.meal} style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                <div style={{ width: 8, height: 8, borderRadius: '50%', background: s.color, flexShrink: 0 }}/>
                <span style={{ fontSize: 11, color: 'var(--muted)' }}>
                  {s.label} <strong style={{ color: 'var(--text)' }}>{s.cal} kcal</strong>
                  {' '}({Math.round((s.cal / totals.calories) * 100)}%)
                </span>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Meal sections */}
      {Object.entries(byMeal).map(([mealKey, mealEntries]) => {
        if (mealEntries.length === 0) return null;
        const mealTotal = mealEntries.reduce((a, e) => ({
          cal: a.cal + (+e.calories || 0),
          protein_g: a.protein_g + (+e.protein_g || 0),
          carbs_g:   a.carbs_g   + (+e.carbs_g   || 0),
          fat_g:     a.fat_g     + (+e.fat_g     || 0),
        }), { cal: 0, protein_g: 0, carbs_g: 0, fat_g: 0 });

        return (
          <div key={mealKey} style={{ ...nutriStyles.card, padding: 0, overflow: 'hidden' }}>
            {/* Meal header */}
            <div style={{
              padding: '10px 12px',
              background: `${NUTRI_MEAL_COLOR[mealKey]}22`,
              borderBottom: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                <span style={{ fontSize: 16 }}>{NUTRI_MEAL_ICON[mealKey]}</span>
                <span style={{ fontSize: 14, fontWeight: 600 }}>{NUTRI_MEAL_LABEL[mealKey]}</span>
              </div>
              <div style={{ fontSize: 12.5, color: 'var(--muted)', textAlign: 'right' }}>
                <strong style={{ color: 'var(--text)' }}>{Math.round(mealTotal.cal)}</strong> kcal
                {' · '}P <span style={{ color: 'var(--c-protein)' }}>{Math.round(mealTotal.protein_g)}g</span>
                {' '}C <span style={{ color: 'var(--c-carbs)' }}>{Math.round(mealTotal.carbs_g)}g</span>
                {' '}F <span style={{ color: 'var(--c-fat)' }}>{Math.round(mealTotal.fat_g)}g</span>
              </div>
            </div>

            {/* Items table */}
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
              <thead>
                <tr style={{ background: 'var(--surface-2)' }}>
                  {['Item', 'Amt', 'Cal', 'P', 'C', 'F'].map((h, i) => (
                    <th key={h} style={{
                      padding: '6px 8px', textAlign: i === 0 ? 'left' : 'right',
                      fontSize: 10, color: 'var(--muted)', fontWeight: 600,
                      letterSpacing: '0.04em', textTransform: 'uppercase',
                      borderBottom: '1px solid var(--border)',
                    }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {mealEntries.map(e => {
                  // If entry has sub-items, expand them; otherwise one row
                  // Helper: '' means macro was absent in input; 0 is valid and must show as 0
                  const _mv = (a, b) => (a !== '' && a != null) ? a : (b !== '' && b != null) ? b : '—';
                  const rows = (Array.isArray(e.items) && e.items.length > 0)
                    ? e.items.map(it => ({
                        name: it.name,
                        amt:  it.qty || it.amount || '',
                        cal:  it.cal != null ? it.cal : (it.calories != null ? it.calories : 0),
                        p:    _mv(it.protein_g, it.p),
                        c:    _mv(it.carbs_g,   it.c),
                        f:    _mv(it.fat_g,     it.f),
                      }))
                    : [{
                        name: e.name || 'Meal',
                        amt:  e.amount ? `${e.amount}${e.unit || 'g'}` : '',
                        cal:  e.calories || 0,
                        p:    e.protein_g || 0,
                        c:    e.carbs_g   || 0,
                        f:    e.fat_g     || 0,
                      }];

                  return rows.map((row, ri) => (
                    <tr key={e.id + ri} style={{ borderBottom: '1px solid var(--border)' }}>
                      <td style={{ padding: '7px 8px', maxWidth: 120, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{row.name}</td>
                      <td style={{ padding: '7px 8px', textAlign: 'right', color: 'var(--muted)' }}>{row.amt}</td>
                      <td style={{ padding: '7px 8px', textAlign: 'right', fontWeight: 600 }}>{Math.round(+row.cal || 0)}</td>
                      <td style={{ padding: '7px 8px', textAlign: 'right', color: 'var(--c-protein)' }}>{typeof row.p === 'number' ? Math.round(row.p) : row.p}</td>
                      <td style={{ padding: '7px 8px', textAlign: 'right', color: 'var(--c-carbs)' }}>{typeof row.c === 'number' ? Math.round(row.c) : row.c}</td>
                      <td style={{ padding: '7px 8px', textAlign: 'right', color: 'var(--c-fat)' }}>{typeof row.f === 'number' ? Math.round(row.f) : row.f}</td>
                    </tr>
                  ));
                })}
              </tbody>
            </table>
          </div>
        );
      })}

      {/* Day note */}
      {note && (
        <div style={{
          ...nutriStyles.card, padding: 14,
          borderLeft: '3px solid var(--accent)',
        }}>
          <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 6 }}>
            📝 Note
          </div>
          <div style={{ fontSize: 13.5, lineHeight: 1.6, whiteSpace: 'pre-wrap', direction: 'auto' }}>{note}</div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// MEAL DONUT CHART — SVG
// ─────────────────────────────────────────────────────────────
function MealDonutChart({ slices, size = 80 }) {
  if (!slices || slices.length === 0) return (
    <div style={{ width: size, height: size, borderRadius: '50%', background: 'var(--surface-2)', border: '2px solid var(--border)' }}/>
  );
  const total = slices.reduce((s, sl) => s + sl.cal, 0);
  if (total === 0) return null;
  const cx = size / 2, cy = size / 2;
  const r  = size / 2 - 6;
  const sw = 10;
  let cumPct = 0;
  const paths = slices.map(sl => {
    const pct   = sl.cal / total;
    const start = cumPct;
    cumPct += pct;
    const a1 = (start * 360 - 90) * Math.PI / 180;
    const a2 = (cumPct * 360 - 90) * Math.PI / 180;
    const x1 = cx + r * Math.cos(a1), y1 = cy + r * Math.sin(a1);
    const x2 = cx + r * Math.cos(a2), y2 = cy + r * Math.sin(a2);
    const large = pct > 0.5 ? 1 : 0;
    return { d: `M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2}`, color: sl.color, pct };
  });
  return (
    <svg width={size} height={size} style={{ flexShrink: 0 }}>
      {/* track */}
      <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border-2)" strokeWidth={sw}/>
      {/* slices */}
      {paths.map((p, i) => (
        <path key={i} d={p.d} fill="none" stroke={p.color} strokeWidth={sw} strokeLinecap="round"/>
      ))}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// RANGE HELPERS — used by CaloriesStats
// ─────────────────────────────────────────────────────────────
const RANGE_PRESETS = [
  { id: 'today',       label: 'Today' },
  { id: 'last7',       label: 'Last 7 Days' },
  { id: 'last14',      label: 'Last 14 Days' },
  { id: 'last30',      label: 'Last 30 Days' },
  { id: 'thisMonth',   label: 'This Month' },
  { id: 'lastMonth',   label: 'Last Month' },
  { id: 'thisQuarter', label: 'This Quarter' },
  { id: 'thisYear',    label: 'This Year' },
  { id: 'allTime',     label: 'All Time' },
  { id: 'custom',      label: '📅 Custom' },
];

function _rangeCompute(rangeId, customStart, customEnd, entries, savedCustoms) {
  const today = isoOf(new Date());
  const now   = new Date();
  // Saved custom filters (cf_…) created via Manage Filters
  if (rangeId && String(rangeId).slice(0, 3) === 'cf_') {
    const cf = (savedCustoms || []).find(c => c.id === rangeId);
    if (cf) { const [rs, re] = (cf.from <= cf.to) ? [cf.from, cf.to] : [cf.to, cf.from]; return { start: rs, end: re, label: cf.label }; }
    return { start: daysAgo(29), end: today, label: 'Last 30 Days' };
  }
  switch (rangeId) {
    case 'today':        return { start: today, end: today, label: 'Today' };
    case 'last7':        return { start: daysAgo(6),  end: today, label: 'Last 7 Days' };
    case 'last14':       return { start: daysAgo(13), end: today, label: 'Last 14 Days' };
    case 'last30':       return { start: daysAgo(29), end: today, label: 'Last 30 Days' };
    case 'thisMonth': {
      const s = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-01`;
      return { start: s, end: today, label: 'This Month' };
    }
    case 'lastMonth': {
      const lm1 = new Date(now.getFullYear(), now.getMonth()-1, 1);
      const lmE = new Date(now.getFullYear(), now.getMonth(), 0);
      return { start: isoOf(lm1), end: isoOf(lmE), label: 'Last Month' };
    }
    case 'thisQuarter': {
      const qStart = new Date(now.getFullYear(), Math.floor(now.getMonth()/3)*3, 1);
      return { start: isoOf(qStart), end: today, label: 'This Quarter' };
    }
    case 'thisYear':
      return { start: `${now.getFullYear()}-01-01`, end: today, label: 'This Year' };
    case 'allTime': {
      const dates = entries.map(e => e.date).filter(Boolean).sort();
      return dates.length
        ? { start: dates[0], end: today, label: 'All Time' }
        : { start: today,    end: today, label: 'All Time' };
    }
    case 'custom': {
      if (!customStart && !customEnd) return { start: daysAgo(29), end: today, label: 'Custom Range' };
      const s = customStart || today, e = customEnd || today;
      const [rs, re] = s <= e ? [s, e] : [e, s];
      return { start: rs, end: re, label: `${rs} → ${re}` };
    }
    default: return { start: daysAgo(29), end: today, label: 'Last 30 Days' };
  }
}

function _buildRangeData(startISO, endISO, entries) {
  const arr = [];
  const cur = new Date(startISO + 'T00:00:00');
  const end = new Date(endISO   + 'T00:00:00');
  while (cur <= end) {
    const iso = isoOf(cur);
    const de  = entries.filter(e => e.date === iso);
    const cal  = de.reduce((s, e) => s + (+e.calories  || 0), 0);
    const prot = de.reduce((s, e) => s + (+e.protein_g || 0), 0);
    const carb = de.reduce((s, e) => s + (+e.carbs_g   || 0), 0);
    const fat  = de.reduce((s, e) => s + (+e.fat_g     || 0), 0);
    const bk = de.filter(e => e.meal === 'breakfast').reduce((s, e) => s + (+e.calories || 0), 0);
    const lu = de.filter(e => e.meal === 'lunch').reduce((s, e) => s + (+e.calories || 0), 0);
    const di = de.filter(e => e.meal === 'dinner').reduce((s, e) => s + (+e.calories || 0), 0);
    const sn = de.filter(e => e.meal === 'snack' || e.meal === 'snacks').reduce((s, e) => s + (+e.calories || 0), 0);
    arr.push({ iso, d: new Date(cur), cal, prot, carb, fat, bk, lu, di, sn, hasData: cal > 0 });
    cur.setDate(cur.getDate() + 1);
  }
  return arr;
}

// Down-sample daily range data to ≤ maxBars chart points.
// ≤60 days → daily, ≤182 days → weekly avg/day, else → monthly avg/day.
function _sampleChart(rangeData, maxBars) {
  if (rangeData.length <= maxBars) {
    return rangeData.map(d => ({
      label: d.d.getDate(), iso: d.iso,
      value: d.cal, prot: d.prot, carb: d.carb, fat: d.fat,
    }));
  }
  if (rangeData.length <= 182) {
    const wMap = {};
    rangeData.forEach(d => {
      const ws = new Date(d.d);
      ws.setDate(ws.getDate() - ws.getDay());
      const wk = isoOf(ws);
      if (!wMap[wk]) wMap[wk] = {
        label: ws.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),
        iso: wk, total: 0, prot: 0, carb: 0, fat: 0, n: 0,
      };
      if (d.hasData) {
        wMap[wk].total += d.cal; wMap[wk].prot += d.prot;
        wMap[wk].carb  += d.carb; wMap[wk].fat  += d.fat; wMap[wk].n++;
      }
    });
    return Object.values(wMap).map(w => ({
      label: w.label, iso: w.iso,
      value: w.n ? Math.round(w.total / w.n) : 0,
      prot:  w.n ? +(w.prot / w.n).toFixed(1) : 0,
      carb:  w.n ? +(w.carb / w.n).toFixed(1) : 0,
      fat:   w.n ? +(w.fat  / w.n).toFixed(1) : 0,
    }));
  }
  const mMap = {};
  rangeData.forEach(d => {
    const mk = d.iso.slice(0, 7);
    const [y, m] = mk.split('-').map(Number);
    if (!mMap[mk]) mMap[mk] = {
      label: new Date(y, m-1, 1).toLocaleDateString(undefined, { month: 'short', year: '2-digit' }),
      iso: mk, total: 0, prot: 0, carb: 0, fat: 0, n: 0,
    };
    if (d.hasData) {
      mMap[mk].total += d.cal; mMap[mk].prot += d.prot;
      mMap[mk].carb  += d.carb; mMap[mk].fat  += d.fat; mMap[mk].n++;
    }
  });
  return Object.values(mMap).map(m => ({
    label: m.label, iso: m.iso,
    value: m.n ? Math.round(m.total / m.n) : 0,
    prot:  m.n ? +(m.prot / m.n).toFixed(1) : 0,
    carb:  m.n ? +(m.carb / m.n).toFixed(1) : 0,
    fat:   m.n ? +(m.fat  / m.n).toFixed(1) : 0,
  }));
}

// ─────────────────────────────────────────────────────────────
// RANGE SELECTOR COMPONENT
// ─────────────────────────────────────────────────────────────
function RangeSelector({ rangeId, setRangeId, customStart, customEnd, setCustomStart, setCustomEnd, savedCustoms, onManage }) {
  const Store = window.Store;
  const cfg = (Store && Store.timeFilterConfig) ? Store.timeFilterConfig('calories') : {};
  const allIds = RANGE_PRESETS.map(p => p.id);
  const visibleIds = cfg.presets || allIds;
  const catMap = {}; RANGE_PRESETS.forEach(p => { catMap[p.id] = p; });
  // visible built-in presets (in catalog order, excluding 'custom') → saved customs → 'custom' (always on)
  const pills = [];
  RANGE_PRESETS.forEach(p => { if (p.id !== 'custom' && visibleIds.includes(p.id)) pills.push({ id: p.id, label: p.label }); });
  (savedCustoms || []).forEach(c => pills.push({ id: c.id, label: '★ ' + c.label }));
  if (catMap.custom) pills.push({ id: 'custom', label: catMap.custom.label });
  return (
    <div>
      <div style={{
        display: 'flex', gap: 6, overflowX: 'auto',
        margin: '0 -16px', padding: '0 16px 2px',
      }} className="nutri-scroll-x">
        {pills.map(p => (
          <button key={p.id} onClick={() => setRangeId(p.id)} style={{
            flexShrink: 0, padding: '6px 12px', borderRadius: 999,
            background: rangeId === p.id ? 'var(--text)' : 'var(--surface)',
            color:      rangeId === p.id ? 'var(--bg)'   : 'var(--text)',
            border: '1px solid ' + (rangeId === p.id ? 'var(--text)' : 'var(--border-2)'),
            fontSize: 12, fontWeight: 600, cursor: 'pointer', font: 'inherit', whiteSpace: 'nowrap',
          }}>{p.label}</button>
        ))}
        {onManage && (
          <button onClick={onManage} title="Manage filters" style={{
            flexShrink: 0, minWidth: 32, padding: '6px 9px', borderRadius: 999, display: 'grid', placeItems: 'center',
            background: 'var(--surface)', color: 'var(--muted)', border: '1px solid var(--border-2)', cursor: 'pointer', font: 'inherit', fontSize: 12.5,
          }}>⚙</button>
        )}
      </div>
      {rangeId === 'custom' && (
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginTop: 8 }}>
          <input type="date" value={customStart} onChange={e => setCustomStart(e.target.value)} style={{
            flex: 1, padding: '8px 10px', borderRadius: 10,
            border: '1px solid var(--border-2)', background: 'var(--surface)',
            color: 'var(--text)', font: 'inherit', fontSize: 13,
          }}/>
          <span style={{ fontSize: 13, color: 'var(--muted)', flexShrink: 0, fontWeight: 700 }}>→</span>
          <input type="date" value={customEnd} onChange={e => setCustomEnd(e.target.value)} style={{
            flex: 1, padding: '8px 10px', borderRadius: 10,
            border: '1px solid var(--border-2)', background: 'var(--surface)',
            color: 'var(--text)', font: 'inherit', fontSize: 13,
          }}/>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CALORIES STATS — charts + data tables
// ─────────────────────────────────────────────────────────────
function CaloriesStats({ entries, goals, weights, onCleanup }) {
  const [view, setView] = React.useState('all');
  const [rangeId,     setRangeId]     = React.useState('last30');
  const [customStart, setCustomStart] = React.useState('');
  const [customEnd,   setCustomEnd]   = React.useState('');
  const [showManage,  setShowManage]  = React.useState(false);

  // Customizable time filters (Manage Filters), persisted per-user via Store.
  const _tfCfg = (window.Store && window.Store.timeFilterConfig) ? window.Store.timeFilterConfig('calories') : {};
  const savedCustoms = _tfCfg.custom || [];
  const _calDefaultVisible = RANGE_PRESETS.map(p => p.id);

  // Compute date-range bounds
  const { start: rStart, end: rEnd, label: rLabel } = React.useMemo(
    () => _rangeCompute(rangeId, customStart, customEnd, entries, savedCustoms),
    [rangeId, customStart, customEnd, entries, JSON.stringify(savedCustoms)]
  );

  // Build day-by-day array for the selected range
  const rangeData = React.useMemo(
    () => _buildRangeData(rStart, rEnd, entries),
    [rStart, rEnd, entries]
  );

  const daysWithData = rangeData.filter(d => d.hasData);
  const avgCal  = daysWithData.length ? Math.round(daysWithData.reduce((s, d) => s + d.cal,  0) / daysWithData.length) : 0;
  const avgProt = daysWithData.length ? +(daysWithData.reduce((s, d) => s + d.prot, 0) / daysWithData.length).toFixed(1) : 0;
  const avgCarb = daysWithData.length ? +(daysWithData.reduce((s, d) => s + d.carb, 0) / daysWithData.length).toFixed(1) : 0;
  const avgFat  = daysWithData.length ? +(daysWithData.reduce((s, d) => s + d.fat,  0) / daysWithData.length).toFixed(1) : 0;

  // Macro totals and highest-day (for Step 7 Macros view)
  const totalProt   = Math.round(daysWithData.reduce((s, d) => s + d.prot, 0));
  const totalCarb   = Math.round(daysWithData.reduce((s, d) => s + d.carb, 0));
  const totalFat    = Math.round(daysWithData.reduce((s, d) => s + d.fat,  0));
  const highProtDay = daysWithData.length ? daysWithData.reduce((a, b) => b.prot > a.prot ? b : a) : null;
  const highCarbDay = daysWithData.length ? daysWithData.reduce((a, b) => b.carb > a.carb ? b : a) : null;
  const highFatDay  = daysWithData.length ? daysWithData.reduce((a, b) => b.fat  > a.fat  ? b : a) : null;
  const _dayLabel   = d => d && d.d instanceof Date ? d.d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) : '';

  // Weight statistics now live in the InBody tab only (data untouched).

  // Smart-sampled chart data (≤60 bars)
  const chartData = React.useMemo(() => _sampleChart(rangeData, 60), [rangeData]);
  const chartUnitLabel = rangeData.length > 182 ? 'Avg/day per month'
                       : rangeData.length > 60  ? 'Avg/day per week'
                       : 'Daily';

  const VIEWS = [
    { id: 'all',      label: 'All' },
    { id: 'calories', label: 'Calories' },
    { id: 'macros',   label: 'Macros' },
    { id: 'perMeal',  label: 'Per Meal' },
    { id: 'tables',   label: 'Tables' },
  ];
  // Weight lives only in the InBody tab now (data is untouched).
  const _allHdr = txt => (view === 'all'
    ? <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-0.01em', paddingTop: 8, borderTop: '1px solid var(--border)', marginTop: 4 }}>{txt}</div>
    : null);

  return (
    <div style={{ padding: '12px 16px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* Header */}
      <div style={{ paddingTop: 4 }}>
        <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>Stats</div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2 }}>{rLabel}</div>
      </div>

      {/* Time range selector (customizable — Manage Filters) */}
      <RangeSelector
        rangeId={rangeId} setRangeId={setRangeId}
        customStart={customStart} customEnd={customEnd}
        setCustomStart={setCustomStart} setCustomEnd={setCustomEnd}
        savedCustoms={savedCustoms} onManage={() => setShowManage(true)}/>

      {/* View tabs */}
      <div style={{ display: 'flex', gap: 6, overflowX: 'auto', margin: '0 -16px', padding: '0 16px 4px' }} className="nutri-scroll-x">
        {VIEWS.map(v => (
          <button key={v.id} onClick={() => setView(v.id)} style={{
            flexShrink: 0, padding: '7px 14px', borderRadius: 999,
            background: view === v.id ? 'var(--text)' : 'var(--surface)',
            color: view === v.id ? 'var(--bg)' : 'var(--text)',
            border: '1px solid ' + (view === v.id ? 'var(--text)' : 'var(--border-2)'),
            fontSize: 12.5, fontWeight: 600, cursor: 'pointer', font: 'inherit',
          }}>{v.label}</button>
        ))}
      </div>

      {/* Empty state — shown when no data in range */}
      {daysWithData.length === 0 && (
        <div style={{ ...nutriStyles.card, padding: '28px 18px', textAlign: 'center', color: 'var(--muted)' }}>
          <div style={{ fontSize: 32, marginBottom: 8 }}>📊</div>
          <div style={{ fontWeight: 600, fontSize: 14, color: 'var(--text)' }}>No data in this range</div>
          <div style={{ fontSize: 12.5, marginTop: 4, maxWidth: 240, margin: '6px auto 0' }}>
            Try a wider range, or log meals to see stats here.
          </div>
        </div>
      )}

      {/* ── CALORIES view ── */}
      {(view === 'calories' || view === 'all') && daysWithData.length > 0 && (
        <>
          {_allHdr('🔥 Calories')}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <StatTile label="Avg / day" value={avgCal.toLocaleString()} unit="kcal"/>
            <StatTile label="Goal" value={goals.calories.toLocaleString()} unit="kcal"
              delta={avgCal > 0 ? `${avgCal >= goals.calories ? '+' : ''}${(avgCal - goals.calories).toLocaleString()} vs goal` : '—'}/>
            <StatTile label="Days logged" value={daysWithData.length} unit={`/ ${rangeData.length} days`}/>
            <StatTile label="On track" value={daysWithData.filter(d => Math.abs(d.cal - goals.calories) <= goals.calories * 0.15).length} unit="days ±15%"/>
          </div>
          <SimpleBarChart
            title={`${chartUnitLabel} Calories — ${rLabel}`}
            data={chartData}
            goalLine={goals.calories}
            color="var(--text)"
            overColor="var(--c-carbs)"/>
        </>
      )}

      {/* ── MACROS view ── */}
      {(view === 'macros' || view === 'all') && daysWithData.length > 0 && (
        <>
          {_allHdr('🍗 Macros')}
          {/* Avg per day */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
            <StatTile label="Avg protein" value={avgProt} unit="g/day" color="var(--c-protein)"/>
            <StatTile label="Avg carbs"   value={avgCarb} unit="g/day" color="var(--c-carbs)"/>
            <StatTile label="Avg fat"     value={avgFat}  unit="g/day" color="var(--c-fat)"/>
          </div>

          {/* Macro distribution donut */}
          <MacroDistChart
            avgProt={avgProt} avgCarb={avgCarb} avgFat={avgFat}
            goalProt={goals.protein_g} goalCarb={goals.carbs_g} goalFat={goals.fat_g}/>

          {/* Macros by Day — grouped bars */}
          <MacroGroupedBarChart
            title={`Macros by Day — ${rLabel}`}
            data={daysWithData}/>

          {/* Totals over selected range */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
            <StatTile label="Total protein" value={totalProt}
              unit={`g · ${daysWithData.length}d`} color="var(--c-protein)"/>
            <StatTile label="Total carbs" value={totalCarb}
              unit={`g · ${daysWithData.length}d`} color="var(--c-carbs)"/>
            <StatTile label="Total fat" value={totalFat}
              unit={`g · ${daysWithData.length}d`} color="var(--c-fat)"/>
          </div>

          {/* Highest-macro days */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
            {highProtDay && <StatTile label="Best protein" value={Math.round(highProtDay.prot)}
              unit={`g · ${_dayLabel(highProtDay)}`} color="var(--c-protein)"/>}
            {highCarbDay && <StatTile label="Most carbs" value={Math.round(highCarbDay.carb)}
              unit={`g · ${_dayLabel(highCarbDay)}`} color="var(--c-carbs)"/>}
            {highFatDay  && <StatTile label="Most fat" value={Math.round(highFatDay.fat)}
              unit={`g · ${_dayLabel(highFatDay)}`} color="var(--c-fat)"/>}
          </div>

          {/* ── Per Macro Over Time — separate charts ── */}
          <div style={{ fontSize: 13, fontWeight: 700, letterSpacing: '-0.01em', paddingTop: 4 }}>
            Per Macro Over Time
          </div>
          {[
            { label: 'Protein', getValue: d => d.prot, color: 'var(--c-protein)', sk: 'nutri_ctype_prot' },
            { label: 'Carbs',   getValue: d => d.carb, color: 'var(--c-carbs)',   sk: 'nutri_ctype_carb' },
            { label: 'Fat',     getValue: d => d.fat,  color: 'var(--c-fat)',     sk: 'nutri_ctype_fat'  },
          ].map(m => (
            <div key={m.sk} style={{ ...nutriStyles.card, padding: 14 }}>
              <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10, display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                <span>{m.label} Over Time</span>
                <span style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 500 }}>{rLabel}</span>
              </div>
              <SingleSeriesChart data={daysWithData} getValue={m.getValue} color={m.color} storageKey={m.sk} unit="g"/>
            </div>
          ))}
        </>
      )}

      {/* ── PER MEAL view ── */}
      {(view === 'perMeal' || view === 'all') && daysWithData.length > 0 && (
        <>
          {_allHdr('🍽️ Per Meal')}
          {(() => {
            const mealAvg = { breakfast: 0, lunch: 0, dinner: 0, snacks: 0 };
            if (daysWithData.length) {
              mealAvg.breakfast = Math.round(daysWithData.reduce((s, d) => s + d.bk, 0) / daysWithData.length);
              mealAvg.lunch     = Math.round(daysWithData.reduce((s, d) => s + d.lu, 0) / daysWithData.length);
              mealAvg.dinner    = Math.round(daysWithData.reduce((s, d) => s + d.di, 0) / daysWithData.length);
              mealAvg.snacks    = Math.round(daysWithData.reduce((s, d) => s + d.sn, 0) / daysWithData.length);
            }
            return (
              <>
                {/* Meal calories by day — stacked bar chart */}
                <MealStackedBarChart
                  title={`Meal Calories by Day — ${rLabel}`}
                  data={daysWithData}/>

                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                  {[
                    { key: 'breakfast', label: 'Breakfast avg', val: mealAvg.breakfast, color: NUTRI_MEAL_COLOR.breakfast },
                    { key: 'lunch',     label: 'Lunch avg',     val: mealAvg.lunch,     color: NUTRI_MEAL_COLOR.lunch },
                    { key: 'dinner',    label: 'Dinner avg',    val: mealAvg.dinner,    color: NUTRI_MEAL_COLOR.dinner },
                    { key: 'snacks',    label: 'Snacks avg',    val: mealAvg.snacks,    color: NUTRI_MEAL_COLOR.snacks },
                  ].map(m => (
                    <StatTile key={m.key} label={m.label} value={m.val} unit="kcal" color={m.color}/>
                  ))}
                </div>
                <div style={{ ...nutriStyles.card, padding: '14px 16px' }}>
                  <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 14 }}>Avg calories per meal type</div>
                  {(() => {
                    const maxV = Math.max(mealAvg.breakfast, mealAvg.lunch, mealAvg.dinner, mealAvg.snacks) || 1;
                    return [
                      { label: 'Breakfast', val: mealAvg.breakfast, color: NUTRI_MEAL_COLOR.breakfast },
                      { label: 'Lunch',     val: mealAvg.lunch,     color: NUTRI_MEAL_COLOR.lunch },
                      { label: 'Dinner',    val: mealAvg.dinner,    color: NUTRI_MEAL_COLOR.dinner },
                      { label: 'Snacks',    val: mealAvg.snacks,    color: NUTRI_MEAL_COLOR.snacks },
                    ].map(m => (
                      <div key={m.label} style={{ marginBottom: 14 }}>
                        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
                          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)' }}>{m.label}</span>
                          <span style={{ fontSize: 13, fontWeight: 700, color: m.color }}>{m.val} <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--muted)' }}>kcal</span></span>
                        </div>
                        <div style={{ height: 10, background: 'var(--surface-2)', borderRadius: 5, overflow: 'hidden' }}>
                          <div style={{ width: `${(m.val / maxV) * 100}%`, height: '100%', background: m.color, borderRadius: 5, transition: 'width .4s ease' }}/>
                        </div>
                        <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 3, textAlign: 'right' }}>
                          {maxV > 0 ? Math.round((m.val / maxV) * 100) : 0}% of largest meal
                        </div>
                      </div>
                    ));
                  })()}
                </div>

                {/* ── Per Meal Over Time — separate charts ── */}
                <div style={{ fontSize: 13, fontWeight: 700, letterSpacing: '-0.01em', paddingTop: 4 }}>
                  Per Meal Over Time
                </div>
                {[
                  { label: 'Breakfast', key: 'bk', color: NUTRI_MEAL_COLOR.breakfast, sk: 'nutri_ctype_bk' },
                  { label: 'Lunch',     key: 'lu', color: NUTRI_MEAL_COLOR.lunch,     sk: 'nutri_ctype_lu' },
                  { label: 'Dinner',    key: 'di', color: NUTRI_MEAL_COLOR.dinner,    sk: 'nutri_ctype_di' },
                  { label: 'Snacks',    key: 'sn', color: NUTRI_MEAL_COLOR.snacks,    sk: 'nutri_ctype_sn' },
                ].map(m => (
                  <div key={m.sk} style={{ ...nutriStyles.card, padding: 14 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10, display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                      <span>{m.label} Over Time</span>
                      <span style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 500 }}>{rLabel}</span>
                    </div>
                    <SingleSeriesChart data={daysWithData} getValue={d => d[m.key] || 0} color={m.color} storageKey={m.sk}/>
                  </div>
                ))}
              </>
            );
          })()}
        </>
      )}

      {/* Weight moved to InBody → Weight (data preserved). */}

      {/* ── TABLES view ── */}
      {(view === 'tables' || view === 'all') && daysWithData.length > 0 && (
        <>
          {_allHdr('📋 Tables')}
          <MacrosTable days={rangeData} rangeLabel={rLabel}/>
        </>
      )}

      {onCleanup && (
        <div style={{ marginTop: 18, paddingTop: 14, borderTop: '1px solid var(--border)' }}>
          <button onClick={onCleanup} style={{
            display: 'inline-flex', alignItems: 'center', gap: 6, padding: '9px 14px', borderRadius: 10,
            background: 'transparent', color: '#C2554E', border: '1px solid rgba(194,85,78,0.3)',
            fontSize: 12.5, fontWeight: 600, cursor: 'pointer', font: 'inherit',
          }}>🧹 Clean up diet data…</button>
          <div style={{ fontSize: 11, color: 'var(--muted-2)', marginTop: 6 }}>Delete meals, notes, weight or InBody for a day, month, or range. Recipes &amp; library are kept.</div>
        </div>
      )}

      <div style={{ height: 60 }}/>

      {showManage && (
        <ManageFiltersSheet scope="calories" catalog={RANGE_PRESETS} defaultVisible={_calDefaultVisible} onClose={() => setShowManage(false)}/>
      )}
    </div>
  );
}

function StatTile({ label, value, unit, delta, color }) {
  return (
    <div style={{ ...nutriStyles.card, padding: '14px 16px' }}>
      <div style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 600, letterSpacing: '0.05em', textTransform: 'uppercase' }}>{label}</div>
      <div style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.02em', marginTop: 5, lineHeight: 1.1, color: color || 'var(--text)' }}>{value}</div>
      {unit  && <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 3 }}>{unit}</div>}
      {delta && <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 4 }}>{delta}</div>}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CHART TYPE SELECTOR — shared hook + picker UI
// ─────────────────────────────────────────────────────────────
function useChartType(storageKey, defaultType) {
  // Cloud-backed (settings.chartTypes) is the source of truth; localStorage is an instant cache.
  const [type, setType] = React.useState(() => {
    try {
      const pref = window.Store && Store.chartTypePref && Store.chartTypePref(storageKey);
      if (pref) return pref;
    } catch (_) {}
    try { return localStorage.getItem(storageKey) || defaultType; }
    catch { return defaultType; }
  });
  const set = React.useCallback(t => {
    setType(t);
    try { localStorage.setItem(storageKey, t); } catch {}
    try { if (window.Store && Store.setChartTypePref) Store.setChartTypePref(storageKey, t); } catch (_) {}
  }, [storageKey]);
  return [type, set];
}

const _CTYPE_ICONS = {
  bar: (
    <svg width="16" height="12" viewBox="0 0 16 12" fill="currentColor">
      <rect x="0" y="5" width="4" height="7" rx="1"/>
      <rect x="6" y="1" width="4" height="11" rx="1"/>
      <rect x="12" y="7" width="4" height="5" rx="1"/>
    </svg>
  ),
  line: (
    <svg width="16" height="12" viewBox="0 0 16 12" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="0,10 5,4 10,7 16,1"/>
      <circle cx="0"  cy="10" r="1.8" fill="currentColor" stroke="none"/>
      <circle cx="5"  cy="4"  r="1.8" fill="currentColor" stroke="none"/>
      <circle cx="10" cy="7"  r="1.8" fill="currentColor" stroke="none"/>
      <circle cx="16" cy="1"  r="1.8" fill="currentColor" stroke="none"/>
    </svg>
  ),
  area: (
    <svg width="16" height="12" viewBox="0 0 16 12">
      <path d="M0,10 L5,4 L10,7 L16,1 L16,12 L0,12 Z" fill="currentColor" opacity="0.3"/>
      <polyline points="0,10 5,4 10,7 16,1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  ),
};

function ChartTypePicker({ supported, active, onSelect }) {
  return (
    <div style={{ display: 'flex', gap: 3, flexShrink: 0 }}>
      {['bar', 'line', 'area'].map(t => {
        const ok = supported.includes(t);
        const on = active === t;
        return (
          <button key={t} onClick={() => ok && onSelect(t)}
            title={t.charAt(0).toUpperCase() + t.slice(1)}
            style={{
              width: 28, height: 24, borderRadius: 6,
              border: '1px solid ' + (on ? 'var(--text)' : 'var(--border)'),
              background: on ? 'var(--text)' : 'transparent',
              color: on ? 'var(--bg)' : ok ? 'var(--muted)' : 'var(--border)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              cursor: ok ? 'pointer' : 'default', opacity: ok ? 1 : 0.3,
              padding: 0,
            }}>
            {_CTYPE_ICONS[t]}
          </button>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// SVG CHARTS
// ─────────────────────────────────────────────────────────────

// Shared Y-axis tick helper: computes ~4-5 nice round values from 0 → maxVal
function _niceYTicks(maxVal, targetCount) {
  targetCount = targetCount || 6; // ~6 ticks for readable scales (Step 9.5 Part 5)
  if (maxVal <= 0) return [0, 1];
  const rough = maxVal / targetCount;
  const mag = Math.pow(10, Math.floor(Math.log10(rough)));
  const step = ([1, 2, 2.5, 5, 10].find(f => f * mag >= rough) || 10) * mag;
  const n = Math.ceil(maxVal / step) + 1;
  return Array.from({ length: n }, (_, i) => Math.round(i * step * 1000) / 1000);
}

function SimpleBarChart({ title, data, goalLine, color = 'var(--text)', overColor = 'var(--c-carbs)' }) {
  const [chartType, setChartType] = useChartType('nutri_ctype_calories', 'bar');
  const SUPPORTED = ['bar', 'line', 'area'];

  if (!data || !data.some(d => (d.value || 0) > 0)) {
    return (
      <div style={{ ...nutriStyles.card, padding: '14px' }}>
        <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 8 }}>{title}</div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', textAlign: 'center', padding: '24px 0' }}>No calorie data for this range.</div>
      </div>
    );
  }

  const VW = 300;
  const PADL = 38, PADR = 6, PADT = 22, PADB = 20;
  const usableW = VW - PADL - PADR;
  const barW = Math.max(3, Math.floor(usableW / (data.length || 1)) - 2);
  const maxVal = Math.max(goalLine || 0, ...data.map(d => d.value), 1);
  const chartH = 148;
  const yTicks = _niceYTicks(maxVal);
  const H = PADT + chartH + PADB;
  const goalY = PADT + chartH - ((goalLine || 0) / maxVal) * chartH;

  const valEvery = data.length <= 7 ? 1 : data.length <= 14 ? 2 : data.length <= 21 ? 3 : data.length <= 35 ? 5 : 7;
  const axisEvery = Math.ceil(data.length / 5);

  // Point positions for line/area (center of each bar's x slot)
  const pts = data.map((d, i) => {
    const x = PADL + i * (barW + 2) + barW / 2;
    const y = PADT + chartH - Math.max(0, (d.value / maxVal) * chartH);
    return [x, y];
  });
  const lineD = pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
  const areaD = pts.length
    ? lineD + ` L${pts[pts.length-1][0].toFixed(1)},${(PADT+chartH).toFixed(1)} L${pts[0][0].toFixed(1)},${(PADT+chartH).toFixed(1)} Z`
    : '';

  // Shared x-axis labels
  const axisLabels = data.map((d, i) => {
    const isRegular = i % axisEvery === 0;
    const isLast = i === data.length - 1;
    const prevRegular = Math.floor((data.length - 1) / axisEvery) * axisEvery;
    if (!isRegular && !(isLast && i - prevRegular > axisEvery / 2)) return null;
    const x = PADL + i * (barW + 2) + barW / 2;
    return (
      <text key={`ax${i}`} x={x} y={H - 4} textAnchor="middle"
        fontSize="10" fill="var(--muted)" fontFamily="inherit">
        {d.label}
      </text>
    );
  });

  return (
    <div style={{ ...nutriStyles.card, padding: '14px 14px 10px' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>
        <ChartTypePicker supported={SUPPORTED} active={chartType} onSelect={setChartType}/>
      </div>
      <svg width="100%" viewBox={`0 0 ${VW} ${H}`}
        style={{ display: 'block', width: '100%', height: 'auto', overflow: 'visible' }}>
        <defs>
          <linearGradient id="calAreaGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.25"/>
            <stop offset="100%" stopColor={color} stopOpacity="0"/>
          </linearGradient>
        </defs>
        {/* Y-axis grid lines + labels */}
        {yTicks.map(v => {
          const gy = PADT + (1 - v / maxVal) * chartH;
          const lbl = v >= 1000 ? (v / 1000).toFixed(1) + 'k' : String(v);
          return (
            <g key={v}>
              <line x1={PADL} x2={VW - PADR} y1={gy} y2={gy}
                stroke="var(--border)" strokeWidth="0.6" strokeDasharray="3 3"/>
              <text x={PADL - 4} y={gy + 3.5} textAnchor="end"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">{lbl}</text>
            </g>
          );
        })}
        {/* goal line — all modes */}
        {goalLine > 0 && (
          <line x1={PADL} y1={goalY} x2={VW - PADR} y2={goalY}
            stroke="var(--border-2)" strokeWidth="1.5" strokeDasharray="5 4"/>
        )}
        {/* BAR mode */}
        {chartType === 'bar' && data.map((d, i) => {
          const bh = Math.max(d.value > 0 ? 3 : 0, (d.value / maxVal) * chartH);
          const x = PADL + i * (barW + 2);
          const barTop = PADT + chartH - bh;
          const over = goalLine && d.value > goalLine;
          const showVal = d.value > 0 && i % valEvery === 0;
          const lbl = d.value >= 1000 ? (d.value / 1000).toFixed(1) + 'k' : String(d.value);
          return (
            <g key={d.iso || i}>
              <rect x={x} y={barTop} width={barW} height={bh}
                rx="2" fill={over ? overColor : color} opacity="0.85"/>
              {showVal && (
                <text x={x + barW / 2} y={barTop - 4} textAnchor="middle"
                  fontSize="9" fill={over ? overColor : 'var(--muted)'} fontFamily="inherit" fontWeight="600">
                  {lbl}
                </text>
              )}
            </g>
          );
        })}
        {/* AREA fill */}
        {chartType === 'area' && <path d={areaD} fill="url(#calAreaGrad)"/>}
        {/* LINE + AREA: stroke + dots + value labels */}
        {(chartType === 'line' || chartType === 'area') && <>
          <path d={lineD} stroke={color} strokeWidth="2" fill="none"
            strokeLinecap="round" strokeLinejoin="round"/>
          {data.map((d, i) => {
            const [x, y] = pts[i];
            const over = goalLine && d.value > goalLine;
            const showVal = d.value > 0 && i % valEvery === 0;
            const lbl = d.value >= 1000 ? (d.value / 1000).toFixed(1) + 'k' : String(d.value);
            return (
              <g key={d.iso || i}>
                <circle cx={x} cy={y} r="3.5"
                  fill={over ? overColor : color} stroke="var(--bg)" strokeWidth="1.5"/>
                {showVal && d.value > 0 && (
                  <text x={x} y={y - 9} textAnchor="middle"
                    fontSize="9" fill={over ? overColor : 'var(--muted)'} fontFamily="inherit" fontWeight="600">
                    {lbl}
                  </text>
                )}
              </g>
            );
          })}
        </>}
        {/* x-axis labels — all modes */}
        {axisLabels}
      </svg>
      {goalLine > 0 && (
        <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 6 }}>
          — — Goal: <strong style={{ color: 'var(--text)' }}>{goalLine.toLocaleString()} kcal</strong>/day
        </div>
      )}
    </div>
  );
}

// GroupedMacrosChart kept as alias for backward compat — replaced by MacroDistChart in stats view
function GroupedMacrosChart({ title, data, goals }) {
  return <MacroDistChart avgProt={data.length ? data[data.length-1].prot : 0} avgCarb={data.length ? data[data.length-1].carb : 0} avgFat={data.length ? data[data.length-1].fat : 0} goalProt={goals.prot} goalCarb={goals.carb} goalFat={goals.fat}/>;
}

function MacroDistChart({ avgProt, avgCarb, avgFat, goalProt, goalCarb, goalFat }) {
  const protCal = Math.round(avgProt * 4);
  const carbCal = Math.round(avgCarb * 4);
  const fatCal  = Math.round(avgFat  * 9);
  const totalCal = protCal + carbCal + fatCal || 1;

  // Donut geometry
  const R = 50, CX = 65, CY = 65, SW = 13;
  const C = 2 * Math.PI * R; // circumference
  const GAP = 5; // gap between segments in path units

  const segs = [
    { label: 'Protein', avg: avgProt, goal: goalProt, cal: protCal,
      pct: Math.round((protCal / totalCal) * 100), color: 'var(--c-protein)' },
    { label: 'Carbs',   avg: avgCarb, goal: goalCarb, cal: carbCal,
      pct: Math.round((carbCal / totalCal) * 100), color: 'var(--c-carbs)' },
    { label: 'Fat',     avg: avgFat,  goal: goalFat,  cal: fatCal,
      pct: 0, color: 'var(--c-fat)' },
  ];
  // Fix rounding so pcts sum to 100
  segs[2].pct = Math.max(0, 100 - segs[0].pct - segs[1].pct);

  let cumOffset = 0;
  const arcs = segs.map(s => {
    const fullLen = (s.pct / 100) * C;
    const len = Math.max(0, fullLen - GAP);
    const arc = { ...s, len, offset: cumOffset };
    cumOffset += fullLen;
    return arc;
  });

  return (
    <div style={{ ...nutriStyles.card, padding: '16px' }}>
      <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 14 }}>Macro Distribution</div>
      <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>

        {/* Donut chart */}
        <div style={{ flexShrink: 0 }}>
          <svg width={130} height={130} viewBox="0 0 130 130">
            {/* track */}
            <circle cx={CX} cy={CY} r={R} fill="none"
              stroke="var(--surface-2)" strokeWidth={SW}/>
            {/* segments */}
            <g transform={`rotate(-90, ${CX}, ${CY})`}>
              {arcs.map((arc, i) => arc.len > 0 && (
                <circle key={i}
                  cx={CX} cy={CY} r={R}
                  fill="none"
                  stroke={arc.color}
                  strokeWidth={SW}
                  strokeLinecap="butt"
                  strokeDasharray={`${arc.len.toFixed(2)} ${C.toFixed(2)}`}
                  strokeDashoffset={(-arc.offset).toFixed(2)}
                />
              ))}
            </g>
            {/* center: total kcal */}
            <text x={CX} y={CY - 6} textAnchor="middle"
              fontSize="16" fontWeight="700" fill="var(--text)" fontFamily="inherit">
              {totalCal}
            </text>
            <text x={CX} y={CY + 10} textAnchor="middle"
              fontSize="10" fill="var(--muted)" fontFamily="inherit">kcal</text>
          </svg>
        </div>

        {/* Right column: macro rows */}
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 12, paddingTop: 2 }}>
          {segs.map(s => {
            const pct = s.goal > 0 ? Math.min(100, (s.avg / s.goal) * 100) : 0;
            return (
              <div key={s.label}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 3 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                    <div style={{ width: 7, height: 7, borderRadius: 2, background: s.color, flexShrink: 0 }}/>
                    <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text)' }}>{s.label}</span>
                  </div>
                  <span style={{ fontSize: 12, fontWeight: 600, color: s.color }}>{s.pct}%</span>
                </div>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 5 }}>
                  <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--text)' }}>{s.avg}g avg</span>
                  <span style={{ fontSize: 11, color: 'var(--muted)' }}>goal {s.goal}g</span>
                </div>
                <div style={{ height: 7, background: 'var(--surface-2)', borderRadius: 4, overflow: 'hidden' }}>
                  <div style={{ width: `${pct}%`, height: '100%', background: s.color, borderRadius: 4, transition: 'width .4s' }}/>
                </div>
                <div style={{ fontSize: 10.5, color: 'var(--muted)', marginTop: 2.5, textAlign: 'right' }}>
                  {pct.toFixed(0)}% of goal
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function WeightLineChart({ points }) {
  const [chartType, setChartType] = useChartType('nutri_ctype_weight', 'area');
  const SUPPORTED = ['line', 'area']; // bar not applicable for a weight trend

  if (points.length < 2) return (
    <div style={{ textAlign: 'center', color: 'var(--muted)', fontSize: 13, padding: '12px 0' }}>
      Add at least 2 weight records to see the trend.
    </div>
  );
  const vals  = points.map(([, v]) => +v);
  const dates = points.map(([d]) => d);
  const minV  = Math.min(...vals);
  const maxV  = Math.max(...vals);
  const pad   = Math.max((maxV - minV) * 0.2, 0.5);
  const lo    = minV - pad;
  const hi    = maxV + pad;
  const range = hi - lo;
  const W = 300, H = 130, PADL = 38, PADR = 10, PADT = 18, PADB = 18;
  const usableW = W - PADL - PADR;
  const step = usableW / Math.max(vals.length - 1, 1);
  // Weight Y-axis ticks: values within [lo, hi]
  const wRange = hi - lo;
  const wStep = wRange <= 0.5 ? 0.1 : wRange <= 1.5 ? 0.25 : wRange <= 4 ? 0.5 : wRange <= 10 ? 1 : 2;
  const wTicks = (() => {
    const first = Math.ceil(lo / wStep) * wStep;
    const arr = [];
    let v = Math.round(first * 1000) / 1000;
    while (v <= hi + wStep * 0.01) { arr.push(v); v = Math.round((v + wStep) * 1000) / 1000; }
    return arr;
  })();
  const wpts = vals.map((v, i) => [
    PADL + i * step,
    PADT + (1 - (v - lo) / range) * (H - PADT - PADB),
  ]);
  const pathD = wpts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
  const areaD = pathD + ` L${wpts[wpts.length-1][0].toFixed(1)},${H-PADB} L${PADL},${H-PADB} Z`;
  const lblEvery = Math.ceil(vals.length / 6);

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 6 }}>
        <ChartTypePicker supported={SUPPORTED} active={chartType} onSelect={setChartType}/>
      </div>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`}
        style={{ display: 'block', overflow: 'visible' }}>
        <defs>
          <linearGradient id="wg2" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--text)" stopOpacity="0.15"/>
            <stop offset="100%" stopColor="var(--text)" stopOpacity="0"/>
          </linearGradient>
        </defs>
        {/* Y-axis grid lines + labels */}
        {wTicks.map(v => {
          const gy = PADT + (1 - (v - lo) / range) * (H - PADT - PADB);
          return (
            <g key={v}>
              <line x1={PADL} x2={W - PADR} y1={gy} y2={gy}
                stroke="var(--border)" strokeWidth="0.6" strokeDasharray="3 3"/>
              <text x={PADL - 4} y={gy + 3.5} textAnchor="end"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">{v.toFixed(1)}</text>
            </g>
          );
        })}
        {/* AREA fill */}
        {chartType === 'area' && <path d={areaD} fill="url(#wg2)"/>}
        {/* Line stroke — both modes */}
        <path d={pathD} stroke="var(--text)" strokeWidth="2.5" fill="none"
          strokeLinecap="round" strokeLinejoin="round"/>
        {wpts.map(([x, y], i) => {
          const showLabel = i % lblEvery === 0 || i === vals.length - 1;
          return (
            <g key={i}>
              <circle cx={x} cy={y} r="4.5" fill="var(--text)"/>
              {showLabel && (
                <text x={x} y={y - 8} textAnchor="middle"
                  fontSize="10" fontWeight="600" fill="var(--text)" fontFamily="inherit">
                  {vals[i].toFixed(1)}
                </text>
              )}
            </g>
          );
        })}
        {vals.length >= 2 && (() => {
          const minI = vals.indexOf(minV), maxI = vals.indexOf(maxV);
          const hasLbl = idx => idx % lblEvery === 0 || idx === vals.length - 1;
          return <>
            {!hasLbl(minI) && (
              <text x={wpts[minI][0]} y={wpts[minI][1] + 16} textAnchor="middle"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">min {minV.toFixed(1)}</text>
            )}
            {!hasLbl(maxI) && (
              <text x={wpts[maxI][0]} y={wpts[maxI][1] - 14} textAnchor="middle"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">max {maxV.toFixed(1)}</text>
            )}
          </>;
        })()}
      </svg>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6 }}>
        <span style={{ fontSize: 11, color: 'var(--muted)' }}>{dates[0]}</span>
        {vals.length > 2 && <span style={{ fontSize: 11, color: 'var(--muted)', textAlign: 'center' }}>
          {vals.length} records
        </span>}
        <span style={{ fontSize: 11, color: 'var(--muted)' }}>{dates[dates.length - 1]}</span>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// MEAL CALORIES BY DAY — stacked bar / line / area (Step 7A + 8)
// ─────────────────────────────────────────────────────────────
function MealStackedBarChart({ title, data }) {
  if (!data || !data.length) return null;
  const [chartType, setChartType] = useChartType('nutri_ctype_meal', 'bar');
  const SUPPORTED = ['bar', 'line', 'area'];

  const days = data.length > 14 ? data.slice(-14) : data;
  const MC = NUTRI_MEAL_COLOR;
  const SEGS = [
    { key: 'bk', color: MC.breakfast },
    { key: 'lu', color: MC.lunch },
    { key: 'di', color: MC.dinner },
    { key: 'sn', color: MC.snacks },
  ];

  const totals = days.map(d => d.bk + d.lu + d.di + d.sn);
  const maxVal = Math.max(...totals, 1);
  const VW = 300, PADL = 38, PADR = 6, PADT = 20, PADB = 20;
  const chartH = 130;
  const H = PADT + chartH + PADB;
  const barW = Math.max(4, Math.floor((VW - PADL - PADR) / days.length) - 2);
  const yTicks = _niceYTicks(maxVal);

  // Day-to-day delta (always based on totals regardless of chart type)
  const daysWithMeals = days.filter(d => (d.bk + d.lu + d.di + d.sn) > 0);
  const hasDelta = daysWithMeals.length >= 2;
  const lastTot = hasDelta ? daysWithMeals.slice(-1)[0].bk + daysWithMeals.slice(-1)[0].lu + daysWithMeals.slice(-1)[0].di + daysWithMeals.slice(-1)[0].sn : 0;
  const prevTot = hasDelta ? daysWithMeals.slice(-2)[0].bk + daysWithMeals.slice(-2)[0].lu + daysWithMeals.slice(-2)[0].di + daysWithMeals.slice(-2)[0].sn : 0;
  const delta = hasDelta ? Math.round(lastTot - prevTot) : 0;

  const labelEvery = days.length <= 7 ? 1 : days.length <= 12 ? 2 : 3;

  // Line/area: total calories per day
  const linePts = days.map((d, i) => {
    const total = totals[i];
    const x = PADL + i * (barW + 2) + barW / 2;
    const y = PADT + chartH - Math.max(0, (total / maxVal) * chartH);
    return [x, y, total];
  });
  const mealLineD = linePts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
  const mealAreaD = linePts.length
    ? mealLineD + ` L${linePts[linePts.length-1][0].toFixed(1)},${(PADT+chartH).toFixed(1)} L${linePts[0][0].toFixed(1)},${(PADT+chartH).toFixed(1)} Z`
    : '';
  const mealLineColor = 'var(--c-carbs)';

  return (
    <div style={{ ...nutriStyles.card, padding: '14px 14px 10px' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
        <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>
        <ChartTypePicker supported={SUPPORTED} active={chartType} onSelect={setChartType}/>
      </div>
      {/* Legend — only for stacked bar */}
      {chartType === 'bar' && (
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 8 }}>
          {[{l:'Breakfast',c:MC.breakfast},{l:'Lunch',c:MC.lunch},{l:'Dinner',c:MC.dinner},{l:'Snacks',c:MC.snacks}]
            .map(m => (
            <div key={m.l} style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
              <div style={{ width: 8, height: 8, borderRadius: 2, background: m.c, flexShrink: 0 }}/>
              <span style={{ fontSize: 10.5, color: 'var(--muted)' }}>{m.l}</span>
            </div>
          ))}
        </div>
      )}
      <svg width="100%" viewBox={`0 0 ${VW} ${H}`}
        style={{ display: 'block', width: '100%', height: 'auto', overflow: 'visible' }}>
        <defs>
          <linearGradient id="mealAreaGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={mealLineColor} stopOpacity="0.28"/>
            <stop offset="100%" stopColor={mealLineColor} stopOpacity="0"/>
          </linearGradient>
        </defs>

        {/* Y-axis grid lines + labels */}
        {yTicks.map(v => {
          const gy = PADT + (1 - v / maxVal) * chartH;
          const lbl = v >= 1000 ? (v / 1000).toFixed(1) + 'k' : String(v);
          return (
            <g key={v}>
              <line x1={PADL} x2={VW - PADR} y1={gy} y2={gy}
                stroke="var(--border)" strokeWidth="0.6" strokeDasharray="3 3"/>
              <text x={PADL - 4} y={gy + 3.5} textAnchor="end"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">{lbl}</text>
            </g>
          );
        })}
        {/* STACKED BAR mode */}
        {chartType === 'bar' && days.map((d, i) => {
          const total = totals[i];
          const x = PADL + i * (barW + 2);
          let yBottom = PADT + chartH;
          const rects = [];
          SEGS.forEach(({ key, color }) => {
            const val = d[key] || 0;
            if (val > 0) {
              const segH = Math.max(2, (val / maxVal) * chartH);
              rects.push({ y: yBottom - segH, h: segH, color });
              yBottom -= segH;
            }
          });
          if (rects.length) rects[0].rx = 2;
          const showLabel = i % labelEvery === 0 || i === days.length - 1;
          return (
            <g key={d.iso || i}>
              {rects.map((r, j) => (
                <rect key={j} x={x} y={r.y} width={barW} height={r.h}
                  rx={j === 0 ? 2 : 0} fill={r.color} opacity="0.9"/>
              ))}
              {total > 0 && (
                <text x={x + barW / 2} y={yBottom - 4} textAnchor="middle"
                  fontSize="9" fontWeight="600" fill="var(--text)" fontFamily="inherit">
                  {total >= 1000 ? (total / 1000).toFixed(1) + 'k' : total}
                </text>
              )}
              {showLabel && (
                <text x={x + barW / 2} y={H - 4} textAnchor="middle"
                  fontSize="10" fill="var(--muted)" fontFamily="inherit">
                  {d.d instanceof Date ? d.d.getDate() : (d.label || '')}
                </text>
              )}
            </g>
          );
        })}

        {/* AREA fill */}
        {chartType === 'area' && <path d={mealAreaD} fill="url(#mealAreaGrad)"/>}

        {/* LINE + AREA: stroke + dots + value labels + x-axis */}
        {(chartType === 'line' || chartType === 'area') && <>
          <path d={mealLineD} stroke={mealLineColor} strokeWidth="2" fill="none"
            strokeLinecap="round" strokeLinejoin="round"/>
          {linePts.map(([x, y, total], i) => {
            const showVal = total > 0 && (i % labelEvery === 0 || i === days.length - 1);
            const lbl = total >= 1000 ? (total / 1000).toFixed(1) + 'k' : String(total);
            return (
              <g key={i}>
                {total > 0 && <circle cx={x} cy={y} r="3.5"
                  fill={mealLineColor} stroke="var(--bg)" strokeWidth="1.5"/>}
                {showVal && (
                  <text x={x} y={y - 9} textAnchor="middle"
                    fontSize="9" fontWeight="600" fill="var(--text)" fontFamily="inherit">
                    {lbl}
                  </text>
                )}
                {(i % labelEvery === 0 || i === days.length - 1) && (
                  <text x={x} y={H - 4} textAnchor="middle"
                    fontSize="10" fill="var(--muted)" fontFamily="inherit">
                    {days[i].d instanceof Date ? days[i].d.getDate() : (days[i].label || '')}
                  </text>
                )}
              </g>
            );
          })}
        </>}
      </svg>
      {/* Day-to-day delta */}
      {hasDelta && (
        <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 6 }}>
          Last day vs previous: <strong style={{ color: delta >= 0 ? 'var(--c-carbs)' : 'var(--c-protein)' }}>
            {delta >= 0 ? '+' : ''}{delta} kcal
          </strong>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// MACROS BY DAY — grouped bar / line / area (Step 7B + 8)
// ─────────────────────────────────────────────────────────────
function MacroGroupedBarChart({ title, data }) {
  if (!data || !data.length) return null;
  const [chartType, setChartType] = useChartType('nutri_ctype_macros', 'bar');
  const SUPPORTED = ['bar', 'line', 'area'];

  const days = data.length > 14 ? data.slice(-14) : data;
  const COLS = ['var(--c-protein)', 'var(--c-carbs)', 'var(--c-fat)'];
  const KEYS = ['prot', 'carb', 'fat'];
  const LBLS = ['Protein', 'Carbs', 'Fat'];

  const maxVal = Math.max(...days.flatMap(d => KEYS.map(k => +(d[k] || 0))), 1);
  const VW = 300, PADL = 38, PADR = 6, PADT = 20, PADB = 20;
  const chartH = 120;
  const H = PADT + chartH + PADB;
  const groupW = Math.floor((VW - PADL - PADR) / days.length);
  const yTicks = _niceYTicks(maxVal);
  const bW = Math.max(2, Math.floor(groupW / 3) - 1);

  const showValues = days.length <= 7;
  const labelEvery = days.length <= 7 ? 1 : days.length <= 12 ? 2 : 3;

  // Per-macro point arrays for line/area
  const macroLines = KEYS.map((key) =>
    days.map((d, i) => {
      const v = +(d[key] || 0);
      const x = PADL + i * groupW + groupW / 2;
      const y = PADT + chartH - Math.max(0, (v / maxVal) * chartH);
      return [x, y, v];
    })
  );
  const makePath = pts => pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
  const makeArea = pts => pts.length
    ? makePath(pts) + ` L${pts[pts.length-1][0].toFixed(1)},${(PADT+chartH).toFixed(1)} L${pts[0][0].toFixed(1)},${(PADT+chartH).toFixed(1)} Z`
    : '';

  return (
    <div style={{ ...nutriStyles.card, padding: '14px 14px 10px' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
        <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>
        <ChartTypePicker supported={SUPPORTED} active={chartType} onSelect={setChartType}/>
      </div>
      {/* Legend */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 8 }}>
        {LBLS.map((l, i) => (
          <div key={l} style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <div style={{ width: 8, height: 8, borderRadius: 2, background: COLS[i] }}/>
            <span style={{ fontSize: 10.5, color: 'var(--muted)' }}>{l}</span>
          </div>
        ))}
      </div>
      <svg width="100%" viewBox={`0 0 ${VW} ${H}`}
        style={{ display: 'block', width: '100%', height: 'auto', overflow: 'visible' }}>
        <defs>
          {COLS.map((c, i) => (
            <linearGradient key={i} id={`macroAreaGrad${i}`} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={c} stopOpacity="0.25"/>
              <stop offset="100%" stopColor={c} stopOpacity="0"/>
            </linearGradient>
          ))}
        </defs>

        {/* Y-axis grid lines + labels */}
        {yTicks.map(v => {
          const gy = PADT + (1 - v / maxVal) * chartH;
          const lbl = v >= 1000 ? (v / 1000).toFixed(1) + 'k' : String(v) + 'g';
          return (
            <g key={v}>
              <line x1={PADL} x2={VW - PADR} y1={gy} y2={gy}
                stroke="var(--border)" strokeWidth="0.6" strokeDasharray="3 3"/>
              <text x={PADL - 4} y={gy + 3.5} textAnchor="end"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">{lbl}</text>
            </g>
          );
        })}
        {/* GROUPED BAR mode */}
        {chartType === 'bar' && days.map((d, i) => {
          const gx = PADL + i * groupW;
          const showLabel = i % labelEvery === 0 || i === days.length - 1;
          return (
            <g key={d.iso || i}>
              {KEYS.map((key, j) => {
                const v = +(d[key] || 0);
                const bh = Math.max(v > 0 ? 2 : 0, (v / maxVal) * chartH);
                const x = gx + j * (bW + 1);
                const y = PADT + chartH - bh;
                return (
                  <g key={j}>
                    <rect x={x} y={y} width={bW} height={bh} rx="2"
                      fill={COLS[j]} opacity="0.85"/>
                    {showValues && v > 0 && (
                      <text x={x + bW / 2} y={y - 3} textAnchor="middle"
                        fontSize="8" fontWeight="600" fill={COLS[j]} fontFamily="inherit">
                        {Math.round(v)}
                      </text>
                    )}
                  </g>
                );
              })}
              {showLabel && (
                <text x={gx + groupW / 2} y={H - 4} textAnchor="middle"
                  fontSize="9" fill="var(--muted)" fontFamily="inherit">
                  {d.d instanceof Date ? d.d.getDate() : (d.label || '')}
                </text>
              )}
            </g>
          );
        })}

        {/* AREA fills (rendered behind lines) */}
        {chartType === 'area' && macroLines.map((pts, j) => (
          <path key={j} d={makeArea(pts)} fill={`url(#macroAreaGrad${j})`}/>
        ))}

        {/* LINE + AREA: per-macro strokes + dots + value labels */}
        {(chartType === 'line' || chartType === 'area') && macroLines.map((pts, j) => (
          <g key={j}>
            <path d={makePath(pts)} stroke={COLS[j]} strokeWidth="2" fill="none"
              strokeLinecap="round" strokeLinejoin="round"/>
            {pts.map(([x, y, v], i) => (
              v > 0 ? (
                <g key={i}>
                  <circle cx={x} cy={y} r="3"
                    fill={COLS[j]} stroke="var(--bg)" strokeWidth="1.5"/>
                  {showValues && (
                    <text x={x} y={y - 8} textAnchor="middle"
                      fontSize="8" fontWeight="600" fill={COLS[j]} fontFamily="inherit">
                      {Math.round(v)}
                    </text>
                  )}
                </g>
              ) : null
            ))}
          </g>
        ))}

        {/* X-axis labels for line/area (rendered once, after all lines) */}
        {(chartType === 'line' || chartType === 'area') && days.map((d, i) => {
          if (!(i % labelEvery === 0 || i === days.length - 1)) return null;
          const x = PADL + i * groupW + groupW / 2;
          return (
            <text key={`ax${i}`} x={x} y={H - 4} textAnchor="middle"
              fontSize="9" fill="var(--muted)" fontFamily="inherit">
              {d.d instanceof Date ? d.d.getDate() : (d.label || '')}
            </text>
          );
        })}
      </svg>
      {days.length > 7 && (
        <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 4 }}>
          Showing last {days.length} days · P = protein · C = carbs · F = fat
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// MACROS DATA TABLE
// ─────────────────────────────────────────────────────────────
function MacrosTable({ days, rangeLabel }) {
  const [deleteDate, setDeleteDate] = React.useState(null);
  const withData = days.filter(d => d.hasData);
  if (withData.length === 0) return (
    <div style={{ ...nutriStyles.card, padding: 20, textAlign: 'center', color: 'var(--muted)', fontSize: 13 }}>
      No data yet. Start logging meals to see the table.
    </div>
  );
  return (
    <div style={{ ...nutriStyles.card, padding: 0, overflow: 'hidden' }}>
      <div style={{ padding: '10px 12px', borderBottom: '1px solid var(--border)', fontSize: 13, fontWeight: 600 }}>
        Daily Macros — {rangeLabel || 'selected range'}
      </div>
      <div style={{ overflowX: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)' }}>
              {['Date','Cal','P (g)','C (g)','F (g)','Bk','Lu','Di','Sn',''].map((h, i) => (
                <th key={i} style={{
                  padding: '7px 8px', textAlign: i === 0 ? 'left' : 'right',
                  fontSize: 10, color: 'var(--muted)', fontWeight: 600, letterSpacing: '0.04em',
                  textTransform: 'uppercase', borderBottom: '1px solid var(--border)',
                  whiteSpace: 'nowrap',
                }}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {withData.slice().reverse().map((d, i) => (
              <tr key={d.iso} style={{ background: i % 2 ? 'var(--surface-2)' : 'var(--surface)' }}>
                <td style={{ padding: '8px 8px', whiteSpace: 'nowrap' }}>
                  {d.d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
                </td>
                <td style={{ padding: '8px 8px', textAlign: 'right', fontWeight: 600 }}>{d.cal}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--c-protein)', fontWeight: 600 }}>{Math.round(d.prot)}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--c-carbs)', fontWeight: 600 }}>{Math.round(d.carb)}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--c-fat)', fontWeight: 600 }}>{Math.round(d.fat)}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--muted)' }}>{d.bk || '—'}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--muted)' }}>{d.lu || '—'}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--muted)' }}>{d.di || '—'}</td>
                <td style={{ padding: '8px 8px', textAlign: 'right', color: 'var(--muted)' }}>{d.sn || '—'}</td>
                <td style={{ padding: '4px 6px', textAlign: 'right' }}>
                  <button
                    onClick={() => setDeleteDate(d.iso)}
                    title="Delete this day"
                    style={{
                      width: 26, height: 26, borderRadius: 6,
                      background: 'transparent', border: 'none',
                      color: '#d9534f', opacity: 0.6, cursor: 'pointer',
                      fontSize: 14, display: 'inline-flex',
                      alignItems: 'center', justifyContent: 'center',
                      font: 'inherit',
                    }}>🗑</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {deleteDate && (
        <DeleteDayConfirmDialog
          date={deleteDate}
          onConfirm={() => {
            window.Store.replaceMealsForDate(deleteDate, []);
            window.Store.setDayNote(deleteDate, '');
            setDeleteDate(null);
          }}
          onCancel={() => setDeleteDate(null)}
        />
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// SINGLE SERIES CHART — reusable bar/line/area for one metric
// ─────────────────────────────────────────────────────────────
function SingleSeriesChart({ data, getValue, color, storageKey, unit }) {
  const [chartType, setChartType] = useChartType(storageKey, 'bar');
  const SUPPORTED = ['bar', 'line', 'area'];

  if (!data || !data.length) return (
    <div style={{ textAlign: 'center', color: 'var(--muted)', fontSize: 12.5, padding: '10px 0' }}>
      No data in range.
    </div>
  );

  const W = 300, H = 110, PADL = 36, PADR = 8, PADT = 20, PADB = 16;
  const usableW = W - PADL - PADR;
  const barSlot  = usableW / data.length;
  const barW     = Math.max(2, barSlot - 2);
  const vals     = data.map(d => Math.round(getValue(d) || 0));
  const maxVal   = Math.max(...vals, 1);
  const yTicks   = _niceYTicks(maxVal);
  const showVals = data.length <= 7;
  const axisEvery = Math.ceil(data.length / 5);
  const gradId   = 'ssc_' + storageKey.replace(/[^a-z0-9]/gi, '_');

  const pts = data.map((d, i) => {
    const x = PADL + i * barSlot + barSlot / 2;
    const y = PADT + (1 - vals[i] / maxVal) * (H - PADT - PADB);
    return [x, y, vals[i]];
  });

  const lineD = pts.map(([x, y], i) => `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
  const areaD = lineD +
    ` L${pts[pts.length - 1][0].toFixed(1)},${(H - PADB).toFixed(1)}` +
    ` L${pts[0][0].toFixed(1)},${(H - PADB).toFixed(1)} Z`;

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 4 }}>
        <ChartTypePicker supported={SUPPORTED} active={chartType} onSelect={setChartType}/>
      </div>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`}
        style={{ display: 'block', overflow: 'visible' }}>
        <defs>
          <linearGradient id={gradId} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.22"/>
            <stop offset="100%" stopColor={color} stopOpacity="0"/>
          </linearGradient>
        </defs>

        {/* Y-axis grid lines + labels */}
        {yTicks.map(v => {
          const sscH = H - PADT - PADB;
          const gy = PADT + (1 - v / maxVal) * sscH;
          const lbl = v >= 1000 ? (v / 1000).toFixed(1) + 'k' : String(v) + (unit || '');
          return (
            <g key={v}>
              <line x1={PADL} x2={W - PADR} y1={gy} y2={gy}
                stroke="var(--border)" strokeWidth="0.6" strokeDasharray="3 3"/>
              <text x={PADL - 4} y={gy + 3.5} textAnchor="end"
                fontSize="9" fill="var(--muted)" fontFamily="inherit">{lbl}</text>
            </g>
          );
        })}
        {/* BAR mode */}
        {chartType === 'bar' && pts.map(([x, y, v], i) => (
          <g key={i}>
            <rect x={(x - barW / 2).toFixed(1)} y={y.toFixed(1)}
              width={barW.toFixed(1)} height={Math.max(0, H - PADB - y).toFixed(1)}
              fill={color} rx="2"/>
            {showVals && v > 0 && (
              <text x={x.toFixed(1)} y={(y - 4).toFixed(1)} textAnchor="middle"
                fontSize="9" fontWeight="600" fill="var(--text)" fontFamily="inherit">
                {v}{unit || ''}
              </text>
            )}
          </g>
        ))}

        {/* LINE / AREA mode */}
        {(chartType === 'line' || chartType === 'area') && (
          <>
            {chartType === 'area' && <path d={areaD} fill={`url(#${gradId})`}/>}
            <path d={lineD} stroke={color} strokeWidth="2" fill="none"
              strokeLinecap="round" strokeLinejoin="round"/>
            {pts.map(([x, y, v], i) => (
              <g key={i}>
                <circle cx={x.toFixed(1)} cy={y.toFixed(1)} r="3.5" fill={color}/>
                {showVals && v > 0 && (
                  <text x={x.toFixed(1)} y={(y - 8).toFixed(1)} textAnchor="middle"
                    fontSize="9" fontWeight="600" fill="var(--text)" fontFamily="inherit">
                    {v}{unit || ''}
                  </text>
                )}
              </g>
            ))}
          </>
        )}

        {/* X-axis labels */}
        {pts.map(([x], i) => {
          if (i % axisEvery !== 0 && i !== pts.length - 1) return null;
          const d = data[i];
          const lbl = d && d.d instanceof Date
            ? d.d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
            : '';
          return (
            <text key={'ax' + i} x={x.toFixed(1)} y={(H - 2).toFixed(1)}
              textAnchor="middle" fontSize="8.5" fill="var(--muted)" fontFamily="inherit">
              {lbl}
            </text>
          );
        })}
      </svg>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// RECIPES SCREEN — browse + quick-log saved recipes
// ─────────────────────────────────────────────────────────────
function RecipesScreen({ localLibrary, entries, selectedDate, onLogMeals }) {
  const [search, setSearch]       = React.useState('');
  const [catFilter, setCatFilter] = React.useState('All');
  const [detail, setDetail]       = React.useState(null);   // recipe shown in detail view
  const [quickLog, setQuickLog]   = React.useState(null);   // recipe being quick-logged
  const [editing, setEditing]     = React.useState(null);   // recipe being edited
  const [confirmDelete, setConfirmDelete] = React.useState(null); // recipe pending delete confirm

  const recipes = React.useMemo(
    () => (localLibrary || []).filter(r => r.type === 'recipe'),
    [localLibrary]
  );

  const categories = React.useMemo(() => {
    const cats = recipes.map(r => r.category).filter(Boolean);
    return ['All', ...new Set(cats)];
  }, [recipes]);

  const filtered = React.useMemo(() => recipes.filter(r => {
    if (catFilter !== 'All' && (r.category || '') !== catFilter) return false;
    if (!search.trim()) return true;
    const q = search.toLowerCase();
    return (
      (r.name || '').toLowerCase().includes(q) ||
      (r.category || '').toLowerCase().includes(q) ||
      (r.note || '').toLowerCase().includes(q) ||
      (r.items || []).some(it => (it.name || '').toLowerCase().includes(q))
    );
  }), [recipes, catFilter, search]);

  return (
    <div style={{ padding: '12px 16px 32px', display: 'flex', flexDirection: 'column', gap: 12 }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingTop: 4 }}>
        <div>
          <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>Recipes</div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2, fontWeight: 500 }}>
            {recipes.length === 0 ? 'No saved recipes yet' : `${recipes.length} saved recipe${recipes.length !== 1 ? 's' : ''}`}
          </div>
        </div>
      </div>

      {/* Search */}
      <div style={{ position: 'relative' }}>
        <input
          type="text"
          value={search}
          onChange={e => setSearch(e.target.value)}
          placeholder="Search by name, ingredient, or category…"
          style={{
            width: '100%', border: '1px solid var(--border)', background: 'var(--surface)',
            borderRadius: 12, padding: '10px 12px 10px 38px', outline: 'none',
            font: 'inherit', fontSize: 13.5, color: 'var(--text)', boxSizing: 'border-box',
          }}
        />
        <span style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', color: 'var(--muted)', display: 'flex', pointerEvents: 'none' }}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>
        </span>
        {search && (
          <button onClick={() => setSearch('')} style={{
            position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)',
            background: 'none', border: 'none', cursor: 'pointer', color: 'var(--muted)',
            padding: 4, fontSize: 18, lineHeight: 1, font: 'inherit',
          }}>×</button>
        )}
      </div>

      {/* Category filter pills */}
      {categories.length > 1 && (
        <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 2 }} className="nutri-scroll-x">
          {categories.map(cat => (
            <button key={cat} onClick={() => setCatFilter(cat)} style={{
              padding: '6px 14px', borderRadius: 999, border: '1px solid var(--border)',
              background: catFilter === cat ? 'var(--accent)' : 'var(--surface)',
              color: catFilter === cat ? 'var(--on-accent)' : 'var(--text)',
              fontSize: 12.5, fontWeight: 600, cursor: 'pointer', font: 'inherit', whiteSpace: 'nowrap', flexShrink: 0,
            }}>{cat}</button>
          ))}
        </div>
      )}

      {/* Empty state — no recipes at all */}
      {recipes.length === 0 && (
        <div style={{ ...nutriStyles.card, padding: '36px 20px', textAlign: 'center', color: 'var(--muted)' }}>
          <div style={{ fontSize: 40, marginBottom: 14 }}>🍳</div>
          <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)', marginBottom: 6 }}>No recipes saved yet</div>
          <div style={{ fontSize: 13, lineHeight: 1.6 }}>
            Save recipes via <strong>Paste & Parse</strong>. Tap the <strong>Paste</strong> tab, paste a recipe using the template, and confirm save.
          </div>
        </div>
      )}

      {/* No search results */}
      {recipes.length > 0 && filtered.length === 0 && (
        <div style={{ ...nutriStyles.card, padding: '28px 20px', textAlign: 'center', color: 'var(--muted)', fontSize: 13 }}>
          No recipes match "{search}"{catFilter !== 'All' ? ` in ${catFilter}` : ''}.
        </div>
      )}

      {/* Recipe list */}
      {filtered.map(r => (
        <RecipeCard
          key={r.id} recipe={r}
          onOpen={() => setDetail(r)}
          onQuickLog={() => setQuickLog(r)}
          onEdit={() => setEditing(r)}
          onDelete={() => setConfirmDelete(r)}
        />
      ))}

      {/* Detail full-screen overlay */}
      {detail && (
        <RecipeDetailSheet
          recipe={detail}
          onClose={() => setDetail(null)}
          onQuickLog={(r) => { setDetail(null); setQuickLog(r); }}
          onEdit={(r) => { setDetail(null); setEditing(r); }}
          onDelete={(r) => { setDetail(null); setConfirmDelete(r); }}
        />
      )}

      {/* Quick Log bottom sheet */}
      {quickLog && (
        <QuickLogRecipeSheet
          recipe={quickLog}
          selectedDate={selectedDate}
          onConfirm={(row) => { onLogMeals(row); setQuickLog(null); }}
          onClose={() => setQuickLog(null)}
        />
      )}

      {/* Edit recipe sheet */}
      {editing && (
        <EditRecipeSheet
          recipe={editing}
          onClose={() => setEditing(null)}
        />
      )}

      {/* Delete confirmation dialog */}
      {confirmDelete && (
        <DeleteRecipeConfirmDialog
          recipe={confirmDelete}
          onClose={() => setConfirmDelete(null)}
          onConfirm={() => {
            window.Store.deleteLocalItem(confirmDelete.id);
            setConfirmDelete(null);
          }}
        />
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// RECIPE CARD
// ─────────────────────────────────────────────────────────────
function RecipeCard({ recipe, onOpen, onQuickLog, onEdit, onDelete }) {
  const r = recipe;
  const cal  = r.cal  || 0;
  const prot = +(r.protein_g || r.p || 0);
  const carb = +(r.carbs_g   || r.c || 0);
  const fat  = +(r.fat_g     || r.f || 0);

  return (
    <div style={{ ...nutriStyles.card, padding: 0, overflow: 'hidden', cursor: 'pointer' }} onClick={onOpen}>
      <div style={{ padding: '14px 14px 0' }}>
        {/* Name + emoji */}
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 8 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-0.01em', lineHeight: 1.3, marginBottom: 3 }}>
              {r.name || 'Untitled Recipe'}
            </div>
            {r.category && (
              <div style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em' }}>
                {r.category}
              </div>
            )}
          </div>
          <div style={{ fontSize: 28, lineHeight: 1, flexShrink: 0 }}>{r.emoji || '🍳'}</div>
        </div>

        {/* Macros */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 16, fontWeight: 700 }}>{cal} kcal</span>
          <span style={{ color: 'var(--muted)', fontSize: 14 }}>·</span>
          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--c-protein)' }}>P {prot}g</span>
          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--c-carbs)' }}>C {carb}g</span>
          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--c-fat)' }}>F {fat}g</span>
        </div>

        {/* Serving options pills */}
        {r.servingOptions && r.servingOptions.length > 0 && (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 8 }}>
            {r.servingOptions.map((opt, i) => (
              <span key={i} style={{
                fontSize: 11, padding: '3px 9px', borderRadius: 999,
                background: 'var(--surface-2)', border: '1px solid var(--border)',
                color: 'var(--muted)', fontWeight: 500,
              }}>{opt.label} · {opt.calories} kcal</span>
            ))}
          </div>
        )}

        {/* Ingredient count */}
        {r.items && r.items.length > 0 && (
          <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 7, marginBottom: 2 }}>
            {r.items.length} ingredient{r.items.length !== 1 ? 's' : ''}
          </div>
        )}
      </div>

      {/* Action row: Edit | Delete | Log */}
      <div style={{ borderTop: '1px solid var(--border)', marginTop: 12, display: 'grid', gridTemplateColumns: '1fr 1fr 1fr' }}>
        <button
          onClick={e => { e.stopPropagation(); onEdit(); }}
          style={{
            padding: '11px 0', background: 'transparent', border: 'none', borderRight: '1px solid var(--border)',
            color: 'var(--muted)', fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
            font: 'inherit', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5,
          }}
        >
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
            <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
          </svg>
          Edit
        </button>
        <button
          onClick={e => { e.stopPropagation(); onDelete(); }}
          style={{
            padding: '11px 0', background: 'transparent', border: 'none', borderRight: '1px solid var(--border)',
            color: '#ef4444', fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
            font: 'inherit', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5,
          }}
        >
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
            <polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/>
            <path d="M10 11v6M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
          </svg>
          Delete
        </button>
        <button
          onClick={e => { e.stopPropagation(); onQuickLog(); }}
          style={{
            padding: '11px 0', background: 'transparent', border: 'none',
            color: 'var(--accent)', fontSize: 12.5, fontWeight: 700, cursor: 'pointer',
            font: 'inherit', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5,
          }}
        >
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
            <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
          </svg>
          Log
        </button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// RECIPE DETAIL SHEET — full-screen overlay
// ─────────────────────────────────────────────────────────────
function RecipeDetailSheet({ recipe, onClose, onQuickLog, onEdit, onDelete }) {
  const r   = recipe;
  const cal  = r.cal  || 0;
  const prot = +(r.protein_g || r.p || 0);
  const carb = +(r.carbs_g   || r.c || 0);
  const fat  = +(r.fat_g     || r.f || 0);

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 100,
      background: 'var(--bg)', overflowY: 'auto',
      animation: 'sheetIn 0.22s ease',
    }}>
      {/* Sticky top bar */}
      <div style={{
        position: 'sticky', top: 0, background: 'var(--bg)',
        borderBottom: '1px solid var(--border)', padding: '10px 16px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', zIndex: 10,
      }}>
        <button onClick={onClose} style={iconBtnGhost}>
          <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M19 12H5M12 19l-7-7 7-7"/>
          </svg>
        </button>
        <div style={{ fontSize: 15, fontWeight: 700, flex: 1, textAlign: 'center', padding: '0 8px' }}>Recipe Details</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <button onClick={() => onEdit(r)} style={iconBtnGhost} title="Edit recipe">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
              <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
              <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
            </svg>
          </button>
          <button onClick={() => onDelete(r)} style={{ ...iconBtnGhost, color: '#ef4444', borderColor: 'rgba(239,68,68,0.35)' }} title="Delete recipe">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
              <polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/>
              <path d="M10 11v6M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
            </svg>
          </button>
          <button
            onClick={() => onQuickLog(r)}
            style={{
              padding: '7px 14px', borderRadius: 999, background: 'var(--accent)', color: 'var(--on-accent)',
              border: 'none', font: 'inherit', fontSize: 12.5, fontWeight: 700, cursor: 'pointer',
            }}
          >Log</button>
        </div>
      </div>

      {/* Body */}
      <div style={{ padding: '16px 16px 44px', display: 'flex', flexDirection: 'column', gap: 14 }}>
        {/* Name + emoji */}
        <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>
          <div style={{ fontSize: 46, lineHeight: 1, flexShrink: 0 }}>{r.emoji || '🍳'}</div>
          <div>
            <div style={{ fontSize: 19, fontWeight: 700, letterSpacing: '-0.02em', lineHeight: 1.25 }}>
              {r.name || 'Untitled Recipe'}
            </div>
            {r.category && (
              <div style={{ fontSize: 13, color: 'var(--muted)', fontWeight: 600, marginTop: 4, textTransform: 'uppercase', letterSpacing: '0.04em' }}>
                {r.category}
              </div>
            )}
          </div>
        </div>

        {/* Macro summary */}
        <div style={{ ...nutriStyles.card, padding: 14, display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 8, textAlign: 'center' }}>
          {[
            { label: 'Calories', val: cal,  unit: 'kcal', color: 'var(--text)' },
            { label: 'Protein',  val: prot, unit: 'g',    color: 'var(--c-protein)' },
            { label: 'Carbs',    val: carb, unit: 'g',    color: 'var(--c-carbs)' },
            { label: 'Fat',      val: fat,  unit: 'g',    color: 'var(--c-fat)' },
          ].map(m => (
            <div key={m.label}>
              <div style={{ fontSize: 19, fontWeight: 800, color: m.color }}>{m.val}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{m.label}</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>{m.unit}</div>
            </div>
          ))}
        </div>

        {/* Serving options */}
        {r.servingOptions && r.servingOptions.length > 0 && (
          <div style={{ ...nutriStyles.card, padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>Serving Options</div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {r.servingOptions.map((opt, i) => (
                <div key={i} style={{
                  padding: '9px 13px', borderRadius: 12, background: 'var(--surface-2)', border: '1px solid var(--border)',
                }}>
                  <div style={{ fontSize: 13, fontWeight: 600 }}>{opt.label}</div>
                  <div style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 500, marginTop: 2 }}>{opt.calories} kcal</div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Note */}
        {r.note && (
          <div style={{ ...nutriStyles.card, padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Note</div>
            <div style={{ fontSize: 13.5, lineHeight: 1.65, color: 'var(--text)' }}>{r.note}</div>
          </div>
        )}

        {/* Ingredients table */}
        {r.items && r.items.length > 0 && (
          <div style={{ ...nutriStyles.card, padding: 0, overflow: 'hidden' }}>
            <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                Ingredients ({r.items.length})
              </div>
            </div>
            {/* Column headers */}
            <div style={{
              display: 'grid', gridTemplateColumns: '1.8fr 1.1fr 56px 38px 38px 38px',
              gap: 4, padding: '7px 12px', borderBottom: '1px solid var(--border)',
              background: 'var(--surface-2)',
            }}>
              {['Ingredient', 'Amount', 'Cal', 'P', 'C', 'F'].map(h => (
                <div key={h} style={{ fontSize: 10, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{h}</div>
              ))}
            </div>
            {r.items.map((it, i) => (
              <div key={i} style={{
                display: 'grid', gridTemplateColumns: '1.8fr 1.1fr 56px 38px 38px 38px',
                gap: 4, padding: '9px 12px',
                borderBottom: i < r.items.length - 1 ? '1px solid var(--border)' : 'none',
                background: i % 2 === 0 ? 'transparent' : 'var(--surface-2)',
              }}>
                <div style={{ fontSize: 12.5, fontWeight: 500, lineHeight: 1.3, wordBreak: 'break-word' }}>{it.name || '—'}</div>
                <div style={{ fontSize: 12, color: 'var(--muted)' }}>{it.amount || '—'}</div>
                <div style={{ fontSize: 12, fontWeight: 600 }}>{+it.calories || 0}</div>
                <div style={{ fontSize: 12, color: 'var(--c-protein)' }}>{+it.protein_g || 0}</div>
                <div style={{ fontSize: 12, color: 'var(--c-carbs)' }}>{+it.carbs_g || 0}</div>
                <div style={{ fontSize: 12, color: 'var(--c-fat)' }}>{+it.fat_g || 0}</div>
              </div>
            ))}
          </div>
        )}

        {/* Quick Log CTA */}
        <button
          onClick={() => onQuickLog(r)}
          style={{
            width: '100%', padding: '14px 0', borderRadius: 14,
            background: 'var(--accent)', color: 'var(--on-accent)',
            border: 'none', font: 'inherit', fontSize: 15, fontWeight: 700, cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          }}
        >
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
            <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
          </svg>
          Quick Log This Recipe
        </button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// QUICK LOG RECIPE SHEET — bottom sheet with editable ingredients
// ─────────────────────────────────────────────────────────────
function QuickLogRecipeSheet({ recipe, selectedDate, onConfirm, onClose }) {
  const r = recipe;
  const MEAL_OPTS = ['breakfast', 'lunch', 'dinner', 'snacks'];

  // Infer default meal from category
  const defaultMeal = (() => {
    const cat = (r.category || '').toLowerCase();
    if (/breakfast|فطار|brunch/.test(cat))  return 'breakfast';
    if (/lunch|غداء/.test(cat))             return 'lunch';
    if (/dinner|عشاء|supper/.test(cat))     return 'dinner';
    if (/snack|سناك/.test(cat))             return 'snacks';
    return 'dinner';
  })();

  const [date, setDate]                   = React.useState(selectedDate || NUTRI_TODAY);
  const [meal, setMeal]                   = React.useState(defaultMeal);
  const [selectedServing, setSelectedServing] = React.useState(null);
  const [note, setNote]                   = React.useState('');

  // Build editable ingredient rows from recipe.items
  const [ingRows, setIngRows] = React.useState(() =>
    (r.items || []).map(it => {
      const m = (it.amount || '').match(/(\d+(?:\.\d+)?)/);
      const origNum = m ? parseFloat(m[1]) : 0;
      // unit text = everything after the number
      const unitStr = m ? (it.amount || '').slice(m.index + m[0].length).trim() : (it.amount || '');
      return {
        name: it.name || '',
        origNum,
        unitStr,
        origCal: +it.calories  || 0,
        origP:   +it.protein_g || 0,
        origC:   +it.carbs_g   || 0,
        origF:   +it.fat_g     || 0,
        editedNum: origNum > 0 ? String(origNum) : '',
      };
    })
  );

  // Apply a serving option — scale all ingredient amounts proportionally
  function applyServing(opt) {
    if (!opt) {
      setSelectedServing(null);
      setIngRows(rows => rows.map(row => ({ ...row, editedNum: row.origNum > 0 ? String(row.origNum) : '' })));
      return;
    }
    setSelectedServing(opt);
    const totalCal = r.cal || 0;
    const mult = totalCal > 0 ? opt.calories / totalCal : 1;
    setIngRows(rows => rows.map(row => ({
      ...row,
      editedNum: row.origNum > 0 ? String(Math.round(row.origNum * mult * 10) / 10) : '',
    })));
  }

  // Edit one ingredient amount — deselects serving option
  function updateIngAmt(idx, val) {
    if (selectedServing) setSelectedServing(null);
    setIngRows(rows => rows.map((row, i) => i === idx ? { ...row, editedNum: val } : row));
  }

  // Live totals — recalculate from edited ingredient amounts
  const totals = React.useMemo(() => {
    if (ingRows.length === 0) {
      // No ingredients stored — use recipe-level macros × serving multiplier
      const mult = selectedServing && (r.cal || 0) > 0 ? selectedServing.calories / r.cal : 1;
      return {
        cal:  Math.round((r.cal || 0) * mult),
        prot: Math.round((+(r.protein_g || r.p || 0)) * mult * 10) / 10,
        carb: Math.round((+(r.carbs_g   || r.c || 0)) * mult * 10) / 10,
        fat:  Math.round((+(r.fat_g     || r.f || 0)) * mult * 10) / 10,
      };
    }
    const acc = ingRows.reduce((a, row) => {
      const edited = parseFloat(row.editedNum);
      const ratio  = (row.origNum > 0 && !isNaN(edited) && edited >= 0) ? edited / row.origNum : 1;
      a.cal  += Math.round(row.origCal * ratio);
      a.prot += row.origP * ratio;
      a.carb += row.origC * ratio;
      a.fat  += row.origF * ratio;
      return a;
    }, { cal: 0, prot: 0, carb: 0, fat: 0 });
    return {
      cal:  Math.round(acc.cal),
      prot: Math.round(acc.prot * 10) / 10,
      carb: Math.round(acc.carb * 10) / 10,
      fat:  Math.round(acc.fat  * 10) / 10,
    };
  }, [ingRows, selectedServing, r]);

  function handleConfirm() {
    const id = 'cal_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 5);
    const row = {
      id,
      date,
      meal: meal.toLowerCase(),
      name: r.name || 'Recipe',
      emoji: r.emoji || '🍳',
      time: new Date().toTimeString().slice(0, 5),
      calories:  Math.round(totals.cal),
      protein_g: Math.round(totals.prot * 10) / 10,
      carbs_g:   Math.round(totals.carb * 10) / 10,
      fat_g:     Math.round(totals.fat  * 10) / 10,
      note: note.trim(),
      source: 'recipe',
      sourceId: r.id,
      items: ingRows.map((row, _) => {
        const edited = parseFloat(row.editedNum);
        const ratio  = (row.origNum > 0 && !isNaN(edited) && edited >= 0) ? edited / row.origNum : 1;
        return {
          name:      row.name,
          amount:    (row.editedNum || String(row.origNum)) + (row.unitStr ? ' ' + row.unitStr : ''),
          qty:       (row.editedNum || String(row.origNum)) + (row.unitStr ? ' ' + row.unitStr : ''),
          calories:  Math.round(row.origCal * ratio),
          cal:       Math.round(row.origCal * ratio),
          protein_g: Math.round(row.origP * ratio * 10) / 10,
          carbs_g:   Math.round(row.origC * ratio * 10) / 10,
          fat_g:     Math.round(row.origF * ratio * 10) / 10,
        };
      }),
    };
    onConfirm(row);
  }

  const qlInputStyle = {
    width: '100%', border: '1px solid var(--border)', background: 'var(--surface)',
    borderRadius: 10, padding: '9px 12px', outline: 'none',
    font: 'inherit', fontSize: 14, color: 'var(--text)', boxSizing: 'border-box',
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 150,
      background: 'rgba(0,0,0,0.45)',
      display: 'flex', flexDirection: 'column', justifyContent: 'flex-end',
    }}>
      <div style={{
        background: 'var(--bg)', borderRadius: '20px 20px 0 0',
        maxHeight: '92vh', overflowY: 'auto',
        animation: 'slideUp 0.28s ease',
      }}>
        {/* Drag handle */}
        <div style={{ display: 'flex', justifyContent: 'center', padding: '12px 0 4px' }}>
          <div style={{ width: 40, height: 4, borderRadius: 2, background: 'var(--border)' }}/>
        </div>

        {/* Sheet header */}
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '0 16px 14px', borderBottom: '1px solid var(--border)',
        }}>
          <div>
            <div style={{ fontSize: 15, fontWeight: 700 }}>Quick Log</div>
            <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2 }}>{r.name}</div>
          </div>
          <button onClick={onClose} style={iconBtnGhost}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
              <path d="M18 6L6 18M6 6l12 12"/>
            </svg>
          </button>
        </div>

        <div style={{ padding: '14px 16px 32px', display: 'flex', flexDirection: 'column', gap: 16 }}>

          {/* Meal type */}
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Meal Type</div>
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 4,
              background: 'var(--surface-2)', borderRadius: 12, padding: 4, border: '1px solid var(--border)',
            }}>
              {MEAL_OPTS.map(o => (
                <button key={o} onClick={() => setMeal(o)} style={{
                  padding: '8px 0', borderRadius: 9, border: 0,
                  background: meal === o ? 'var(--surface)' : 'transparent',
                  color: meal === o ? 'var(--text)' : 'var(--muted)',
                  fontSize: 11.5, fontWeight: 700, cursor: 'pointer', font: 'inherit',
                  boxShadow: meal === o ? 'var(--shadow-sm)' : 'none',
                  textTransform: 'capitalize',
                }}>{o}</button>
              ))}
            </div>
          </div>

          {/* Date */}
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Date</div>
            <input type="date" value={date} onChange={e => setDate(e.target.value)} style={qlInputStyle}/>
          </div>

          {/* Serving options */}
          {r.servingOptions && r.servingOptions.length > 0 && (
            <div>
              <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Serving</div>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                <button onClick={() => applyServing(null)} style={{
                  padding: '7px 13px', borderRadius: 10, border: '1.5px solid var(--border)',
                  background: selectedServing === null ? 'var(--accent)' : 'var(--surface)',
                  color: selectedServing === null ? 'var(--on-accent)' : 'var(--text)',
                  font: 'inherit', fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
                }}>Custom</button>
                {r.servingOptions.map((opt, i) => (
                  <button key={i} onClick={() => applyServing(opt)} style={{
                    padding: '7px 13px', borderRadius: 10, border: '1.5px solid var(--border)',
                    background: selectedServing === opt ? 'var(--accent)' : 'var(--surface)',
                    color: selectedServing === opt ? 'var(--on-accent)' : 'var(--text)',
                    font: 'inherit', fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
                  }}>{opt.label} · {opt.calories} kcal</button>
                ))}
              </div>
            </div>
          )}

          {/* Editable ingredient amounts */}
          {ingRows.length > 0 && (
            <div>
              <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>
                Adjust Ingredients
              </div>
              <div style={{ ...nutriStyles.card, padding: 0, overflow: 'hidden' }}>
                {ingRows.map((row, idx) => {
                  const edited = parseFloat(row.editedNum);
                  const ratio  = (row.origNum > 0 && !isNaN(edited) && edited >= 0) ? edited / row.origNum : 1;
                  const sCal   = Math.round(row.origCal * ratio);
                  const sP     = Math.round(row.origP * ratio * 10) / 10;
                  const sC     = Math.round(row.origC * ratio * 10) / 10;
                  const sF     = Math.round(row.origF * ratio * 10) / 10;
                  return (
                    <div key={idx} style={{
                      padding: '10px 12px',
                      borderBottom: idx < ingRows.length - 1 ? '1px solid var(--border)' : 'none',
                    }}>
                      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, marginBottom: 5 }}>
                        <div style={{ fontSize: 13, fontWeight: 600, flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                          {row.name}
                        </div>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 5, flexShrink: 0 }}>
                          <input
                            type="number" inputMode="decimal"
                            value={row.editedNum}
                            onChange={e => updateIngAmt(idx, e.target.value)}
                            style={{
                              width: 64, border: '1px solid var(--border)', background: 'var(--surface)',
                              borderRadius: 8, padding: '5px 8px', outline: 'none', font: 'inherit',
                              fontSize: 13, color: 'var(--text)', textAlign: 'right',
                            }}
                          />
                          {row.unitStr && (
                            <span style={{ fontSize: 11.5, color: 'var(--muted)', fontWeight: 500, minWidth: 24 }}>{row.unitStr}</span>
                          )}
                        </div>
                      </div>
                      {/* Per-ingredient recalculated macros */}
                      <div style={{ display: 'flex', gap: 10, fontSize: 11.5 }}>
                        <span style={{ fontWeight: 600 }}>{sCal} kcal</span>
                        <span style={{ color: 'var(--c-protein)' }}>P {sP}g</span>
                        <span style={{ color: 'var(--c-carbs)' }}>C {sC}g</span>
                        <span style={{ color: 'var(--c-fat)' }}>F {sF}g</span>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {/* Live total macros */}
          <div style={{ ...nutriStyles.card, padding: 14, display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 8, textAlign: 'center' }}>
            <div>
              <div style={{ fontSize: 20, fontWeight: 800 }}>{totals.cal}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>Calories</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>kcal</div>
            </div>
            <div>
              <div style={{ fontSize: 20, fontWeight: 800, color: 'var(--c-protein)' }}>{totals.prot}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>Protein</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>g</div>
            </div>
            <div>
              <div style={{ fontSize: 20, fontWeight: 800, color: 'var(--c-carbs)' }}>{totals.carb}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>Carbs</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>g</div>
            </div>
            <div>
              <div style={{ fontSize: 20, fontWeight: 800, color: 'var(--c-fat)' }}>{totals.fat}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>Fat</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>g</div>
            </div>
          </div>

          {/* Optional note */}
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Note (optional)</div>
            <input
              value={note} onChange={e => setNote(e.target.value)}
              placeholder="Add a note…" style={qlInputStyle}
            />
          </div>

          {/* Confirm */}
          <button
            onClick={handleConfirm}
            disabled={!date || totals.cal <= 0}
            style={{
              width: '100%', padding: '14px 0', borderRadius: 14, border: 'none',
              background: (!date || totals.cal <= 0) ? 'var(--surface-2)' : 'var(--accent)',
              color:      (!date || totals.cal <= 0) ? 'var(--muted)'    : 'var(--on-accent)',
              font: 'inherit', fontSize: 15, fontWeight: 700, cursor: 'pointer',
            }}
          >
            Log Recipe
          </button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// EDIT RECIPE SHEET — full-screen editor for a saved recipe
// ─────────────────────────────────────────────────────────────
function EditRecipeSheet({ recipe, onClose }) {
  const r = recipe;

  const [name,     setName]     = React.useState(r.name     || '');
  const [emoji,    setEmoji]    = React.useState(r.emoji    || '🍳');
  const [category, setCategory] = React.useState(r.category || '');
  const [note,     setNote]     = React.useState(r.note     || '');

  // Editable ingredient rows
  const [items, setItems] = React.useState(() =>
    (r.items || []).map(it => ({
      name:      it.name      || '',
      amount:    it.amount    || '',
      calories:  String(+(it.calories  || 0)),
      protein_g: String(+(it.protein_g || 0)),
      carbs_g:   String(+(it.carbs_g   || 0)),
      fat_g:     String(+(it.fat_g     || 0)),
    }))
  );

  // Editable serving options
  const [servingOpts, setServingOpts] = React.useState(() =>
    (r.servingOptions || []).map(opt => ({
      label:    opt.label    || '',
      calories: String(+(opt.calories || 0)),
    }))
  );

  // Live totals recalculated from ingredient rows
  const totals = React.useMemo(() => {
    if (items.length === 0) {
      return {
        cal:  +(r.cal  || 0),
        prot: +(r.protein_g || r.p || 0),
        carb: +(r.carbs_g   || r.c || 0),
        fat:  +(r.fat_g     || r.f || 0),
      };
    }
    return items.reduce((acc, it) => {
      acc.cal  += +(it.calories  || 0);
      acc.prot += +(it.protein_g || 0);
      acc.carb += +(it.carbs_g   || 0);
      acc.fat  += +(it.fat_g     || 0);
      return acc;
    }, { cal: 0, prot: 0, carb: 0, fat: 0 });
  }, [items, r]);

  function addItem() {
    setItems(prev => [...prev, { name: '', amount: '', calories: '0', protein_g: '0', carbs_g: '0', fat_g: '0' }]);
  }
  function removeItem(idx) {
    setItems(prev => prev.filter((_, i) => i !== idx));
  }
  function updateItem(idx, field, val) {
    setItems(prev => prev.map((it, i) => i === idx ? { ...it, [field]: val } : it));
  }
  function addServingOpt() {
    setServingOpts(prev => [...prev, { label: '', calories: '0' }]);
  }
  function removeServingOpt(idx) {
    setServingOpts(prev => prev.filter((_, i) => i !== idx));
  }
  function updateServingOpt(idx, field, val) {
    setServingOpts(prev => prev.map((opt, i) => i === idx ? { ...opt, [field]: val } : opt));
  }

  function handleSave() {
    const updatedRecipe = {
      ...r,
      name:      name.trim() || r.name,
      emoji:     emoji.trim() || '🍳',
      category:  category.trim(),
      note:      note.trim(),
      cal:       Math.round(totals.cal),
      protein_g: Math.round(totals.prot * 10) / 10,
      carbs_g:   Math.round(totals.carb * 10) / 10,
      fat_g:     Math.round(totals.fat  * 10) / 10,
      p:         Math.round(totals.prot * 10) / 10,
      c:         Math.round(totals.carb * 10) / 10,
      f:         Math.round(totals.fat  * 10) / 10,
      items: items.map(it => ({
        name:      it.name,
        amount:    it.amount,
        calories:  +(it.calories  || 0),
        protein_g: +(it.protein_g || 0),
        carbs_g:   +(it.carbs_g   || 0),
        fat_g:     +(it.fat_g     || 0),
      })),
      servingOptions: servingOpts
        .filter(opt => opt.label.trim())
        .map(opt => ({ label: opt.label.trim(), calories: +(opt.calories || 0) })),
      updatedAt: new Date().toISOString(),
    };
    window.Store.updateLocalItem(r.id, updatedRecipe);
    onClose();
  }

  const erInputStyle = {
    width: '100%', border: '1px solid var(--border)', background: 'var(--surface)',
    borderRadius: 10, padding: '9px 12px', outline: 'none',
    font: 'inherit', fontSize: 14, color: 'var(--text)', boxSizing: 'border-box',
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 160,
      background: 'var(--bg)', overflowY: 'auto',
      animation: 'sheetIn 0.22s ease',
    }}>
      {/* Sticky header */}
      <div style={{
        position: 'sticky', top: 0, background: 'var(--bg)',
        borderBottom: '1px solid var(--border)', padding: '10px 16px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', zIndex: 10,
      }}>
        <button onClick={onClose} style={iconBtnGhost}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
            <path d="M18 6L6 18M6 6l12 12"/>
          </svg>
        </button>
        <div style={{ fontSize: 15, fontWeight: 700 }}>Edit Recipe</div>
        <button
          onClick={handleSave}
          disabled={!name.trim()}
          style={{
            padding: '7px 18px', borderRadius: 999, border: 'none',
            background: name.trim() ? 'var(--accent)' : 'var(--surface-2)',
            color: name.trim() ? 'var(--on-accent)' : 'var(--muted)',
            font: 'inherit', fontSize: 12.5, fontWeight: 700, cursor: name.trim() ? 'pointer' : 'default',
          }}
        >Save</button>
      </div>

      {/* Scrollable body */}
      <div style={{ padding: '16px 16px 56px', display: 'flex', flexDirection: 'column', gap: 18 }}>

        {/* Recipe Name */}
        <div>
          <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 7 }}>Recipe Name</div>
          <input
            type="text" value={name} onChange={e => setName(e.target.value)}
            placeholder="e.g. Chicken & Rice Bowl"
            style={erInputStyle}
          />
        </div>

        {/* Emoji + Category */}
        <div style={{ display: 'grid', gridTemplateColumns: '76px 1fr', gap: 10 }}>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 7 }}>Emoji</div>
            <input
              type="text" value={emoji} onChange={e => setEmoji(e.target.value)}
              placeholder="🍳"
              style={{ ...erInputStyle, textAlign: 'center', fontSize: 22, padding: '6px 8px' }}
            />
          </div>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 7 }}>Category</div>
            <input
              type="text" value={category} onChange={e => setCategory(e.target.value)}
              placeholder="e.g. Lunch"
              style={erInputStyle}
            />
          </div>
        </div>

        {/* Note */}
        <div>
          <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 7 }}>Note (optional)</div>
          <textarea
            value={note} onChange={e => setNote(e.target.value)}
            placeholder="Any notes about this recipe…"
            rows={3}
            style={{ ...erInputStyle, resize: 'none', lineHeight: 1.55 }}
          />
        </div>

        {/* Ingredients */}
        <div>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
              Ingredients ({items.length})
            </div>
            <button
              onClick={addItem}
              style={{
                padding: '5px 13px', borderRadius: 999, border: '1.5px solid var(--accent)',
                background: 'transparent', color: 'var(--accent)',
                font: 'inherit', fontSize: 12, fontWeight: 700, cursor: 'pointer',
              }}
            >+ Add Row</button>
          </div>

          {items.length === 0 && (
            <div style={{ fontSize: 12.5, color: 'var(--muted)', textAlign: 'center', padding: '14px 0' }}>
              No ingredients. Tap "+ Add Row" to add one.
            </div>
          )}

          {items.map((it, idx) => (
            <div key={idx} style={{
              ...nutriStyles.card, padding: '10px 12px', marginBottom: 8,
              display: 'flex', flexDirection: 'column', gap: 8,
            }}>
              {/* Name row */}
              <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                <input
                  type="text" value={it.name}
                  onChange={e => updateItem(idx, 'name', e.target.value)}
                  placeholder="Ingredient name"
                  style={{ ...erInputStyle, flex: 1 }}
                />
                <button
                  onClick={() => removeItem(idx)}
                  style={{
                    width: 30, height: 36, borderRadius: 8, border: '1px solid var(--border)',
                    background: 'transparent', color: '#ef4444', cursor: 'pointer',
                    font: 'inherit', fontSize: 18, display: 'grid', placeItems: 'center', flexShrink: 0,
                  }}
                >×</button>
              </div>
              {/* Amount + macros row */}
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 56px 44px 44px 44px', gap: 6 }}>
                {[
                  { field: 'amount',    label: 'Amount', isText: true  },
                  { field: 'calories',  label: 'Cal',    isText: false },
                  { field: 'protein_g', label: 'P(g)',   isText: false },
                  { field: 'carbs_g',   label: 'C(g)',   isText: false },
                  { field: 'fat_g',     label: 'F(g)',   isText: false },
                ].map(col => (
                  <div key={col.field}>
                    <div style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 3 }}>
                      {col.label}
                    </div>
                    <input
                      type={col.isText ? 'text' : 'number'}
                      inputMode={col.isText ? 'text' : 'decimal'}
                      value={it[col.field]}
                      onChange={e => updateItem(idx, col.field, e.target.value)}
                      placeholder={col.isText ? 'e.g. 100g' : '0'}
                      style={{
                        width: '100%', border: '1px solid var(--border)', background: 'var(--surface)',
                        borderRadius: 8, padding: '7px 6px', outline: 'none',
                        font: 'inherit', fontSize: 12.5, color: 'var(--text)', boxSizing: 'border-box',
                        textAlign: col.isText ? 'left' : 'right',
                      }}
                    />
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>

        {/* Live totals preview */}
        <div style={{ ...nutriStyles.card, padding: 14, display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 8, textAlign: 'center' }}>
          {[
            { label: 'Calories', val: Math.round(totals.cal),              unit: 'kcal', color: 'var(--text)' },
            { label: 'Protein',  val: Math.round(totals.prot * 10) / 10,  unit: 'g',    color: 'var(--c-protein)' },
            { label: 'Carbs',    val: Math.round(totals.carb * 10) / 10,  unit: 'g',    color: 'var(--c-carbs)' },
            { label: 'Fat',      val: Math.round(totals.fat  * 10) / 10,  unit: 'g',    color: 'var(--c-fat)' },
          ].map(m => (
            <div key={m.label}>
              <div style={{ fontSize: 18, fontWeight: 800, color: m.color }}>{m.val}</div>
              <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{m.label}</div>
              <div style={{ fontSize: 9.5, color: 'var(--muted)' }}>{m.unit}</div>
            </div>
          ))}
        </div>

        {/* Serving options */}
        <div>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
              Serving Options ({servingOpts.length})
            </div>
            <button
              onClick={addServingOpt}
              style={{
                padding: '5px 13px', borderRadius: 999, border: '1.5px solid var(--accent)',
                background: 'transparent', color: 'var(--accent)',
                font: 'inherit', fontSize: 12, fontWeight: 700, cursor: 'pointer',
              }}
            >+ Add</button>
          </div>

          {servingOpts.length === 0 && (
            <div style={{ fontSize: 12.5, color: 'var(--muted)', textAlign: 'center', padding: '12px 0' }}>
              No serving options. Tap "+ Add" to define portions.
            </div>
          )}

          {servingOpts.map((opt, idx) => (
            <div key={idx} style={{ display: 'grid', gridTemplateColumns: '1fr 110px 32px', gap: 8, marginBottom: 8, alignItems: 'center' }}>
              <input
                type="text" value={opt.label}
                onChange={e => updateServingOpt(idx, 'label', e.target.value)}
                placeholder="e.g. Half portion"
                style={erInputStyle}
              />
              <div style={{ position: 'relative' }}>
                <input
                  type="number" inputMode="decimal"
                  value={opt.calories}
                  onChange={e => updateServingOpt(idx, 'calories', e.target.value)}
                  placeholder="0"
                  style={{ ...erInputStyle, paddingRight: 38 }}
                />
                <span style={{ position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)', fontSize: 11, color: 'var(--muted)', pointerEvents: 'none' }}>kcal</span>
              </div>
              <button
                onClick={() => removeServingOpt(idx)}
                style={{
                  width: 32, height: 38, borderRadius: 8, border: '1px solid var(--border)',
                  background: 'transparent', color: '#ef4444', cursor: 'pointer',
                  font: 'inherit', fontSize: 18, display: 'grid', placeItems: 'center',
                }}
              >×</button>
            </div>
          ))}
        </div>

      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// DELETE RECIPE CONFIRM DIALOG
// ─────────────────────────────────────────────────────────────
function DeleteRecipeConfirmDialog({ recipe, onClose, onConfirm }) {
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 170,
      background: 'rgba(0,0,0,0.55)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '0 24px',
    }}>
      <div style={{
        background: 'var(--bg)', borderRadius: 20, padding: '28px 24px',
        width: '100%', maxWidth: 360,
        animation: 'sheetIn 0.2s ease',
        boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
      }}>
        <div style={{ fontSize: 40, textAlign: 'center', marginBottom: 10 }}>{recipe.emoji || '🍳'}</div>
        <div style={{ fontSize: 18, fontWeight: 700, textAlign: 'center', marginBottom: 6 }}>Delete Recipe?</div>
        <div style={{ fontSize: 14, color: 'var(--text)', textAlign: 'center', fontWeight: 600, marginBottom: 10 }}>
          {recipe.name}
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', textAlign: 'center', lineHeight: 1.65, marginBottom: 24 }}>
          This will remove the recipe from your library. Meals you already logged from this recipe will not be affected.
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          <button
            onClick={onClose}
            style={{
              flex: 1, padding: '13px 0', borderRadius: 12,
              border: '1px solid var(--border)', background: 'var(--surface)',
              font: 'inherit', fontSize: 14, fontWeight: 600, cursor: 'pointer', color: 'var(--text)',
            }}
          >Cancel</button>
          <button
            onClick={onConfirm}
            style={{
              flex: 1, padding: '13px 0', borderRadius: 12,
              border: 'none', background: '#ef4444',
              font: 'inherit', fontSize: 14, fontWeight: 700, cursor: 'pointer', color: '#fff',
            }}
          >Delete</button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Shared helpers referenced from nutri-app.jsx
// ─────────────────────────────────────────────────────────────
const iconBtnGhost = {
  width: 34, height: 34, borderRadius: '50%',
  background: 'transparent', border: '1px solid var(--border)',
  color: 'var(--text)', display: 'grid', placeItems: 'center', cursor: 'pointer',
  fontSize: 18, fontFamily: 'inherit',
};

// ─────────────────────────────────────────────────────────────
// EXPORTS
// ─────────────────────────────────────────────────────────────
Object.assign(window, {
  CaloriesHome,
  TodayProgressCard,
  MacroGoalEditorSheet,
  CalRecentMeals,
  FoodLibraryTab,
  LocalLibraryTab,
  AddLocalItemSheet,
  LogFoodSheet,
  DuplicateEntryDialog,
  CaloriesCalendar,
  DayDetailPanel,
  MealDonutChart,
  CaloriesStats,
  StatTile,
  SimpleBarChart,
  GroupedMacrosChart,
  MacroDistChart,
  MealStackedBarChart,
  MacroGroupedBarChart,
  WeightLineChart,
  MacrosTable,
  RecipesScreen,
  RecipeCard,
  RecipeDetailSheet,
  QuickLogRecipeSheet,
  EditRecipeSheet,
  DeleteRecipeConfirmDialog,
});
