/* ============================================================================
   BROWSER-CDN HOST SHIM — added 2026-05-17 for Option-1 deployment.
   This file now runs through Babel standalone in index.html instead of a
   bundler. The three ESM imports below were replaced with destructuring from
   CDN globals so nothing else in the file had to change. The `export default`
   on `App` (around line 656) was also dropped so this script defines App on
   the page's global scope; index.html mounts it with ReactDOM.createRoot.
   Restore the original imports + export default when migrating to Vite.

   Original imports (kept for reference):
     import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
     import { Home, Users, BarChart3, Settings as SettingsIcon, ... } from 'lucide-react';
     import { BarChart, Bar, XAxis, YAxis, ... } from 'recharts';
   ============================================================================ */
const { useState, useEffect, useRef, useCallback, useMemo } = React;
const __Lucide = window['lucide-react'] || window.LucideReact || window.lucide;
const {
  Home, Users, BarChart3, Settings: SettingsIcon, Plus, Search, ChevronRight,
  ChevronLeft, Check, Droplet, ClipboardList, FileText, Phone, Mail,
  DollarSign, Calendar, Clock, CheckCircle2, AlertCircle, CreditCard,
  Send, Zap, ArrowLeft, MessageSquare, Trash2, Minus, BookOpen, Beaker,
  TrendingUp, X, Edit3, BadgeCheck, Gauge, CheckCheck, Navigation, Wrench, ChevronDown, Camera, Image
} = __Lucide;
const { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, LineChart, Line } = window.Recharts;

/* ============================================================================
   SUPABASE CLIENT — thin fetch-based wrapper, interface-compatible with
   @supabase/supabase-js so we can drop-in swap to the official SDK once we
   move to a Vite/Vercel deployment. Stays inside the JSX artifact runtime
   without needing an extra dependency.
   ============================================================================ */
const SUPABASE_URL = 'https://spjcwvoxdiqiwfjpbiku.supabase.co';
const SUPABASE_KEY = 'sb_publishable_tIWqsJ3_QM8O3kAZ4Zys_w_WvBlYW4L';
const SESSION_STORAGE_KEY = 'routebook-supa-session-v1';

const supa = (() => {
  let session = null;
  const listeners = new Set();
  const notify = () => listeners.forEach(cb => cb(session));

  const headers = (extra = {}) => {
    const h = { apikey: SUPABASE_KEY, 'Content-Type': 'application/json', ...extra };
    if (session?.access_token) h.Authorization = `Bearer ${session.access_token}`;
    return h;
  };

  // Persist session via window.storage so it survives artifact refreshes.
  // (Not best practice for a real production app, but fine for prototype.)
  const persistSession = async () => {
    try {
      if (session) await window.storage.set(SESSION_STORAGE_KEY, JSON.stringify(session));
      else await window.storage.delete(SESSION_STORAGE_KEY);
    } catch {}
  };

  const restoreSession = async () => {
    try {
      const r = await window.storage.get(SESSION_STORAGE_KEY);
      if (r?.value) {
        const s = JSON.parse(r.value);
        // Basic expiry check; if expired, clear it
        if (s.expires_at && Date.now() / 1000 < s.expires_at - 30) {
          session = s;
          notify();
          return s;
        }
        await window.storage.delete(SESSION_STORAGE_KEY);
      }
    } catch {}
    notify();
    return null;
  };

  const handle401 = async () => {
    if (session) { session = null; await persistSession(); notify(); }
  };

  const auth = {
    async signUp(email, password) {
      const res = await fetch(`${SUPABASE_URL}/auth/v1/signup`, {
        method: 'POST', headers: headers(), body: JSON.stringify({ email, password }),
      });
      const data = await res.json().catch(() => null);
      if (!res.ok) return { data: null, error: data || { message: `HTTP ${res.status}` } };
      if (data?.access_token) { session = data; await persistSession(); notify(); }
      return { data, error: null };
    },
    async signIn(email, password) {
      const res = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=password`, {
        method: 'POST', headers: headers(), body: JSON.stringify({ email, password }),
      });
      const data = await res.json().catch(() => null);
      if (!res.ok) return { data: null, error: data || { message: `HTTP ${res.status}` } };
      session = data; await persistSession(); notify();
      return { data, error: null };
    },
    async signOut() {
      session = null; await persistSession(); notify();
      return { error: null };
    },
    getUser: () => session?.user || null,
    getSession: () => session,
    onAuthChange: (cb) => { listeners.add(cb); return () => listeners.delete(cb); },
    restoreSession,
  };

  // PostgREST query builder — chainable, awaitable
  const from = (table) => {
    let _filters = [], _select = '*', _single = false, _order = null, _verb = 'GET', _body = null;

    const buildUrl = () => {
      const params = [];
      if (_verb === 'GET') params.push(`select=${_select}`);
      if (_order) params.push(`order=${_order}`);
      _filters.forEach(f => params.push(f));
      return `${SUPABASE_URL}/rest/v1/${table}${params.length ? '?' + params.join('&') : ''}`;
    };

    const exec = async () => {
      const opts = { method: _verb,
        headers: _verb === 'GET' ? headers() : headers({ Prefer: 'return=representation' }) };
      if (_body) opts.body = JSON.stringify(_body);
      const res = await fetch(buildUrl(), opts);
      if (res.status === 401) await handle401();
      if (res.status === 204) return { data: null, error: null };
      const data = await res.json().catch(() => null);
      if (!res.ok) return { data: null, error: data || { message: `HTTP ${res.status}` } };
      if (_single) return { data: Array.isArray(data) ? (data[0] || null) : data, error: null };
      return { data, error: null };
    };

    const builder = {
      select(cols = '*')  { _select = cols; _verb = 'GET'; return builder; },
      insert(row)         { _verb = 'POST'; _body = Array.isArray(row) ? row : [row]; return builder; },
      update(patch)       { _verb = 'PATCH'; _body = patch; return builder; },
      delete()            { _verb = 'DELETE'; return builder; },
      eq(col, val)        { _filters.push(`${col}=eq.${encodeURIComponent(val)}`); return builder; },
      order(col, opts = {}) { _order = `${col}.${opts.ascending === false ? 'desc' : 'asc'}`; return builder; },
      single()            { _single = true; return builder; },
      then(onFulfilled, onRejected) { return exec().then(onFulfilled, onRejected); },
    };
    return builder;
  };

  return { auth, from };
})();

/* ============================================================================
   STORAGE — persistent across sessions via window.storage (no localStorage)
   ============================================================================ */
const DB_KEY = 'routebook-db-v1';

const todayISO = () => new Date().toISOString().slice(0, 10);
const offsetISO = (n) => { const d = new Date(); d.setDate(d.getDate() + n); return d.toISOString().slice(0, 10); };

const seedVisit = (id, customerId, date, durationMin, chems, readings, complete, paid, maint = {}) => ({
  id, customerId, date, durationMin,
  chemicalsUsed: chems,
  waterReadings: readings,
  checklist: { skimmed: true, vacuumed: true, brushed: true, basketsEmptied: true, filterChecked: true, waterLevel: true, equipmentInspected: true },
  backwashed: !!maint.backwashed,
  filterCleaned: !!maint.filterCleaned,
  filterPsi: maint.filterPsi != null ? maint.filterPsi : '',
  algaeLevel: maint.algaeLevel || 0,
  poolRxDosed: !!maint.poolRxDosed,
  repairsNeeded: '', notes: '',
  invoiced: complete, paid: paid && complete,
  completedAt: complete ? `${date}T15:00:00Z` : null,
  mileage: null,
});

const defaultDB = () => ({
  profile: { name: '', businessName: '', email: '', phone: '', businessAddress: '', businessCity: '', businessLat: null, businessLng: null, onboarded: false, laborRate: 60, defaultVisitMins: 30, poolRxPrice: 50, filterCleanPrice: 75 },
  chemicals: [
    { id: 'ch1', name: 'Chlorine Tabs (3")', unit: 'tab', costPerUnit: 3.00 },
    { id: 'ch2', name: 'Liquid Chlorine', unit: 'gal', costPerUnit: 5.50 },
    { id: 'ch3', name: 'Muriatic Acid', unit: 'gal', costPerUnit: 8.00 },
    { id: 'ch4', name: 'Soda Ash', unit: 'lb', costPerUnit: 2.20 },
    { id: 'ch5', name: 'Calcium Chloride', unit: 'lb', costPerUnit: 2.80 },
    { id: 'ch6', name: 'Cyanuric Acid', unit: 'lb', costPerUnit: 6.50 },
    { id: 'ch7', name: 'Shock', unit: 'lb', costPerUnit: 5.25 },
    { id: 'ch8', name: 'Algaecide', unit: 'oz', costPerUnit: 0.75 },
  ],
  customers: [
    { id: 'c1', name: 'The Hendersons', address: '412 Sea Cliff Dr', city: 'Cerritos, CA', lat: null, lng: null, phone: '(562) 555-0142', email: 'mike.h@example.com', poolSize: 18000, poolType: 'Chlorine', filterType: 'DE', filterPsiBaseline: 14, cleaner: 'Robotic', poolRx: true, serviceRate: 165, serviceFreq: 'Weekly', notes: 'Gate code 4421. Friendly dog.', addedDate: offsetISO(-180) },
    { id: 'c2', name: 'Vasquez Residence', address: '78 Larkspur Ln', city: 'Cerritos, CA', lat: null, lng: null, phone: '(562) 555-0198', email: 'a.vasquez@example.com', poolSize: 14500, poolType: 'Salt', filterType: 'Cartridge', filterPsiBaseline: 12, cleaner: 'None', poolRx: false, serviceRate: 145, serviceFreq: 'Weekly', notes: 'Salt cell replaced March.', addedDate: offsetISO(-220) },
    { id: 'c3', name: 'Patel Pool', address: '1209 Birchwood Ct', city: 'Long Beach, CA', lat: null, lng: null, phone: '(562) 555-0111', email: 'r.patel@example.com', poolSize: 22000, poolType: 'Chlorine', filterType: 'Cartridge', filterPsiBaseline: 10, cleaner: 'Pressure', poolRx: false, serviceRate: 195, serviceFreq: 'Weekly', notes: 'Polaris on pressure line.', addedDate: offsetISO(-90) },
    { id: 'c4', name: 'Brookside HOA', address: '5500 Brookside Pkwy', city: 'Lakewood, CA', lat: null, lng: null, phone: '(562) 555-0173', email: 'mgmt@brooksidehoa.com', poolSize: 45000, poolType: 'Chlorine', filterType: 'DE', filterPsiBaseline: 12, cleaner: 'In-floor', poolRx: true, serviceRate: 425, serviceFreq: '2x Weekly', notes: 'Commercial — log readings.', addedDate: offsetISO(-300) },
    { id: 'c5', name: 'Kim Family', address: '88 Coral Reef Way', city: 'Cerritos, CA', lat: null, lng: null, phone: '(562) 555-0166', email: 'jkim@example.com', poolSize: 16000, poolType: 'Salt', filterType: 'Cartridge', filterPsiBaseline: 12, cleaner: 'Suction', poolRx: false, serviceRate: 155, serviceFreq: 'Weekly', notes: '', addedDate: offsetISO(-45) },
  ],
  visits: [
    // Today's stops (in progress)
    { id: 'v_today_1', customerId: 'c1', date: todayISO(), durationMin: 30, chemicalsUsed: [], waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' }, checklist: { skimmed: false, vacuumed: false, brushed: false, basketsEmptied: false, filterChecked: false, waterLevel: false, equipmentInspected: false }, backwashed: false, filterCleaned: false, filterPsi: '', algaeLevel: 0, poolRxDosed: false, repairsNeeded: '', notes: '', invoiced: false, paid: false, completedAt: null, mileage: null },
    { id: 'v_today_2', customerId: 'c2', date: todayISO(), durationMin: 30, chemicalsUsed: [], waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' }, checklist: { skimmed: false, vacuumed: false, brushed: false, basketsEmptied: false, filterChecked: false, waterLevel: false, equipmentInspected: false }, backwashed: false, filterCleaned: false, filterPsi: '', algaeLevel: 0, poolRxDosed: false, repairsNeeded: '', notes: '', invoiced: false, paid: false, completedAt: null, mileage: null },
    { id: 'v_today_3', customerId: 'c5', date: todayISO(), durationMin: 30, chemicalsUsed: [], waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' }, checklist: { skimmed: false, vacuumed: false, brushed: false, basketsEmptied: false, filterChecked: false, waterLevel: false, equipmentInspected: false }, backwashed: false, filterCleaned: false, filterPsi: '', algaeLevel: 0, poolRxDosed: false, repairsNeeded: '', notes: '', invoiced: false, paid: false, completedAt: null, mileage: null },
    // History — c1 had a backwash 30d ago, filter clean 200d ago (DUE for clean); c2 backwash 14d ago, clean 60d ago (recent); c4 backwash 7d ago
    // Algae history: c3 had moderate algae last week (still being treated), c1 had light algae 2 weeks ago (resolved)
    // Filter PSI history: c1 pressure climbing ~1 PSI/wk (clean predicted), c4 just dropped after 7d-ago backwash
    seedVisit('v1', 'c1', offsetISO(-7), 32, [{ chemId: 'ch1', amount: 2 }, { chemId: 'ch4', amount: 1 }], { fc: 3.0, ph: 7.5, alk: 100, cal: 250, cya: 45 }, true, true, { filterPsi: 17 }),
    seedVisit('v2', 'c2', offsetISO(-7), 28, [{ chemId: 'ch3', amount: 0.5 }], { fc: 2.8, ph: 7.7, alk: 90, cal: 220, cya: 40 }, true, true, { filterPsi: 13 }),
    seedVisit('v3', 'c3', offsetISO(-7), 38, [{ chemId: 'ch1', amount: 3 }, { chemId: 'ch7', amount: 1 }, { chemId: 'ch8', amount: 4 }], { fc: 1.5, ph: 7.8, alk: 110, cal: 280, cya: 50 }, true, false, { algaeLevel: 2, filterPsi: 14 }),
    seedVisit('v4', 'c4', offsetISO(-7), 55, [{ chemId: 'ch1', amount: 5 }, { chemId: 'ch3', amount: 1 }], { fc: 3.5, ph: 7.4, alk: 95, cal: 240, cya: 50 }, true, true, { backwashed: true, filterPsi: 12 }),
    seedVisit('v5', 'c5', offsetISO(-7), 30, [{ chemId: 'ch3', amount: 0.25 }], { fc: 3.2, ph: 7.6, alk: 100, cal: 230, cya: 45 }, true, true, { filterPsi: 13 }),
    seedVisit('v6', 'c1', offsetISO(-14), 35, [{ chemId: 'ch1', amount: 2 }, { chemId: 'ch7', amount: 1 }], { fc: 2.8, ph: 7.5, alk: 95, cal: 245, cya: 50 }, true, true, { backwashed: true, algaeLevel: 1, filterPsi: 16 }),
    seedVisit('v_c2_clean', 'c2', offsetISO(-14), 45, [{ chemId: 'ch1', amount: 2 }], { fc: 2.5, ph: 7.5, alk: 100, cal: 230, cya: 45 }, true, true, { backwashed: true, filterPsi: 12 }),
    seedVisit('v7', 'c3', offsetISO(-14), 40, [{ chemId: 'ch1', amount: 3 }, { chemId: 'ch4', amount: 2 }, { chemId: 'ch7', amount: 2 }], { fc: 2.0, ph: 7.4, alk: 110, cal: 270, cya: 55 }, true, true, { algaeLevel: 3, filterPsi: 13 }),
    seedVisit('v8', 'c4', offsetISO(-14), 60, [{ chemId: 'ch1', amount: 6 }], { fc: 3.0, ph: 7.5, alk: 100, cal: 250, cya: 50 }, true, true, { filterPsi: 18 }),
    seedVisit('v9', 'c1', offsetISO(-21), 30, [{ chemId: 'ch1', amount: 2 }], { fc: 2.5, ph: 7.6, alk: 100, cal: 245, cya: 50 }, true, true, { filterPsi: 15 }),
    seedVisit('v10', 'c4', offsetISO(-21), 55, [{ chemId: 'ch1', amount: 5 }], { fc: 3.0, ph: 7.5, alk: 95, cal: 240, cya: 48 }, true, true, { filterCleaned: true, filterPsi: 17 }),
    seedVisit('v_c2_oldclean', 'c2', offsetISO(-60), 50, [{ chemId: 'ch1', amount: 2 }], { fc: 2.5, ph: 7.5, alk: 100, cal: 230, cya: 45 }, true, true, { filterCleaned: true, filterPsi: 12 }),
    // Pool RX dose history: Hendersons treated 90d ago (next due in 90d), Brookside treated 150d ago (due in 30d)
    seedVisit('v_c1_rx', 'c1', offsetISO(-90), 38, [{ chemId: 'ch1', amount: 2 }], { fc: 3.0, ph: 7.5, alk: 100, cal: 245, cya: 50 }, true, true, { poolRxDosed: true, filterPsi: 14 }),
    seedVisit('v_c4_rx', 'c4', offsetISO(-150), 60, [{ chemId: 'ch1', amount: 5 }], { fc: 3.0, ph: 7.5, alk: 100, cal: 250, cya: 50 }, true, true, { poolRxDosed: true, filterPsi: 12 }),
  ],
  settings: { squareConnected: false, squareAccessToken: '', squareLocationId: '', squareEnvironment: 'sandbox', smsRemindersEnabled: false, emailRemindersEnabled: false, autoRemindersEnabled: true, invoiceReminderDays: 14, reminderDaysBefore: 1, mileageTrackingEnabled: true },
  repairs: [],
  invoices: [],
});

const storageGet = async () => {
  try { const r = await window.storage.get(DB_KEY); return r?.value ? JSON.parse(r.value) : null; }
  catch { return null; }
};
const storageSet = async (db) => {
  try { await window.storage.set(DB_KEY, JSON.stringify(db)); return true; } catch { return false; }
};

/* ============================================================================
   UTILITIES
   ============================================================================ */
const fmt = (n) => `$${(n || 0).toFixed(2)}`;
const fmt0 = (n) => `$${Math.round(n || 0).toLocaleString()}`;
const dayName = (iso) => new Date(iso + 'T12:00:00').toLocaleDateString('en-US', { weekday: 'long' });
const shortDate = (iso) => new Date(iso + 'T12:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
const uid = (p = 'id') => `${p}_${Math.random().toString(36).slice(2, 9)}`;

const visitChemCost = (visit, chemicals) =>
  (visit.chemicalsUsed || []).reduce((s, c) => {
    const ch = chemicals.find(x => x.id === c.chemId);
    return s + (ch ? ch.costPerUnit * c.amount : 0);
  }, 0);

const visitLaborCost = (visit, laborRate) => ((visit.durationMin || 0) / 60) * laborRate;

/* ============================================================================
   MILEAGE TRACKING — geocode addresses + haversine distance estimation
   Uses OpenStreetMap Nominatim (free, no API key, 1 req/sec rate limit).
   Coordinates are cached on customer/profile records after first geocode.
   ============================================================================ */
let _lastGeocodeTime = 0;

const geocodeAddress = async (address, city) => {
  if (!address || !city) return null;
  // Respect Nominatim 1 req/sec rate limit
  const now = Date.now();
  const wait = Math.max(0, 1100 - (now - _lastGeocodeTime));
  if (wait > 0) await new Promise(r => setTimeout(r, wait));
  _lastGeocodeTime = Date.now();
  try {
    const q = encodeURIComponent(`${address}, ${city}`);
    const res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${q}`, {
      headers: { 'User-Agent': 'Routebook/0.1 (pool-service-prototype)' },
    });
    const data = await res.json();
    if (data && data.length > 0) {
      return { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) };
    }
  } catch (e) {
    console.warn('Geocode failed for:', address, city, e);
  }
  return null;
};

const haversineDistance = (lat1, lng1, lat2, lng2) => {
  const R = 3958.8; // Earth radius in miles
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLng = (lng2 - lng1) * Math.PI / 180;
  const a = Math.sin(dLat / 2) ** 2 +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLng / 2) ** 2;
  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};

const ROAD_FACTOR = 1.4; // Straight-line → approximate road distance

const estimateDrivingMiles = (lat1, lng1, lat2, lng2) => {
  if (lat1 == null || lng1 == null || lat2 == null || lng2 == null) return null;
  const straight = haversineDistance(lat1, lng1, lat2, lng2);
  return +(straight * ROAD_FACTOR).toFixed(1);
};

// Calculate total daily mileage from completed visits (home → stops → home)
const calcDailyMileage = (todayVisits, customers, profile) => {
  const completed = todayVisits
    .filter(v => v.completedAt)
    .sort((a, b) => a.completedAt.localeCompare(b.completedAt));
  if (completed.length === 0) return { stopMiles: 0, returnMiles: null, totalMiles: 0, stops: 0 };

  let stopMiles = completed.reduce((sum, v) => sum + (v.mileage || 0), 0);

  // Return trip: last completed stop → home base
  let returnMiles = null;
  if (profile.businessLat != null && profile.businessLng != null) {
    const lastVisit = completed[completed.length - 1];
    const lastCustomer = customers.find(c => c.id === lastVisit.customerId);
    if (lastCustomer?.lat != null && lastCustomer?.lng != null) {
      returnMiles = estimateDrivingMiles(lastCustomer.lat, lastCustomer.lng, profile.businessLat, profile.businessLng);
    }
  }

  return {
    stopMiles: +stopMiles.toFixed(1),
    returnMiles,
    totalMiles: +(stopMiles + (returnMiles || 0)).toFixed(1),
    stops: completed.length,
  };
};

// Aggregate mileage from all visit records for monthly/yearly totals
const calcMileageSummary = (visits) => {
  const now = new Date();
  const thisMonth = now.toISOString().slice(0, 7); // 'YYYY-MM'
  const thisYear = now.getFullYear().toString();
  const withMileage = visits.filter(v => v.completedAt && v.mileage > 0);

  const monthMiles = withMileage
    .filter(v => v.date.startsWith(thisMonth))
    .reduce((s, v) => s + v.mileage, 0);
  const monthStops = withMileage.filter(v => v.date.startsWith(thisMonth)).length;

  const yearMiles = withMileage
    .filter(v => v.date.startsWith(thisYear))
    .reduce((s, v) => s + v.mileage, 0);
  const yearStops = withMileage.filter(v => v.date.startsWith(thisYear)).length;

  // Group by month for the current year
  const monthlyBreakdown = {};
  withMileage.filter(v => v.date.startsWith(thisYear)).forEach(v => {
    const m = v.date.slice(0, 7);
    if (!monthlyBreakdown[m]) monthlyBreakdown[m] = { miles: 0, stops: 0 };
    monthlyBreakdown[m].miles += v.mileage;
    monthlyBreakdown[m].stops += 1;
  });

  return { monthMiles: +monthMiles.toFixed(1), monthStops, yearMiles: +yearMiles.toFixed(1), yearStops, monthlyBreakdown };
};

// Helper: compute mileage for a visit being completed, given db state
const computeVisitMileage = async (visit, db, updateDb) => {
  if (!db.settings.mileageTrackingEnabled) return null;
  const customer = db.customers.find(c => c.id === visit.customerId);
  if (!customer) return null;

  // Ensure current customer has geocoded coords
  let custLat = customer.lat, custLng = customer.lng;
  if (custLat == null || custLng == null) {
    const coords = await geocodeAddress(customer.address, customer.city);
    if (coords) {
      custLat = coords.lat;
      custLng = coords.lng;
      // Cache on customer
      updateDb(d => ({
        ...d,
        customers: d.customers.map(c => c.id === customer.id ? { ...c, lat: coords.lat, lng: coords.lng } : c),
      }));
    } else {
      return null; // Can't geocode destination
    }
  }

  // Determine origin: previous completed stop today, or home base
  const today = todayISO();
  const completedToday = db.visits
    .filter(v => v.date === today && v.completedAt && v.id !== visit.id)
    .sort((a, b) => a.completedAt.localeCompare(b.completedAt));

  let originLat, originLng;

  if (completedToday.length > 0) {
    // Origin = last completed stop
    const prevVisit = completedToday[completedToday.length - 1];
    const prevCustomer = db.customers.find(c => c.id === prevVisit.customerId);
    if (prevCustomer?.lat != null && prevCustomer?.lng != null) {
      originLat = prevCustomer.lat;
      originLng = prevCustomer.lng;
    } else if (prevCustomer) {
      const coords = await geocodeAddress(prevCustomer.address, prevCustomer.city);
      if (coords) {
        originLat = coords.lat;
        originLng = coords.lng;
        updateDb(d => ({
          ...d,
          customers: d.customers.map(c => c.id === prevCustomer.id ? { ...c, lat: coords.lat, lng: coords.lng } : c),
        }));
      }
    }
  } else {
    // Origin = home base
    if (db.profile.businessLat != null && db.profile.businessLng != null) {
      originLat = db.profile.businessLat;
      originLng = db.profile.businessLng;
    } else if (db.profile.businessAddress && db.profile.businessCity) {
      const coords = await geocodeAddress(db.profile.businessAddress, db.profile.businessCity);
      if (coords) {
        originLat = coords.lat;
        originLng = coords.lng;
        updateDb(d => ({
          ...d,
          profile: { ...d.profile, businessLat: coords.lat, businessLng: coords.lng },
        }));
      }
    }
  }

  return estimateDrivingMiles(originLat, originLng, custLat, custLng);
};

