/* ============ RAVO KAFE — main app ============ */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- Tiny icons ---------- */
const Icon = {
  Search: () =>
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></svg>,

  Bag: () =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 7h12l-1 13H7L6 7z" /><path d="M9 7V5a3 3 0 0 1 6 0v2" /></svg>,

  User: () =>
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 4-6 8-6s8 2 8 6" /></svg>,

  ArrowRight: () =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14" /><path d="m13 5 7 7-7 7" /></svg>,

  ArrowLeft: () =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5" /><path d="m11 5-7 7 7 7" /></svg>,

  Plus: () =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14" /></svg>,

  Close: () =>
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg>,

  Leaf: () =>
  <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M17 4c0 8-4 13-12 16 2-8 6-13 12-16Z" /></svg>

};

/* ---------- Bean SVG ornament ---------- */
function BeanGlyph({ size = 60, fill = "currentColor" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 60 60" fill="none">
      <ellipse cx="30" cy="30" rx="22" ry="14" transform="rotate(-25 30 30)" fill={fill} />
      <path d="M14 38 C 22 28, 38 32, 46 22" stroke={fill === 'currentColor' ? 'var(--paper)' : 'var(--sage)'} strokeWidth="2.2" fill="none" strokeLinecap="round" />
    </svg>);

}

/* ---------- Wordmark (real SVG logo) ---------- */
function Wordmark({ variant = "dark", height = 56, style }) {
  const src = variant === "light" ? "assets/ravo-kafe-ravo-logo-light.svg" : "assets/ravo-kafe-ravo-logo-dark.svg";
  return (
    <img
      src={src}
      alt="Ravo Kafe"
      style={{ height, width: "auto", display: "inline-block", ...style }} />);

}

/* ============================================================ */
/* TWEAKABLE DEFAULTS                                            */
/* ============================================================ */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "forest",
  "heroAuto": true,
  "showTicker": true,
  "showPress": true,
  "subscriptionMode": false
} /*EDITMODE-END*/;

const PALETTES = {
  forest: { "--forest": "#1B3A26", "--forest-2": "#244D33", "--moss": "#2D5A3C", "--sage": "#DDE1BE", "--sage-2": "#C9D0A4", "--cream": "#F2EEDF", "--paper": "#FAF8F1", "--coffee": "#6B4332", "--ember": "#C97A48" },
  ember: { "--forest": "#3A1F12", "--forest-2": "#4D2C1B", "--moss": "#5C3522", "--sage": "#EFD9B8", "--sage-2": "#E2BE8E", "--cream": "#F4ECD8", "--paper": "#FAF5E8", "--coffee": "#8B4A2C", "--ember": "#C97A48" },
  midnight: { "--forest": "#16202B", "--forest-2": "#222F3D", "--moss": "#2C3D4F", "--sage": "#D6DBE1", "--sage-2": "#B7BFC9", "--cream": "#ECEEF1", "--paper": "#F6F7F9", "--coffee": "#735A3F", "--ember": "#C97A48" }
};

