// The Fone Shop — marketing components
// Inter-only, pure black, single-accent. Copy verbatim from content.ts.

const { useState, useEffect, useRef } = React;

// ---------- PRIMITIVES ----------

const Eyebrow = ({ children, style }) => (
  <div style={{ fontSize: 12, fontWeight: 500, letterSpacing: '0.2em', color: 'var(--muted)', textTransform: 'uppercase', ...style }}>
    {children}
  </div>
);

const BtnPrimary = ({ children, onClick, size = 'lg', style, icon }) => {
  const [hover, setHover] = useState(false);
  const [press, setPress] = useState(false);
  const bg = press ? '#B8450C' : hover ? '#E55A10' : '#FF6B1A';
  const color = press ? '#fff' : '#000';
  const h = size === 'lg' ? 56 : 44;
  const p = size === 'lg' ? '0 28px' : '0 20px';
  const fs = size === 'lg' ? 18 : 16;
  return (
    <button
      onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}
      onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}
      onClick={onClick}
      style={{
        height: h, padding: p, background: bg, color, border: 0, borderRadius: 8,
        font: `500 ${fs}px Inter`, letterSpacing: '-0.022em', cursor: 'pointer',
        display: 'inline-flex', alignItems: 'center', gap: 10,
        transition: 'background 150ms cubic-bezier(0.25,0.1,0.25,1)',
        ...style
      }}>
      {icon}{children}
    </button>
  );
};

const BtnSecondary = ({ children, onClick, size = 'md', style }) => {
  const [hover, setHover] = useState(false);
  const h = size === 'lg' ? 56 : 44;
  const p = size === 'lg' ? '0 24px' : '0 20px';
  const fs = size === 'lg' ? 17 : 16;
  return (
    <button onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} onClick={onClick}
      style={{
        height: h, padding: p, background: 'transparent', color: 'var(--fg)', border: 0, borderRadius: 8,
        boxShadow: `inset 0 0 0 1px ${hover ? 'var(--fg-3)' : 'var(--border)'}`,
        font: `500 ${fs}px Inter`, letterSpacing: '-0.022em', cursor: 'pointer',
        display: 'inline-flex', alignItems: 'center', gap: 10,
        transition: 'box-shadow 200ms cubic-bezier(0.25,0.1,0.25,1)',
        ...style
      }}>
      {children}
    </button>
  );
};

const OpenNowPill = ({ state = 'open', label = 'Open until 7pm' }) => {
  const color = state === 'open' ? '#30d158' : state === 'override' ? '#ff453a' : '#ff9f0a';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 8, padding: '6px 12px',
      borderRadius: 980, background: 'var(--surface-2)',
      boxShadow: 'inset 0 0 0 1px var(--border)',
      fontSize: 13, color: 'var(--fg)', backdropFilter: 'blur(8px)',
      WebkitBackdropFilter: 'blur(8px)'
    }}>
      <span style={{ width: 8, height: 8, borderRadius: '50%', background: color, boxShadow: `0 0 8px ${color}` }} />
      {label}
    </span>
  );
};

// ---------- HEADER ----------

const NAV_ITEMS = [
  ['Repairs', 'services'],
  ['Pricing', 'pricing'],
  ['Before/After', 'before-after'],
  ['How it works', 'how'],
  ['Reviews', 'reviews'],
  ['Contact', 'contact'],
];

// Hamburger icon button — three lines morph into an X when open.
const Hamburger = ({ open, onClick }) => (
  <button onClick={onClick} aria-label={open ? 'Close menu' : 'Open menu'} aria-expanded={open}
    style={{
      width: 40, height: 40, borderRadius: '50%',
      background: open ? 'var(--accent)' : 'var(--surface-2)',
      border: `1px solid ${open ? 'var(--accent)' : 'var(--border)'}`,
      color: open ? 'var(--accent-text)' : 'var(--fg)',
      cursor: 'pointer', position: 'relative', padding: 0,
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 250ms, border-color 250ms, color 250ms',
      flexShrink: 0,
    }}>
    {[0, 1, 2].map(i => (
      <span key={i} style={{
        position: 'absolute', width: 18, height: 1.75, background: 'currentColor',
        borderRadius: 2, left: '50%', top: '50%',
        marginLeft: -9, marginTop: -0.875,
        transform: open
          ? (i === 1 ? 'scaleX(0)' : `rotate(${i === 0 ? 45 : -45}deg)`)
          : `translateY(${(i - 1) * 5}px)`,
        opacity: open && i === 1 ? 0 : 1,
        transformOrigin: 'center',
        transition: `transform 380ms cubic-bezier(0.32,0.72,0,1) ${i * 30}ms, opacity 200ms`,
      }} />
    ))}
  </button>
);

