// BookUno Web — Logged-in customer home & Search/discover

/* ─── Logged-in customer home (desktop + responsive) ──────── */
function PageHome({ logoVariant = 'default' }) {
  const [trendingBiz, setTrendingBiz] = React.useState([]);
  const [firstName, setFirstName] = React.useState('');
  const [myBookings, setMyBookings] = React.useState([]);

  React.useEffect(() => {
    const api = window.BOOKUNO_API;
    if (api && typeof api.listPublicBusinesses === 'function') {
      api.listPublicBusinesses('', '').then(data => {
        if (Array.isArray(data)) setTrendingBiz(data.slice(0, 4));
      }).catch(() => {});
    }
    if (api && typeof api.getCurrentUser === 'function') {
      api.getCurrentUser().then(u => {
        if (!u) return;
        const name = u.user_metadata?.full_name || u.user_metadata?.name || '';
        if (name) setFirstName(name.split(' ')[0]);
        if (typeof api.listCustomerBookings === 'function') {
          api.listCustomerBookings().then(rows => {
            if (!Array.isArray(rows)) return;
            const now = new Date();
            const upcoming = rows
              .filter(b => b.status !== 'cancelled' && new Date(b.date || b.starts_at) >= now)
              .sort((a, b2) => new Date(a.date || a.starts_at) - new Date(b2.date || b2.starts_at));
            setMyBookings(upcoming.slice(0, 3));
          }).catch(() => {});
        }
      }).catch(() => {});
    }
  }, []);

  const now = new Date();
  const hour = now.getHours();
  const greetWord = hour < 12 ? 'Good morning' : hour < 18 ? 'Good afternoon' : 'Good evening';
  const dateStr = now.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' }).toUpperCase();

  const trendingCards = trendingBiz.map((b, i) => ({
    id: b.id,
    name: b.name,
    slug: b.slug,
    seed: i,
    cat: b.type,
    rating: '4.9',
    dist: (b.address && (b.address.city || b.address.region || b.address.postcode)) || 'Nearby',
    from: '£18',
    next: 'Today 14:00',
    open: true,
  }));

  // Read What + Where from the hero-search and navigate to results.
  const heroGoSearch = (el) => {
    const root = el.closest('.hero-search');
    const q = (root?.querySelector('.field:nth-child(1) input')?.value || '').trim();
    const loc = (root?.querySelector('.field:nth-child(2) input')?.value || '').trim();
    const params = new URLSearchParams();
    if (q) params.set('q', q);
    if (loc) params.set('loc', loc);
    const qs = params.toString();
    window.location.hash = qs ? `#/search?${qs}` : '#/search';
  };

  return (
    <div className="web">
      <TopNav active="discover" logoVariant={logoVariant} loggedIn/>

      {/* Greeting band */}
      <section style={{ background: 'linear-gradient(180deg, #1A0E4A 0%, #2B1373 100%)', color: '#fff', padding: '52px 0 40px', position: 'relative', overflow: 'hidden' }}>
        <div className="blob" style={{ width: 360, height: 360, background: '#FF8FCB', top: -100, right: -100, opacity: 0.35 }}/>
        <div className="blob" style={{ width: 280, height: 280, background: '#7B5BFF', bottom: -100, left: -80, opacity: 0.5 }}/>
        <div className="container" style={{ position: 'relative' }}>
          <Rv>
            <div className="micro" style={{ opacity: 0.7 }}>{dateStr}</div>
          </Rv>
          <Rv delay={60}>
            <h1 style={{ fontSize: 'clamp(32px, 5cqi, 56px)', fontWeight: 800, letterSpacing: -0.03, marginTop: 8, lineHeight: 1 }}>{greetWord}{firstName ? `, ${firstName}` : ''}.</h1>
          </Rv>
          <Rv delay={120}>
            <p style={{ opacity: 0.85, fontSize: 17, marginTop: 12 }}>
              {myBookings.length > 0
                ? `You have ${myBookings.length} upcoming booking${myBookings.length === 1 ? '' : 's'}.`
                : 'Find and book trusted local services — hair, home, wellness and more.'}
            </p>
          </Rv>
          {/* Inline search */}
          <Rv delay={200}>
            <div className="hero-search" style={{ marginTop: 28 }}>
              <div className="field">
                <label>What</label>
                <input placeholder='Search businesses or services' onKeyDown={(e) => { if (e.key === 'Enter') heroGoSearch(e.currentTarget); }}/>
              </div>
              <div className="field">
                <label>Where</label>
                <input placeholder='Town, city or postcode' onKeyDown={(e) => { if (e.key === 'Enter') heroGoSearch(e.currentTarget); }}/>
              </div>
              <div className="field hide-mobile">
                <label>When</label>
                <input defaultValue="Any time"/>
              </div>
              <button className="submit" type="button" onClick={(e) => heroGoSearch(e.currentTarget)}><Ic.search style={{ width: 18, height: 18 }}/> <span className="hide-mobile">Search</span></button>
            </div>
          </Rv>
          {/* Social proof */}
          <Rv delay={280}>
            <div style={{ marginTop: 18, display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 13.5, color: 'rgba(255,255,255,0.75)', fontWeight: 600 }}>Free for customers</span>
              <span style={{ color: 'rgba(255,255,255,0.35)' }}>·</span>
              <span style={{ fontSize: 13.5, color: 'rgba(255,255,255,0.75)', fontWeight: 600 }}>Verified local businesses</span>
              <span style={{ color: 'rgba(255,255,255,0.35)' }}>·</span>
              <span style={{ fontSize: 13.5, color: 'rgba(255,255,255,0.75)', fontWeight: 600 }}>Cancel free up to 24 h before</span>
            </div>
          </Rv>
        </div>
      </section>

      {/* How it works */}
      <section style={{ background: '#fff', padding: '52px 0' }}>
        <div className="container">
          <div style={{ textAlign: 'center', marginBottom: 36 }}>
            <div className="micro" style={{ color: 'var(--pri)' }}>HOW IT WORKS</div>
            <h2 style={{ marginTop: 8, fontSize: 28, fontWeight: 800, letterSpacing: -0.025 }}>Book anything in 3 steps</h2>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 24, maxWidth: 780, margin: '0 auto' }}>
            {[
              { icon: Ic.search, title: 'Search', desc: 'Find local services near you' },
              { icon: Ic.cal, title: 'Book', desc: 'Pick a slot and send your booking request' },
              { icon: Ic.check, title: 'Done', desc: 'Get reminders, manage everything in one place' },
            ].map((s, i) => {
              const StepIcon = s.icon;
              return (
              <Rv key={i} delay={i * 60}>
                <div style={{ textAlign: 'center', padding: '28px 20px', borderRadius: 20, background: 'var(--bg)', border: '1px solid var(--line)' }}>
                  <div style={{ width: 56, height: 56, borderRadius: 18, margin: '0 auto 14px', background: 'var(--pri-50)', color: 'var(--pri)', display: 'grid', placeItems: 'center' }}>
                    <StepIcon style={{ width: 26, height: 26 }}/>
                  </div>
                  <div style={{ fontWeight: 800, fontSize: 17, marginBottom: 8 }}>{s.title}</div>
                  <div style={{ fontSize: 14, color: 'var(--muted)', lineHeight: 1.5 }}>{s.desc}</div>
                </div>
              </Rv>
              );
            })}
          </div>
        </div>
      </section>

      {/* Upcoming bookings — real data, only shown when the signed-in user has some */}
      {myBookings.length > 0 && (
        <section className="section" style={{ background: 'var(--bg)', paddingTop: 40 }}>
          <div className="container">
            <div className="section-h">
              <div>
                <div className="micro" style={{ color: 'var(--pri)' }}>UPCOMING</div>
                <h2 style={{ marginTop: 6, fontSize: 26 }}>Next on your calendar</h2>
              </div>
              <a href="/app.html#/account" style={{ color: 'var(--pri)', fontWeight: 700, fontSize: 14 }}>All bookings →</a>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: 18 }}>
              {myBookings.map((b, i) => {
                const dt = new Date(b.date || b.starts_at);
                const day = dt.toLocaleDateString('en-GB', { weekday: 'short' }).toUpperCase();
                const mo = dt.toLocaleDateString('en-GB', { month: 'short' }).toUpperCase();
                const time = dt.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
                const svcName = b.services?.name || b.service_name || 'Booking';
                const bizName = b.businesses?.name || b.business_name || '';
                const pending = (b.status || '').toLowerCase() === 'pending';
                return (
                  <Rv key={b.id || i} delay={i*60}>
                    <a href="/app.html#/account" className="card hover" style={{ padding: 0, overflow: 'hidden', display: 'block' }}>
                      <div style={{ padding: 18, display: 'flex', gap: 16 }}>
                        <Cover seed={i} h={84} r={14} style={{ width: 72, padding: 0, flexShrink: 0, alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>
                          <div style={{ color: '#fff', fontWeight: 700, fontSize: 11, opacity: 0.85, letterSpacing: 0.05 }}>{day}</div>
                          <div style={{ color: '#fff', fontWeight: 800, fontSize: 26, letterSpacing: -0.02, lineHeight: 1 }}>{dt.getDate()}</div>
                          <div style={{ color: '#fff', fontWeight: 700, fontSize: 9.5, opacity: 0.85, marginTop: 2 }}>{mo}</div>
                        </Cover>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <span className="badge" style={{ background: pending ? 'var(--amber-bg)' : 'var(--green-bg)', color: pending ? '#B45309' : 'var(--green)' }}>{pending ? 'PENDING' : 'CONFIRMED'}</span>
                          <div style={{ fontWeight: 800, fontSize: 16, letterSpacing: -0.015, marginTop: 6 }}>{svcName} · {time}</div>
                          <div style={{ fontSize: 13, color: 'var(--muted)', marginTop: 2 }}>{bizName}</div>
                        </div>
                      </div>
                    </a>
                  </Rv>
                );
              })}
            </div>
          </div>
        </section>
      )}

      {/* Quick access cards */}
      <section style={{ background: 'var(--bg)', padding: '12px 0 40px' }}>
        <div className="container" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 14 }}>
          {[
            { i: Ic.cal,    n: 'My bookings', d: 'View, reschedule or cancel', href: '/app.html#/account', c1: '#C8B8FF', c2: '#7B5BFF' },
            { i: Ic.search, n: 'Explore nearby', d: 'Browse every category near you', href: '/app.html#/search', c1: '#A8E0FF', c2: '#7C5BFF' },
            { i: Ic.gift,   n: 'For businesses', d: 'Get your own booking page — free', href: '/app.html#/business', c1: '#FFE4A8', c2: '#FFB870' },
          ].map((q, i) => {
            const Icon = q.i;
            return (
              <Rv key={i} delay={i*40}>
                <a href={q.href} className="card hover" style={{ padding: 18, display: 'flex', alignItems: 'center', gap: 14, textAlign: 'left', width: '100%' }}>
                  <div style={{ width: 48, height: 48, borderRadius: 14, background: `linear-gradient(135deg, ${q.c1}, ${q.c2})`, color: '#fff', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
                    <Icon style={{ width: 22, height: 22 }}/>
                  </div>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontWeight: 800, fontSize: 15 }}>{q.n}</div>
                    <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>{q.d}</div>
                  </div>
                  <Ic.chev style={{ width: 18, height: 18, color: 'var(--muted-2)' }}/>
                </a>
              </Rv>
            );
          })}
        </div>
      </section>

      {/* Recommended */}
      <section className="section" style={{ background: '#fff' }}>
        <div className="container">
          <div className="section-h">
            <div>
              <div className="micro" style={{ color: 'var(--pri)' }}>TRENDING</div>
              <h2 style={{ marginTop: 6, fontSize: 26 }}>Popular near you</h2>
              <p>Top-rated businesses taking bookings on Bookuno.</p>
            </div>
            <a href="/app.html#/search" style={{ color: 'var(--pri)', fontWeight: 700, fontSize: 14 }}>See all →</a>
          </div>
          <div className="sf-grid">
            {trendingCards.length > 0
              ? trendingCards.map((b, i) => <SFCard key={b.id || i} b={b} delay={i*40}/>)
              : (
                <Rv>
                  <a href="/app.html#/business/start" className="sf-card" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200, textAlign: 'center', padding: 32 }}>
                    <div>
                      <div style={{ width: 56, height: 56, borderRadius: 18, margin: '0 auto 12px', background: 'var(--pri-50)', color: 'var(--pri)', display: 'grid', placeItems: 'center' }}>
                        <Ic.globe style={{ width: 26, height: 26 }}/>
                      </div>
                      <div style={{ fontWeight: 800, fontSize: 16 }}>Be the first business in your area →</div>
                      <div style={{ fontSize: 13, color: 'var(--muted)', marginTop: 6 }}>List your business free today</div>
                    </div>
                  </a>
                </Rv>
              )
            }
          </div>
        </div>
      </section>

      {/* Categories pill row */}
      <section className="section" style={{ background: 'var(--bg)' }}>
        <div className="container">
          <div className="section-h">
            <div>
              <div className="micro" style={{ color: 'var(--pri)' }}>BROWSE</div>
              <h2 style={{ marginTop: 6, fontSize: 26 }}>Categories</h2>
            </div>
          </div>
          <div className="cats">
            {CATEGORIES.slice(0, 12).map((c, i) => {
              const Icon = c.icon;
              const p = GRAD_PALETTES[c.seed];
              return (
                <Rv key={c.id} delay={i*25}>
                  <a href={`/app.html#/search?cat=${encodeURIComponent(c.id)}`} className="cat-card">
                    <div className="icon" style={{ background: `linear-gradient(135deg, ${p[0]}, ${p[3]})` }}>
                      <Icon style={{ width: 24, height: 24 }}/>
                    </div>
                    <div>
                      <div className="name">{c.name}</div>
                      <div className="count">Browse &amp; book</div>
                    </div>
                  </a>
                </Rv>
              );
            })}
          </div>
        </div>
      </section>

      {/* For businesses CTA */}
      <section style={{ background: 'linear-gradient(135deg, #1A0E4A 0%, #2B1373 100%)', padding: '52px 0', position: 'relative', overflow: 'hidden' }}>
        <div className="blob" style={{ width: 300, height: 300, background: '#FF8FCB', top: -80, right: -80, opacity: 0.25, position: 'absolute', borderRadius: '50%' }}/>
        <div className="container" style={{ position: 'relative', textAlign: 'center' }}>
          <Rv>
            <div style={{ fontSize: 11, fontWeight: 800, letterSpacing: 0.08, color: 'rgba(255,255,255,0.6)', textTransform: 'uppercase', marginBottom: 12 }}>FOR BUSINESSES</div>
            <h2 style={{ fontSize: 'clamp(24px, 4cqi, 36px)', fontWeight: 800, color: '#fff', letterSpacing: -0.025, lineHeight: 1.15, marginBottom: 14 }}>
              Run a salon, barbershop or fitness studio?
            </h2>
            <p style={{ fontSize: 16, color: 'rgba(255,255,255,0.75)', marginBottom: 28 }}>
              Get your own booking page in 5 minutes.
            </p>
            <a href="/app.html#/business/start" className="btn primary lg" style={{ background: '#fff', color: '#1A0E4A', fontWeight: 800, fontSize: 16, padding: '14px 32px', borderRadius: 14, textDecoration: 'none', display: 'inline-block' }}>
              Start free →
            </a>
          </Rv>
        </div>
      </section>

      <Footer logoVariant={logoVariant}/>
    </div>
  );
}

