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

// ============================================================
//  Le 1821 — Refonte
//  - Single React app, hash-routed
//  - 2 directions esthétiques pilotées via Tweaks (data-theme)
//  - Prototype cliquable complet (navigation + formulaire + lightbox)
// ============================================================

// ============================================================
// Données dynamiques — chargées depuis data/*.json
// (édition via le back-office /admin/, sans toucher au code)
// ============================================================
const GALLERY_FALLBACK = [
  { id: "g0", src: "assets/gite/entree.jpg", alt: "Façade en pierre du gîte Le 1821 avec terrasse", cap: "Façade en pierre · 1821", layout: "c-hero" },
];

function useJSON(path, fallback) {
  const [data, setData] = useState(fallback);
  useEffect(() => {
    let alive = true;
    fetch(path, { cache: "no-store" })
      .then(r => r.ok ? r.json() : Promise.reject(r.status))
      .then(j => { if (alive) setData(j); })
      .catch(() => {});
    return () => { alive = false; };
  }, [path]);
  return data;
}

const FEATURES = [
  { title: "4 personnes",     desc: "1 chambre lit double + mezzanine avec lit double",  ico: "users" },
  { title: "Accès piscine",   desc: "Saison juin → sept., non chauffée, horaires sur place", ico: "pool" },
  { title: "Cuisine équipée", desc: "Lave-vaisselle, four, plaque induction, frigo",    ico: "kitchen" },
  { title: "Borne électrique",desc: "Recharge véhicule type 2, 7 kW",            ico: "ev" },
  { title: "Wifi fibre",      desc: "Connexion stable, télétravail possible",    ico: "wifi" },
  { title: "Animaux",desc: "Sur demande",       ico: "paw" },
];

// Endpoint Formspree / Web3Forms — laisser vide pour utiliser mailto: en fallback.
// Ex: "https://formspree.io/f/xxxxxxx"  ou  "https://api.web3forms.com/submit"
const FORM_ENDPOINT = "";
const CONTACT_EMAIL = "gite.le1821@gmail.com";

// Lien Google pour laisser un avis sur la fiche établissement.
// ⚠️ À remplacer par l'URL réelle de votre fiche ("Écrire un avis") :
// 1) Cherchez "Gîte Le 1821" sur Google Maps
// 2) Cliquez sur "Écrire un avis"
// 3) Copiez l'URL de cette page ici.
// En attendant, le lien ouvre une recherche Google sur le nom du gîte.
const GOOGLE_REVIEW_URL = "https://www.google.com/search?q=G%C3%AEte+Le+1821+Frayssinet+avis";