/* ============================================================================
   COLOR-CODED WATER READINGS — gradient by deviation from ideal range
   Tone: 'good' (green) | 'warn' (yellow) | 'caution' (orange) | 'critical' (red)
   ============================================================================ */
const readingTone = (key, val) => {
  if (val === '' || val == null) return null;
  const v = parseFloat(val);
  if (isNaN(v)) return null;
  if (key === 'fc') {
    if (v >= 1 && v <= 3) return 'good';
    if ((v >= 0.5 && v < 1) || (v > 3 && v <= 5)) return 'warn';
    if ((v >= 0.2 && v < 0.5) || (v > 5 && v <= 8)) return 'caution';
    return 'critical';
  }
  if (key === 'ph') {
    if (v >= 7.4 && v <= 7.6) return 'good';
    if ((v >= 7.2 && v < 7.4) || (v > 7.6 && v <= 7.8)) return 'warn';
    if ((v >= 7.0 && v < 7.2) || (v > 7.8 && v <= 8.0)) return 'caution';
    return 'critical';
  }
  if (key === 'alk') {
    if (v >= 80 && v <= 120) return 'good';
    if ((v >= 60 && v < 80) || (v > 120 && v <= 150)) return 'warn';
    if ((v >= 40 && v < 60) || (v > 150 && v <= 200)) return 'caution';
    return 'critical';
  }
  if (key === 'cal') {
    if (v >= 200 && v <= 400) return 'good';
    if ((v >= 150 && v < 200) || (v > 400 && v <= 500)) return 'warn';
    if ((v >= 100 && v < 150) || (v > 500 && v <= 700)) return 'caution';
    return 'critical';
  }
  if (key === 'cya') {
    if (v >= 30 && v <= 50) return 'good';
    if ((v >= 20 && v < 30) || (v > 50 && v <= 80)) return 'warn';
    if ((v >= 10 && v < 20) || (v > 80 && v <= 100)) return 'caution';
    return 'critical';
  }
  return null;
};

const TONE_COLOR = {
  good: '#1F8B3E',     // green
  warn: '#B58100',     // amber
  caution: '#D97706',  // orange
  critical: '#FF3B30', // red
};

/* ============================================================================
   ALGAE SEVERITY — 5-step scale from clean to black algae
   ============================================================================ */
const ALGAE_LEVELS = [
  { label: 'None',     color: '#5BC0DE', dotColor: '#5BC0DE', description: 'Pool clear and clean' },
  { label: 'Light',    color: '#9DD8AB', dotColor: '#7AC388', description: 'Slight green tint, early bloom' },
  { label: 'Moderate', color: '#52A35A', dotColor: '#52A35A', description: 'Visible green water, walls slimy' },
  { label: 'Severe',   color: '#2D7A4D', dotColor: '#2D7A4D', description: 'Dark green, low visibility' },
  { label: 'Black',    color: '#1F3D2A', dotColor: '#1F3D2A', description: 'Black algae spots on walls' },
];

/* ============================================================================
   POOL RX — biannual phosphate treatment, 180 days between doses
   ============================================================================ */
const POOL_RX_INTERVAL_DAYS = 180;

const poolRxStatus = (customerId, visits) => {
  const cv = visits.filter(v => v.customerId === customerId && v.completedAt);
  const lastDose = cv.filter(v => v.poolRxDosed).sort((a, b) => b.date.localeCompare(a.date))[0];
  const daysSince = (iso) => Math.floor((Date.now() - new Date(iso + 'T12:00:00').getTime()) / 86400000);
  if (!lastDose) {
    return { lastDate: null, daysSince: null, dueInDays: 0, due: true };
  }
  const ds = daysSince(lastDose.date);
  return {
    lastDate: lastDose.date,
    daysSince: ds,
    dueInDays: POOL_RX_INTERVAL_DAYS - ds,
    due: ds >= POOL_RX_INTERVAL_DAYS,
  };
};

/* ============================================================================
   FILTER PRESSURE PREDICTION
   Industry rule of thumb: clean filter when PSI rises 8 over post-clean baseline.
   We fit a linear rate from visit history and project days-until-threshold.
   ============================================================================ */
const PSI_CLEAN_THRESHOLD = 8; // PSI over baseline = clean needed

const predictFilterClean = (customerId, visits, baselinePsi, currentPsi) => {
  const baseline = parseFloat(baselinePsi);
  if (isNaN(baseline)) return null;

  // Gather completed-visit pressure readings, oldest first
  const readings = visits
    .filter(v => v.customerId === customerId && v.completedAt && v.filterPsi != null && v.filterPsi !== '')
    .map(v => ({ date: v.date, psi: parseFloat(v.filterPsi) }))
    .filter(r => !isNaN(r.psi))
    .sort((a, b) => a.date.localeCompare(b.date));

  // Use live current value if entered, else fall back to last completed reading
  const liveCurrent = currentPsi != null && currentPsi !== '' ? parseFloat(currentPsi) : NaN;
  const current = !isNaN(liveCurrent) ? liveCurrent : (readings.length ? readings[readings.length - 1].psi : null);
  if (current == null || isNaN(current)) return { baseline, current: null, delta: null, status: null, rate: null, daysUntilClean: null };

  const delta = +(current - baseline).toFixed(1);

  // Compute rate of rise — only if we have ≥2 historical points spanning ≥1 day
  let rate = null;
  let daysUntilClean = null;
  if (readings.length >= 2) {
    // Use only readings since the last filter clean (if any) — pressure resets after a clean
    const lastClean = visits
      .filter(v => v.customerId === customerId && v.completedAt && v.filterCleaned)
      .sort((a, b) => b.date.localeCompare(a.date))[0];
    const since = lastClean ? lastClean.date : readings[0].date;
    const trend = readings.filter(r => r.date >= since);
    if (trend.length >= 2) {
      const oldest = trend[0];
      const newest = trend[trend.length - 1];
      const daysSpan = (new Date(newest.date + 'T12:00:00').getTime() - new Date(oldest.date + 'T12:00:00').getTime()) / 86400000;
      if (daysSpan >= 1) {
        const psiRise = newest.psi - oldest.psi;
        rate = +(psiRise / daysSpan).toFixed(2);
        if (rate > 0 && delta < PSI_CLEAN_THRESHOLD) {
          daysUntilClean = Math.max(1, Math.round((PSI_CLEAN_THRESHOLD - delta) / rate));
        }
      }
    }
  }

  let status;
  if (delta >= PSI_CLEAN_THRESHOLD) status = 'critical';
  else if (delta >= 5) status = 'caution';
  else if (delta >= 3) status = 'warn';
  else status = 'good';

  return { baseline, current, delta, status, rate, daysUntilClean };
};

/* ============================================================================
   POOL CLEANER TYPES — built-in cleaner = no manual vacuum needed
   ============================================================================ */
const CLEANER_OPTIONS = ['None', 'Robotic', 'Suction', 'Pressure', 'In-floor'];
const cleanerBadge = (cleaner) => {
  if (!cleaner || cleaner === 'None') return null;
  const config = {
    Robotic:   { label: 'Robotic',   color: '#7C3AED', bg: '#7C3AED15' },  // purple — electronics
    Suction:   { label: 'Suction',   color: '#0891B2', bg: '#0891B215' },  // teal
    Pressure:  { label: 'Pressure',  color: '#0369A1', bg: '#0369A115' },  // blue
    'In-floor':{ label: 'In-floor',  color: '#16A34A', bg: '#16A34A15' },  // green — built-in/permanent
  };
  return config[cleaner] || null;
};

/* ============================================================================
   REPAIR TYPES — standard pool industry repair catalog
   ============================================================================ */
const REPAIR_TYPES = [
  { id: 'acid_wash',       label: 'Acid Wash',              defaultPrice: 500,  icon: '🧪' },
  { id: 'motor_replace',   label: 'Motor Replacement',      defaultPrice: 450,  icon: '⚙️' },
  { id: 'basket_replace',  label: 'Basket Replacement',     defaultPrice: 45,   icon: '🧺' },
  { id: 'seal_replace',    label: 'Seal Replacement',       defaultPrice: 275,  icon: '🔧' },
  { id: 'de_grid_replace', label: 'DE Grid Replacement',    defaultPrice: 350,  icon: '🔲' },
  { id: 'cart_replace',    label: 'Cartridge Replacement',  defaultPrice: 175,  icon: '🔄' },
  { id: 'pump_replumb',    label: 'Pump Re-plumb',          defaultPrice: 350,  icon: '🔩' },
  { id: 'other',           label: 'Other / Custom',         defaultPrice: 0,    icon: '🛠️' },
];

const WATER_BODY_TYPES = [
  { id: 'pool',         label: 'Pool',           icon: '🏊' },
  { id: 'spa',          label: 'Spa / Hot Tub',  icon: '♨️' },
  { id: 'above_ground', label: 'Above Ground',   icon: '🟢' },
  { id: 'fountain',     label: 'Fountain',       icon: '⛲' },
  { id: 'pond',         label: 'Pond',           icon: '🌊' },
];

const REPAIR_STATUSES = [
  { id: 'quoted',      label: 'Quoted',      color: '#FF9500', bg: '#FFF3E0' },
  { id: 'approved',    label: 'Approved',    color: '#1A8CB8', bg: '#E5F2FF' },
  { id: 'in_progress', label: 'In Progress', color: '#7C3AED', bg: '#F3E8FF' },
  { id: 'completed',   label: 'Completed',   color: '#34C759', bg: '#E8F5E9' },
  { id: 'cancelled',   label: 'Cancelled',   color: '#FF3B30', bg: '#FFF5F5' },
];

const POOL_SHAPES = [
  { id: 'rectangular', label: 'Rectangular', icon: '▬', formula: (l, w, ds, dd) => l * w * ((+ds + +dd) / 2) * 7.5 },
  { id: 'oval',        label: 'Oval / Round', icon: '⬭', formula: (l, w, ds, dd) => l * w * ((+ds + +dd) / 2) * 5.9 },
  { id: 'kidney',      label: 'Kidney',       icon: '🫘', formula: (l, w, ds, dd) => l * w * ((+ds + +dd) / 2) * 6.7 },
  { id: 'freeform',    label: 'Freeform',     icon: '〰', formula: (l, w, ds, dd) => l * w * ((+ds + +dd) / 2) * 6.4 },
];

const calcPoolGallons = (shape, length, width, depthShallow, depthDeep) => {
  const s = POOL_SHAPES.find(p => p.id === shape) || POOL_SHAPES[0];
  const gallons = s.formula(+length || 0, +width || 0, +depthShallow || 0, +depthDeep || depthShallow || 0);
  return Math.round(gallons);
};

/* ============================================================================
   FILTER STATUS — last backwash + last filter clean per customer
   Filter clean is due every 6 months (180 days)
   ============================================================================ */
const FILTER_CLEAN_INTERVAL_DAYS = 180;

const filterStatus = (customerId, visits) => {
  const cv = visits.filter(v => v.customerId === customerId && v.completedAt);
  const lastBackwash = cv.filter(v => v.backwashed).sort((a, b) => b.date.localeCompare(a.date))[0];
  const lastClean = cv.filter(v => v.filterCleaned).sort((a, b) => b.date.localeCompare(a.date))[0];
  const daysSince = (iso) => Math.floor((Date.now() - new Date(iso + 'T12:00:00').getTime()) / 86400000);
  return {
    lastBackwashDate: lastBackwash?.date || null,
    daysSinceBackwash: lastBackwash ? daysSince(lastBackwash.date) : null,
    lastCleanDate: lastClean?.date || null,
    daysSinceClean: lastClean ? daysSince(lastClean.date) : null,
    cleanDue: !lastClean || daysSince(lastClean.date) >= FILTER_CLEAN_INTERVAL_DAYS,
    cleanDueIn: lastClean ? FILTER_CLEAN_INTERVAL_DAYS - daysSince(lastClean.date) : 0,
  };
};

/* ============================================================================
   GOOGLE MAPS — open today's route as multi-stop directions
   ============================================================================ */
const buildMapsUrl = (stops) => {
  if (!stops.length) return null;
  const addrs = stops.map(s => encodeURIComponent(`${s.address}, ${s.city}`));
  if (addrs.length === 1) return `https://www.google.com/maps/search/?api=1&query=${addrs[0]}`;
  const origin = addrs[0];
  const destination = addrs[addrs.length - 1];
  const waypoints = addrs.slice(1, -1).join('|');
  return `https://www.google.com/maps/dir/?api=1&origin=${origin}&destination=${destination}` + (waypoints ? `&waypoints=${waypoints}` : '');
};

const customerProfit = (customer, visits, chemicals, profile) => {
  const cv = visits.filter(v => v.customerId === customer.id && v.completedAt);
  const months = Math.max(1, cv.length / 4);
  const baseRevenue = customer.serviceRate * months;
  const rxDoses = cv.filter(v => v.poolRxDosed).length;
  const rxRevenue = rxDoses * (profile.poolRxPrice || 0);
  const filterCleans = cv.filter(v => v.filterCleaned).length;
  const filterCleanRevenue = filterCleans * (profile.filterCleanPrice || 0);
  const revenue = baseRevenue + rxRevenue + filterCleanRevenue;
  const chemCost = cv.reduce((s, v) => s + visitChemCost(v, chemicals), 0);
  const laborCost = cv.reduce((s, v) => s + visitLaborCost(v, profile.laborRate), 0);
  const profit = revenue - chemCost - laborCost;
  return { revenue, baseRevenue, rxRevenue, rxDoses, filterCleanRevenue, filterCleans, chemCost, laborCost, profit, visits: cv.length, margin: revenue ? (profit / revenue) * 100 : 0 };
};

const fontStack = { fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", system-ui, sans-serif' };
const greetingByTime = () => { const h = new Date().getHours(); if (h < 12) return 'Good morning'; if (h < 18) return 'Good afternoon'; return 'Good evening'; };

const inputCls = "w-full bg-[#F2F2F7] border-0 rounded-xl px-3.5 py-3 text-[15px] text-[#1D1D1F] placeholder-[#86868B] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30 transition";

/* ============================================================================
   ROOT APP
   ============================================================================ */
/* `export default` removed for browser-CDN host (see header comment).
   index.html mounts this component. Restore `export default` on Vite migration. */
function App() {
  const [db, setDb] = useState(null);
  const [tab, setTab] = useState('home');
  const [route, setRoute] = useState({ name: 'tab' });
  const [saveState, setSaveState] = useState('idle');
  const [session, setSession] = useState(null);
  const [authReady, setAuthReady] = useState(false);
  const [profileLoading, setProfileLoading] = useState(false);
  const saveTimer = useRef(null);
  const isFirstLoad = useRef(true);

  // Restore session on mount + subscribe to auth changes
  useEffect(() => {
    let mounted = true;
    (async () => {
      const restored = await supa.auth.restoreSession();
      if (mounted) { setSession(restored); setAuthReady(true); }
    })();
    const unsubscribe = supa.auth.onAuthChange((s) => { if (mounted) setSession(s); });
    return () => { mounted = false; unsubscribe(); };
  }, []);

  // Load DB on mount (local data still — customers/visits/chemicals)
  useEffect(() => {
    (async () => {
      let d = await storageGet();
      if (!d) { d = defaultDB(); await storageSet(d); }
      setDb(d);
    })();
  }, []);

  // When a session arrives, fetch the real profile from Supabase and merge
  // into local db.profile so the rest of the app keeps reading from db.profile.
  useEffect(() => {
    if (!session || !db) return;
    let cancelled = false;
    (async () => {
      setProfileLoading(true);
      const { data: p, error } = await supa.from('profiles').select('*').eq('id', session.user.id).single();
      if (cancelled) return;
      setProfileLoading(false);
      if (error || !p) return;
      setDb(prev => ({
        ...prev,
        profile: {
          ...prev.profile,
          name: p.owner_name || '',
          businessName: p.business_name || '',
          email: p.email || session.user.email || '',
          phone: p.phone || '',
          laborRate: p.labor_rate != null ? +p.labor_rate : 60,
          defaultVisitMins: p.default_visit_duration_min ?? 30,
          poolRxPrice: p.pool_rx_price != null ? +p.pool_rx_price : 50,
          onboarded: !!p.onboarded,
        },
      }));
    })();
    return () => { cancelled = true; };
  }, [session, db?.profile?.businessName === undefined]);

  // Debounced auto-save (local data only — profile flows through Supabase)
  useEffect(() => {
    if (!db) return;
    if (isFirstLoad.current) { isFirstLoad.current = false; return; }
    setSaveState('saving');
    if (saveTimer.current) clearTimeout(saveTimer.current);
    saveTimer.current = setTimeout(async () => {
      await storageSet(db);
      setSaveState('saved');
      setTimeout(() => setSaveState('idle'), 1200);
    }, 400);
    return () => saveTimer.current && clearTimeout(saveTimer.current);
  }, [db]);

  const updateDb = useCallback((mutator) => {
    setDb(prev => typeof mutator === 'function' ? { ...mutator(prev) } : { ...mutator });
  }, []);

  // Loading states
  if (!authReady || !db) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-[#F5F5F7]" style={fontStack}>
        <div className="w-2 h-2 rounded-full bg-[#1A8CB8] animate-pulse" />
      </div>
    );
  }

  // Not signed in → SignIn screen
  if (!session) return <SignIn />;

  // Signed in but profile still loading on first arrival
  if (profileLoading && !db.profile.businessName) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-[#F5F5F7]" style={fontStack}>
        <div className="w-2 h-2 rounded-full bg-[#1A8CB8] animate-pulse" />
      </div>
    );
  }

  if (!db.profile.onboarded) return <Onboarding session={session} updateDb={updateDb} />;
  if (route.name === 'visit') return <ServiceStop visitId={route.visitId} db={db} updateDb={updateDb} saveState={saveState} onClose={() => setRoute({ name: 'tab' })} />;
  if (route.name === 'customer') return <CustomerDetail customerId={route.customerId} db={db} updateDb={updateDb} onBack={() => setRoute({ name: 'tab' })} onStartVisit={(visitId) => setRoute({ name: 'visit', visitId })} />;
  if (route.name === 'newCustomer') return <CustomerForm db={db} updateDb={updateDb} onBack={() => setRoute({ name: 'tab' })} />;
  if (route.name === 'settings') return <SettingsView db={db} updateDb={updateDb} onBack={() => setRoute({ name: 'tab' })} />;

  const openSettings = () => setRoute({ name: 'settings' });

  return (
    <div className="min-h-screen bg-[#F5F5F7] text-[#1D1D1F]" style={fontStack}>
      <SaveIndicator state={saveState} />
      <main className="pb-24">
        {tab === 'home' && <HomeView db={db} updateDb={updateDb} setRoute={setRoute} setTab={setTab} openSettings={openSettings} />}
        {tab === 'customers' && <CustomersView db={db} setRoute={setRoute} openSettings={openSettings} />}
        {tab === 'reports' && <ReportsView db={db} openSettings={openSettings} />}
      </main>
      <BottomNav tab={tab} setTab={setTab} />
    </div>
  );
}

/* ============================================================================
   SIGN IN — first screen for unauthenticated users
   ============================================================================ */
function SignIn() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [mode, setMode] = useState('signin');  // 'signin' or 'signup'
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [info, setInfo] = useState(null);

  const submit = async () => {
    setError(null); setInfo(null);
    if (!email.trim() || !password) { setError('Email and password are required.'); return; }
    if (mode === 'signup' && password.length < 8) { setError('Password must be at least 8 characters.'); return; }
    setLoading(true);
    const fn = mode === 'signin' ? supa.auth.signIn : supa.auth.signUp;
    const { data, error } = await fn(email.trim(), password);
    setLoading(false);
    if (error) { setError(error.message || error.error_description || JSON.stringify(error)); return; }
    if (mode === 'signup' && !data?.access_token) {
      setInfo('Account created. Check your email for a confirmation link, then come back and sign in.');
      setMode('signin'); setPassword('');
    }
    // On success the auth listener swaps the screen automatically
  };

  return (
    <div className="min-h-screen bg-[#F5F5F7] flex items-center justify-center p-6" style={fontStack}>
      <div className="w-full max-w-md">
        <div className="text-center mb-10">
          <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] shadow-lg shadow-[#1A8CB8]/20 mb-5">
            <BookOpen className="w-8 h-8 text-white" strokeWidth={2.2} />
          </div>
          <h1 className="text-[32px] font-semibold tracking-tight">Routebook</h1>
          <p className="text-[#86868B] mt-2">{mode === 'signin' ? 'Sign in to your route' : 'Create your account'}</p>
        </div>
        <div className="bg-white rounded-2xl p-6 space-y-4 shadow-sm border border-black/5">
          <Field label="Email">
            <input value={email} onChange={e => setEmail(e.target.value)} type="email" autoComplete="email" placeholder="alex@example.com" className={inputCls} onKeyDown={e => e.key === 'Enter' && submit()} />
          </Field>
          <Field label="Password">
            <input value={password} onChange={e => setPassword(e.target.value)} type="password" autoComplete={mode === 'signin' ? 'current-password' : 'new-password'} placeholder="At least 8 characters" className={inputCls} onKeyDown={e => e.key === 'Enter' && submit()} />
          </Field>
          {error && (
            <div className="bg-[#FFF5F5] border-l-2 border-[#FF3B30] rounded px-3 py-2 text-[13px] text-[#C4302B]">{error}</div>
          )}
          {info && (
            <div className="bg-[#E5F2FF] border-l-2 border-[#1A8CB8] rounded px-3 py-2 text-[13px] text-[#0F6586]">{info}</div>
          )}
          <button onClick={submit} disabled={loading} className="w-full bg-[#1A8CB8] hover:bg-[#157aa1] disabled:bg-[#C7C7CC] text-white font-medium py-3.5 rounded-xl transition-colors">
            {loading ? '…' : (mode === 'signin' ? 'Sign in' : 'Create account')}
          </button>
          <button onClick={() => { setMode(m => m === 'signin' ? 'signup' : 'signin'); setError(null); setInfo(null); }} className="w-full text-center text-[14px] text-[#1A8CB8] font-medium pt-1">
            {mode === 'signin' ? 'Need an account? Sign up' : 'Already have an account? Sign in'}
          </button>
        </div>
        <p className="text-center text-xs text-[#86868B] mt-6">
          Sessions persist on this device. Sign out from Settings.
        </p>
      </div>
    </div>
  );
}

/* ============================================================================
   ONBOARDING — collects business details after first sign-up
   ============================================================================ */
function Onboarding({ session, updateDb }) {
  const [name, setName] = useState('');
  const [business, setBusiness] = useState('');
  const [email, setEmail] = useState(session?.user?.email || '');
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState(null);

  const submit = async () => {
    if (!name.trim() || !business.trim()) return;
    setSaving(true); setError(null);
    const { error: err } = await supa.from('profiles').update({
      owner_name: name.trim(),
      business_name: business.trim(),
      email: email.trim() || null,
      onboarded: true,
    }).eq('id', session.user.id);
    setSaving(false);
    if (err) {
      setError(err.message || JSON.stringify(err));
      return;
    }
    updateDb(d => ({ ...d, profile: { ...d.profile, name: name.trim(), businessName: business.trim(), email: email.trim(), onboarded: true } }));
  };

  return (
    <div className="min-h-screen bg-[#F5F5F7] flex items-center justify-center p-6" style={fontStack}>
      <div className="w-full max-w-md">
        <div className="text-center mb-10">
          <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] shadow-lg shadow-[#1A8CB8]/20 mb-5">
            <BookOpen className="w-8 h-8 text-white" strokeWidth={2.2} />
          </div>
          <h1 className="text-[32px] font-semibold tracking-tight">Welcome to Routebook</h1>
          <p className="text-[#86868B] mt-2">Set up your business in 30 seconds.</p>
        </div>
        <div className="bg-white rounded-2xl p-6 space-y-4 shadow-sm border border-black/5">
          <Field label="Your name"><input value={name} onChange={e => setName(e.target.value)} placeholder="Alex Rivera" className={inputCls} /></Field>
          <Field label="Business name"><input value={business} onChange={e => setBusiness(e.target.value)} placeholder="Rivera Pool Service" className={inputCls} /></Field>
          <Field label="Email"><input value={email} onChange={e => setEmail(e.target.value)} type="email" placeholder="alex@example.com" className={inputCls} /></Field>
          {error && <div className="bg-[#FFF5F5] border-l-2 border-[#FF3B30] rounded px-3 py-2 text-[13px] text-[#C4302B]">{error}</div>}
          <button onClick={submit} disabled={!name.trim() || !business.trim() || saving} className="w-full mt-2 bg-[#1A8CB8] hover:bg-[#157aa1] disabled:bg-[#C7C7CC] text-white font-medium py-3.5 rounded-xl transition-colors">
            {saving ? 'Saving…' : 'Get started'}
          </button>
        </div>
        <p className="text-center text-xs text-[#86868B] mt-6">Sample customers and visit history are pre-loaded so you can explore.</p>
      </div>
    </div>
  );
}

