/* global React */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ============== Brand SVG icons (no emojis) ==============
const CP_ICONS = {
  breakfast: () => (
    <svg viewBox="0 0 64 64" width="34" height="34" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M26 10c2 3-2 5 0 8M32 8c2 3-2 5 0 8M38 10c2 3-2 5 0 8" opacity="0.85"/>
      <path d="M18 24h28l-2 18a8 8 0 0 1-8 7h-8a8 8 0 0 1-8-7z"/>
      <ellipse cx="32" cy="26" rx="13" ry="2.2"/>
      <path d="M30 26c1-1 3-1 4 0" opacity="0.6"/>
      <path d="M46 28c5 0 8 3 8 7s-3 7-8 7"/>
      <path d="M14 53h36"/>
      <path d="M12 53c0 2 4 3 20 3s20-1 20-3" opacity="0.7"/>
    </svg>
  ),
  lunch: () => (
    <svg viewBox="0 0 64 64" width="34" height="34" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M44 6c-1 4 0 8 3 9s4-5 3-9z" opacity="0.85"/>
      <path d="M47 15v9M43 24h8" opacity="0.85"/>
      <circle cx="32" cy="38" r="16"/>
      <circle cx="32" cy="38" r="11" opacity="0.55"/>
      <path d="M14 24v10a4 4 0 0 0 4 4v18"/>
      <path d="M18 24v8M22 24v10a4 4 0 0 1-4 4"/>
      <path d="M50 24c-3 4-4 9-4 14h4z"/>
      <path d="M48 38v18"/>
    </svg>
  ),
  google: () => (
    <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
      <path fill="#4285F4" d="M23.49 12.27c0-.79-.07-1.54-.2-2.27H12v4.51h6.45c-.28 1.45-1.13 2.68-2.4 3.5v2.91h3.88c2.27-2.09 3.56-5.17 3.56-8.65z"/>
      <path fill="#34A853" d="M12 24c3.24 0 5.96-1.07 7.95-2.91l-3.88-2.91c-1.07.72-2.45 1.16-4.07 1.16-3.13 0-5.78-2.11-6.73-4.96H1.27v3.09C3.25 21.31 7.31 24 12 24z"/>
      <path fill="#FBBC04" d="M5.27 14.38a7.21 7.21 0 0 1 0-4.76V6.53H1.27a12 12 0 0 0 0 10.94l4-3.09z"/>
      <path fill="#EA4335" d="M12 4.75c1.77 0 3.35.61 4.6 1.8l3.43-3.43C17.95 1.19 15.24 0 12 0 7.31 0 3.25 2.69 1.27 6.53l4 3.09C6.22 6.86 8.87 4.75 12 4.75z"/>
    </svg>
  ),
  star: () => (
    <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" stroke="none" aria-hidden="true">
      <path d="M12 2.5l1.7 8.8 8.8 1.7-8.8 1.7L12 21.5l-1.7-8.8L1.5 11l8.8-1.7z"/>
    </svg>
  )
};

// ============== Logo SVG ==============
function Logo({ size = 1, animated = false }) {
  return (
    <svg viewBox="0 0 320 140" style={{ width: 200 * size, height: 'auto', display: 'block' }} className={animated ? 'logo-anim' : ''}>
      <defs>
        <linearGradient id="goldGrad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#f0dfb5"/>
          <stop offset="40%" stopColor="#e6c98a"/>
          <stop offset="60%" stopColor="#c9a86a"/>
          <stop offset="100%" stopColor="#9c7d44"/>
        </linearGradient>
      </defs>
      <text x="40" y="62" fontFamily="Cormorant Garamond, serif" fontStyle="italic" fontWeight="500" fontSize="34" fill="url(#goldGrad)">can</text>
      <text x="100" y="78" fontFamily="Cormorant Garamond, serif" fontWeight="600" fontSize="86" fill="url(#goldGrad)" letterSpacing="-2">P</text>
      <text x="146" y="92" fontFamily="Cormorant Garamond, serif" fontStyle="italic" fontWeight="500" fontSize="46" fill="url(#goldGrad)">e</text>
      <text x="172" y="78" fontFamily="Cormorant Garamond, serif" fontWeight="600" fontSize="86" fill="url(#goldGrad)" letterSpacing="-2">T</text>
      <text x="210" y="92" fontFamily="Cormorant Garamond, serif" fontStyle="italic" fontWeight="500" fontSize="46" fill="url(#goldGrad)">it</text>
      <text x="246" y="78" fontFamily="Cormorant Garamond, serif" fontWeight="600" fontSize="86" fill="url(#goldGrad)" letterSpacing="-2">A</text>
      <path d="M 36 100 Q 160 118 290 92" stroke="url(#goldGrad)" strokeWidth="3" fill="none" strokeLinecap="round"/>
    </svg>
  );
}

// ============== Cursor (desktop only) ==============
function Cursor() {
  const haloRef = useRef(null);
  const dotRef = useRef(null);
  useEffect(() => {
    if (window.matchMedia('(hover: none)').matches) return;
    let raf, tx = 0, ty = 0, hx = 0, hy = 0;
    const move = (e) => {
      tx = e.clientX; ty = e.clientY;
      if (dotRef.current) {
        dotRef.current.style.left = tx + 'px';
        dotRef.current.style.top = ty + 'px';
        dotRef.current.classList.add('visible');
        haloRef.current.classList.add('visible');
      }
    };
    const tick = () => {
      hx += (tx - hx) * 0.18;
      hy += (ty - hy) * 0.18;
      if (haloRef.current) {
        haloRef.current.style.left = hx + 'px';
        haloRef.current.style.top = hy + 'px';
      }
      raf = requestAnimationFrame(tick);
    };
    const enter = (e) => {
      if (e.target.closest && e.target.closest('a, button, .menu-tab, .tile, input, select, textarea, label, .nav-logo')) {
        haloRef.current?.classList.add('hover');
      }
    };
    const leave = (e) => {
      if (e.target.closest && e.target.closest('a, button, .menu-tab, .tile, input, select, textarea, label, .nav-logo')) {
        haloRef.current?.classList.remove('hover');
      }
    };
    window.addEventListener('mousemove', move, { passive: true });
    document.addEventListener('mouseover', enter);
    document.addEventListener('mouseout', leave);
    tick();
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('mousemove', move);
      document.removeEventListener('mouseover', enter);
      document.removeEventListener('mouseout', leave);
    };
  }, []);
  return (
    <>
      <div ref={haloRef} className="cursor-halo"/>
      <div ref={dotRef} className="cursor-dot"/>
    </>
  );
}