// Slide-in sheet from the right. Locks scroll, backdrop blur, staggered item reveal.
const NavSheet = ({ open, onClose, onNav }) => {
  const closeBtnRef = useRef(null);
  useEffect(() => {
    if (!open) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    // Focus the close button when opened for keyboard a11y
    const t = setTimeout(() => closeBtnRef.current?.focus(), 100);
    return () => {
      document.body.style.overflow = prev;
      window.removeEventListener('keydown', onKey);
      clearTimeout(t);
    };
  }, [open, onClose]);

  const handleNav = (n, id) => {
    onNav?.(n);
    onClose();
    // Scroll after the sheet begins closing so the motion feels linked
    setTimeout(() => document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }), 120);
  };

  const stagger = (i) => ({
    opacity: open ? 1 : 0,
    transform: open ? 'translateX(0)' : 'translateX(24px)',
    transition: `opacity 420ms ${120 + i * 55}ms cubic-bezier(0.32,0.72,0,1), transform 460ms ${120 + i * 55}ms cubic-bezier(0.32,0.72,0,1)`,
  });

  return (
    <React.Fragment>
      {/* Backdrop */}
      <div onClick={onClose} aria-hidden="true" style={{
        position: 'fixed', inset: 0, zIndex: 60,
        background: 'rgba(0,0,0,0.5)',
        backdropFilter: 'blur(10px) saturate(140%)',
        WebkitBackdropFilter: 'blur(10px) saturate(140%)',
        opacity: open ? 1 : 0,
        pointerEvents: open ? 'auto' : 'none',
        transition: 'opacity 320ms cubic-bezier(0.25,0.1,0.25,1)',
      }} />

      {/* Sheet — fixed to viewport right edge, full height */}
      <aside
        role="dialog" aria-modal="true" aria-label="Menu"
        style={{
          position: 'fixed', top: 0, right: 0, bottom: 0,
          width: 'min(460px, 92vw)', zIndex: 61,
          background: 'var(--bg)',
          borderLeft: '1px solid var(--border)',
          boxShadow: '-40px 0 80px rgba(0,0,0,0.4)',
          transform: open ? 'translateX(0)' : 'translateX(100%)',
          transition: 'transform 520ms cubic-bezier(0.32,0.72,0,1)',
          display: 'flex', flexDirection: 'column',
          overflowY: 'auto',
        }}
      >
        {/* Top row: logo + close */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '20px 24px 8px' }}>
          <img src="../../assets/the-fone-shop-logo-mark.png" alt="The Fone Shop" style={{ height: 52, width: 'auto' }} />
          <button ref={closeBtnRef} onClick={onClose} aria-label="Close menu" style={{
            width: 40, height: 40, borderRadius: '50%',
            background: 'var(--surface-2)', border: '1px solid var(--border)',
            color: 'var(--fg)', cursor: 'pointer', fontSize: 22, lineHeight: 1,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          }}>×</button>
        </div>

        {/* Status strip */}
        <div style={{ padding: '12px 24px 8px', display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center', ...stagger(0) }}>
          <OpenNowPill />
          {typeof RepairCounter !== 'undefined' && <RepairCounter />}
        </div>

        {/* Nav — staggered slide-in */}
        <nav style={{ display: 'flex', flexDirection: 'column', padding: '16px 0 8px' }}>
          {NAV_ITEMS.map(([n, id], i) => (
            <a key={n} href={`#${id}`}
              onClick={e => { e.preventDefault(); handleNav(n, id); }}
              style={{
                fontSize: 28, fontWeight: 400, letterSpacing: '-0.022em',
                color: 'var(--fg)', textDecoration: 'none',
                padding: '14px 24px', cursor: 'pointer',
                display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                borderBottom: '1px solid var(--border-soft)',
                ...stagger(1 + i),
              }}
              onMouseEnter={e => {
                e.currentTarget.style.background = 'var(--surface-2)';
                const arrow = e.currentTarget.querySelector('[data-arrow]');
                if (arrow) arrow.style.transform = 'translateX(6px)';
              }}
              onMouseLeave={e => {
                e.currentTarget.style.background = 'transparent';
                const arrow = e.currentTarget.querySelector('[data-arrow]');
                if (arrow) arrow.style.transform = 'translateX(0)';
              }}
            >
              <span>{n}</span>
              <span data-arrow style={{ color: 'var(--accent)', fontSize: 18, transition: 'transform 220ms cubic-bezier(0.32,0.72,0,1)' }}>→</span>
            </a>
          ))}
        </nav>

        {/* Primary CTA */}
        <div style={{ padding: '12px 24px 8px', ...stagger(1 + NAV_ITEMS.length) }}>
          <BtnPrimary size="lg" style={{ width: '100%', justifyContent: 'center', whiteSpace: 'nowrap' }} icon={
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>
          } onClick={() => { onNav?.('camera'); onClose(); }}>Snap a quote</BtnPrimary>
        </div>

        {/* Cross-kit links — admin PWA + standalone camera quote */}
        <div style={{ padding: '20px 24px 4px', ...stagger(2 + NAV_ITEMS.length) }}>
          <div style={{ fontSize: 11, color: 'var(--fg-3)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 10 }}>
            Other kits
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <a href="../admin/" target="_blank" rel="noopener"
              style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                padding: '12px 14px', borderRadius: 10,
                background: 'var(--surface-2)', color: 'var(--fg)', textDecoration: 'none',
                border: '1px solid var(--border-soft)',
                transition: 'background 160ms, border-color 160ms',
              }}
              onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface-3)'; e.currentTarget.style.borderColor = 'var(--border)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'var(--surface-2)'; e.currentTarget.style.borderColor = 'var(--border-soft)'; }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
                <span style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--accent-soft)', color: 'var(--accent)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <rect x="5" y="2" width="14" height="20" rx="3"/>
                    <path d="M12 18h.01"/>
                  </svg>
                </span>
                <span style={{ display: 'flex', flexDirection: 'column' }}>
                  <span style={{ fontSize: 15, fontWeight: 500, letterSpacing: '-0.011em' }}>Admin PWA</span>
                  <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>Leads · Bookings · Shop · Settings</span>
                </span>
              </span>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--fg-3)' }}>
                <path d="M7 17L17 7M7 7h10v10"/>
              </svg>
            </a>

            <a href="../camera_quote/" target="_blank" rel="noopener"
              style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                padding: '12px 14px', borderRadius: 10,
                background: 'var(--surface-2)', color: 'var(--fg)', textDecoration: 'none',
                border: '1px solid var(--border-soft)',
                transition: 'background 160ms, border-color 160ms',
              }}
              onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface-3)'; e.currentTarget.style.borderColor = 'var(--border)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'var(--surface-2)'; e.currentTarget.style.borderColor = 'var(--border-soft)'; }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
                <span style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--accent-soft)', color: 'var(--accent)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/>
                    <circle cx="12" cy="13" r="3"/>
                  </svg>
                </span>
                <span style={{ display: 'flex', flexDirection: 'column' }}>
                  <span style={{ fontSize: 15, fontWeight: 500, letterSpacing: '-0.011em' }}>Camera Quote</span>
                  <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>Standalone Pillar 1 flow</span>
                </span>
              </span>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--fg-3)' }}>
                <path d="M7 17L17 7M7 7h10v10"/>
              </svg>
            </a>
          </div>
        </div>

        {/* Footer: call + theme toggle + address */}
        <div style={{ marginTop: 'auto', padding: '24px', borderTop: '1px solid var(--border-soft)', ...stagger(4 + NAV_ITEMS.length) }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
            <a href="tel:01782343842" style={{ textDecoration: 'none', color: 'var(--fg)', display: 'inline-flex', flexDirection: 'column' }}>
              <span style={{ fontSize: 11, color: 'var(--fg-3)', letterSpacing: '0.14em', textTransform: 'uppercase' }}>Call the shop</span>
              <span style={{ fontSize: 17, fontWeight: 500, letterSpacing: '-0.022em', fontVariantNumeric: 'tabular-nums' }}>01782 343 842</span>
            </a>
            {typeof ThemeToggle !== 'undefined' && <ThemeToggle />}
          </div>
          <div style={{ marginTop: 12, fontSize: 13, color: 'var(--fg-3)', letterSpacing: '-0.011em' }}>
            27 The Strand, Longton, Stoke-on-Trent · ST3 2NR
          </div>
        </div>
      </aside>
    </React.Fragment>
  );
};