/* ---------- Data ---------- */
const BEANS = [
{ id: "ethi", name: "Yirgacheffe", origin: "Éthiopie", roast: 2, price: 18, notes: ["Bergamote", "Jasmin", "Miel"], tag: "Nouveauté", subtitle: "Lavé · Altitude 1900m", image: "assets/ravo-kafe-bean-ethi.webp", heroImage: "assets/ravo-kafe-hero-ethi.webp", tone: "#B26233", lot: "024 / 250", score: "88.0", featured: true, blurb: "Récolté à la main sur les hauts plateaux éthiopiens. Une tasse florale, lumineuse, presque théïe — le grain qu'on offre pour faire découvrir le café spécialité." },
{ id: "colo", name: "La Esperanza", origin: "Colombie", roast: 3, price: 16, notes: ["Cacao", "Caramel", "Noisette"], tag: "Best-seller", subtitle: "Honey · Huila", image: "assets/ravo-kafe-bean-colo.webp", heroImage: "assets/ravo-kafe-hero-colo.webp", tone: "#8F5A2A", lot: "025 / 400", score: "86.5" },
{ id: "guat", name: "Antigua Pacaya", origin: "Guatemala", roast: 3, price: 17, notes: ["Chocolat noir", "Cerise", "Épices"], tag: "Édition limitée", subtitle: "Lavé · 1650m", image: "assets/ravo-kafe-bean-guat.webp", heroImage: "assets/ravo-kafe-hero-guat.webp", tone: "#6E2D2A", lot: "027 / 180", score: "87.0" },
{ id: "kenya", name: "Nyeri AA", origin: "Kenya", roast: 2, price: 19, notes: ["Cassis", "Tomate", "Sucre brun"], tag: "Single origin", subtitle: "Lavé · SL28/SL34", image: "assets/ravo-kafe-bean-kenya.webp", heroImage: "assets/ravo-kafe-hero-kenya.webp", tone: "#6A4B6C", lot: "026 / 220", score: "87.5" }];


const STEPS = {
  espresso: [
  { t: "00:00", h: "Mouture fine", d: "18g de café fraîchement moulu, tamper appliqué d'un geste régulier." },
  { t: "00:08", h: "Pré-infusion", d: "Laisser l'eau saturer le palet pendant 8 secondes." },
  { t: "00:25", h: "Extraction", d: "Viser 36g en tasse pour un ratio 1:2 équilibré et soyeux." },
  { t: "00:40", h: "Dégustation", d: "Servir immédiatement, laisser respirer 30 secondes." }],

  v60: [
  { t: "00:00", h: "Bloom", d: "30g d'eau à 94°C sur 15g de mouture moyenne, attendre 45s." },
  { t: "00:45", h: "Premier versement", d: "Verser jusqu'à 120g en spirales lentes du centre vers les bords." },
  { t: "01:30", h: "Second versement", d: "Compléter jusqu'à 250g en gardant un débit constant." },
  { t: "02:45", h: "Drawdown", d: "Le lit doit être plat. Servir et déguster sans attendre." }],

  coldbrew: [
  { t: "00:00", h: "Préparation", d: "80g de mouture grossière dans 1L d'eau filtrée froide." },
  { t: "08:00", h: "Infusion", d: "Au réfrigérateur, 8h minimum, 16h pour plus de corps." },
  { t: "16:00", h: "Filtration", d: "Filtre papier ou Chemex pour une tasse limpide." },
  { t: "—", h: "Conservation", d: "Se garde 7 jours en bouteille fermée." }]

};

const CAFES = [
{ city: "Paris 11e", name: "Atelier Saint-Maur", addr: "84 rue Saint-Maur", hours: "07:30 → 19:00", open: true, image: "assets/ravo-kafe-cafe-saint-maur.webp" },
{ city: "Paris 3e", name: "Maison Bretagne", addr: "12 rue de Bretagne", hours: "08:00 → 18:00", open: true, image: "assets/ravo-kafe-cafe-bretagne.webp" },
{ city: "Lyon 1er", name: "Comptoir des Terreaux", addr: "5 place des Terreaux", hours: "08:00 → 19:00", open: false, image: "assets/ravo-kafe-cafe-comptoir.webp" }];