const REGION = [
  {
    name: "Rocamadour",
    km: "32 km",
    type: "Cité médiévale · UNESCO",
    summary: "Cité médiévale suspendue à la falaise, classée UNESCO.",
    paragraphs: [
      "Rocamadour, classé parmi les Plus Beaux Villages de France, s'accroche à 120 mètres au-dessus du canyon de l'Alzou. La cité s'étage en trois niveaux — village, sanctuaires, château — reliés par le Grand Escalier de 216 marches que les pèlerins gravissaient autrefois à genoux.",
      "La Chapelle Notre-Dame, qui abrite la Vierge Noire vénérée depuis le XIIᵉ siècle, et la basilique Saint-Sauveur composent l'ensemble sanctuaire, inscrit au patrimoine mondial au titre des chemins de Saint-Jacques-de-Compostelle. Vue à couper le souffle depuis le belvédère de l'Hospitalet, au coucher du soleil.",
    ],
    tags: ["Patrimoine", "Vue panoramique", "30 min en voiture"],
    img: "assets/regions/rocamadour.webp",
  },
  {
    name: "Gouffre de Padirac",
    km: "38 km",
    type: "Site souterrain",
    summary: "Rivière souterraine et grotte aux dimensions impressionnantes.",
    paragraphs: [
      "Une descente en ascenseur de 75 mètres dans la terre vous mène à la rivière plana, navigable en barque sur 700 mètres. Des stalactites monumentales — dont la Grande Pendeloque, 60 mètres de haut — éclairent un parcours sculpté par des millions d'années.",
      "Comptez 1h30 de visite, températures fraîches (13°C constants). Réservation en ligne fortement conseillée en juillet-août. Idéal en famille à partir de 4 ans.",
    ],
    tags: ["Famille", "Tout temps", "Réserver à l'avance"],
    img: "assets/regions/padirac.webp",
  },
  {
    name: "Saint-Cirq-Lapopie",
    km: "45 km",
    type: "Plus beau village de France",
    summary: "Village perché au-dessus du Lot, classé Plus beau village.",
    paragraphs: [
      "Saint-Cirq-Lapopie est élu Village préféré des Français en 2012. Ses ruelles médiévales en pente raide, ses maisons à pans de bois et ses ateliers d'artisans (verriers, ébénistes, peintres) en font une halte vivante au-dessus d'une boucle spectaculaire du Lot.",
      "À combiner avec une balade le long du chemin de halage taillé dans la roche, ou une descente en gabare. Marché de producteurs le mercredi matin en été.",
    ],
    tags: ["Artisanat", "Randonnée", "1h en voiture"],
    img: "assets/regions/saintcirq.jpg",
  },
  {
    name: "Causses du Quercy",
    km: "Sur place",
    type: "Parc Naturel Régional",
    summary: "Géoparc UNESCO — paysages de pierre sèche, dolmens, lavognes.",
    paragraphs: [
      "Le Parc Naturel Régional des Causses du Quercy, classé Géoparc mondial UNESCO, étire ses plateaux calcaires juste autour du gîte. Murets de pierre sèche, bories, lavognes (mares pavées) et chemins de transhumance forment un paysage façonné par 5 000 ans d'agropastoralisme.",
      "Une vingtaine de circuits balisés démarrent à moins de 15 minutes du gîte — du sentier d'interprétation accessible à tous (Frayssinet-le-Gélat) aux boucles plus exigeantes au-dessus du Lot. Topo-guides remis sur place.",
    ],
    tags: ["Randonnée", "Patrimoine naturel", "À pied depuis le gîte"],
    img: "assets/regions/caussesquercy.jpg",
  },
  {
    name: "Forêt des Singes & Rocher des Aigles",
    km: "30 km",
    type: "Parcs animaliers",
    summary: "20 hectares en liberté pour 150 macaques de Barbarie, à Rocamadour.",
    paragraphs: [
      "Sur les hauteurs de Rocamadour, la Forêt des Singes laisse évoluer en liberté 150 macaques de Barbarie sur 20 hectares — vous distribuez des graines, ils s'approchent à 50 cm. Programme de réintroduction des animaux dans l'Atlas marocain depuis 1980.",
      "À 2 km, le Rocher des Aigles présente des démonstrations de vol libre quotidiennes : aigles, vautours, condors. Les deux sites se font sur une demi-journée, idéal avec des enfants.",
    ],
    tags: ["Famille", "Avril → novembre"],
    img: "assets/regions/singes.jpg",
  },
  {
    name: "Vignobles de Cahors",
    km: "55 km",
    type: "Œnotourisme",
    summary: "Le Malbec noir, cépage emblématique de la vallée du Lot.",
    paragraphs: [
      "Au sud du gîte, la vallée du Lot serpente entre les domaines viticoles de l'appellation Cahors — vins rouges puissants, charpentés, issus du cépage Malbec (ou Côt). Plusieurs domaines en biodynamie ouvrent leur chai pour des dégustations sur rendez-vous.",
      "Pour une découverte sur une journée : Pont Valentré, vieille ville de Cahors, et 2-3 domaines en boucle.",
    ],
    tags: ["Œnologie", "Gastronomie", "Visite sur RDV"],
    img: "assets/regions/vignobles.jpg",
  },
  {
    name: "Marché aux truffes de Lalbenque",
    km: "50 km",
    type: "Marché saisonnier",
    summary: "L'un des plus grands marchés de truffe noire de France.",
    paragraphs: [
      "De début décembre à mi-mars, le mardi à 14h30 précises : le coup de sifflet ouvre le marché aux truffes de Lalbenque. Les rabassiers déballent leurs paniers, les négociants comparent, le ballet dure une heure. Une institution du Quercy depuis les années 1890.",
      "Hors saison, plusieurs trufficulteurs autour du gîte organisent des cavages avec leur chien et des dégustations à la ferme.",
    ],
    tags: ["Gastronomie", "Décembre → mars"],
    img: "assets/regions/truffes.jpg",
  },
  {
    name: "Gourdon, Figeac, Cahors",
    km: "20 → 75 km",
    type: "Patrimoine · Trois cités",
    summary: "Trois cités d'histoire à explorer en journée.",
    paragraphs: [
      "Gourdon, la plus proche (20 km), est une cité médiévale étagée sur une butte, dont les ruelles convergent vers la place couverte de la halle aux grains. Idéale pour une matinée flânerie + marché du samedi.",
      "Figeac (60 km) abrite le Musée Champollion-Les Écritures du Monde, dans la maison natale du déchiffreur des hiéroglyphes — collection unique d'écritures du monde entier. Cahors (75 km) avec son Pont Valentré, le seul pont fortifié médiéval encore intact en France.",
    ],
    tags: ["Patrimoine", "Musées", "Journée complète"],
    img: "assets/regions/gourdon.jpg",
  },
  {
    name: "Randonnée & canoë",
    km: "Sur place",
    type: "Nature & Activités",
    summary: "GR652, canoë sur la Dordogne ou le Célé.",
    paragraphs: [
      "Le sentier de Grande Randonnée GR652 passe à proximité du gîte et relie Rocamadour à Conques. Plusieurs boucles de 10 à 25 km traversent les Causses depuis Frayssinet-le-Gourdonnais — patrimoine de pierre sèche, points de vue sur les vallées.",
      "Pour l'eau : canoë-kayak sur la Dordogne au nord (Carennac, Saint-Sozy) ou sur le Célé à l'est (Marcilhac-sur-Célé) — locations en demi-journée ou journée complète, avec navette retour.",
    ],
    tags: ["Randonnée", "Famille", "Toute saison"],
    img: "assets/regions/randonnee.webp",
  },
  {
    name: "Triangle Noir du Quercy",
    km: "Sur place",
    type: "Astronomie · Ciel nocturne",
    summary: "L'un des ciels les plus purs de France métropolitaine.",
    paragraphs: [
      "Le gîte est situé au cœur du Triangle Noir du Quercy, l'une des zones de France métropolitaine où la pollution lumineuse est la plus faible. Les nuits sans lune révèlent la Voie lactée à l'œil nu, et les étoiles filantes des Perséides (août) ou des Géminides (décembre) y sont spectaculaires.",
      "Un télescope d'initiation est disponible sur place. Le Parc Naturel Régional organise plusieurs soirées d'observation publiques chaque été — programme remis à l'arrivée.",
    ],
    tags: ["Nature", "Soir", "Tout public"],
    img: "assets/regions/triangle_noir.jpg",
  },
];

const TARIFS_FALLBACK = {
  rows: [
    { id: "low", period: "Basse saison", dates: "Janv. → mai · oct. → déc.", week: "420 €", night: "70 €" },
    { id: "high", period: "Moyenne et haute saison", dates: "Juin à septembre", week: "600 €", night: "—" }
  ],
  included: [],
  options: [],
  conditions: ""
};

const TESTIMONIALS_FALLBACK = [
  { id: "t1", quote: "Un havre de paix dans les Causses.", author: "—" }
];