const SiteHeader = ({ scrolled, current = 'Home', onNav }) => {
  const [sheetOpen, setSheetOpen] = useState(false);
  return (
    <React.Fragment>
      <header style={{
        position: 'fixed', top: 0, left: 0, right: 0, height: 88, zIndex: 50,
        background: 'var(--header-blur-bg)',
        backdropFilter: `saturate(180%) blur(${scrolled ? 24 : 16}px)`,
        WebkitBackdropFilter: `saturate(180%) blur(${scrolled ? 24 : 16}px)`,
        borderBottom: `1px solid ${scrolled ? 'var(--border-soft)' : 'transparent'}`,
        transition: 'all 300ms cubic-bezier(0.25,0.1,0.25,1)',
      }}>
        <div style={{ maxWidth: 1200, margin: '0 auto', padding: '0 32px', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <a href="#" onClick={e=>{e.preventDefault(); onNav?.('Home');}} aria-label="The Fone Shop — home" style={{ display: 'inline-flex', alignItems: 'center', textDecoration: 'none' }}>
            <img src="../../assets/the-fone-shop-logo-mark.png" alt="The Fone Shop" style={{ height: 72, width: 'auto', display: 'block', marginLeft: -8 }} />
          </a>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            {typeof ThemeToggle !== 'undefined' && <ThemeToggle />}
            <BtnPrimary size="md" style={{ whiteSpace: 'nowrap' }} onClick={()=>onNav?.('camera')}>Snap a quote</BtnPrimary>
            <Hamburger open={sheetOpen} onClick={() => setSheetOpen(v => !v)} />
          </div>
        </div>
      </header>
      <NavSheet open={sheetOpen} onClose={() => setSheetOpen(false)} onNav={onNav} />
    </React.Fragment>
  );
};

// ---------- HERO ----------

const Hero = ({ onSnap, onMessage }) => {
  // scroll-driven weight
  const [weight, setWeight] = useState(600);
  useEffect(() => {
    let last = 0, raf;
    const tick = () => {
      const v = Math.min(100, Math.abs(window.scrollY - last));
      last = window.scrollY;
      setWeight(640 + v * 0.7);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  return (
    <section style={{
      position: 'relative', minHeight: '100vh', overflow: 'hidden',
      display: 'flex', alignItems: 'center',
      /* Hero is always treated as an immersive dark stage regardless of the
         site's theme — the video is authored dark, so white text reads. */
      color: '#fff',
      background: '#000',
    }}>
      {/* Full-bleed cinematic clip */}
      <HeroVideo full />

      {/* Readability gradient — heavy on the left where the copy sits,
          clearing on the right so the video breathes, with a vignette at
          bottom so the ShopTicker pill floats clean. */}
      <div aria-hidden="true" style={{
        position: 'absolute', inset: 0, zIndex: 1,
        background: [
          'linear-gradient(90deg, rgba(0,0,0,0.92) 0%, rgba(0,0,0,0.65) 35%, rgba(0,0,0,0.2) 65%, rgba(0,0,0,0.6) 100%)',
          'linear-gradient(180deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0) 22%, rgba(0,0,0,0) 70%, rgba(0,0,0,0.75) 100%)',
        ].join(', '),
        pointerEvents: 'none',
      }} />

      <div style={{ maxWidth: 1200, margin: '0 auto', width: '100%', padding: '140px 32px 80px', position: 'relative', zIndex: 2 }}>
        <Eyebrow style={{ marginBottom: 24, color: 'rgba(255,255,255,0.7)' }}>SINCE 2012 · LONGTON, STOKE-ON-TRENT</Eyebrow>
        <h1 style={{
          fontFamily: 'Inter',
          fontSize: 'clamp(48px, 7vw, 88px)',
          fontWeight: weight, fontVariationSettings: `"wght" ${weight}`,
          letterSpacing: '-0.015em', lineHeight: 1.05,
          margin: 0, maxWidth: 900,
          color: '#fff',
          textShadow: '0 2px 40px rgba(0,0,0,0.55)',
          transition: 'font-variation-settings 200ms cubic-bezier(0.25,0.1,0.25,1)'
        }}>
          Drop it off.<br />Grab a coffee.<br />Collect it fixed.
        </h1>
        <p style={{ marginTop: 32, fontSize: 20, color: 'rgba(255,255,255,0.85)', letterSpacing: '-0.022em', maxWidth: 560, lineHeight: 1.4, textShadow: '0 1px 20px rgba(0,0,0,0.55)' }}>
          If it's broken, we'll open it. Same pair of hands, same day, since 2012.
        </p>
        <div style={{ marginTop: 40, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
          <BtnPrimary size="lg" onClick={onSnap} icon={
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>
          }>Snap a quote</BtnPrimary>
          <BtnSecondary size="lg" style={{ color: '#fff', boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.35)' }} onClick={onMessage}>Message us on Messenger</BtnSecondary>
        </div>
      </div>
      {typeof ShopTicker !== 'undefined' && <ShopTicker />}
      {/* scroll hint */}
      <div style={{ position: 'absolute', bottom: 32, left: '50%', transform: 'translateX(-50%)', zIndex: 3 }}>
        <button onClick={() => document.getElementById('services')?.scrollIntoView({ behavior: 'smooth' })}
          style={{ background: 'transparent', border: 0, cursor: 'pointer', color: 'rgba(255,255,255,0.6)', display: 'inline-flex', flexDirection: 'column', alignItems: 'center', gap: 6, fontSize: 11, letterSpacing: '0.2em', textTransform: 'uppercase' }}
        >
          Scroll
          <svg width="12" height="18" viewBox="0 0 12 18" fill="none" stroke="currentColor" strokeWidth="1.5" style={{ animation: 'bounce 2s ease-in-out infinite' }}><path d="M6 2v12M2 10l4 4 4-4"/></svg>
        </button>
      </div>
    </section>
  );
};

// ─────────────────────────────────────────────────────────────
// HeroVideo — full-bleed cinematic background for the hero section.
// Renders behind the hero copy; gradient overlay handles contrast.
// Scroll drives currentTime so the dive into the phone follows the
// user's scroll, same mental model as the old TeardownCanvas.
// ─────────────────────────────────────────────────────────────
const HeroVideo = ({ full = false }) => {
  const videoRef = useRef(null);

  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    // Force the iOS-friendly flags via JS (React JSX sometimes misses them
    // on hydration, and iOS Safari shows a play overlay if autoplay fails).
    v.muted = true;
    v.defaultMuted = true;
    v.playsInline = true;
    v.setAttribute('playsinline', '');
    v.setAttribute('webkit-playsinline', '');
    v.setAttribute('muted', '');

    const tryPlay = () => {
      const p = v.play();
      if (p && p.catch) p.catch(() => {
        // Autoplay rejected — attempt on first user interaction
        const kick = () => { v.play().catch(() => {}); document.removeEventListener('touchstart', kick); document.removeEventListener('click', kick); };
        document.addEventListener('touchstart', kick, { once: true, passive: true });
        document.addEventListener('click', kick, { once: true });
      });
    };
    tryPlay();
    v.addEventListener('loadeddata', tryPlay, { once: true });

    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      v.pause();
      v.currentTime = 1.8;
      return;
    }
    let raf;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = null;
        const duration = v.duration || 5;
        const start = 1.0;
        const range = Math.max(0.5, duration - start - 0.1);
        const t = start + Math.min(range, Math.max(0, window.scrollY / 900 * range));
        try { v.currentTime = t; } catch (e) {}
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => {
      window.removeEventListener('scroll', onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <video
      ref={videoRef}
      aria-hidden="true"
      autoPlay muted loop playsInline
      webkit-playsinline=""
      preload="auto"
      disableRemotePlayback
      controls={false}
      poster="../../assets/hero-teardown-poster.jpg"
      style={{
        position: 'absolute', inset: 0, zIndex: 0,
        width: '100%', height: '100%',
        objectFit: 'cover', objectPosition: 'center',
        pointerEvents: 'none',
      }}
    >
      <source src="../../assets/hero-teardown.webm" type="video/webm" />
      <source src="../../assets/hero-teardown.mp4" type="video/mp4" />
    </video>
  );
};

// Teardown SVG — phone disassembles on scroll (kept for reference, unused)
const TeardownCanvas = () => {
  const [p, setP] = useState(0); // 0..1
  useEffect(() => {
    const on = () => setP(Math.min(1, window.scrollY / 800));
    window.addEventListener('scroll', on, { passive: true });
    return () => window.removeEventListener('scroll', on);
  }, []);
  const screwFloat = p * 60;
  const screenLift = p > 0.2 ? (p - 0.2) * 180 : 0;
  const batterySlide = p > 0.4 ? (p - 0.4) * 140 : 0;
  const newScreenY = p > 0.6 ? 80 - (p - 0.6) * 200 : 80;
  const newScreenOp = p > 0.6 ? Math.min(1, (p - 0.6) * 3) : 0;
  const glow = p > 0.85 ? (p - 0.85) * 6 : 0;
  return (
    <div style={{ position: 'absolute', right: -80, top: '50%', transform: 'translateY(-50%)', width: 600, height: 800, pointerEvents: 'none', opacity: 0.6 }}>
      <svg viewBox="0 0 400 700" width="100%" height="100%">
        {/* workbench cutting mat */}
        <defs>
          <pattern id="mat" width="20" height="20" patternUnits="userSpaceOnUse">
            <path d="M 20 0 L 0 0 0 20" fill="none" stroke="#1a1a1a" strokeWidth="0.5"/>
          </pattern>
          <radialGradient id="glow">
            <stop offset="0%" stopColor="#FF6B1A" stopOpacity="0.8"/>
            <stop offset="100%" stopColor="#FF6B1A" stopOpacity="0"/>
          </radialGradient>
        </defs>
        <rect x="0" y="0" width="400" height="700" fill="url(#mat)" opacity="0.4"/>
        {/* glow */}
        {glow > 0 && <circle cx="200" cy="350" r={200 * glow} fill="url(#glow)" />}
        {/* phone body — back */}
        <g transform={`translate(100, ${150 + screenLift * 0.3})`}>
          <rect x="0" y="0" width="200" height="400" rx="28" fill="#0a0a0a" stroke="#2c2c2e" strokeWidth="1.5"/>
          <rect x="140" y="30" width="40" height="40" rx="8" fill="#050505" stroke="#2c2c2e"/>
          <circle cx="155" cy="50" r="6" fill="#111"/>
        </g>
        {/* battery */}
        <g transform={`translate(${120 + batterySlide}, ${200 + batterySlide * 0.4})`} opacity={p > 0.4 ? 1 : 0.3}>
          <rect x="0" y="0" width="160" height="280" rx="10" fill="#1d1d1f" stroke="#FF6B1A" strokeWidth="1" opacity="0.9"/>
          <text x="80" y="150" textAnchor="middle" fill="#86868b" fontSize="11" letterSpacing="0.1em" fontFamily="monospace">LI-ION 3095mAh</text>
        </g>
        {/* old screen — lifts off */}
        <g transform={`translate(100, ${150 - screenLift}) rotate(${screenLift * 0.08} 200 200)`} opacity={newScreenOp > 0.5 ? 1 - (newScreenOp - 0.5) * 2 : 1}>
          <rect x="0" y="0" width="200" height="400" rx="28" fill="#0a0a0a" stroke="#2c2c2e" strokeWidth="1.5"/>
          {/* cracks */}
          <path d="M 40 80 L 160 180 M 80 40 L 120 220 M 20 200 L 180 240 M 100 280 L 160 360" stroke="#FF6B1A" strokeWidth="0.8" opacity="0.9"/>
          <rect x="60" y="20" width="80" height="16" rx="8" fill="#050505"/>
        </g>
        {/* new screen glides in */}
        <g transform={`translate(100, ${newScreenY})`} opacity={newScreenOp}>
          <rect x="0" y="0" width="200" height="400" rx="28" fill="#050505" stroke="#FF6B1A" strokeWidth="1.5"/>
          <rect x="60" y="20" width="80" height="16" rx="8" fill="#000"/>
        </g>
        {/* screws float out */}
        {[[40,170],[360,170],[40,530],[360,530]].map(([x,y],i)=> (
          <g key={i} transform={`translate(${x + (x>200?1:-1)*screwFloat * (0.5 + i*0.2)}, ${y - screwFloat * 0.4})`}>
            <circle r="6" fill="#2a2a2d" stroke="#FF6B1A" strokeWidth="0.5" opacity={p>0 ? 1 : 0.2}/>
            <line x1="-3" y1="0" x2="3" y2="0" stroke="#86868b" strokeWidth="0.8"/>
            <line x1="0" y1="-3" x2="0" y2="3" stroke="#86868b" strokeWidth="0.8"/>
          </g>
        ))}
      </svg>
    </div>
  );
};

// ---------- TRUST BAR ----------

const TrustBar = () => (
  <section style={{ padding: '60px 32px', borderTop: 'var(--border-soft) 1px solid', borderBottom: 'var(--border-soft) 1px solid' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto', display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 24 }}>
      {[
        ['Since 2012', 'on The Strand'],
        ['Under an hour', 'most repairs'],
        ['12 month', 'warranty on every fix'],
        ['Open it first', 'no "send it off"'],
      ].map(([big, small]) => (
        <div key={big}>
          <div style={{ fontSize: 36, fontWeight: 600, letterSpacing: '-0.02em' }}>{big}</div>
          <div style={{ marginTop: 4, fontSize: 14, color: 'var(--muted)', letterSpacing: '-0.011em' }}>{small}</div>
        </div>
      ))}
    </div>
  </section>
);

// ---------- SERVICES ----------

const DeviceSilhouette = ({ slug }) => {
  const P = {
    phone: <><rect x="65" y="20" width="70" height="160" rx="12" stroke="currentColor" strokeWidth="1.5"/><rect x="72" y="28" width="56" height="144" rx="6" fill="#050505"/><rect x="88" y="32" width="24" height="4" rx="2" fill="#1a1a1a"/></>,
    tablet: <><rect x="35" y="25" width="130" height="150" rx="12" stroke="currentColor" strokeWidth="1.5"/><rect x="42" y="32" width="116" height="136" rx="4" fill="#050505"/></>,
    laptop: <><path d="M 25 135 L 25 55 Q 25 45, 35 45 L 165 45 Q 175 45, 175 55 L 175 135 Z" stroke="currentColor" strokeWidth="1.5"/><rect x="35" y="55" width="130" height="76" rx="2" fill="#050505"/><path d="M 15 140 L 185 140 L 178 158 L 22 158 Z" stroke="currentColor" strokeWidth="1.5"/></>,
    console: <><rect x="20" y="70" width="160" height="80" rx="10" stroke="currentColor" strokeWidth="1.5"/><circle cx="60" cy="110" r="12" fill="#050505" stroke="currentColor" strokeWidth="1.5"/><circle cx="140" cy="110" r="12" fill="#050505" stroke="currentColor" strokeWidth="1.5"/></>,
  };
  return <svg viewBox="0 0 200 200" style={{ width: '100%', height: '100%', color: '#FF6B1A', fill: 'currentColor' }}>{P[slug]}</svg>;
};

const ServiceCard = ({ device, title, body, idx }) => {
  const [hover, setHover] = useState(false);
  return (
    <div
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        position: 'relative', padding: '32px 28px', height: 340,
        border: `1px solid ${hover ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 16,
        background: hover ? 'color-mix(in oklab, var(--accent) 4%, var(--surface))' : 'var(--surface)',
        display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
        overflow: 'hidden', cursor: 'pointer',
        transform: hover ? 'translateY(-2px)' : 'translateY(0)',
        transition: 'all 500ms cubic-bezier(0.25,0.1,0.25,1)',
      }}>
      <div style={{ position: 'absolute', right: -30, top: -20, width: 200, height: 200, opacity: hover ? 0.2 : 0.08, transition: 'opacity 500ms cubic-bezier(0.25,0.1,0.25,1)' }}>
        <DeviceSilhouette slug={device} />
      </div>
      <div style={{ position: 'relative' }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--muted)', letterSpacing: '0.1em' }}>{String(idx).padStart(2,'0')}</div>
        <h3 style={{ margin: '12px 0 0', fontSize: 26, fontWeight: 600, letterSpacing: '-0.015em' }}>{title}</h3>
        <p style={{ margin: '12px 0 0', fontSize: 14, color: 'var(--muted)', lineHeight: 1.5, maxWidth: 220 }}>{body}</p>
      </div>
      <div onClick={() => document.getElementById('pricing')?.scrollIntoView({ behavior: 'smooth' })} style={{ position: 'relative', color: hover ? '#FF6B1A' : '#FFA366', fontSize: 14, letterSpacing: '-0.011em', transition: 'color 500ms', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
        See pricing <span style={{ transform: hover ? 'translateX(4px)' : 'translateX(0)', transition: 'transform 300ms' }}>→</span>
      </div>
      <span style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, height: 2, background: '#FF6B1A',
        transform: hover ? 'scaleX(1)' : 'scaleX(0)', transformOrigin: 'left',
        transition: 'transform 500ms cubic-bezier(0.25,0.1,0.25,1)',
      }} />
    </div>
  );
};

const ServicesSection = () => (
  <section id="services" style={{ padding: '140px 32px', background: 'transparent' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto' }}>
      <Eyebrow>SERVICES</Eyebrow>
      <h2 style={{ marginTop: 16, fontSize: 'clamp(40px, 5vw, 64px)', fontWeight: 600, letterSpacing: '-0.015em', lineHeight: 1.05, maxWidth: 800 }}>
        Whatever's broken.<br />Probably fixable.
      </h2>
      <div style={{ marginTop: 64, display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 16 }}>
        <ServiceCard idx={1} device="phone" title="Phone repair" body="Screens in 40 minutes. Boards the same day. No send-offs, no 'we'll ring you'." />
        <ServiceCard idx={2} device="tablet" title="Tablet repair" body="iPads, Samsung, Kindle. Digitisers relaminated — not bodged with a generic glass kit." />
        <ServiceCard idx={3} device="laptop" title="Laptop repair" body="Screens, keyboards, boards. Write-offs welcome. Show us before you bin it." />
        <ServiceCard idx={4} device="console" title="Console repair" body="PS5, Xbox, Switch. HDMI drop-ins, disc drives, fan rebuilds, liquid-damage boards." />
      </div>
    </div>
  </section>
);

// ---------- INTERSTITIAL ----------

const Interstitial = () => (
  <section style={{ position: 'relative', minHeight: '85vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '80px 32px', background: 'transparent', overflow: 'hidden' }}>
    <div style={{
      position: 'absolute', inset: 0,
      background: 'radial-gradient(ellipse at center, rgba(255,107,26,0.12) 0%, rgba(0,0,0,0) 60%)',
      pointerEvents: 'none',
    }} />
    <div style={{ textAlign: 'center', position: 'relative', zIndex: 2 }}>
      <div style={{
        fontFamily: 'Inter', fontWeight: 700,
        fontSize: 'clamp(100px, 18vw, 220px)',
        letterSpacing: '-0.02em', lineHeight: 0.95,
        color: 'var(--fg)',
      }}>Same day.</div>
      <div style={{ marginTop: 32, fontSize: 22, color: 'var(--fg-3)', letterSpacing: '-0.022em' }}>
        Most repairs, under an hour.
      </div>
    </div>
  </section>
);

// ---------- HOW IT WORKS ----------

const HowItWorks = () => (
  <section id="how" style={{ padding: '140px 32px', background: 'transparent' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto' }}>
      <Eyebrow>HOW IT WORKS</Eyebrow>
      <h2 style={{ marginTop: 16, fontSize: 'clamp(40px, 5vw, 56px)', fontWeight: 600, letterSpacing: '-0.015em', lineHeight: 1.05, maxWidth: 700, marginBottom: 80 }}>
        Three steps.<br/>Usually one morning.
      </h2>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 32 }}>
        {[
          ['01', 'Drop in or message.', "No appointment needed. We're on The Strand."],
          ['02', 'Free diagnostic.', "We tell you exactly what's wrong. No pressure, no jargon."],
          ['03', 'Fixed. Usually same day.', "Grab a coffee. We'll text when it's ready."],
        ].map(([n, h, b]) => (
          <div key={n} style={{ borderTop: 'var(--border) 1px solid', paddingTop: 32 }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 13, color: '#FF6B1A', letterSpacing: '0.1em' }}>{n}</div>
            <h3 style={{ margin: '20px 0 12px', fontSize: 28, fontWeight: 600, letterSpacing: '-0.015em' }}>{h}</h3>
            <p style={{ margin: 0, fontSize: 16, color: 'var(--muted)', lineHeight: 1.5 }}>{b}</p>
          </div>
        ))}
      </div>
    </div>
  </section>
);

// ---------- REVIEWS ----------

const REVIEWS = [
  { name: 'Sarah M.', src: 'GOOGLE', date: '18 APR 2026', stars: 5, body: "Cracked my iPhone on the Sunday, dropped it in Monday morning, picked it up at lunch. Lovely folk — the woman behind the counter offered me a cuppa. Price matched what they said on the phone. Will use again, obviously.", rot: -0.6, rec: false },
  { name: 'Dave', src: 'FACEBOOK', date: '12 APR 2026', stars: 0, body: "Honest, quick, fair price. Fixed my laptop screen when Currys said it was a write-off.", rot: 1.0, rec: true },
  { name: 'Linda H.', src: 'GOOGLE', date: '04 APR 2026', stars: 5, body: "My grandson smashed the back of my phone. These lovely lads sorted it in an hour and only charged me £45. Proper local shop.", rot: -0.3, rec: false },
  { name: 'Ahmed', src: 'FACEBOOK', date: '28 MAR 2026', stars: 0, body: "PS5 HDMI port snapped off after my kids went mental with it. Thought it was gone. £70 and 2 days later, good as new.", rot: 0.8, rec: true },
];

const ReviewCard = ({ r }) => (
  <article className="review-paper" style={{
    position: 'relative', padding: '32px 36px', background: '#f5f2ea', color: '#111',
    borderRadius: 16, boxShadow: '3px 5px 30px rgba(0,0,0,0.22)',
    transform: `rotate(${r.rot}deg)`, flex: '0 0 360px',
  }}>
    <div style={{
      position: 'absolute', right: 20, top: 18,
      fontFamily: 'JetBrains Mono, monospace', fontSize: 10,
      color: '#a8332f', letterSpacing: '0.2em', textAlign: 'right', lineHeight: 1.5,
    }}>{r.date}<br/>{r.src}</div>
    <div style={{ fontFamily: 'Caveat, cursive', fontWeight: 600, fontSize: 44, lineHeight: 1, color: '#111' }}>{r.name}</div>
    {r.stars > 0 && <div style={{ color: '#f5c518', fontSize: 18, letterSpacing: 2, marginTop: 8 }}>{'★'.repeat(r.stars)}</div>}
    {r.rec && (
      <div style={{ marginTop: 10, color: '#0071e3', fontSize: 13, fontWeight: 500, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 10v11h10V10l-5-8zm11 0h2a1 1 0 011 1v9a1 1 0 01-1 1h-2z"/></svg>
        Recommends The Fone Shop
      </div>
    )}
    <p style={{ margin: '16px 0 0', fontSize: 15, lineHeight: 1.5, color: '#111' }}>{r.body}</p>
  </article>
);

const Reviews = () => (
  <section id="reviews" style={{ padding: '140px 0', background: 'transparent' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto', padding: '0 32px' }}>
      <Eyebrow>REAL WORDS · GOOGLE &amp; FACEBOOK</Eyebrow>
      <h2 style={{ marginTop: 16, fontSize: 'clamp(40px, 5vw, 64px)', fontWeight: 600, letterSpacing: '-0.015em', lineHeight: 1.05, maxWidth: 800 }}>
        People say nice things<br/>about us.
      </h2>
      <p style={{ marginTop: 24, fontSize: 17, color: 'var(--muted)', letterSpacing: '-0.022em' }}>
        Real reviews from real customers on Facebook and Google.
      </p>
    </div>
    <div style={{ marginTop: 64, display: 'flex', gap: 32, padding: '40px 48px', overflowX: 'auto', scrollbarWidth: 'none' }}>
      {REVIEWS.map((r, i) => <ReviewCard key={i} r={r} />)}
      <div style={{ flex: '0 0 24px' }} />
    </div>
  </section>
);

// ---------- FOOTER ----------

const SiteFooter = () => (
  <footer id="contact" style={{ padding: '80px 32px 48px', background: 'var(--bg-2)', borderTop: 'var(--border-soft) 1px solid' }}>
    <div style={{ maxWidth: 1200, margin: '0 auto' }}>
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr 1fr', gap: 48 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', marginLeft: -10 }}>
            <img src="../../assets/the-fone-shop-logo-mark.png" alt="The Fone Shop" style={{ height: 84, width: 'auto', display: 'block' }} />
          </div>
          <p style={{ marginTop: 20, fontSize: 14, color: 'var(--muted)', lineHeight: 1.6, maxWidth: 320 }}>
            27 The Strand, Longton, Stoke-on-Trent, ST3 2NR. Open Mon–Sat, 9:00–17:30. Sunday, closed.
          </p>
          <a href="tel:01782343842" style={{ marginTop: 16, fontFamily: 'JetBrains Mono, monospace', fontSize: 14, color: 'var(--fg)', textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: 6, whiteSpace: 'nowrap' }}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF6B1A" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.1-8.7A2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1.9.3 1.8.6 2.7a2 2 0 0 1-.5 2.1L8 9.8a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.5c.9.3 1.8.5 2.7.6a2 2 0 0 1 1.7 2z"/></svg>
            01782 343 842
          </a>
        </div>
        {[
          ['Repairs',   [['Phones',  'services'], ['Tablets', 'services'], ['Laptops', 'services'], ['Consoles', 'services']]],
          ['Shop',      [['Pricing', 'pricing'], ['Before / After', 'before-after'], ['How it works', 'how']]],
          ['Company',   [['Reviews', 'reviews'], ['Visit us',  'contact'], ['Call us', 'tel:01782343842', true]]],
        ].map(([h, items]) => (
          <div key={h}>
            <Eyebrow>{h}</Eyebrow>
            <ul style={{ margin: '16px 0 0', padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 10 }}>
              {items.map(([label, target, ext]) => (
                <li key={label}>
                  <a
                    href={ext ? target : `#${target}`}
                    onClick={ext ? undefined : (e => { e.preventDefault(); document.getElementById(target)?.scrollIntoView({ behavior: 'smooth' }); })}
                    style={{ color: 'var(--fg-2)', fontSize: 14, textDecoration: 'none', letterSpacing: '-0.011em', cursor: 'pointer' }}
                    onMouseEnter={e => e.currentTarget.style.color = 'var(--accent)'}
                    onMouseLeave={e => e.currentTarget.style.color = 'var(--fg-2)'}
                  >{label}</a>
                </li>
              ))}
            </ul>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 80, paddingTop: 24, borderTop: 'var(--border-soft) 1px solid', display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12, color: 'var(--muted)' }}>
        <div>© The Fone Shop Longton Ltd · Since 2012</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 24 }}>
          <span style={{ letterSpacing: '0.2em' }}>STAY CONNECTED · STAY AHEAD</span>
          <a href="/sign-in" style={{ color: 'var(--muted)', letterSpacing: '0.08em', textTransform: 'uppercase', textDecoration: 'none', opacity: 0.7 }}
            onMouseEnter={e => e.currentTarget.style.opacity = 1}
            onMouseLeave={e => e.currentTarget.style.opacity = 0.7}>
            Owner →
          </a>
        </div>
      </div>
    </div>
  </footer>
);

// ---------- CAMERA QUOTE SHEET ----------

const CameraQuoteSheet = ({ open, onClose }) => {
  const [step, setStep] = useState('capture'); // capture | processing | result
  const [photos, setPhotos] = useState([]);
  useEffect(() => { if (open) { setStep('capture'); setPhotos([]); } }, [open]);
  const addPhoto = () => {
    // fake photo — use a placeholder gradient as proxy
    const next = [...photos, `photo-${photos.length + 1}`];
    setPhotos(next);
  };
  const analyse = () => {
    setStep('processing');
    setTimeout(() => setStep('result'), 1800);
  };
  if (!open) return null;
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(0,0,0,0.8)',
      backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)',
      display: 'flex', alignItems: 'flex-end',
    }}
      onClick={onClose}
    >
      <div onClick={e=>e.stopPropagation()} style={{
        background: 'var(--surface)', width: '100%', height: '92vh',
        borderTopLeftRadius: 24, borderTopRightRadius: 24,
        boxShadow: '0 -24px 64px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.06)',
        overflow: 'hidden', display: 'flex', flexDirection: 'column',
        animation: 'slideUp 500ms cubic-bezier(0.25,0.1,0.25,1)',
      }}>
        {/* handle + close */}
        <div style={{ padding: '16px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ width: 40, height: 4, borderRadius: 2, background: 'var(--border)', margin: '0 auto', position: 'absolute', left: '50%', transform: 'translateX(-50%)', top: 12 }} />
          <span style={{ fontSize: 14, color: 'var(--muted)', letterSpacing: '-0.011em' }}>Snap a quote</span>
          <button onClick={onClose} style={{ background: 'transparent', border: 0, color: 'var(--fg)', cursor: 'pointer', fontSize: 22, lineHeight: 1 }}>×</button>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: '24px 32px 48px', maxWidth: 720, margin: '0 auto', width: '100%' }}>
          {step === 'capture' && <CaptureStep photos={photos} addPhoto={addPhoto} analyse={analyse} />}
          {step === 'processing' && <ProcessingStep />}
          {step === 'result' && <ResultStep onBook={onClose} />}
        </div>
      </div>
    </div>
  );
};

