<script lang="ts">
  import { onMount } from 'svelte';

  type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack';
  type FitnessTab = 'log' | 'foods' | 'templates';

  interface FoodEntry {
    id: string;
    name: string;
    serving: string;
    calories: number;
    protein: number;
    carbs: number;
    fat: number;
    sugar: number;
    fiber: number;
    method: string;
    image?: string;
    note?: string;
    meal: MealType;
    rawQty: number;
    rawUnit: string;
  }

  interface FoodItem {
    id: string;
    name: string;
    info: string;
    calories: number;
    protein?: number;
    carbs?: number;
    fat?: number;
    sugar?: number;
    fiber?: number;
    favorite?: boolean;
  }

  interface Template {
    id: string;
    name: string;
    calories: number;
    items: number;
    meal: string;
  }

  const now = new Date();
  const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;

  let activeTab = $state<FitnessTab>('log');
  let selectedDate = $state(todayStr);
  let expandedMeals = $state<Set<string>>(new Set(['breakfast', 'lunch', 'dinner', 'snack']));
  let foodSearch = $state('');
  let highlightTemplate = $state('');
  let loading = $state(true);
  let foodsLoading = $state(false);
  let templatesLoading = $state(false);

  let entries = $state<FoodEntry[]>([]);
  let goal = $state({ calories: 2000, protein: 150, carbs: 200, fat: 65, sugar: 0, fiber: 0 });
  let foods = $state<FoodItem[]>([]);
  let recentFoods = $state<FoodItem[]>([]);
  let templates = $state<Template[]>([]);
  let starterMeal = $state<MealType>(guessCurrentMeal());
  let mealStarterFoods = $state<Record<MealType, FoodItem[]>>({
    breakfast: [],
    lunch: [],
    dinner: [],
    snack: []
  });

  function isIosSafari(): boolean {
    const ua = navigator.userAgent;
    const isIos = /iPhone|iPad|iPod/.test(ua);
    const isWebKit = /WebKit/.test(ua);
    const otherIosBrowser = /CriOS|FxiOS|EdgiOS|OPiOS|DuckDuckGo|YaBrowser/i.test(ua);
    return isIos && isWebKit && !otherIosBrowser;
  }

  function openAssistant() {
    window.dispatchEvent(new CustomEvent('openassistant', { detail: { entryDate: selectedDate } }));
  }

  // Map backend entry to UI entry
  function mapEntry(e: any): FoodEntry {
    return {
      id: e.id,
      name: e.snapshot_food_name || 'Unknown',
      serving: e.serving_description || e.snapshot_serving_label || `${e.quantity || 1} ${e.unit || 'serving'}`,
      calories: Math.round(e.snapshot_calories || 0),
      protein: Math.round(e.snapshot_protein || 0),
      carbs: Math.round(e.snapshot_carbs || 0),
      fat: Math.round(e.snapshot_fat || 0),
      sugar: Math.round(e.snapshot_sugar || 0),
      fiber: Math.round(e.snapshot_fiber || 0),
      method: e.entry_method || 'manual',
      image: e.food_image_path,
      note: e.note,
      meal: (e.meal_type || 'snack') as MealType,
      rawQty: e.quantity || 1,
      rawUnit: e.unit || 'serving',
    };
  }

  // Map backend food to UI food (handles both /foods and /foods/recent shapes)
  function mapFood(f: any): FoodItem {
    const id = f.id || f.food_id || '';
    const name = f.name || f.snapshot_food_name || 'Unknown';
    const brand = f.brand ? `${f.brand} · ` : '';
    const unit = f.base_unit === '100g' ? '100g' : (f.servings?.[0]?.label || f.base_unit || 'serving');
    return {
      id,
      name,
      info: `${brand}${unit}`,
      calories: Math.round(f.calories_per_base || 0),
      protein: Math.round(f.protein_per_base || 0),
      carbs: Math.round(f.carbs_per_base || 0),
      fat: Math.round(f.fat_per_base || 0),
      sugar: Math.round(f.sugar_per_base || 0),
      fiber: Math.round(f.fiber_per_base || 0),
      favorite: f.is_favorite || false,
    };
  }

  // Map backend template to UI template
  function mapTemplate(t: any): Template {
    const items = t.items || [];
    const totalCal = items.reduce((s: number, i: any) => s + (i.snapshot_calories || 0) * (i.quantity || 1), 0);
    return {
      id: t.id,
      name: t.name,
      calories: Math.round(totalCal),
      items: items.length,
      meal: t.meal_type || 'snack',
    };
  }

  async function loadDayData() {
    loading = true;
    try {
      const [entriesRes, goalsRes] = await Promise.all([
        fetch(`/api/fitness/entries?date=${selectedDate}`, { credentials: 'include' }),
        fetch(`/api/fitness/goals/for-date?date=${selectedDate}`, { credentials: 'include' }),
      ]);
      if (entriesRes.ok) {
        const raw = await entriesRes.json();
        entries = (Array.isArray(raw) ? raw : []).map(mapEntry);
      } else {
        entries = [];
      }
      if (goalsRes.ok) {
        const g = await goalsRes.json();
        goal = {
          calories: g.calories || 2000,
          protein: g.protein || 150,
          carbs: g.carbs || 200,
          fat: g.fat || 65,
          sugar: g.sugar || 0,
          fiber: g.fiber || 0
        };
      }
    } catch { /* silent */ }
    loading = false;
  }

  async function loadFoods(query?: string) {
    foodsLoading = true;
    try {
      const url = query
        ? `/api/fitness/foods/search?q=${encodeURIComponent(query)}&limit=30`
        : `/api/fitness/foods?limit=100`;
      const res = await fetch(url, { credentials: 'include' });
      if (res.ok) {
        const raw = await res.json();
        foods = (Array.isArray(raw) ? raw : []).map(mapFood);
      }
    } catch { /* silent */ }
    foodsLoading = false;
  }

  async function loadTemplates() {
    templatesLoading = true;
    try {
      const res = await fetch('/api/fitness/templates', { credentials: 'include' });
      if (res.ok) {
        const raw = await res.json();
        templates = (Array.isArray(raw) ? raw : []).map(mapTemplate);
      }
    } catch { /* silent */ }
    templatesLoading = false;
  }

  async function loadRecentFoods() {
    try {
      const res = await fetch('/api/fitness/foods/recent?limit=8', { credentials: 'include' });
      if (res.ok) {
        const raw = await res.json();
        recentFoods = (Array.isArray(raw) ? raw : []).map(mapFood);
      } else {
        recentFoods = [];
      }
    } catch {
      recentFoods = [];
    }
  }

  function dateDaysAgo(base: string, daysAgo: number): string {
    const d = new Date(`${base}T00:00:00`);
    d.setDate(d.getDate() - daysAgo);
    return d.toISOString().slice(0, 10);
  }

  async function loadMealStarterFoods() {
    try {
      const dates = Array.from({ length: 14 }, (_, i) => dateDaysAgo(selectedDate, i + 1));
      const responses = await Promise.all(
        dates.map(async (entryDate) => {
          const res = await fetch(`/api/fitness/entries?date=${entryDate}`, { credentials: 'include' });
          if (!res.ok) return [];
          const raw = await res.json();
          return Array.isArray(raw) ? raw : [];
        })
      );

      const buckets: Record<MealType, Map<string, { count: number; lastUsed: string; food: FoodItem }>> = {
        breakfast: new Map(),
        lunch: new Map(),
        dinner: new Map(),
        snack: new Map()
      };

      for (const dayEntries of responses) {
        for (const entry of dayEntries) {
          const meal = (entry.meal_type || 'snack') as MealType;
          const foodId = entry.food_id;
          if (!foodId || !buckets[meal]) continue;
          const existing = buckets[meal].get(foodId);
          const food: FoodItem = {
            id: foodId,
            name: entry.snapshot_food_name || 'Unknown',
            info: entry.snapshot_serving_label || entry.serving_description || entry.unit || 'serving',
            calories: Math.round(entry.snapshot_calories || 0)
          };

          if (existing) {
            existing.count += 1;
            if ((entry.created_at || '') > existing.lastUsed) existing.lastUsed = entry.created_at || existing.lastUsed;
          } else {
            buckets[meal].set(foodId, {
              count: 1,
              lastUsed: entry.created_at || '',
              food
            });
          }
        }
      }

      mealStarterFoods = {
        breakfast: [...buckets.breakfast.values()].sort((a, b) => b.count - a.count || b.lastUsed.localeCompare(a.lastUsed)).map((item) => item.food).slice(0, 6),
        lunch: [...buckets.lunch.values()].sort((a, b) => b.count - a.count || b.lastUsed.localeCompare(a.lastUsed)).map((item) => item.food).slice(0, 6),
        dinner: [...buckets.dinner.values()].sort((a, b) => b.count - a.count || b.lastUsed.localeCompare(a.lastUsed)).map((item) => item.food).slice(0, 6),
        snack: [...buckets.snack.values()].sort((a, b) => b.count - a.count || b.lastUsed.localeCompare(a.lastUsed)).map((item) => item.food).slice(0, 6)
      };
    } catch {
      mealStarterFoods = {
        breakfast: [],
        lunch: [],
        dinner: [],
        snack: []
      };
    }
  }

  let expandedEntry = $state<string | null>(null);

  async function deleteEntry(id: string) {
    expandedEntry = null;
    entries = entries.filter(e => e.id !== id);
    try {
      await fetch(`/api/fitness/entries/${id}`, { method: 'DELETE', credentials: 'include' });
    } catch {
      await loadDayData();
    }
  }

  let editQtyValue = $state('');

  function toggleEntry(id: string) {
    if (expandedEntry === id) {
      expandedEntry = null;
    } else {
      expandedEntry = id;
      const entry = entries.find(e => e.id === id);
      editQtyValue = entry ? String(entry.rawQty) : '1';
    }
  }

  async function updateEntryQty(id: string) {
    const newQty = parseFloat(editQtyValue);
    if (!newQty || newQty <= 0) return;
    expandedEntry = null;
    try {
      const res = await fetch(`/api/fitness/entries/${id}`, {
        method: 'PATCH',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ quantity: newQty }),
      });
      if (res.ok) {
        await loadDayData();
      }
    } catch { /* silent */ }
  }

  async function logTemplate(tpl: Template) {
    try {
      const res = await fetch(`/api/fitness/templates/${tpl.id}/log`, {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ meal_type: tpl.meal, entry_date: selectedDate }),
      });
      if (res.ok) {
        activeTab = 'log';
        await loadDayData();
      }
    } catch { /* silent */ }
  }

  async function quickAddRecentFood(food: FoodItem, meal: MealType) {
    try {
      const res = await fetch('/api/fitness/entries', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          food_id: food.id,
          quantity: 1,
          unit: 'serving',
          meal_type: meal,
          entry_date: selectedDate,
          entry_method: 'search',
          source: 'web'
        })
      });
      if (res.ok) {
        await loadDayData();
      }
    } catch { /* silent */ }
  }

  // ── AI Food Resolve (multi-item) ──
  interface ResolvedItem {
    result: any;
    name: string;
    qty: number;
    unit: string;
    calories: number;
    protein: number;
    carbs: number;
    fat: number;
  }

  let resolveInput = $state('');
  let resolveMeal = $state<MealType>('snack');
  let resolving = $state(false);
  let resolvedItems = $state<ResolvedItem[]>([]);
  let resolveError = $state('');
  let confirmLogging = $state(false);

  function guessCurrentMeal(): MealType {
    const h = new Date().getHours();
    if (h >= 6 && h < 11) return 'breakfast';
    if (h >= 11 && h < 15) return 'lunch';
    if (h >= 17 && h < 21) return 'dinner';
    return 'snack';
  }

  async function splitInputItems(input: string): Promise<string[]> {
    // Use AI to split multi-item input into individual food items
    try {
      const res = await fetch('/api/fitness/foods/split', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phrase: input }),
      });
      if (res.ok) {
        const data = await res.json();
        if (data.items?.length > 0) return data.items;
      }
    } catch { /* fallback below */ }
    // Fallback: comma split
    return input.split(/,/).map(s => s.trim()).filter(s => s.length > 0);
  }

  function resolveToItem(r: any): ResolvedItem {
    const qty = r.parsed?.quantity || 1;
    const food = r.matched_food;
    let cal = 0, pro = 0, carb = 0, f = 0;
    if (food) {
      cal = (food.calories_per_base || 0) * qty;
      pro = (food.protein_per_base || 0) * qty;
      carb = (food.carbs_per_base || 0) * qty;
      f = (food.fat_per_base || 0) * qty;
    } else if (r.ai_estimate) {
      cal = (r.ai_estimate.calories_per_base || 0) * qty;
      pro = (r.ai_estimate.protein_per_base || 0) * qty;
      carb = (r.ai_estimate.carbs_per_base || 0) * qty;
      f = (r.ai_estimate.fat_per_base || 0) * qty;
    } else if (r.resolution_type === 'quick_add') {
      cal = r.parsed?.quantity || 0;
    }
    const name = r.snapshot_name_override || food?.name || r.ai_estimate?.food_name || r.raw_text || 'Unknown';
    return {
      result: r,
      name,
      qty: Math.round(qty * 10) / 10,
      unit: r.parsed?.unit || 'serving',
      calories: Math.round(cal),
      protein: Math.round(pro),
      carbs: Math.round(carb),
      fat: Math.round(f),
    };
  }

  async function submitResolve() {
    const phrase = resolveInput.trim();
    if (!phrase) return;
    resolving = true;
    resolveError = '';
    resolvedItems = [];
    resolveMeal = guessCurrentMeal();

    const parts = await splitInputItems(phrase);

    try {
      const results = await Promise.all(parts.map(async (part) => {
        const res = await fetch('/api/fitness/foods/resolve', {
          method: 'POST',
          credentials: 'include',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ raw_phrase: part, meal_type: resolveMeal, entry_date: selectedDate }),
        });
        if (!res.ok) {
          if (res.status === 401) throw new Error('Not connected — connect fitness in Settings');
          throw new Error(`Failed to resolve "${part}" (${res.status})`);
        }
        return res.json();
      }));
      resolvedItems = results.map(resolveToItem);
    } catch (e: any) {
      resolveError = e?.message || 'Network error';
    }
    resolving = false;
  }

  function updateItemQty(index: number, newQty: number) {
    if (newQty <= 0) return;
    const item = resolvedItems[index];
    const r = item.result;
    const food = r.matched_food;
    const base = food || r.ai_estimate;
    if (!base) return;
    resolvedItems[index] = {
      ...item,
      qty: Math.round(newQty * 10) / 10,
      calories: Math.round((base.calories_per_base || 0) * newQty),
      protein: Math.round((base.protein_per_base || 0) * newQty),
      carbs: Math.round((base.carbs_per_base || 0) * newQty),
      fat: Math.round((base.fat_per_base || 0) * newQty),
    };
  }

  function removeItem(index: number) {
    resolvedItems = resolvedItems.filter((_, i) => i !== index);
    if (resolvedItems.length === 0) cancelResolve();
  }

  const resolveTotalCal = $derived(resolvedItems.reduce((s, i) => s + i.calories, 0));

  async function confirmResolve() {
    if (resolvedItems.length === 0) return;
    confirmLogging = true;
    try {
      for (const item of resolvedItems) {
        const r = item.result;
        let body: any;
        if (r.resolution_type === 'quick_add' && !r.matched_food) {
          body = {
            entry_type: 'quick_add',
            snapshot_food_name: r.raw_text || 'Quick add',
            snapshot_calories: item.calories,
            meal_type: resolveMeal,
            entry_date: selectedDate,
            source: 'web',
            raw_text: r.raw_text,
          };
        } else if (r.matched_food) {
          body = {
            food_id: r.matched_food.id,
            quantity: item.qty,
            unit: item.unit,
            meal_type: resolveMeal,
            entry_date: selectedDate,
            entry_method: r.resolution_type === 'ai_estimated' ? 'ai_label' : 'search',
            source: 'web',
            raw_text: r.raw_text,
            confidence_score: r.confidence,
            note: r.note || undefined,
            snapshot_food_name_override: r.snapshot_name_override || undefined,
          };
        }
        if (body) {
          await fetch('/api/fitness/entries', {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
          });
        }
      }
      resolvedItems = [];
      resolveInput = '';
      await loadDayData();
    } catch { /* silent */ }
    confirmLogging = false;
  }

  function cancelResolve() {
    resolvedItems = [];
    resolveError = '';
  }

  // ── Food Edit/Delete ──
  let editingFood = $state<any>(null);
  let editFoodName = $state('');
  let editFoodCal = $state('');
  let editFoodProtein = $state('');
  let editFoodCarbs = $state('');
  let editFoodFat = $state('');
  let editFoodSugar = $state('');
  let editFoodFiber = $state('');
  let editFoodUnit = $state('');
  let savingFood = $state(false);

  function openFoodEdit(food: FoodItem) {
    editingFood = food;
    editFoodName = food.name;
    editFoodCal = String(food.calories);
    editFoodProtein = '';
    editFoodCarbs = '';
    editFoodFat = '';
    editFoodSugar = '';
    editFoodFiber = '';
    editFoodUnit = food.info.split('·').pop()?.trim() || 'serving';
    // Fetch full food data for macros
    fetch(`/api/fitness/foods/${food.id}`, { credentials: 'include' })
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) {
          editFoodProtein = String(Math.round(data.protein_per_base || 0));
          editFoodCarbs = String(Math.round(data.carbs_per_base || 0));
          editFoodFat = String(Math.round(data.fat_per_base || 0));
          editFoodSugar = String(Math.round(data.sugar_per_base || 0));
          editFoodFiber = String(Math.round(data.fiber_per_base || 0));
          editFoodUnit = data.base_unit || 'serving';
        }
      })
      .catch(() => {});
  }

  function closeFoodEdit() {
    editingFood = null;
  }

  async function saveFoodEdit() {
    if (!editingFood) return;
    savingFood = true;
    try {
      await fetch(`/api/fitness/foods/${editingFood.id}`, {
        method: 'PATCH',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: editFoodName.trim(),
          calories_per_base: parseFloat(editFoodCal) || 0,
          protein_per_base: parseFloat(editFoodProtein) || 0,
          carbs_per_base: parseFloat(editFoodCarbs) || 0,
          fat_per_base: parseFloat(editFoodFat) || 0,
          sugar_per_base: parseFloat(editFoodSugar) || 0,
          fiber_per_base: parseFloat(editFoodFiber) || 0,
        }),
      });
      editingFood = null;
      await loadFoods(foodSearch || undefined);
    } catch { /* silent */ }
    savingFood = false;
  }

  async function deleteFood() {
    if (!editingFood) return;
    savingFood = true;
    try {
      await fetch(`/api/fitness/foods/${editingFood.id}`, {
        method: 'DELETE',
        credentials: 'include',
      });
      editingFood = null;
      await loadFoods(foodSearch || undefined);
    } catch { /* silent */ }
    savingFood = false;
  }

  // Reload day data when date changes
  $effect(() => {
    selectedDate; // track
    loadDayData();
    loadMealStarterFoods();
  });

  // Reload foods when search changes (debounced)
  let foodSearchTimeout: ReturnType<typeof setTimeout>;
  $effect(() => {
    const q = foodSearch;
    clearTimeout(foodSearchTimeout);
    foodSearchTimeout = setTimeout(() => loadFoods(q || undefined), q ? 300 : 0);
  });

  onMount(() => {
    loadRecentFoods();
    loadTemplates();

    const handleAssistantApplied = (event: Event) => {
      const detail = (event as CustomEvent<{ entryDate?: string | null }>).detail;
      if (!detail?.entryDate || detail.entryDate === selectedDate) {
        void loadDayData();
        void loadMealStarterFoods();
      }
    };

    window.addEventListener('fitnessassistantapplied', handleAssistantApplied);

    const viewportMeta = document.querySelector('meta[name="viewport"]');
    const originalViewport = viewportMeta?.getAttribute('content') ?? '';

    if (viewportMeta && isIosSafari()) {
      viewportMeta.setAttribute(
        'content',
        'width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover'
      );
    }

    return () => {
      window.removeEventListener('fitnessassistantapplied', handleAssistantApplied);
      if (viewportMeta && originalViewport) {
        viewportMeta.setAttribute('content', originalViewport);
      }
    };
  });

  function jumpToTemplates() {
    activeTab = 'templates';
    if (rankedTemplates.length > 0) {
      highlightTemplate = rankedTemplates[0].name;
      setTimeout(() => { highlightTemplate = ''; }, 2000);
    }
  }

  const filteredFoods = $derived(foods);

  const totals = $derived({
    calories: entries.reduce((s, e) => s + e.calories, 0),
    protein: entries.reduce((s, e) => s + e.protein, 0),
    carbs: entries.reduce((s, e) => s + e.carbs, 0),
    fat: entries.reduce((s, e) => s + e.fat, 0),
    sugar: entries.reduce((s, e) => s + e.sugar, 0),
    fiber: entries.reduce((s, e) => s + e.fiber, 0),
    count: entries.length
  });

  const caloriesRemaining = $derived(goal.calories > 0 ? Math.max(goal.calories - totals.calories, 0) : 0);
  const caloriesPercent = $derived(goal.calories > 0 ? Math.round((totals.calories / goal.calories) * 100) : 0);
  const isToday = $derived(selectedDate === todayStr);

  function entriesByMeal(meal: MealType) { return entries.filter(e => e.meal === meal); }
  function mealCalories(meal: MealType) { return entriesByMeal(meal).reduce((s, e) => s + e.calories, 0); }
  function mealProtein(meal: MealType) { return entriesByMeal(meal).reduce((s, e) => s + e.protein, 0); }

  function toggleMeal(meal: string) {
    const next = new Set(expandedMeals);
    if (next.has(meal)) next.delete(meal); else next.add(meal);
    expandedMeals = next;
  }

  function shiftDate(days: number) {
    const d = new Date(selectedDate + 'T00:00:00');
    d.setDate(d.getDate() + days);
    selectedDate = d.toISOString().split('T')[0];
  }

  function formatDate(date: string) {
    const d = new Date(date + 'T00:00:00');
    return d.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' });
  }

  // Action-oriented coaching based on progress
  function coachMessage(remaining: number, percent: number): string {
    if (percent >= 100) return 'Done for the day — you hit your goal';
    if (percent >= 90) return 'Almost done — keep it light';
    if (percent >= 75) return 'Finish strong — ' + remaining.toLocaleString() + ' cal left';
    if (percent >= 50) return 'You\'ve got room for a solid meal';
    if (percent >= 25) return 'On track — plan your next meal';
    if (percent > 0) return 'Just getting started — ' + remaining.toLocaleString() + ' cal to work with';
    return 'Start logging to see your progress';
  }

  // Coaching focus — what the user needs most right now
  type CoachFocus = 'protein' | 'low_carb' | 'low_fat' | 'light' | 'balanced';

  function getCoachFocus(t: typeof totals, g: typeof goal, calLeft: number): CoachFocus {
    const proteinPct = t.protein / g.protein;
    const carbsPct = t.carbs / g.carbs;
    const fatPct = t.fat / g.fat;
    if (calLeft < 300) return 'light';
    if (proteinPct < 0.7) return 'protein';
    if (carbsPct > 0.8 && proteinPct < 0.8) return 'low_carb';
    if (fatPct > 0.8) return 'low_fat';
    return 'balanced';
  }

  const coachFocus = $derived(getCoachFocus(totals, goal, caloriesRemaining));

  // "Best next move" — realistic meal suggestions
  function bestNextMove(t: typeof totals, g: typeof goal, calRemaining: number): string {
    if (calRemaining <= 0) return '';

    const proteinPct = t.protein / g.protein;
    const carbsPct = t.carbs / g.carbs;
    const fatPct = t.fat / g.fat;
    const proteinLeft = Math.max(g.protein - t.protein, 0);

    // Protein-focused — use realistic meal combos
    if (proteinPct < 0.4 && proteinLeft > 40) {
      const lo = Math.round(proteinLeft * 0.3);
      const hi = Math.round(proteinLeft * 0.45);
      return `Best next: ~${lo}–${hi}g protein (chicken + rice, 3 eggs, or a shake)`;
    }
    if (proteinPct < 0.6 && proteinLeft > 25) {
      const lo = Math.round(proteinLeft * 0.35);
      const hi = Math.round(proteinLeft * 0.5);
      return `Best next: ~${lo}–${hi}g protein (chicken, Greek yogurt, or protein shake)`;
    }
    if (proteinPct < 0.8 && proteinLeft > 10) {
      return `Best next: ~${Math.round(proteinLeft * 0.6)}–${proteinLeft}g protein (eggs, yogurt, or tuna)`;
    }

    // Carbs running high + still need protein
    if (carbsPct > 0.8 && proteinPct < 0.75) {
      return 'Best next: skip the carbs — chicken salad, eggs, or a protein shake';
    }

    // Fat running high
    if (fatPct > 0.85) {
      return 'Best next: lean protein + rice or sweet potato — skip the oils';
    }
    if (fatPct > 0.7 && carbsPct < 0.5) {
      return 'Best next: oatmeal, rice bowl, or pasta with grilled chicken';
    }

    // Low calories remaining
    if (calRemaining < 200) {
      return 'Best next: something light — yogurt, fruit, or veggies';
    }
    if (calRemaining < 400) {
      return 'Best next: small meal — salad with chicken, or a shake with fruit';
    }

    // Everything balanced
    return 'Best next: balanced plate — protein, carbs, and veggies';
  }

  // Macro guidance — considers both target gap and calories budget
  function macroInstruction(macro: 'protein' | 'carbs' | 'fat', current: number, target: number, calLeft: number): string {
    if (target <= 0) return 'Set target in goals';
    const pct = Math.round((current / target) * 100);
    if (pct >= 100) return 'On target';

    const budgetTight = calLeft < 400;

    if (macro === 'protein') {
      if (pct < 50 && !budgetTight) return 'Prioritize protein';
      if (pct < 50 && budgetTight) return 'Add lean protein';
      if (pct < 80) return 'Add protein';
      return 'Almost there';
    }
    if (macro === 'carbs') {
      if (pct >= 85) return 'Ease off carbs';
      if (pct >= 70) return 'Watch carbs';
      return 'Carbs on track';
    }
    // fat
    if (pct >= 85) return 'Keep fats minimal';
    if (pct >= 70) return 'Keep fats light';
    return 'Fats on track';
  }

  function macroLeft(current: number, target: number): string {
    if (target <= 0) return 'Set goal';
    const left = Math.max(target - current, 0);
    if (left === 0) return '';
    return `${left}g left`;
  }

  function nutrientPercent(current: number, target: number): number {
    if (target <= 0) return 0;
    return Math.min(Math.round((current / target) * 100), 100);
  }

  function extraInstruction(kind: 'sugar' | 'fiber', current: number, target: number): string {
    if (target <= 0) return 'Set target in goals';
    const pct = nutrientPercent(current, target);
    if (kind === 'sugar') {
      if (pct >= 100) return 'Over target';
      if (pct >= 80) return 'Close to limit';
      return 'Within target';
    }

    if (pct >= 100) return 'Goal hit';
    if (pct >= 75) return 'Almost there';
    if (pct >= 35) return 'Build fiber';
    return 'Add fiber foods';
  }

  // Meal weight label — contextual per meal type
  function mealWeight(mealCal: number, dailyGoal: number, meal: MealType): string {
    if (mealCal === 0) return '';
    const pct = Math.round((mealCal / dailyGoal) * 100);

    if (meal === 'snack') {
      // Snacks: bias toward Light/Snack
      if (pct >= 25) return 'Heavy';
      if (pct >= 12) return 'Moderate';
      return 'Light';
    }
    if (meal === 'breakfast') {
      // Breakfast: cap at Moderate
      if (pct >= 30) return 'Moderate';
      if (pct >= 12) return 'Light';
      return 'Snack';
    }
    // Lunch / Dinner: normal scale
    if (pct >= 35) return 'Heavy';
    if (pct >= 20) return 'Moderate';
    if (pct >= 8) return 'Light';
    return 'Snack';
  }

  function mealEmptyCopy(meal: MealType): string {
    if (meal === 'breakfast') return 'Start light or protein-first';
    if (meal === 'lunch') return 'Nothing logged for midday yet';
    if (meal === 'dinner') return 'Dinner is still open';
    return 'Leave room for a snack or dessert';
  }

  // Template scoring — decisive ranking aligned with coaching focus
  function templateScore(tpl: Template, t: typeof totals, g: typeof goal, calLeft: number, focus: CoachFocus): number {
    let score = 0;
    const hour = new Date().getHours();
    const isProteinRich = /protein|chicken|egg|salmon/i.test(tpl.name);
    const isCarbHeavy = /oatmeal|rice|pasta/i.test(tpl.name);

    // ── Calorie fit (highest weight) ──
    if (calLeft > 0) {
      if (tpl.calories <= calLeft) {
        const ratio = tpl.calories / calLeft;
        // Perfect fit: within ±15%
        if (ratio >= 0.85 && ratio <= 1.0) score += 50;
        // Good fit: within ±30%
        else if (ratio >= 0.7) score += 35;
        // Usable: under budget but not close
        else if (ratio >= 0.4) score += 15;
      } else {
        // Over remaining — penalize harder
        const overBy = (tpl.calories - calLeft) / calLeft;
        score -= overBy > 0.3 ? 30 : 15;
      }
    }

    // ── Coaching alignment (reinforce "Best next" direction) ──
    if (focus === 'protein' && isProteinRich) score += 35;
    if (focus === 'protein' && !isProteinRich) score -= 5;
    if (focus === 'low_carb' && isCarbHeavy) score -= 20;
    if (focus === 'low_carb' && isProteinRich) score += 20;
    if (focus === 'low_fat' && isProteinRich) score += 15;
    if (focus === 'light' && tpl.calories < 350) score += 20;
    if (focus === 'light' && tpl.calories > 500) score -= 20;

    // ── Time-of-day ──
    if (tpl.meal === 'breakfast' && hour >= 6 && hour < 11) score += 15;
    if (tpl.meal === 'lunch' && hour >= 11 && hour < 15) score += 15;
    if (tpl.meal === 'dinner' && hour >= 17 && hour < 21) score += 15;
    if (tpl.meal === 'snack' && hour >= 14 && hour < 17) score += 10;

    // ── Macro penalties ──
    const carbsPct = t.carbs / g.carbs;
    const fatPct = t.fat / g.fat;
    if (carbsPct > 0.85 && isCarbHeavy) score -= 15;
    if (fatPct > 0.85) score -= 5;

    return score;
  }

  // Sorted templates by score (descending)
  const rankedTemplates = $derived(
    [...templates]
      .map(tpl => ({ tpl, score: templateScore(tpl, totals, goal, caloriesRemaining, coachFocus) }))
      .sort((a, b) => b.score - a.score)
      .map(item => item.tpl)
  );

  // Template hints — selective, max 3 total, top-ranked only
  function templateHints(ranked: Template[], t: typeof totals, g: typeof goal, calLeft: number): Map<string, string> {
    const hints = new Map<string, string>();
    const hour = new Date().getHours();
    const proteinPct = t.protein / g.protein;
    const proteinPhrases = ['High protein option', 'Great for protein', 'Helps close your protein gap'];
    let proteinIdx = 0;
    const MAX_HINTS = 3;

    // Only consider top-ranked templates for hints
    const candidates = ranked.slice(0, Math.min(ranked.length, 5));

    for (const tpl of candidates) {
      if (hints.size >= MAX_HINTS) break;

      // Calorie fit — tight ±15%
      if (calLeft > 0 && tpl.calories <= calLeft) {
        const ratio = tpl.calories / calLeft;
        if (ratio >= 0.85 && ratio <= 1.0) {
          hints.set(tpl.name, 'Fits your remaining calories');
          continue;
        }
      }

      // Protein hint — varied phrasing, max 2
      const isProteinRich = /protein|chicken|egg|salmon/i.test(tpl.name);
      if (isProteinRich && proteinPct < 0.7 && proteinIdx < 2) {
        hints.set(tpl.name, proteinPhrases[proteinIdx]);
        proteinIdx++;
        continue;
      }

      // Time-of-day — max 1
      if (!Array.from(hints.values()).some(h => h.startsWith('Good '))) {
        if (tpl.meal === 'breakfast' && hour >= 6 && hour < 11) { hints.set(tpl.name, 'Good for this morning'); continue; }
        if (tpl.meal === 'lunch' && hour >= 11 && hour < 15) { hints.set(tpl.name, 'Good for lunch right now'); continue; }
        if (tpl.meal === 'dinner' && hour >= 17 && hour < 21) { hints.set(tpl.name, 'Good dinner choice'); continue; }
        if (tpl.meal === 'snack' && hour >= 14 && hour < 17) { hints.set(tpl.name, 'Good afternoon pick-me-up'); continue; }
      }
    }

    return hints;
  }

  const templateHintMap = $derived(templateHints(rankedTemplates, totals, goal, caloriesRemaining));

  const mealTypes: MealType[] = ['breakfast', 'lunch', 'dinner', 'snack'];
  const starterFoods = $derived(
    mealStarterFoods[starterMeal].length > 0
      ? mealStarterFoods[starterMeal]
      : recentFoods.slice(0, 6)
  );