// ============================================================
// Icons (line, minimal — no decorative SVG)
// ============================================================
const Ico = ({ name, size = 22 }) => {
  const s = size;
  switch (name) {
    case "users":   return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><circle cx="9" cy="8" r="3.2"/><path d="M3 20c0-3.3 2.7-6 6-6s6 2.7 6 6"/><circle cx="17" cy="9" r="2.5"/><path d="M14.5 14.5c2 .4 5 1.8 5 5"/></svg>;
    case "pool":    return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M3 18c1.5-1 3-1 4.5 0s3 1 4.5 0 3-1 4.5 0 3 1 4.5 0"/><path d="M3 14c1.5-1 3-1 4.5 0s3 1 4.5 0 3-1 4.5 0 3 1 4.5 0"/><path d="M7 14V6a2 2 0 1 1 4 0"/><path d="M13 14V6a2 2 0 1 1 4 0"/></svg>;
    case "kitchen": return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><rect x="4" y="4" width="16" height="16" rx="1"/><circle cx="9" cy="9" r="1.4"/><circle cx="15" cy="9" r="1.4"/><rect x="7" y="13" width="10" height="5"/></svg>;
    case "ev":      return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M13 3 7 13h4l-1 8 6-10h-4l1-8Z"/></svg>;
    case "wifi":    return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M3 9c5-5 13-5 18 0"/><path d="M6 13c3.5-3.5 9-3.5 12 0"/><path d="M9 17c1.7-1.7 4.3-1.7 6 0"/><circle cx="12" cy="20" r=".8" fill="currentColor"/></svg>;
    case "paw":     return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4"><circle cx="6" cy="11" r="2"/><circle cx="10" cy="6" r="2"/><circle cx="14" cy="6" r="2"/><circle cx="18" cy="11" r="2"/><path d="M8 20c0-3 1.8-5 4-5s4 2 4 5"/></svg>;
    case "arrow":   return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M5 12h14M13 6l6 6-6 6"/></svg>;
    case "close":   return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M5 5l14 14M19 5L5 19"/></svg>;
    default: return null;
  }
};

// ============================================================
// NAV
// ============================================================
function Nav({ route, go, theme }) {
  const [open, setOpen] = useState(false);
  const links = [
    { id: "home",    label: "Le Gîte" },
    { id: "photos",  label: "Photos" },
    { id: "region",  label: "La Région" },
    { id: "tarifs",  label: "Tarifs" },
    { id: "contact", label: "Contact" },
  ];
  return (
    <nav className="nav">
      <div className="nav-inner">
        <button className="brand" onClick={() => go("home")} style={{ background: "transparent", border: 0, padding: 0, cursor: "pointer" }}>
          <span className="display"><em>Le</em> <span className="mark">1821</span></span>
          <span className="brand-meta">
            <span className="mono">Gîte · Lot · Quercy</span>
            <span className="mono brand-rating">★★★ · 3 étoiles France</span>
          </span>
        </button>

        <button className="burger" onClick={() => setOpen(!open)} aria-label="Menu">☰</button>

        <ul className={"nav-links" + (open ? " open" : "")}>
          {links.map(l => (
            <li key={l.id}>
              <button
                className={"linklike" + (route === l.id ? " is-active" : "")}
                onClick={() => { go(l.id); setOpen(false); }}>
                {l.label}
              </button>
            </li>
          ))}
          <li>
            <button className="cta" onClick={() => { go("contact"); setOpen(false); }}>
              Réserver <Ico name="arrow" size={14} />
            </button>
          </li>
        </ul>
      </div>
    </nav>
  );
}

// ============================================================
// HERO
// ============================================================
function Hero({ go }) {
  return (
    <header className="hero">
      <div className="hero-inner">
        <div className="hero-copy">
          <div className="eyebrow">Frayssinet-le-Gourdonnais · Lot · 46310</div>
          <h1 className="display">
            Un gîte<br/>
            de pierre,<br/>
            depuis <span className="num">1821</span>
          </h1>
          <p className="lede">
            Maison du Quercy restaurée pour 4 personnes, accès piscine en saison et silence des
            Causses. À l'écart, tout en restant à 30 minutes de Rocamadour et des plus beaux
            villages de France.
          </p>
          <dl className="hero-meta">
            <div><dt>Capacité</dt><dd>4 personnes · 1 chambre + mezzanine</dd></div>
            <div><dt>Classement</dt><dd>★★★ — 3 étoiles France</dd></div>
            <div><dt>Disponible</dt><dd>Semaine toute l'année · Nuitée d'octobre à mai (2 nuits min.)</dd></div>
          </dl>
          <div className="hero-cta-row">
            <button className="cta" onClick={() => go("contact")}>Vérifier les dates <Ico name="arrow" size={14} /></button>
            <button className="cta ghost" onClick={() => go("photos")}>Voir les photos</button>
          </div>
        </div>
        <div className="hero-img">
          <img src="assets/gite/entree.jpg" alt="Façade en pierre du gîte Le 1821 avec terrasse" />
          <div className="stars-tag"><span className="stars">★★★</span> Classement officiel</div>
        </div>
      </div>
    </header>
  );
}

// ============================================================
// SECTION HEAD
// ============================================================
function SectionHead({ idx, kicker, title, em }) {
  return (
    <div className="section-head">
      <div className="label">
        <span className="idx">— {idx}</span>
        <span>{kicker}</span>
      </div>
      <h2 className="display">
        {title} {em && <em>{em}</em>}
      </h2>
    </div>
  );
}

