/* pierre · Orbita — consumer-first landing, notturna.
   Signature: il pallino viola orbita lungo l'anello bianco, legato allo scroll.
   Vanilla React + Babel. Nessun localStorage. */

const { useState, useEffect, useRef, useCallback } = React;
const Ic = window.PRIcons;

/* ---------- palette presets (per i Tweak) ---------- */
const PALETTES = {
  // [violet, magenta, glow, bg]
  'viola·magenta': { violet: '#A65CFF', magenta: '#E45BC8', glow: '#C24DE8', bg: '#09060e', panel: '#160f26' },
  'indaco':        { violet: '#8257FF', magenta: '#7C5CFF', glow: '#8257FF', bg: '#0E0A1F', panel: '#16112E' },
  'ciano·viola':   { violet: '#7C5CFF', magenta: '#36C8E0', glow: '#5A8BFF', bg: '#070912', panel: '#101626' },
};

/* ---------- sezioni (l'ordine guida l'orbita) ---------- */
const SECTIONS = [
  { id: 'hero',     label: 'intro' },
  { id: 'problema', label: 'problema' },
  { id: 'tour',     label: '360°' },
  { id: 'tavolo',   label: 'tavolo' },
  { id: 'split',    label: 'conto' },
  { id: 'qr',       label: 'accesso' },
  { id: 'locali',   label: 'locali' },
  { id: 'finale',   label: 'serata' },
];

/* ====================================================================== */
/*  Wordmark — "pierre" minuscolo, puntino viola orbitante sulla i        */
/* ====================================================================== */
function Wordmark({ size = 25 }) {
  return (
    <span className="wordmark" style={{ fontSize: size }} aria-label="pierre">
      p<span className="i-wrap">ı<span className="i-dot" /></span>erre
    </span>
  );
}

/* ====================================================================== */
/*  Badges store (solo App Store, come richiesto)                          */
/* ====================================================================== */
function StoreBadges({ large }) {
  return (
    <div className="badges">
      <a className={'badge' + (large ? ' lg' : '')} href="#" aria-label="Scarica su App Store">
        <Ic.Apple size={large ? 26 : 23} />
        <span><span className="b-top">Scarica su</span><span className="b-main">App Store</span></span>
      </a>
    </div>
  );
}