/* ============================================================================
   PRIMITIVES
   ============================================================================ */
function Field({ label, children }) {
  return <div><label className="block text-[13px] font-medium text-[#1D1D1F] mb-1.5">{label}</label>{children}</div>;
}
function Section({ title, subtitle, action, children }) {
  return (
    <section className="mb-7">
      <div className="flex items-end justify-between mb-2.5 px-1">
        <div>
          <h2 className="text-[20px] font-semibold tracking-tight">{title}</h2>
          {subtitle && <p className="text-[13px] text-[#86868B] mt-0.5">{subtitle}</p>}
        </div>
        {action}
      </div>
      {children}
    </section>
  );
}
function StatCard({ label, value, sub, tone }) {
  const t = tone === 'primary' ? 'text-[#1A8CB8]' : tone === 'success' ? 'text-[#1F8B3E]' : 'text-[#1D1D1F]';
  return (
    <div className="bg-white rounded-2xl p-3.5 border border-black/5">
      <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B]">{label}</div>
      <div className={`text-[22px] font-semibold tracking-tight mt-1 ${t}`}>{value}</div>
      <div className="text-[11px] text-[#86868B] mt-0.5">{sub}</div>
    </div>
  );
}
function Row({ label, value, last }) {
  return (
    <div className={`flex items-center justify-between px-4 py-3 ${last ? '' : 'border-b border-black/5'}`}>
      <span className="text-[14px] text-[#86868B]">{label}</span>
      <span className="text-[14px] text-[#1D1D1F] font-medium">{value || '—'}</span>
    </div>
  );
}

function SaveIndicator({ state }) {
  if (state === 'idle') return null;
  return (
    <div className="fixed top-4 right-4 z-50 pointer-events-none">
      <div className={`px-3 py-1.5 rounded-full text-[12px] font-medium flex items-center gap-1.5 backdrop-blur-md ${state === 'saving' ? 'bg-white/80 text-[#86868B]' : 'bg-[#34C759]/15 text-[#1F8B3E]'} shadow-sm border border-black/5`}>
        {state === 'saving' ? <><div className="w-1.5 h-1.5 rounded-full bg-[#86868B] animate-pulse" />Saving</> : <><Check className="w-3 h-3" strokeWidth={3} />Saved</>}
      </div>
    </div>
  );
}

function BottomNav({ tab, setTab }) {
  const items = [
    { key: 'home', label: 'Today', icon: Home },
    { key: 'customers', label: 'Customers', icon: Users },
    { key: 'reports', label: 'Reports', icon: BarChart3 },
  ];
  return (
    <nav className="fixed bottom-0 inset-x-0 bg-white/85 backdrop-blur-xl border-t border-black/5 z-40">
      <div className="max-w-2xl mx-auto px-2 py-2 flex justify-around">
        {items.map(it => {
          const active = tab === it.key;
          const Icon = it.icon;
          return (
            <button key={it.key} onClick={() => setTab(it.key)} className={`flex-1 flex flex-col items-center gap-0.5 py-2 rounded-xl ${active ? 'text-[#1A8CB8]' : 'text-[#86868B]'}`}>
              <Icon className="w-[22px] h-[22px]" strokeWidth={active ? 2.2 : 1.8} />
              <span className="text-[10px] font-medium tracking-tight">{it.label}</span>
            </button>
          );
        })}
      </div>
    </nav>
  );
}

/* Reusable gear button for top-right of main views */
function GearButton({ onClick }) {
  return (
    <button onClick={onClick} aria-label="Settings" className="w-10 h-10 rounded-full bg-white border border-black/5 flex items-center justify-center text-[#1D1D1F] hover:bg-[#FAFAFA] active:bg-[#F2F2F7] transition-colors">
      <SettingsIcon className="w-[18px] h-[18px]" strokeWidth={1.8} />
    </button>
  );
}

/* Pool RX verified-style badge — solid blue with white check, easy to spot at a glance */
function PoolRxBadge({ size = 'sm' }) {
  const cls = size === 'lg'
    ? 'text-[11px] px-2 py-1 gap-1.5'
    : 'text-[10px] px-1.5 py-0.5 gap-1';
  const iconSize = size === 'lg' ? 'w-3.5 h-3.5' : 'w-3 h-3';
  return (
    <span className={`font-semibold uppercase tracking-wider rounded-md flex items-center flex-shrink-0 text-white shadow-sm ${cls}`} style={{ backgroundColor: '#1A8CB8' }}>
      <BadgeCheck className={iconSize} strokeWidth={2.5} />
      Pool RX
    </span>
  );
}

/* ============================================================================
   HOME — Today's stops + week stats
   ============================================================================ */