const PhotoSlot = ({ filled, onClick, idx }) => (
  <button onClick={onClick} style={{
    position: 'relative', aspectRatio: '3/4', borderRadius: 16,
    background: filled ? `linear-gradient(135deg, #2a1810 0%, var(--surface) 100%)` : 'var(--surface)',
    border: `1px dashed ${filled ? 'var(--accent)' : 'var(--border)'}`,
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    color: filled ? 'var(--accent)' : 'var(--muted)',
    cursor: filled ? 'default' : 'pointer', overflow: 'hidden',
  }}>
    {filled ? (
      <>
        {/* faux phone photo */}
        <svg viewBox="0 0 100 140" style={{ width: '70%', height: '70%' }}>
          <rect x="25" y="10" width="50" height="120" rx="8" fill="#050505" stroke="#FF6B1A" strokeWidth="0.8"/>
          <path d="M 30 40 L 70 80 M 35 100 L 65 50 M 40 30 L 50 110" stroke="#FF6B1A" strokeWidth="0.6" opacity="0.6"/>
        </svg>
        <span style={{ position: 'absolute', bottom: 8, left: 10, fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: '#FF6B1A' }}>0{idx}</span>
      </>
    ) : (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>
        <span style={{ fontSize: 12 }}>Add {idx === 1 ? 'photo' : idx === 2 ? '2nd photo' : '3rd photo'}</span>
      </div>
    )}
  </button>
);