/* ====================================================================== */
/*  Orbit — anello + pallino che orbita legato allo scroll                 */
/* ====================================================================== */
function Orbit({ reduced, onJump, accent }) {
  const orbitRef = useRef(null);
  const dotArmRef = useRef(null);
  const trailRef = useRef(null);
  const markersRef = useRef([]);
  const stateRef = useRef({ angle: 0, target: 0, smoothY: 0, raf: 0 });
  const heroRectRef = useRef(null);
  const [activeIdx, setActiveIdx] = useState(0);

  const N = SECTIONS.length;
  const STEP = 360 / (N - 1); // S0=0° … S_last=360°

  // Easing helpers — smoothstep aggiunge un lieve magnetismo sui marker;
  // easeInOutCubic per il dock dà un movimento più "signorile".
  const smoothstep = (t) => t * t * (3 - 2 * t);
  const easeInOutCubic = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);

  // Rettangolo d'ancoraggio dell'anello nell'hero: lo calcoliamo dal placeholder
  // .ring-reserve in flow (così il cerchio è sempre centrato nel suo spazio,
  // senza sovrapposizioni con il titolo).
  const computeHeroRect = useCallback(() => {
    const r = document.getElementById('ring-reserve');
    if (!r) return;
    const rr = r.getBoundingClientRect();
    const absTop = rr.top + window.scrollY;
    const size = Math.min(rr.width, rr.height) * 0.96;
    heroRectRef.current = {
      size,
      cx: rr.left + rr.width / 2,
      cy: absTop + rr.height / 2,
    };
  }, []);

  // posizioni di scroll d'ancoraggio per ogni sezione (centro sezione → centro viewport)
  const anchorsRef = useRef([]);
  const computeAnchors = useCallback(() => {
    const vh = window.innerHeight;
    const max = Math.max(1, document.documentElement.scrollHeight - vh);
    anchorsRef.current = SECTIONS.map((s, i) => {
      const el = document.getElementById(s.id);
      if (!el) return (i / (N - 1)) * max;
      const r = el.getBoundingClientRect();
      const centerY = r.top + window.scrollY + r.height / 2;
      if (i === 0) return 0;                       // hero ancorato a 0
      if (i === N - 1) return max;                 // finale chiude il giro
      return Math.min(max, Math.max(0, centerY - vh / 2));
    });
  }, [N]);

  // scroll → angolo (mappatura a tratti = tappe angolari UNIFORMI)
  // Dentro ogni segmento applichiamo un lieve smoothstep: il pallino "si assesta"
  // dolcemente attorno a ciascun marker (magnetismo soft, non a scatti).
  const angleFromScroll = useCallback((y) => {
    const a = anchorsRef.current;
    if (a.length < 2) return 0;
    if (y <= a[0]) return 0;
    if (y >= a[a.length - 1]) return 360;
    for (let i = 0; i < a.length - 1; i++) {
      if (y >= a[i] && y <= a[i + 1]) {
        const span = Math.max(1, a[i + 1] - a[i]);
        const f = (y - a[i]) / span;
        // Mix 70% lineare + 30% smoothstep: mantiene il legame con lo scroll
        // ma sussurra un magnetismo verso gli ancoraggi.
        const eased = f * 0.7 + smoothstep(f) * 0.3;
        return (i + eased) * STEP;
      }
    }
    return 360;
  }, [STEP]);

  const activeFromScroll = useCallback((y) => {
    const a = anchorsRef.current;
    let best = 0, bd = Infinity;
    for (let i = 0; i < a.length; i++) {
      const d = Math.abs(y - a[i]);
      if (d < bd) { bd = d; best = i; }
    }
    return best;
  }, []);

  // geometria dell'anello: grande+centrato sul .ring-reserve dell'hero,
  // → piccolo+ancorato in alto a sinistra man mano che si scrolla.
  const applyGeometry = useCallback((dock) => {
    const el = orbitRef.current;
    if (!el) return;
    const vw = window.innerWidth, vh = window.innerHeight;
    const hero = heroRectRef.current || {
      size: Math.min(vw * 0.7, vh * 0.5, 420),
      cx: vw / 2, cy: vh * 0.32,
    };
    const dockSize = vw < 640 ? 84 : 116;
    const ease = easeInOutCubic(dock); // dock con easing cubico (più morbido)
    const size = hero.size + (dockSize - hero.size) * ease;
    // hero in coords viewport: hero.cy è in coords documento → sottraggo scrollY.
    // Lo facciamo qui ogni frame: durante il dock l'anello si stacca dall'hero
    // e migra verso l'angolo, indipendentemente da dove sei nella pagina.
    const heroL = hero.cx - size / 2;
    const heroT = hero.cy - size / 2 - window.scrollY;
    const dockL = vw < 640 ? 14 : 22;
    const dockT = vw < 640 ? 80 : 90;
    const left = heroL + (dockL - heroL) * ease;
    const top = heroT + (dockT - heroT) * ease;
    el.style.width = size + 'px';
    el.style.height = size + 'px';
    el.style.transform = `translate3d(${left}px, ${top}px, 0)`;
    el.style.setProperty('--r', (size / 2) + 'px');

    // Trail (SVG): stroke-dashoffset proporzionale all'angolo per disegnare la scia.
    const tr = trailRef.current;
    if (tr) {
      const C = 2 * Math.PI * 50; // r=50 nel viewBox 100×100
      const angle = stateRef.current.angle;
      tr.style.strokeDasharray = String(C);
      tr.style.strokeDashoffset = String(C * (1 - Math.min(1, Math.max(0, angle / 360))));
      // più visibile da docked, appena percettibile nell'hero
      tr.style.opacity = String(0.18 + 0.55 * ease);
    }

    // markers via trigonometria (label sempre orizzontale)
    const r = size / 2, c = size / 2;
    markersRef.current.forEach((m, i) => {
      if (!m) return;
      const th = (i * STEP) * Math.PI / 180;
      m.style.left = (c + r * Math.sin(th)) + 'px';
      m.style.top = (c - r * Math.cos(th)) + 'px';
      m.style.opacity = String(ease); // visibili solo da docked
      m.style.pointerEvents = ease > 0.6 ? 'auto' : 'none';
    });
  }, [STEP]);

  // loop rAF: input scroll lerpato + angolo lerpato → orbita di seta.
  useEffect(() => {
    computeHeroRect();
    computeAnchors();

    // un input smoothato di scrollY: assorbe i "ticks" della rotellina,
    // così la rotazione del pianeta non è mai a scatti, è continua.
    stateRef.current.smoothY = window.scrollY;

    const dockProg = (y) => {
      return Math.min(1, Math.max(0, y / (window.innerHeight * 0.6)));
    };

    // render(): unico punto che disegna.
    const render = () => {
      const st = stateRef.current;
      const rawY = window.scrollY;
      // lerp dello scrollY → input morbido per l'orbita
      if (reduced) {
        st.smoothY = rawY;
      } else {
        st.smoothY += (rawY - st.smoothY) * 0.22;
        if (Math.abs(rawY - st.smoothY) < 0.4) st.smoothY = rawY;
      }
      st.target = angleFromScroll(st.smoothY);

      if (reduced) {
        st.angle = st.target; // niente rotazione continua: salto secco
      } else {
        const d = st.target - st.angle;
        st.angle += d * 0.18; // lerp easato
        if (Math.abs(d) < 0.04) st.angle = st.target;
      }
      if (dotArmRef.current) dotArmRef.current.style.transform = `rotate(${st.angle}deg)`;
      applyGeometry(reduced ? (rawY > 40 ? 1 : 0) : dockProg(rawY));
    };

    const onScroll = () => {
      const y = window.scrollY;
      // active section sull'input "grezzo" (reattivo)
      const ai = activeFromScroll(y);
      setActiveIdx((p) => (p === ai ? p : ai));
      render(); // aggiornamento immediato, indipendente dal rAF
    };

    const onResize = () => { computeHeroRect(); computeAnchors(); onScroll(); };

    let alive = true;
    const tick = () => {
      if (!alive) return;
      render();
      stateRef.current.raf = requestAnimationFrame(tick);
    };

    onScroll();
    tick();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onResize);
    // dopo il primo paint i font possono spostare le sezioni: ricalcolo.
    const t1 = setTimeout(() => { computeHeroRect(); computeAnchors(); onScroll(); }, 250);
    const t2 = setTimeout(() => { computeHeroRect(); computeAnchors(); onScroll(); }, 1200);
    return () => {
      alive = false;
      cancelAnimationFrame(stateRef.current.raf);
      clearTimeout(t1); clearTimeout(t2);
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onResize);
    };
  }, [reduced, computeHeroRect, computeAnchors, angleFromScroll, activeFromScroll, applyGeometry]);

  return (
    <div className="orbit" ref={orbitRef} role="navigation" aria-label="Indicatore di avanzamento">
      <div className="orbit-ring" />
      {/* Scia: traccia il giro del pianeta col progredire dello scroll */}
      <svg className="orbit-trail" viewBox="0 0 100 100" aria-hidden="true">
        <circle ref={trailRef} cx="50" cy="50" r="50" fill="none"
          stroke="url(#orbitGrad)" strokeWidth="1.6" strokeLinecap="round"
          pathLength="undefined" transform="rotate(-90 50 50)" />
        <defs>
          <linearGradient id="orbitGrad" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stopColor="var(--violet)" stopOpacity="0" />
            <stop offset="60%" stopColor="var(--violet)" stopOpacity="0.85" />
            <stop offset="100%" stopColor="var(--magenta)" stopOpacity="1" />
          </linearGradient>
        </defs>
      </svg>
      {SECTIONS.map((s, i) => (
        <button
          key={s.id}
          ref={(n) => (markersRef.current[i] = n)}
          className={'mk' + (i === activeIdx ? ' active' : '')}
          data-label={s.label}
          aria-label={`Vai a ${s.label}`}
          onClick={() => onJump(s.id)}
        />
      ))}
      <div className="dot-arm" ref={dotArmRef}>
        <div className="orbit-dot" />
      </div>
    </div>
  );
}