// ============================================================
// HOME — composition complète
// ============================================================
function Home({ go, openLightbox, gallery }) {
  return (
    <>
      <Hero go={go} />

      <Strip />

      {/* LE GÎTE */}
      <section className="block" id="gite">
        <div className="block-inner">
          <SectionHead idx="01" kicker="Le Gîte" title="Une grange de" em="1821, devenue refuge." />
          <div className="gite-grid">
            <div className="gite-text">
              <p>
                Cette ancienne dépendance agricole, datée de 1821 sur sa clé de voûte,
                a gardé ses murs de pierre sèche et sa charpente apparente en chêne.
                La restauration, menée en matériaux naturels (chaux, terre crue, bois
                local), conserve l'esprit du lieu tout en intégrant un chauffage et
                une climatisation modernes par pompe à chaleur.
              </p>
              <blockquote className="pull">
                « 200 ans de pierre, restaurées avec patience et respect des matières. »
              </blockquote>
              <p style={{ fontSize: 13.5, color: "var(--ink-soft)", borderTop: "1px solid var(--line)", paddingTop: 16, marginTop: 24, fontFamily: "var(--font-mono)", letterSpacing: "0.02em" }}>
                <strong>À noter —</strong> Le gîte n'est pas adapté aux personnes à mobilité
                réduite (escalier vers l'étage).
              </p>
            </div>
            <div className="features">
              {FEATURES.map(f => (
                <div className="feature" key={f.title}>
                  <div className="ico"><Ico name={f.ico} size={26} /></div>
                  <h4>{f.title}</h4>
                  <p>{f.desc}</p>
                </div>
              ))}
            </div>
          </div>
        </div>
      </section>

      {/* PHOTOS */}
      <section className="block alt" id="photos">
        <div className="block-inner">
          <SectionHead idx="02" kicker="Photos" title="Le lieu," em="en images." />
          <div className="gallery">
            {gallery.map((g, i) => (
              <button
                key={g.id || i}
                className={"cell " + (g.layout || "c-sq")}
                onClick={() => openLightbox(i)}
                style={{ border: 0, padding: 0 }}>
                <img src={g.src} alt={g.alt} loading="lazy" />
                <div className="cap">{g.cap}</div>
              </button>
            ))}
          </div>
          <div style={{ marginTop: 56, textAlign: "center" }}>
            <button className="cta ghost" onClick={() => go("region")}>
              Explorer la région <Ico name="arrow" size={14} />
            </button>
          </div>
        </div>
      </section>

      {/* TESTIMONIAL */}
      <section className="block tight">
        <div className="block-inner">
          <Testimonials />
        </div>
      </section>

      {/* REGION */}
      <section className="block alt" id="region">
        <div className="block-inner">
          <SectionHead idx="03" kicker="La Région" title="Les Causses," em="Rocamadour, le Lot." />
          <div className="region-grid">
            {REGION.slice(0, 3).map(r => (
              <article className="region-card" key={r.name}>
                <div className="img">
                  {r.img
                    ? <img src={r.img} alt={r.name} />
                    : <div className="img-placeholder">Photo {r.name} ·<br/>à fournir</div>}
                  <span className="km">{r.km}</span>
                </div>
                <h4>{r.name}</h4>
                <p>{r.summary}</p>
              </article>
            ))}
          </div>
          <div style={{ marginTop: 48, textAlign: "center" }}>
            <button className="cta" onClick={() => go("region")}>Explorer la région ({REGION.length} lieux) <Ico name="arrow" size={14} /></button>
          </div>
        </div>
      </section>
    </>
  );
}

// ============================================================
// REGION PAGE — long-form éditorial
// ============================================================
function RegionPage({ go }) {
  const [filter, setFilter] = useState("all");
  const tags = ["all", "Patrimoine", "Nature", "Famille", "Randonnée", "Gastronomie", "Œnologie"];
  const filtered = filter === "all" ? REGION : REGION.filter(r => r.tags.some(t => t === filter));

  return (
    <section className="block" id="region" style={{ paddingTop: 64 }}>
      <div className="block-inner">
        <SectionHead idx="03" kicker="La Région" title="Dix lieux" em="à 1 h du gîte." />
        <p style={{ maxWidth: "60ch", fontSize: 17, color: "var(--ink-soft)", marginTop: -28, marginBottom: 32 }}>
          Le 1821 est niché dans le Parc Naturel Régional des Causses du Quercy,
          à mi-chemin entre la vallée de la Dordogne et celle du Lot. Voici les
          dix lieux que nous recommandons en priorité — du château accroché à
          la falaise au ciel étoilé du Triangle Noir, en passant par les vignobles
          de Cahors et le marché aux truffes de Lalbenque.
        </p>

        <div className="region-filters">
          {tags.map(t => (
            <button key={t} className={"region-filter" + (filter === t ? " is-active" : "")} onClick={() => setFilter(t)}>
              {t === "all" ? "Tous les lieux" : t}
            </button>
          ))}
        </div>

        <div className="region-long">
          {filtered.map((r, i) => (
            <article className={"region-entry " + (i % 2 === 1 ? "rev" : "")} key={r.name}>
              <div className="region-entry-media">
                {r.img
                  ? <img src={r.img} alt={r.name} />
                  : <div className="img-placeholder">Photo {r.name} ·<br/>à fournir</div>}
                <span className="region-entry-km">{r.km}</span>
              </div>
              <div className="region-entry-copy">
                <div className="region-entry-meta">
                  <span className="region-entry-idx">— {String(i + 1).padStart(2, "0")}</span>
                  <span className="region-entry-type">{r.type}</span>
                </div>
                <h3 className="display">{r.name}</h3>
                {r.paragraphs.map((p, k) => <p key={k}>{p}</p>)}
                <div className="region-entry-tags">
                  {r.tags.map(t => <span key={t}>{t}</span>)}
                </div>
              </div>
            </article>
          ))}
        </div>

      </div>
    </section>
  );
}

// ============================================================
// TARIFS
// ============================================================
function Tarifs({ go }) {
  const T = useJSON("data/tarifs.json", TARIFS_FALLBACK);
  return (
    <section className="block" id="tarifs" style={{ paddingTop: 64 }}>
      <div className="block-inner">
        <SectionHead idx="04" kicker="Tarifs & disponibilités" title="À partir de" em="70 € la nuit." />
        <div className="tarifs-grid">
          <div>
            <table className="tarifs-table">
              <thead>
                <tr>
                  <th>Période</th>
                  <th>Semaine</th>
                  <th>Nuit (basse)</th>
                </tr>
              </thead>
              <tbody>
                {(T.rows || []).map(t => (
                  <tr key={t.id}>
                    <td>
                      <span className="period">{t.period}</span>
                      <span className="dates">{t.dates}</span>
                    </td>
                    <td className="week">{t.week}</td>
                    <td className="night">{t.night}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>

          <aside className="tarifs-card">
            <h4>Inclus</h4>
            <ul>
              {(T.included || []).map(it => (
                <li key={it.id}><span>{it.label}</span><span className="v">{it.value}</span></li>
              ))}
            </ul>

            <h4 style={{ marginTop: 28 }}>Options & suppléments</h4>
            <ul>
              {(T.options || []).map(it => (
                <li key={it.id}><span>{it.label}</span><span className="v">{it.value}</span></li>
              ))}
            </ul>
            <h4 style={{ marginTop: 24 }}>Conditions de paiement</h4>
            <p className="note" style={{ whiteSpace: "pre-line" }}>
              {T.conditions || ""}
            </p>
            <button className="cta" style={{ marginTop: 18 }} onClick={() => go("contact")}>
              Demander un devis <Ico name="arrow" size={14} />
            </button>
          </aside>
        </div>
      </div>
    </section>
  );
}

// ============================================================
// CALENDAR (statique mais interactif)
// ============================================================
function Calendar() {
  const today = new Date();
  const [m, setM] = useState({ y: today.getFullYear(), mo: today.getMonth() });
  const MONTH_NAMES = ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"];
  const DOW = ["L","M","M","J","V","S","D"];

  // génère un set de jours réservés / options selon le mois
  const generated = useMemo(() => {
    const seed = m.y * 12 + m.mo;
    const booked = new Set();
    const option = new Set();
    const rng = (i) => Math.abs(Math.sin(seed * 13.37 + i)) % 1;
    for (let d = 1; d <= 31; d++) {
      const r = rng(d);
      if (r < 0.18) booked.add(d);
      else if (r < 0.24) option.add(d);
    }
    return { booked, option };
  }, [m]);

  const first = new Date(m.y, m.mo, 1);
  const startDow = (first.getDay() + 6) % 7;
  const daysInMonth = new Date(m.y, m.mo + 1, 0).getDate();

  const nav = (delta) => {
    const d = new Date(m.y, m.mo + delta, 1);
    setM({ y: d.getFullYear(), mo: d.getMonth() });
  };

  return (
    <div className="calendar-wrap" style={{ marginTop: 32 }}>
      <div className="cal-head">
        <h5>{MONTH_NAMES[m.mo]} {m.y}</h5>
        <div className="cal-nav">
          <button onClick={() => nav(-1)} aria-label="Précédent">‹</button>
          <button onClick={() => nav(1)} aria-label="Suivant">›</button>
        </div>
      </div>
      <div className="cal-grid">
        {DOW.map((d, i) => <div className="cal-dow" key={i}>{d}</div>)}
        {Array.from({ length: startDow }).map((_, i) => <div className="cal-day muted" key={"e"+i}></div>)}
        {Array.from({ length: daysInMonth }).map((_, i) => {
          const d = i + 1;
          const cls = generated.booked.has(d) ? "booked"
                   : generated.option.has(d) ? "option"
                   : "free";
          return <div className={"cal-day " + cls} key={d}>{d}</div>;
        })}
      </div>
      <div className="cal-legend">
        <span><i style={{ background: "var(--surface-2)" }}></i> Disponible</span>
        <span><i style={{ background: "var(--accent-soft)" }}></i> Option</span>
        <span><i style={{ background: "var(--ink-soft)" }}></i> Réservé</span>
      </div>
    </div>
  );
}

// ============================================================
// CONTACT
// ============================================================
function Contact() {
  const [data, setData] = useState({ name: "", email: "", phone: "", arrive: "", depart: "", people: 2, message: "" });
  const [errors, setErrors] = useState({});
  const [sent, setSent] = useState(false);

  const submit = async (e) => {
    e.preventDefault();
    const err = {};
    if (!data.name.trim()) err.name = "Votre nom est requis.";
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) err.email = "Email invalide.";
    if (!data.arrive) err.arrive = "Date d'arrivée requise.";
    if (!data.depart) err.depart = "Date de départ requise.";
    if (data.arrive && data.depart && data.depart <= data.arrive) err.depart = "La date de départ doit être après l'arrivée.";
    setErrors(err);
    if (Object.keys(err).length > 0) return;

    // ── Mode 1 : Formspree / Web3Forms si FORM_ENDPOINT renseigné ──
    if (FORM_ENDPOINT) {
      try {
        await fetch(FORM_ENDPOINT, {
          method: "POST",
          headers: { "Content-Type": "application/json", "Accept": "application/json" },
          body: JSON.stringify(data)
        });
      } catch (_) {}
      setSent(true);
      return;
    }

    // ── Mode 2 (par défaut, statique NAS) : mailto: pré-rempli ──
    const subject = encodeURIComponent(`Demande de réservation — ${data.name}`);
    const body = encodeURIComponent(
      `Bonjour Patricia et Philippe,\n\n` +
      `Je souhaite réserver le gîte Le 1821 :\n` +
      `• Arrivée : ${data.arrive}\n` +
      `• Départ  : ${data.depart}\n` +
      `• Voyageurs : ${data.people}\n` +
      `• Téléphone : ${data.phone || "—"}\n\n` +
      `Message :\n${data.message || "—"}\n\n` +
      `Cordialement,\n${data.name}\n${data.email}`
    );
    window.location.href = `mailto:${CONTACT_EMAIL}?subject=${subject}&body=${body}`;
    setSent(true);
  };

  return (
    <section className="block" id="contact" style={{ paddingTop: 64 }}>
      <div className="block-inner">
        <SectionHead idx="05" kicker="Contact & réservation" title="On vous répond" em="sous 24 heures." />
        <div className="contact-grid">
          <div className="contact-info">
            <dl>
              <dt>Vos hôtes</dt>
              <dd>Patricia et Philippe</dd>
              <dt>Adresse</dt>
              <dd>1213 route du Plegat<br/>46310 Frayssinet-le-Gourdonnais</dd>
              <dt>Téléphone</dt>
              <dd>
                <a href="tel:+33666586361">06 66 58 63 61</a> · Patricia<br/>
                <a href="tel:+33695143168">06 95 14 31 68</a> · Philippe
              </dd>
              <dt>Email</dt>
              <dd><a href={`mailto:${CONTACT_EMAIL}`}>{CONTACT_EMAIL}</a></dd>
              <dt>Accessibilité</dt>
              <dd style={{ fontSize: 13.5, color: "var(--ink-soft)" }}>Non adapté aux personnes à mobilité réduite.</dd>
              <dt>Accueil</dt>
              <dd style={{ fontSize: 13.5, color: "var(--ink-soft)" }}>L'accueil au gîte est assuré par vos hôtes.</dd>
            </dl>
            <div className="map">
              <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
                <defs>
                  <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                    <path d="M40 0H0V40" fill="none" stroke="currentColor" strokeWidth="0.5" opacity="0.2"/>
                  </pattern>
                </defs>
                <rect width="400" height="300" fill="url(#grid)" />
                <path d="M0 180 Q100 160 180 175 T400 200" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.4"/>
                <path d="M50 0 Q90 80 120 140 T200 280" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.3"/>
                <circle cx="220" cy="150" r="6" fill="var(--accent)"/>
                <circle cx="220" cy="150" r="14" fill="none" stroke="var(--accent)" strokeWidth="1"/>
                <text x="232" y="146" fontSize="10" fontFamily="ui-monospace,monospace" fill="currentColor">Le 1821</text>
                <text x="232" y="158" fontSize="8" fontFamily="ui-monospace,monospace" fill="currentColor" opacity="0.6">44.6555°N · 1.4945°E</text>
              </svg>
            </div>
          </div>

          {!sent ? (
            <form className="contact-form" onSubmit={submit} noValidate>
              <div className="form-row">
                <div className={"field" + (errors.name ? " error" : "")}>
                  <label>Nom complet</label>
                  <input value={data.name} onChange={e => setData({ ...data, name: e.target.value })} />
                  {errors.name && <span className="err-msg">{errors.name}</span>}
                </div>
                <div className={"field" + (errors.email ? " error" : "")}>
                  <label>Email</label>
                  <input type="email" value={data.email} onChange={e => setData({ ...data, email: e.target.value })} />
                  {errors.email && <span className="err-msg">{errors.email}</span>}
                </div>
              </div>
              <div className="form-row">
                <div className="field">
                  <label>Téléphone (optionnel)</label>
                  <input value={data.phone} onChange={e => setData({ ...data, phone: e.target.value })} />
                </div>
                <div className="field">
                  <label>Voyageurs</label>
                  <select value={data.people} onChange={e => setData({ ...data, people: +e.target.value })}>
                    <option value={1}>1 personne</option>
                    <option value={2}>2 personnes</option>
                    <option value={3}>3 personnes</option>
                    <option value={4}>4 personnes</option>
                  </select>
                </div>
              </div>
              <div className="form-row">
                <div className={"field" + (errors.arrive ? " error" : "")}>
                  <label>Arrivée</label>
                  <input type="date" value={data.arrive} onChange={e => setData({ ...data, arrive: e.target.value })} />
                  {errors.arrive && <span className="err-msg">{errors.arrive}</span>}
                </div>
                <div className={"field" + (errors.depart ? " error" : "")}>
                  <label>Départ</label>
                  <input type="date" value={data.depart} onChange={e => setData({ ...data, depart: e.target.value })} />
                  {errors.depart && <span className="err-msg">{errors.depart}</span>}
                </div>
              </div>
              <div className="field">
                <label>Message</label>
                <textarea
                  placeholder="Activités souhaitées, animaux, questions particulières…"
                  value={data.message}
                  onChange={e => setData({ ...data, message: e.target.value })}
                />
              </div>
              <button className="form-submit" type="submit">
                Envoyer la demande <Ico name="arrow" size={12} />
              </button>
            </form>
          ) : (
            <div className="contact-form form-success">
              <h4 className="display">Merci, votre demande est envoyée.</h4>
              <p style={{ fontSize: 15, color: "var(--ink-soft)", marginTop: 12 }}>
                Nous reviendrons vers vous à <strong>{data.email}</strong> sous 24h pour confirmer
                la disponibilité du <strong>{data.arrive}</strong> au <strong>{data.depart}</strong>
                pour <strong>{data.people} {data.people > 1 ? "personnes" : "personne"}</strong>.
              </p>
              <button className="cta" style={{ marginTop: 18 }} onClick={() => { setSent(false); setData({ name:"", email:"", phone:"", arrive:"", depart:"", people:2, message:"" }); }}>
                Envoyer une autre demande
              </button>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// ============================================================
// LEGAL — Mentions légales
// ============================================================
function LegalPage({ go }) {
  const SECTIONS = [
    {
      n: "01",
      kicker: "Présentation du site",
      title: "Qui édite ce site.",
      body: (
        <>
          <p>
            En vertu de l'article 6 de la loi n° 2004-575 du 21 juin 2004 pour
            la confiance dans l'économie numérique, il est précisé aux
            utilisateurs du site <a href="https://le1821.fr">https://le1821.fr</a> l'identité des
            différents intervenants.
          </p>
          <dl className="legal-dl">
            <div>
              <dt>Propriétaire & éditeur</dt>
              <dd>
                Philippe et Patricia ROGER<br/>
                1213 route du Plegat<br/>
                46310 Frayssinet
              </dd>
            </div>
            <div>
              <dt>Responsable de la publication</dt>
              <dd>
                Frédéric MALRIEU<br/>
                <a href="mailto:fred31500@yahoo.fr">fred31500@yahoo.fr</a>
              </dd>
            </div>
          </dl>
        </>
      ),
    },
    {
      n: "02",
      kicker: "Hébergement",
      title: "Auto-hébergement sur le Lot.",
      body: (
        <>
          <p>
            Le site est <strong>auto-hébergé</strong> sur un serveur privé situé à
            Frayssinet, dans le Lot (46). Aucun prestataire tiers n'intervient
            dans la mise en ligne ou la conservation des données.
          </p>
          <dl className="legal-dl">
            <div>
              <dt>Contact technique</dt>
              <dd><a href="mailto:fred31500@yahoo.fr">fred31500@yahoo.fr</a></dd>
            </div>
            <div>
              <dt>Localisation du serveur</dt>
              <dd>Frayssinet — Lot (46), France</dd>
            </div>
          </dl>
        </>
      ),
    },
    {
      n: "03",
      kicker: "Webmaster",
      title: "Conception & développement.",
      body: (
        <>
          <p>
            Frédéric MALRIEU est le concepteur et webmaster du site.
            Pour toute question relative au fonctionnement du site ou à son
            contenu technique&nbsp;: <a href="mailto:fred31500@yahoo.fr">fred31500@yahoo.fr</a>.
          </p>
          <figure className="legal-figure">
            <img src="assets/web.jpg" alt="Frédéric Malrieu, webmaster du site Le 1821" />
            <figcaption>
              <span className="legal-figure-eyebrow">Webmaster</span>
              <span className="legal-figure-name">Frédéric Malrieu</span>
              <span className="legal-figure-role">Conception, design & développement</span>
            </figcaption>
          </figure>
        </>
      ),
    },
    {
      n: "04",
      kicker: "Propriété intellectuelle",
      title: "Droits & reproductions.",
      body: (
        <>
          <p>
            L'ensemble des contenus présents sur ce site — textes, logos,
            photographies du gîte (notamment celle du linteau gravé de 1821) —
            est la <strong>propriété exclusive de l'éditeur</strong>. Toute reproduction,
            représentation, modification ou diffusion, totale ou partielle, est
            interdite sans accord préalable écrit.
          </p>
          <p>
            Les photographies illustrant les activités et lieux de la région
            sont des images libres de droits, accessibles en ligne, et utilisées
            à des fins strictement informatives.
          </p>
        </>
      ),
    },
    {
      n: "05",
      kicker: "Données personnelles · RGPD",
      title: "Vos données, vos droits.",
      body: (
        <>
          <p>
            Les données collectées via le formulaire de contact
            (nom, adresse email, téléphone éventuel, dates de séjour) servent
            <strong> uniquement au traitement de votre demande de réservation</strong> et
            ne sont jamais cédées, vendues ou communiquées à des tiers.
          </p>
          <p>
            Conformément à la loi « Informatique et Libertés » du 6 janvier 1978
            modifiée, ainsi qu'au Règlement Général sur la Protection des
            Données (RGPD), vous disposez d'un droit d'accès, de rectification
            et de suppression des données vous concernant. Pour exercer ce
            droit, contactez-nous à
            {" "}<a href="mailto:gite.le1821@gmail.com">gite.le1821@gmail.com</a>.
          </p>
          <p className="legal-fineprint">
            Le site n'utilise aucun cookie de mesure d'audience, aucun traceur
            publicitaire et aucun service tiers de profilage.
          </p>
        </>
      ),
    },
  ];

  return (
    <section className="block legal-page" id="legal" style={{ paddingTop: 64 }}>
      <div className="block-inner">
        <SectionHead idx="06" kicker="Mentions Légales" title="Informations" em="légales." />
        <p className="legal-lede">
          Dernière mise à jour&nbsp;: mai 2026 · En application de la
          loi pour la confiance dans l'économie numérique (LCEN) et du
          Règlement Général sur la Protection des Données (RGPD).
        </p>

        <div className="legal-toc">
          {SECTIONS.map(s => (
            <a key={s.n} href={`#legal-${s.n}`} onClick={(e) => {
              e.preventDefault();
              const el = document.getElementById(`legal-${s.n}`);
              if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
            }}>
              <span className="legal-toc-n">— {s.n}</span>
              <span className="legal-toc-l">{s.kicker}</span>
            </a>
          ))}
        </div>

        <div className="legal-stack">
          {SECTIONS.map(s => (
            <article className="legal-entry" id={`legal-${s.n}`} key={s.n}>
              <div className="legal-entry-meta">
                <span className="legal-entry-n">— {s.n}</span>
                <span className="legal-entry-kicker">{s.kicker}</span>
              </div>
              <div className="legal-entry-body">
                <h3 className="display">{s.title}</h3>
                {s.body}
              </div>
            </article>
          ))}
        </div>

        <div className="legal-foot">
          <p>
            Pour toute autre question relative à ces mentions légales ou à
            l'utilisation de vos données, n'hésitez pas à
            {" "}<button className="linklike-inline" onClick={() => go("contact")}>nous contacter</button>.
          </p>
          <button className="cta ghost" onClick={() => go("home")}>
            Retour à l'accueil <Ico name="arrow" size={14} />
          </button>
        </div>
      </div>
    </section>
  );
}

// ============================================================
// MARQUEE
// ============================================================
function Strip() {
  const items = [
    "Causses du Quercy", "1 hectare de prairie", "Accès piscine en saison",
    "Classé 3 étoiles", "Borne de recharge VE", "Réservation directe",
    "Triangle Noir du Quercy", "Sans intermédiaire"
  ];
  return (
    <div className="strip">
      <div className="strip-track">
        {[...items, ...items].map((t, i) => <span key={i}>{t}</span>)}
      </div>
    </div>
  );
}

// ============================================================
// TESTIMONIALS
// ============================================================
function Testimonials() {
  const list = useJSON("data/testimonials.json", TESTIMONIALS_FALLBACK);
  const items = Array.isArray(list) && list.length ? list : TESTIMONIALS_FALLBACK;
  const [i, setI] = useState(0);
  useEffect(() => {
    if (i >= items.length) setI(0);
  }, [items.length, i]);
  useEffect(() => {
    if (items.length <= 1) return;
    const t = setInterval(() => setI(x => (x + 1) % items.length), 7000);
    return () => clearInterval(t);
  }, [items.length]);
  const cur = items[Math.min(i, items.length - 1)];
  return (
    <div className="testimonial">
      <blockquote className="display">« {cur.quote} »</blockquote>
      <cite>{cur.author}</cite>
      <div className="dots">
        {items.map((_, k) => (
          <button key={k} className={k === i ? "active" : ""} onClick={() => setI(k)} aria-label={"Avis " + (k+1)}></button>
        ))}
      </div>
      <div className="testimonial-cta">
        <a
          className="linklike-inline"
          href={GOOGLE_REVIEW_URL}
          target="_blank"
          rel="noopener noreferrer"
        >
          Laisser un avis sur Google <Ico name="arrow" size={12} />
        </a>
      </div>
    </div>
  );
}

// ============================================================
// LIGHTBOX
// ============================================================
function Lightbox({ index, close, setIndex, gallery }) {
  useEffect(() => {
    const k = (e) => {
      if (e.key === "Escape") close();
      if (e.key === "ArrowRight") setIndex((index + 1) % gallery.length);
      if (e.key === "ArrowLeft") setIndex((index - 1 + gallery.length) % gallery.length);
    };
    window.addEventListener("keydown", k);
    return () => window.removeEventListener("keydown", k);
  }, [index, gallery.length]);
  if (!gallery[index]) return null;
  return (
    <div className="lightbox" onClick={close}>
      <button className="close" onClick={close} aria-label="Fermer"><Ico name="close" size={16} /></button>
      <button className="arrow prev" onClick={(e) => { e.stopPropagation(); setIndex((index - 1 + gallery.length) % gallery.length); }}>‹</button>
      <button className="arrow next" onClick={(e) => { e.stopPropagation(); setIndex((index + 1) % gallery.length); }}>›</button>
      <img src={gallery[index].src} alt={gallery[index].alt} onClick={(e) => e.stopPropagation()} />
      <div className="counter">{String(index + 1).padStart(2, "0")} / {String(gallery.length).padStart(2, "0")} · {gallery[index].cap}</div>
    </div>
  );
}

// ============================================================
// FOOTER
// ============================================================
function Foot({ go }) {
  return (
    <footer className="foot">
      <div className="foot-inner">
        <div>
          <div className="foot-brand display"><em>Le</em> <span className="num">1821</span></div>
          <p>Gîte de charme en pierre, au cœur du Parc Naturel Régional des Causses du Quercy.</p>
        </div>
        <div>
          <h6>Visiter</h6>
          <ul>
            <li><button onClick={() => go("home")}>Le Gîte</button></li>
            <li><button onClick={() => go("photos")}>Photos</button></li>
            <li><button onClick={() => go("region")}>La Région</button></li>
          </ul>
        </div>
        <div>
          <h6>Réserver</h6>
          <ul>
            <li><button onClick={() => go("tarifs")}>Tarifs</button></li>
            <li><button onClick={() => go("contact")}>Contact</button></li>
            <li>Virement 24h avant</li>
            <li>Caution 150 €</li>
            <li>Annulation 48h</li>
          </ul>
        </div>
        <div>
          <h6>Contact</h6>
          <ul>
            <li>1213 route du Plegat</li>
            <li>46310 Frayssinet</li>
            <li>+33 6 66 58 63 61</li>
            <li>gite.le1821@gmail.com</li>
          </ul>
        </div>
      </div>
      <div className="foot-bottom">
        <span>© 2026 Gîte Le 1821 · Frayssinet-le-Gourdonnais</span>
        <button
          className="foot-legal-link"
          onClick={() => go("legal")}
          title="Mentions légales"
        >
          Mentions légales
        </button>
      </div>
    </footer>
  );
}

// ============================================================
// APP ROOT
// ============================================================
function App() {
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "direction": "A",
    "paletteA": "terracotta",
    "paletteB": "forest",
    "showBookBar": true
  }/*EDITMODE-END*/;
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  const [route, setRoute] = useState(() => (location.hash.replace("#", "") || "home"));
  const [lightbox, setLightbox] = useState(null);
  const gallery = useJSON("data/gallery.json", { photos: GALLERY_FALLBACK });
  const galleryList = (gallery && gallery.photos) || GALLERY_FALLBACK;

  const go = useCallback((r) => {
    location.hash = r;
    setRoute(r);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }, []);

  useEffect(() => {
    const onHash = () => setRoute(location.hash.replace("#", "") || "home");
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  // sync data-theme
  useEffect(() => {
    document.documentElement.setAttribute("data-theme", tweaks.direction);
    const palette = tweaks.direction === "A" ? tweaks.paletteA : tweaks.paletteB;
    document.documentElement.setAttribute("data-palette", palette);
  }, [tweaks.direction, tweaks.paletteA, tweaks.paletteB]);

  const TP = window.TweaksPanel;
  const TweakSection = window.TweakSection;
  const TweakRadio = window.TweakRadio;
  const TweakColor = window.TweakColor;
  const TweakToggle = window.TweakToggle;

  const paletteOptionsA = [
    ["#b75a3c", "#f1e7d6", "#2a1f15"],
    ["#c08530", "#f1e7d6", "#2a1f15"],
    ["#a44a3a", "#f1e7d6", "#7a5a3a"],
  ];
  const paletteOptionsB = [
    ["#2f4a3a", "#f6f1e7", "#a98648"],
    ["#1f3346", "#f6f1e7", "#a98648"],
    ["#5e2a2a", "#f6f1e7", "#a98648"],
  ];
  const paletteNamesA = ["terracotta", "ochre", "clay"];
  const paletteNamesB = ["forest", "navy", "bordeaux"];

  return (
    <div className="app">
      <Nav route={route} go={go} theme={tweaks.direction} />
      {route === "home"      && <Home go={go} openLightbox={setLightbox} gallery={galleryList} />}
      {route === "photos"    && (
        <section className="block" style={{ paddingTop: 56 }}>
          <div className="block-inner">
            <SectionHead idx="02" kicker="Photos" title="Le lieu," em="en images." />
            <div className="gallery">
              {galleryList.map((g, i) => (
                <button key={g.id || i} className={"cell " + (g.layout || "c-sq")} onClick={() => setLightbox(i)} style={{ border: 0, padding: 0 }}>
                  <img src={g.src} alt={g.alt} loading="lazy" />
                  <div className="cap">{g.cap}</div>
                </button>
              ))}
            </div>
          </div>
        </section>
      )}
      {route === "region"    && <RegionPage go={go} />}
      {route === "tarifs"    && <Tarifs go={go} />}
      {route === "contact"   && <Contact />}
      {route === "legal"     && <LegalPage go={go} />}

      <Foot go={go} />

      {tweaks.showBookBar && route !== "contact" && (
        <div className="book-bar">
          <span className="label">Semaine toute l'année · Nuitée Octobre → Mai</span>
          <button onClick={() => go("contact")}>Réserver maintenant</button>
        </div>
      )}

      {lightbox !== null && <Lightbox index={lightbox} setIndex={setLightbox} close={() => setLightbox(null)} gallery={galleryList} />}

      {TP && (
        <TP title="Tweaks · Le 1821">
          <TweakSection title="Direction esthétique">
            <TweakRadio
              label="Style"
              value={tweaks.direction}
              options={[
                { value: "A", label: "Artisanal" },
                { value: "B", label: "Raffiné" }
              ]}
              onChange={(v) => setTweak("direction", v)}
            />
          </TweakSection>

          {tweaks.direction === "A" ? (
            <TweakSection title="Palette · Artisanal">
              <TweakColor
                label="Accent"
                value={tweaks.paletteA}
                options={paletteOptionsA.map((p, i) => ({ value: paletteNamesA[i], color: p }))}
                onChange={(v) => setTweak("paletteA", v)}
              />
            </TweakSection>
          ) : (
            <TweakSection title="Palette · Raffiné">
              <TweakColor
                label="Accent"
                value={tweaks.paletteB}
                options={paletteOptionsB.map((p, i) => ({ value: paletteNamesB[i], color: p }))}
                onChange={(v) => setTweak("paletteB", v)}
              />
            </TweakSection>
          )}

          <TweakSection title="Affichage">
            <TweakToggle
              label="Barre de réservation flottante"
              value={tweaks.showBookBar}
              onChange={(v) => setTweak("showBookBar", v)}
            />
          </TweakSection>
        </TP>
      )}
    </div>
  );
}

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