/* ============================================================ */
/* APP                                                           */
/* ============================================================ */
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [cart, setCart] = useState([]);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [toast, setToast] = useState(null);
  const [activeBrew, setActiveBrew] = useState("espresso");
  const toastTimer = useRef(null);

  // Apply palette
  useEffect(() => {
    const p = PALETTES[t.palette] || PALETTES.forest;
    Object.entries(p).forEach(([k, v]) => document.documentElement.style.setProperty(k, v));
  }, [t.palette]);

  const cartCount = cart.reduce((a, c) => a + c.qty, 0);
  const cartTotal = cart.reduce((a, c) => a + c.qty * c.price, 0);

  function addBean(bean) {
    setCart((prev) => {
      const i = prev.findIndex((p) => p.id === bean.id);
      if (i >= 0) {
        const next = [...prev];
        next[i] = { ...next[i], qty: next[i].qty + 1 };
        return next;
      }
      return [...prev, { id: bean.id, name: bean.name, origin: bean.origin, price: bean.price, qty: 1 }];
    });
    showToast(`${bean.name} ajouté au panier`);
  }
  function updateQty(id, delta) {
    setCart((prev) => prev.flatMap((p) => {
      if (p.id !== id) return [p];
      const q = p.qty + delta;
      return q <= 0 ? [] : [{ ...p, qty: q }];
    }));
  }
  function showToast(msg) {
    setToast(msg);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2400);
  }

  return (
    <div className="shell">
      {t.showTicker && <TickerBar />}
      <Nav cartCount={cartCount} onCart={() => setDrawerOpen(true)} />
      <Hero autoRotate={t.heroAuto} />
      <Shop onAdd={addBean} />
      <Manifesto />
      <Brew active={activeBrew} setActive={setActiveBrew} />
      <Cafes />
      {t.showPress && <Press />}
      <Footer subscription={t.subscriptionMode} />

      <CartDrawer
        open={drawerOpen}
        onClose={() => setDrawerOpen(false)}
        items={cart}
        total={cartTotal}
        updateQty={updateQty} />
      
      <div className={`toast ${toast ? 'show' : ''}`}>
        <span className="bean-dot">✓</span>
        <span>{toast}</span>
      </div>

      <TweaksUI t={t} setTweak={setTweak} />
    </div>);

}

/* ---------- Sections ---------- */
function TickerBar() {
  const items = ["Livraison offerte dès 35€", "Torréfié à Pantin chaque mardi", "Café d'origine, traçable du grain à la tasse", "Abonnement —15% sans engagement", "✦ Nouveau lot Kenya Nyeri AA"];
  const doubled = [...items, ...items];
  return (
    <div className="tickerbar">
      <div className="tickerbar__track">
        {doubled.map((it, i) => <span key={i} className="tickerbar__item">{it}</span>)}
      </div>
    </div>);

}

function Nav({ cartCount, onCart }) {
  return (
    <header className="nav">
      <div className="wrap nav__inner">
        <nav className="nav__links">
          <a href="#shop" className="nav__link">La boutique</a>
          <a href="#manifesto" className="nav__link">Le manifeste</a>
          <a href="#brew" className="nav__link">Méthodes</a>
          <a href="#cafes" className="nav__link">Cafés</a>
        </nav>
        <a href="#" className="nav__logo"><Wordmark variant="dark" height={42} /></a>
        <div className="nav__right">
          <button className="nav__icon" aria-label="Recherche"><Icon.Search /></button>
          <button className="nav__icon" aria-label="Compte"><Icon.User /></button>
          <button className="nav__cart" onClick={onCart}>
            <Icon.Bag />
            <span>Panier</span>
            <span className="nav__cart__count">{cartCount}</span>
          </button>
        </div>
      </div>
    </header>);

}