/* ====================================================================== */
/*  Reveal on scroll                                                       */
/* ====================================================================== */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    if (!('IntersectionObserver' in window)) {
      els.forEach((e) => e.classList.add('in')); return;
    }
    const io = new IntersectionObserver((ents) => {
      ents.forEach((e) => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
    }, { threshold: 0.16, rootMargin: '0px 0px -8% 0px' });
    els.forEach((e) => io.observe(e));
    return () => io.disconnect();
  }, []);
}

/* lieve parallax sull'immagine del tour */
function useParallax(ref, strength = 26) {
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    let raf = 0;
    const upd = () => {
      const r = el.getBoundingClientRect();
      const prog = (r.top + r.height / 2 - window.innerHeight / 2) / window.innerHeight;
      el.style.transform = `translateY(${(-prog * strength).toFixed(1)}px) scale(1.06)`;
      raf = 0;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(upd); };
    upd();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, [ref, strength]);
}

/* tilt elegantissimo legato allo scroll: i mockup si "presentano" e si
   ritirano con un sottile flotta verticale. Niente layout thrash: solo transform. */
function useTilt(ref, drift = 12) {
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    let raf = 0;
    const upd = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const prog = (r.top + r.height / 2 - vh / 2) / vh; // -0.5…0.5 quando è in viewport
      const t = Math.max(-1, Math.min(1, prog));
      el.style.transform = `translate3d(0, ${(-t * drift).toFixed(1)}px, 0) rotateX(${(t * 1.4).toFixed(2)}deg)`;
      raf = 0;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(upd); };
    upd();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, [ref, drift]);
}