// ============== Nav (with mobile drawer) ==============
function Nav({ t, lang, setLang }) {
  const [scrolled, setScrolled] = useState(false);
  const [open, setOpen] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 60);
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  useEffect(() => {
    document.body.style.overflow = open ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [open]);
  const langs = ['ca', 'es', 'en', 'fr', 'nl'];
  const close = () => setOpen(false);
  return (
    <>
      <nav className={`nav ${scrolled ? 'scrolled' : ''}`}>
        <a href="#top" className="nav-logo" onClick={close}>
          <span style={{ fontStyle: 'italic' }}>can</span><b>Petita</b>
        </a>
        <div className="nav-links">
          <a href="#story">{t.nav.story}</a>
          <a href="#breakfast">{t.nav.breakfast}</a>
          <a href="#lunch">{t.nav.lunch}</a>
          <a href="#gallery">{t.nav.gallery}</a>
          <a href="#visit">{t.nav.visit}</a>
          <button type="button" className="nav-manage" onClick={() => window.dispatchEvent(new CustomEvent('cp:open-manage'))}>
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <rect x="3" y="4.5" width="18" height="17" rx="2"/>
              <path d="M16 2.5v4M8 2.5v4M3 10h18" opacity="0.85"/>
              <circle cx="12" cy="15" r="1.4" fill="currentColor"/>
            </svg>
            <span>{t.nav.manage || t.reserve.floaterLabel || 'Mi reserva'}</span>
          </button>
          <div className="lang">
            {langs.map(l => (
              <button key={l} className={lang === l ? 'active' : ''} onClick={() => setLang(l)} aria-label={`Language ${l}`}>{l}</button>
            ))}
          </div>
          <a href="#reserve" className="book-pill">{t.nav.reserve}</a>
          <button className="nav-burger" onClick={() => setOpen(true)} aria-label="Menu">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="13" x2="20" y2="13"/><line x1="4" y1="19" x2="20" y2="19"/></svg>
          </button>
        </div>
      </nav>

      <div className={`drawer-backdrop ${open ? 'show' : ''}`} onClick={close}/>
      <aside className={`nav-drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
        <button className="drawer-close" onClick={close} aria-label="Close">×</button>
        <a href="#story" onClick={close}>{t.nav.story}</a>
        <a href="#breakfast" onClick={close}>{t.nav.breakfast}</a>
        <a href="#lunch" onClick={close}>{t.nav.lunch}</a>
        <a href="#gallery" onClick={close}>{t.nav.gallery}</a>
        <a href="#visit" onClick={close}>{t.nav.visit}</a>
        <button type="button" className="drawer-manage" onClick={() => { close(); window.dispatchEvent(new CustomEvent('cp:open-manage')); }}>
          <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <rect x="3" y="4.5" width="18" height="17" rx="2"/>
            <path d="M16 2.5v4M8 2.5v4M3 10h18" opacity="0.85"/>
            <circle cx="12" cy="15" r="1.4" fill="currentColor"/>
          </svg>
          <span>{t.nav.manage || t.reserve.floaterLabel || 'Mi reserva'}</span>
        </button>
        <div className="lang">
          {langs.map(l => (
            <button key={l} className={lang === l ? 'active' : ''} onClick={() => { setLang(l); close(); }}>{l}</button>
          ))}
        </div>
        <a href="#reserve" className="book-pill" onClick={close}>{t.nav.reserve} →</a>
      </aside>
    </>
  );
}

// ============== Hero language switcher (mobile only) — reactive ==============
function HeroLangSwitcher({ lang, setLang }) {
  const langs = ['ca', 'es', 'en', 'fr', 'nl'];
  return (
    <div className="hero-lang">
      {langs.map(l => (
        <button
          key={l}
          className={lang === l ? 'active' : ''}
          onClick={() => setLang(l)}
          aria-label={`Idioma ${l}`}
        >{l}</button>
      ))}
    </div>
  );
}

// ============== Hero ==============
function Hero({ t, lang, setLang }) {
  const heroRef = useRef(null);
  useEffect(() => {
    if (window.matchMedia('(hover: none)').matches) return;
    const onMove = (e) => {
      if (!heroRef.current) return;
      const r = heroRef.current.getBoundingClientRect();
      const x = (e.clientX - r.left) / r.width - 0.5;
      const y = (e.clientY - r.top) / r.height - 0.5;
      heroRef.current.style.setProperty('--mx', x);
      heroRef.current.style.setProperty('--my', y);
    };
    const el = heroRef.current;
    el?.addEventListener('mousemove', onMove);
    return () => el?.removeEventListener('mousemove', onMove);
  }, []);
  return (
    <section className="hero" id="top" ref={heroRef}>
      <div className="hero-bg-grain"/>
      <div className="hero-orb a" style={{ transform: 'translate(calc(var(--mx, 0) * 30px), calc(var(--my, 0) * 30px))' }}/>
      <div className="hero-orb b" style={{ transform: 'translate(calc(var(--mx, 0) * -20px), calc(var(--my, 0) * -20px))' }}/>
      <div className="hero-inner">
        {t.hero.badge && (
          <div className="hero-badge">{t.hero.badge}</div>
        )}
        <div className="hero-eyebrow">
          <span className="eyebrow">{t.hero.eyebrow}</span>
        </div>
        {/* Mobile-only language switcher (visible only when burger is shown) */}
        <HeroLangSwitcher lang={lang} setLang={setLang}/>
        <h1 className="hero-title">
          <span className="word">{t.hero.title}</span>
          <span className="and">{t.hero.titleAnd}</span>
          <span className="word">{t.hero.title2}</span>
        </h1>
        <p className="hero-sub">{t.hero.sub}</p>
        <div className="hero-ctas">
          <a href="#reserve" className="btn btn-gold">{t.hero.cta} <span className="arrow">→</span></a>
        </div>
        <div className="hero-cta-cards">
          <a href="#breakfast" className="cta-card">
            <span className="cta-card-icon"><CP_ICONS.breakfast/></span>
            <span className="cta-card-text">
              <span className="cta-card-eyebrow">descubre</span>
              <span className="cta-card-label">{t.hero.ctaBreakfast || t.nav.breakfast}</span>
            </span>
            <span className="cta-card-arrow">→</span>
          </a>
          <a href="#lunch" className="cta-card">
            <span className="cta-card-icon"><CP_ICONS.lunch/></span>
            <span className="cta-card-text">
              <span className="cta-card-eyebrow">descubre</span>
              <span className="cta-card-label">{t.hero.ctaLunch || t.nav.lunch}</span>
            </span>
            <span className="cta-card-arrow">→</span>
          </a>
        </div>
      </div>
      <div className="hero-scroll">
        <span className="label">{t.hero.scroll}</span>
        <span className="mouse"/>
      </div>
    </section>
  );
}

// ============== Story ==============
function Story({ t }) {
  const StatsCounter = window.CP_GAME?.StatsCounter;
  return (
    <section className="story" id="story">
      <div className="section-inner">
        <div className="story-grid">
          <div className="story-text reveal">
            <span className="eyebrow">{t.story.eyebrow}</span>
            <h2 style={{ marginTop: 18 }}>
              {t.story.title.split('\n').map((line, i) => (
                <div key={i}>{i === 1 ? <span className="gold">{line}</span> : line}</div>
              ))}
            </h2>
            <p>{t.story.p1}</p>
            <p>{t.story.p2}</p>
            <div className="story-sign">{t.story.sign}</div>
            <div className="story-stats">
              <div className="stat"><div className="v">{t.story.stat1Value}</div><div className="l">{t.story.stat1Label}</div></div>
              <div className="stat"><div className="v">{t.story.stat2Value}</div><div className="l">{t.story.stat2Label}</div></div>
              <div className="stat"><div className="v">{t.story.stat3Value}</div><div className="l">{t.story.stat3Label}</div></div>
            </div>
          </div>
          <div className="story-photo reveal">
            <img src="assets/photos/paco.jpg" alt={t.story.ownerName} loading="lazy"/>
            <div className="story-card">
              <div className="name">{t.story.ownerName}</div>
              <div className="role">{t.story.ownerRole}</div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ============== Generic Menu Renderer (used for breakfast & lunch) ==============
function MenuItems({ items }) {
  if (!items || !items.length) return null;
  return items.map((it, i) => (
    <div key={i} className={`menu-item ${it.opt ? 'opt' : ''}`} style={{ animation: `fadeUp .5s var(--ease) ${Math.min(i, 12) * 0.03}s both` }}>
      <div className="top">
        <span className="name">{it.n}</span>
        <span className="dots"/>
      </div>
      <span className="price">{it.p}{it.p && !/^[+]/.test(it.p) ? <span className="price-sym"> €</span> : null}</span>
      {it.d && <div className="desc">{it.d}</div>}
    </div>
  ));
}

// ============== Category Pager (arrows + name + dots) ==============
function CategoryPager({ cats, active, onChange }) {
  const idx = Math.max(0, cats.indexOf(active));
  const total = cats.length;
  const go = (i) => onChange(cats[(i + total) % total]);
  const prev = () => go(idx - 1);
  const next = () => go(idx + 1);
  const startX = useRef(0);
  const startY = useRef(0);
  const onTouchStart = (e) => {
    startX.current = e.touches[0].clientX;
    startY.current = e.touches[0].clientY;
  };
  const onTouchEnd = (e) => {
    const dx = e.changedTouches[0].clientX - startX.current;
    const dy = e.changedTouches[0].clientY - startY.current;
    if (Math.abs(dx) > 45 && Math.abs(dx) > Math.abs(dy) * 1.4) {
      if (dx > 0) prev(); else next();
    }
  };
  return (
    <div className="cat-pager reveal" onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}>
      <div className="cat-pager-row">
        <button className="cat-arrow" onClick={prev} aria-label="Categoría anterior" type="button">
          <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path d="M15 5l-7 7 7 7" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </button>
        <div className="cat-pager-track">
          <span className="cat-name" key={active}>{active}</span>
          <span className="cat-counter">{idx + 1} / {total}</span>
        </div>
        <button className="cat-arrow" onClick={next} aria-label="Categoría siguiente" type="button">
          <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </button>
      </div>
      <div className="cat-dots" role="tablist" aria-label="Categorías">
        {cats.map((c, i) => (
          <button
            key={c}
            type="button"
            role="tab"
            aria-selected={i === idx}
            aria-label={c}
            className={`cat-dot ${i === idx ? 'active' : ''}`}
            onClick={() => go(i)}
          />
        ))}
      </div>
    </div>
  );
}

// ============== Breakfast Menu ==============
function BreakfastMenu({ t }) {
  const cats = t.breakfast.cats || [];
  const [active, setActive] = useState(cats[0]);
  useEffect(() => { setActive(cats[0]); }, [cats[0]]);
  const items = t.breakfast.items[active] || [];
  return (
    <section className="menu-section" id="breakfast">
      <div className="section-inner">
        <div className="section-head reveal">
          <span className="eyebrow">{t.breakfast.eyebrow}</span>
          <h2 style={{ marginTop: 14 }}>{t.breakfast.title}</h2>
          <p className="sub">{t.breakfast.sub}</p>
        </div>
        <CategoryPager cats={cats} active={active} onChange={setActive}/>
        <div className="menu-grid" key={active}>
          <MenuItems items={items}/>
        </div>
      </div>
    </section>
  );
}

// ============== Lunch Menu ==============
function LunchMenu({ t }) {
  const cats = t.lunch.cats || [];
  const [active, setActive] = useState(cats[0]);
  useEffect(() => { setActive(cats[0]); }, [cats[0]]);
  const items = t.lunch.items[active] || [];
  return (
    <section className="menu-section dark" id="lunch">
      <div className="section-inner">
        <div className="section-head reveal">
          <span className="eyebrow">{t.lunch.eyebrow}</span>
          <h2 style={{ marginTop: 14 }}><span className="gold">{t.lunch.title}</span></h2>
          <p className="sub">{t.lunch.sub}</p>
        </div>
        <CategoryPager cats={cats} active={active} onChange={setActive}/>
        <div className="menu-grid" key={active}>
          <MenuItems items={items}/>
        </div>
      </div>
    </section>
  );
}

// ============== Gallery (real photos with lightbox) ==============
const GALLERY_PHOTOS = [
  { src: 'assets/photos/exterior.jpg', cls: 't1', key: 0 },
  { src: 'assets/photos/octopus.jpg', cls: 't2', key: 1 },
  { src: 'assets/photos/salmon-toast.jpg', cls: 't3', key: 2 },
  { src: 'assets/photos/table-overhead.jpg', cls: 't4', key: 3 },
  { src: 'assets/photos/charcuterie.jpg', cls: 't5', key: 4 },
  { src: 'assets/photos/bravas.jpg', cls: 't6', key: 5 },
  { src: 'assets/photos/teacups.jpg', cls: 't7', key: 6 },
  { src: 'assets/photos/matcha-cat.jpg', cls: 't8', key: 7 },
  { src: 'assets/photos/canas-fresas.jpg', cls: 't9', key: 8 },
  { src: 'assets/photos/coconut-bowl.jpg', cls: 't10', key: 9 }
];

function Gallery({ t }) {
  const [lbIndex, setLbIndex] = useState(-1);
  const Lightbox = window.CP_GAME?.PhotoLightbox;
  const labels = t.gallery.labels || [];
  const photos = GALLERY_PHOTOS.map((p, i) => ({ ...p, caption: labels[i] || '', alt: labels[i] || 'Can Petita' }));
  return (
    <section className="gallery" id="gallery">
      <div className="section-inner">
        <div className="section-head reveal">
          <span className="eyebrow">{t.gallery.eyebrow}</span>
          <h2 style={{ marginTop: 14 }}>{t.gallery.title}</h2>
          <p className="sub">{t.gallery.sub}</p>
        </div>
        <div className="gallery-grid reveal">
          {photos.map((p, i) => (
            <div key={i} className={`tile ${p.cls}`} onClick={() => setLbIndex(i)} role="button" tabIndex={0}
                 onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') setLbIndex(i); }}>
              <img src={p.src} alt={p.alt} loading="lazy"/>
              <div className="tile-label">{p.caption}</div>
            </div>
          ))}
        </div>
        <div className="ig-cta">
          <a href="https://www.instagram.com/canpetita" target="_blank" rel="noopener" className="btn btn-ghost">
            <span style={{ fontSize: 16 }}>◉</span> {t.gallery.cta}
          </a>
        </div>
      </div>
      {Lightbox && lbIndex >= 0 && (
        <Lightbox photos={photos} index={lbIndex} onClose={() => setLbIndex(-1)}/>
      )}
    </section>
  );
}

// ============== Reviews (real Google reviews) ==============
function Reviews({ t }) {
  return (
    <section className="reviews" id="reviews">
      <div className="section-inner">
        <div className="section-head reveal" style={{ textAlign: 'center' }}>
          <span className="eyebrow" style={{ justifyContent: 'center' }}>{t.reviews.eyebrow}</span>
          <h2 style={{ marginTop: 14 }}><span className="gold">{t.reviews.title}</span></h2>
          {t.reviews.sub && <p className="sub" style={{ marginLeft: 'auto', marginRight: 'auto' }}>{t.reviews.sub}</p>}
        </div>
        <div className="reviews-meta reveal">
          <span className="stars-row">★★★★★</span>
          {t.trust?.rating || '4,9'} / 5 · {t.trust?.reviewsCount || '157'} {t.trust?.reviewsLabel || 'reseñas verificadas'}
        </div>
        <div className="review-track">
          {t.reviews.list.map((r, i) => (
            <div key={i} className="review reveal">
              <span className="quote">"</span>
              <div className="stars">{'★'.repeat(r.s || 5)}</div>
              <h4>{r.t}</h4>
              <p className="body">{r.b}</p>
              <div className="author">{r.a}</div>
              {r.src && <div className="src">{r.src}</div>}
            </div>
          ))}
        </div>
        <div className="reviews-cta reveal">
          <p className="reviews-cta-text">{t.reviews.askText || '¿Te gustó? Déjanos una reseña — nos hace mucha ilusión.'}</p>
          <a href="https://www.google.com/search?q=Can+Petita+Sant+Antoni+de+Calonge#lrd=0x12bafa75836715dd:0x4a8de07a9da8b0aa,3" target="_blank" rel="noopener" className="btn btn-ghost reviews-cta-btn">
            <CP_ICONS.google/> {t.reviews.askCTA || 'Dejar reseña en Google'} <span className="arrow">→</span>
          </a>
        </div>
      </div>
    </section>
  );
}

// ============== Visit (hours + Google Maps) ==============
function Visit({ t }) {
  const now = new Date();
  const jsDay = now.getDay(); // 0=Sun, 1=Mon, ... 6=Sat
  // Our hoursList is Mon-first → index = (Sun=6, Mon=0, Tue=1, ..., Sat=5)
  const todayIdx = jsDay === 0 ? 6 : jsDay - 1;
  const mapsEmbed = "https://maps.google.com/maps?q=Carrer%20de%20Sant%20Antoni%2C%2017252%20Sant%20Antoni%20de%20Calonge%2C%20Girona&t=&z=15&ie=UTF8&iwloc=&output=embed";
  return (
    <section className="visit" id="visit">
      <div className="section-inner">
        <div className="section-head reveal" style={{ textAlign: 'center' }}>
          <span className="eyebrow" style={{ justifyContent: 'center' }}>{t.visit.eyebrow}</span>
          <h2 style={{ marginTop: 14 }}>{t.visit.title}</h2>
        </div>
        <div className="visit-grid">
          <div className="visit-info reveal">
            <dl>
              <div className="row">
                <div className="label">{t.visit.title}</div>
                <div className="value">
                  {t.visit.address}<br/>
                  <span style={{ color: 'rgba(244,237,224,0.65)', fontSize: 14 }}>{t.visit.city || '17252 Sant Antoni de Calonge · Girona'}</span>
                </div>
              </div>
              <div className="row">
                <div className="label">{t.visit.hours}</div>
                <ul className="hours-list">
                  {t.visit.hoursList.map((h, i) => (
                    <li key={i} className={`${i === todayIdx ? 'now' : ''} ${h.closed ? 'closed' : ''}`}>
                      <span className="day">{h.d}</span>
                      <span className="time">{h.h}</span>
                    </li>
                  ))}
                </ul>
              </div>
              <div className="row">
                <div className="label">{t.visit.contact}</div>
                <div className="value">
                  <div><a href={`tel:${t.visit.phone}`}>{t.visit.phoneDisplay || t.visit.phone}</a></div>
                  <div style={{ marginTop: 6 }}><a href={`mailto:${t.visit.email}`}>{t.visit.email}</a></div>
                </div>
              </div>
            </dl>
          </div>
          <div className="map-wrap reveal">
            <iframe src={mapsEmbed} loading="lazy" referrerPolicy="no-referrer-when-downgrade" title="Can Petita map"/>
            <a href={t.visit.mapsUrl || "https://maps.google.com/?q=Can+Petita+Sant+Antoni+de+Calonge"} target="_blank" rel="noopener" className="map-cta">
              {t.visit.directions} →
            </a>
          </div>
        </div>
      </div>
    </section>
  );
}

// ============== Helper: friendly date formatter (i18n aware) ==============
function fmtFriendlyDate(ymd, lang) {
  if (!ymd) return '—';
  try {
    const d = new Date(ymd + 'T00:00:00');
    const localeMap = { ca: 'ca-ES', es: 'es-ES', en: 'en-GB', fr: 'fr-FR', nl: 'nl-NL' };
    return new Intl.DateTimeFormat(localeMap[lang] || 'es-ES', { weekday: 'long', day: 'numeric', month: 'long' }).format(d);
  } catch (_) { return ymd; }
}

// ============== Manage-reservation icons (line-art, brand) ==============
const CP_MANAGE_ICONS = {
  calendar: () => (
    <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <rect x="3" y="4.5" width="18" height="17" rx="2"/>
      <path d="M16 2.5v4M8 2.5v4M3 10h18" opacity="0.85"/>
      <circle cx="12" cy="15" r="1.4" fill="currentColor"/>
    </svg>
  ),
  arrowRight: () => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>
    </svg>
  ),
  close: () => (
    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
    </svg>
  ),
  warning: () => (
    <svg viewBox="0 0 64 64" width="42" height="42" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M32 8L4 56h56z"/>
      <line x1="32" y1="26" x2="32" y2="40"/>
      <circle cx="32" cy="48" r="1.5" fill="currentColor"/>
    </svg>
  ),
  info: () => (
    <svg viewBox="0 0 64 64" width="42" height="42" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="32" cy="32" r="26"/>
      <line x1="32" y1="28" x2="32" y2="46"/>
      <circle cx="32" cy="20" r="1.6" fill="currentColor"/>
    </svg>
  ),
  check: () => (
    <svg viewBox="0 0 64 64" width="44" height="44" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="32" cy="32" r="26"/>
      <path d="M20 32l9 9 16-18"/>
    </svg>
  ),
  search: () => (
    <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="11" cy="11" r="7"/><line x1="20" y1="20" x2="16" y2="16"/>
    </svg>
  ),
  whatsapp: () => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
      <path d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.817 11.817 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.339 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.516 5.26l.241.383-1.005 3.665 3.737-.98z"/>
    </svg>
  )
};

// Persistent floating pill: when the visitor has a future reservation in localStorage,
// show a small chip on every page so they can open the manage modal in one tap.
function ReservationFloater({ t, lang }) {
  const [last, setLast] = useState(() => {
    try {
      const raw = localStorage.getItem('cp_last_reservation');
      const obj = raw ? JSON.parse(raw) : null;
      if (!obj) return null;
      const today = new Date().toISOString().slice(0, 10);
      return obj.date >= today ? obj : null;
    } catch { return null; }
  });
  const [dismissed, setDismissed] = useState(() => {
    try { return sessionStorage.getItem('cp_floater_dismissed') === '1'; } catch { return false; }
  });

  useEffect(() => {
    const refresh = () => {
      try {
        const raw = localStorage.getItem('cp_last_reservation');
        const obj = raw ? JSON.parse(raw) : null;
        const today = new Date().toISOString().slice(0, 10);
        setLast(obj && obj.date >= today ? obj : null);
      } catch { setLast(null); }
    };
    window.addEventListener('storage', refresh);
    window.addEventListener('cp:reservation-updated', refresh);
    return () => {
      window.removeEventListener('storage', refresh);
      window.removeEventListener('cp:reservation-updated', refresh);
    };
  }, []);

  if (!last || dismissed) return null;
  const open = () => window.dispatchEvent(new CustomEvent('cp:open-manage', { detail: { id: last.id } }));
  const dismiss = (e) => {
    e.stopPropagation();
    try { sessionStorage.setItem('cp_floater_dismissed', '1'); } catch (_) {}
    setDismissed(true);
  };
  const Cal = CP_MANAGE_ICONS.calendar;
  const Arrow = CP_MANAGE_ICONS.arrowRight;
  const X = CP_MANAGE_ICONS.close;
  return (
    <div className="res-floater" onClick={open} role="button" tabIndex={0}
         onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }}
         aria-label={t.reserve.floaterLabel || 'Tu reserva'}>
      <span className="res-floater-icon"><Cal/></span>
      <span className="res-floater-text">
        <span className="res-floater-eyebrow">{t.reserve.floaterLabel || 'Tu reserva'}</span>
        <span className="res-floater-info">{fmtFriendlyDate(last.date, lang)} · {last.time}</span>
      </span>
      <span className="res-floater-arrow"><Arrow/></span>
      <button type="button" className="res-floater-close" onClick={dismiss} aria-label="ocultar"><X/></button>
    </div>
  );
}

// ============== Manage Reservation modal (cancel / lookup / reschedule) ==============
function ManageReservation({ t, lang, open, onClose, prefillId }) {
  const [code, setCode] = useState('');
  const [reservation, setReservation] = useState(null);
  const [step, setStep] = useState('lookup'); // lookup, found, alreadyCancelled, justCancelled, confirm
  const [busy, setBusy] = useState(false);
  const [errMsg, setErrMsg] = useState('');

  useEffect(() => {
    if (open && prefillId) { setCode(prefillId); setTimeout(() => doLookup(prefillId), 200); }
    if (!open) { setCode(''); setReservation(null); setStep('lookup'); setErrMsg(''); }
    // ESC handler
    const onKey = (e) => { if (e.key === 'Escape' && open) onClose(); };
    if (open) document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [open, prefillId]);

  const doLookup = async (id) => {
    const clean = (id || code).trim();  // ⚠️ NO toUpperCase — Firestore IDs are case-sensitive
    if (!clean) return;
    setBusy(true); setErrMsg('');
    try {
      const fb = window.CP_FIREBASE;
      const r = fb ? await fb.getReservationById(clean) : null;
      if (!r) {
        setErrMsg(t.reserve.notFound || 'No encontramos ninguna reserva con ese código.');
        setStep('lookup');
      } else {
        setReservation(r);
        setStep(r.status === 'cancelled' ? 'alreadyCancelled' : 'found');
      }
    } catch (e) {
      const msg = (e.message || '').toLowerCase().includes('network')
        ? (t.reserve.networkErr || 'Sin conexión. Revisa tu internet y vuelve a intentar.')
        : 'Error: ' + (e.message || 'algo falló');
      setErrMsg(msg);
    } finally {
      setBusy(false);
    }
  };

  const askCancel = () => setStep('confirm');

  const doCancel = async () => {
    if (!reservation) return;
    setBusy(true); setErrMsg('');
    try {
      await window.CP_FIREBASE.cancelReservationByCustomer(reservation.id);
      setReservation({ ...reservation, status: 'cancelled' });
      setStep('justCancelled');
      // Clear last-reservation pill so "ver mi reserva" doesn't suggest the cancelled one
      try { localStorage.removeItem('cp_last_reservation'); } catch (_) {}
      try { window.dispatchEvent(new CustomEvent('cp:reservation-updated')); } catch (_) {}
    } catch (e) {
      const msg = (e.message || '').toLowerCase().includes('network')
        ? (t.reserve.networkErr || 'Sin conexión. Revisa tu internet y vuelve a intentar.')
        : 'Error: ' + (e.message || 'algo falló');
      setErrMsg(msg);
      setStep('found');
    } finally {
      setBusy(false);
    }
  };

  const whatsappUrl = (action) => {
    if (!reservation) return '#';
    const phone = '+34972077350';
    const dateText = fmtFriendlyDate(reservation.date, lang);
    let msg;
    if (action === 'reschedule') {
      msg = `Hola Paco, soy ${reservation.name}. Necesito cambiar mi reserva del ${dateText} a las ${reservation.time} (${reservation.people} personas). Código: ${reservation.id}`;
    } else {
      msg = `Hola Paco, soy ${reservation.name}. Te escribo por mi reserva del ${dateText} a las ${reservation.time} (${reservation.people} personas). Código: ${reservation.id}`;
    }
    return `https://wa.me/${phone.replace(/\D/g,'')}?text=${encodeURIComponent(msg)}`;
  };

  if (!open) return null;
  return (
    <div className="manage-modal" onClick={(e) => { if (e.target.classList.contains('manage-modal')) onClose(); }} role="dialog" aria-modal="true">
      <div className="manage-card">
        <button className="manage-close" onClick={onClose} aria-label="cerrar">×</button>
        <div className="manage-head">
          <span className="eyebrow">{t.reserve.manageEyebrow || 'Tu reserva'}</span>
          <h2>{t.reserve.manageTitle || 'Gestionar mi reserva'}</h2>
        </div>

        {step === 'lookup' && (
          <div className="manage-body">
            <p className="manage-text">{t.reserve.manageHelp || 'Introduce el código que recibiste al hacer la reserva.'}</p>
            <form onSubmit={(e) => { e.preventDefault(); doLookup(); }} className="manage-form">
              <div className="manage-input-wrap">
                <span className="manage-input-icon">{(() => { const I = CP_MANAGE_ICONS.search; return <I/>; })()}</span>
                <input
                  type="text"
                  value={code}
                  onChange={e => setCode(e.target.value.trim().slice(0, 32))}
                  placeholder={t.reserve.codePlaceholder || 'CÓDIGO DE RESERVA'}
                  autoFocus
                  spellCheck={false}
                  autoComplete="off"
                  autoCapitalize="off"
                  className="manage-input"
                />
              </div>
              <button type="submit" className="btn btn-gold" disabled={busy || code.trim().length < 6}>
                {busy ? '…' : (t.reserve.findRes || 'Buscar')} <span className="arrow">→</span>
              </button>
            </form>
            {errMsg && <div className="manage-error">{errMsg}</div>}
            <a className="manage-fallback" href={`https://wa.me/34972077350?text=${encodeURIComponent('Hola Paco, no encuentro el código de mi reserva. ¿Me ayudas?')}`} target="_blank" rel="noopener">
              {(() => { const W = CP_MANAGE_ICONS.whatsapp; return <W/>; })()}
              <span>{t.reserve.lostCode || '¿Has perdido el código? Escríbenos por WhatsApp'}</span>
            </a>
          </div>
        )}

        {step === 'found' && reservation && (
          <div className="manage-body">
            <div className="res-summary">
              <div className="res-row"><span>{t.reserve.name}</span><strong>{reservation.name}</strong></div>
              <div className="res-row"><span>{t.reserve.date}</span><strong>{fmtFriendlyDate(reservation.date, lang)}</strong></div>
              <div className="res-row"><span>{t.reserve.time}</span><strong>{reservation.time}</strong></div>
              <div className="res-row"><span>{t.reserve.people}</span><strong>{reservation.people}</strong></div>
              {reservation.notes && (<div className="res-row"><span>notas</span><em>{reservation.notes}</em></div>)}
              <div className="res-row"><span>{t.reserve.statusLabel || 'estado'}</span><strong className={`status-pill ${reservation.status || 'pending'}`}>{reservation.status === 'confirmed' ? (t.reserve.statusConfirmed || 'confirmada') : (t.reserve.statusPending || 'recibida · te llamamos')}</strong></div>
            </div>
            <div className="manage-actions-row">
              <a href={whatsappUrl('reschedule')} target="_blank" rel="noopener" className="btn btn-ghost btn-wa">
                <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.817 11.817 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.339 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.516 5.26l.241.383-1.005 3.665 3.737-.98z"/></svg>
                {t.reserve.reschedule || 'Cambiar fecha por WhatsApp'}
              </a>
            </div>
            <div className="manage-actions">
              <button className="btn btn-ghost" onClick={onClose}>{t.reserve.keepRes || 'Mantener reserva'}</button>
              <button className="btn-danger" onClick={askCancel} disabled={busy}>
                {t.reserve.cancelRes || 'Cancelar reserva'}
              </button>
            </div>
            {errMsg && <div className="manage-error">{errMsg}</div>}
          </div>
        )}

        {step === 'confirm' && reservation && (
          <div className="manage-body">
            <div className="manage-confirm">
              <div className="manage-confirm-icon">{(() => { const W = CP_MANAGE_ICONS.warning; return <W/>; })()}</div>
              <h3>{t.reserve.confirmTitle || '¿Cancelar definitivamente?'}</h3>
              <p>{t.reserve.confirmSub || 'Si quieres cambiar el día o la hora, mejor escríbenos por WhatsApp en lugar de cancelar.'}</p>
              <div className="res-summary res-summary-mini">
                <div className="res-row"><span>{t.reserve.name}</span><strong>{reservation.name}</strong></div>
                <div className="res-row"><span>{t.reserve.date}</span><strong>{fmtFriendlyDate(reservation.date, lang)} · {reservation.time}</strong></div>
              </div>
            </div>
            <div className="manage-actions">
              <button className="btn btn-ghost" onClick={() => setStep('found')} disabled={busy}>{t.reserve.no || 'No, mantener'}</button>
              <button className="btn-danger" onClick={doCancel} disabled={busy}>
                {busy ? '…' : (t.reserve.yesCancel || 'Sí, cancelar')}
              </button>
            </div>
            {errMsg && <div className="manage-error">{errMsg}</div>}
          </div>
        )}

        {step === 'justCancelled' && reservation && (
          <div className="manage-body">
            <div className="manage-success">
              <div className="manage-success-icon">{(() => { const C = CP_MANAGE_ICONS.check; return <C/>; })()}</div>
              <h3>{t.reserve.cancelledTitle || 'Reserva cancelada'}</h3>
              <p>{t.reserve.cancelledSub || 'Hemos avisado a Paco. Esperamos verte pronto.'}</p>
            </div>
            <div className="manage-actions" style={{ justifyContent: 'center' }}>
              <button className="btn btn-gold" onClick={onClose}>{t.reserve.close || 'Cerrar'}</button>
            </div>
          </div>
        )}

        {step === 'alreadyCancelled' && reservation && (
          <div className="manage-body">
            <div className="manage-info">
              <div className="manage-info-icon">{(() => { const I = CP_MANAGE_ICONS.info; return <I/>; })()}</div>
              <h3>{t.reserve.alreadyTitle || 'Esta reserva ya estaba cancelada'}</h3>
              <p>{t.reserve.alreadySub || 'Si quieres venir, haz una nueva reserva — Paco te recibe encantado.'}</p>
            </div>
            <div className="manage-actions" style={{ justifyContent: 'center', gap: 10 }}>
              <button className="btn btn-ghost" onClick={onClose}>{t.reserve.close || 'Cerrar'}</button>
              <a href="#reserve" className="btn btn-gold" onClick={onClose}>{t.reserve.newRes || 'Hacer nueva reserva'} →</a>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ============== ICS calendar download (no library) ==============
function downloadICS({ id, name, date, time, people }) {
  const dt = new Date(date + 'T' + time + ':00');
  const end = new Date(dt.getTime() + 90 * 60 * 1000); // 90-minute reservation
  const fmt = (d) => d.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z';
  const ics = [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//Can Petita//Reservation//ES',
    'METHOD:PUBLISH',
    'BEGIN:VEVENT',
    `UID:${id}@canpetitacafe.com`,
    `DTSTAMP:${fmt(new Date())}`,
    `DTSTART:${fmt(dt)}`,
    `DTEND:${fmt(end)}`,
    `SUMMARY:Reserva Can Petita · ${people}p`,
    `DESCRIPTION:Reserva a nombre de ${name}\\n\\nCódigo: ${id}\\n\\nGestionar: https://canpetitacafe.com/?reserva=${id}`,
    'LOCATION:Carrer de Sant Antoni\\, 17252 Sant Antoni de Calonge\\, Girona',
    'BEGIN:VALARM',
    'TRIGGER:-PT2H',
    'ACTION:DISPLAY',
    'DESCRIPTION:Recordatorio reserva Can Petita',
    'END:VALARM',
    'END:VEVENT',
    'END:VCALENDAR'
  ].join('\r\n');
  const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `can-petita-${date}.ics`;
  document.body.appendChild(a); a.click();
  setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 100);
}

// ============== Reserve (Firebase + localStorage fallback) ==============
function Reserve({ t, lang }) {
  const [people, setPeople] = useState(2);
  const [date, setDate] = useState(() => {
    // pick the next OPEN date (skip Tuesdays / any closed day)
    const fn = window.CP_RESERVE?.getAvailableTimeSlots;
    const d = new Date();
    for (let i = 0; i < 8; i++) {
      const y = d.getFullYear(), m = String(d.getMonth()+1).padStart(2,'0'), day = String(d.getDate()).padStart(2,'0');
      const ymd = `${y}-${m}-${day}`;
      if (!fn || (fn(ymd) || []).length > 0) return ymd;
      d.setDate(d.getDate() + 1);
    }
    return d.toISOString().slice(0, 10);
  });
  const [time, setTime] = useState('13:30');
  const [name, setName] = useState('');
  const [phone, setPhone] = useState('');
  const [notes, setNotes] = useState('');
  const [errors, setErrors] = useState({});
  const [status, setStatus] = useState('idle'); // idle, sending, sent, error
  const [resultId, setResultId] = useState(null);
  const [persisted, setPersisted] = useState(null);
  const [manageOpen, setManageOpen] = useState(false);
  const [managePrefill, setManagePrefill] = useState('');
  const [copied, setCopied] = useState(false);
  const [lastReservation, setLastReservation] = useState(() => {
    try {
      const raw = localStorage.getItem('cp_last_reservation');
      return raw ? JSON.parse(raw) : null;
    } catch { return null; }
  });

  // ?reserva=ID URL handler — auto-opens the manage modal
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const r = params.get('reserva') || params.get('reservation');
    if (r) { setManagePrefill(r); setManageOpen(true); }
    const onOpen = (e) => {
      setManagePrefill((e.detail && e.detail.id) || '');
      setManageOpen(true);
    };
    window.addEventListener('cp:open-manage', onOpen);
    return () => window.removeEventListener('cp:open-manage', onOpen);
  }, []);

  // Recompute today inside submit for late-night edge case
  const today = new Date().toISOString().slice(0, 10);

  // Detect if selected date is closed
  const isClosed = useMemo(() => {
    const fn = window.CP_RESERVE?.getAvailableTimeSlots;
    return fn ? (fn(date) || []).length === 0 : false;
  }, [date]);

  // Available time slots
  const slots = useMemo(() => {
    const fn = window.CP_RESERVE?.getAvailableTimeSlots;
    if (!fn) return ['09:00','10:00','11:00','12:00','13:00','13:30','14:00','14:30'];
    return fn(date) || [];
  }, [date]);

  useEffect(() => {
    if (slots.length && !slots.includes(time)) setTime(slots[0]);
  }, [slots]);

  // jump to next open day
  const jumpToNextOpen = () => {
    const fn = window.CP_RESERVE?.getAvailableTimeSlots;
    if (!fn) return;
    const d = new Date(date + 'T00:00:00');
    for (let i = 1; i < 8; i++) {
      d.setDate(d.getDate() + 1);
      const ymd = d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0');
      if ((fn(ymd) || []).length > 0) { setDate(ymd); break; }
    }
  };

  const submit = async (e) => {
    e.preventDefault();
    const payload = { name: name.trim(), phone: phone.trim(), people, date, time, notes: notes.trim(), language: lang };
    const validate = window.CP_RESERVE?.validateReservation;
    const v = validate ? validate(payload) : { ok: name && phone && date && time, errors: {} };
    if (!v.ok) { setErrors(v.errors || {}); return; }
    setErrors({});
    setStatus('sending');
    try {
      const fb = window.CP_FIREBASE;
      let id;
      if (!fb) {
        const arr = JSON.parse(localStorage.getItem('cp_reservations') || '[]');
        id = 'L' + Date.now().toString(36).toUpperCase();
        arr.push({ ...payload, id, createdAt: new Date().toISOString(), status: 'pending', source: 'web' });
        localStorage.setItem('cp_reservations', JSON.stringify(arr));
        setResultId(id); setPersisted('local'); setStatus('sent');
      } else {
        const res = await fb.addReservation({ ...payload, source: 'web' });
        id = res.id;
        setResultId(id); setPersisted(res.persisted); setStatus('sent');
      }
      // Persist last reservation in localStorage so revisits show "Tu reserva"
      try {
        const last = { id, name: payload.name, date: payload.date, time: payload.time, people: payload.people, savedAt: Date.now() };
        localStorage.setItem('cp_last_reservation', JSON.stringify(last));
        setLastReservation(last);
        try { sessionStorage.removeItem('cp_floater_dismissed'); } catch (_) {}
        window.dispatchEvent(new CustomEvent('cp:reservation-updated'));
      } catch (_) {}
      // NO auto-clear — let user dismiss manually so they have time to copy/save the code
    } catch (err) {
      console.error(err);
      setStatus('error');
      setTimeout(() => setStatus('idle'), 6000);
    }
  };

  const copyCode = async () => {
    if (!resultId) return;
    try {
      await navigator.clipboard.writeText(resultId);
      setCopied(true);
      setTimeout(() => setCopied(false), 2200);
    } catch (_) {
      // Fallback: select the code element so user can long-press
      const el = document.querySelector('.code-pill');
      if (el && window.getSelection) {
        const range = document.createRange();
        range.selectNode(el);
        const sel = window.getSelection();
        sel.removeAllRanges(); sel.addRange(range);
      }
    }
  };

  const newReservation = () => {
    setStatus('idle');
    setName(''); setPhone(''); setNotes('');
    setResultId(null);
  };

  const whatsappConfirmUrl = useMemo(() => {
    if (!resultId) return '#';
    const dateText = fmtFriendlyDate(date, lang);
    const msg = `Hola Paco! Acabo de reservar mesa: ${name || ''} · ${dateText} · ${time} · ${people}p · Código ${resultId}`;
    return `https://wa.me/34972077350?text=${encodeURIComponent(msg)}`;
  }, [resultId, date, time, people, name, lang]);

  const reservationLink = useMemo(() => {
    if (!resultId) return '';
    const origin = (typeof window !== 'undefined' && window.location && window.location.origin) || '';
    return `${origin}/?reserva=${encodeURIComponent(resultId)}`;
  }, [resultId]);

  const [linkShared, setLinkShared] = useState('');
  const shareReservationLink = async () => {
    if (!reservationLink) return;
    const dateText = fmtFriendlyDate(date, lang);
    const text = `Mi reserva en Can Petita · ${dateText} · ${time} · ${people}p`;
    try {
      if (navigator.share) {
        await navigator.share({ title: 'Mi reserva — Can Petita', text, url: reservationLink });
        setLinkShared('shared');
      } else {
        await navigator.clipboard.writeText(reservationLink);
        setLinkShared('copied');
      }
    } catch (_) {
      try { await navigator.clipboard.writeText(reservationLink); setLinkShared('copied'); } catch (__) {}
    }
    setTimeout(() => setLinkShared(''), 2500);
  };
  const whatsappSelfUrl = useMemo(() => {
    if (!reservationLink) return '#';
    const dateText = fmtFriendlyDate(date, lang);
    const msg = `Mi reserva en Can Petita · ${dateText} · ${time} · ${people}p\n${reservationLink}`;
    return `https://wa.me/?text=${encodeURIComponent(msg)}`;
  }, [reservationLink, date, time, people, lang]);

  const peopleSliderStyle = { '--rng': `${((people - 1) / 11) * 100}%` };

  return (
    <section className="reserve" id="reserve">
      <div className="section-inner">
        <div className="reserve-card reveal">
          <div className="section-head">
            <span className="eyebrow">{t.reserve.eyebrow}</span>
            <h2 style={{ marginTop: 14 }}><span className="gold">{t.reserve.title}</span></h2>
            <p className="sub">{t.reserve.sub}</p>
          </div>

          {/* Returning visitor: pill with last reservation */}
          {lastReservation && status !== 'sent' && (
            <div className="last-res-pill" onClick={() => { setManagePrefill(lastReservation.id); setManageOpen(true); }}>
              <div className="last-res-icon">{(() => { const C = CP_MANAGE_ICONS.calendar; return <C/>; })()}</div>
              <div className="last-res-text">
                <div className="last-res-eyebrow">{t.reserve.lastResLabel || 'Tu última reserva'}</div>
                <div className="last-res-info">{lastReservation.name} · {fmtFriendlyDate(lastReservation.date, lang)} · {lastReservation.time}</div>
              </div>
              <div className="last-res-arrow">{(() => { const A = CP_MANAGE_ICONS.arrowRight; return <A/>; })()}</div>
            </div>
          )}

          {/* Closed-day banner */}
          {isClosed && status !== 'sent' && (
            <div className="closed-banner">
              <span>{t.reserve.closedBanner || 'Cerramos los martes — prueba otro día.'}</span>
              <button type="button" onClick={jumpToNextOpen} className="btn-link-gold">{t.reserve.jumpNext || 'Saltar al siguiente día abierto →'}</button>
            </div>
          )}

          {status !== 'sent' && (
          <form onSubmit={submit} className="form-grid" noValidate>
            <div className="field">
              <label>{t.reserve.name}</label>
              <input type="text" required value={name} onChange={e => setName(e.target.value)} placeholder={t.reserve.namePh || 'María García'} className={errors.name ? 'invalid' : ''} autoComplete="name"/>
              {errors.name && <div className="err">{errors.name}</div>}
            </div>
            <div className="field">
              <label>{t.reserve.phone}</label>
              <input type="tel" required value={phone} onChange={e => setPhone(e.target.value)} placeholder="+34 612 34 56 78" className={errors.phone ? 'invalid' : ''} autoComplete="tel"/>
              {errors.phone && <div className="err">{errors.phone}</div>}
            </div>
            <div className="field">
              <label>{t.reserve.date}</label>
              <input type="date" required value={date} onChange={e => setDate(e.target.value)} min={today} className={errors.date ? 'invalid' : ''}/>
              {errors.date && <div className="err">{errors.date}</div>}
            </div>
            <div className="field">
              <label>{t.reserve.time}</label>
              <select value={time} onChange={e => setTime(e.target.value)} className={errors.time ? 'invalid' : ''} disabled={slots.length === 0}>
                {slots.length === 0
                  ? <option>—</option>
                  : slots.map(h => <option key={h} value={h}>{h}</option>)}
              </select>
            </div>
            <div className="field wide">
              <label>{t.reserve.people}: {people} {people === 1 ? t.reserve.person : t.reserve.people_pl}{people >= 8 ? ' · grupo grande' : ''}</label>
              <input type="range" min="1" max="12" value={people} onChange={e => setPeople(+e.target.value)} style={peopleSliderStyle}/>
              {people >= 8 && (
                <div className="big-group-note">
                  {t.reserve.bigGroup || 'Para grupos grandes, llámanos al 972 07 73 50 para asegurar mesa.'}
                </div>
              )}
            </div>
            <div className="field wide">
              <label>{t.reserve.notes}</label>
              <textarea rows="3" value={notes} onChange={e => setNotes(e.target.value)} placeholder={t.reserve.notesPh || 'Mesa interior, terraza, cumpleaños, alergias…'}/>
            </div>
            <div className="form-submit wide">
              <button type="submit" className="btn btn-gold" disabled={status === 'sending' || slots.length === 0}>
                {status === 'sending' ? (t.reserve.sending || '…') : t.reserve.submit} <span className="arrow">→</span>
              </button>
            </div>
            {status === 'error' && (
              <div className="form-error wide">{t.reserve.error}</div>
            )}
            <div className="manage-link wide">
              <button type="button" className="manage-link-btn" onClick={() => { setManagePrefill(''); setManageOpen(true); }}>
                {t.reserve.manageLink || '¿ya tienes reserva? gestiónala con tu código'}
              </button>
            </div>
          </form>
          )}

          {/* Premium success card */}
          {status === 'sent' && (
            <div className="success-card">
              <div className="success-tick">
                <svg viewBox="0 0 64 64" width="56" height="56" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                  <circle cx="32" cy="32" r="28"/>
                  <path d="M20 32l9 9 16-18"/>
                </svg>
              </div>
              <h3 className="success-title">{t.reserve.sentTitle || '¡Mesa apuntada!'}</h3>
              <p className="success-sub">{t.reserve.sentDescription || 'Paco te llamará pronto para confirmarla.'}</p>

              <div className="success-meta">
                <span><strong>{name}</strong></span>
                <span>·</span>
                <span>{fmtFriendlyDate(date, lang)}</span>
                <span>·</span>
                <span>{time}</span>
                <span>·</span>
                <span>{people}{people === 1 ? ` ${t.reserve.person}` : ` ${t.reserve.people_pl}`}</span>
              </div>

              {resultId && (
                <div className="code-block">
                  <div className="code-label">{t.reserve.codeLabel || 'Guarda este código si necesitas cancelar o gestionar tu reserva'}</div>
                  <button type="button" className="code-pill" onClick={copyCode} title={t.reserve.copyCode || 'Copiar código'}>
                    <span>{resultId}</span>
                    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                      <rect x="9" y="9" width="13" height="13" rx="2"/>
                      <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
                    </svg>
                  </button>
                  {copied && <div className="code-copied">✓ {t.reserve.copiedMsg || 'copiado al portapapeles'}</div>}
                </div>
              )}

              {resultId && (
                <div className="save-link-block">
                  <div className="save-link-eyebrow">{t.reserve.saveLinkEyebrow || 'Guarda este enlace en tu móvil'}</div>
                  <div className="save-link-help">{t.reserve.saveLinkHelp || 'Te servirá para cambiar o cancelar tu reserva desde cualquier dispositivo, sin necesidad de recordar el código.'}</div>
                  <div className="save-link-actions">
                    <button type="button" className="save-link-btn primary" onClick={shareReservationLink}>
                      <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                        <circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
                        <line x1="8.6" y1="10.5" x2="15.4" y2="6.5"/><line x1="8.6" y1="13.5" x2="15.4" y2="17.5"/>
                      </svg>
                      <span>{linkShared === 'copied' ? (t.reserve.linkCopied || '✓ copiado') : linkShared === 'shared' ? (t.reserve.linkSharedMsg || '✓ enviado') : (t.reserve.shareLink || 'Compartir / guardar enlace')}</span>
                    </button>
                    <a href={whatsappSelfUrl} target="_blank" rel="noopener" className="save-link-btn">
                      <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
                        <path d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.817 11.817 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.339 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.516 5.26l.241.383-1.005 3.665 3.737-.98z"/>
                      </svg>
                      <span>{t.reserve.sendToMyself || 'Enviármelo por WhatsApp'}</span>
                    </a>
                  </div>
                  <div className="save-link-url" title={reservationLink}>{reservationLink}</div>
                </div>
              )}

              <div className="success-actions">
                <a href={whatsappConfirmUrl} target="_blank" rel="noopener" className="btn btn-gold success-btn">
                  <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.817 11.817 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.339 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.516 5.26l.241.383-1.005 3.665 3.737-.98z"/></svg>
                  {t.reserve.confirmByWA || 'Confirmar por WhatsApp'}
                </a>
                <button type="button" className="btn btn-ghost success-btn" onClick={() => downloadICS({ id: resultId, name, date, time, people })}>
                  <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
                  {t.reserve.addCalendar || 'Añadir al calendario'}
                </button>
              </div>

              <div className="success-secondary">
                <button type="button" className="manage-link-btn" onClick={newReservation}>
                  {t.reserve.newRes || 'Hacer otra reserva'}
                </button>
                <span className="success-sep">·</span>
                <button type="button" className="manage-link-btn" onClick={() => { setManagePrefill(resultId); setManageOpen(true); }}>
                  {t.reserve.manageLink || 'gestionar mi reserva'}
                </button>
              </div>

              {persisted === 'local' && (
                <div className="success-warn">
                  Guardada localmente · sin conexión con Firebase
                </div>
              )}
            </div>
          )}
        </div>
      </div>
      <ManageReservation t={t} lang={lang} open={manageOpen} onClose={() => setManageOpen(false)} prefillId={managePrefill}/>
    </section>
  );
}

// ============== Footer ==============
function Footer({ t }) {
  return (
    <footer>
      <div className="footer-script">{t.footer.tag}</div>
      <div className="ornament"><span className="glyph">✦</span></div>
      <div className="footer-socials">
        <a href="https://www.instagram.com/canpetita" target="_blank" rel="noopener" aria-label="Instagram">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="0.8" fill="currentColor"/></svg>
        </a>
        <a href={t.visit?.mapsUrl || "https://maps.google.com/?q=Can+Petita+Sant+Antoni+de+Calonge"} target="_blank" rel="noopener" aria-label="Maps">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M12 21s7-7 7-12a7 7 0 1 0-14 0c0 5 7 12 7 12z"/><circle cx="12" cy="9" r="2.5"/></svg>
        </a>
        <a href={`tel:${t.visit?.phone || '+34972077350'}`} aria-label="Phone">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M5 4h4l2 5-3 2a12 12 0 0 0 5 5l2-3 5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z"/></svg>
        </a>
      </div>
      <div className="footer-rights">{t.footer.rights}</div>
      <div className="footer-meta">
        {t.footer.legal && <a href="#">{t.footer.legal}</a>}
        {t.footer.cookies && <a href="#">{t.footer.cookies}</a>}
      </div>
    </footer>
  );
}

Object.assign(window, {
  Logo, Cursor, Nav, Hero, Story, BreakfastMenu, LunchMenu, Gallery, Reviews, Visit, Reserve, ReservationFloater, Footer
});