function Hero({ autoRotate }) {
  const [idx, setIdx] = useState(0);
  const [progress, setProgress] = useState(0);
  const [manualClick, setManualClick] = useState(false);
  const ROTATE_MS = 6500;

  useEffect(() => {
    if (!autoRotate || manualClick) { setProgress(0); return; }
    setProgress(0);
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const p = Math.min(1, (now - start) / ROTATE_MS);
      setProgress(p);
      if (p < 1) raf = requestAnimationFrame(tick);
      else setIdx((i) => (i + 1) % BEANS.length);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [idx, autoRotate, manualClick]);

  const handleDotClick = (i) => {
    setIdx(i);
    setManualClick(true);
    setTimeout(() => setManualClick(false), 500);
  };

  const bean = BEANS[idx];

  return (
    <section className="hero">
      {/* Stack of background images cross-fading */}
      <div className="hero__stage">
        {BEANS.map((b, i) =>
        <div
          key={b.id}
          className={`hero__layer ${i === idx ? 'is-active' : ''}`}
          style={{ backgroundImage: `url(${b.heroImage})` }}
          aria-hidden={i !== idx} />
        )}
        <div className="hero__veil"></div>
        <div className="hero__grain"></div>
      </div>

      <div className="wrap hero__content">
        <div className="hero__lhs">
          <div className="hero__kicker">
            <span className="hero__kicker__dot"><Icon.Leaf /></span>
            <span className="eyebrow">Lot {bean.lot} · Récolte 2026</span>
          </div>

          <div className="hero__origin">
            <span className="hero__origin__pin">●</span>
            <span>{bean.origin.toUpperCase()} · {bean.subtitle}</span>
          </div>

          <h1 className="display hero__title">
            <span className="hero__title__line hero__title__line--small">Single origin —</span>
            <span className="hero__title__big">{bean.name}</span>
          </h1>

          <p className="hero__sub">
            Café d'origine cultivé en altitude, torréfié en petite série à Pantin et livré frais sous huit jours. Notes de <em>{bean.notes[0].toLowerCase()}</em>, <em>{bean.notes[1].toLowerCase()}</em> et <em>{bean.notes[2].toLowerCase()}</em>.
          </p>

          <div className="hero__cta">
            <a href="#shop" className="btn btn--primary">Commander · {bean.price}€ <Icon.ArrowRight /></a>
            <a href="#brew" className="btn btn--ghost-light">Notre méthode</a>
          </div>

          <div className="hero__stats">
            <div className="hero__stat">
              <div className="hero__stat__lbl">Score SCA</div>
              <div className="hero__stat__val">{bean.score}</div>
            </div>
            <div className="hero__stat">
              <div className="hero__stat__lbl">Torréfaction</div>
              <div className="hero__stat__val">
                <span className="hero__stat__dots">
                  {[1, 2, 3, 4].map((n) => <i key={n} className={n <= bean.roast ? 'on' : ''}></i>)}
                </span>
              </div>
            </div>
            <div className="hero__stat">
              <div className="hero__stat__lbl">Format</div>
              <div className="hero__stat__val">250 g</div>
            </div>
          </div>
        </div>

        {/* Right column intentionally empty — image holds the subject */}
        <div className="hero__rhs-spacer" aria-hidden="true"></div>
      </div>

      {/* Carousel rail at bottom */}
      <div className="hero__rail">
        <div className="wrap hero__rail__inner">
          <div className="hero__rail__lbl">
            <span className="eyebrow">Édition 026</span>
            <span className="hero__rail__count">{String(idx + 1).padStart(2, '0')} / {String(BEANS.length).padStart(2, '0')}</span>
          </div>
          <div className="hero__rail__dots" role="tablist">
            {BEANS.map((b, i) =>
            <button
              key={b.id}
              className={`hero__dot ${i === idx ? 'is-active' : ''}`}
              onClick={() => handleDotClick(i)}
              role="tab"
              aria-selected={i === idx}>
                <span className="hero__dot__n">{String(i + 1).padStart(2, '0')}</span>
                <span className="hero__dot__name">{b.name}</span>
                <span className="hero__dot__origin">{b.origin}</span>
                {i === idx && autoRotate && !manualClick &&
              <span className="hero__dot__bar" style={{ transform: `scaleX(${progress})` }} />
              }
              </button>
            )}
          </div>
        </div>
      </div>
    </section>);

}

function Shop({ onAdd }) {
  const featured = BEANS.find((b) => b.featured);
  const others = BEANS.filter((b) => !b.featured);
  return (
    <section className="section shop" id="shop">
      <div className="wrap">
        <div className="sec-head">
          <div>
            <div className="eyebrow">La boutique · Édition 026</div>
            <h2 className="display sec-head__title">Quatre grains,<br />quatre histoires.</h2>
          </div>
          <div className="sec-head__nav">
            <a href="#" className="btn btn--ghost">Tout voir <Icon.ArrowRight /></a>
          </div>
        </div>

        {featured &&
        <article
          className="featured"
          style={{ "--tone": featured.tone }}
          onClick={() => onAdd(featured)}>
          
            <div className="featured__media">
              <img src={featured.image} alt={featured.name} />
              <span className="featured__badge">{featured.tag}</span>
            </div>
            <div className="featured__body">
              <div className="featured__meta">
                <span className="label">{featured.origin}</span>
                <span className="label">{featured.subtitle}</span>
              </div>
              <h3 className="display featured__name">{featured.name}</h3>
              <p className="featured__blurb">{featured.blurb}</p>
              <div className="featured__notes">
                <span className="eyebrow">Notes de dégustation</span>
                <div className="featured__chips">
                  {featured.notes.map((n) => <span key={n} className="chip">{n}</span>)}
                </div>
              </div>
              <div className="featured__roast">
                <span className="label">Torréfaction</span>
                <RoastBar level={featured.roast} />
              </div>
              <div className="featured__foot">
                <div>
                  <div className="label">250 g · grains entiers</div>
                  <div className="featured__price">{featured.price}€</div>
                </div>
                <button className="btn btn--primary" onClick={(e) => {e.stopPropagation();onAdd(featured);}}>
                  Ajouter au panier <Icon.Plus />
                </button>
              </div>
            </div>
          </article>
        }

        <div className="beans">
          {others.map((b) => <Bean key={b.id} bean={b} onAdd={() => onAdd(b)} />)}
        </div>
      </div>
    </section>);

}

function RoastBar({ level }) {
  return (
    <div className="roast">
      {[1, 2, 3, 4].map((i) =>
      <span key={i} className={`roast__seg ${i <= level ? 'on' : ''}`} />
      )}
      <span className="roast__lbl">{["", "Doux", "Médium", "Corpsé", "Intense"][level]}</span>
    </div>);

}

function Bean({ bean, onAdd }) {
  return (
    <article className="bean" style={{ "--tone": bean.tone }} onClick={onAdd}>
      <div className="bean__media">
        <img src={bean.image} alt={bean.name} />
        <span className="bean__badge">{bean.tag}</span>
        <button className="bean__quick" aria-label="Ajouter au panier" onClick={(e) => {e.stopPropagation();onAdd();}}>
          <Icon.Plus />
        </button>
      </div>
      <div className="bean__body">
        <div className="bean__row">
          <div className="bean__origin">{bean.origin}</div>
          <div className="bean__price">{bean.price}€</div>
        </div>
        <h3 className="bean__name">{bean.name}</h3>
        <div className="bean__sub">{bean.subtitle}</div>
        <div className="bean__notes">
          {bean.notes.map((n) => <span key={n}>{n}</span>)}
        </div>
        <RoastBar level={bean.roast} />
      </div>
    </article>);

}

function Manifesto() {
  return (
    <section className="section manifesto" id="manifesto">
      <div className="wrap manifesto__grid">
        <div>
          <div className="eyebrow" style={{ color: 'var(--sage-2)' }}>Le manifeste</div>
          <h2 className="display manifesto__title">Du grain<br />à la tasse,<br />sans détour.</h2>
          <p className="manifesto__body">
            Nous travaillons avec onze producteurs, sur quatre continents, que nous visitons chaque année. Pas d'intermédiaires : chaque sac de Ravo est tracé, signé, daté. La torréfaction est lente, par lots de douze kilos, dans notre atelier de Pantin — pour révéler ce que le terroir a déjà fait de mieux.
          </p>
          <div className="hero__cta">
            <a href="#" className="btn btn--light">Lire l'histoire <Icon.ArrowRight /></a>
          </div>
          <div className="manifesto__stats">
            <div>
              <div className="manifesto__stat__num">11</div>
              <div className="manifesto__stat__lbl">Producteurs<br />partenaires</div>
            </div>
            <div>
              <div className="manifesto__stat__num">87+</div>
              <div className="manifesto__stat__lbl">Score SCA<br />minimum</div>
            </div>
            <div>
              <div className="manifesto__stat__num">12kg</div>
              <div className="manifesto__stat__lbl">Lots de<br />torréfaction</div>
            </div>
          </div>
        </div>
        <div className="manifesto__visual">
          <img src="assets/ravo-kafe-manifesto-journey.webp" alt="Du grain à la tasse — cultiver, récolter, torréfier, déguster" style={{ width: "100%", height: "auto", display: "block" }} />
        </div>
      </div>
    </section>);

}

function Brew({ active, setActive }) {
  const tabs = [
  { id: "espresso", label: "Espresso" },
  { id: "v60", label: "V60" },
  { id: "coldbrew", label: "Cold brew" }];

  const specs = {
    espresso: [["Dose", "18 g"], ["Eau", "94 °C"], ["Temps", "25 s"]],
    v60: [["Dose", "15 g"], ["Eau", "94 °C"], ["Temps", "2:45"]],
    coldbrew: [["Dose", "80 g/L"], ["Eau", "Froide"], ["Temps", "8 h"]]
  };
  return (
    <section className="section brew" id="brew">
      <div className="wrap">
        <div className="sec-head">
          <div>
            <div className="eyebrow">Méthodes · Journal de préparation</div>
            <h2 className="display sec-head__title">Comment<br />infuser Ravo.</h2>
          </div>
        </div>
        <div className="brew__tabs">
          {tabs.map((tab) =>
          <button key={tab.id} className={`brew__tab ${active === tab.id ? 'is-active' : ''}`} onClick={() => setActive(tab.id)}>
              {tab.label}
            </button>
          )}
        </div>
        <div className="brew__grid">
          <div className="brew__lhs">
            <h3 className="display brew__h">{tabs.find((x) => x.id === active).label}</h3>
            <p className="brew__lede">
              {active === "espresso" && "Le geste précis du barista. Une extraction courte qui concentre les arômes pour une tasse dense et soyeuse."}
              {active === "v60" && "Le rituel du matin. L'eau prend son temps, révèle les notes florales et la complexité du grain."}
              {active === "coldbrew" && "L'infusion longue à froid. Faible acidité, sucrosité naturelle, parfait pour les longues journées d'été."}
            </p>
            <div className="brew__specs">
              {specs[active].map(([l, v]) =>
              <div className="brew__spec" key={l}>
                  <div className="brew__spec__lbl">{l}</div>
                  <div className="brew__spec__val">{v}</div>
                </div>
              )}
            </div>
          </div>
          <div className="brew__steps">
            {STEPS[active].map((s, i) =>
            <div className="brew__step" key={i}>
                <div className="brew__step__n">{String(i + 1).padStart(2, '0')}</div>
                <div>
                  <h4 className="brew__step__title">{s.h}</h4>
                  <p className="brew__step__desc">{s.d}</p>
                </div>
                <div className="brew__step__time">{s.t}</div>
              </div>
            )}
          </div>
        </div>
      </div>
    </section>);

}

function Cafes() {
  return (
    <section className="section cafes" id="cafes">
      <div className="wrap">
        <div className="sec-head">
          <div>
            <div className="eyebrow">Cafés · Adresses</div>
            <h2 className="display sec-head__title">Nous trouver,<br />tasse en main.</h2>
          </div>
          <a href="#" className="btn btn--ghost">Toutes les adresses <Icon.ArrowRight /></a>
        </div>
        <div className="cafe-grid">
          {CAFES.map((c) =>
          <article key={c.name} className="cafe">
              <div className="cafe__media" style={{ fontWeight: "400", lineHeight: "0.5", fontSize: "6px", width: "410px" }}>
                <img src={c.image} alt={c.name} className="cafe__media__img" />
                <div className="cafe__media__tag">{c.city}</div>
              </div>
              <div className="cafe__body">
                <div className="cafe__city">Boutique-atelier</div>
                <h3 className="cafe__name">{c.name}</h3>
                <p className="cafe__addr">{c.addr}<br />{c.city}, France</p>
                <div className="cafe__hours">
                  <span><span className="dot" style={{ background: c.open ? '#4CAF50' : '#C97A48' }}></span>{c.open ? "Ouvert" : "Fermé"}</span>
                  <strong>{c.hours}</strong>
                </div>
              </div>
            </article>
          )}
        </div>
      </div>
    </section>);

}

function Press() {
  return (
    <section className="press">
      <div className="wrap press__row">
        <span className="press__lbl">Ils en parlent</span>
        <a href="#" className="press__name">Le Monde</a>
        <a href="#" className="press__name">L'Express</a>
        <a href="#" className="press__name">Konbini Food</a>
        <a href="#" className="press__name">Telerama</a>
        <a href="#" className="press__name">Frenchy Coffee</a>
      </div>
    </section>);

}

function Footer({ subscription }) {
  const [email, setEmail] = useState("");
  const [sent, setSent] = useState(false);
  function submit(e) {
    e.preventDefault();
    if (!email) return;
    setSent(true);
    setEmail("");
    setTimeout(() => setSent(false), 3000);
  }
  return (
    <footer className="footer">
      <div className="wrap footer__inner">
        <div className="footer__top">
          <div>
            <div className="eyebrow" style={{ color: 'var(--sage-2)' }}>
              {subscription ? "L'abonnement Ravo" : "Le carnet"}
            </div>
            <h2 className="display footer__h">
              {subscription ? "Un café par mois,\nlivré chez vous." : "Recevez le grain\navant les autres."}
            </h2>
            <p className="footer__lede">
              {subscription ?
              "250g chaque mois, sélectionnés selon votre profil, livrés frais sous huit jours de torréfaction. Sans engagement." :
              "Une lettre mensuelle pour suivre les nouveaux lots, les méthodes et la vie de l'atelier."}
            </p>
          </div>
          <form className="footer__form" onSubmit={submit}>
            <input
              type="email"
              placeholder={sent ? "Merci ! 🌱" : "votre@email.com"}
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              disabled={sent}
              required />
            
            <button type="submit">{subscription ? "S'abonner" : "M'inscrire"}</button>
          </form>
        </div>
        <div className="footer__cols">
          <div className="footer__col footer__brand">
            <Wordmark variant="light" height={90} />
            <p style={{ marginTop: 18 }}>Café d'origine, torréfié à la main, à Pantin. Depuis 2021.</p>
          </div>
          <div className="footer__col">
            <h5>Boutique</h5>
            <ul>
              <li><a href="#">Grains</a></li>
              <li><a href="#">Abonnement</a></li>
              <li><a href="#">Cartes cadeaux</a></li>
              <li><a href="#">Accessoires</a></li>
            </ul>
          </div>
          <div className="footer__col">
            <h5>Maison</h5>
            <ul>
              <li><a href="#">L'atelier</a></li>
              <li><a href="#">Producteurs</a></li>
              <li><a href="#">Le journal</a></li>
              <li><a href="#">Recrutement</a></li>
            </ul>
          </div>
          <div className="footer__col">
            <h5>Aide</h5>
            <ul>
              <li><a href="#">Livraison</a></li>
              <li><a href="#">Retours</a></li>
              <li><a href="#">Contact</a></li>
              <li><a href="#">Mentions légales</a></li>
            </ul>
          </div>
        </div>
        <div className="footer__bottom">
          <span>© 2026 Ravo Kafe · Tous droits réservés</span>
          <span>Pantin · Paris · Lyon</span>
        </div>
      </div>
    </footer>);

}

/* ---------- Drawer ---------- */
function CartDrawer({ open, onClose, items, total, updateQty }) {
  return (
    <>
      <div className={`drawer-bg ${open ? 'open' : ''}`} onClick={onClose}></div>
      <aside className={`drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
        <div className="drawer__head">
          <h3 className="drawer__title">Panier · {items.reduce((a, c) => a + c.qty, 0)}</h3>
          <button className="drawer__close" onClick={onClose}><Icon.Close /></button>
        </div>
        <div className="drawer__body">
          {items.length === 0 ?
          <div className="drawer__empty">
              <div className="drawer__empty__bean">
                <BeanGlyph size={64} fill="var(--sage-2)" />
              </div>
              <p>Votre panier est vide.<br />Commencez par un grain.</p>
            </div> :
          items.map((it) =>
          <div className="drawer__item" key={it.id}>
              <div className="drawer__item__media">
                <Wordmark variant="dark" style={{ width: "80%", height: "auto" }} />
              </div>
              <div>
                <h4 className="drawer__item__name">{it.name}</h4>
                <div className="drawer__item__meta">{it.origin} · 250g</div>
                <div className="drawer__qty">
                  <button onClick={() => updateQty(it.id, -1)}>−</button>
                  <span>{it.qty}</span>
                  <button onClick={() => updateQty(it.id, +1)}>+</button>
                </div>
              </div>
              <div className="drawer__item__price">{(it.price * it.qty).toFixed(0)}€</div>
            </div>
          )}
        </div>
        {items.length > 0 &&
        <div className="drawer__foot">
            <div className="drawer__total">
              <span>Total</span>
              <span>{total.toFixed(0)}€</span>
            </div>
            <a href="#" className="btn btn--primary">Passer commande <Icon.ArrowRight /></a>
            <div className="drawer__note">Livraison offerte dès 35€</div>
          </div>
        }
      </aside>
    </>);

}

/* ---------- Tweaks panel ---------- */
function TweaksUI({ t, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Palette">
        <TweakColor
          label="Direction"
          value={t.palette}
          onChange={(v) => setTweak('palette', v)}
          options={[
          ['#1B3A26', '#DDE1BE', '#F2EEDF'],
          ['#3A1F12', '#EFD9B8', '#F4ECD8'],
          ['#16202B', '#D6DBE1', '#ECEEF1']].
          map((p, i) => ({ value: ['forest', 'ember', 'midnight'][i], color: p }))} />
        
        <TweakRadio
          label=""
          value={t.palette}
          onChange={(v) => setTweak('palette', v)}
          options={[
          { value: 'forest', label: 'Forêt' },
          { value: 'ember', label: 'Braise' },
          { value: 'midnight', label: 'Minuit' }]
          } />
        
      </TweakSection>
      <TweakSection title="Contenu">
        <TweakToggle label="Carousel auto" value={t.heroAuto} onChange={(v) => setTweak('heroAuto', v)} />
        <TweakToggle label="Bandeau défilant" value={t.showTicker} onChange={(v) => setTweak('showTicker', v)} />
        <TweakToggle label="Strip presse" value={t.showPress} onChange={(v) => setTweak('showPress', v)} />
        <TweakToggle label="Mode abonnement (footer)" value={t.subscriptionMode} onChange={(v) => setTweak('subscriptionMode', v)} />
      </TweakSection>
    </TweaksPanel>);

}

/* TweakColor doesn't natively support options-as-objects in starter — fallback wrapper */
function TweakColor({ label, value, onChange, options }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {label && <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', textTransform: 'uppercase', letterSpacing: '0.12em', color: '#666' }}>{label}</div>}
      <div style={{ display: 'flex', gap: 8 }}>
        {options.map((opt) =>
        <button
          key={opt.value}
          onClick={() => onChange(opt.value)}
          style={{
            flex: 1, height: 48, borderRadius: 10, border: value === opt.value ? '2px solid #111' : '1px solid #ddd',
            padding: 0, cursor: 'pointer', overflow: 'hidden', display: 'flex'
          }}>
          
            {opt.color.map((c, i) =>
          <span key={i} style={{ flex: i === 0 ? 2 : 1, background: c }} />
          )}
          </button>
        )}
      </div>
    </div>);

}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);