/* ====================================================================== */
/*  Sezioni di contenuto                                                   */
/* ====================================================================== */
const PAINS = [
  { ic: 'NoChat', t: 'Messaggi ovunque', d: 'DM su Instagram, gruppi WhatsApp, screenshot. La prenotazione si perde tra mille chat.' },
  { ic: 'Tag',    t: 'Prezzi che cambiano', d: 'Il preventivo a voce non torna mai con quello che paghi davvero all’arrivo.' },
  { ic: 'Sparkle',t: 'Dipendi dal PR “amico”', d: 'Senza il contatto giusto resti fuori, o paghi di più. Tutto informale, niente garanzie.' },
  { ic: 'Wallet', t: 'Code e pagamenti lenti', d: 'File all’ingresso, contanti da raccogliere tra amici, serata che parte storta.' },
];

function Hero({ onCta }) {
  return (
    <section id="hero" className="hero" data-screen-label="Hero">
      <div id="ring-reserve" className="ring-reserve" aria-hidden="true" />
      <div className="reveal in">
        <h1>Immergiti nella serata<br />prima di <span className="grad-text">viverla</span>.</h1>
        <p className="lede">Esplora il locale in 360°, scegli il tuo tavolo, dividi il conto con un link.
          Tutto dall’app — zero messaggi, zero code.</p>
        <div className="hero-actions">
          <StoreBadges />
        </div>
        <div className="hero-trust">La nightlife, finalmente digitale.</div>
      </div>
    </section>
  );
}