/* ─── Reusable storefront card ────────────────────────────── */
function SFCard({ b, delay = 0 }) {
  const href = b.slug ? `/app.html#/b/${b.slug}` : '/app.html#/search';
  return (
    <Rv delay={delay}>
      <a href={href} className="sf-card">
        <div className="cover" style={{ position: 'relative' }}>
          <Cover seed={b.seed} h={180} r={0} label={b.cat} photo={b.photo || categoryPhoto(b.cat)}>
            <span aria-hidden="true" style={{ position: 'absolute', top: 14, right: 14, width: 36, height: 36, borderRadius: 12, background: 'rgba(255,255,255,0.92)', color: 'var(--ink)', display: 'grid', placeItems: 'center' }}>
              <Ic.heart style={{ width: 16, height: 16 }}/>
            </span>
          </Cover>
        </div>
        <div className="body" style={{ padding: 16 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <div style={{ fontWeight: 800, fontSize: 16, letterSpacing: -0.015 }}>{b.name}</div>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 3, fontSize: 13, fontWeight: 700 }}>
              <Ic.star style={{ width: 13, height: 13, color: 'var(--amber)' }}/>{b.rating}
            </div>
          </div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 4, display: 'flex', alignItems: 'center', gap: 6 }}>
            <Ic.pin style={{ width: 12, height: 12 }}/>{b.dist} · from {b.from}
          </div>
          <div style={{ marginTop: 10, fontSize: 11, fontWeight: 700, letterSpacing: 0.04, textTransform: 'uppercase', color: 'var(--muted)' }}>Available slots</div>
          {/* Availability slots */}
          {(() => {
            const hrs = [9,10,11,12,13,14,15,16,17];
            const s = b.seed || 0;
            const h1 = hrs[(s * 3 + 2) % hrs.length];
            const h2 = hrs[(s * 3 + 5) % hrs.length];
            const m1 = s % 2 === 0 ? '00' : '30';
            const m2 = s % 2 === 0 ? '30' : '00';
            const days = ['Mon','Tue','Wed','Thu','Fri'];
            const day2 = days[(s + 2) % days.length];
            const slots = [b.next, `Tomorrow ${h1}:${m1}`, `${day2} ${h2}:${m2}`].filter(Boolean);
            return (
              <div style={{ marginTop: 10, display: 'flex', flexWrap: 'wrap', gap: 5 }}>
                {slots.map((slot, i) => (
                  <span key={i} style={{ padding: '5px 9px', borderRadius: 8, background: i === 0 ? 'var(--pri)' : 'var(--pri-50)', color: i === 0 ? '#fff' : 'var(--pri-700)', fontSize: 11, fontWeight: 700, whiteSpace: 'nowrap' }}>{slot}</span>
                ))}
              </div>
            );
          })()}
        </div>
      </a>
    </Rv>
  );
}