</script>

<div class="fitness-page">
  <div class="fitness-shell">
    <header class="fitness-header">
      <div class="fitness-heading">
        <h1>Nutrition</h1>
        <p class="fitness-subcopy">
          Daily intake, food memory, and quick meal decisions in one quieter workspace.
        </p>
        <div class="fitness-mobile-note">Daily intake and food memory.</div>
      </div>

      <div class="fitness-header-side">
        <div class="date-nav">
          <button class="btn-icon" onclick={() => shiftDate(-1)} aria-label="Previous day">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
          </button>
          <label class="date-display">
            <span class="date-display-text">{#if isToday}Today{:else}{formatDate(selectedDate)}{/if}</span>
            <input type="date" class="date-display-input" bind:value={selectedDate} aria-label="Choose day" />
          </label>
          <button class="btn-icon" onclick={() => shiftDate(1)} aria-label="Next day">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
          </button>
          {#if !isToday}
            <button class="today-btn" onclick={() => selectedDate = todayStr}>Today</button>
          {/if}
        </div>
      </div>
    </header>

    <div class="top-tabs">
      <button class="top-tab" class:active={activeTab === 'log'} onclick={() => activeTab = 'log'}>Day log</button>
      <button class="top-tab" class:active={activeTab === 'foods'} onclick={() => activeTab = 'foods'}>Food library</button>
      <button class="top-tab" class:active={activeTab === 'templates'} onclick={() => activeTab = 'templates'}>Quick meals</button>
    </div>

    {#if activeTab === 'log'}
      <div class="fitness-log-grid">
        <aside class="fitness-rail">
          <section class="rail-panel calorie-card">
            <div class="panel-kicker">Daily target</div>
            <div class="calorie-eaten">
              <span class="calorie-number">{totals.calories.toLocaleString()}</span>
              <span class="calorie-of">/ {goal.calories.toLocaleString()}</span>
            </div>
            <div class="calorie-meta-row">
              <span class="calorie-meta-pill">{totals.count} entr{totals.count === 1 ? 'y' : 'ies'}</span>
              <span class="calorie-meta-pill">{caloriesRemaining.toLocaleString()} left</span>
            </div>
            <div class="progress-bar">
              <div class="progress-fill" style="width:{Math.min(caloriesPercent, 100)}%"></div>
            </div>
            <div class="calorie-coach">{coachMessage(caloriesRemaining, caloriesPercent)}</div>
            {#if caloriesRemaining > 0}
              {@const hint = bestNextMove(totals, goal, caloriesRemaining)}
              {#if hint}
                <button class="calorie-next" onclick={jumpToTemplates}>{hint} <span class="next-arrow">→</span></button>
              {/if}
            {/if}
          </section>

          <section class="rail-panel macro-panel">
            <div class="panel-kicker">Nutrition balance</div>
            <div class="macro-row">
              <div class="macro-item">
                <div class="macro-card-head">
                  <span class="macro-name">Protein</span>
                  <span class="macro-left">{macroLeft(totals.protein, goal.protein)}</span>
                </div>
                <div class="macro-bar-wrap">
                  <div class="macro-bar-fill protein" style="width:{Math.min(totals.protein / goal.protein * 100, 100)}%"></div>
                </div>
                <div class="macro-label">
                  <span class="macro-current">{totals.protein}g</span>
                  <span class="macro-target">/ {goal.protein}g</span>
                </div>
                <div class="macro-guidance">
                  <div class="macro-instruction">{macroInstruction('protein', totals.protein, goal.protein, caloriesRemaining)}</div>
                </div>
              </div>
              <div class="macro-item">
                <div class="macro-card-head">
                  <span class="macro-name">Carbs</span>
                  <span class="macro-left">{macroLeft(totals.carbs, goal.carbs)}</span>
                </div>
                <div class="macro-bar-wrap">
                  <div class="macro-bar-fill carbs" style="width:{Math.min(totals.carbs / goal.carbs * 100, 100)}%"></div>
                </div>
                <div class="macro-label">
                  <span class="macro-current">{totals.carbs}g</span>
                  <span class="macro-target">/ {goal.carbs}g</span>
                </div>
                <div class="macro-guidance">
                  <div class="macro-instruction">{macroInstruction('carbs', totals.carbs, goal.carbs, caloriesRemaining)}</div>
                </div>
              </div>
              <div class="macro-item">
                <div class="macro-card-head">
                  <span class="macro-name">Fat</span>
                  <span class="macro-left">{macroLeft(totals.fat, goal.fat)}</span>
                </div>
                <div class="macro-bar-wrap">
                  <div class="macro-bar-fill fat" style="width:{Math.min(totals.fat / goal.fat * 100, 100)}%"></div>
                </div>
                <div class="macro-label">
                  <span class="macro-current">{totals.fat}g</span>
                  <span class="macro-target">/ {goal.fat}g</span>
                </div>
                <div class="macro-guidance">
                  <div class="macro-instruction">{macroInstruction('fat', totals.fat, goal.fat, caloriesRemaining)}</div>
                </div>
              </div>
            </div>
            <div class="extra-nutrients-head">
              <span>Tracked extras</span>
            </div>
            <div class="extra-nutrients-row">
              <div class="macro-item extra-item sugar-item">
                <div class="macro-card-head">
                  <span class="macro-name">Sugar</span>
                  <span class="macro-left">{macroLeft(totals.sugar, goal.sugar)}</span>
                </div>
                <div class="macro-bar-wrap">
                  <div class="macro-bar-fill sugar" style="width:{nutrientPercent(totals.sugar, goal.sugar)}%"></div>
                </div>
                <div class="macro-label">
                  <span class="macro-current">{totals.sugar}g</span>
                  <span class="macro-target">{goal.sugar > 0 ? `/ ${goal.sugar}g` : '/ tracking only'}</span>
                </div>
                <div class="macro-guidance">
                  <div class="macro-instruction">{extraInstruction('sugar', totals.sugar, goal.sugar)}</div>
                </div>
              </div>
              <div class="macro-item extra-item fiber-item">
                <div class="macro-card-head">
                  <span class="macro-name">Fiber</span>
                  <span class="macro-left">{macroLeft(totals.fiber, goal.fiber)}</span>
                </div>
                <div class="macro-bar-wrap">
                  <div class="macro-bar-fill fiber" style="width:{nutrientPercent(totals.fiber, goal.fiber)}%"></div>
                </div>
                <div class="macro-label">
                  <span class="macro-current">{totals.fiber}g</span>
                  <span class="macro-target">{goal.fiber > 0 ? `/ ${goal.fiber}g` : '/ tracking only'}</span>
                </div>
                <div class="macro-guidance">
                  <div class="macro-instruction">{extraInstruction('fiber', totals.fiber, goal.fiber)}</div>
                </div>
              </div>
            </div>
          </section>

        </aside>

        <main class="fitness-workspace">
          {#if totals.count === 0 && starterFoods.length > 0}
            <section class="starter-panel">
              <div class="starter-header">
                <div>
                  <div class="panel-kicker">Start with recent</div>
                  <h3>Use something you already log for {starterMeal}.</h3>
                  <p>These suggestions are ranked from your recent meal history, with your most repeated foods first.</p>
                </div>
                <div class="starter-meals">
                  {#each mealTypes as meal}
                    <button class="starter-meal-btn" class:active={starterMeal === meal} onclick={() => starterMeal = meal}>
                      {meal}
                    </button>
                  {/each}
                </div>
              </div>

              <div class="starter-grid">
                {#each starterFoods as food}
                  <button class="starter-food" onclick={() => quickAddRecentFood(food, starterMeal)}>
                    <div class="starter-food-name">{food.name}</div>
                    <div class="starter-food-meta">{food.info} · {food.calories} cal</div>
                    <div class="starter-food-action">Add to {starterMeal}</div>
                  </button>
                {/each}
              </div>
            </section>
          {/if}

          <div class="meals-divider">
            <span class="meals-label">Meals</span>
            <span class="meals-count">{totals.count} entries</span>
          </div>

          {#each mealTypes as meal, i}
            {@const mealEntries = entriesByMeal(meal)}
            {@const mCal = mealCalories(meal)}
            {@const mPro = mealProtein(meal)}
            {@const expanded = expandedMeals.has(meal)}
            {@const weight = mealWeight(mCal, goal.calories, meal)}
            {@const mealPct = mCal > 0 ? Math.round((mCal / goal.calories) * 100) : 0}

            <section class="meal-section">
              <button class="meal-header" onclick={() => toggleMeal(meal)}>
                <div class="meal-number" class:has-entries={mealEntries.length > 0}>{i + 1}</div>
                <div class="meal-info">
                  <div class="meal-top">
                    <span class="meal-name">{meal}</span>
                    {#if weight}
                      <span class="meal-weight {weight.toLowerCase()}">{weight}</span>
                    {/if}
                  </div>
                  {#if mCal > 0}
                    <span class="meal-stats">{Math.round(mCal)} cal · {mealPct}% of daily · {Math.round(mPro)}g protein</span>
                  {:else}
                    <span class="meal-stats empty">{mealEmptyCopy(meal)}</span>
                  {/if}
                </div>
                <svg class="meal-chevron" class:expanded viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
              </button>

              {#if expanded}
                <div class="meal-entries">
                  {#if mealEntries.length > 0}
                    {#each mealEntries as entry}
                      <div class="entry-wrap">
                        <!-- svelte-ignore a11y_no_static_element_interactions -->
                        <div class="entry-row" onclick={() => toggleEntry(entry.id)}>
                          <div class="entry-info">
                            <div class="entry-name">
                              {entry.name}
                              {#if entry.method === 'ai_plate' || entry.method === 'ai_label'}
                                <span class="entry-badge ai">AI</span>
                              {/if}
                              {#if entry.method === 'quick_add'}
                                <span class="entry-badge quick">quick</span>
                              {/if}
                            </div>
                            <div class="entry-serving">{entry.serving}</div>
                            {#if entry.note}
                              <div class="entry-note">{entry.note}</div>
                            {/if}
                          </div>
                          <div class="entry-cals">
                            <span class="entry-cal-value">{entry.calories}</span>
                            <span class="entry-cal-label">cal</span>
                          </div>
                        </div>
                        {#if expandedEntry === entry.id}
                          <div class="entry-actions">
                            <div class="entry-qty-control">
                              <input
                                type="number"
                                class="entry-qty-input"
                                bind:value={editQtyValue}
                                onkeydown={(e) => { if (e.key === 'Enter') updateEntryQty(entry.id); }}
                                step="0.5"
                                min="0.1"
                              />
                              <span class="entry-qty-unit">{entry.rawUnit}</span>
                              <button class="entry-qty-save" onclick={() => updateEntryQty(entry.id)}>Save</button>
                            </div>
                            <button class="entry-delete-btn" onclick={() => deleteEntry(entry.id)}>
                              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
                              Delete
                            </button>
                          </div>
                        {/if}
                      </div>
                    {/each}
                  {/if}

                  <button class="add-food-btn" onclick={openAssistant}>
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
                    Add to {meal}
                  </button>
                </div>
              {/if}
            </section>
          {/each}
        </main>
      </div>
    {:else if activeTab === 'foods'}
      <section class="library-stage">
        <div class="list-stage-header">
          <div>
            <div class="panel-kicker">Food library</div>
            <h2>Search, edit, and curate your ingredients.</h2>
          </div>
          <div class="foods-nudge">
            Looking for a quick option? <button class="nudge-link" onclick={() => activeTab = 'templates'}>Try Quick Meals →</button>
          </div>
        </div>

        <div class="list-header">
          <div class="search-wrap">
            <svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
            <input type="text" class="search-input" placeholder="Search food library..." bind:value={foodSearch} />
            {#if foodSearch}
              <button class="search-clear" onclick={() => foodSearch = ''}>
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
              </button>
            {/if}
          </div>
        </div>

        <div class="list-card">
          {#each filteredFoods as food (food.id || `${food.name}-${food.info}-${food.calories}`)}
            <!-- svelte-ignore a11y_no_static_element_interactions -->
            <div class="list-row" onclick={() => openFoodEdit(food)}>
              <div class="list-row-info">
                <div class="list-row-name">
                  {food.name}
                  {#if food.favorite}
                    <svg class="fav-icon" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
                  {/if}
                </div>
                <div class="list-row-meta">{food.info}</div>
              </div>
              <div class="list-row-right">
                <span class="list-row-value">{food.calories} cal</span>
                <svg class="list-row-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
              </div>
            </div>
          {/each}
          {#if filteredFoods.length === 0}
            <div class="empty-state empty-state-rich">
              <div class="empty-state-kicker">Library is quiet</div>
              <h3>{foodSearch ? 'No foods matched your search' : 'No foods in your library yet'}</h3>
              <p>{foodSearch ? `Try a broader term than "${foodSearch}".` : 'Create foods or keep logging meals and the workspace will start building its own memory.'}</p>
            </div>
          {/if}
        </div>
      </section>
    {:else if activeTab === 'templates'}
      <section class="library-stage">
        <div class="list-stage-header">
          <div>
            <div class="panel-kicker">Quick meals</div>
            <h2>Reusable meals ranked against what your day still needs.</h2>
          </div>
          <div class="list-count">{#if templatesLoading}Loading...{:else if templates.length > 0}{templates.length} go-to meals · ranked for you{/if}</div>
        </div>

        <div class="list-card">
          {#if rankedTemplates.length > 0}
            {#each rankedTemplates as tpl}
              {@const hint = templateHintMap.get(tpl.name) || ''}
              <div class="list-row" class:highlighted={highlightTemplate === tpl.name}>
                <div class="template-badge">{tpl.meal.charAt(0).toUpperCase()}</div>
                <div class="list-row-info">
                  <div class="list-row-name">{tpl.name}</div>
                  <div class="list-row-meta"><span class="template-meal-label">{tpl.meal}</span> · {tpl.calories} cal</div>
                  <div class="list-row-sub">{tpl.items} items</div>
                  {#if hint}
                    <div class="template-hint">{hint}</div>
                  {/if}
                </div>
                <div class="list-row-right">
                  <button class="log-btn" onclick={() => logTemplate(tpl)}>Log meal</button>
                  <svg class="list-row-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
                </div>
              </div>
            {/each}
          {:else}
            <div class="empty-state empty-state-rich">
              <div class="empty-state-kicker">Quick meals</div>
              <h3>No reusable meals yet</h3>
              <p>Once you save a go-to meal, this view can recommend the best fit for the rest of your day.</p>
            </div>
          {/if}
        </div>
      </section>
    {/if}
  </div>
</div>

<button class="fab assistant-fab" aria-label="Open fitness assistant" onclick={openAssistant}>
  <span class="assistant-fab-mark">
    <svg class="fab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.15"><path d="M8 10.5h8"/><path d="M8 14.5h5"/><path d="M12 3c4.97 0 9 3.358 9 7.5 0 1.944-.887 3.715-2.344 5.047-.392.36-.656.845-.735 1.372L17.5 20l-3.234-1.212a2.483 2.483 0 0 0-1.59 0L9.5 20l-.42-3.081a2.301 2.301 0 0 0-.735-1.372C6.887 14.215 6 12.444 6 10.5 6 6.358 10.03 3 15 3"/></svg>
  </span>
  <span class="assistant-fab-copy">
    <span class="assistant-fab-title">Ask AI</span>
    <span class="assistant-fab-sub">Log food or photo</span>
  </span>
</button>

<!-- Food edit modal -->
{#if editingFood}
  <!-- svelte-ignore a11y_no_static_element_interactions -->
  <div class="resolve-overlay" onclick={closeFoodEdit}>
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <div class="resolve-modal" onclick={(e) => e.stopPropagation()}>
      <div class="resolve-modal-header">
        <div class="resolve-modal-title">Edit Food</div>
        <button class="resolve-modal-close" onclick={closeFoodEdit}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
        </button>
      </div>
      <div class="resolve-modal-body">
        <div class="food-edit-field">
          <label class="food-edit-label">Name</label>
          <input class="food-edit-input" type="text" bind:value={editFoodName} />
        </div>
        <div class="food-edit-row">
          <div class="food-edit-field">
            <label class="food-edit-label">Calories</label>
            <input class="food-edit-input" type="number" bind:value={editFoodCal} />
          </div>
          <div class="food-edit-field">
            <label class="food-edit-label">Protein (g)</label>
            <input class="food-edit-input" type="number" bind:value={editFoodProtein} />
          </div>
        </div>
        <div class="food-edit-row">
          <div class="food-edit-field">
            <label class="food-edit-label">Carbs (g)</label>
            <input class="food-edit-input" type="number" bind:value={editFoodCarbs} />
          </div>
          <div class="food-edit-field">
            <label class="food-edit-label">Fat (g)</label>
            <input class="food-edit-input" type="number" bind:value={editFoodFat} />
          </div>
        </div>
        <div class="food-edit-row">
          <div class="food-edit-field">
            <label class="food-edit-label">Sugar (g)</label>
            <input class="food-edit-input" type="number" bind:value={editFoodSugar} />
          </div>
          <div class="food-edit-field">
            <label class="food-edit-label">Fiber (g)</label>
            <input class="food-edit-input" type="number" bind:value={editFoodFiber} />
          </div>
        </div>
        <div class="food-edit-unit">Per 1 {editFoodUnit}</div>
      </div>
      <div class="resolve-modal-footer">
        <button class="entry-delete-btn" onclick={deleteFood} disabled={savingFood}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
          Delete
        </button>
        <div class="resolve-footer-actions">
          <button class="btn-secondary" onclick={closeFoodEdit}>Cancel</button>
          <button class="btn-primary" onclick={saveFoodEdit} disabled={savingFood}>
            {savingFood ? 'Saving...' : 'Save'}
          </button>
        </div>
      </div>
    </div>
  </div>
{/if}

<!-- Resolve confirmation modal -->
{#if resolvedItems.length > 0}
  <!-- svelte-ignore a11y_no_static_element_interactions -->
  <div class="resolve-overlay" onclick={cancelResolve}>
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <div class="resolve-modal" onclick={(e) => e.stopPropagation()}>
      <div class="resolve-modal-header">
        <div class="resolve-modal-title">
          {resolvedItems.length === 1 ? 'Confirm entry' : `Confirm ${resolvedItems.length} items`}
        </div>
        <button class="resolve-modal-close" onclick={cancelResolve}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
        </button>
      </div>

      <div class="resolve-modal-body">
        {#each resolvedItems as item, idx}
          <div class="resolve-item" class:resolve-item-border={idx > 0}>
            <div class="resolve-item-top">
              <div class="resolve-item-info">
                <div class="resolve-food-name">{item.name}</div>
                <div class="resolve-food-detail">{item.calories} cal · {item.protein}g P · {item.carbs}g C · {item.fat}g F</div>
              </div>
              {#if resolvedItems.length > 1}
                <button class="resolve-item-remove" onclick={() => removeItem(idx)} aria-label="Remove">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
                </button>
              {/if}
            </div>
            <div class="resolve-qty-row">
              <button class="resolve-qty-btn" onclick={() => updateItemQty(idx, item.qty - 0.5)} disabled={item.qty <= 0.5}>−</button>
              <span class="resolve-qty-value">{item.qty} {item.unit}</span>
              <button class="resolve-qty-btn" onclick={() => updateItemQty(idx, item.qty + 0.5)}>+</button>
            </div>
          </div>
        {/each}

        <div class="resolve-meal-row">
          <span class="resolve-meal-label">Meal</span>
          <select class="resolve-meal-select" bind:value={resolveMeal}>
            <option value="breakfast">Breakfast</option>
            <option value="lunch">Lunch</option>
            <option value="dinner">Dinner</option>
            <option value="snack">Snack</option>
          </select>
        </div>

        {#if resolvedItems.some(i => i.result.resolution_type === 'ai_estimated')}
          <div class="resolve-note">Some items estimated by AI — values are approximate</div>
        {/if}
      </div>

      <div class="resolve-modal-footer">
        <div class="resolve-total">{resolveTotalCal} cal total</div>
        <div class="resolve-footer-actions">
          <button class="btn-secondary" onclick={cancelResolve}>Cancel</button>
          <button class="btn-primary" onclick={confirmResolve} disabled={confirmLogging}>
            {confirmLogging ? 'Logging...' : resolvedItems.length === 1 ? 'Log entry' : `Log ${resolvedItems.length} entries`}
          </button>
        </div>
      </div>
    </div>
  </div>
{/if}

<style>
  :global(:root) {
    --fitness-bg: #efe6d8;
    --fitness-bg-soft: #f7f1e8;
    --fitness-paper: rgba(255, 251, 246, 0.82);
    --fitness-paper-strong: rgba(255, 252, 248, 0.94);
    --fitness-line: rgba(44, 31, 19, 0.09);
    --fitness-line-strong: rgba(44, 31, 19, 0.16);
    --fitness-text: #1f1710;
    --fitness-muted: #6d5d4c;
    --fitness-soft: #8f7f6d;
    --fitness-accent: #2f6a52;
    --fitness-accent-soft: rgba(47, 106, 82, 0.12);
    --fitness-gold: #c88932;
  }

  .fitness-page {
    min-height: calc(100vh - 56px);
    background:
      radial-gradient(circle at top left, rgba(255,255,255,0.7), transparent 30%),
      linear-gradient(180deg, var(--fitness-bg-soft) 0%, var(--fitness-bg) 100%);
  }

  .fitness-shell {
    max-width: 1440px;
    margin: 0 auto;
    padding: 22px 28px 120px;
    color: var(--fitness-text);
  }

  .fitness-header {
    display: flex;
    justify-content: space-between;
    gap: 24px;
    align-items: end;
    margin-bottom: 14px;
  }

  .fitness-heading {
    max-width: 640px;
  }

  .panel-kicker {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fitness-soft);
  }

  .fitness-heading h1 {
    margin: 6px 0 6px;
    font-size: clamp(2.6rem, 5vw, 4.6rem);
    line-height: 0.92;
    letter-spacing: -0.07em;
  }

  .fitness-heading p {
    margin: 0;
    max-width: 560px;
    color: var(--fitness-muted);
    font-size: 0.96rem;
    line-height: 1.5;
  }

  .fitness-mobile-note {
    display: none;
  }

  .fitness-header-side {
    display: grid;
    gap: 10px;
    justify-items: end;
  }

  .fitness-date-readout {
    font-size: 1.1rem;
    line-height: 1;
    letter-spacing: -0.04em;
    color: var(--fitness-text);
    padding: 10px 14px;
    border-radius: 999px;
    background: rgba(255,255,255,0.56);
    border: 1px solid var(--fitness-line);
  }

  .top-tabs {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(255,255,255,0.48);
    border: 1px solid var(--fitness-line);
    backdrop-filter: blur(12px);
    margin-bottom: 18px;
  }

  .top-tab {
    padding: 10px 16px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--fitness-muted);
    cursor: pointer;
    font-size: 0.94rem;
    font-weight: 600;
    transition: all 180ms ease;
    font-family: var(--font);
  }

  .top-tab:hover {
    color: var(--fitness-text);
  }

  .top-tab.active {
    background: var(--fitness-paper-strong);
    color: var(--fitness-text);
    box-shadow: 0 10px 24px rgba(33, 22, 14, 0.08);
  }

  .fitness-log-grid {
    display: grid;
    grid-template-columns: 356px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
  }

  .fitness-rail {
    display: grid;
    gap: 14px;
    position: sticky;
    top: 78px;
  }

  .rail-panel,
  .composer-panel,
  .meal-section,
  .list-card,
  .fab-sheet,
  .resolve-modal {
    background: var(--fitness-paper);
    border: 1px solid var(--fitness-line);
    box-shadow: 0 16px 38px rgba(39, 28, 18, 0.07);
    backdrop-filter: blur(16px);
  }

  .rail-panel,
  .composer-panel,
  .list-card {
    border-radius: 28px;
  }

  .rail-panel {
    padding: 20px 20px 22px;
  }

  .calorie-card {
    background: linear-gradient(180deg, rgba(248, 245, 239, 0.98), rgba(240, 247, 241, 0.88));
    border-color: rgba(47, 106, 82, 0.14);
  }

  .macro-panel {
    background: linear-gradient(180deg, rgba(255,251,246,0.92), rgba(248,242,233,0.86));
  }

  .meals-summary {
    background: linear-gradient(180deg, rgba(255,250,245,0.92), rgba(248,243,235,0.82));
  }

  .date-nav {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .date-display {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 36px;
    min-width: 176px;
    padding: 0 16px;
    border-radius: 12px;
    border: 1px solid var(--fitness-line);
    background: rgba(255,255,255,0.72);
    color: var(--fitness-text);
    font-size: 0.92rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    overflow: hidden;
    cursor: pointer;
  }

  .date-display-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .date-display-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }

  .btn-icon {
    width: 36px;
    height: 36px;
    border-radius: 12px;
    border: 1px solid var(--fitness-line);
    background: rgba(255,255,255,0.62);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--fitness-muted);
    transition: all 160ms ease;
    flex-shrink: 0;
  }

  .btn-icon:hover {
    color: var(--fitness-text);
    background: rgba(255,255,255,0.9);
  }

  .btn-icon svg {
    width: 16px;
    height: 16px;
  }

  .date-input,
  .resolve-input,
  .search-input,
  .food-edit-input,
  .entry-qty-input,
  .resolve-meal-select {
    border: 1px solid var(--fitness-line);
    background: rgba(255,255,255,0.88);
    color: var(--fitness-text);
  }

  .today-btn,
  .entry-qty-save,
  .resolve-submit,
  .btn-primary,
  .log-btn {
    background: var(--fitness-accent);
    color: #f9f6f1;
    border: none;
  }

  .today-btn {
    padding: 8px 14px;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
    font-family: var(--font);
  }

  .calorie-eaten {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 10px 0 8px;
  }

  .calorie-meta-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 12px;
  }

  .calorie-meta-pill {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 0 9px;
    border-radius: 999px;
    background: rgba(255,255,255,0.56);
    border: 1px solid rgba(69, 53, 39, 0.08);
    color: var(--fitness-muted);
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.01em;
  }

  .calorie-number {
    font-size: clamp(2.4rem, 4vw, 3.4rem);
    font-weight: 600;
    letter-spacing: -0.08em;
    line-height: 0.92;
    color: var(--fitness-text);
    font-family: var(--mono);
  }

  .calorie-of {
    color: var(--fitness-soft);
    font-size: 0.96rem;
    font-family: var(--mono);
  }

  .progress-bar {
    height: 9px;
    background: rgba(69, 53, 39, 0.1);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: 10px;
  }

  .progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #346c56 0%, #4d8f73 100%);
    border-radius: inherit;
    transition: width 500ms ease;
  }

  .calorie-coach {
    font-size: 0.94rem;
    line-height: 1.42;
    color: var(--fitness-text);
  }

  .calorie-next,
  .nudge-link {
    margin-top: 10px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--fitness-accent);
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-size: 0.92rem;
    font-weight: 600;
    font-family: var(--font);
    text-align: left;
  }

  .next-arrow {
    transition: transform 160ms ease;
  }

  .calorie-next:hover .next-arrow,
  .nudge-link:hover {
    transform: translateX(2px);
  }

  .macro-panel .macro-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    margin-top: 14px;
  }

  .macro-item {
    padding: 14px 12px 13px;
    border: 1px solid rgba(69, 53, 39, 0.08);
    border-radius: 18px;
    background: rgba(255, 252, 248, 0.72);
    display: grid;
    gap: 0;
    align-content: start;
  }

  .macro-card-head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    margin-bottom: 8px;
  }

  .macro-bar-wrap {
    height: 6px;
    border-radius: 999px;
    background: rgba(69, 53, 39, 0.09);
    overflow: hidden;
    margin-bottom: 11px;
  }

  .macro-bar-fill { height: 100%; border-radius: inherit; transition: width 500ms ease; }
  .macro-bar-fill.protein { background: #346c56; }
  .macro-bar-fill.carbs { background: #c88932; }
  .macro-bar-fill.fat { background: #8f5d42; }
  .macro-bar-fill.sugar { background: #b77a38; }
  .macro-bar-fill.fiber { background: #4c7e5f; }

  .macro-label {
    display: flex;
    align-items: baseline;
    gap: 4px;
    flex-wrap: wrap;
  }

  .macro-current {
    font-size: 1.08rem;
    font-weight: 600;
    color: var(--fitness-text);
    font-family: var(--mono);
    line-height: 1;
  }

  .macro-name {
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #3d2f23;
  }

  .macro-left {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 20px;
    padding: 0 7px;
    border-radius: 999px;
    background: rgba(64, 50, 38, 0.06);
    font-size: 0.67rem;
    font-weight: 700;
    white-space: nowrap;
  }

  .macro-target {
    line-height: 1;
  }

  .macro-name,
  .macro-target,
  .macro-left,
  .summary-label,
  .summary-value,
  .meals-count,
  .meal-stats,
  .entry-serving,
  .entry-note,
  .list-row-meta,
  .list-row-sub,
  .template-hint,
  .foods-nudge,
  .resolve-food-detail,
  .food-edit-label,
  .food-edit-unit,
  .resolve-note,
  .resolve-meal-label,
  .resolve-total {
    color: var(--fitness-muted);
  }

  .macro-guidance {
    display: grid;
    gap: 4px;
    margin-top: 9px;
    min-height: 38px;
  }

  .extra-nutrients-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid rgba(69, 53, 39, 0.08);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--fitness-soft);
    font-weight: 700;
  }

  .extra-nutrients-note {
    color: var(--fitness-muted);
    letter-spacing: 0.06em;
  }

  .extra-nutrients-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-top: 10px;
  }

  .extra-item {
    background: rgba(255, 250, 244, 0.68);
    padding-top: 12px;
  }

  .sugar-item {
    border-color: rgba(183, 122, 56, 0.16);
  }

  .fiber-item {
    border-color: rgba(76, 126, 95, 0.16);
  }

  .macro-instruction,
  .list-row-name,
  .entry-name,
  .meal-name,
  .resolve-food-name,
  .resolve-modal-title,
  .fab-action-name,
  .fitness-date-readout {
    color: var(--fitness-text);
  }

  .summary-list {
    display: grid;
    gap: 10px;
    margin-top: 14px;
  }

  .summary-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--fitness-line);
  }

  .summary-label {
    text-transform: capitalize;
  }

  .summary-value {
    font-family: var(--mono);
  }

  .fitness-workspace {
    display: grid;
    gap: 14px;
  }

  .composer-panel {
    padding: 18px 20px;
    background: linear-gradient(180deg, rgba(255,252,248,0.96), rgba(248,242,233,0.9));
  }

  .starter-panel {
    padding: 22px;
    border-radius: 28px;
    background:
      radial-gradient(circle at top right, rgba(47, 106, 82, 0.08), transparent 30%),
      linear-gradient(180deg, rgba(255,252,248,0.96), rgba(246,240,231,0.9));
    border: 1px solid var(--fitness-line);
    box-shadow: 0 16px 38px rgba(39, 28, 18, 0.07);
  }

  .starter-header {
    display: flex;
    justify-content: space-between;
    gap: 18px;
    align-items: end;
    margin-bottom: 16px;
  }

  .starter-header h3 {
    margin: 8px 0 6px;
    font-size: 1.5rem;
    line-height: 1.02;
    letter-spacing: -0.05em;
    color: var(--fitness-text);
  }

  .starter-header p {
    margin: 0;
    max-width: 520px;
    color: var(--fitness-muted);
    line-height: 1.55;
  }

  .starter-meals {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(255,255,255,0.66);
    border: 1px solid var(--fitness-line);
    flex-wrap: wrap;
  }

  .starter-meal-btn {
    padding: 8px 12px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--fitness-muted);
    text-transform: capitalize;
    font-size: 0.86rem;
    font-weight: 600;
    cursor: pointer;
    font-family: var(--font);
    transition: all 160ms ease;
  }

  .starter-meal-btn.active {
    background: var(--fitness-accent);
    color: #f9f6f1;
  }

  .starter-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
  }

  .starter-food {
    padding: 16px;
    border-radius: 20px;
    border: 1px solid rgba(44,31,19,0.08);
    background: rgba(255,255,255,0.78);
    text-align: left;
    cursor: pointer;
    transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease;
    font-family: var(--font);
  }

  .starter-food:hover {
    transform: translateY(-1px);
    background: rgba(255,255,255,0.94);
    box-shadow: 0 12px 28px rgba(39, 28, 18, 0.06);
  }

  .starter-food-name {
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    color: var(--fitness-text);
  }

  .starter-food-meta {
    margin-top: 4px;
    font-size: 0.88rem;
    color: var(--fitness-muted);
  }

  .starter-food-action {
    margin-top: 12px;
    font-size: 0.82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--fitness-accent);
  }

  .composer-copy {
    margin-bottom: 10px;
  }

  .composer-copy h2,
  .list-stage-header h2 {
    margin: 6px 0 4px;
    font-size: clamp(1.5rem, 2vw, 2rem);
    line-height: 1.02;
    letter-spacing: -0.05em;
  }

  .composer-copy p {
    margin: 0;
    max-width: 560px;
    color: var(--fitness-muted);
    line-height: 1.4;
    font-size: 0.92rem;
  }

  .resolve-bar {
    display: flex;
    gap: 10px;
  }

  .resolve-input {
    flex: 1;
    padding: 14px 16px;
    border-radius: 18px;
    font-size: 1rem;
    transition: border-color 160ms ease, box-shadow 160ms ease;
  }

  .resolve-input::placeholder,
  .search-input::placeholder {
    color: var(--fitness-soft);
  }

  .resolve-input:focus,
  .search-input:focus,
  .food-edit-input:focus,
  .entry-qty-input:focus,
  .resolve-meal-select:focus,
  .date-input:focus {
    outline: none;
    border-color: rgba(47, 106, 82, 0.38);
    box-shadow: 0 0 0 4px rgba(47, 106, 82, 0.12);
  }

  .resolve-submit {
    width: 52px;
    height: 52px;
    border-radius: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform 160ms ease, opacity 160ms ease;
    flex-shrink: 0;
  }

  .resolve-submit:hover:not(:disabled) {
    transform: translateY(-1px);
  }

  .resolve-submit:disabled {
    opacity: 0.45;
    cursor: default;
  }

  .resolve-submit svg {
    width: 18px;
    height: 18px;
  }

  .resolve-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid rgba(255,255,255,0.24);
    border-top-color: white;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
  }

  .resolve-error {
    margin-top: 10px;
    color: #a13e2f;
    font-size: 0.92rem;
  }

  .meals-divider {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 2px 2px 0;
  }

  .meals-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fitness-soft);
  }

  .meal-section {
    padding: 8px 18px 14px;
    border-radius: 26px;
    background: linear-gradient(180deg, rgba(255,252,248,0.95), rgba(251,246,239,0.9));
  }

  .meal-header {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 2px;
    background: none;
    border: none;
    text-align: left;
    cursor: pointer;
    font-family: var(--font);
  }

  .meal-number {
    width: 38px;
    height: 38px;
    border-radius: 999px;
    background: rgba(69, 53, 39, 0.06);
    color: var(--fitness-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.82rem;
    font-weight: 700;
    flex-shrink: 0;
  }

  .meal-number.has-entries {
    background: var(--fitness-accent-soft);
    color: var(--fitness-accent);
  }

  .meal-info {
    flex: 1;
    min-width: 0;
  }

  .meal-top {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }

  .meal-name {
    font-size: 1.08rem;
    font-weight: 700;
    text-transform: capitalize;
    letter-spacing: -0.03em;
  }

  .meal-weight {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    border-radius: 999px;
    padding: 5px 8px;
  }

  .meal-weight.heavy { background: rgba(161, 62, 47, 0.1); color: #a13e2f; }
  .meal-weight.moderate { background: rgba(200, 137, 50, 0.12); color: #9f5f18; }
  .meal-weight.light { background: var(--fitness-accent-soft); color: var(--fitness-accent); }
  .meal-weight.snack { background: rgba(69, 53, 39, 0.06); color: var(--fitness-muted); }

  .meal-stats {
    display: inline-block;
    margin-top: 3px;
    font-size: 0.92rem;
  }

  .meal-stats.empty {
    color: var(--fitness-soft);
    font-style: normal;
  }

  .meal-chevron {
    width: 16px;
    height: 16px;
    color: var(--fitness-soft);
    transition: transform 160ms ease;
    flex-shrink: 0;
  }

  .meal-chevron.expanded {
    transform: rotate(180deg);
  }

  .meal-entries {
    display: grid;
    gap: 10px;
    padding-left: 14px;
    border-left: 2px solid rgba(44,31,19,0.09);
    margin-left: 18px;
  }

  .entry-wrap {
    display: grid;
    gap: 0;
  }

  .entry-row {
    display: flex;
    justify-content: space-between;
    align-items: start;
    gap: 14px;
    padding: 14px 16px;
    border-radius: 18px;
    background: rgba(255,255,255,0.78);
    border: 1px solid rgba(44,31,19,0.07);
    cursor: pointer;
    transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease;
  }

  .entry-row:hover {
    background: rgba(255,255,255,0.94);
    transform: translateY(-1px);
    box-shadow: 0 10px 22px rgba(39, 28, 18, 0.06);
  }

  .entry-info {
    flex: 1;
    min-width: 0;
  }

  .entry-name {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.03em;
  }

  .entry-badge {
    padding: 4px 7px;
    border-radius: 999px;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-weight: 700;
  }

  .entry-badge.ai { background: rgba(47, 106, 82, 0.12); color: var(--fitness-accent); }
  .entry-badge.quick { background: rgba(69, 53, 39, 0.08); color: var(--fitness-muted); }

  .entry-serving,
  .entry-note {
    margin-top: 4px;
    font-size: 0.92rem;
    line-height: 1.45;
  }

  .entry-cals {
    display: flex;
    align-items: baseline;
    gap: 3px;
    flex-shrink: 0;
    padding-top: 2px;
  }

  .entry-cal-value {
    font-size: 1rem;
    font-weight: 700;
    font-family: var(--mono);
    color: var(--fitness-text);
  }

  .entry-cal-label {
    font-size: 11px;
    color: var(--fitness-soft);
  }

  .entry-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 12px 16px 0;
  }

  .entry-qty-control {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }

  .entry-qty-input {
    width: 74px;
    padding: 9px 10px;
    border-radius: 12px;
    text-align: center;
    font-family: var(--mono);
    font-size: 0.96rem;
  }

  .entry-qty-unit {
    font-size: 0.9rem;
    color: var(--fitness-muted);
  }

  .entry-qty-save,
  .entry-delete-btn,
  .btn-secondary,
  .btn-primary,
  .log-btn {
    padding: 10px 14px;
    border-radius: 14px;
    font-size: 0.9rem;
    font-weight: 600;
    font-family: var(--font);
    cursor: pointer;
    transition: transform 160ms ease, opacity 160ms ease, background 160ms ease, color 160ms ease;
  }

  .entry-qty-save:hover,
  .btn-primary:hover,
  .log-btn:hover,
  .today-btn:hover {
    opacity: 0.92;
  }

  .entry-delete-btn,
  .btn-secondary {
    background: rgba(255,255,255,0.7);
    color: #9a4b3f;
    border: 1px solid rgba(154, 75, 63, 0.16);
  }

  .entry-delete-btn:hover,
  .btn-secondary:hover {
    background: rgba(154, 75, 63, 0.08);
  }

  .entry-delete-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }

  .entry-delete-btn svg {
    width: 14px;
    height: 14px;
  }

  .add-food-btn {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: center;
    padding: 14px;
    border-radius: 18px;
    border: 1px dashed rgba(47, 106, 82, 0.26);
    background: rgba(47, 106, 82, 0.04);
    color: var(--fitness-accent);
    font-size: 0.92rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 160ms ease, transform 160ms ease;
    font-family: var(--font);
  }

  .add-food-btn:hover {
    background: rgba(47, 106, 82, 0.1);
    transform: translateY(-1px);
  }

  .add-food-btn svg {
    width: 16px;
    height: 16px;
  }

  .library-stage {
    display: grid;
    gap: 14px;
  }

  .list-stage-header {
    display: flex;
    justify-content: space-between;
    gap: 18px;
    align-items: end;
  }

  .list-stage-header h2 {
    max-width: 640px;
  }

  .list-header {
    display: flex;
    gap: 12px;
    align-items: center;
  }

  .list-count {
    color: var(--fitness-muted);
    font-size: 0.94rem;
  }

  .search-wrap {
    flex: 1;
    position: relative;
  }

  .search-icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--fitness-soft);
    pointer-events: none;
  }

  .search-input {
    width: 100%;
    padding: 13px 42px 13px 40px;
    border-radius: 18px;
    font-size: 0.96rem;
    transition: border-color 160ms ease, box-shadow 160ms ease;
  }

  .search-clear {
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--fitness-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }

  .search-clear svg {
    width: 14px;
    height: 14px;
  }

  .list-card {
    overflow: hidden;
  }

  .list-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px;
    border-bottom: 1px solid var(--fitness-line);
    cursor: pointer;
    transition: background 160ms ease;
  }

  .list-row:last-child {
    border-bottom: none;
  }

  .list-row:hover {
    background: rgba(255,255,255,0.54);
  }

  .list-row.highlighted {
    background: rgba(47, 106, 82, 0.08);
  }

  .list-row-info {
    flex: 1;
    min-width: 0;
  }

  .list-row-name {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.03em;
  }

  .list-row-meta {
    margin-top: 3px;
    font-size: 0.92rem;
  }

  .list-row-sub {
    margin-top: 3px;
    font-size: 0.82rem;
  }

  .list-row-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
  }

  .list-row-value {
    font-size: 0.9rem;
    color: var(--fitness-text);
    font-family: var(--mono);
  }

  .list-row-chevron {
    width: 14px;
    height: 14px;
    color: var(--fitness-soft);
  }

  .fav-icon {
    width: 13px;
    height: 13px;
    color: var(--fitness-gold);
  }

  .empty-state {
    padding: 36px 24px;
    text-align: center;
    color: var(--fitness-muted);
  }

  .empty-state-rich {
    display: grid;
    gap: 8px;
    justify-items: start;
    text-align: left;
    padding: 28px 24px 30px;
    background:
      radial-gradient(circle at top right, rgba(47, 106, 82, 0.08), transparent 32%),
      linear-gradient(180deg, rgba(255,252,248,0.66), rgba(248,243,236,0.44));
  }

  .empty-state-kicker {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fitness-soft);
  }

  .empty-state-rich h3 {
    margin: 0;
    font-size: 1.35rem;
    line-height: 1.05;
    letter-spacing: -0.05em;
    color: var(--fitness-text);
  }

  .empty-state-rich p {
    margin: 0;
    max-width: 520px;
    font-size: 0.96rem;
    line-height: 1.6;
    color: var(--fitness-muted);
  }

  .template-badge {
    width: 38px;
    height: 38px;
    border-radius: 14px;
    background: rgba(47, 106, 82, 0.1);
    color: var(--fitness-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.92rem;
    font-weight: 700;
    flex-shrink: 0;
  }

  .template-meal-label {
    text-transform: capitalize;
  }

  .template-hint {
    margin-top: 5px;
    color: var(--fitness-accent);
    font-size: 0.82rem;
  }

  .log-btn:hover {
    transform: translateY(-1px);
  }

  .fab {
    position: fixed;
    right: 28px;
    bottom: 28px;
    min-height: 54px;
    padding: 9px 12px 9px 9px;
    border-radius: 18px;
    border: 1px solid rgba(35, 26, 17, 0.1);
    background: linear-gradient(180deg, rgba(255, 251, 245, 0.96) 0%, rgba(245, 237, 228, 0.96) 100%);
    color: #20170f;
    box-shadow: 0 14px 30px rgba(35, 26, 17, 0.11);
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease;
    z-index: 50;
  }

  .fab:hover {
    transform: translateY(-2px);
    box-shadow: 0 22px 42px rgba(35, 26, 17, 0.16);
  }

  .fab-icon {
    width: 16px;
    height: 16px;
  }

  .assistant-fab-mark {
    width: 36px;
    height: 36px;
    border-radius: 12px;
    background: linear-gradient(180deg, #2e6953 0%, #21493b 100%);
    color: #f8f5f0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.16);
  }

  .assistant-fab-copy {
    display: grid;
    align-content: center;
    gap: 1px;
    text-align: left;
    min-width: 0;
  }

  .assistant-fab-title {
    font-size: 0.84rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    color: #1f1710;
  }

  .assistant-fab-sub {
    font-size: 0.7rem;
    color: #746758;
  }

  .fab-overlay {
    position: fixed;
    inset: 0;
    background: rgba(18, 12, 8, 0.32);
    backdrop-filter: blur(8px);
    z-index: 45;
    animation: fadeIn 160ms ease;
  }

  @keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  .fab-sheet {
    position: fixed;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    width: min(720px, calc(100vw - 24px));
    z-index: 48;
    border-radius: 28px;
    padding: 14px;
    animation: slideUp 180ms ease;
  }

  @keyframes slideUp {
    from { transform: translateX(-50%) translateY(18px); opacity: 0; }
    to { transform: translateX(-50%) translateY(0); opacity: 1; }
  }

  .fab-sheet-handle {
    width: 42px;
    height: 4px;
    border-radius: 999px;
    background: rgba(44, 31, 19, 0.16);
    margin: 4px auto 14px;
  }

  .fab-action {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px;
    border: none;
    border-radius: 18px;
    background: transparent;
    cursor: pointer;
    text-align: left;
    font-family: var(--font);
    transition: background 160ms ease;
  }

  .fab-action:hover {
    background: rgba(255,255,255,0.56);
  }

  .fab-action-icon {
    width: 42px;
    height: 42px;
    border-radius: 14px;
    background: rgba(255,255,255,0.7);
    border: 1px solid var(--fitness-line);
    color: var(--fitness-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }

  .fab-action-icon.accent {
    background: var(--fitness-accent);
    color: #f9f6f1;
    border-color: transparent;
  }

  .fab-action-icon svg {
    width: 18px;
    height: 18px;
  }

  .fab-action-text {
    flex: 1;
    min-width: 0;
  }

  .fab-action-desc {
    margin-top: 2px;
    color: var(--fitness-muted);
    font-size: 0.9rem;
  }

  .resolve-overlay {
    position: fixed;
    inset: 0;
    background: rgba(18, 12, 8, 0.34);
    backdrop-filter: blur(10px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 70;
    animation: fadeIn 160ms ease;
  }

  .resolve-modal {
    width: min(520px, calc(100vw - 24px));
    border-radius: 28px;
    overflow: hidden;
    animation: modalUp 180ms ease;
  }

  @keyframes modalUp {
    from { transform: translateY(16px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
  }

  .resolve-modal-header,
  .resolve-modal-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 18px 22px;
    border-bottom: 1px solid var(--fitness-line);
  }

  .resolve-modal-footer {
    border-top: 1px solid var(--fitness-line);
    border-bottom: none;
  }

  .resolve-modal-close,
  .resolve-item-remove {
    width: 32px;
    height: 32px;
    border-radius: 999px;
    border: none;
    background: transparent;
    color: var(--fitness-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }

  .resolve-modal-close:hover,
  .resolve-item-remove:hover {
    background: rgba(44, 31, 19, 0.06);
    color: var(--fitness-text);
  }

  .resolve-modal-close svg,
  .resolve-item-remove svg {
    width: 16px;
    height: 16px;
  }

  .resolve-modal-body {
    padding: 20px 22px;
  }

  .resolve-item + .resolve-item {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--fitness-line);
  }

  .resolve-item-top {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: start;
  }

  .resolve-item-info {
    flex: 1;
    min-width: 0;
  }

  .resolve-food-name {
    font-size: 1rem;
    font-weight: 600;
  }

  .resolve-food-detail {
    margin-top: 4px;
    font-size: 0.9rem;
  }

  .resolve-qty-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
  }

  .resolve-qty-btn {
    width: 30px;
    height: 30px;
    border-radius: 999px;
    border: 1px solid var(--fitness-line);
    background: rgba(255,255,255,0.8);
    color: var(--fitness-text);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }

  .resolve-qty-btn:disabled {
    opacity: 0.35;
    cursor: default;
  }

  .resolve-qty-value {
    min-width: 72px;
    text-align: center;
    color: var(--fitness-text);
    font-family: var(--mono);
    font-size: 0.92rem;
  }

  .resolve-meal-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--fitness-line);
  }

  .resolve-meal-select {
    padding: 10px 12px;
    border-radius: 14px;
    font-size: 0.92rem;
    font-family: var(--font);
  }

  .resolve-footer-actions {
    display: flex;
    gap: 10px;
  }

  .food-edit-field {
    display: grid;
    gap: 6px;
  }

  .food-edit-input {
    padding: 12px 14px;
    border-radius: 14px;
    font-size: 0.95rem;
    font-family: var(--font);
  }

  .food-edit-input[type="number"] {
    font-family: var(--mono);
  }

  .food-edit-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 12px;
  }

  @keyframes spin {
    to { transform: rotate(360deg); }
  }

  @media (max-width: 768px) {
    .macro-panel .macro-row {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 8px;
      overflow: visible;
      padding-bottom: 0;
      margin-right: 0;
    }

    .macro-item {
      padding: 12px 10px 11px;
      border-radius: 16px;
      min-width: 0;
    }

    .macro-card-head {
      gap: 6px;
      margin-bottom: 8px;
      align-items: start;
      flex-direction: column;
    }

    .macro-label {
      gap: 4px;
      align-items: baseline;
      flex-wrap: wrap;
    }

    .macro-current {
      font-size: 0.9rem;
    }

    .macro-name,
    .macro-target,
    .macro-left,
    .macro-instruction {
      font-size: 0.74rem;
      line-height: 1.3;
    }

    .macro-guidance {
      margin-top: 6px;
    }

    .extra-nutrients-head {
      margin-top: 14px;
      padding-top: 12px;
      font-size: 0.68rem;
      flex-wrap: wrap;
    }

    .extra-nutrients-row {
      gap: 8px;
      margin-top: 8px;
    }

    .calorie-meta-row {
      gap: 6px;
      margin-bottom: 10px;
    }

    .calorie-meta-pill {
      font-size: 0.72rem;
      padding: 0 8px;
    }
  }

  .summary-list {
    display: grid;
    gap: 10px;
    margin-top: 14px;
  }

  @media (max-width: 768px) {
    .fitness-log-grid {
      grid-template-columns: 1fr;
    }

    .fitness-shell {
      padding: 20px 16px 120px;
    }

    .fitness-header {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 4px;
      align-items: center;
    }

    .list-stage-header {
      grid-template-columns: 1fr;
      display: grid;
      gap: 14px;
      align-items: start;
    }

    .fitness-header-side {
      justify-items: end;
      width: auto;
    }

    .fitness-heading {
      display: block;
      max-width: none;
    }

    .fitness-heading h1 {
      font-size: 2.15rem;
      margin: 0;
      line-height: 0.95;
    }

    .fitness-subcopy {
      display: none;
    }

    .fitness-mobile-note {
      display: none;
    }

    .date-nav {
      width: auto;
      display: grid;
      grid-template-columns: 28px minmax(146px, auto) 28px auto;
      gap: 4px;
      align-items: center;
    }

    .date-display {
      min-height: 32px;
      min-width: 146px;
      padding: 0 14px;
      border-radius: 10px;
      background: rgba(255,255,255,0.62);
      font-size: 0.84rem;
    }

    .date-display-text {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .today-btn {
      min-width: 44px;
      padding: 6px 8px;
      font-size: 0.72rem;
    }

    .btn-icon {
      width: 28px;
      height: 28px;
      border-radius: 10px;
    }

    .btn-icon svg {
      width: 14px;
      height: 14px;
    }

    .fitness-header-side {
      width: 100%;
      justify-items: start;
    }

    .top-tabs {
      width: 100%;
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      overflow: visible;
      padding: 4px;
      gap: 0;
    }

    .top-tab {
      width: 100%;
      min-width: 0;
      text-align: center;
      padding: 10px 8px;
      font-size: 0.84rem;
    }

    .fitness-rail {
      position: static;
      grid-template-columns: 1fr;
    }

    .rail-panel,
    .composer-panel,
    .meal-section,
    .list-card {
      border-radius: 24px;
    }

    .resolve-bar,
    .list-header,
    .resolve-modal-footer,
    .entry-actions,
    .starter-header {
      flex-direction: column;
      align-items: stretch;
    }

    .starter-grid {
      grid-template-columns: 1fr;
    }

    .resolve-submit,
    .entry-qty-save,
    .entry-delete-btn,
    .btn-secondary,
    .btn-primary,
    .log-btn {
      width: 100%;
      justify-content: center;
    }

    .meal-entries {
      margin-left: 10px;
      padding-left: 10px;
    }

    .entry-row,
    .list-row {
      padding: 14px;
    }

    .food-edit-row {
      grid-template-columns: 1fr;
    }

    .fab {
      right: 16px;
      left: auto;
      bottom: calc(14px + env(safe-area-inset-bottom));
      min-height: 56px;
      max-width: calc(100vw - 32px);
      justify-content: flex-start;
      box-shadow: 0 14px 28px rgba(35, 26, 17, 0.14);
    }

    .assistant-fab-title {
      font-size: 0.9rem;
    }

    .assistant-fab-sub {
      font-size: 0.74rem;
    }

    .fab-sheet {
      left: 12px;
      right: 12px;
      width: auto;
      transform: none;
      bottom: 12px;
    }

    @keyframes slideUp {
      from { transform: translateY(18px); opacity: 0; }
      to { transform: translateY(0); opacity: 1; }
    }
  }
</style>