function Problema() {
  return (
    <section id="problema" className="sec">
      <div className="wrap">
        <div className="sec-head reveal">
          <span className="eyebrow"><span className="dot" />Il problema</span>
          <h2>Prenotare un tavolo<br />oggi è un caos.</h2>
          <p className="lede">Tra chat sparse e accordi informali, organizzare una serata è più stress che divertimento.</p>
        </div>
        <div className="pain-grid">
          {PAINS.map((p, i) => {
            const I = Ic[p.ic];
            return (
              <div className="pain reveal" key={i} style={{ transitionDelay: (i * 70) + 'ms' }}>
                <div className="p-ic"><I size={22} /></div>
                <div>
                  <h3>{p.t}</h3>
                  <p>{p.d}</p>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

function Tour() {
  const phoneRef = useRef(null);
  useTilt(phoneRef, 16);
  return (
    <section id="tour" className="sec tour">
      <div className="wrap">
        <div className="tour-head reveal">
          <span className="eyebrow"><span className="dot" />Tour immersivo · sezione clou</span>
          <h2>Vedi il locale<br />prima di entrarci.</h2>
          <p className="lede">Naviga gli interni in 360°, esplora ogni area e scegli con consapevolezza
            dove sederti — con la disponibilità aggiornata in tempo reale.</p>
        </div>
        <div className="tour-stage reveal">
          {/* Anelli ruotanti sullo sfondo — richiamano l'orbita signature */}
          <div className="tour-orbit tour-orbit-1" aria-hidden="true" />
          <div className="tour-orbit tour-orbit-2" aria-hidden="true" />
          <div className="tour-orbit tour-orbit-3" aria-hidden="true" />
          <span className="tour-tag"><span className="live" />Disponibilità live</span>
          <div className="phone phone-lg" ref={phoneRef}>
            <div className="phone-screen"><img src="assets/orbit-360.jpg" alt="Tour 360° dell’interno del locale" /></div>
            <span className="tour-pill">
              <span className="swipe"><i /><i /><i /></span>
              Trascina · 360°
            </span>
          </div>
        </div>
      </div>
    </section>
  );
}

/* feature row riutilizzabile (telefono + copy) */
function FeatureRow({ id, flip, eyebrow, title, lede, points, img, alt }) {
  const phoneRef = useRef(null);
  useTilt(phoneRef, 10);
  return (
    <section id={id} className="sec">
      <div className="wrap">
        <div className={'frow' + (flip ? ' flip' : '')}>
          <div className="frow-media reveal">
            <div className="phone" ref={phoneRef}>
              <div className="phone-screen"><img src={img} alt={alt} /></div>
            </div>
          </div>
          <div className="frow-copy reveal">
            <span className="eyebrow"><span className="dot" />{eyebrow}</span>
            <h2>{title}</h2>
            <p className="lede">{lede}</p>
            <ul className="frow-points">
              {points.map((p, i) => (
                <li key={i}><span className="tick"><Ic.Bolt size={13} /></span><span>{p}</span></li>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </section>
  );
}

/* B2B — per i locali */
const B2B_FEATS = [
  { ic: 'Pin',      t: 'Gestione tavoli live', d: 'Mappa visiva del locale, stato di ogni tavolo in tempo reale.' },
  { ic: 'Calendar', t: 'Prenotazioni centralizzate', d: 'Da app o inserite a mano: un’unica vista per tutto lo staff.' },
  { ic: 'Qr',       t: 'Check-in QR', d: 'Validazione istantanea all’ingresso, senza attriti.' },
  { ic: 'Sparkle',  t: 'Gestione PR', d: 'Un pannello per ogni promoter, con visibilità totale.' },
  { ic: 'Eye',      t: 'Database clienti', d: 'Storico ospiti, preferenze e no-show sempre a portata.' },
  { ic: 'Gauge',    t: 'Analytics & report', d: 'Riempimento, conversioni e revenue per ogni serata.' },
];

function Locali({ onDemo }) {
  return (
    <section id="locali" className="sec b2b">
      <div className="wrap">
        <div className="b2b-card reveal">
          <div className="b2b-top">
            <div>
              <span className="b2b-badge"><Ic.Shield size={14} />Per i locali</span>
              <h2>Hai un locale? pierre è<br />anche il tuo gestionale.</h2>
              <p className="lede">Dietro l’app c’è <b style={{ color: 'var(--text)' }}>pierre Dashboard</b>:
                il sistema centralizzato che sostituisce Excel, WhatsApp e la gestione informale dei PR.</p>
              <div className="b2b-actions">
                <a className="btn btn-outline" href="per-i-locali.html">Richiedi una demo <Ic.ArrowRight size={17} /></a>
              </div>
            </div>
            <div className="dash-win reveal">
              <div className="dash-bar">
                <div className="dots"><i /><i /><i /></div>
                <span className="url">dashboard.pierre.app</span>
              </div>
              <img src="assets/orbit-dashboard.png" alt="pierre Dashboard — gestionale per locali" />
            </div>
          </div>
          <div className="b2b-feats">
            {B2B_FEATS.map((f, i) => {
              const FI = Ic[f.ic];
              return (
                <div className="b2b-feat reveal" key={i} style={{ transitionDelay: (i % 3 * 60) + 'ms' }}>
                  <div className="f-ic"><FI size={19} /></div>
                  <h3>{f.t}</h3>
                  <p>{f.d}</p>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </section>
  );
}

function Finale() {
  return (
    <section id="finale" className="final">
      <div className="wrap">
        <div className="reveal">
          <h2>Pronto per la<br />prossima <span className="grad-text">serata</span>?</h2>
          <p className="lede">Il cerchio si chiude dove è cominciato. Scarica pierre e immergiti nella serata prima di viverla.</p>
          <StoreBadges large />
        </div>
      </div>
    </section>
  );
}

function Footer({ onDemo }) {
  return (
    <footer>
      <div className="wrap foot-inner">
        <div>
          <Wordmark size={26} />
          <div className="foot-claim">Immergiti nella serata prima di viverla.</div>
        </div>
        <nav className="foot-links" aria-label="Footer">
          <a href="https://instagram.com/pierre" target="_blank" rel="noopener noreferrer">Instagram</a>
          <a href="mailto:info@pierreclubs.it">Contatti</a>
          <a href="privacy-policy.html">Privacy</a>
          <a href="termini-e-condizioni.html">Termini</a>
          <a href="per-i-locali.html">Sei un locale? Contattaci</a>
        </nav>
      </div>
      <div className="wrap"><div className="foot-copy">© {new Date().getFullYear()} pierre — la nightlife, finalmente digitale.</div></div>
    </footer>
  );
}

/* ====================================================================== */
/*  App                                                                    */
/* ====================================================================== */
function App() {
  useReveal();
  const [scrolled, setScrolled] = useState(false);
  const reduced = typeof window !== 'undefined'
    && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  const [t, setTweak] = useTweaks({
    palette: 'indaco',
    font: 'Schibsted Grotesk',
    glow: 1,
    grain: true,
  });

  // applica i Tweak alle CSS vars
  useEffect(() => {
    const p = PALETTES[t.palette] || PALETTES['viola·magenta'];
    const root = document.documentElement.style;
    root.setProperty('--violet', p.violet);
    root.setProperty('--magenta', p.magenta);
    root.setProperty('--grad-a', p.violet);
    root.setProperty('--grad-b', p.magenta);
    root.setProperty('--glow', p.glow);
    root.setProperty('--bg', p.bg);
    root.setProperty('--panel-2', p.panel);
    root.setProperty('--glow-k', String(t.glow));
    root.setProperty('--font-display', `'${t.font}', system-ui, sans-serif`);
    root.setProperty('--font-body', `'${t.font}', system-ui, sans-serif`);
    document.body.classList.toggle('no-grain', !t.grain);
    document.body.style.background = p.bg;
  }, [t]);

  // carica il font scelto via Tweak
  useEffect(() => {
    const fam = t.font.replace(/ /g, '+');
    const id = 'twk-font';
    let l = document.getElementById(id);
    if (!l) { l = document.createElement('link'); l.id = id; l.rel = 'stylesheet'; document.head.appendChild(l); }
    l.href = `https://fonts.googleapis.com/css2?family=${fam}:wght@400;500;600;700;800;900&display=swap`;
  }, [t.font]);

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 16);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  const jump = useCallback((id) => {
    const el = document.getElementById(id);
    if (!el) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    el.scrollIntoView ? null : null; // (evitiamo scrollIntoView)
    const y = id === 'hero' ? 0 : el.getBoundingClientRect().top + window.scrollY - 70;
    window.scrollTo({ top: y, behavior: reduce ? 'auto' : 'smooth' });
  }, []);

  const demo = useCallback(() => jump('locali'), [jump]);

  return (
    <>
      <Orbit reduced={reduced} onJump={jump} />

      <nav className={scrolled ? 'scrolled' : ''}>
        <div className="wrap nav-inner">
          <a href="#hero" onClick={(e) => { e.preventDefault(); jump('hero'); }}><Wordmark /></a>
          <div className="nav-links">
            <a href="#tour" onClick={(e) => { e.preventDefault(); jump('tour'); }}>Tour 360°</a>
            <a href="#split" onClick={(e) => { e.preventDefault(); jump('split'); }}>Dividi il conto</a>
            <a href="#locali" onClick={(e) => { e.preventDefault(); jump('locali'); }}>Per i locali</a>
          </div>
          <div className="nav-cta">
            <button className="btn btn-primary" onClick={() => jump('finale')}>Scarica l’app</button>
          </div>
        </div>
      </nav>

      <main>
        <Hero />
        <Problema />
        <Tour />
        <FeatureRow
          id="tavolo"
          eyebrow="Scegli e blocca"
          title="Il tavolo giusto, bloccato in un tap."
          lede="Vedi cosa è davvero libero, scegli la posizione e blocca il tavolo prima che lo faccia qualcun altro."
          points={[
            <span><b>Disponibilità live</b>, sempre aggiornata.</span>,
            <span>Blocco del tavolo per <b>24 ore</b>.</span>,
            <span>Nessuna ambiguità sul prezzo, mai.</span>,
          ]}
          img="assets/orbit-tavolo.jpg"
          alt="Selezione del tavolo nell'app pierre"
        />
        <FeatureRow
          id="split"
          flip
          eyebrow="Pagamento di gruppo"
          title="Un link. Il conto diviso da solo."
          lede="Condividi il link, gli amici si uniscono e ognuno mette la sua parte. Senza inseguire nessuno."
          points={[
            <span>Addebito solo <b>2 ore prima</b> dell’evento.</span>,
            <span>Gruppo modificabile <b>fino all’ultimo</b>.</span>,
            <span>Ognuno paga la propria quota, in app.</span>,
          ]}
          img="assets/orbit-split.jpg"
          alt="Divisione del conto con link nell'app pierre"
        />
        <FeatureRow
          id="qr"
          eyebrow="Accesso fluido"
          title="Salta la coda. Entra con un QR."
          lede="Check-in istantaneo all’ingresso: niente contanti, niente liste cartacee, niente attese."
          points={[
            <span>Un <b>QR personale</b> per ogni prenotazione.</span>,
            <span>Validazione <b>istantanea</b> all’ingresso.</span>,
            <span>Niente contanti, niente attese.</span>,
          ]}
          img="assets/orbit-qr.jpg"
          alt="Accesso con QR nell'app pierre"
        />
        <Locali onDemo={demo} />
        <Finale />
      </main>

      <Footer onDemo={demo} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Atmosfera" />
        <TweakColor
          label="Palette"
          value={t.palette}
          options={Object.keys(PALETTES).map((k) => {
            const p = PALETTES[k];
            return [p.violet, p.magenta, p.bg];
          })}
          onChange={(arr) => {
            const key = Object.keys(PALETTES).find((k) => PALETTES[k].violet === arr[0]) || 'viola·magenta';
            setTweak('palette', key);
          }}
        />
        <TweakSlider label="Intensità glow" value={t.glow} min={0} max={1.6} step={0.1}
          onChange={(v) => setTweak('glow', v)} />
        <TweakToggle label="Grain" value={t.grain} onChange={(v) => setTweak('grain', v)} />
        <TweakSection label="Tipografia" />
        <TweakRadio label="Carattere" value={t.font}
          options={['Schibsted Grotesk', 'Space Grotesk', 'Manrope']}
          onChange={(v) => setTweak('font', v)} />
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