/* ─── Search empty state ──────────────────────────────────── */
function SearchEmptyState({ query, category, onClear }) {
  const [suggestName, setSuggestName] = React.useState('');
  const [suggestType, setSuggestType] = React.useState('');
  const [sent, setSent] = React.useState(false);

  function handleSuggest(e) {
    e.preventDefault();
    if (!suggestName.trim()) return;
    const subject = encodeURIComponent('Business suggestion: ' + suggestName.trim());
    const body = encodeURIComponent(`Business: ${suggestName.trim()}\nType: ${suggestType.trim() || 'not specified'}\nSuggested via Bookuno search`);
    window.open(`mailto:hello@bookuno.co.uk?subject=${subject}&body=${body}`);
    setSent(true);
  }

  return (
    <div style={{ padding: '60px 24px', textAlign: 'center', maxWidth: 480, margin: '0 auto' }}>
      <div style={{ fontSize: 42, marginBottom: 16 }}>📍</div>
      <h3 style={{ fontSize: 20, fontWeight: 800, letterSpacing: -0.02, marginBottom: 8 }}>
        Still growing in this area
      </h3>
      <p style={{ fontSize: 14, color: 'var(--muted)', lineHeight: 1.6, marginBottom: 24 }}>
        Bookuno is launching across the UK — more businesses are joining every week.
        {query && <> No results yet for <b>"{query}"</b>.</>}
      </p>
      {(query || category) && (
        <button className="btn outline sm" onClick={onClear} style={{ marginBottom: 20 }}>Clear search</button>
      )}
      {!sent ? (
        <div style={{ padding: 20, borderRadius: 16, background: 'var(--bg)', border: '1px solid var(--line)', textAlign: 'left' }}>
          <div style={{ fontWeight: 800, fontSize: 14, marginBottom: 4 }}>Know a business that should be here?</div>
          <p style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 14 }}>Suggest them and we'll reach out to get them listed.</p>
          <form onSubmit={handleSuggest} style={{ display: 'grid', gap: 10 }}>
            <input
              value={suggestName}
              onChange={e => setSuggestName(e.target.value)}
              placeholder="Business name (required)"
              style={{ width: '100%', border: '1.5px solid var(--line)', borderRadius: 10, padding: '9px 12px', fontSize: 13.5, fontWeight: 600, outline: 'none', background: '#fff', boxSizing: 'border-box' }}
            />
            <input
              value={suggestType}
              onChange={e => setSuggestType(e.target.value)}
              placeholder="Type of business — e.g. barber, cleaner"
              style={{ width: '100%', border: '1.5px solid var(--line)', borderRadius: 10, padding: '9px 12px', fontSize: 13.5, fontWeight: 600, outline: 'none', background: '#fff', boxSizing: 'border-box' }}
            />
            <button type="submit" className="btn primary sm block" style={{ height: 42 }}>Suggest this business →</button>
          </form>
        </div>
      ) : (
        <div style={{ padding: 20, borderRadius: 16, background: 'var(--pri-50)', border: '1px solid var(--pri)', textAlign: 'center' }}>
          <div style={{ fontSize: 28, marginBottom: 8 }}>🙌</div>
          <div style={{ fontWeight: 800, fontSize: 15, color: 'var(--pri-700)', marginBottom: 4 }}>Thanks for the tip!</div>
          <p style={{ fontSize: 13, color: 'var(--pri-700)' }}>We'll reach out to {suggestName} and let you know when they're live.</p>
        </div>
      )}
      <div style={{ marginTop: 24, paddingTop: 20, borderTop: '1px solid var(--line-2)' }}>
        <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 12 }}>Are you a business owner?</div>
        <a href="/#/business" className="btn primary sm">Get listed free →</a>
      </div>
    </div>
  );
}

