// BookUno mobile redesign — shared components
// Phone frame, logo system, bottom nav, icons, gradient placeholders.

const { useEffect, useRef, useState } = React;

/* ─── Icon set ────────────────────────────────────────────── */
const Ic = {
  search:  (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="1.7"/><path d="m20 20-3.5-3.5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  home:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 11.5 12 4l8 7.5V20a1 1 0 0 1-1 1h-4v-6h-6v6H5a1 1 0 0 1-1-1z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  cal:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><rect x="3.5" y="5.5" width="17" height="15" rx="2.5" stroke="currentColor" strokeWidth="1.7"/><path d="M3.5 10h17M8 3v4M16 3v4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  heart:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 20s-7-4.5-7-10a4 4 0 0 1 7-2.5A4 4 0 0 1 19 10c0 5.5-7 10-7 10z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  heartF:  (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M12 20s-7-4.5-7-10a4 4 0 0 1 7-2.5A4 4 0 0 1 19 10c0 5.5-7 10-7 10z"/></svg>,
  user:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="8" r="4" stroke="currentColor" strokeWidth="1.7"/><path d="M4 20a8 8 0 0 1 16 0" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  star:    (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="m12 3 2.6 5.6L20.5 9.5l-4.4 4.1 1.1 6.1L12 16.8l-5.2 2.9 1.1-6.1L3.5 9.5l5.9-.9L12 3z"/></svg>,
  chev:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m9 6 6 6-6 6" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  chevL:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m15 6-6 6 6 6" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  chevDn:  (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m6 9 6 6 6-6" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  close:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M6 6l12 12M18 6 6 18" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  plus:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  filter:  (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 6h16M7 12h10M10 18h4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  pin:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 22s7-7.2 7-12a7 7 0 0 0-14 0c0 4.8 7 12 7 12z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><circle cx="12" cy="10" r="2.5" stroke="currentColor" strokeWidth="1.7"/></svg>,
  bell:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M6 16V10a6 6 0 1 1 12 0v6l1.5 2H4.5L6 16z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><path d="M10 21a2 2 0 0 0 4 0" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  msg:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 6.5A2.5 2.5 0 0 1 6.5 4h11A2.5 2.5 0 0 1 20 6.5V15a2.5 2.5 0 0 1-2.5 2.5H10l-4 3.5v-3.5H6.5A2.5 2.5 0 0 1 4 15V6.5z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  check:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m5 12.5 4.5 4.5L19 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  clock:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="12" r="8.5" stroke="currentColor" strokeWidth="1.7"/><path d="M12 7.5V12l3 2" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  share:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 4v12m0-12-4 4m4-4 4 4M5 14v4a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  more:    (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg>,
  apple:   (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M16.4 12.3c0-2 1.6-3 1.7-3.1-.9-1.4-2.4-1.6-2.9-1.6-1.2-.1-2.4.7-3 .7-.7 0-1.6-.7-2.6-.7-1.4 0-2.6.8-3.3 2-1.4 2.4-.4 6 1 8 .7 1 1.4 2 2.4 2s1.4-.7 2.6-.7 1.5.7 2.6.7c1.1 0 1.8-.9 2.4-1.9.8-1.1 1.1-2.2 1.1-2.3 0 0-2-.8-2-3.1zm-2-5.7c.5-.7 1-1.6.9-2.6-.8 0-1.9.5-2.5 1.2-.5.6-1 1.5-.9 2.5.9.1 1.9-.4 2.5-1.1z"/></svg>,
  google:  (p) => <svg viewBox="0 0 24 24" {...p}><path fill="#4285F4" d="M22 12.2c0-.7-.1-1.4-.2-2H12v3.9h5.6a4.8 4.8 0 0 1-2.1 3.1v2.6h3.3c2-1.8 3.2-4.5 3.2-7.6z"/><path fill="#34A853" d="M12 22c2.8 0 5.2-.9 7-2.5l-3.3-2.6c-.9.6-2.1 1-3.6 1-2.8 0-5.1-1.9-6-4.4H2.6V16A10 10 0 0 0 12 22z"/><path fill="#FBBC04" d="M6 13.5a6 6 0 0 1 0-3.8V7H2.6a10 10 0 0 0 0 10L6 13.5z"/><path fill="#EA4335" d="M12 5.8a5.4 5.4 0 0 1 3.8 1.5l2.9-2.9A10 10 0 0 0 2.6 7L6 9.7C7 7.7 9.2 5.8 12 5.8z"/></svg>,
  mail:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" strokeWidth="1.7"/><path d="m3 7 9 6 9-6" stroke="currentColor" strokeWidth="1.7"/></svg>,
  phone:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 5.5C4 4.7 4.7 4 5.5 4H8l2 4-2 1.5a11 11 0 0 0 6.5 6.5L16 14l4 2v2.5c0 .8-.7 1.5-1.5 1.5C10.4 20 4 13.6 4 5.5z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  arrow:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M5 12h14m-5-5 5 5-5 5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  spark:   (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M12 2 13.5 8 19.5 9.5 13.5 11 12 17l-1.5-6L4.5 9.5 10.5 8 12 2zM19 14l.8 2.5 2.5.8-2.5.7-.8 2.5-.7-2.5-2.5-.7 2.5-.8L19 14z"/></svg>,
  shield:  (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 3 4 6v6c0 5 3.5 8 8 9 4.5-1 8-4 8-9V6l-8-3z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><path d="m9 12 2.2 2.2L15 10.5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  zap:     (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M13 2 4 14h6l-1 8 9-12h-6l1-8z"/></svg>,
  card:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><rect x="3" y="6" width="18" height="12" rx="2" stroke="currentColor" strokeWidth="1.7"/><path d="M3 10h18" stroke="currentColor" strokeWidth="1.7"/></svg>,
  globe:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.7"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" stroke="currentColor" strokeWidth="1.7"/></svg>,
  gift:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><rect x="3" y="9" width="18" height="5" rx="1" stroke="currentColor" strokeWidth="1.7"/><path d="M5 14v6.5h14V14M12 9v12M12 9s-3-5-5-3 0 3 5 3zm0 0s3-5 5-3 0 3-5 3z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  tag:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 12V4h8l9 9-8 8-9-9z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><circle cx="8.5" cy="8.5" r="1.5" fill="currentColor"/></svg>,
  truck:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 7h11v9H3zM14 10h4l3 3v3h-7" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><circle cx="7" cy="18" r="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="17" cy="18" r="2" stroke="currentColor" strokeWidth="1.7"/></svg>,
  // Category iconography (simple, monoline)
  catBarber:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M6 4 12 12l6-8M4 18h16M5 21h14" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  catBeauty:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 3v18M5 8c4 0 7 2 7 4 0-2 3-4 7-4M5 16c4 0 7-2 7-4 0 2 3 4 7 4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  catWell:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 18c2-1 3-3 3-5 0-4 3-6 6-6s6 2 6 6c0 2 1 4 3 5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/><circle cx="12" cy="11" r="1.5" fill="currentColor"/></svg>,
  catClean:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M5 9V5h6v4M3 13l2-4h12l2 4-1 8H4l-1-8z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catTrade:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m4 18 8-8m-3-3 5-2 6 6-2 5-9-9z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catGarden:   (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M12 21V11m0 0c-3 0-5-2-5-5 0 0 5 0 5 5zm0 0c3 0 5-2 5-5 0 0-5 0-5 5z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  catFit:      (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 9v6M7 6v12M11 9v6M17 6v12M21 9v6M11 12h6" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  catCamp:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 20 12 4l9 16M9 20l3-5 3 5" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catHire:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.7"/><path d="M12 6v6l4 2" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>,
  catEvent:    (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M5 6h14l-2 14H7L5 6zM9 6V4h6v2" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catPet:      (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="6" cy="9" r="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="10" cy="5" r="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="14" cy="5" r="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="18" cy="9" r="2" stroke="currentColor" strokeWidth="1.7"/><path d="M8 19c0-3 2-5 4-5s4 2 4 5-1.5 3-4 3-4 0-4-3z" stroke="currentColor" strokeWidth="1.7"/></svg>,
  catAuto:     (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 14h18l-2-6H5l-2 6zm0 0v4h3v-4M21 14v4h-3v-4" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catEdu:      (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><path d="m12 4 10 5-10 5L2 9l10-5zM6 11v5c0 1 3 3 6 3s6-2 6-3v-5" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>,
  catPro:      (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><rect x="3" y="7" width="18" height="13" rx="2" stroke="currentColor" strokeWidth="1.7"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" stroke="currentColor" strokeWidth="1.7"/></svg>,
  catCreative: (p) => <svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="12" r="8" stroke="currentColor" strokeWidth="1.7"/><circle cx="9" cy="9" r="1" fill="currentColor"/><circle cx="15" cy="9" r="1" fill="currentColor"/><circle cx="15" cy="15" r="1" fill="currentColor"/><circle cx="9" cy="15" r="1" fill="currentColor"/></svg>,
};

/* ─── Logo system ─────────────────────────────────────────── */
// BookUno logo — multiple variants. The "default" variant is the
// star-square wordmark from the existing brand.
function BULogo({ variant = 'default', size = 28, dark = false, label = true }) {
  const fg = dark ? '#fff' : 'var(--ink)';
  const accent = 'var(--pri)';
  const mark = (() => {
    switch (variant) {
      case 'star':
        return (
          <div style={{
            width: size, height: size, borderRadius: size * 0.32,
            background: 'linear-gradient(135deg, var(--pri), var(--pri-700))',
            color: '#fff', display: 'grid', placeItems: 'center',
            fontWeight: 900, fontSize: size * 0.54, letterSpacing: -0.5,
            boxShadow: '0 6px 16px var(--pri-glow)', position: 'relative',
          }}>B
            <span style={{
              position: 'absolute', top: size * 0.15, right: size * 0.18,
              width: size * 0.16, height: size * 0.16, background: '#fff', borderRadius: 1.5,
            }} />
          </div>
        );
      case 'orb':
        return (
          <svg width={size} height={size} viewBox="0 0 40 40">
            <defs>
              <radialGradient id="luOrb" cx="30%" cy="20%" r="80%">
                <stop offset="0%" stopColor="#FFE0F0"/>
                <stop offset="40%" stopColor="#B58CFF"/>
                <stop offset="100%" stopColor="#3324AE"/>
              </radialGradient>
            </defs>
            <circle cx="20" cy="20" r="18" fill="url(#luOrb)"/>
            <text x="20" y="27" textAnchor="middle" fontFamily="Plus Jakarta Sans, sans-serif" fontWeight="900" fontSize="22" fill="#fff">B</text>
          </svg>
        );
      case 'cal':
        return (
          <svg width={size} height={size} viewBox="0 0 40 40">
            <rect x="3" y="6" width="34" height="31" rx="9" fill="var(--pri)"/>
            <rect x="3" y="6" width="34" height="8" fill="var(--pri-700)"/>
            <circle cx="11" cy="10" r="1.5" fill="#fff"/>
            <circle cx="29" cy="10" r="1.5" fill="#fff"/>
            <text x="20" y="31" textAnchor="middle" fontFamily="Plus Jakarta Sans, sans-serif" fontWeight="900" fontSize="16" fill="#fff">B</text>
          </svg>
        );
      case 'ring':
        return (
          <svg width={size} height={size} viewBox="0 0 40 40">
            <circle cx="20" cy="20" r="17" fill="none" stroke="var(--pri)" strokeWidth="3"/>
            <path d="M14 12h6a4 4 0 0 1 0 8h-6zm0 8h7a4 4 0 0 1 0 8h-7z" fill="var(--pri)"/>
          </svg>
        );
      case 'mono':
        return (
          <div style={{
            width: size, height: size, borderRadius: '50%',
            background: 'var(--ink)', color: '#fff',
            display: 'grid', placeItems: 'center',
            fontWeight: 900, fontSize: size * 0.5,
          }}>B</div>
        );
      case 'chip':
        return (
          <div style={{
            width: size * 1.6, height: size, borderRadius: size,
            background: 'var(--pri)', color: '#fff',
            display: 'inline-flex', alignItems: 'center', gap: 4,
            padding: '0 8px', fontWeight: 900, fontSize: size * 0.5,
            boxShadow: '0 6px 14px var(--pri-glow)',
          }}>
            <span style={{ width: 6, height: 6, background: '#fff', borderRadius: 2 }} />
            B
          </div>
        );
      case 'default':
      default:
        return (
          <div style={{
            width: size, height: size, borderRadius: size * 0.3,
            background: 'linear-gradient(135deg, var(--pri), #8E7CFF)',
            color: '#fff', display: 'grid', placeItems: 'center',
            fontWeight: 900, fontSize: size * 0.55,
            boxShadow: '0 6px 16px var(--pri-glow)', position: 'relative',
          }}>B
            <span style={{
              position: 'absolute', top: size * 0.18, right: size * 0.18,
              width: size * 0.14, height: size * 0.14, background: '#fff', borderRadius: 1.5,
            }} />
          </div>
        );
    }
  })();
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 9 }}>
      {mark}
      {label && (
        <span style={{
          fontSize: size * 0.62, fontWeight: 800, letterSpacing: -0.5, color: fg,
        }}>
          Book<span style={{ color: accent }}>uno</span>
        </span>
      )}
    </div>
  );
}

/* ─── Phone frame (compact, for canvas) ───────────────────── */
function Phone({ width = 320, height = 680, dark = false, statusDark, children, label, noBezel = false, time = '9:41' }) {
  const sd = statusDark ?? dark;
  if (noBezel) {
    return (
      <div style={{ width, height, position: 'relative', overflow: 'hidden', borderRadius: 28, background: dark ? '#000' : '#FAF8FF', boxShadow: '0 24px 60px rgba(40,30,80,0.18), 0 0 0 1px rgba(0,0,0,0.06)' }}>
        <PhoneStatus dark={sd} time={time}/>
        {children}
      </div>
    );
  }
  return (
    <div style={{ width, height, position: 'relative' }}>
      <div style={{
        position: 'absolute', inset: 0, borderRadius: 42, background: dark ? '#0B0A18' : '#1A1727',
        boxShadow: '0 28px 70px rgba(30,20,60,0.22), 0 0 0 1px rgba(0,0,0,0.18), inset 0 0 0 2px rgba(255,255,255,0.06)',
      }}/>
      <div style={{
        position: 'absolute', inset: 7, borderRadius: 36, overflow: 'hidden',
        background: dark ? '#000' : '#FAF8FF',
      }}>
        {/* dynamic island */}
        <div style={{
          position: 'absolute', top: 8, left: '50%', transform: 'translateX(-50%)',
          width: 96, height: 28, borderRadius: 18, background: '#000', zIndex: 60,
        }}/>
        <PhoneStatus dark={sd} time={time}/>
        {children}
        {/* home indicator */}
        <div style={{
          position: 'absolute', bottom: 6, left: '50%', transform: 'translateX(-50%)',
          width: 110, height: 4.5, borderRadius: 99,
          background: dark ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.32)',
          zIndex: 60, pointerEvents: 'none',
        }}/>
      </div>
    </div>
  );
}

function PhoneStatus({ dark, time = '9:41' }) {
  const c = dark ? '#fff' : '#15111F';
  return (
    <div style={{
      position: 'absolute', top: 0, left: 0, right: 0, height: 38,
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '12px 22px 0', zIndex: 30, fontSize: 13, fontWeight: 700, color: c,
      pointerEvents: 'none',
    }}>
      <span style={{ letterSpacing: -0.2 }}>{time}</span>
      <span style={{ display: 'inline-flex', gap: 5, alignItems: 'center' }}>
        <svg width="14" height="10" viewBox="0 0 14 10"><rect x="0" y="6" width="2.4" height="3.4" rx="0.5" fill={c}/><rect x="3.6" y="4" width="2.4" height="5.4" rx="0.5" fill={c}/><rect x="7.2" y="2" width="2.4" height="7.4" rx="0.5" fill={c}/><rect x="10.8" y="0" width="2.4" height="9.4" rx="0.5" fill={c}/></svg>
        <svg width="20" height="10" viewBox="0 0 22 11"><rect x="0.5" y="0.5" width="18" height="10" rx="2.5" stroke={c} strokeOpacity="0.45" fill="none"/><rect x="2" y="2" width="13" height="7" rx="1.2" fill={c}/><path d="M20 3.5v4c.6-.3 1-.9 1-2s-.4-1.7-1-2z" fill={c} opacity="0.5"/></svg>
      </span>
    </div>
  );
}

/* ─── Bottom nav ──────────────────────────────────────────── */
function BottomNav({ active = 'home', onChange = () => {}, variant = 'fab' }) {
  const items = [
    { id: 'home',    icon: Ic.home,  label: 'Home' },
    { id: 'explore', icon: Ic.search,label: 'Explore' },
    { id: 'book',    icon: Ic.plus,  label: 'Book',  fab: variant === 'fab' },
    { id: 'saved',   icon: Ic.heart, label: 'Saved' },
    { id: 'me',      icon: Ic.user,  label: 'Account' },
  ];
  return (
    <div className="botnav">
      {items.map(it => {
        const Icon = it.icon;
        const isAct = active === it.id;
        if (it.fab) return (
          <button key={it.id} className="botnav-item fab" onClick={() => onChange(it.id)}>
            <div className="botnav-fab-circle"><Icon style={{ width: 24, height: 24 }} /></div>
          </button>
        );
        return (
          <button key={it.id} className={`botnav-item ${isAct ? 'act' : ''}`} onClick={() => onChange(it.id)}>
            <Icon style={{ width: 22, height: 22 }} />
            <span>{it.label}</span>
          </button>
        );
      })}
    </div>
  );
}

/* ─── Gradient placeholder image ──────────────────────────── */
const GRAD_PALETTES = [
  ['#C8B8FF', '#FFB8DA', '#6B57FF', '#9B7CFF'],
  ['#FFCAA8', '#FFA0C8', '#FF7BAD', '#9F6BFF'],
  ['#A8E0FF', '#C6B6FF', '#5673FF', '#8E4FFF'],
  ['#B8FFE0', '#CFFFC0', '#43C49E', '#6B57FF'],
  ['#FFE4A8', '#FFC0D2', '#FF8E94', '#C56BFF'],
  ['#B8C8FF', '#D8B8FF', '#5550FF', '#9B5DFF'],
  ['#FFD8B8', '#FFB0E0', '#FF6BB1', '#7B5BFF'],
  ['#C5F0CF', '#A8D8FF', '#3DA9FF', '#7C5BFF'],
];
function gradVars(seed) {
  const p = GRAD_PALETTES[seed % GRAD_PALETTES.length];
  return { '--g-1': p[0], '--g-2': p[1], '--g-3': p[2], '--g-4': p[3] };
}
/* Resolve a category-appropriate photo for a business type / category label.
   Accepts CATEGORIES ids ('barbershop'), api business types ('barber',
   'cleaner') and display names ('Barber', 'Hair & Beauty'). Returns a photo
   URL or null (caller falls back to the gradient placeholder). */
const CATEGORY_PHOTO_ALIASES = {
  barber: 'barbershop', barbershop: 'barbershop',
  beauty: 'hair_salon', hair: 'hair_salon', hair_salon: 'hair_salon', salon: 'hair_salon', 'hair & beauty': 'hair_salon',
  wellness: 'massage_spa', massage: 'massage_spa', massage_spa: 'massage_spa', spa: 'massage_spa',
  fitness: 'personal_trainer', personal_trainer: 'personal_trainer', gym: 'personal_trainer',
  cleaning: 'cleaner', cleaner: 'cleaner',
  trades: 'tradesperson', tradesperson: 'tradesperson', trade: 'tradesperson',
  nails: 'nail_salon', nail_salon: 'nail_salon',
  'pet care': 'pet', pet: 'pet', pets: 'pet', grooming: 'pet',
  auto: 'auto', campsite: 'camp', camp: 'camp', 'stays & camp': 'camp',
  hire: 'hire', 'hire & rental': 'hire', rental: 'hire',
  events: 'event', event: 'event', lessons: 'edu', edu: 'edu',
  'photo & media': 'creative', creative: 'creative', photography: 'creative',
  'pro services': 'other', other: 'other',
  gardening: 'gardening', garden: 'gardening', landscaping: 'gardening',
};
const EXTRA_CATEGORY_PHOTOS = {
  gardening: '/assets/img/cat/garden.jpg',
};
function categoryPhoto(cat) {
  if (!cat) return null;
  const key = String(cat).trim().toLowerCase();
  const id = CATEGORY_PHOTO_ALIASES[key] || key;
  if (EXTRA_CATEGORY_PHOTOS[id]) return EXTRA_CATEGORY_PHOTOS[id];
  const hit = CATEGORIES.find(c => c.id === id) || CATEGORIES.find(c => c.name.toLowerCase() === key);
  return hit ? hit.photo : null;
}

function Cover({ seed = 0, label, h = 140, r = 16, icon, children, badge, photo, style = {} }) {
  const Icon = icon;
  return (
    <div className="gph" style={{ ...gradVars(seed), height: h, borderRadius: r, padding: 14, ...style }}>
      {photo && (
        <React.Fragment>
          <img src={photo} alt="" loading="lazy" decoding="async" style={{ position: 'absolute', inset: 0, zIndex: 0, width: '100%', height: '100%', objectFit: 'cover' }}/>
          <div style={{ position: 'absolute', inset: 0, zIndex: 0, background: 'linear-gradient(180deg, rgba(15,14,26,0) 40%, rgba(15,14,26,0.55) 100%)', pointerEvents: 'none' }}/>
        </React.Fragment>
      )}
      {Icon && (
        <div style={{ position: 'absolute', top: 16, right: 16, width: 38, height: 38, borderRadius: 12, background: 'rgba(255,255,255,0.22)', backdropFilter: 'blur(8px)', display: 'grid', placeItems: 'center' }}>
          <Icon style={{ width: 22, height: 22, color: '#fff' }} />
        </div>
      )}
      {badge && (
        <div style={{ position: 'absolute', top: 16, left: 16, fontSize: 11, fontWeight: 800, letterSpacing: 0.04, padding: '4px 8px', borderRadius: 999, background: 'rgba(255,255,255,0.9)', color: 'var(--pri-700)' }}>{badge}</div>
      )}
      {label && (
        <div style={{ color: '#fff', fontWeight: 800, fontSize: 15, letterSpacing: -0.3, textShadow: '0 1px 8px rgba(0,0,0,0.18)' }}>{label}</div>
      )}
      {children}
    </div>
  );
}

/* ─── Stars ───────────────────────────────────────────────── */
function Stars({ value = 5, size = 12 }) {
  return (
    <span style={{ display: 'inline-flex', gap: 1, color: 'var(--amber)' }}>
      {Array.from({ length: 5 }).map((_, i) => (
        <Ic.star key={i} style={{ width: size, height: size, opacity: i < Math.round(value) ? 1 : 0.25 }} />
      ))}
    </span>
  );
}

/* ─── Reveal-on-scroll wrapper ────────────────────────────── */
function Rv({ delay = 0, children, as: As = 'div', ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    // Belt-and-braces: even if IntersectionObserver never fires (e.g. inside
    // a sandboxed iframe whose viewport never overlaps the element from IO's
    // perspective), force the reveal after a short timeout so content always
    // becomes visible.
    const fallback = setTimeout(() => el.classList.add('in'), 700);
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          el.classList.add('in');
          clearTimeout(fallback);
          io.unobserve(el);
        }
      });
    }, { root: el.closest('.bu, .web') || null, threshold: 0.15 });
    io.observe(el);
    return () => { clearTimeout(fallback); io.disconnect(); };
  }, []);
  return <As ref={ref} className="rv" style={{ '--rv-d': `${delay}ms` }} {...rest}>{children}</As>;
}

/* ─── Categories data ─────────────────────────────────────── */
const CATEGORIES = [
  { id: 'barbershop',       name: 'Barber',           icon: Ic.catBarber,   seed: 0, photo: '/assets/img/cat/barber.jpg' },
  { id: 'hair_salon',       name: 'Hair & Beauty',    icon: Ic.catBeauty,   seed: 1, photo: '/assets/img/cat/beauty.jpg' },
  { id: 'massage_spa',      name: 'Wellness',         icon: Ic.catWell,     seed: 2, photo: '/assets/img/cat/wellness.jpg' },
  { id: 'personal_trainer', name: 'Fitness',          icon: Ic.catFit,      seed: 3, photo: '/assets/img/cat/fitness.jpg' },
  { id: 'cleaner',          name: 'Cleaning',         icon: Ic.catClean,    seed: 4, photo: '/assets/img/cat/cleaning.jpg' },
  { id: 'tradesperson',     name: 'Trades',           icon: Ic.catTrade,    seed: 5, photo: '/assets/img/cat/trades.jpg' },
  { id: 'nail_salon',       name: 'Nails',            icon: Ic.catGarden,   seed: 6, photo: '/assets/img/cat/nails.jpg' },
  { id: 'pet',              name: 'Pet Care',         icon: Ic.catPet,      seed: 7, photo: '/assets/img/cat/pet.jpg' },
  { id: 'auto',             name: 'Auto',             icon: Ic.catAuto,     seed: 0, photo: '/assets/img/cat/auto.jpg' },
  { id: 'camp',             name: 'Stays & Camp',     icon: Ic.catCamp,     seed: 1, photo: '/assets/img/cat/camp.jpg' },
  { id: 'hire',             name: 'Hire & Rental',    icon: Ic.catHire,     seed: 2, photo: '/assets/img/cat/hire.jpg' },
  { id: 'event',            name: 'Events',           icon: Ic.catEvent,    seed: 3, photo: '/assets/img/cat/event.jpg' },
  { id: 'edu',              name: 'Lessons',          icon: Ic.catEdu,      seed: 5, photo: '/assets/img/cat/edu.jpg' },
  { id: 'creative',         name: 'Photo & Media',    icon: Ic.catCreative, seed: 6, photo: '/assets/img/cat/creative.jpg' },
  { id: 'other',            name: 'Pro Services',     icon: Ic.catPro,      seed: 7, photo: '/assets/img/cat/pro.jpg' },
];

/* ─── Full service taxonomy ───────────────────────────────────
   The 15 CATEGORIES above are the visual "browse by category" tiles.
   SERVICE_GROUPS is the comprehensive A-Z of services anyone can list
   or search for — modelled on the wider marketplace taxonomy so a
   provider of essentially any local service can sign up and be found.

   Each group carries:
     id      — stable slug (used as the onboarding business-type value;
               lib/bookuno-api normalizeBusinessType maps it to the coarse
               business_type enum, defaulting unknowns to general_service)
     name    — display heading
     icon    — emoji shown in the signup picker
     cat      — which of the 15 top tiles it rolls up to (drives the
               /#/search?cat= link + tile imagery)
     services — the granular services within the group

   Granularity beyond the enum is preserved as the business's actual
   `services` rows (which have their own category), so nothing is lost. */
const SERVICE_GROUPS = [
  { id: 'building', name: 'Building & Renovation', icon: '🏗️', cat: 'tradesperson',
    services: ['General builder', 'House extension', 'Loft conversion', 'Garage conversion', 'Conservatory', 'Restoration & refurbishment', 'Structural engineer', 'Architect', 'Surveyor', 'Damp proofing', 'Scaffolding', 'Demolition', 'Bricklaying', 'Groundwork & foundations'] },
  { id: 'plumbing_heating', name: 'Plumbing, Heating & Gas', icon: '🔧', cat: 'tradesperson',
    services: ['General plumbing', 'Boiler installation', 'Boiler repair & service', 'Central heating', 'Bathroom installation', 'Drainage & blockages', 'Gas safety check', 'Underfloor heating', 'Hot water cylinders', 'Radiators'] },
  { id: 'electrical', name: 'Electrical & Lighting', icon: '💡', cat: 'tradesperson',
    services: ['Electrician', 'Rewiring', 'Fuse box / consumer unit', 'Lighting installation', 'EV charger installation', 'Security & CCTV', 'Fire & smoke alarms', 'Home networking', 'Aerial & satellite', 'Home cinema'] },
  { id: 'handyman', name: 'Handyman & Repairs', icon: '🛠️', cat: 'tradesperson',
    services: ['Handyman', 'Furniture assembly', 'TV mounting', 'Picture & shelf hanging', 'Door & lock repair', 'Locksmith', 'Appliance repair', 'Fence & gate repair'] },
  { id: 'interiors', name: 'Home Improvement & Interiors', icon: '🎨', cat: 'tradesperson',
    services: ['Painting & decorating', 'Plastering', 'Tiling', 'Flooring & carpets', 'Kitchen fitting', 'Bathroom fitting', 'Carpentry & joinery', 'Windows & doors', 'Glazing', 'Blinds & curtains', 'Wallpapering'] },
  { id: 'roofing', name: 'Roofing & Exterior', icon: '🏠', cat: 'tradesperson',
    services: ['Roof repair', 'Roof installation or replacement', 'Guttering', 'Chimney work', 'Cladding', 'Rendering', 'Driveways & paving', 'Patios', 'Pressure washing'] },
  { id: 'garden', name: 'Garden & Outdoor', icon: '🌳', cat: 'tradesperson',
    services: ['Gardening', 'Landscaping', 'Lawn care', 'Tree surgery & removal', 'Hedge trimming', 'Fencing & decking', 'Artificial grass', 'Garden design', 'Ponds & water features', 'Garden clearance'] },
  { id: 'cleaning', name: 'Cleaning', icon: '🧹', cat: 'cleaner',
    services: ['Domestic cleaning', 'Deep cleaning', 'End of tenancy cleaning', 'Commercial & office cleaning', 'Carpet & upholstery cleaning', 'Oven cleaning', 'Window cleaning', 'Gutter cleaning', 'Pest control', 'Waste & rubbish removal'] },
  { id: 'removals', name: 'Removals & Storage', icon: '📦', cat: 'hire',
    services: ['House removals', 'Man & van', 'Office removals', 'Furniture removals', 'Packing services', 'Self storage', 'International removals'] },
  { id: 'hair_beauty', name: 'Hair & Beauty', icon: '💇', cat: 'hair_salon',
    services: ['Hairdresser', 'Barber', 'Hair colouring', 'Hair extensions', 'Wedding hair', 'Makeup artist', 'Eyebrows & lashes', 'Waxing', 'Spray tan', 'Facials', 'Skin treatments'] },
  { id: 'nails', name: 'Nails', icon: '💅', cat: 'nail_salon',
    services: ['Manicure', 'Pedicure', 'Gel nails', 'Acrylic nails', 'Nail art'] },
  { id: 'wellbeing', name: 'Health & Wellbeing', icon: '🧖', cat: 'massage_spa',
    services: ['Massage therapy', 'Sports massage', 'Spa treatments', 'Reflexology', 'Acupuncture', 'Physiotherapy', 'Osteopathy', 'Chiropractor', 'Nutritionist', 'Counselling & therapy', 'Hypnotherapy', 'Reiki'] },
  { id: 'medical_care', name: 'Medical & Care', icon: '🩺', cat: 'other',
    services: ['Private GP & doctor', 'Dentist', 'Optician', 'Podiatry', 'Home & domiciliary care', 'Childcare & nanny', 'Mobility & disability support'] },
  { id: 'fitness', name: 'Fitness & Coaching', icon: '🏋️', cat: 'personal_trainer',
    services: ['Personal trainer', 'Group fitness', 'Yoga', 'Pilates', 'Boxing', 'Swimming lessons', 'Sports coaching', 'Online coaching', 'Life coaching', 'Nutrition coaching'] },
  { id: 'pets', name: 'Pet Services', icon: '🐾', cat: 'pet',
    services: ['Dog walking', 'Pet sitting', 'Dog grooming', 'Dog training', 'Pet boarding', 'Cattery', 'Mobile vet', 'Pet taxi'] },
  { id: 'auto', name: 'Auto & Motoring', icon: '🚗', cat: 'auto',
    services: ['Mobile mechanic', 'Car servicing', 'MOT', 'Car bodywork & repair', 'Mobile car valeting', 'Tyres', 'Car detailing', 'Windscreen repair', 'Vehicle wrapping', 'Breakdown recovery'] },
  { id: 'events', name: 'Events & Entertainment', icon: '🎉', cat: 'event',
    services: ['DJ', 'Live band', 'Musician', 'Magician', 'Photo booth', 'Event planning', 'Party entertainer', "Children's entertainer", 'MC & host', 'Lighting & sound', 'Marquee hire', 'Bouncy castle hire'] },
  { id: 'weddings', name: 'Weddings', icon: '💍', cat: 'event',
    services: ['Wedding photography', 'Wedding videography', 'Wedding planner', 'Wedding florist', 'Wedding cars', 'Wedding cake', 'Celebrant'] },
  { id: 'catering', name: 'Catering & Food', icon: '🍽️', cat: 'event',
    services: ['Catering', 'Private chef', 'Mobile bar', 'Cake maker', 'Street food', 'Grazing tables', 'Waiting staff'] },
  { id: 'photo_video', name: 'Photography & Video', icon: '📷', cat: 'creative',
    services: ['Photographer', 'Videographer', 'Portrait photography', 'Event photography', 'Product photography', 'Property photography', 'Drone & aerial', 'Photo editing'] },
  { id: 'music_arts', name: 'Music & Performing Arts', icon: '🎵', cat: 'creative',
    services: ['Music lessons', 'Singing lessons', 'Music production', 'Recording studio', 'Voiceover', 'Dance lessons', 'Acting & drama'] },
  { id: 'lessons', name: 'Lessons & Tuition', icon: '📚', cat: 'edu',
    services: ['Private tutor', 'Maths tuition', 'English tuition', 'Science tuition', 'Language lessons', 'Exam preparation', 'University & academic', 'Driving instructor', 'Cookery classes', 'Art classes'] },
  { id: 'design_tech', name: 'Design, Web & Software', icon: '💻', cat: 'other',
    services: ['Web design', 'Web development', 'App development', 'Software development', 'Graphic design', 'Logo & branding', 'UX/UI design', 'SEO', 'IT support', 'Tech repair & support'] },
  { id: 'marketing', name: 'Marketing & Advertising', icon: '📣', cat: 'other',
    services: ['Social media marketing', 'Digital marketing', 'Advertising & media buying', 'PR', 'Content marketing', 'Email marketing', 'Marketing strategy', 'Influencer marketing'] },
  { id: 'writing', name: 'Writing & Translation', icon: '✍️', cat: 'other',
    services: ['Copywriting', 'Content writing', 'Translation', 'Transcription', 'Proofreading & editing', 'CV writing', 'Technical writing', 'Grant & bid writing'] },
  { id: 'business_pro', name: 'Business & Professional', icon: '💼', cat: 'other',
    services: ['Business consulting', 'Bookkeeping', 'Virtual assistant', 'HR consulting', 'Recruitment', 'Project management', 'Data & analytics', 'Employment law advice'] },
  { id: 'legal', name: 'Legal Services', icon: '⚖️', cat: 'other',
    services: ['Solicitor', 'Conveyancing', 'Employment law', 'Family law', 'Immigration', 'Wills & probate', 'Commercial law', 'Notary'] },
  { id: 'finance', name: 'Finance & Insurance', icon: '📊', cat: 'other',
    services: ['Accountant', 'Tax advisor', 'Financial advisor', 'Mortgage advisor', 'Insurance broker', 'Payroll', 'Pensions'] },
  { id: 'stays', name: 'Stays & Camping', icon: '⛺', cat: 'camp',
    services: ['Campsite', 'Glamping', 'Holiday let', 'Lodge & cabin', 'Caravan & motorhome pitch'] },
  { id: 'hire', name: 'Hire & Rental', icon: '🎪', cat: 'hire',
    services: ['Equipment hire', 'Tool hire', 'Vehicle hire', 'Party & event hire', 'AV & PA hire', 'Furniture hire'] },
];

// A curated row of high-demand services for the "Popular" pills.
const POPULAR_SERVICES = [
  { name: 'General builder',          cat: 'tradesperson' },
  { name: 'Roof repair',             cat: 'tradesperson' },
  { name: 'Painting & decorating',   cat: 'tradesperson' },
  { name: 'General plumbing',        cat: 'tradesperson' },
  { name: 'Electrician',             cat: 'tradesperson' },
  { name: 'Gardening',               cat: 'tradesperson' },
  { name: 'Domestic cleaning',       cat: 'cleaner' },
  { name: 'End of tenancy cleaning', cat: 'cleaner' },
  { name: 'House removals',          cat: 'hire' },
  { name: 'Handyman',                cat: 'tradesperson' },
  { name: 'Dog walking',             cat: 'pet' },
  { name: 'Personal trainer',        cat: 'personal_trainer' },
  { name: 'Massage therapy',         cat: 'massage_spa' },
  { name: 'Wedding photography',     cat: 'event' },
  { name: 'DJ',                      cat: 'event' },
  { name: 'Private tutor',           cat: 'edu' },
  { name: 'Web design',              cat: 'other' },
  { name: 'Social media marketing',  cat: 'other' },
  { name: 'Catering',                cat: 'event' },
  { name: 'Mobile mechanic',         cat: 'auto' },
];

/* ─── Sample businesses ───────────────────────────────────── */
const BUSINESSES = [
  { id:'sf1', name:'Knot & Comb',    cat:'Barber',     rating:4.9, count:284, dist:'0.4 mi', from:'£18', next:'Today 14:30', seed:0 },
  { id:'sf2', name:'Lumière Skin',   cat:'Beauty',     rating:4.8, count:412, dist:'0.7 mi', from:'£28', next:'Today 16:00', seed:1 },
  { id:'sf3', name:'Stillpoint Studio',cat:'Wellness', rating:5.0, count:198, dist:'1.1 mi', from:'£42', next:'Tomorrow', seed:2 },
  { id:'sf4', name:'Brightline Cleaning',cat:'Cleaning',rating:4.7, count:128, dist:'Mobile',  from:'£60', next:'Mon 09:00', seed:4 },
  { id:'sf5', name:'Greenroot Garden Co.',cat:'Gardening',rating:4.9, count:96,  dist:'Mobile',  from:'£35', next:'Wed', seed:6 },
  { id:'sf6', name:'Pole Star Camp',  cat:'Campsite',  rating:4.8, count:512, dist:'12 mi',  from:'£24', next:'Fri', seed:1 },
  { id:'sf7', name:'Forge Fitness',   cat:'Fitness',   rating:4.9, count:340, dist:'0.9 mi', from:'£15', next:'Today 18:00', seed:3 },
  { id:'sf8', name:'Pawline Grooming',cat:'Pet Care',  rating:4.9, count:156, dist:'1.4 mi', from:'£22', next:'Thu 11:00', seed:7 },
];

Object.assign(window, {
  Ic, BULogo, Phone, PhoneStatus, BottomNav, Cover, Stars, Rv,
  CATEGORIES, BUSINESSES, gradVars, GRAD_PALETTES,
  SERVICE_GROUPS, POPULAR_SERVICES,
});