const CaptureStep = ({ photos, addPhoto, analyse }) => (
  <>
    <h2 style={{ fontSize: 40, fontWeight: 600, letterSpacing: '-0.015em', lineHeight: 1.05, margin: 0 }}>
      Show us what<br/>we're dealing with.
    </h2>
    <p style={{ marginTop: 20, fontSize: 17, color: 'var(--muted)', letterSpacing: '-0.022em', lineHeight: 1.47 }}>
      Snap or upload a photo — front, back, or the damage close-up. Three is best, one is fine.
    </p>
    <div style={{ marginTop: 40, display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
      {[1,2,3].map(i => (
        <PhotoSlot key={i} idx={i} filled={i <= photos.length} onClick={i === photos.length + 1 ? addPhoto : undefined} />
      ))}
    </div>
    <div style={{ marginTop: 32, display: 'flex', gap: 16, alignItems: 'center' }}>
      <BtnPrimary size="lg" onClick={analyse} style={{ opacity: photos.length === 0 ? 0.4 : 1, pointerEvents: photos.length === 0 ? 'none' : 'auto' }}>
        Get my quote
      </BtnPrimary>
      <button style={{ background: 'transparent', border: 0, color: '#FFA366', fontSize: 14, cursor: 'pointer' }}>
        Not right? Pick it manually →
      </button>
    </div>
    <p style={{ marginTop: 40, fontSize: 13, color: 'var(--muted)' }}>
      Final price confirmed after a free in-store diagnostic.
    </p>
  </>
);

const ProcessingStep = () => (
  <div style={{ padding: '80px 0', textAlign: 'center' }}>
    <div style={{ display: 'inline-block', position: 'relative' }}>
      <svg width="120" height="120" viewBox="0 0 100 100">
        <circle cx="50" cy="50" r="44" fill="none" stroke="#1a1a1a" strokeWidth="2"/>
        <circle cx="50" cy="50" r="44" fill="none" stroke="#FF6B1A" strokeWidth="2"
          strokeDasharray="60 280" strokeLinecap="round"
          style={{ transformOrigin: 'center', animation: 'spin 1.2s linear infinite' }}/>
        <circle cx="50" cy="50" r="6" fill="#FF6B1A"/>
      </svg>
    </div>
    <h2 style={{ marginTop: 40, fontSize: 32, fontWeight: 600, letterSpacing: '-0.015em' }}>Taking a look…</h2>
    <p style={{ marginTop: 12, fontSize: 15, color: 'var(--muted)' }}>Identifying the device and what's wrong.</p>
  </div>
);

const ResultStep = ({ onBook }) => {
  const [device, setDevice] = useState('');
  const target = 'iPhone 13';
  useEffect(() => {
    let i = 0;
    const id = setInterval(() => {
      i++;
      setDevice(target.slice(0, i));
      if (i >= target.length) clearInterval(id);
    }, 60);
    return () => clearInterval(id);
  }, []);
  return (
    <>
      <Eyebrow>CONFIDENCE 94%</Eyebrow>
      <h2 style={{ marginTop: 16, fontSize: 44, fontWeight: 600, letterSpacing: '-0.015em', lineHeight: 1.05 }}>
        Looks like an<br/>
        <span style={{ color: '#FF6B1A', fontVariationSettings: '"wght" 700' }}>{device}<span style={{ opacity: device.length < target.length ? 1 : 0, color: '#FF6B1A' }}>|</span></span><br/>
        with a cracked screen.
      </h2>
      <div style={{ marginTop: 48, padding: 32, background: 'rgba(10,10,10,0.6)', border: '1px solid var(--border)', borderRadius: 16, backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', flexWrap: 'wrap', gap: 16 }}>
          <div>
            <Eyebrow>STARTING FROM</Eyebrow>
            <div style={{ marginTop: 8, fontSize: 64, fontWeight: 600, letterSpacing: '-0.02em', lineHeight: 1 }}>£89</div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontSize: 14, color: 'var(--muted)' }}>Turnaround</div>
            <div style={{ marginTop: 4, fontSize: 22, fontWeight: 500, letterSpacing: '-0.011em' }}>Same day</div>
          </div>
        </div>
        <div style={{ marginTop: 28, paddingTop: 24, borderTop: 'var(--border-soft) 1px solid', display: 'flex', gap: 12, flexWrap: 'wrap' }}>
          <BtnPrimary size="lg" onClick={onBook}>Book this repair</BtnPrimary>
          <BtnSecondary size="lg">Call the shop</BtnSecondary>
        </div>
      </div>
      <p style={{ marginTop: 24, fontSize: 13, color: 'var(--muted)' }}>
        Final price confirmed after a free in-store diagnostic.
      </p>
    </>
  );
};

// ---------- EXPORT ----------

Object.assign(window, {
  SiteHeader, Hero, TrustBar, ServicesSection, Interstitial, HowItWorks, Reviews, SiteFooter, CameraQuoteSheet,
  BtnPrimary, BtnSecondary, OpenNowPill, Eyebrow,
});