/* ─── Search results page (desktop layout) ────────────────── */
const { useState, useEffect } = React;
function PageSearch({ logoVariant = 'default', loggedIn = true }) {
  const getInitialParams = () => {
    try {
      const hash = window.location.hash || '';
      const qIndex = hash.indexOf('?');
      if (qIndex === -1) return { q: '', cat: '', loc: '' };
      const params = new URLSearchParams(hash.slice(qIndex + 1));
      return { q: params.get('q') || '', cat: params.get('cat') || '', loc: params.get('loc') || '' };
    } catch { return { q: '', cat: '', loc: '' }; }
  };

  const initial = getInitialParams();
  const [query, setQuery] = useState(initial.q);
  const [category, setCategory] = useState(initial.cat);
  const [locationText, setLocationText] = useState(initial.loc);
  const [businesses, setBusinesses] = useState([]);
  const [loading, setLoading] = useState(true);
  const [searching, setSearching] = useState(false);
  const [error, setError] = useState(null);

  const doSearch = (q, cat) => {
    setSearching(true);
    setError(null);
    const api = window.BOOKUNO_API;
    if (!api || typeof api.listPublicBusinesses !== 'function') {
      setLoading(false);
      setSearching(false);
      setError('API not available');
      return;
    }
    api.listPublicBusinesses(q, cat)
      .then(data => {
        setBusinesses(data || []);
        setLoading(false);
        setSearching(false);
      })
      .catch(err => {
        setError(err?.message || 'Failed to load businesses');
        setLoading(false);
        setSearching(false);
      });
  };

  useEffect(() => { doSearch(query, category); }, []);

  // Debounce query input — wait 300ms after typing stops
  useEffect(() => {
    if (loading) return; // skip debounce during initial load
    const timer = setTimeout(() => { doSearch(query, category); }, 300);
    return () => clearTimeout(timer);
  }, [query]);

  const handleSearch = (e) => {
    e && e.preventDefault();
    doSearch(query, category);
  };

  // Address helpers — businesses carry a JSONB `address` (city/postcode/formatted).
  const addressText = (b) => {
    const a = b.address;
    if (!a) return '';
    if (typeof a === 'string') return a;
    return [a.line1, a.line2, a.city, a.region, a.postcode, a.formatted].filter(Boolean).join(' ');
  };
  const areaLabel = (b) => {
    const a = b.address;
    if (!a) return 'Nearby';
    if (typeof a === 'string') return a;
    return a.city || a.region || a.postcode || 'Nearby';
  };

  // Location filter — narrows results to the area the user typed ("search around them").
  // Businesses that haven't published an address yet are kept visible (we can't
  // confirm they're elsewhere) so a location search never hides everything.
  const locNeedle = locationText.trim().toLowerCase();
  const filteredBiz = locNeedle
    ? businesses.filter(b => { const hay = addressText(b).toLowerCase(); return !hay || hay.includes(locNeedle); })
    : businesses;

  const cards = filteredBiz.map((b, i) => ({
    id: b.id,
    name: b.name,
    slug: b.slug,
    seed: i,
    cat: b.type,
    rating: '4.9',
    dist: areaLabel(b),
    from: '£18',
    next: 'Today 14:00',
    open: true,
  }));

  return (
    <div className="web">
      <TopNav active="discover" logoVariant={logoVariant} loggedIn={loggedIn}/>

      {/* Search header */}
      <section style={{ background: '#fff', borderBottom: '1px solid var(--line)', padding: '28px 0 22px' }}>
        <div className="container">
          <h1 style={{ position: 'absolute', width: 1, height: 1, padding: 0, margin: -1, overflow: 'hidden', clip: 'rect(0,0,0,0)', whiteSpace: 'nowrap', border: 0 }}>Find local services — Bookuno</h1>
          <form onSubmit={handleSearch} style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <input
              value={query}
              onChange={e => setQuery(e.target.value)}
              placeholder="Search businesses…"
              style={{ flex: '2 1 200px', height: 44, borderRadius: 10, border: '1.5px solid var(--line)', padding: '0 14px', fontSize: 16, fontWeight: 600, outline: 'none' }}
            />
            <div style={{ position: 'relative', flex: '1 1 150px', display: 'flex', alignItems: 'center' }}>
              <Ic.pin style={{ width: 15, height: 15, position: 'absolute', left: 12, color: 'var(--muted)', pointerEvents: 'none' }}/>
              <input
                value={locationText}
                onChange={e => setLocationText(e.target.value)}
                placeholder="Town, city or postcode"
                aria-label="Location"
                style={{ width: '100%', height: 44, borderRadius: 10, border: '1.5px solid var(--line)', padding: '0 12px 0 34px', fontSize: 16, fontWeight: 600, outline: 'none' }}
              />
            </div>
            <button type="submit" className="btn primary sm" style={{ height: 44, minWidth: 44 }}>
              <Ic.search style={{ width: 16, height: 16 }}/> <span className="hide-mobile">Search</span>
            </button>
            {searching && <span style={{ fontSize: 13, color: 'var(--muted)', fontWeight: 600 }}>Searching…</span>}
            {!loading && !searching && (
              <span className="muted" style={{ fontSize: 14 }}>
                · <b style={{ color: 'var(--ink)' }}>{cards.length}</b> {cards.length === 1 ? 'business' : 'businesses'}
              </span>
            )}
          </form>
        </div>
      </section>

      {/* Two-column results */}
      <div className="search-shell">
        {/* Filters sidebar */}
        <aside className="filters-side">
          <div className="card" style={{ padding: 18 }}>
            <h3 style={{ fontSize: 14, fontWeight: 800, marginBottom: 14, display: 'flex', alignItems: 'center', gap: 8 }}>
              <Ic.filter style={{ width: 16, height: 16 }}/>Filters
            </h3>
            <FilterGroup label="Category">
              {[
                { label: 'Barber', id: 'barbershop' },
                { label: 'Hair & Beauty', id: 'hair_salon' },
                { label: 'Wellness', id: 'massage_spa' },
                { label: 'Trades', id: 'tradesperson' },
                { label: 'Cleaning', id: 'cleaner' },
              ].map((c) => (
                <div key={c.id} onClick={() => {
                  const next = category === c.id ? '' : c.id;
                  setCategory(next);
                  doSearch(query, next);
                }} style={{ cursor: 'pointer' }}>
                  <CheckLine label={c.label} checked={category === c.id}/>
                </div>
              ))}
            </FilterGroup>
            <FilterGroup label="Distance">
              <RangeMock value={5}/>
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11.5, color: 'var(--muted)' }}>
                <span>1 mi</span><span><b style={{ color: 'var(--ink)' }}>5 miles</b></span><span>25 mi</span>
              </div>
            </FilterGroup>
            <FilterGroup label="Availability">
              <CheckLine label="Open now" checked/>
              <CheckLine label="Bookable today"/>
              <CheckLine label="Weekends"/>
              <CheckLine label="Mobile / at-home"/>
            </FilterGroup>
            <button className="btn outline block sm" style={{ marginTop: 16 }}>Clear all</button>
          </div>
        </aside>

        {/* Results */}
        <div style={{ flex: 1, minWidth: 0 }}>
          {/* Initial load skeleton — only shown when no results yet */}
          {loading && businesses.length === 0 && (
            <div className="results-grid">
              {[0,1,2].map(i => (
                <div key={i} className="sf-card" style={{ pointerEvents: 'none' }}>
                  <div style={{ height: 180, background: 'linear-gradient(90deg, var(--chip) 25%, var(--line) 50%, var(--chip) 75%)', backgroundSize: '200% 100%', animation: 'shimmer 1.4s infinite', borderRadius: '14px 14px 0 0' }}/>
                  <div style={{ padding: 16 }}>
                    <div style={{ height: 16, borderRadius: 8, background: 'var(--chip)', marginBottom: 8, width: '70%' }}/>
                    <div style={{ height: 13, borderRadius: 8, background: 'var(--chip)', width: '45%' }}/>
                  </div>
                </div>
              ))}
            </div>
          )}
          {!loading && error && (
            <div style={{ padding: '60px 0', textAlign: 'center', color: 'var(--muted)' }}>
              <div style={{ fontWeight: 700, color: 'var(--red, #DC2626)' }}>{error}</div>
            </div>
          )}
          {!loading && !searching && !error && cards.length === 0 && (
            <SearchEmptyState query={query} category={category} onClear={() => { setQuery(''); setCategory(''); setLocationText(''); doSearch('', ''); }}/>
          )}
          {/* Show results — keep visible even while re-searching */}
          {!loading && !error && cards.length > 0 && (
            <div className="results-grid" style={{ opacity: searching ? 0.6 : 1, transition: 'opacity 0.2s' }}>
              {cards.map((b, i) => <SFCard key={b.id || i} b={b} delay={i * 30}/>)}
            </div>
          )}
        </div>
      </div>

      <Footer logoVariant={logoVariant}/>
    </div>
  );
}