function HomeView({ db, updateDb, setRoute, setTab, openSettings }) {
  const today = todayISO();
  const todayVisits = db.visits.filter(v => v.date === today);
  const [showMileageDetails, setShowMileageDetails] = useState(false);
  const completedToday = todayVisits.filter(v => v.completedAt).length;
  const incompleteToday = todayVisits.filter(v => !v.completedAt).map(v => db.customers.find(c => c.id === v.customerId)).filter(Boolean);
  const mapsUrl = buildMapsUrl(incompleteToday);

  const last7 = useMemo(() => {
    const startISO = offsetISO(-6);
    return db.visits.filter(v => v.date >= startISO);
  }, [db.visits]);

  const weekRevenue = useMemo(() => {
    const ids = new Set(last7.map(v => v.customerId));
    return Array.from(ids).reduce((s, id) => s + (db.customers.find(x => x.id === id)?.serviceRate || 0), 0);
  }, [last7, db.customers]);

  const weekCosts = useMemo(() =>
    last7.reduce((s, v) => s + visitChemCost(v, db.chemicals) + visitLaborCost(v, db.profile.laborRate), 0),
    [last7, db.chemicals, db.profile.laborRate]);

  const startNewVisit = (customerId) => {
    const visit = {
      id: uid('v'), customerId, date: today, durationMin: db.profile.defaultVisitMins,
      chemicalsUsed: [], waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' },
      checklist: { skimmed: false, vacuumed: false, brushed: false, basketsEmptied: false, filterChecked: false, waterLevel: false, equipmentInspected: false },
      backwashed: false, filterCleaned: false, filterPsi: '', algaeLevel: 0, poolRxDosed: false,
      repairsNeeded: '', notes: '', invoiced: false, paid: false, completedAt: null, mileage: null,
    };
    updateDb(d => ({ ...d, visits: [...d.visits, visit] }));
    setRoute({ name: 'visit', visitId: visit.id });
  };

  // Quick complete — copy carry-over fields from the most recent completed visit and mark done
  const quickComplete = async (visit) => {
    const last = db.visits
      .filter(x => x.customerId === visit.customerId && x.completedAt && x.id !== visit.id)
      .sort((a, b) => b.date.localeCompare(a.date))[0];
    if (!last) return;
    const carryOver = {
      waterReadings: { ...last.waterReadings },
      chemicalsUsed: last.chemicalsUsed.map(c => ({ ...c })),
      checklist: { skimmed: true, vacuumed: true, brushed: true, basketsEmptied: true, filterChecked: true, waterLevel: true, equipmentInspected: true },
      algaeLevel: last.algaeLevel || 0,
      filterPsi: last.filterPsi || '',
      // Don't carry over event flags — these are specific actions, not routine
      backwashed: false, filterCleaned: false, poolRxDosed: false,
      // Reset notes/repairs — these are situational
      repairsNeeded: '', notes: '',
      completedAt: new Date().toISOString(),
      invoiced: db.settings.squareConnected,
      mileage: null,
    };
    updateDb(d => ({
      ...d,
      visits: d.visits.map(v => v.id === visit.id ? { ...v, ...carryOver } : v),
    }));
    // Compute mileage async after marking complete
    const miles = await computeVisitMileage(visit, db, updateDb);
    if (miles != null) {
      updateDb(d => ({
        ...d,
        visits: d.visits.map(v => v.id === visit.id ? { ...v, mileage: miles } : v),
      }));
    }
  };

  const due = useMemo(() => {
    return db.customers
      .map(c => {
        const last = db.visits.filter(v => v.customerId === c.id && v.completedAt).sort((a, b) => b.date.localeCompare(a.date))[0];
        const lastDate = last?.date || c.addedDate;
        const days = Math.floor((Date.now() - new Date(lastDate + 'T12:00:00').getTime()) / 86400000);
        return { customer: c, days };
      })
      .filter(x => x.days >= 6 && !todayVisits.some(v => v.customerId === x.customer.id))
      .sort((a, b) => b.days - a.days);
  }, [db, todayVisits]);

  // Filter clean reminders
  const filterDue = useMemo(() => {
    return db.customers
      .map(c => ({ c, status: filterStatus(c.id, db.visits) }))
      .filter(x => x.status.cleanDue)
      .sort((a, b) => (b.status.daysSinceClean || 999) - (a.status.daysSinceClean || 999));
  }, [db.customers, db.visits]);

  // Pool RX due reminders — enrolled customers within 30d of next dose, or already past
  const poolRxDue = useMemo(() => {
    return db.customers
      .filter(c => c.poolRx)
      .map(c => ({ c, rx: poolRxStatus(c.id, db.visits) }))
      .filter(x => x.rx.dueInDays <= 30)
      .sort((a, b) => a.rx.dueInDays - b.rx.dueInDays);
  }, [db.customers, db.visits]);

  // PSI clean predicted within 7 days
  const psiPredicted = useMemo(() => {
    return db.customers
      .map(c => ({ c, pred: predictFilterClean(c.id, db.visits, c.filterPsiBaseline) }))
      .filter(x => x.pred && x.pred.daysUntilClean != null && x.pred.daysUntilClean <= 7 && x.pred.status !== 'critical')
      .sort((a, b) => (a.pred.daysUntilClean || 99) - (b.pred.daysUntilClean || 99));
  }, [db.customers, db.visits]);

  return (
    <div className="max-w-2xl mx-auto px-5 pt-8">
      <header className="mb-7">
        <div className="flex items-center justify-between mb-5">
          <button onClick={() => setRoute({ name: 'newCustomer' })} className="h-10 px-3.5 rounded-full bg-white border border-black/5 flex items-center gap-1.5 text-[#1A8CB8] hover:bg-[#FAFAFA] active:bg-[#F2F2F7] transition-colors">
            <Plus className="w-4 h-4" strokeWidth={2.5} />
            <span className="text-[14px] font-medium">Add customer</span>
          </button>
          <button onClick={openSettings} className="flex items-center gap-2 h-10 pl-3 pr-1.5 rounded-full bg-white border border-black/5 hover:bg-[#FAFAFA] active:bg-[#F2F2F7] transition-colors" title="My Business">
            <span className="text-[13px] font-medium text-[#1D1D1F] max-w-[120px] truncate">{db.profile.businessName || 'My Business'}</span>
            <div className="w-7 h-7 rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center text-[10px] font-semibold flex-shrink-0">
              {(db.profile.businessName || 'MB').split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
            </div>
          </button>
        </div>
        <div>
          <p className="text-[12px] font-medium uppercase tracking-wider text-[#1A8CB8]">{dayName(today)}, {shortDate(today)}</p>
          <h1 className="text-[32px] font-semibold tracking-tight leading-tight mt-1">{greetingByTime()}, {db.profile.name.split(' ')[0]}</h1>
        </div>
      </header>

      <div className="grid grid-cols-3 gap-3 mb-7">
        <StatCard label="This week" value={fmt0(weekRevenue)} sub="Revenue" tone="primary" />
        <StatCard label="Costs" value={fmt0(weekCosts)} sub="Chems + labor" />
        <StatCard label="Profit" value={fmt0(weekRevenue - weekCosts)} sub={`${weekRevenue ? Math.round(((weekRevenue - weekCosts) / weekRevenue) * 100) : 0}% margin`} tone="success" />
      </div>

      <Section title="Today's stops" subtitle={todayVisits.some(v => !v.completedAt) ? 'Tap a stop to log details · or use the quick-check icon if no changes from last visit' : null} action={
        <div className="flex items-center gap-3">
          {todayVisits.length > 0 && <span className="text-[13px] text-[#86868B]">{completedToday} of {todayVisits.length}</span>}
          {mapsUrl && (
            <a href={mapsUrl} target="_blank" rel="noopener noreferrer" className="text-[13px] font-medium text-[#1A8CB8] hover:text-[#157aa1] flex items-center gap-1">
              <Zap className="w-3.5 h-3.5" strokeWidth={2.5} />Route
            </a>
          )}
        </div>
      }>
        {todayVisits.length === 0 ? (
          <div className="bg-white rounded-2xl border border-black/5 px-5 py-8 text-center">
            <div className="inline-flex w-12 h-12 rounded-full bg-[#F2F2F7] items-center justify-center mb-3"><Calendar className="w-5 h-5 text-[#86868B]" /></div>
            <p className="font-medium text-[15px]">No stops scheduled today</p>
            <p className="text-[13px] text-[#86868B] mt-1">Tap "Start" on a customer below to begin a visit.</p>
          </div>
        ) : (
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {todayVisits.map((v, i) => {
              const c = db.customers.find(x => x.id === v.customerId);
              if (!c) return null;
              const done = !!v.completedAt;
              const cBadge = cleanerBadge(c.cleaner);
              const hasLastVisit = !!db.visits.find(x => x.customerId === c.id && x.completedAt && x.id !== v.id);
              return (
                <div
                  key={v.id}
                  onClick={() => setRoute({ name: 'visit', visitId: v.id })}
                  onKeyDown={(e) => { if (e.key === 'Enter') setRoute({ name: 'visit', visitId: v.id }); }}
                  role="button"
                  tabIndex={0}
                  className={`w-full flex items-center gap-3 px-4 py-3.5 text-left hover:bg-[#F5F5F7] active:bg-[#EFEFF0] transition-colors cursor-pointer ${i > 0 ? 'border-t border-black/5' : ''}`}
                >
                  <div className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 ${done ? 'bg-[#34C759]' : 'border-[1.5px] border-[#C7C7CC] bg-white'}`}>
                    {done && <Check className="w-4 h-4 text-white" strokeWidth={3} />}
                  </div>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2 min-w-0">
                      <div className={`font-medium text-[15px] truncate ${done ? 'text-[#86868B] line-through' : 'text-[#1D1D1F]'}`}>{c.name}</div>
                      {c.poolRx && <PoolRxBadge />}
                      {cBadge && (
                        <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md flex-shrink-0" style={{ color: cBadge.color, backgroundColor: cBadge.bg }}>{cBadge.label}</span>
                      )}
                    </div>
                    <div className="text-[13px] text-[#86868B] truncate">{c.address}</div>
                  </div>
                  <div className="text-right flex-shrink-0 mr-1">
                    <div className="text-[14px] font-medium text-[#1D1D1F]">{fmt0(c.serviceRate)}</div>
                    <div className="text-[11px] text-[#86868B]">{c.poolSize.toLocaleString()} gal</div>
                  </div>
                  {!done && hasLastVisit && (
                    <button
                      onClick={(e) => { e.stopPropagation(); quickComplete(v); }}
                      className="w-9 h-9 rounded-full bg-[#1A8CB8]/10 hover:bg-[#1A8CB8]/20 active:bg-[#1A8CB8]/30 flex items-center justify-center text-[#1A8CB8] flex-shrink-0 transition-colors"
                      aria-label="Quick complete using last visit's data"
                      title="Same as last visit"
                    >
                      <CheckCheck className="w-[18px] h-[18px]" strokeWidth={2.5} />
                    </button>
                  )}
                  <ChevronRight className="w-4 h-4 text-[#C7C7CC] flex-shrink-0" />
                </div>
              );
            })}
          </div>
        )}
      </Section>

      {due.length > 0 && (
        <Section title="Due for service" subtitle="Customers you haven't seen in a week+">
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {due.slice(0, 4).map((d, i) => (
              <div key={d.customer.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="w-9 h-9 rounded-full bg-[#FF9500]/15 text-[#C77400] flex items-center justify-center flex-shrink-0"><Clock className="w-4 h-4" /></div>
                <div className="flex-1 min-w-0">
                  <div className="font-medium text-[15px]">{d.customer.name}</div>
                  <div className="text-[13px] text-[#86868B]">{d.days} days since last visit</div>
                </div>
                <button onClick={() => startNewVisit(d.customer.id)} className="bg-[#1A8CB8] hover:bg-[#157aa1] text-white text-[13px] font-medium px-3.5 py-1.5 rounded-full flex items-center gap-1">
                  <Plus className="w-3.5 h-3.5" strokeWidth={2.5} />Start
                </button>
              </div>
            ))}
          </div>
        </Section>
      )}

      {filterDue.length > 0 && (
        <Section title="Filter clean due" subtitle="Every 6 months — tap to start a visit and log it">
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {filterDue.slice(0, 4).map((d, i) => (
              <div key={d.c.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="w-9 h-9 rounded-full bg-[#FF3B30]/12 text-[#C4302B] flex items-center justify-center flex-shrink-0"><Beaker className="w-4 h-4" /></div>
                <div className="flex-1 min-w-0">
                  <div className="font-medium text-[15px]">{d.c.name}</div>
                  <div className="text-[13px] text-[#86868B]">{d.c.filterType || 'Cartridge'} filter · {d.status.lastCleanDate ? `Last cleaned ${d.status.daysSinceClean}d ago` : 'Never logged'}</div>
                </div>
                <button onClick={() => startNewVisit(d.c.id)} className="bg-white border border-black/5 hover:bg-[#F5F5F7] text-[#1A8CB8] text-[13px] font-medium px-3 py-1.5 rounded-full">Start</button>
              </div>
            ))}
          </div>
        </Section>
      )}

      {psiPredicted.length > 0 && (
        <Section title="Filter clean predicted" subtitle="Based on rising pressure trend — schedule ahead">
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {psiPredicted.slice(0, 4).map((d, i) => (
              <div key={d.c.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="w-9 h-9 rounded-full bg-[#FF9500]/15 text-[#C77400] flex items-center justify-center flex-shrink-0"><Gauge className="w-4 h-4" /></div>
                <div className="flex-1 min-w-0">
                  <div className="font-medium text-[15px]">{d.c.name}</div>
                  <div className="text-[13px] text-[#86868B]">~{d.pred.daysUntilClean} day{d.pred.daysUntilClean !== 1 ? 's' : ''} · Δ +{d.pred.delta} PSI · rising {d.pred.rate.toFixed(2)}/day</div>
                </div>
                <button onClick={() => startNewVisit(d.c.id)} className="bg-white border border-black/5 hover:bg-[#F5F5F7] text-[#1A8CB8] text-[13px] font-medium px-3 py-1.5 rounded-full">Start</button>
              </div>
            ))}
          </div>
        </Section>
      )}

      {poolRxDue.length > 0 && (
        <Section title="Pool RX due" subtitle="Biannual phosphate program — billable add-on">
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {poolRxDue.slice(0, 4).map((d, i) => (
              <div key={d.c.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="w-9 h-9 rounded-full flex items-center justify-center flex-shrink-0 text-white" style={{ backgroundColor: '#1A8CB8' }}><BadgeCheck className="w-4 h-4" strokeWidth={2.5} /></div>
                <div className="flex-1 min-w-0">
                  <div className="font-medium text-[15px]">{d.c.name}</div>
                  <div className="text-[13px] text-[#86868B]">
                    {d.rx.lastDate ? `Last ${d.rx.daysSince}d ago` : 'Never dosed'}
                    {' · '}
                    {d.rx.due ? <span className="text-[#1A8CB8] font-medium">Due now</span> : `Due in ${d.rx.dueInDays}d`}
                  </div>
                </div>
                <button onClick={() => startNewVisit(d.c.id)} className="bg-white border border-black/5 hover:bg-[#F5F5F7] text-[#1A8CB8] text-[13px] font-medium px-3 py-1.5 rounded-full">Start</button>
              </div>
            ))}
          </div>
        </Section>
      )}

      {/* Daily mileage tracking — only shows when mileage tracking is enabled and there are completed stops */}
      {db.settings.mileageTrackingEnabled && (() => {
        const mileData = calcDailyMileage(todayVisits, db.customers, db.profile);
        const hasBusinessAddr = db.profile.businessAddress && db.profile.businessCity;
        if (mileData.stops === 0 && !hasBusinessAddr) return null;
        const summary = calcMileageSummary(db.visits);
        const IRS_RATE = 0.70;
        const monthNames = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
        return (
          <Section title="Mileage" subtitle="Estimated driving for tax records">
            <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
              {!hasBusinessAddr ? (
                <div className="text-center py-5 px-5">
                  <div className="inline-flex w-10 h-10 rounded-full bg-[#F2F2F7] items-center justify-center mb-2">
                    <Navigation className="w-5 h-5 text-[#86868B]" />
                  </div>
                  <p className="text-[14px] font-medium text-[#1D1D1F]">Set your business address</p>
                  <p className="text-[12px] text-[#86868B] mt-1">Go to Settings → Profile to add your business address for mileage tracking.</p>
                </div>
              ) : mileData.stops === 0 && summary.monthMiles === 0 ? (
                <div className="text-center py-5 px-5">
                  <div className="inline-flex w-10 h-10 rounded-full bg-[#F2F2F7] items-center justify-center mb-2">
                    <Navigation className="w-5 h-5 text-[#86868B]" />
                  </div>
                  <p className="text-[14px] text-[#86868B]">Complete a stop to start tracking mileage</p>
                </div>
              ) : (
                <>
                  {/* Today row */}
                  <button onClick={() => setShowMileageDetails(s => !s)} className="w-full px-5 py-4 flex items-center gap-4 hover:bg-[#FAFAFA] transition-colors">
                    <div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-[#34C759]/15 to-[#34C759]/5 flex items-center justify-center flex-shrink-0">
                      <Navigation className="w-6 h-6 text-[#1F8B3E]" />
                    </div>
                    <div className="flex-1 min-w-0 text-left">
                      <div className="text-[22px] font-semibold tracking-tight text-[#1D1D1F] leading-none">
                        {mileData.totalMiles} <span className="text-[14px] font-medium text-[#86868B]">mi today</span>
                      </div>
                      <div className="text-[12px] text-[#86868B] mt-1 flex items-center gap-2 flex-wrap">
                        <span>{mileData.stops} stop{mileData.stops !== 1 ? 's' : ''}</span>
                        {mileData.returnMiles != null && <span>· {mileData.returnMiles} mi return</span>}
                      </div>
                    </div>
                    <div className="text-right flex-shrink-0 mr-1">
                      <div className="text-[14px] font-semibold text-[#1F8B3E]">${(mileData.totalMiles * IRS_RATE).toFixed(2)}</div>
                      <div className="text-[10px] text-[#86868B]">@ $0.70/mi</div>
                    </div>
                    <ChevronDown className={`w-4 h-4 text-[#C7C7CC] transition-transform ${showMileageDetails ? 'rotate-180' : ''}`} />
                  </button>

                  {/* Expanded monthly/yearly summary */}
                  {showMileageDetails && (
                    <div className="border-t border-black/5">
                      {/* Month & Year summary row */}
                      <div className="grid grid-cols-2 divide-x divide-black/5">
                        <div className="px-5 py-3.5 text-center">
                          <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B] mb-1">This month</div>
                          <div className="text-[18px] font-semibold text-[#1D1D1F]">{summary.monthMiles} <span className="text-[12px] text-[#86868B] font-medium">mi</span></div>
                          <div className="text-[11px] text-[#1F8B3E] font-medium">${(summary.monthMiles * IRS_RATE).toFixed(2)}</div>
                          <div className="text-[10px] text-[#86868B]">{summary.monthStops} stops</div>
                        </div>
                        <div className="px-5 py-3.5 text-center">
                          <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B] mb-1">{new Date().getFullYear()} total</div>
                          <div className="text-[18px] font-semibold text-[#1D1D1F]">{summary.yearMiles} <span className="text-[12px] text-[#86868B] font-medium">mi</span></div>
                          <div className="text-[11px] text-[#1F8B3E] font-medium">${(summary.yearMiles * IRS_RATE).toFixed(2)}</div>
                          <div className="text-[10px] text-[#86868B]">{summary.yearStops} stops</div>
                        </div>
                      </div>
                      {/* Monthly breakdown for current year */}
                      {Object.keys(summary.monthlyBreakdown).length > 0 && (
                        <div className="border-t border-black/5 px-5 py-3">
                          <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B] mb-2">Monthly breakdown</div>
                          {Object.entries(summary.monthlyBreakdown).sort((a, b) => b[0].localeCompare(a[0])).map(([month, data]) => (
                            <div key={month} className="flex items-center justify-between py-1.5">
                              <span className="text-[13px] text-[#1D1D1F]">{monthNames[parseInt(month.slice(5)) - 1]} {month.slice(0, 4)}</span>
                              <div className="flex items-center gap-3">
                                <span className="text-[12px] text-[#86868B]">{data.stops} stops</span>
                                <span className="text-[13px] font-medium text-[#1D1D1F] w-16 text-right">{data.miles.toFixed(1)} mi</span>
                                <span className="text-[12px] font-medium text-[#1F8B3E] w-14 text-right">${(data.miles * IRS_RATE).toFixed(2)}</span>
                              </div>
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                  )}
                </>
              )}
            </div>
          </Section>
        );
      })()}
      {/* Overdue invoices card */}
      {(() => {
        const overdue = (db.invoices || []).filter(inv => {
          if (inv.status !== 'sent' || inv.paidAt) return false;
          const sentDate = new Date(inv.sentAt || inv.date);
          const daysSince = Math.floor((Date.now() - sentDate.getTime()) / 86400000);
          return daysSince >= (db.settings.invoiceReminderDays || 14);
        });
        if (overdue.length === 0) return null;
        const overdueTotal = overdue.reduce((s, i) => s + (i.total || 0), 0);
        return (
          <Section title="Overdue invoices" subtitle={`${overdue.length} unpaid past ${db.settings.invoiceReminderDays || 14} days`}>
            <div className="bg-white rounded-2xl border border-[#FF3B30]/20 overflow-hidden">
              {overdue.map((inv, i) => {
                const customer = db.customers.find(c => c.id === inv.customerId);
                const sentDate = new Date(inv.sentAt || inv.date);
                const daysSince = Math.floor((Date.now() - sentDate.getTime()) / 86400000);
                return (
                  <div key={inv.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                    <div className="w-8 h-8 rounded-full bg-[#FF3B30]/10 flex items-center justify-center flex-shrink-0">
                      <AlertCircle className="w-4 h-4 text-[#FF3B30]" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <div className="text-[13px] font-medium truncate">{customer?.name || 'Unknown'}</div>
                      <div className="text-[11px] text-[#86868B]">{daysSince}d overdue · sent {shortDate(inv.sentAt || inv.date)}</div>
                    </div>
                    <div className="text-right">
                      <div className="text-[14px] font-semibold text-[#FF3B30]">{fmt(inv.total)}</div>
                      {inv.lastReminder ? (
                        <div className="text-[9px] text-[#86868B]">Reminded</div>
                      ) : (
                        <button onClick={() => {
                          updateDb(d => ({ ...d, invoices: d.invoices.map(x => x.id === inv.id ? { ...x, lastReminder: new Date().toISOString() } : x) }));
                        }} className="text-[10px] text-[#1A8CB8] font-medium">Send reminder</button>
                      )}
                    </div>
                  </div>
                );
              })}
              <div className="border-t border-black/5 px-4 py-2.5 flex items-center justify-between bg-[#FFF5F5]">
                <span className="text-[12px] font-medium text-[#FF3B30]">Total outstanding</span>
                <span className="text-[14px] font-semibold text-[#FF3B30]">{fmt(overdueTotal)}</span>
              </div>
            </div>
          </Section>
        );
      })()}
    </div>
  );
}

/* ============================================================================
   CUSTOMERS LIST
   ============================================================================ */
function CustomersView({ db, setRoute, openSettings }) {
  const [q, setQ] = useState('');
  const filtered = db.customers.filter(c => {
    if (!q) return true;
    const needle = q.toLowerCase();
    // Strip non-digits from search and from phone for digit-only phone matches
    const needleDigits = needle.replace(/\D/g, '');
    const phoneDigits = (c.phone || '').replace(/\D/g, '');
    return c.name.toLowerCase().includes(needle)
      || c.address.toLowerCase().includes(needle)
      || (c.email || '').toLowerCase().includes(needle)
      || (c.phone || '').toLowerCase().includes(needle)
      || (needleDigits.length >= 3 && phoneDigits.includes(needleDigits));
  });
  return (
    <div className="max-w-2xl mx-auto px-5 pt-8">
      <header className="mb-5 flex items-end justify-between gap-3">
        <div>
          <h1 className="text-[32px] font-semibold tracking-tight leading-tight">Customers</h1>
          <p className="text-[13px] text-[#86868B] mt-1">{db.customers.length} active</p>
        </div>
        <div className="flex items-center gap-2">
          <button onClick={() => setRoute({ name: 'newCustomer' })} className="bg-[#1A8CB8] hover:bg-[#157aa1] text-white w-10 h-10 rounded-full flex items-center justify-center" aria-label="Add customer">
            <Plus className="w-5 h-5" strokeWidth={2.5} />
          </button>
          <GearButton onClick={openSettings} />
        </div>
      </header>
      <div className="relative mb-4">
        <Search className="w-4 h-4 text-[#86868B] absolute left-3.5 top-1/2 -translate-y-1/2" />
        <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search name, address, phone, or email" className="w-full bg-[#E9E9EB] border-0 rounded-xl pl-9 pr-4 py-2.5 text-[15px] placeholder-[#86868B] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30" />
      </div>
      {filtered.length === 0 ? (
        <div className="text-center py-16 text-[#86868B] text-[15px]">No customers found.</div>
      ) : (
        <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
          {filtered.map((c, i) => {
            const lastVisit = db.visits.filter(v => v.customerId === c.id && v.completedAt).sort((a, b) => b.date.localeCompare(a.date))[0];
            return (
              <button key={c.id} onClick={() => setRoute({ name: 'customer', customerId: c.id })} className={`w-full flex items-center gap-3 px-4 py-3.5 text-left hover:bg-[#F5F5F7] active:bg-[#EFEFF0] ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="w-10 h-10 rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center font-medium text-[14px] flex-shrink-0">
                  {c.name.split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
                </div>
                <div className="flex-1 min-w-0">
                  <div className="font-medium text-[15px]">{c.name}</div>
                  <div className="text-[13px] text-[#86868B] truncate">{c.address} · {c.serviceFreq}</div>
                </div>
                <div className="text-right flex-shrink-0 mr-1">
                  <div className="text-[14px] font-medium">{fmt0(c.serviceRate)}/mo</div>
                  <div className="text-[11px] text-[#86868B]">{lastVisit ? `Last: ${shortDate(lastVisit.date)}` : 'No visits'}</div>
                </div>
                <ChevronRight className="w-4 h-4 text-[#C7C7CC] flex-shrink-0" />
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

/* ============================================================================
   CUSTOMER DETAIL
   ============================================================================ */
function CustomerDetail({ customerId, db, updateDb, onBack, onStartVisit }) {
  const c = db.customers.find(x => x.id === customerId);
  const [editing, setEditing] = useState(false);
  const [detailTab, setDetailTab] = useState('visits');
  const [showRepairForm, setShowRepairForm] = useState(false);
  const [editingRepairId, setEditingRepairId] = useState(null);
  const [newRepair, setNewRepair] = useState({ type: 'acid_wash', description: '', laborHours: 1, partsCost: 0, totalPrice: 500, status: 'quoted', notes: '' });
  const [showAddWaterBody, setShowAddWaterBody] = useState(false);
  const [editingWaterBodyId, setEditingWaterBodyId] = useState(null);
  const [newWaterBody, setNewWaterBody] = useState({ name: '', type: 'spa', size: 500, poolType: 'Chlorine', filterType: 'Cartridge', address: '' });
  const [showPoolCalc, setShowPoolCalc] = useState(false);
  const [calcDims, setCalcDims] = useState({ shape: c?.poolShape || 'rectangular', length: c?.poolLength || '', width: c?.poolWidth || '', depthShallow: c?.poolDepthShallow || '', depthDeep: c?.poolDepthDeep || '' });
  const photoInputRef = useRef(null);
  const [showCustomInvoice, setShowCustomInvoice] = useState(false);
  const [customInvoiceItems, setCustomInvoiceItems] = useState([{ label: '', amount: 0 }]);
  const repairPhotoInputRef = useRef(null);
  const [repairPhotoTarget, setRepairPhotoTarget] = useState(null); // { repairId, tag: 'before'|'after' }
  if (!c) return null;
  const visits = db.visits.filter(v => v.customerId === customerId).sort((a, b) => b.date.localeCompare(a.date));
  const repairs = (db.repairs || []).filter(r => r.customerId === customerId).sort((a, b) => (b.date || '').localeCompare(a.date || ''));
  const stats = customerProfit(c, db.visits, db.chemicals, db.profile);

  const saveRepair = () => {
    const repairType = REPAIR_TYPES.find(t => t.id === newRepair.type);
    const repair = {
      ...newRepair, id: uid('rep'), customerId: c.id, date: todayISO(),
      typeLabel: repairType?.label || 'Other', icon: repairType?.icon || '🛠️',
      invoiced: false, paid: false, completedAt: null,
    };
    updateDb(d => ({ ...d, repairs: [...(d.repairs || []), repair] }));
    setShowRepairForm(false);
    setNewRepair({ type: 'acid_wash', description: '', laborHours: 1, partsCost: 0, totalPrice: 500, status: 'quoted', notes: '' });
  };

  const updateRepairStatus = (repairId, status) => {
    const patch = { status };
    if (status === 'completed') patch.completedAt = new Date().toISOString();
    updateDb(d => ({ ...d, repairs: (d.repairs || []).map(r => r.id === repairId ? { ...r, ...patch } : r) }));
  };

  const deleteRepair = (repairId) => {
    if (!confirm('Delete this repair?')) return;
    updateDb(d => ({ ...d, repairs: (d.repairs || []).filter(r => r.id !== repairId) }));
    if (editingRepairId === repairId) setEditingRepairId(null);
  };

  const updateRepairField = (repairId, patch) => {
    updateDb(d => ({ ...d, repairs: (d.repairs || []).map(r => r.id === repairId ? { ...r, ...patch } : r) }));
  };

  const addWaterBody = () => {
    const wb = { ...newWaterBody, id: uid('wb') };
    if (!wb.name) wb.name = WATER_BODY_TYPES.find(t => t.id === wb.type)?.label || 'Water Body';
    updateField({ waterBodies: [...(c.waterBodies || []), wb] });
    setShowAddWaterBody(false);
    setNewWaterBody({ name: '', type: 'spa', size: 500, poolType: 'Chlorine', filterType: 'Cartridge', address: '' });
  };

  const updateWaterBody = (wbId, patch) => {
    updateField({ waterBodies: (c.waterBodies || []).map(w => w.id === wbId ? { ...w, ...patch } : w) });
  };

  const removeWaterBody = (wbId) => {
    if (!confirm('Remove this water body?')) return;
    updateField({ waterBodies: (c.waterBodies || []).filter(w => w.id !== wbId) });
    if (editingWaterBodyId === wbId) setEditingWaterBodyId(null);
  };

  const startVisit = () => {
    const visit = {
      id: uid('v'), customerId: c.id, date: todayISO(), durationMin: db.profile.defaultVisitMins,
      chemicalsUsed: [], waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' },
      checklist: { skimmed: false, vacuumed: false, brushed: false, basketsEmptied: false, filterChecked: false, waterLevel: false, equipmentInspected: false },
      backwashed: false, filterCleaned: false, filterPsi: '', algaeLevel: 0, poolRxDosed: false,
      repairsNeeded: '', notes: '', invoiced: false, paid: false, completedAt: null, mileage: null,
    };
    updateDb(d => ({ ...d, visits: [...d.visits, visit] }));
    onStartVisit(visit.id);
  };

  const removeCustomer = () => {
    if (!confirm(`Remove ${c.name} and all their visit history?`)) return;
    updateDb(d => ({ ...d, customers: d.customers.filter(x => x.id !== c.id), visits: d.visits.filter(v => v.customerId !== c.id), repairs: (d.repairs || []).filter(r => r.customerId !== c.id) }));
    onBack();
  };

  const updateField = (patch) => updateDb(d => ({ ...d, customers: d.customers.map(x => x.id === c.id ? { ...x, ...patch } : x) }));

  return (
    <div className="min-h-screen bg-[#F5F5F7] pb-32" style={fontStack}>
      <div className="bg-white/85 backdrop-blur-xl border-b border-black/5 sticky top-0 z-30">
        <div className="max-w-2xl mx-auto px-3 py-3 flex items-center gap-2">
          <button onClick={onBack} className="text-[#1A8CB8] flex items-center gap-1 px-2 py-1 -ml-2 text-[15px]"><ChevronLeft className="w-5 h-5" />Customers</button>
          <div className="flex-1" />
          <button onClick={() => setEditing(e => !e)} className="text-[#1A8CB8] text-[15px] font-medium px-2">{editing ? 'Done' : 'Edit'}</button>
        </div>
      </div>

      <div className="max-w-2xl mx-auto px-5 pt-6">
        <div className="text-center mb-7">
          <div className="w-20 h-20 mx-auto rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center font-medium text-2xl mb-3 shadow-lg shadow-[#1A8CB8]/20">
            {c.name.split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
          </div>
          <div className="flex items-center justify-center gap-2 flex-wrap">
            <h1 className="text-[26px] font-semibold tracking-tight">{c.name}</h1>
            {c.poolRx && <PoolRxBadge size="lg" />}
          </div>
          <p className="text-[14px] text-[#86868B] mt-1">{c.address} · {c.city}</p>
        </div>

        <div className="grid grid-cols-4 gap-3 mb-7">
          <ActionTile icon={Plus} label="New visit" onClick={startVisit} primary />
          <ActionTile icon={Send} label="Invoice" onClick={() => setShowCustomInvoice(s => !s)} />
          <ActionTile icon={Phone} label="Call" onClick={() => window.open(`tel:${c.phone}`)} />
          <ActionTile icon={Mail} label="Email" onClick={() => window.open(`mailto:${c.email}`)} />
        </div>

        {/* Custom invoice builder */}
        {showCustomInvoice && (
          <Section title="New invoice" action={
            <button onClick={() => setShowCustomInvoice(false)} className="text-[#86868B] text-[13px] font-medium">Cancel</button>
          }>
            <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3">
              <div className="flex items-center gap-3 mb-2">
                <div className="w-8 h-8 rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center text-[10px] font-semibold flex-shrink-0">
                  {c.name.split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
                </div>
                <div>
                  <div className="text-[13px] font-medium">{c.name}</div>
                  <div className="text-[11px] text-[#86868B]">{c.email || 'No email on file'}</div>
                </div>
              </div>
              <div className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider">Line items</div>
              {customInvoiceItems.map((item, i) => (
                <div key={i} className="flex gap-2 items-end">
                  <div className="flex-1">
                    <Field label={i === 0 ? 'Description' : ''}>
                      <input className={inputCls} value={item.label} onChange={e => {
                        const items = [...customInvoiceItems];
                        items[i] = { ...items[i], label: e.target.value };
                        setCustomInvoiceItems(items);
                      }} placeholder="e.g. Monthly service, Acid wash..." />
                    </Field>
                  </div>
                  <div className="w-24">
                    <Field label={i === 0 ? 'Amount' : ''}>
                      <input type="number" step="1" className={inputCls} value={item.amount || ''} onChange={e => {
                        const items = [...customInvoiceItems];
                        items[i] = { ...items[i], amount: +e.target.value };
                        setCustomInvoiceItems(items);
                      }} placeholder="$0" />
                    </Field>
                  </div>
                  {customInvoiceItems.length > 1 && (
                    <button onClick={() => setCustomInvoiceItems(customInvoiceItems.filter((_, j) => j !== i))} className="text-[#FF3B30] p-1 mb-0.5"><X className="w-4 h-4" /></button>
                  )}
                </div>
              ))}
              <button onClick={() => setCustomInvoiceItems([...customInvoiceItems, { label: '', amount: 0 }])} className="text-[#1A8CB8] text-[13px] font-medium flex items-center gap-1">
                <Plus className="w-3.5 h-3.5" />Add line item
              </button>
              {/* Total + actions */}
              {(() => {
                const total = customInvoiceItems.reduce((s, i) => s + (i.amount || 0), 0);
                const validItems = customInvoiceItems.filter(i => i.label.trim() && i.amount > 0);
                return (
                  <>
                    <div className="border-t border-black/5 pt-3 flex items-center justify-between">
                      <span className="text-[14px] font-semibold">Total</span>
                      <span className="text-[18px] font-semibold text-[#1A8CB8]">{fmt(total)}</span>
                    </div>
                    <div className="flex gap-2">
                      <button disabled={validItems.length === 0} onClick={() => {
                        const invoice = {
                          id: uid('inv'), visitId: null, customerId: c.id,
                          date: todayISO(), items: validItems.map(i => ({ ...i, type: 'custom' })),
                          total, status: 'archived', squareInvoiceId: null, sentAt: null, paidAt: null,
                        };
                        updateDb(d => ({ ...d, invoices: [...(d.invoices || []), invoice] }));
                        setShowCustomInvoice(false);
                        setCustomInvoiceItems([{ label: '', amount: 0 }]);
                      }} className={`flex-1 py-3 rounded-xl text-[13px] font-medium flex items-center justify-center gap-1.5 ${validItems.length > 0 ? 'bg-[#F2F2F7] text-[#1D1D1F]' : 'bg-[#F2F2F7] text-[#C7C7CC]'}`}>
                        <BookOpen className="w-3.5 h-3.5" />Save & Archive
                      </button>
                      <button disabled={validItems.length === 0} onClick={() => {
                        const invoice = {
                          id: uid('inv'), visitId: null, customerId: c.id,
                          date: todayISO(), items: validItems.map(i => ({ ...i, type: 'custom' })),
                          total, status: 'sent', squareInvoiceId: null, sentAt: new Date().toISOString(), paidAt: null,
                        };
                        updateDb(d => ({ ...d, invoices: [...(d.invoices || []), invoice] }));
                        setShowCustomInvoice(false);
                        setCustomInvoiceItems([{ label: '', amount: 0 }]);
                      }} className={`flex-1 py-3 rounded-xl text-[13px] font-medium flex items-center justify-center gap-1.5 ${validItems.length > 0 ? 'bg-[#1A8CB8] text-white shadow-sm' : 'bg-[#E5E5EA] text-[#C7C7CC]'}`}>
                        <Send className="w-3.5 h-3.5" />Send to customer
                      </button>
                    </div>
                  </>
                );
              })()}
            </div>
          </Section>
        )}

        <Section title="Profit summary">
          <div className="bg-white rounded-2xl p-5 border border-black/5">
            <div className="grid grid-cols-2 gap-4">
              <Stat label="Revenue" value={fmt0(stats.revenue)} />
              <Stat label="Profit" value={fmt0(stats.profit)} tone="success" />
              <Stat label="Chemicals" value={fmt(stats.chemCost)} />
              <Stat label="Labor" value={fmt(stats.laborCost)} />
            </div>
            <div className="mt-4 pt-4 border-t border-black/5 flex items-center justify-between">
              <span className="text-[13px] text-[#86868B]">Margin</span>
              <span className={`text-[15px] font-semibold ${stats.margin > 50 ? 'text-[#1F8B3E]' : stats.margin > 25 ? 'text-[#1D1D1F]' : 'text-[#C77400]'}`}>{stats.margin.toFixed(1)}%</span>
            </div>
          </div>
        </Section>

        {!editing ? (
          <>
            <Section title="Pool details">
              <div className="bg-white rounded-2xl border border-black/5">
                <Row label="Size" value={`${c.poolSize.toLocaleString()} gal`} />
                <Row label="Type" value={c.poolType} />
                <Row label="Filter" value={`${c.filterType || 'Cartridge'}${c.filterPsiBaseline ? ` · ${c.filterPsiBaseline} PSI baseline` : ''}`} />
                <Row label="Cleaner" value={c.cleaner && c.cleaner !== 'None' ? c.cleaner : 'Manual vacuum'} />
                <Row label="Pool RX" value={c.poolRx ? (() => {
                  const rx = poolRxStatus(c.id, db.visits);
                  if (!rx.lastDate) return 'Yes — never dosed';
                  return `Yes · last ${rx.daysSince}d ago · ${rx.due ? 'due now' : `next in ${rx.dueInDays}d`}`;
                })() : 'No'} />
                <Row label="Service" value={`${fmt0(c.serviceRate)} · ${c.serviceFreq}`} />
                <Row label="Phone" value={c.phone} />
                <Row label="Email" value={c.email} last />
              </div>
              {c.notes && (
                <div className="bg-white rounded-2xl border border-black/5 p-4 mt-3">
                  <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B] mb-1">Notes</div>
                  <p className="text-[14px]">{c.notes}</p>
                </div>
              )}
            </Section>

            {/* Pool sizing calculator + photos */}
            <Section title="Pool sizing & photos" action={
              <div className="flex gap-2">
                <button onClick={() => setShowPoolCalc(s => !s)} className="text-[#1A8CB8] text-[13px] font-medium">{showPoolCalc ? 'Close' : 'Calculator'}</button>
                <button onClick={() => photoInputRef.current?.click()} className="text-[#1A8CB8] flex items-center gap-1 text-[13px] font-medium">
                  <Camera className="w-3.5 h-3.5" />Photo
                </button>
                <input ref={photoInputRef} type="file" accept="image/*" capture="environment" className="hidden" onChange={e => {
                  const file = e.target.files?.[0];
                  if (!file) return;
                  const reader = new FileReader();
                  reader.onload = (ev) => {
                    const photo = { id: uid('ph'), dataUrl: ev.target.result, date: todayISO(), name: file.name };
                    updateField({ photos: [...(c.photos || []), photo] });
                  };
                  reader.readAsDataURL(file);
                  e.target.value = '';
                }} />
              </div>
            }>
              {/* Pool gallon calculator */}
              {showPoolCalc && (
                <div className="bg-white rounded-2xl border border-black/5 p-4 mb-3 space-y-3">
                  <div className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider">Gallon calculator</div>
                  <div className="flex gap-2">
                    {POOL_SHAPES.map(s => (
                      <button key={s.id} onClick={() => setCalcDims(p => ({ ...p, shape: s.id }))} className={`flex-1 py-2 rounded-xl text-center text-[12px] font-medium transition-all ${calcDims.shape === s.id ? 'bg-[#1A8CB8] text-white shadow-sm' : 'bg-[#F2F2F7] text-[#1D1D1F]'}`}>
                        <div className="text-lg leading-none mb-0.5">{s.icon}</div>
                        {s.label}
                      </button>
                    ))}
                  </div>
                  <div className="grid grid-cols-2 gap-3">
                    <Field label="Length (ft)"><input type="number" step="0.5" className={inputCls} value={calcDims.length} onChange={e => setCalcDims(p => ({ ...p, length: e.target.value }))} placeholder="e.g. 32" /></Field>
                    <Field label="Width (ft)"><input type="number" step="0.5" className={inputCls} value={calcDims.width} onChange={e => setCalcDims(p => ({ ...p, width: e.target.value }))} placeholder="e.g. 16" /></Field>
                  </div>
                  <div className="grid grid-cols-2 gap-3">
                    <Field label="Shallow depth (ft)"><input type="number" step="0.5" className={inputCls} value={calcDims.depthShallow} onChange={e => setCalcDims(p => ({ ...p, depthShallow: e.target.value }))} placeholder="e.g. 3" /></Field>
                    <Field label="Deep end (ft)"><input type="number" step="0.5" className={inputCls} value={calcDims.depthDeep} onChange={e => setCalcDims(p => ({ ...p, depthDeep: e.target.value }))} placeholder="e.g. 8" /></Field>
                  </div>
                  {calcDims.length && calcDims.width && calcDims.depthShallow && (() => {
                    const gal = calcPoolGallons(calcDims.shape, calcDims.length, calcDims.width, calcDims.depthShallow, calcDims.depthDeep);
                    return (
                      <div className="bg-gradient-to-r from-[#1A8CB8]/10 to-[#5BC0DE]/10 rounded-xl p-4 text-center">
                        <div className="text-[28px] font-semibold text-[#1A8CB8] tracking-tight">{gal.toLocaleString()}</div>
                        <div className="text-[12px] text-[#86868B]">estimated gallons</div>
                        <button onClick={() => {
                          updateField({ poolSize: gal, poolShape: calcDims.shape, poolLength: +calcDims.length, poolWidth: +calcDims.width, poolDepthShallow: +calcDims.depthShallow, poolDepthDeep: +(calcDims.depthDeep || calcDims.depthShallow) });
                          setShowPoolCalc(false);
                        }} className="mt-3 bg-[#1A8CB8] text-white px-5 py-2 rounded-xl text-[13px] font-medium">
                          Apply to pool size
                        </button>
                      </div>
                    );
                  })()}
                </div>
              )}
              {/* Photo gallery */}
              {(c.photos || []).length > 0 ? (
                <div className="grid grid-cols-3 gap-2">
                  {(c.photos || []).map(photo => (
                    <div key={photo.id} className="relative group">
                      <img src={photo.dataUrl} alt={photo.name || 'Pool photo'} className="w-full h-24 object-cover rounded-xl border border-black/5" />
                      <div className="absolute bottom-0 left-0 right-0 bg-black/40 backdrop-blur-sm rounded-b-xl px-2 py-1">
                        <div className="text-[9px] text-white truncate">{shortDate(photo.date)}</div>
                      </div>
                      <button onClick={() => {
                        if (confirm('Remove this photo?')) updateField({ photos: (c.photos || []).filter(p => p.id !== photo.id) });
                      }} className="absolute top-1 right-1 w-5 h-5 rounded-full bg-black/50 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
                        <X className="w-3 h-3" />
                      </button>
                    </div>
                  ))}
                </div>
              ) : !showPoolCalc ? (
                <div className="bg-white rounded-2xl border border-black/5 p-5 text-center">
                  <div className="inline-flex w-10 h-10 rounded-full bg-[#F2F2F7] items-center justify-center mb-2">
                    <Image className="w-5 h-5 text-[#86868B]" />
                  </div>
                  <p className="text-[13px] text-[#86868B]">Tap "Photo" to add pool photos or "Calculator" to estimate gallons</p>
                </div>
              ) : null}
            </Section>

            {/* Water bodies — additional pools, spas, fountains */}
            {((c.waterBodies || []).length > 0 || !editing) && (
              <Section title="Water bodies" subtitle={`Primary pool${(c.waterBodies || []).length > 0 ? ` + ${(c.waterBodies || []).length} additional` : ''}`} action={
                <button onClick={() => setShowAddWaterBody(s => !s)} className="text-[#1A8CB8] text-[14px] font-medium flex items-center gap-1">
                  <Plus className="w-4 h-4" strokeWidth={2.5} />{showAddWaterBody ? 'Cancel' : 'Add'}
                </button>
              }>
                {showAddWaterBody && (
                  <div className="bg-white rounded-2xl border border-black/5 p-4 mb-3 space-y-3">
                    <Field label="Name (e.g. 'Back yard spa')"><input className={inputCls} value={newWaterBody.name} onChange={e => setNewWaterBody(p => ({ ...p, name: e.target.value }))} placeholder="Optional — defaults to type" /></Field>
                    <div className="grid grid-cols-2 gap-3">
                      <Field label="Type">
                        <select className={inputCls} value={newWaterBody.type} onChange={e => setNewWaterBody(p => ({ ...p, type: e.target.value }))}>
                          {WATER_BODY_TYPES.map(t => <option key={t.id} value={t.id}>{t.icon} {t.label}</option>)}
                        </select>
                      </Field>
                      <Field label="Size (gal)"><input type="number" className={inputCls} value={newWaterBody.size} onChange={e => setNewWaterBody(p => ({ ...p, size: +e.target.value }))} /></Field>
                    </div>
                    <div className="grid grid-cols-2 gap-3">
                      <Field label="Water type">
                        <select className={inputCls} value={newWaterBody.poolType} onChange={e => setNewWaterBody(p => ({ ...p, poolType: e.target.value }))}><option>Chlorine</option><option>Salt</option><option>Bromine</option><option>Mineral</option></select>
                      </Field>
                      <Field label="Filter">
                        <select className={inputCls} value={newWaterBody.filterType} onChange={e => setNewWaterBody(p => ({ ...p, filterType: e.target.value }))}><option>Cartridge</option><option>DE</option><option>Sand</option><option>None</option></select>
                      </Field>
                    </div>
                    <Field label="Address (if different property)"><input className={inputCls} value={newWaterBody.address} onChange={e => setNewWaterBody(p => ({ ...p, address: e.target.value }))} placeholder="Leave blank if same location" /></Field>
                    <button onClick={addWaterBody} className="w-full bg-[#1A8CB8] text-white py-2.5 rounded-xl font-medium text-[14px]">Add water body</button>
                  </div>
                )}
                {(c.waterBodies || []).length === 0 && !showAddWaterBody ? null : (
                  <div className="space-y-3">
                    {(c.waterBodies || []).map(wb => {
                      const wbType = WATER_BODY_TYPES.find(t => t.id === wb.type) || WATER_BODY_TYPES[0];
                      const isWbEditing = editingWaterBodyId === wb.id;
                      return (
                        <div key={wb.id} className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                          <div className="px-4 py-3.5 flex items-center gap-3">
                            <div className="text-2xl flex-shrink-0">{wbType.icon}</div>
                            <div className="flex-1 min-w-0">
                              <div className="text-[15px] font-medium">{wb.name || wbType.label}</div>
                              <div className="text-[12px] text-[#86868B]">{wb.size?.toLocaleString()} gal · {wb.poolType} · {wb.filterType}{wb.address ? ` · ${wb.address}` : ''}</div>
                            </div>
                            <button onClick={() => setEditingWaterBodyId(isWbEditing ? null : wb.id)} className="text-[#1A8CB8] p-1"><Edit3 className="w-3.5 h-3.5" /></button>
                          </div>
                          {isWbEditing && (
                            <div className="border-t border-black/5 px-4 py-3 space-y-2.5 bg-[#FAFAFA]">
                              <Field label="Name"><input className={inputCls} value={wb.name || ''} onChange={e => updateWaterBody(wb.id, { name: e.target.value })} /></Field>
                              <div className="grid grid-cols-2 gap-2">
                                <Field label="Size (gal)"><input type="number" className={inputCls} value={wb.size || 0} onChange={e => updateWaterBody(wb.id, { size: +e.target.value })} /></Field>
                                <Field label="Type"><select className={inputCls} value={wb.poolType || 'Chlorine'} onChange={e => updateWaterBody(wb.id, { poolType: e.target.value })}><option>Chlorine</option><option>Salt</option><option>Bromine</option><option>Mineral</option></select></Field>
                              </div>
                              <Field label="Address (if different)"><input className={inputCls} value={wb.address || ''} onChange={e => updateWaterBody(wb.id, { address: e.target.value })} placeholder="Leave blank if same location" /></Field>
                              <div className="flex gap-2 pt-1">
                                <button onClick={() => setEditingWaterBodyId(null)} className="flex-1 bg-[#F2F2F7] text-[#1D1D1F] py-2 rounded-xl text-[13px] font-medium">Done</button>
                                <button onClick={() => removeWaterBody(wb.id)} className="bg-[#FFF5F5] text-[#FF3B30] px-4 py-2 rounded-xl text-[13px] font-medium">Remove</button>
                              </div>
                            </div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                )}
              </Section>
            )}
          </>
        ) : (
          <Section title="Edit details">
            <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3">
              <Field label="Name"><input className={inputCls} value={c.name} onChange={e => updateField({ name: e.target.value })} /></Field>
              <Field label="Address"><input className={inputCls} value={c.address} onChange={e => updateField({ address: e.target.value })} /></Field>
              <Field label="City"><input className={inputCls} value={c.city} onChange={e => updateField({ city: e.target.value })} /></Field>
              <div className="grid grid-cols-2 gap-3">
                <Field label="Phone"><input className={inputCls} value={c.phone} onChange={e => updateField({ phone: e.target.value })} /></Field>
                <Field label="Email"><input className={inputCls} value={c.email} onChange={e => updateField({ email: e.target.value })} /></Field>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <Field label="Pool size (gal)"><input type="number" className={inputCls} value={c.poolSize} onChange={e => updateField({ poolSize: +e.target.value })} /></Field>
                <Field label="Pool type"><select className={inputCls} value={c.poolType} onChange={e => updateField({ poolType: e.target.value })}><option>Chlorine</option><option>Salt</option><option>Bromine</option><option>Mineral</option></select></Field>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <Field label="Filter type"><select className={inputCls} value={c.filterType || 'Cartridge'} onChange={e => updateField({ filterType: e.target.value })}><option>Cartridge</option><option>DE</option><option>Sand</option></select></Field>
                <Field label="Cleaner"><select className={inputCls} value={c.cleaner || 'None'} onChange={e => updateField({ cleaner: e.target.value })}>{CLEANER_OPTIONS.map(o => <option key={o}>{o}</option>)}</select></Field>
              </div>
              <Field label="Filter clean baseline (PSI when freshly cleaned)">
                <input type="number" step="1" inputMode="numeric" className={inputCls} value={c.filterPsiBaseline || ''} onChange={e => updateField({ filterPsiBaseline: +e.target.value })} placeholder="e.g., 12" />
              </Field>
              <Field label="Pool RX (biannual phosphate program)">
                <select className={inputCls} value={c.poolRx ? 'Yes' : 'No'} onChange={e => updateField({ poolRx: e.target.value === 'Yes' })}>
                  <option>No</option>
                  <option>Yes</option>
                </select>
              </Field>
              <div className="grid grid-cols-2 gap-3">
                <Field label="Rate ($/mo)"><input type="number" className={inputCls} value={c.serviceRate} onChange={e => updateField({ serviceRate: +e.target.value })} /></Field>
                <Field label="Frequency"><select className={inputCls} value={c.serviceFreq} onChange={e => updateField({ serviceFreq: e.target.value })}><option>Weekly</option><option>2x Weekly</option><option>Bi-weekly</option><option>Monthly</option></select></Field>
              </div>
              <Field label="Notes"><textarea rows={3} className={inputCls} value={c.notes} onChange={e => updateField({ notes: e.target.value })} /></Field>
            </div>
          </Section>
        )}

        {/* Tab bar: Visits | Repairs | Invoices */}
        <div className="flex gap-1 bg-[#E5E5EA] rounded-xl p-1 mb-5">
          <button onClick={() => setDetailTab('visits')} className={`flex-1 py-2 rounded-lg text-[13px] font-medium transition-all ${detailTab === 'visits' ? 'bg-white text-[#1D1D1F] shadow-sm' : 'text-[#86868B]'}`}>
            Visits <span className="text-[11px] ml-1 opacity-60">{visits.length}</span>
          </button>
          <button onClick={() => setDetailTab('repairs')} className={`flex-1 py-2 rounded-lg text-[13px] font-medium transition-all ${detailTab === 'repairs' ? 'bg-white text-[#1D1D1F] shadow-sm' : 'text-[#86868B]'}`}>
            Repairs <span className="text-[11px] ml-1 opacity-60">{repairs.length}</span>
          </button>
          <button onClick={() => setDetailTab('invoices')} className={`flex-1 py-2 rounded-lg text-[13px] font-medium transition-all ${detailTab === 'invoices' ? 'bg-white text-[#1D1D1F] shadow-sm' : 'text-[#86868B]'}`}>
            Invoices <span className="text-[11px] ml-1 opacity-60">{(db.invoices || []).filter(i => i.customerId === c.id).length}</span>
          </button>
        </div>

        {detailTab === 'visits' && (
          <Section title="Visit history" subtitle={`${visits.length} ${visits.length === 1 ? 'visit' : 'visits'}`}>
            {visits.length === 0 ? (
              <div className="bg-white rounded-2xl p-6 border border-black/5 text-center text-[#86868B]">No visits yet. Tap "New visit" to start.</div>
            ) : (
              <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                {visits.slice(0, 8).map((v, i) => (
                  <button key={v.id} onClick={() => onStartVisit(v.id)} className={`w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-[#F5F5F7] ${i > 0 ? 'border-t border-black/5' : ''}`}>
                    <div className={`w-2 h-2 rounded-full flex-shrink-0 ${v.completedAt ? 'bg-[#34C759]' : 'bg-[#FF9500]'}`} />
                    <div className="flex-1">
                      <div className="text-[14px] font-medium">{shortDate(v.date)} · {dayName(v.date)}</div>
                      <div className="text-[12px] text-[#86868B]">{v.completedAt ? 'Completed' : 'In progress'} · {v.chemicalsUsed.length} chemicals · {v.durationMin}m</div>
                    </div>
                    <div className="text-[13px] text-[#86868B] mr-2">{v.paid ? 'Paid' : v.invoiced ? 'Invoiced' : '—'}</div>
                    <ChevronRight className="w-4 h-4 text-[#C7C7CC]" />
                  </button>
                ))}
              </div>
            )}
          </Section>
        )}

        {detailTab === 'repairs' && (
          <>
            <Section title="Repairs" subtitle={repairs.length > 0 ? `${repairs.length} total · ${fmt0(repairs.reduce((s, r) => s + (r.totalPrice || 0), 0))} value` : 'No repairs yet'} action={
              <button onClick={() => setShowRepairForm(s => !s)} className="text-[#1A8CB8] text-[14px] font-medium flex items-center gap-1">
                <Plus className="w-4 h-4" strokeWidth={2.5} />{showRepairForm ? 'Cancel' : 'New'}
              </button>
            }>
              {showRepairForm && (
                <div className="bg-white rounded-2xl border border-black/5 p-4 mb-3 space-y-3">
                  <Field label="Repair type">
                    <select className={inputCls} value={newRepair.type} onChange={e => {
                      const rt = REPAIR_TYPES.find(t => t.id === e.target.value);
                      setNewRepair(p => ({ ...p, type: e.target.value, totalPrice: rt?.defaultPrice || 0 }));
                    }}>
                      {REPAIR_TYPES.map(t => <option key={t.id} value={t.id}>{t.icon} {t.label}</option>)}
                    </select>
                  </Field>
                  <Field label="Description (optional)">
                    <input className={inputCls} value={newRepair.description} onChange={e => setNewRepair(p => ({ ...p, description: e.target.value }))} placeholder="Details about the repair..." />
                  </Field>
                  <div className="grid grid-cols-3 gap-3">
                    <Field label="Labor hrs">
                      <input type="number" step="0.5" className={inputCls} value={newRepair.laborHours} onChange={e => setNewRepair(p => ({ ...p, laborHours: +e.target.value }))} />
                    </Field>
                    <Field label="Parts $">
                      <input type="number" step="1" className={inputCls} value={newRepair.partsCost} onChange={e => setNewRepair(p => ({ ...p, partsCost: +e.target.value }))} />
                    </Field>
                    <Field label="Total $">
                      <input type="number" step="1" className={inputCls} value={newRepair.totalPrice} onChange={e => setNewRepair(p => ({ ...p, totalPrice: +e.target.value }))} />
                    </Field>
                  </div>
                  <Field label="Status">
                    <select className={inputCls} value={newRepair.status} onChange={e => setNewRepair(p => ({ ...p, status: e.target.value }))}>
                      {REPAIR_STATUSES.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
                    </select>
                  </Field>
                  <Field label="Notes">
                    <textarea rows={2} className={inputCls} value={newRepair.notes} onChange={e => setNewRepair(p => ({ ...p, notes: e.target.value }))} placeholder="Internal notes..." />
                  </Field>
                  <button onClick={saveRepair} className="w-full bg-[#1A8CB8] text-white py-2.5 rounded-xl font-medium text-[14px]">Save repair</button>
                </div>
              )}

              {repairs.length === 0 && !showRepairForm ? (
                <div className="bg-white rounded-2xl p-6 border border-black/5 text-center">
                  <div className="inline-flex w-12 h-12 rounded-full bg-[#F2F2F7] items-center justify-center mb-3">
                    <Wrench className="w-6 h-6 text-[#86868B]" />
                  </div>
                  <p className="text-[14px] font-medium text-[#1D1D1F]">No repairs yet</p>
                  <p className="text-[12px] text-[#86868B] mt-1">Tap "New" to log an acid wash, motor replacement, or other repair work.</p>
                </div>
              ) : (
                <div className="space-y-3">
                  {repairs.map(r => {
                    const statusInfo = REPAIR_STATUSES.find(s => s.id === r.status) || REPAIR_STATUSES[0];
                    const nextStatuses = REPAIR_STATUSES.filter(s => REPAIR_STATUSES.indexOf(s) > REPAIR_STATUSES.indexOf(statusInfo));
                    const isEditing = editingRepairId === r.id;
                    return (
                      <div key={r.id} className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                        <div className="px-4 py-3.5">
                          <div className="flex items-start gap-3">
                            <div className="text-2xl flex-shrink-0 mt-0.5">{r.icon || '🛠️'}</div>
                            <div className="flex-1 min-w-0">
                              <div className="flex items-center gap-2 flex-wrap mb-0.5">
                                <span className="text-[15px] font-medium">{r.typeLabel || r.type}</span>
                                <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md" style={{ color: statusInfo.color, backgroundColor: statusInfo.bg }}>{statusInfo.label}</span>
                              </div>
                              {!isEditing && r.description && <p className="text-[13px] text-[#86868B] mb-1">{r.description}</p>}
                              {!isEditing && (
                                <div className="text-[12px] text-[#86868B] flex items-center gap-2 flex-wrap">
                                  <span>{shortDate(r.date)}</span>
                                  {r.laborHours > 0 && <span>· {r.laborHours}h labor</span>}
                                  {r.partsCost > 0 && <span>· {fmt(r.partsCost)} parts</span>}
                                  {(r.photos || []).length > 0 && <span>· 📷 {r.photos.length} photo{r.photos.length > 1 ? 's' : ''}</span>}
                                </div>
                              )}
                              {/* Photo thumbnails when not editing */}
                              {!isEditing && (r.photos || []).length > 0 && (
                                <div className="flex gap-1.5 mt-2">
                                  {(r.photos || []).map(photo => (
                                    <div key={photo.id} className="relative">
                                      <img src={photo.dataUrl} alt={photo.tag} className="w-12 h-12 rounded-lg object-cover border border-black/5" />
                                      <div className="absolute bottom-0 left-0 right-0 bg-black/50 text-[7px] text-white text-center rounded-b-lg py-px font-medium uppercase">{photo.tag}</div>
                                    </div>
                                  ))}
                                </div>
                              )}
                            </div>
                            <div className="text-right flex-shrink-0 flex items-start gap-1.5">
                              <div>
                                <div className="text-[16px] font-semibold text-[#1D1D1F]">{fmt0(r.totalPrice)}</div>
                                <div className="text-[10px] text-[#86868B]">{r.paid ? 'Paid' : r.invoiced ? 'Invoiced' : 'Not billed'}</div>
                              </div>
                              <button onClick={() => setEditingRepairId(isEditing ? null : r.id)} className="text-[#1A8CB8] p-1 -mr-1">
                                <Edit3 className="w-3.5 h-3.5" />
                              </button>
                            </div>
                          </div>
                        </div>
                        {/* Inline edit form */}
                        {isEditing && (
                          <div className="border-t border-black/5 px-4 py-3 space-y-2.5 bg-[#FAFAFA]">
                            <Field label="Description">
                              <input className={inputCls} value={r.description || ''} onChange={e => updateRepairField(r.id, { description: e.target.value })} placeholder="Repair details..." />
                            </Field>
                            <div className="grid grid-cols-3 gap-2">
                              <Field label="Labor hrs">
                                <input type="number" step="0.5" className={inputCls} value={r.laborHours || 0} onChange={e => updateRepairField(r.id, { laborHours: +e.target.value })} />
                              </Field>
                              <Field label="Parts $">
                                <input type="number" step="1" className={inputCls} value={r.partsCost || 0} onChange={e => updateRepairField(r.id, { partsCost: +e.target.value })} />
                              </Field>
                              <Field label="Total $">
                                <input type="number" step="1" className={inputCls} value={r.totalPrice || 0} onChange={e => updateRepairField(r.id, { totalPrice: +e.target.value })} />
                              </Field>
                            </div>
                            <Field label="Status">
                              <select className={inputCls} value={r.status} onChange={e => {
                                const patch = { status: e.target.value };
                                if (e.target.value === 'completed') patch.completedAt = new Date().toISOString();
                                if (e.target.value === 'cancelled') patch.completedAt = null;
                                updateRepairField(r.id, patch);
                              }}>
                                {REPAIR_STATUSES.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
                              </select>
                            </Field>
                            <Field label="Notes">
                              <textarea rows={2} className={inputCls} value={r.notes || ''} onChange={e => updateRepairField(r.id, { notes: e.target.value })} placeholder="Internal notes..." />
                            </Field>
                            {/* Repair photos — before/after */}
                            <div className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider mt-1">Photos</div>
                            <input ref={repairPhotoInputRef} type="file" accept="image/*" capture="environment" className="hidden" onChange={e => {
                              const file = e.target.files?.[0];
                              if (!file || !repairPhotoTarget) return;
                              const reader = new FileReader();
                              reader.onload = (ev) => {
                                const photo = { id: uid('rph'), dataUrl: ev.target.result, tag: repairPhotoTarget.tag, date: todayISO() };
                                updateRepairField(repairPhotoTarget.repairId, { photos: [...(r.photos || []), photo] });
                              };
                              reader.readAsDataURL(file);
                              e.target.value = '';
                              setRepairPhotoTarget(null);
                            }} />
                            <div className="flex gap-2">
                              <button onClick={() => { setRepairPhotoTarget({ repairId: r.id, tag: 'before' }); setTimeout(() => repairPhotoInputRef.current?.click(), 50); }} className="flex-1 bg-[#F2F2F7] text-[#1D1D1F] py-2.5 rounded-xl text-[12px] font-medium flex items-center justify-center gap-1.5">
                                <Camera className="w-3.5 h-3.5" />Before
                              </button>
                              <button onClick={() => { setRepairPhotoTarget({ repairId: r.id, tag: 'after' }); setTimeout(() => repairPhotoInputRef.current?.click(), 50); }} className="flex-1 bg-[#F2F2F7] text-[#1D1D1F] py-2.5 rounded-xl text-[12px] font-medium flex items-center justify-center gap-1.5">
                                <Camera className="w-3.5 h-3.5" />After
                              </button>
                            </div>
                            {(r.photos || []).length > 0 && (
                              <div className="flex gap-2 flex-wrap">
                                {(r.photos || []).map(photo => (
                                  <div key={photo.id} className="relative group">
                                    <img src={photo.dataUrl} alt={photo.tag} className="w-16 h-16 rounded-xl object-cover border border-black/5" />
                                    <div className="absolute bottom-0 left-0 right-0 bg-black/50 text-[8px] text-white text-center rounded-b-xl py-0.5 font-medium uppercase">{photo.tag}</div>
                                    <button onClick={() => updateRepairField(r.id, { photos: (r.photos || []).filter(p => p.id !== photo.id) })} className="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-[#FF3B30] text-white flex items-center justify-center">
                                      <X className="w-2.5 h-2.5" />
                                    </button>
                                  </div>
                                ))}
                              </div>
                            )}
                            <div className="flex gap-2 pt-1">
                              <button onClick={() => setEditingRepairId(null)} className="flex-1 bg-[#F2F2F7] text-[#1D1D1F] py-2 rounded-xl text-[13px] font-medium">Done</button>
                              <button onClick={() => deleteRepair(r.id)} className="bg-[#FFF5F5] text-[#FF3B30] px-4 py-2 rounded-xl text-[13px] font-medium">Delete</button>
                            </div>
                          </div>
                        )}
                        {!isEditing && r.status !== 'completed' && r.status !== 'cancelled' && (
                          <div className="border-t border-black/5 px-4 py-2.5 flex items-center gap-2">
                            {nextStatuses.filter(s => s.id !== 'cancelled').map(ns => (
                              <button key={ns.id} onClick={() => updateRepairStatus(r.id, ns.id)} className="text-[12px] font-medium px-3 py-1.5 rounded-lg transition-colors" style={{ color: ns.color, backgroundColor: ns.bg }}>
                                {ns.id === 'completed' ? '✓ ' : ''}{ns.label}
                              </button>
                            ))}
                            <div className="flex-1" />
                          </div>
                        )}
                        {!isEditing && r.status === 'completed' && (
                          <div className="border-t border-black/5 px-4 py-2 flex items-center gap-2">
                            <CheckCircle2 className="w-3.5 h-3.5 text-[#34C759]" />
                            <span className="text-[11px] text-[#86868B]">Completed {r.completedAt ? new Date(r.completedAt).toLocaleDateString() : ''}</span>
                          </div>
                        )}
                        {!isEditing && r.status === 'cancelled' && (
                          <div className="border-t border-black/5 px-4 py-2 flex items-center gap-2">
                            <X className="w-3.5 h-3.5 text-[#FF3B30]" />
                            <span className="text-[11px] text-[#86868B]">Cancelled</span>
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </Section>
          </>
        )}

        {detailTab === 'invoices' && (() => {
          const custInvoices = (db.invoices || []).filter(i => i.customerId === c.id).sort((a, b) => (b.date || '').localeCompare(a.date || ''));
          const statusColors = { archived: { color: '#86868B', bg: '#F2F2F7', label: 'Archived' }, sent: { color: '#FF9500', bg: '#FFF3E0', label: 'Sent' }, paid: { color: '#34C759', bg: '#E8F5E9', label: 'Paid' }, draft: { color: '#1A8CB8', bg: '#E5F2FF', label: 'Draft' } };
          return (
            <Section title="Invoice history" subtitle={custInvoices.length > 0 ? `${custInvoices.length} invoices · ${fmt(custInvoices.reduce((s, i) => s + (i.total || 0), 0))} total` : 'No invoices yet'}>
              {custInvoices.length === 0 ? (
                <div className="bg-white rounded-2xl p-6 border border-black/5 text-center">
                  <div className="inline-flex w-10 h-10 rounded-full bg-[#F2F2F7] items-center justify-center mb-2">
                    <FileText className="w-5 h-5 text-[#86868B]" />
                  </div>
                  <p className="text-[13px] text-[#86868B]">Tap "Invoice" above to create one, or complete a visit to auto-generate.</p>
                </div>
              ) : (
                <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                  {custInvoices.map((inv, i) => {
                    const sc = statusColors[inv.status] || statusColors.draft;
                    const sentDate = inv.sentAt ? new Date(inv.sentAt) : null;
                    const daysSince = sentDate ? Math.floor((Date.now() - sentDate.getTime()) / 86400000) : 0;
                    const isOverdue = inv.status === 'sent' && !inv.paidAt && daysSince >= (db.settings.invoiceReminderDays || 14);
                    return (
                      <div key={inv.id} className={`px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                        <div className="flex items-center justify-between mb-1">
                          <div className="flex items-center gap-2">
                            <span className="text-[13px] font-medium">{shortDate(inv.date)}</span>
                            <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md" style={{ color: isOverdue ? '#FF3B30' : sc.color, backgroundColor: isOverdue ? '#FFF5F5' : sc.bg }}>
                              {isOverdue ? `${daysSince}d overdue` : sc.label}
                            </span>
                          </div>
                          <span className="text-[14px] font-semibold">{fmt(inv.total)}</span>
                        </div>
                        <div className="text-[11px] text-[#86868B]">
                          {(inv.items || []).map(item => item.label).join(' · ')}
                        </div>
                        {inv.status === 'sent' && !inv.paidAt && (
                          <div className="flex gap-2 mt-2">
                            <button onClick={() => updateDb(d => ({ ...d, invoices: d.invoices.map(x => x.id === inv.id ? { ...x, paidAt: new Date().toISOString(), status: 'paid' } : x) }))} className="text-[11px] font-medium text-[#34C759] bg-[#E8F5E9] px-2.5 py-1 rounded-lg">Mark paid</button>
                            <button onClick={() => updateDb(d => ({ ...d, invoices: d.invoices.map(x => x.id === inv.id ? { ...x, lastReminder: new Date().toISOString() } : x) }))} className="text-[11px] font-medium text-[#1A8CB8] bg-[#E5F2FF] px-2.5 py-1 rounded-lg">
                              {inv.lastReminder ? 'Remind again' : 'Send reminder'}
                            </button>
                          </div>
                        )}
                        {inv.status === 'archived' && (
                          <button onClick={() => updateDb(d => ({ ...d, invoices: d.invoices.map(x => x.id === inv.id ? { ...x, status: 'sent', sentAt: new Date().toISOString() } : x) }))} className="text-[11px] font-medium text-[#1A8CB8] mt-1.5">Send to customer →</button>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </Section>
          );
        })()}

        {editing && (
          <button onClick={removeCustomer} className="w-full bg-white border border-black/5 rounded-2xl py-3.5 text-[#FF3B30] font-medium mt-2 hover:bg-[#FFF5F5]">Remove customer</button>
        )}
      </div>
    </div>
  );
}

function ActionTile({ icon: Icon, label, onClick, primary }) {
  return (
    <button onClick={onClick} className={`flex flex-col items-center gap-1.5 py-3.5 rounded-2xl border ${primary ? 'bg-[#1A8CB8] hover:bg-[#157aa1] text-white border-transparent shadow-md shadow-[#1A8CB8]/20' : 'bg-white text-[#1A8CB8] border-black/5 hover:bg-[#FAFAFA]'}`}>
      <Icon className="w-5 h-5" />
      <span className="text-[12px] font-medium">{label}</span>
    </button>
  );
}
function Stat({ label, value, tone }) {
  const tc = tone === 'success' ? 'text-[#1F8B3E]' : 'text-[#1D1D1F]';
  return (
    <div>
      <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B]">{label}</div>
      <div className={`text-[22px] font-semibold tracking-tight ${tc}`}>{value}</div>
    </div>
  );
}

/* ============================================================================
   NEW CUSTOMER FORM
   ============================================================================ */
function CustomerForm({ db, updateDb, onBack }) {
  const [c, setC] = useState({
    name: '', address: '', city: '', phone: '', email: '',
    poolSize: 15000, poolType: 'Chlorine', filterType: 'Cartridge', filterPsiBaseline: 12, cleaner: 'None', poolRx: false, serviceRate: 150, serviceFreq: 'Weekly', notes: '',
  });
  const upd = (patch) => setC(p => ({ ...p, ...patch }));
  const valid = c.name.trim() && c.address.trim();
  const save = async () => {
    const customer = { ...c, id: uid('c'), lat: null, lng: null, addedDate: todayISO() };
    updateDb(d => ({ ...d, customers: [...d.customers, customer] }));
    // Geocode in background after save
    if (c.address && c.city) {
      geocodeAddress(c.address, c.city).then(coords => {
        if (coords) {
          updateDb(d => ({
            ...d,
            customers: d.customers.map(x => x.id === customer.id ? { ...x, lat: coords.lat, lng: coords.lng } : x),
          }));
        }
      });
    }
    onBack();
  };
  return (
    <div className="min-h-screen bg-[#F5F5F7] pb-12" style={fontStack}>
      <div className="bg-white/85 backdrop-blur-xl border-b border-black/5 sticky top-0 z-30">
        <div className="max-w-2xl mx-auto px-3 py-3 flex items-center justify-between">
          <button onClick={onBack} className="text-[#1A8CB8] px-2 text-[15px]">Cancel</button>
          <h1 className="text-[16px] font-semibold">New customer</h1>
          <button onClick={save} disabled={!valid} className={`px-3 py-1.5 rounded-full text-[14px] font-medium ${valid ? 'bg-[#1A8CB8] text-white' : 'text-[#C7C7CC]'}`}>Save</button>
        </div>
      </div>
      <div className="max-w-2xl mx-auto px-5 pt-6">
        <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3 mb-4">
          <Field label="Name *"><input className={inputCls} value={c.name} onChange={e => upd({ name: e.target.value })} placeholder="The Smith Family" /></Field>
          <Field label="Address *"><input className={inputCls} value={c.address} onChange={e => upd({ address: e.target.value })} placeholder="123 Main St" /></Field>
          <Field label="City"><input className={inputCls} value={c.city} onChange={e => upd({ city: e.target.value })} placeholder="Cerritos, CA" /></Field>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Phone"><input className={inputCls} value={c.phone} onChange={e => upd({ phone: e.target.value })} /></Field>
            <Field label="Email"><input className={inputCls} value={c.email} onChange={e => upd({ email: e.target.value })} /></Field>
          </div>
        </div>
        <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3 mb-4">
          <h3 className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider">Pool</h3>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Size (gal)"><input type="number" className={inputCls} value={c.poolSize} onChange={e => upd({ poolSize: +e.target.value })} /></Field>
            <Field label="Type"><select className={inputCls} value={c.poolType} onChange={e => upd({ poolType: e.target.value })}><option>Chlorine</option><option>Salt</option><option>Bromine</option><option>Mineral</option></select></Field>
          </div>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Filter type"><select className={inputCls} value={c.filterType} onChange={e => upd({ filterType: e.target.value })}><option>Cartridge</option><option>DE</option><option>Sand</option></select></Field>
            <Field label="Cleaner"><select className={inputCls} value={c.cleaner} onChange={e => upd({ cleaner: e.target.value })}>{CLEANER_OPTIONS.map(o => <option key={o}>{o}</option>)}</select></Field>
          </div>
          <Field label="Filter clean baseline (PSI when freshly cleaned)">
            <input type="number" step="1" inputMode="numeric" className={inputCls} value={c.filterPsiBaseline} onChange={e => upd({ filterPsiBaseline: +e.target.value })} placeholder="e.g., 12" />
          </Field>
          <Field label="Pool RX (biannual phosphate program)">
            <select className={inputCls} value={c.poolRx ? 'Yes' : 'No'} onChange={e => upd({ poolRx: e.target.value === 'Yes' })}>
              <option>No</option>
              <option>Yes</option>
            </select>
          </Field>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Rate ($/mo)"><input type="number" className={inputCls} value={c.serviceRate} onChange={e => upd({ serviceRate: +e.target.value })} /></Field>
            <Field label="Frequency"><select className={inputCls} value={c.serviceFreq} onChange={e => upd({ serviceFreq: e.target.value })}><option>Weekly</option><option>2x Weekly</option><option>Bi-weekly</option><option>Monthly</option></select></Field>
          </div>
        </div>
        <div className="bg-white rounded-2xl border border-black/5 p-4">
          <Field label="Notes"><textarea rows={4} className={inputCls} value={c.notes} onChange={e => upd({ notes: e.target.value })} placeholder="Gate code, pet info, anything to remember…" /></Field>
        </div>
      </div>
    </div>
  );
}

/* ============================================================================
   SERVICE STOP — the core quick-input flow with auto-save
   ============================================================================ */
function ServiceStop({ visitId, db, updateDb, saveState, onClose }) {
  const visit = db.visits.find(v => v.id === visitId);
  const customer = visit ? db.customers.find(c => c.id === visit.customerId) : null;

  if (!visit || !customer) {
    return (
      <div className="min-h-screen bg-[#F5F5F7] flex items-center justify-center" style={fontStack}>
        <button onClick={onClose} className="text-[#1A8CB8]">Visit not found — go back</button>
      </div>
    );
  }

  const updateVisit = (patch) => updateDb(d => ({
    ...d,
    visits: d.visits.map(v => v.id === visit.id ? { ...v, ...patch } : v),
  }));

  // Water body tab support
  const waterBodies = customer.waterBodies || [];
  const hasMultipleBodies = waterBodies.length > 0;
  const [activeWaterBody, setActiveWaterBody] = useState('primary');

  // Get/set readings for the active water body
  const getActiveReadings = () => {
    if (activeWaterBody === 'primary') return visit.waterReadings;
    return (visit.waterBodyData || {})[activeWaterBody]?.waterReadings || { fc: '', ph: '', alk: '', cal: '', cya: '' };
  };

  const updateActiveReadings = (patch) => {
    if (activeWaterBody === 'primary') {
      updateVisit({ waterReadings: { ...visit.waterReadings, ...patch } });
    } else {
      const wbd = visit.waterBodyData || {};
      const current = wbd[activeWaterBody] || { waterReadings: { fc: '', ph: '', alk: '', cal: '', cya: '' }, notes: '' };
      updateVisit({ waterBodyData: { ...wbd, [activeWaterBody]: { ...current, waterReadings: { ...current.waterReadings, ...patch } } } });
    }
  };

  const activeReadings = getActiveReadings();
  const activeWaterBodyInfo = activeWaterBody === 'primary' ? null : waterBodies.find(w => w.id === activeWaterBody);
  const activeWaterBodyType = activeWaterBodyInfo ? (WATER_BODY_TYPES.find(t => t.id === activeWaterBodyInfo.type) || WATER_BODY_TYPES[0]) : null;

  const updateReadings = (patch) => updateActiveReadings(patch);
  const updateChecklist = (key) => updateVisit({ checklist: { ...visit.checklist, [key]: !visit.checklist[key] } });

  const addChemical = (chemId) => {
    if (visit.chemicalsUsed.find(x => x.chemId === chemId)) return;
    updateVisit({ chemicalsUsed: [...visit.chemicalsUsed, { chemId, amount: 1 }] });
  };
  const setChemAmount = (chemId, amount) => {
    if (amount <= 0) {
      updateVisit({ chemicalsUsed: visit.chemicalsUsed.filter(x => x.chemId !== chemId) });
    } else {
      updateVisit({ chemicalsUsed: visit.chemicalsUsed.map(x => x.chemId === chemId ? { ...x, amount } : x) });
    }
  };

  const [showInvoicePreview, setShowInvoicePreview] = useState(false);

  // Build invoice line items for this visit
  const buildInvoiceItems = () => {
    const items = [];
    // Monthly service (prorated per visit based on frequency)
    const freqMap = { 'Weekly': 4, '2x Weekly': 8, 'Bi-weekly': 2, 'Monthly': 1 };
    const visitsPerMonth = freqMap[customer.serviceFreq] || 4;
    const perVisitRate = customer.serviceRate / visitsPerMonth;
    items.push({ label: `Pool service - ${customer.serviceFreq}`, amount: perVisitRate, type: 'service' });
    // Filter clean
    if (visit.filterCleaned && (db.profile.filterCleanPrice || 0) > 0) {
      items.push({ label: 'Filter clean', amount: db.profile.filterCleanPrice, type: 'addon' });
    }
    // Pool RX dose
    if (visit.poolRxDosed && (db.profile.poolRxPrice || 0) > 0) {
      items.push({ label: 'Pool RX treatment', amount: db.profile.poolRxPrice, type: 'addon' });
    }
    // Chemical costs (pass-through if desired)
    const chemTotal = visitChemCost(visit, db.chemicals);
    if (chemTotal > 0) {
      items.push({ label: `Chemicals used (${visit.chemicalsUsed.length} items)`, amount: chemTotal, type: 'chemical' });
    }
    return items;
  };

  const invoiceItems = buildInvoiceItems();
  const invoiceTotal = invoiceItems.reduce((s, i) => s + i.amount, 0);

  const completeVisit = (invoiceStatus) => {
    const completedAt = new Date().toISOString();
    const invoice = {
      id: uid('inv'), visitId: visit.id, customerId: customer.id,
      date: todayISO(), items: buildInvoiceItems(),
      total: buildInvoiceItems().reduce((s, i) => s + i.amount, 0),
      status: invoiceStatus, // 'archived' or 'sent'
      squareInvoiceId: null,
      sentAt: invoiceStatus === 'sent' ? completedAt : null,
      paidAt: null,
    };
    updateDb(d => ({
      ...d,
      visits: d.visits.map(v => v.id === visit.id ? { ...v, completedAt, invoiced: invoiceStatus === 'sent', mileage: null } : v),
      invoices: [...(d.invoices || []), invoice],
    }));
    computeVisitMileage(visit, db, updateDb).then(miles => {
      if (miles != null) {
        updateDb(d => ({
          ...d,
          visits: d.visits.map(v => v.id === visit.id ? { ...v, mileage: miles } : v),
        }));
      }
    });
    onClose();
  };
  const reopenVisit = () => updateVisit({ completedAt: null });

  const isComplete = !!visit.completedAt;
  const checklistCount = Object.values(visit.checklist).filter(Boolean).length;
  const checklistTotal = Object.keys(visit.checklist).length;
  const chemCost = visitChemCost(visit, db.chemicals);
  const stats = customerProfit(customer, db.visits, db.chemicals, db.profile);
  const fStatus = filterStatus(customer.id, db.visits);

  const checklistItems = [
    { key: 'skimmed', label: 'Skimmed surface' },
    { key: 'vacuumed', label: 'Vacuumed pool' },
    { key: 'brushed', label: 'Brushed walls' },
    { key: 'basketsEmptied', label: 'Emptied baskets' },
    { key: 'filterChecked', label: 'Checked filter' },
    { key: 'waterLevel', label: 'Water level OK' },
    { key: 'equipmentInspected', label: 'Equipment inspection' },
  ];

  const readingTargets = {
    fc: { label: 'Free Chlorine', target: '1–3', unit: 'ppm' },
    ph: { label: 'pH', target: '7.4–7.6', unit: '' },
    alk: { label: 'Total Alkalinity', target: '80–120', unit: 'ppm' },
    cal: { label: 'Calcium Hardness', target: '200–400', unit: 'ppm' },
    cya: { label: 'Cyanuric Acid', target: '30–50', unit: 'ppm' },
  };

  return (
    <div className="min-h-screen bg-[#F5F5F7] pb-32" style={fontStack}>
      <SaveIndicator state={saveState} />

      <div className="bg-white/85 backdrop-blur-xl border-b border-black/5 sticky top-0 z-30">
        <div className="max-w-2xl mx-auto px-3 py-3 flex items-center justify-between">
          <button onClick={onClose} className="text-[#1A8CB8] flex items-center gap-1 px-2 py-1 -ml-2 text-[15px]"><ChevronLeft className="w-5 h-5" />Back</button>
          <div className="text-center">
            <div className="text-[10px] font-medium uppercase tracking-wider text-[#86868B]">{shortDate(visit.date)}</div>
            <div className="text-[15px] font-semibold leading-tight">{customer.name}</div>
          </div>
          <div className="w-12" />
        </div>
      </div>

      <div className="max-w-2xl mx-auto px-5 pt-5">
        {/* Customer mini-card */}
        <div className="bg-white rounded-2xl border border-black/5 p-4 mb-5">
          <div className="flex items-center gap-3">
            <div className="w-10 h-10 rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center font-medium text-[14px] flex-shrink-0">
              {customer.name.split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
            </div>
            <div className="flex-1 min-w-0">
              <div className="flex items-center gap-2 mb-0.5">
                <div className="text-[14px] text-[#86868B] truncate">{customer.address}</div>
                {customer.poolRx && <PoolRxBadge size="lg" />}
              </div>
              <div className="text-[12px] text-[#86868B] flex items-center gap-1.5 flex-wrap">
                <span>{customer.poolSize.toLocaleString()} gal · {customer.poolType} · {customer.filterType || 'Cartridge'} filter</span>
                {(() => {
                  const cBadge = cleanerBadge(customer.cleaner);
                  return cBadge ? (
                    <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md" style={{ color: cBadge.color, backgroundColor: cBadge.bg }}>{cBadge.label}</span>
                  ) : (
                    <span className="text-[10px] font-medium uppercase tracking-wider px-1.5 py-0.5 rounded-md text-[#86868B] bg-[#F2F2F7]">Manual vac</span>
                  );
                })()}
              </div>
            </div>
            {customer.notes && (
              <div className="bg-[#FFF3CD]/40 text-[#8A6D3B] rounded-lg px-2 py-1 text-[11px] max-w-[140px] truncate" title={customer.notes}>{customer.notes}</div>
            )}
          </div>
        </div>

        {/* Water body tabs — only shown when customer has additional water bodies */}
        {hasMultipleBodies && (
          <div className="flex gap-1.5 overflow-x-auto pb-1 mb-4 -mx-1 px-1" style={{ scrollbarWidth: 'none' }}>
            <button onClick={() => setActiveWaterBody('primary')} className={`flex-shrink-0 flex items-center gap-1.5 px-3.5 py-2 rounded-xl text-[13px] font-medium transition-all ${activeWaterBody === 'primary' ? 'bg-[#1A8CB8] text-white shadow-md shadow-[#1A8CB8]/20' : 'bg-white border border-black/5 text-[#1D1D1F]'}`}>
              🏊 <span>Main Pool</span>
              <span className="text-[11px] opacity-70">{customer.poolSize.toLocaleString()}g</span>
            </button>
            {waterBodies.map(wb => {
              const wbType = WATER_BODY_TYPES.find(t => t.id === wb.type) || WATER_BODY_TYPES[0];
              const isActive = activeWaterBody === wb.id;
              return (
                <button key={wb.id} onClick={() => setActiveWaterBody(wb.id)} className={`flex-shrink-0 flex items-center gap-1.5 px-3.5 py-2 rounded-xl text-[13px] font-medium transition-all ${isActive ? 'bg-[#1A8CB8] text-white shadow-md shadow-[#1A8CB8]/20' : 'bg-white border border-black/5 text-[#1D1D1F]'}`}>
                  {wbType.icon} <span>{wb.name || wbType.label}</span>
                  <span className="text-[11px] opacity-70">{(wb.size || 0).toLocaleString()}g</span>
                </button>
              );
            })}
          </div>
        )}

        {/* Active water body info banner (when on secondary body) */}
        {activeWaterBody !== 'primary' && activeWaterBodyInfo && (
          <div className="bg-white rounded-2xl border border-black/5 px-4 py-3 mb-5 flex items-center gap-3">
            <div className="text-2xl">{activeWaterBodyType?.icon}</div>
            <div className="flex-1">
              <div className="text-[14px] font-medium">{activeWaterBodyInfo.name || activeWaterBodyType?.label}</div>
              <div className="text-[11px] text-[#86868B]">{(activeWaterBodyInfo.size || 0).toLocaleString()} gal · {activeWaterBodyInfo.poolType} · {activeWaterBodyInfo.filterType}{activeWaterBodyInfo.address ? ` · ${activeWaterBodyInfo.address}` : ''}</div>
            </div>
          </div>
        )}

        {/* This pool — financial summary */}
        <Section title="This pool" subtitle={stats.rxDoses > 0 ? `Profitability · ${stats.rxDoses} Pool RX dose${stats.rxDoses > 1 ? 's' : ''} contributing ${fmt0(stats.rxRevenue)}` : 'Profitability based on visit history'}>
          <div className="bg-white rounded-2xl p-5 border border-black/5">
            <div className="grid grid-cols-2 gap-4">
              <Stat label="Revenue" value={fmt0(stats.revenue)} />
              <Stat label="Profit" value={fmt0(stats.profit)} tone="success" />
              <Stat label="Chemicals" value={fmt(stats.chemCost)} />
              <Stat label="Labor" value={fmt(stats.laborCost)} />
            </div>
            <div className="mt-4 pt-4 border-t border-black/5 flex items-center justify-between">
              <span className="text-[13px] text-[#86868B]">Margin</span>
              <span className={`text-[15px] font-semibold ${stats.margin > 50 ? 'text-[#1F8B3E]' : stats.margin > 25 ? 'text-[#1D1D1F]' : 'text-[#C77400]'}`}>{stats.margin.toFixed(1)}%</span>
            </div>
          </div>
        </Section>

        {/* Water readings — color coded */}
        <Section title="Water readings" subtitle="Numbers turn green when in range, red when out">
          <div className="bg-white rounded-2xl border border-black/5 p-4 grid grid-cols-2 gap-3">
            {Object.entries(readingTargets).map(([k, info]) => {
              const tone = readingTone(k, activeReadings[k]);
              const color = tone ? TONE_COLOR[tone] : '#1D1D1F';
              return (
                <div key={k}>
                  <div className="flex items-center gap-1.5 mb-1">
                    <label className="block text-[11px] font-medium text-[#86868B] uppercase tracking-wider">{info.label}</label>
                    {tone && <div className="w-1.5 h-1.5 rounded-full" style={{ backgroundColor: color }} />}
                  </div>
                  <div className="relative">
                    <input
                      type="number"
                      inputMode="decimal"
                      step="0.1"
                      value={activeReadings[k]}
                      onChange={e => updateReadings({ [k]: e.target.value })}
                      placeholder={info.target}
                      style={{ color }}
                      className="w-full bg-[#F2F2F7] border-0 rounded-xl px-3 py-2.5 text-[18px] font-semibold tabular-nums placeholder-[#C7C7CC] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30 transition-colors"
                    />
                    {info.unit && <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[12px] text-[#86868B] pointer-events-none">{info.unit}</span>}
                  </div>
                  <div className="text-[10px] text-[#86868B] mt-1">Target: {info.target} {info.unit}</div>
                </div>
              );
            })}
          </div>
        </Section>

        {/* Pool condition — algae severity */}
        <Section title="Pool condition" subtitle={ALGAE_LEVELS[visit.algaeLevel || 0].description}>
          <div className="bg-white rounded-2xl border border-black/5 p-3">
            <div className="flex gap-1.5">
              {ALGAE_LEVELS.map((lvl, i) => {
                const selected = (visit.algaeLevel || 0) === i;
                return (
                  <button
                    key={i}
                    onClick={() => updateVisit({ algaeLevel: i })}
                    className={`flex-1 rounded-xl py-2 px-1 transition-all ${selected ? 'bg-[#F2F2F7] ring-2 ring-[#1A8CB8]/40' : 'bg-transparent hover:bg-[#F5F5F7]'}`}
                  >
                    <div className="w-full h-3 rounded-full mb-1.5 mx-auto" style={{ backgroundColor: lvl.color, opacity: selected ? 1 : 0.55 }} />
                    <div className={`text-[11px] font-medium ${selected ? 'text-[#1D1D1F]' : 'text-[#86868B]'}`}>{lvl.label}</div>
                  </button>
                );
              })}
            </div>
          </div>
        </Section>

        {/* Chemicals added */}
        <Section title="Chemicals added" subtitle={visit.chemicalsUsed.length > 0 ? `${visit.chemicalsUsed.length} added · ${fmt(chemCost)} cost` : 'Tap below to add'}>
          {visit.chemicalsUsed.length > 0 && (
            <div className="bg-white rounded-2xl border border-black/5 mb-3 overflow-hidden">
              {visit.chemicalsUsed.map((cu, i) => {
                const ch = db.chemicals.find(x => x.id === cu.chemId);
                if (!ch) return null;
                const isCountable = ch.unit === 'tab';
                const step = isCountable ? 1 : 0.5;
                const unitLabel = isCountable && cu.amount !== 1 ? `${ch.unit}s` : ch.unit;
                return (
                  <div key={cu.chemId} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                    <div className="w-9 h-9 rounded-full bg-[#1A8CB8]/10 text-[#1A8CB8] flex items-center justify-center flex-shrink-0">
                      <Beaker className="w-4 h-4" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <div className="text-[14px] font-medium truncate">{ch.name}</div>
                      <div className="text-[11px] text-[#86868B]">{fmt(ch.costPerUnit * cu.amount)} · {fmt(ch.costPerUnit)}/{ch.unit}</div>
                    </div>
                    <div className="flex items-center gap-2">
                      <button onClick={() => setChemAmount(cu.chemId, +(cu.amount - step).toFixed(2))} className="w-8 h-8 rounded-full bg-[#F2F2F7] flex items-center justify-center active:bg-[#E5E5EA]">
                        <Minus className="w-4 h-4 text-[#1D1D1F]" />
                      </button>
                      <div className="text-[14px] font-medium tabular-nums w-16 text-center">{cu.amount} {unitLabel}</div>
                      <button onClick={() => setChemAmount(cu.chemId, +(cu.amount + step).toFixed(2))} className="w-8 h-8 rounded-full bg-[#F2F2F7] flex items-center justify-center active:bg-[#E5E5EA]">
                        <Plus className="w-4 h-4 text-[#1D1D1F]" />
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
          <div className="flex flex-wrap gap-2">
            {db.chemicals.filter(ch => !visit.chemicalsUsed.find(cu => cu.chemId === ch.id)).map(ch => (
              <button key={ch.id} onClick={() => addChemical(ch.id)} className="bg-white border border-black/5 hover:bg-[#F5F5F7] rounded-full px-3.5 py-1.5 text-[13px] font-medium text-[#1D1D1F] flex items-center gap-1">
                <Plus className="w-3.5 h-3.5 text-[#1A8CB8]" strokeWidth={2.5} />{ch.name}
              </button>
            ))}
          </div>
        </Section>

        {/* Tasks checklist */}
        <Section title="Tasks" subtitle={`${checklistCount} of ${checklistTotal} complete`}>
          <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
            {checklistItems.map((item, i) => {
              const done = visit.checklist[item.key];
              return (
                <button key={item.key} onClick={() => updateChecklist(item.key)} className={`w-full flex items-center gap-3 px-4 py-3.5 text-left active:bg-[#F5F5F7] ${i > 0 ? 'border-t border-black/5' : ''}`}>
                  <div className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 transition-colors ${done ? 'bg-[#34C759]' : 'border-[1.5px] border-[#C7C7CC] bg-white'}`}>
                    {done && <Check className="w-4 h-4 text-white" strokeWidth={3} />}
                  </div>
                  <span className={`text-[15px] ${done ? 'text-[#86868B] line-through' : 'text-[#1D1D1F]'}`}>{item.label}</span>
                </button>
              );
            })}
          </div>
        </Section>

        {/* Filter maintenance — pressure tracking + service toggles */}
        {(() => {
          const pred = predictFilterClean(customer.id, db.visits, customer.filterPsiBaseline, visit.filterPsi);
          const psiColor = pred && pred.delta != null ? TONE_COLOR[pred.status] : '#1D1D1F';
          const subtitleParts = [`${customer.filterType || 'Cartridge'} filter`];
          if (fStatus.cleanDue) subtitleParts.push('6mo clean due');
          else if (fStatus.lastCleanDate) subtitleParts.push(`6mo clean in ${fStatus.cleanDueIn}d`);
          if (pred?.daysUntilClean != null && pred.status !== 'critical') subtitleParts.push(`PSI clean ~${pred.daysUntilClean}d`);
          return (
            <Section title="Filter maintenance" subtitle={subtitleParts.join(' · ')}>
              <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                {/* Pressure reading row */}
                <div className="px-4 py-3.5 border-b border-black/5">
                  <div className="flex items-start gap-3">
                    <div className="w-9 h-9 rounded-full bg-[#1A8CB8]/10 text-[#1A8CB8] flex items-center justify-center flex-shrink-0 mt-0.5">
                      <Gauge className="w-4 h-4" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2 mb-1 flex-wrap">
                        <span className="text-[15px] font-medium">Filter pressure</span>
                        {pred?.status === 'critical' && (
                          <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md text-white" style={{ backgroundColor: '#FF3B30' }}>Clean now</span>
                        )}
                      </div>
                      <div className="text-[11px] text-[#86868B]">
                        Baseline {customer.filterPsiBaseline ?? '—'} PSI
                        {pred?.delta != null && (
                          <> · <span style={{ color: psiColor }} className="font-medium">Δ {pred.delta >= 0 ? '+' : ''}{pred.delta} PSI</span></>
                        )}
                        {pred?.rate != null && pred.rate > 0 && (
                          <> · rising {pred.rate.toFixed(2)} PSI/day</>
                        )}
                      </div>
                      {pred?.daysUntilClean != null && pred.status !== 'critical' && (
                        <div className="text-[12px] font-medium mt-1.5" style={{ color: psiColor }}>
                          Clean predicted in ~{pred.daysUntilClean} day{pred.daysUntilClean !== 1 ? 's' : ''}
                        </div>
                      )}
                      {pred?.status === 'critical' && (
                        <div className="text-[12px] font-medium mt-1.5 text-[#FF3B30]">
                          Pressure exceeds clean threshold — clean today
                        </div>
                      )}
                    </div>
                    <div className="relative w-24 flex-shrink-0">
                      <input
                        type="number"
                        inputMode="numeric"
                        step="1"
                        value={visit.filterPsi || ''}
                        onChange={e => updateVisit({ filterPsi: e.target.value })}
                        placeholder="—"
                        style={{ color: psiColor }}
                        className="w-full bg-[#F2F2F7] border-0 rounded-xl px-3 py-2.5 text-[18px] font-semibold tabular-nums text-right placeholder-[#C7C7CC] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30 transition-colors"
                      />
                      <span className="absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-[#86868B] pointer-events-none">PSI</span>
                    </div>
                  </div>
                </div>

                {/* Backwashed toggle */}
                <button onClick={() => updateVisit({ backwashed: !visit.backwashed })} className="w-full flex items-center gap-3 px-4 py-3.5 text-left active:bg-[#F5F5F7]">
                  <div className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 transition-colors ${visit.backwashed ? 'bg-[#34C759]' : 'border-[1.5px] border-[#C7C7CC] bg-white'}`}>
                    {visit.backwashed && <Check className="w-4 h-4 text-white" strokeWidth={3} />}
                  </div>
                  <div className="flex-1">
                    <div className={`text-[15px] ${visit.backwashed ? 'text-[#86868B] line-through' : 'text-[#1D1D1F]'}`}>Backwashed today</div>
                    <div className="text-[11px] text-[#86868B]">{fStatus.lastBackwashDate ? `Last: ${shortDate(fStatus.lastBackwashDate)} (${fStatus.daysSinceBackwash}d ago)` : 'Never logged'}</div>
                  </div>
                </button>

                {/* Filter cleaned toggle — now billable */}
                <button onClick={() => updateVisit({ filterCleaned: !visit.filterCleaned })} className="w-full flex items-center gap-3 px-4 py-3.5 text-left active:bg-[#F5F5F7] border-t border-black/5">
                  <div className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 transition-colors ${visit.filterCleaned ? 'bg-[#34C759]' : fStatus.cleanDue ? 'border-[1.5px] border-[#FF3B30]/40 bg-[#FF3B30]/5' : 'border-[1.5px] border-[#C7C7CC] bg-white'}`}>
                    {visit.filterCleaned && <Check className="w-4 h-4 text-white" strokeWidth={3} />}
                  </div>
                  <div className="flex-1">
                    <div className="flex items-center gap-2">
                      <div className={`text-[15px] ${visit.filterCleaned ? 'text-[#86868B] line-through' : 'text-[#1D1D1F]'}`}>Filter cleaned today {fStatus.cleanDue && !visit.filterCleaned && <span className="text-[12px] text-[#FF3B30] font-medium ml-1">DUE</span>}</div>
                    </div>
                    <div className="text-[11px] text-[#86868B]">{fStatus.lastCleanDate ? `Last: ${shortDate(fStatus.lastCleanDate)} (${fStatus.daysSinceClean}d ago) · 6mo interval` : '6 months recommended interval'}</div>
                  </div>
                  {(db.profile.filterCleanPrice || 0) > 0 && (
                    <div className="text-right flex-shrink-0">
                      <div className="text-[14px] font-semibold text-[#34C759]">+{fmt0(db.profile.filterCleanPrice)}</div>
                      <div className="text-[10px] text-[#86868B]">billable</div>
                    </div>
                  )}
                </button>

                {/* Pool RX dose toggle — only for enrolled customers; billable */}
                {customer.poolRx && (() => {
                  const rx = poolRxStatus(customer.id, db.visits);
                  return (
                    <button onClick={() => updateVisit({ poolRxDosed: !visit.poolRxDosed })} className="w-full flex items-center gap-3 px-4 py-3.5 text-left active:bg-[#F5F5F7] border-t border-black/5">
                      <div className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 transition-colors ${visit.poolRxDosed ? 'bg-[#1A8CB8]' : rx.due ? 'border-[1.5px] border-[#1A8CB8]/40 bg-[#1A8CB8]/5' : 'border-[1.5px] border-[#C7C7CC] bg-white'}`}>
                        {visit.poolRxDosed && <BadgeCheck className="w-4 h-4 text-white" strokeWidth={2.5} />}
                      </div>
                      <div className="flex-1">
                        <div className="flex items-center gap-2">
                          <div className={`text-[15px] ${visit.poolRxDosed ? 'text-[#86868B] line-through' : 'text-[#1D1D1F]'}`}>Pool RX dose applied today</div>
                          {rx.due && !visit.poolRxDosed && <span className="text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded-md text-white" style={{ backgroundColor: '#1A8CB8' }}>Due</span>}
                        </div>
                        <div className="text-[11px] text-[#86868B]">
                          {rx.lastDate ? `Last: ${shortDate(rx.lastDate)} (${rx.daysSince}d ago) · ` : 'Never logged · '}
                          {rx.due ? 'Due now' : `Next due in ${rx.dueInDays}d`} · 6mo interval
                        </div>
                      </div>
                      <div className="text-right flex-shrink-0">
                        <div className="text-[14px] font-semibold text-[#1A8CB8]">+{fmt0(db.profile.poolRxPrice || 0)}</div>
                        <div className="text-[10px] text-[#86868B]">add-on</div>
                      </div>
                    </button>
                  );
                })()}
              </div>
            </Section>
          );
        })()}

        {/* Repairs needed */}
        <Section title="Repairs needed" subtitle="Optional — note anything to follow up on">
          <div className="bg-white rounded-2xl border border-black/5 p-3">
            <textarea rows={2} value={visit.repairsNeeded} onChange={e => updateVisit({ repairsNeeded: e.target.value })} placeholder="e.g., pump is making a grinding noise" className="w-full bg-transparent border-0 text-[14px] resize-none focus:outline-none placeholder-[#C7C7CC]" />
          </div>
        </Section>

        {/* Notes */}
        <Section title="Notes">
          <div className="bg-white rounded-2xl border border-black/5 p-3">
            <textarea rows={2} value={visit.notes} onChange={e => updateVisit({ notes: e.target.value })} placeholder="Anything else to remember about this visit" className="w-full bg-transparent border-0 text-[14px] resize-none focus:outline-none placeholder-[#C7C7CC]" />
          </div>
        </Section>

        {/* Duration */}
        <Section title="Time on site">
          <div className="bg-white rounded-2xl border border-black/5 p-4 flex items-center justify-between">
            <span className="text-[14px] text-[#86868B]">Duration</span>
            <div className="flex items-center gap-2">
              <button onClick={() => updateVisit({ durationMin: Math.max(5, visit.durationMin - 5) })} className="w-8 h-8 rounded-full bg-[#F2F2F7] flex items-center justify-center active:bg-[#E5E5EA]"><Minus className="w-4 h-4" /></button>
              <div className="text-[15px] font-medium tabular-nums w-16 text-center">{visit.durationMin} min</div>
              <button onClick={() => updateVisit({ durationMin: visit.durationMin + 5 })} className="w-8 h-8 rounded-full bg-[#F2F2F7] flex items-center justify-center active:bg-[#E5E5EA]"><Plus className="w-4 h-4" /></button>
            </div>
          </div>
        </Section>

        {/* Complete Stop button — fixed bottom; transforms blue → green when complete */}
        <div className="fixed bottom-0 inset-x-0 bg-gradient-to-t from-[#F5F5F7] via-[#F5F5F7]/95 to-transparent pt-6 pb-5 px-5 z-20">
          <div className="max-w-2xl mx-auto">
            {isComplete ? (
              <>
                <button
                  onClick={reopenVisit}
                  className="w-full bg-[#34C759] hover:bg-[#2DB54D] active:bg-[#27A43F] text-white font-semibold py-4 rounded-2xl shadow-lg shadow-[#34C759]/30 flex items-center justify-center gap-2 text-[16px] transition-colors"
                >
                  <CheckCircle2 className="w-5 h-5" strokeWidth={2.5} />
                  Stop Complete · {new Date(visit.completedAt).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}
                </button>
                <p className="text-center text-[11px] text-[#86868B] mt-2">Tap above to reopen this stop</p>
              </>
            ) : (
              <>
                {/* Invoice preview before completing */}
                {showInvoicePreview && (
                  <div className="bg-white rounded-2xl border border-black/5 p-4 mb-3">
                    <div className="flex items-center justify-between mb-3">
                      <div className="text-[13px] font-semibold text-[#1D1D1F]">Invoice preview</div>
                      <button onClick={() => setShowInvoicePreview(false)} className="text-[#86868B] p-1"><X className="w-4 h-4" /></button>
                    </div>
                    <div className="space-y-2 mb-3">
                      {invoiceItems.map((item, i) => (
                        <div key={i} className="flex items-center justify-between text-[13px]">
                          <div className="flex items-center gap-2">
                            <div className={`w-1.5 h-1.5 rounded-full ${item.type === 'service' ? 'bg-[#1A8CB8]' : item.type === 'addon' ? 'bg-[#34C759]' : 'bg-[#86868B]'}`} />
                            <span className="text-[#1D1D1F]">{item.label}</span>
                          </div>
                          <span className="font-medium">{fmt(item.amount)}</span>
                        </div>
                      ))}
                    </div>
                    <div className="border-t border-black/5 pt-2 flex items-center justify-between">
                      <span className="text-[14px] font-semibold">Total</span>
                      <span className="text-[16px] font-semibold text-[#1A8CB8]">{fmt(invoiceTotal)}</span>
                    </div>
                  </div>
                )}
                {showInvoicePreview ? (
                  <div className="flex gap-2">
                    <button
                      onClick={() => completeVisit('archived')}
                      className="flex-1 bg-[#E5E5EA] hover:bg-[#D1D1D6] active:bg-[#C7C7CC] text-[#1D1D1F] font-semibold py-4 rounded-2xl flex items-center justify-center gap-2 text-[14px] transition-colors"
                    >
                      <BookOpen className="w-4 h-4" strokeWidth={2.5} />Save & Archive
                    </button>
                    <button
                      onClick={() => completeVisit('sent')}
                      className="flex-1 bg-[#1A8CB8] hover:bg-[#157aa1] active:bg-[#0F6586] text-white font-semibold py-4 rounded-2xl shadow-lg shadow-[#1A8CB8]/30 flex items-center justify-center gap-2 text-[14px] transition-colors"
                    >
                      <Send className="w-4 h-4" strokeWidth={2.5} />Send {fmt(invoiceTotal)}
                    </button>
                  </div>
                ) : (
                  <button
                    onClick={() => setShowInvoicePreview(true)}
                    className="w-full bg-[#1A8CB8] hover:bg-[#157aa1] active:bg-[#0F6586] text-white font-semibold py-4 rounded-2xl shadow-lg shadow-[#1A8CB8]/30 flex items-center justify-center gap-2 text-[16px] transition-colors"
                  >
                    <Check className="w-5 h-5" strokeWidth={2.5} />Complete Stop
                  </button>
                )}
                {!showInvoicePreview && (
                  <p className="text-center text-[11px] text-[#86868B] mt-2">Review invoice before completing</p>
                )}
              </>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============================================================================
   REPORTS
   ============================================================================ */
function ReportsView({ db, openSettings }) {
  const [period, setPeriod] = useState(30);

  const customerStats = useMemo(() =>
    db.customers
      .map(c => ({ c, ...customerProfit(c, db.visits, db.chemicals, db.profile) }))
      .sort((a, b) => b.profit - a.profit),
    [db]);

  // Weekly trend data
  const weeklyData = useMemo(() => {
    const weeks = [];
    for (let w = 3; w >= 0; w--) {
      const startOffset = -7 * (w + 1) + 1;
      const endOffset = -7 * w;
      const startD = offsetISO(startOffset);
      const endD = offsetISO(endOffset);
      const weekVisits = db.visits.filter(v => v.date >= startD && v.date <= endD && v.completedAt);
      const customerIds = new Set(weekVisits.map(v => v.customerId));
      const revenue = Array.from(customerIds).reduce((s, id) => s + (db.customers.find(x => x.id === id)?.serviceRate || 0), 0);
      const costs = weekVisits.reduce((s, v) => s + visitChemCost(v, db.chemicals) + visitLaborCost(v, db.profile.laborRate), 0);
      weeks.push({
        label: w === 0 ? 'This week' : `${w}w ago`,
        revenue: Math.round(revenue),
        profit: Math.round(revenue - costs),
        costs: Math.round(costs),
      });
    }
    return weeks;
  }, [db]);

  const totalRevenue = customerStats.reduce((s, x) => s + x.revenue, 0);
  const totalProfit = customerStats.reduce((s, x) => s + x.profit, 0);
  const totalChem = customerStats.reduce((s, x) => s + x.chemCost, 0);

  return (
    <div className="max-w-2xl mx-auto px-5 pt-8">
      <header className="mb-7 flex items-start justify-between gap-3">
        <div>
          <h1 className="text-[32px] font-semibold tracking-tight leading-tight">Reports</h1>
          <p className="text-[13px] text-[#86868B] mt-1">Profit performance across your route</p>
        </div>
        <div className="pt-1"><GearButton onClick={openSettings} /></div>
      </header>

      <div className="grid grid-cols-3 gap-3 mb-7">
        <StatCard label="Revenue" value={fmt0(totalRevenue)} sub="All customers" tone="primary" />
        <StatCard label="Chem cost" value={fmt0(totalChem)} sub="To date" />
        <StatCard label="Profit" value={fmt0(totalProfit)} sub={`${totalRevenue ? Math.round((totalProfit / totalRevenue) * 100) : 0}% margin`} tone="success" />
      </div>

      <Section title="Weekly trend">
        <div className="bg-white rounded-2xl border border-black/5 p-4">
          <div style={{ width: '100%', height: 200 }}>
            <ResponsiveContainer>
              <BarChart data={weeklyData} margin={{ top: 10, right: 10, left: 0, bottom: 0 }}>
                <CartesianGrid strokeDasharray="3 3" stroke="#E5E5EA" vertical={false} />
                <XAxis dataKey="label" stroke="#86868B" fontSize={11} tickLine={false} axisLine={false} />
                <YAxis stroke="#86868B" fontSize={11} tickLine={false} axisLine={false} tickFormatter={(v) => `$${v}`} />
                <Tooltip contentStyle={{ borderRadius: 12, border: '1px solid rgba(0,0,0,0.06)', fontSize: 12 }} formatter={(v) => `$${v}`} />
                <Bar dataKey="revenue" fill="#1A8CB8" radius={[6, 6, 0, 0]} />
                <Bar dataKey="profit" fill="#34C759" radius={[6, 6, 0, 0]} />
              </BarChart>
            </ResponsiveContainer>
          </div>
          <div className="flex items-center gap-4 mt-2 text-[12px]">
            <div className="flex items-center gap-1.5"><div className="w-2.5 h-2.5 rounded-sm bg-[#1A8CB8]" />Revenue</div>
            <div className="flex items-center gap-1.5"><div className="w-2.5 h-2.5 rounded-sm bg-[#34C759]" />Profit</div>
          </div>
        </div>
      </Section>

      {(() => {
        // Algae rollup
        const thisWeekStart = offsetISO(-6);
        const lastWeekStart = offsetISO(-13);
        const lastWeekEnd = offsetISO(-7);
        const thisWeekAlgae = db.visits.filter(v => v.date >= thisWeekStart && v.completedAt && (v.algaeLevel || 0) > 0);
        const lastWeekAlgae = db.visits.filter(v => v.date >= lastWeekStart && v.date <= lastWeekEnd && v.completedAt && (v.algaeLevel || 0) > 0);
        const trend = thisWeekAlgae.length - lastWeekAlgae.length;
        if (thisWeekAlgae.length === 0 && lastWeekAlgae.length === 0) return null;
        return (
          <Section title="Algae issues" subtitle={
            thisWeekAlgae.length === 0
              ? `Clean week — last week had ${lastWeekAlgae.length}`
              : `${thisWeekAlgae.length} this week${trend !== 0 ? (trend > 0 ? ` · +${trend} from last week` : ` · ${trend} from last week`) : ''}`
          }>
            {thisWeekAlgae.length === 0 ? (
              <div className="bg-white rounded-2xl border border-black/5 px-5 py-6 text-center">
                <div className="inline-flex w-10 h-10 rounded-full items-center justify-center mb-2" style={{ backgroundColor: ALGAE_LEVELS[0].color + '33' }}>
                  <Droplet className="w-5 h-5" style={{ color: ALGAE_LEVELS[0].color }} />
                </div>
                <p className="text-[14px] font-medium">No algae reported this week</p>
              </div>
            ) : (
              <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                {thisWeekAlgae.sort((a, b) => (b.algaeLevel || 0) - (a.algaeLevel || 0)).map((v, i) => {
                  const c = db.customers.find(x => x.id === v.customerId);
                  if (!c) return null;
                  const lvl = ALGAE_LEVELS[v.algaeLevel || 0];
                  // Compare to same customer's previous algae reading to show trend
                  const prev = db.visits
                    .filter(x => x.customerId === v.customerId && x.date < v.date && x.completedAt)
                    .sort((a, b) => b.date.localeCompare(a.date))[0];
                  const prevLvl = prev ? (prev.algaeLevel || 0) : null;
                  const trendArrow = prevLvl == null ? null : (v.algaeLevel || 0) < prevLvl ? '↓' : (v.algaeLevel || 0) > prevLvl ? '↑' : '→';
                  const trendColor = trendArrow === '↓' ? '#1F8B3E' : trendArrow === '↑' ? '#FF3B30' : '#86868B';
                  return (
                    <div key={v.id} className={`flex items-center gap-3 px-4 py-3.5 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                      <div className="w-9 h-9 rounded-full flex items-center justify-center flex-shrink-0" style={{ backgroundColor: lvl.color }}>
                        <Droplet className="w-4 h-4 text-white" strokeWidth={2.2} />
                      </div>
                      <div className="flex-1 min-w-0">
                        <div className="text-[14px] font-medium truncate">{c.name}</div>
                        <div className="text-[12px] text-[#86868B]">{shortDate(v.date)} · <span style={{ color: lvl.color }} className="font-medium">{lvl.label}</span></div>
                      </div>
                      {trendArrow && (
                        <div className="text-right">
                          <div className="text-[18px] font-semibold leading-none" style={{ color: trendColor }}>{trendArrow}</div>
                          <div className="text-[10px] text-[#86868B] mt-0.5">{prevLvl != null ? `was ${ALGAE_LEVELS[prevLvl].label.toLowerCase()}` : ''}</div>
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            )}
          </Section>
        );
      })()}

      {/* Repair & add-on revenue analytics */}
      {(() => {
        const repairs = db.repairs || [];
        const completed = repairs.filter(r => r.status === 'completed');
        const pending = repairs.filter(r => r.status !== 'completed' && r.status !== 'cancelled');
        const completedRevenue = completed.reduce((s, r) => s + (r.totalPrice || 0), 0);
        const pendingValue = pending.reduce((s, r) => s + (r.totalPrice || 0), 0);

        // Filter clean revenue
        const allCompleted = db.visits.filter(v => v.completedAt);
        const filterCleans = allCompleted.filter(v => v.filterCleaned).length;
        const fcRevenue = filterCleans * (db.profile.filterCleanPrice || 0);
        const rxDoses = allCompleted.filter(v => v.poolRxDosed).length;
        const rxRevenue = rxDoses * (db.profile.poolRxPrice || 0);

        // Breakdown by repair type
        const byType = {};
        completed.forEach(r => {
          const key = r.typeLabel || r.type;
          if (!byType[key]) byType[key] = { count: 0, revenue: 0, icon: r.icon || '🛠️' };
          byType[key].count++;
          byType[key].revenue += r.totalPrice || 0;
        });
        const typeEntries = Object.entries(byType).sort((a, b) => b[1].revenue - a[1].revenue);
        const totalAddOnRevenue = completedRevenue + fcRevenue + rxRevenue;

        if (repairs.length === 0 && filterCleans === 0 && rxDoses === 0) return null;
        return (
          <Section title="Add-on revenue" subtitle={`${fmt0(totalAddOnRevenue)} total from repairs, filter cleans & Pool RX`}>
            {/* Summary cards */}
            <div className="grid grid-cols-3 gap-3 mb-3">
              <div className="bg-white rounded-2xl border border-black/5 p-3.5 text-center">
                <Wrench className="w-5 h-5 text-[#7C3AED] mx-auto mb-1" />
                <div className="text-[16px] font-semibold">{fmt0(completedRevenue)}</div>
                <div className="text-[10px] text-[#86868B]">{completed.length} repairs</div>
              </div>
              <div className="bg-white rounded-2xl border border-black/5 p-3.5 text-center">
                <Gauge className="w-5 h-5 text-[#34C759] mx-auto mb-1" />
                <div className="text-[16px] font-semibold">{fmt0(fcRevenue)}</div>
                <div className="text-[10px] text-[#86868B]">{filterCleans} cleans</div>
              </div>
              <div className="bg-white rounded-2xl border border-black/5 p-3.5 text-center">
                <BadgeCheck className="w-5 h-5 text-[#1A8CB8] mx-auto mb-1" />
                <div className="text-[16px] font-semibold">{fmt0(rxRevenue)}</div>
                <div className="text-[10px] text-[#86868B]">{rxDoses} doses</div>
              </div>
            </div>
            {/* Pending pipeline */}
            {pending.length > 0 && (
              <div className="bg-[#FFF3E0] rounded-2xl border border-[#FF9500]/20 px-4 py-3 mb-3 flex items-center gap-3">
                <AlertCircle className="w-5 h-5 text-[#FF9500] flex-shrink-0" />
                <div className="flex-1">
                  <div className="text-[13px] font-medium text-[#8A5600]">{pending.length} pending repair{pending.length > 1 ? 's' : ''}</div>
                  <div className="text-[11px] text-[#8A5600]/80">{fmt0(pendingValue)} in quoted/approved/in-progress work</div>
                </div>
              </div>
            )}
            {/* Breakdown by repair type */}
            {typeEntries.length > 0 && (
              <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
                {typeEntries.map(([label, data], i) => (
                  <div key={label} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                    <div className="text-xl flex-shrink-0">{data.icon}</div>
                    <div className="flex-1 min-w-0">
                      <div className="text-[14px] font-medium">{label}</div>
                      <div className="text-[11px] text-[#86868B]">{data.count} completed</div>
                    </div>
                    <div className="text-[14px] font-semibold text-[#1F8B3E]">{fmt0(data.revenue)}</div>
                  </div>
                ))}
              </div>
            )}
          </Section>
        );
      })()}

      <Section title="Profit per customer" subtitle="Sorted by total profit">
        <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
          {customerStats.map((s, i) => {
            const marginColor = s.margin > 50 ? 'text-[#1F8B3E]' : s.margin > 25 ? 'text-[#1D1D1F]' : 'text-[#C77400]';
            const barWidth = totalRevenue ? (s.revenue / customerStats[0].revenue) * 100 : 0;
            return (
              <div key={s.c.id} className={`px-4 py-3.5 ${i > 0 ? 'border-t border-black/5' : ''}`}>
                <div className="flex items-center justify-between mb-2">
                  <div className="flex-1 min-w-0">
                    <div className="text-[14px] font-medium truncate">{s.c.name}</div>
                    <div className="text-[11px] text-[#86868B]">{s.visits} visits · {fmt(s.chemCost)} chems · {fmt(s.laborCost)} labor</div>
                  </div>
                  <div className="text-right ml-3">
                    <div className="text-[14px] font-semibold text-[#1F8B3E]">{fmt0(s.profit)}</div>
                    <div className={`text-[11px] font-medium ${marginColor}`}>{s.margin.toFixed(0)}% margin</div>
                  </div>
                </div>
                <div className="h-1.5 bg-[#F2F2F7] rounded-full overflow-hidden">
                  <div className="h-full bg-gradient-to-r from-[#5BC0DE] to-[#1A8CB8]" style={{ width: `${barWidth}%` }} />
                </div>
              </div>
            );
          })}
        </div>
      </Section>

      <div className="bg-[#FFF8E5] border border-[#F5C842]/30 rounded-2xl p-4 mb-7">
        <div className="flex items-start gap-3">
          <AlertCircle className="w-5 h-5 text-[#C77400] flex-shrink-0 mt-0.5" />
          <div className="flex-1">
            <div className="text-[13px] font-semibold text-[#5C4400] mb-1">Profit math note</div>
            <p className="text-[12px] text-[#5C4400] leading-relaxed">
              Margins assume your labor rate of {fmt(db.profile.laborRate)}/hr from Settings. Adjust there if it's wrong. Revenue uses the customer's monthly rate × estimated months active.
            </p>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============================================================================
   SETTINGS
   ============================================================================ */
function SettingsView({ db, updateDb, onBack }) {
  const updateProfile = (patch) => updateDb(d => ({ ...d, profile: { ...d.profile, ...patch } }));
  const profileSyncTimer = useRef(null);

  // Debounced Supabase sync — fires 600ms after the last profile edit
  useEffect(() => {
    if (!db.profile.onboarded) return;
    const session = supa.auth.getSession();
    if (!session) return;
    if (profileSyncTimer.current) clearTimeout(profileSyncTimer.current);
    profileSyncTimer.current = setTimeout(() => {
      supa.from('profiles').update({
        owner_name: db.profile.name || null,
        business_name: db.profile.businessName || null,
        email: db.profile.email || null,
        phone: db.profile.phone || null,
        labor_rate: db.profile.laborRate,
        default_visit_duration_min: db.profile.defaultVisitMins,
        pool_rx_price: db.profile.poolRxPrice,
      }).eq('id', session.user.id);
    }, 600);
    return () => profileSyncTimer.current && clearTimeout(profileSyncTimer.current);
  }, [db.profile.name, db.profile.businessName, db.profile.email, db.profile.phone, db.profile.laborRate, db.profile.defaultVisitMins, db.profile.poolRxPrice]);

  const handleSignOut = async () => {
    if (!confirm('Sign out of Routebook?')) return;
    await supa.auth.signOut();
  };
  const updateSettings = (patch) => updateDb(d => ({ ...d, settings: { ...d.settings, ...patch } }));

  const [editingChem, setEditingChem] = useState(null);
  const [showAddChem, setShowAddChem] = useState(false);
  const [newChem, setNewChem] = useState({ name: '', unit: 'lb', costPerUnit: 0 });

  const addChem = () => {
    if (!newChem.name.trim()) return;
    updateDb(d => ({ ...d, chemicals: [...d.chemicals, { ...newChem, id: uid('ch') }] }));
    setNewChem({ name: '', unit: 'lb', costPerUnit: 0 });
    setShowAddChem(false);
  };
  const updateChem = (id, patch) => updateDb(d => ({ ...d, chemicals: d.chemicals.map(c => c.id === id ? { ...c, ...patch } : c) }));
  const deleteChem = (id) => updateDb(d => ({ ...d, chemicals: d.chemicals.filter(c => c.id !== id) }));

  const resetData = () => {
    if (!confirm('Reset all data including customers and visits? This cannot be undone.')) return;
    updateDb(defaultDB());
  };

  return (
    <div className="min-h-screen bg-[#F5F5F7] pb-12" style={fontStack}>
      <div className="bg-white/85 backdrop-blur-xl border-b border-black/5 sticky top-0 z-30">
        <div className="max-w-2xl mx-auto px-3 py-3 flex items-center gap-2">
          <button onClick={onBack} className="text-[#1A8CB8] flex items-center gap-1 px-2 py-1 -ml-2 text-[15px]"><ChevronLeft className="w-5 h-5" />Back</button>
          <div className="flex-1 text-center"><h1 className="text-[16px] font-semibold">Settings</h1></div>
          <div className="w-12" />
        </div>
      </div>

      <div className="max-w-2xl mx-auto px-5 pt-6">
        <div className="mb-7">
          <p className="text-[13px] text-[#86868B]">{db.profile.businessName}</p>
        </div>

      <Section title="Profile">
        <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3">
          <Field label="Your name"><input className={inputCls} value={db.profile.name} onChange={e => updateProfile({ name: e.target.value })} /></Field>
          <Field label="Business name"><input className={inputCls} value={db.profile.businessName} onChange={e => updateProfile({ businessName: e.target.value })} /></Field>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Email"><input className={inputCls} value={db.profile.email} onChange={e => updateProfile({ email: e.target.value })} /></Field>
            <Field label="Phone"><input className={inputCls} value={db.profile.phone} onChange={e => updateProfile({ phone: e.target.value })} /></Field>
          </div>
          <div className="pt-2 border-t border-black/5">
            <div className="text-[11px] font-medium uppercase tracking-wider text-[#86868B] mb-2 flex items-center gap-1.5">
              <Navigation className="w-3 h-3" />Business address
            </div>
            <p className="text-[11px] text-[#86868B] mb-2">Your daily starting point for mileage tracking.</p>
            <div className="grid grid-cols-1 gap-3">
              <Field label="Street address">
                <input className={inputCls} value={db.profile.businessAddress} onChange={e => updateProfile({ businessAddress: e.target.value, businessLat: null, businessLng: null })} placeholder="123 Main St" onBlur={() => {
                  if (db.profile.businessAddress && db.profile.businessCity) {
                    geocodeAddress(db.profile.businessAddress, db.profile.businessCity).then(coords => {
                      if (coords) updateProfile({ businessLat: coords.lat, businessLng: coords.lng });
                    });
                  }
                }} />
              </Field>
              <Field label="City, State ZIP">
                <input className={inputCls} value={db.profile.businessCity} onChange={e => updateProfile({ businessCity: e.target.value, businessLat: null, businessLng: null })} placeholder="Cerritos, CA 90703" onBlur={() => {
                  if (db.profile.businessAddress && db.profile.businessCity) {
                    geocodeAddress(db.profile.businessAddress, db.profile.businessCity).then(coords => {
                      if (coords) updateProfile({ businessLat: coords.lat, businessLng: coords.lng });
                    });
                  }
                }} />
              </Field>
            </div>
            {db.profile.businessLat != null && db.profile.businessLng != null && (
              <div className="flex items-center gap-1.5 mt-2">
                <div className="w-1.5 h-1.5 rounded-full bg-[#34C759]" />
                <span className="text-[11px] text-[#1F8B3E] font-medium">Address verified</span>
              </div>
            )}
            {db.profile.businessAddress && db.profile.businessCity && db.profile.businessLat == null && (
              <div className="flex items-center gap-1.5 mt-2">
                <div className="w-1.5 h-1.5 rounded-full bg-[#FF9500]" />
                <span className="text-[11px] text-[#C77400] font-medium">Tap out of the field to verify address</span>
              </div>
            )}
          </div>
          <div className="grid grid-cols-2 gap-3">
            <Field label="Labor rate ($/hr)"><input type="number" className={inputCls} value={db.profile.laborRate} onChange={e => updateProfile({ laborRate: +e.target.value })} /></Field>
            <Field label="Default visit (min)"><input type="number" className={inputCls} value={db.profile.defaultVisitMins} onChange={e => updateProfile({ defaultVisitMins: +e.target.value })} /></Field>
          </div>
          <Field label="Pool RX dose price ($)">
            <input type="number" step="1" className={inputCls} value={db.profile.poolRxPrice ?? 50} onChange={e => updateProfile({ poolRxPrice: +e.target.value })} />
          </Field>
          <Field label="Filter clean price ($)">
            <input type="number" step="1" className={inputCls} value={db.profile.filterCleanPrice ?? 75} onChange={e => updateProfile({ filterCleanPrice: +e.target.value })} />
          </Field>
        </div>
      </Section>

      <Section title="Chemicals" subtitle="Your price list — used for cost calculations" action={
        <button onClick={() => setShowAddChem(s => !s)} className="text-[#1A8CB8] text-[14px] font-medium flex items-center gap-1">
          <Plus className="w-4 h-4" strokeWidth={2.5} />Add
        </button>
      }>
        {showAddChem && (
          <div className="bg-white rounded-2xl border border-black/5 p-4 mb-3">
            <Field label="Name"><input className={inputCls} value={newChem.name} onChange={e => setNewChem({ ...newChem, name: e.target.value })} placeholder="Chlorine Tabs" autoFocus /></Field>
            <div className="grid grid-cols-2 gap-3 mt-3">
              <Field label="Unit"><select className={inputCls} value={newChem.unit} onChange={e => setNewChem({ ...newChem, unit: e.target.value })}><option>lb</option><option>gal</option><option>oz</option><option>tab</option></select></Field>
              <Field label={`Cost per ${newChem.unit}`}><input type="number" step="0.01" className={inputCls} value={newChem.costPerUnit} onChange={e => setNewChem({ ...newChem, costPerUnit: +e.target.value })} /></Field>
            </div>
            <div className="flex gap-2 mt-3">
              <button onClick={() => { setShowAddChem(false); setNewChem({ name: '', unit: 'lb', costPerUnit: 0 }); }} className="flex-1 bg-[#F2F2F7] text-[#1D1D1F] py-2.5 rounded-xl font-medium text-[14px]">Cancel</button>
              <button onClick={addChem} className="flex-1 bg-[#1A8CB8] text-white py-2.5 rounded-xl font-medium text-[14px]">Add chemical</button>
            </div>
          </div>
        )}
        <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
          {db.chemicals.map((ch, i) => (
            <div key={ch.id} className={`flex items-center gap-3 px-4 py-3 ${i > 0 ? 'border-t border-black/5' : ''}`}>
              <div className="w-9 h-9 rounded-full bg-[#1A8CB8]/10 text-[#1A8CB8] flex items-center justify-center flex-shrink-0">
                <Beaker className="w-4 h-4" />
              </div>
              {editingChem === ch.id ? (
                <>
                  <input className="flex-1 bg-[#F2F2F7] rounded-lg px-2 py-1 text-[14px] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30" value={ch.name} onChange={e => updateChem(ch.id, { name: e.target.value })} />
                  <input type="number" step="0.01" className="w-20 bg-[#F2F2F7] rounded-lg px-2 py-1 text-[14px] focus:outline-none focus:ring-2 focus:ring-[#1A8CB8]/30" value={ch.costPerUnit} onChange={e => updateChem(ch.id, { costPerUnit: +e.target.value })} />
                  <button onClick={() => setEditingChem(null)} className="text-[#1A8CB8] text-[13px] font-medium">Done</button>
                </>
              ) : (
                <>
                  <div className="flex-1 min-w-0">
                    <div className="text-[14px] font-medium truncate">{ch.name}</div>
                    <div className="text-[11px] text-[#86868B]">{fmt(ch.costPerUnit)} per {ch.unit}</div>
                  </div>
                  <button onClick={() => setEditingChem(ch.id)} className="text-[#1A8CB8] p-1.5"><Edit3 className="w-4 h-4" /></button>
                  <button onClick={() => deleteChem(ch.id)} className="text-[#86868B] p-1.5"><Trash2 className="w-4 h-4" /></button>
                </>
              )}
            </div>
          ))}
        </div>
      </Section>

      <Section title="Team" subtitle="Multi-tech support — coming in Phase 2">
        <div className="bg-white rounded-2xl border border-black/5 overflow-hidden">
          <div className="flex items-center gap-3 px-4 py-3">
            <div className="w-10 h-10 rounded-full bg-gradient-to-br from-[#5BC0DE] to-[#1A8CB8] text-white flex items-center justify-center font-medium text-[14px] flex-shrink-0">
              {(db.profile.name || 'You').split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase() || 'YOU'}
            </div>
            <div className="flex-1 min-w-0">
              <div className="text-[14px] font-medium">{db.profile.name || 'You'} <span className="text-[11px] text-[#86868B] font-normal ml-1">Owner</span></div>
              <div className="text-[12px] text-[#86868B]">{db.profile.email || 'no email set'}</div>
            </div>
          </div>
          <div className="border-t border-black/5 px-4 py-3 flex items-center gap-3 opacity-50">
            <div className="w-10 h-10 rounded-full bg-[#F2F2F7] flex items-center justify-center flex-shrink-0">
              <Plus className="w-4 h-4 text-[#86868B]" />
            </div>
            <div className="flex-1">
              <div className="text-[14px] text-[#86868B]">Add team member</div>
              <div className="text-[11px] text-[#86868B]">Track stops per tech · Phase 2</div>
            </div>
          </div>
        </div>
        <p className="text-[11px] text-[#86868B] px-1 mt-2 leading-relaxed">When unlocked, you'll see each tech's daily stops, completion rate, and average time per pool on the Reports tab.</p>
      </Section>

      <Section title="Mileage tracking" subtitle="Estimated driving distance between stops for tax records">
        <IntegrationRow
          icon={Navigation}
          title="Mileage tracking"
          sub="Auto-estimate miles when stops are completed"
          connected={db.settings.mileageTrackingEnabled}
          onToggle={() => updateSettings({ mileageTrackingEnabled: !db.settings.mileageTrackingEnabled })}
          note="Uses address geocoding to estimate driving distance. Includes IRS standard mileage rate ($0.70/mi for 2025)."
        />
      </Section>

      <Section title="Integrations" subtitle="Coming in the full release">
        <div className="space-y-3">
          <IntegrationRow
            icon={CreditCard}
            title="Square Payments"
            sub={db.settings.squareConnected ? 'Connected — invoices auto-sent on stop completion' : 'Auto-draft invoices when visits complete'}
            connected={db.settings.squareConnected}
            onToggle={() => updateSettings({ squareConnected: !db.settings.squareConnected })}
            note={db.settings.squareConnected ? 'Invoices will be created in Square when stops are completed.' : 'Enable to auto-send invoices via Square when stops are completed.'}
          />
          {db.settings.squareConnected && (
            <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3">
              <div className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider">Square API credentials</div>
              <Field label="Environment">
                <select className={inputCls} value={db.settings.squareEnvironment || 'sandbox'} onChange={e => updateSettings({ squareEnvironment: e.target.value })}>
                  <option value="sandbox">Sandbox (testing)</option>
                  <option value="production">Production (live)</option>
                </select>
              </Field>
              <Field label="Access Token">
                <input type="password" className={inputCls} value={db.settings.squareAccessToken || ''} onChange={e => updateSettings({ squareAccessToken: e.target.value })} placeholder="sq0atp-..." />
              </Field>
              <Field label="Location ID">
                <input className={inputCls} value={db.settings.squareLocationId || ''} onChange={e => updateSettings({ squareLocationId: e.target.value })} placeholder="L..." />
              </Field>
              <div className="bg-[#E5F2FF] rounded-xl p-3 text-[12px] text-[#1A8CB8]">
                <strong>Setup guide:</strong> Go to <a href="https://developer.squareup.com/apps" target="_blank" rel="noopener" className="underline">Square Developer Dashboard</a> → Create an app → Copy your Access Token and Location ID.
              </div>
            </div>
          )}
          <IntegrationRow
            icon={MessageSquare}
            title="SMS reminders"
            sub="Twilio — automatic billing reminders"
            connected={db.settings.smsRemindersEnabled}
            onToggle={() => updateSettings({ smsRemindersEnabled: !db.settings.smsRemindersEnabled })}
            note="Requires Twilio account in production."
          />
          <IntegrationRow
            icon={Send}
            title="Email reminders"
            sub={db.settings.autoRemindersEnabled ? `Auto-remind after ${db.settings.invoiceReminderDays || 14} days unpaid` : 'Automatic payment reminders via Square'}
            connected={db.settings.autoRemindersEnabled}
            onToggle={() => updateSettings({ autoRemindersEnabled: !db.settings.autoRemindersEnabled })}
            note={db.settings.autoRemindersEnabled ? 'Square sends payment reminder emails automatically when invoices are overdue.' : 'Enable to auto-send payment reminders for unpaid invoices.'}
          />
          {db.settings.autoRemindersEnabled && (
            <div className="bg-white rounded-2xl border border-black/5 p-4 space-y-3">
              <div className="text-[11px] font-medium text-[#86868B] uppercase tracking-wider">Reminder settings</div>
              <Field label="Days before first reminder">
                <div className="flex items-center gap-3">
                  <input type="range" min="7" max="30" step="1" value={db.settings.invoiceReminderDays || 14} onChange={e => updateSettings({ invoiceReminderDays: +e.target.value })} className="flex-1" />
                  <span className="text-[15px] font-semibold text-[#1A8CB8] w-14 text-right">{db.settings.invoiceReminderDays || 14} days</span>
                </div>
              </Field>
              <div className="bg-[#F2F2F7] rounded-xl p-3 text-[12px] text-[#86868B] space-y-1">
                <div className="flex items-center gap-2"><Check className="w-3 h-3 text-[#34C759]" /><span>Invoice sent to customer via Square</span></div>
                <div className="flex items-center gap-2"><Clock className="w-3 h-3 text-[#FF9500]" /><span>After {db.settings.invoiceReminderDays || 14} days — auto-reminder email sent</span></div>
                <div className="flex items-center gap-2"><AlertCircle className="w-3 h-3 text-[#FF3B30]" /><span>Shows as overdue on your dashboard</span></div>
              </div>
            </div>
          )}
        </div>
      </Section>

      <Section title="Account" subtitle={(supa.auth.getUser()?.email) || ''}>
        <button onClick={handleSignOut} className="w-full bg-white border border-black/5 rounded-2xl py-3.5 text-[#1D1D1F] font-medium hover:bg-[#F5F5F7] flex items-center justify-center gap-2">
          <ArrowLeft className="w-4 h-4" strokeWidth={2.5} />Sign out
        </button>
      </Section>

      <Section title="Data">
        <button onClick={resetData} className="w-full bg-white border border-black/5 rounded-2xl py-3.5 text-[#FF3B30] font-medium hover:bg-[#FFF5F5]">Reset all data</button>
        <p className="text-center text-[11px] text-[#86868B] mt-2">All data is stored on this device only.</p>
      </Section>

      <div className="text-center pb-4">
        <p className="text-[11px] text-[#86868B]">Routebook prototype · v0.1</p>
      </div>
      </div>
    </div>
  );
}

function IntegrationRow({ icon: Icon, title, sub, connected, onToggle, note }) {
  return (
    <div className="bg-white rounded-2xl border border-black/5 p-4">
      <div className="flex items-center gap-3">
        <div className={`w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0 ${connected ? 'bg-[#34C759]/15 text-[#1F8B3E]' : 'bg-[#F2F2F7] text-[#86868B]'}`}>
          <Icon className="w-5 h-5" />
        </div>
        <div className="flex-1 min-w-0">
          <div className="text-[15px] font-medium">{title}</div>
          <div className="text-[12px] text-[#86868B]">{sub}</div>
        </div>
        <button onClick={onToggle} className={`relative w-12 h-7 rounded-full transition-colors ${connected ? 'bg-[#34C759]' : 'bg-[#E5E5EA]'}`}>
          <div className={`absolute top-0.5 w-6 h-6 rounded-full bg-white shadow-sm transition-all ${connected ? 'left-[22px]' : 'left-0.5'}`} />
        </button>
      </div>
      {note && <p className="text-[11px] text-[#86868B] mt-2 pl-13" style={{ paddingLeft: 52 }}>{note}</p>}
    </div>
  );
}