function FilterGroup({ label, children }) {
  return (
    <div style={{ paddingBottom: 16, marginBottom: 16, borderBottom: '1px solid var(--line-2)' }}>
      <div style={{ fontSize: 12, fontWeight: 800, letterSpacing: 0.05, textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 10 }}>{label}</div>
      <div style={{ display: 'grid', gap: 6 }}>{children}</div>
    </div>
  );
}
function CheckLine({ label, checked = false, count }) {
  return (
    <label style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 13.5, cursor: 'pointer', padding: '2px 0' }}>
      <span style={{ width: 18, height: 18, borderRadius: 5, background: checked ? 'var(--pri)' : '#fff', border: checked ? 'none' : '1.5px solid var(--line)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
        {checked && <Ic.check style={{ width: 11, height: 11, color: '#fff' }}/>}
      </span>
      <span style={{ flex: 1, display: 'inline-flex', alignItems: 'center', gap: 5 }}>{label}</span>
      {count && <span style={{ fontSize: 11.5, color: 'var(--muted-2)' }}>{count}</span>}
    </label>
  );
}
function RangeMock({ value = 5, max = 25 }) {
  const pct = (value / max) * 100;
  return (
    <div style={{ padding: '6px 0' }}>
      <div style={{ height: 6, borderRadius: 6, background: 'var(--line)', position: 'relative' }}>
        <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: `${pct}%`, background: 'var(--pri)', borderRadius: 6 }}/>
        <div style={{ position: 'absolute', left: `${pct}%`, top: '50%', transform: 'translate(-50%, -50%)', width: 18, height: 18, borderRadius: '50%', background: '#fff', boxShadow: 'var(--sh-2), 0 0 0 1.5px var(--pri)' }}/>
      </div>
    </div>
  );
}

Object.assign(window, { PageHome, PageSearch, SFCard });
