// DB Design & Services — landing page

const { useState, useEffect, useRef, useCallback } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#A8865A",
  "bgTone": "#F5F0E6",
  "softTone": "#EBE2D1",
  "headlineFont": "Cormorant Garamond"
} /*EDITMODE-END*/;

const ACCENT_OPTIONS = ["#A8865A", "#6B4F2A", "#7E8C5B", "#4A5660", "#9C3D2B"];
const BG_PALETTES = [
["#F5F0E6", "#EBE2D1"], // warm sand (default)
["#F2EDE3", "#E5DCC6"], // deeper beige
["#F6F2EA", "#ECE6D6"], // light cream
["#EFE9DD", "#1C1A17"] // contrast (kept inside theme)
];
const HEADLINE_FONTS = ["Cormorant Garamond", "Spectral", "EB Garamond", "Lora"];

// ─────────────────────────────────────────────────────────────────────────
// Reveal-on-scroll hook
function useReveal() {
  useEffect(() => {
    const els = Array.from(document.querySelectorAll(".reveal"));
    // Content is visible by default (see CSS); `.in` only plays the entrance
    // animation, so we never need a failsafe to "rescue" hidden content.
    if (!("IntersectionObserver" in window)) return;

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add("in");
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.08, rootMargin: "0px 0px -40px 0px" });
    els.forEach((el) => io.observe(el));

    return () => io.disconnect();
  }, []);
}

// ─────────────────────────────────────────────────────────────────────────
// Before/After slider
function BeforeAfter() {
  const wrapRef = useRef(null);
  const [pct, setPct] = useState(52);
  const dragging = useRef(false);

  const setFromEvent = useCallback((clientX) => {
    const el = wrapRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (clientX - r.left) / r.width;
    const next = Math.max(4, Math.min(96, x * 100));
    setPct(next);
  }, []);

  useEffect(() => {
    const move = (e) => {
      if (!dragging.current) return;
      const x = e.touches ? e.touches[0].clientX : e.clientX;
      setFromEvent(x);
    };
    const up = () => {dragging.current = false;document.body.style.cursor = "";};
    window.addEventListener("mousemove", move);
    window.addEventListener("touchmove", move, { passive: true });
    window.addEventListener("mouseup", up);
    window.addEventListener("touchend", up);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("touchmove", move);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchend", up);
    };
  }, [setFromEvent]);

  // gentle auto-nudge on first mount so users notice it's draggable
  useEffect(() => {
    const t1 = setTimeout(() => setPct(38), 900);
    const t2 = setTimeout(() => setPct(64), 2000);
    const t3 = setTimeout(() => setPct(52), 3100);
    return () => {clearTimeout(t1);clearTimeout(t2);clearTimeout(t3);};
  }, []);

  const onDown = (e) => {
    dragging.current = true;
    document.body.style.cursor = "ew-resize";
    const x = e.touches ? e.touches[0].clientX : e.clientX;
    setFromEvent(x);
  };

  return (
    <div className="ba" ref={wrapRef}
    style={{ "--clip": `${100 - pct}%`, "--handle": `${pct}%` }}
    onMouseDown={onDown} onTouchStart={onDown}>
      <div className="ba-stage" aria-hidden="true">
        <div className="ba-frame">
          <AvantMockup />
        </div>
      </div>
      <div className="ba-stage ba-clip">
        <div className="ba-frame">
          <ApresMockup />
        </div>
      </div>

      <div className="ba-label before">Avant</div>
      <div className="ba-label after">Après</div>

      <div className="ba-handle" style={{ left: `${pct}%` }}>
        <div className="ba-knob" aria-label="Slider before / after">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="9 18 3 12 9 6" />
            <polyline points="15 6 21 12 15 18" />
          </svg>
        </div>
      </div>

      <div className="ba-caption">Exemple fictif — refresh de présence en ligne</div>
    </div>);

}

// ─────────────────────────────────────────────────────────────────────────
// Sections

function Nav() {
  return (
    <nav className="nav">
      <div className="wrap nav-inner">
        <a href="#top" className="logo" aria-label="DB Design & Services">
          <div className="logo-mark"><span>DB</span></div>
          <div className="logo-word">
            <b>DB Design</b>
            <span>& Services</span>
          </div>
        </a>
        <div className="nav-links">
          <a href="#services">Services</a>
          <a href="#exemples">Exemples</a>
          <a href="#offres">Offres</a>
          <a href="#methode">Méthode</a>
          <a href="#a-propos">À propos</a>
        </div>
        <a href="#contact" className="btn btn-ghost btn-sm">
          Demander un diagnostic
          <span className="arrow" aria-hidden="true">→</span>
        </a>
      </div>
    </nav>);

}

function Hero() {
  return (
    <section className="hero" id="top">
      <div className="hero-bg" aria-hidden="true">
        <div className="layer then" />
        <div className="layer now" />
      </div>
      <div className="hero-wash" aria-hidden="true" />
      <div className="hero-grain" aria-hidden="true" />
      <div className="hero-era" aria-hidden="true">
        <span className="lbl">
          <span>Paris · 1900</span>
          <span>Paris · 2026</span>
        </span>
      </div>
      <div className="wrap hero-grid">
        <div className="hero-copy" style={{ opacity: "0.7" }}>
          <div className="eyebrow reveal"><span className="dot" />Design indépendant · Paris</div>
          <h1 className="reveal d1">
            Votre commerce est vivant. <em style={{ color: "rgb(196, 77, 36)" }}>Votre présence en ligne</em> doit le montrer.
          </h1>
          <p className="lead reveal d2">
            Pages vitrines, mises à jour visuelles et parcours client clairs pour
            restaurants, cafés, boutiques et commerces indépendants.
          </p>
          <div className="hero-ctas reveal d3">
            <a href="#contact" className="btn btn-primary">
              Demander un diagnostic
              <span className="arrow" aria-hidden="true">→</span>
            </a>
            <a href="#exemples" className="btn btn-ghost">
              Voir les exemples
            </a>
          </div>
          <div className="trust reveal d3">
            <span>Basé à Paris</span>
            <span>Design orienté utilisateur</span>
            <span>Marketing Croissance pragmatique</span>
            <span>Missions ponctuelles</span>
          </div>
        </div>

        <div className="reveal d2">
          <BeforeAfter />
        </div>
      </div>
    </section>);

}

function Problem() {
  const items = [
  "Infos pas toujours à jour",
  "Site peu lisible sur mobile",
  "Offre difficile à comprendre",
  "Photos anciennes ou peu représentatives",
  "Réservation/contact pas assez évident"];

  return (
    <section className="problem" id="probleme">
      <div className="wrap problem-grid">
        <div className="reveal">
          <div className="eyebrow"><span className="dot" />Le constat</div>
          <h2 style={{ marginTop: 18 }}>
            Vos clients vous découvrent <em style={{ fontStyle: "italic", color: "rgb(180, 97, 68)", fontWeight: 400 }}>avant même</em> de passer la porte.
          </h2>
          <p className="lead" style={{ marginTop: 22, maxWidth: 540 }}>Pour beaucoup, le premier contact passe par Google, Instagram, un QR code, un lien de réservation ou un site. Les photos sont anciennes ? L'offre peu claire ? Le chemin pour vous contacter confus ? L'expérience commence mal.



          </p>
        </div>
        <ul className="reveal d1">
          {items.map((t, i) =>
          <li key={i}>
              <span className="num">0{i + 1}</span>
              <span>{t}</span>
              <span className="dot" />
            </li>
          )}
        </ul>
      </div>
    </section>);

}

function Services() {
  const cards = [
  { idx: "S·01", title: "Page vitrine express", body: "Une page mobile claire avec vos infos essentielles, vos services, vos photos, vos liens de réservation/contact et votre QR code.", tag: "Livrée en 7–10 jours" },
  { idx: "S·02", title: "Mise à jour présence en ligne", body: "Audit rapide, textes corrigés, fiche Google, Instagram, site, menu ou services réalignés.", tag: "Audit + corrections" },
  { idx: "S·03", title: "Parcours client & conversion", body: "J'améliore les étapes entre « je vous découvre » et « je réserve / j'appelle / je viens ».", tag: "UX pratique" },
  { idx: "S·04", title: "Contenus prêts à publier", body: "Captions, textes courts, Google posts, idées photo et calendrier simple.", tag: "Sans abonnement" }];

  return (
    <section id="services">
      <div className="wrap">
        <div className="section-head reveal">
          <div className="eyebrow"><span className="dot" />Services</div>
          <h2>Des améliorations simples, <em style={{ fontStyle: "italic", color: "var(--gold-deep)", fontWeight: 400 }}>visibles et utiles.</em></h2>
        </div>
        <div className="services-grid">
          {cards.map((c, i) =>
          <div className={`service reveal d${i % 3}`} key={c.idx}>
              <div className="idx">{c.idx}</div>
              <h3>{c.title}</h3>
              <p>{c.body}</p>
              <div className="tag">{c.tag}</div>
            </div>
          )}
        </div>
      </div>
    </section>);

}

function Flow() {
  return (
    <section className="flow" id="pourquoi">
      <div className="wrap">
        <div className="section-head reveal">
          <div className="eyebrow"><span className="dot" />Pourquoi ça compte</div>
          <h2>Moins de confusion. <em style={{ fontStyle: "italic", color: "var(--gold-soft)", fontWeight: 400 }}>Plus d'actions utiles.</em></h2>
        </div>

        <div className="flow-diagram reveal d1">
          <div className="flow-node">
            <div className="lbl">Découverte</div>
            <div className="ttl">Le premier contact</div>
            <div className="items">
              <span>· Google</span>
              <span>· Instagram</span>
              <span>· QR code</span>
            </div>
          </div>
          <div className="flow-arrow">→</div>
          <div className="flow-node accent">
            <div className="lbl">Étape clé</div>
            <div className="ttl">Page claire</div>
            <div className="items">
              <span>· Infos à jour</span>
              <span>· Lisible mobile</span>
            </div>
          </div>
          <div className="flow-arrow">→</div>
          <div className="flow-node">
            <div className="lbl">Effet</div>
            <div className="ttl">Confiance</div>
            <div className="items">
              <span>· « C'est sérieux »</span>
              <span>· « Ça me parle »</span>
            </div>
          </div>
          <div className="flow-arrow">→</div>
          <div className="flow-node">
            <div className="lbl">Action</div>
            <div className="ttl">Réservation, appel, itinéraire</div>
            <div className="items">
              <span>· Le client passe à l'acte</span>
            </div>
          </div>
        </div>

        <p className="flow-note reveal d2">
          « Je ne promets pas de magie. Je rends simplement le parcours plus clair
          pour les personnes qui vous trouvent déjà. »
        </p>
      </div>
    </section>);

}

function Portfolio() {
  const cases = [
  {
    tone: "brasserie",
    img: "assets/case-brasserie.png",
    label: "Concept non officiel",
    title: "Brasserie rénovée",
    problem: "Le lieu a évolué, mais les photos, la carte et les informations en ligne ne reflètent pas encore clairement l'expérience actuelle.",
    solution: "Créer une page mobile claire, sélectionner les bons visuels, aligner les horaires et mettre en avant le lien de réservation.",
    objective: "Faire comprendre rapidement l'ambiance du lieu et faciliter la réservation, l'appel ou l'itinéraire.",
    deliverables: ["Page vitrine", "Fiche Google", "Photos sélectionnées", "QR code"]
  },
  {
    tone: "salon",
    img: "assets/case-salon.png",
    label: "Concept non officiel",
    title: "Salon indépendant",
    problem: "L'activité est visible sur Instagram, mais les prestations, les tarifs et le chemin vers la réservation ne sont pas assez clairs.",
    solution: "Créer une page intermédiaire simple entre Instagram et l'outil de réservation, avec les services, les prix indicatifs et les informations utiles.",
    objective: "Aider les visiteurs à comprendre l'offre rapidement et réduire les hésitations avant de réserver.",
    deliverables: ["Page de bio", "Réécriture services", "Captions modèles", "Calendrier light"]
  },
  {
    tone: "galerie",
    img: "assets/case-galerie.png",
    label: "Concept non officiel",
    title: "Galerie de quartier",
    problem: "Le programme d'expositions est difficile à suivre, les visiteurs demandent les informations en message privé, et la fiche Google reste peu active.",
    solution: "Créer une mini-page mensuelle facile à mettre à jour, préparer des Google Posts et ajouter un QR code en vitrine.",
    objective: "Rendre l'exposition en cours plus visible, faciliter la visite et réduire les questions répétitives.",
    deliverables: ["Mini-page mois", "Google posts", "QR vitrine", "Modèle vernissage"]
  }];

  return (
    <section id="exemples">
      <div className="wrap">
        <div className="section-head reveal">
          <div className="eyebrow"><span className="dot" />EXEMPLES FICTIFS</div>
          <h2>Des cas concrets, inspirés de commerces de quartier.</h2>
          <p className="lead muted" style={{ maxWidth: 640 }}>
            Exemples fictifs, créés pour montrer ma méthode : rendre une présence en ligne
            plus claire, plus actuelle et plus facile à utiliser.
          </p>
        </div>

        <div className="reveal d1">
          <CaseCarousel cases={cases} />
        </div>
      </div>
    </section>);

}

function Packages() {
  const packs = [
  {
    name: "Diagnostic",
    title: "Diagnostic express",
    price: "150 €",
    featured: false,
    items: [
    "Audit rapide site / Google / Instagram",
    "Problèmes prioritaires",
    "Recommandations concrètes",
    "Checklist prête à appliquer"]

  },
  {
    name: "Mise à jour",
    title: "Mise à jour présence en ligne",
    price: "290 €",
    featured: true,
    badge: "Le plus demandé",
    items: [
    "Textes corrigés",
    "Google / Instagram / site alignés",
    "CTA (Appel à l'action) améliorés",
    "Contenus prêts à publier"]

  },
  {
    name: "Page vitrine",
    title: "Page vitrine express",
    price: "390 €",
    featured: false,
    items: [
    "Page mobile simple",
    "Structure + rédaction",
    "Liens contact / réservation",
    "Google Maps + Instagram",
    "QR code",
    "Une série de retours incluse"]

  }];


  return (
    <section className="packages" id="offres">
      <div className="wrap">
        <div className="section-head reveal">
          <div className="eyebrow"><span className="dot" />Offres</div>
          <h2>Des offres simples, <em style={{ fontStyle: "italic", color: "var(--gold-deep)", fontWeight: 400 }}>sans engagement lourd.</em></h2>
        </div>

        <div className="pack-grid">
          {packs.map((p, i) =>
          <div className={`pack ${p.featured ? "featured" : ""} reveal d${i}`} key={p.title}>
              {p.badge && <div className="badge">{p.badge}</div>}
              <div className="pack-name">{p.name}</div>
              <h3>{p.title}</h3>
              <div className="pack-price">
                <span className="from">à partir de</span>{p.price}
              </div>
              <ul className="pack-list">
                {p.items.map((it) => <li key={it}>{it}</li>)}
              </ul>
              <a href="#contact" className={`btn ${p.featured ? "btn-gold" : "btn-ghost"}`} style={{ marginTop: "auto" }}>
                {p.featured ? "Commencer ici" : "En discuter"}
                <span className="arrow" aria-hidden="true">→</span>
              </a>
            </div>
          )}
        </div>

        <p className="pack-note reveal">
          « Les frais externes éventuels — hébergement, domaine, outil de site ou photos —
          sont toujours séparés et validés avant engagement. »
        </p>
      </div>
    </section>);

}

function Process() {
  const steps = [
  { n: "01", title: "Observation", body: "Je regarde votre site, vos réseaux, votre fiche Google et votre offre. Je note ce qui aide vos clients et ce qui les freine." },
  { n: "02", title: "Proposition", body: "Une recommandation courte, écrite simplement, avec un périmètre et un prix clairs avant tout engagement." },
  { n: "03", title: "Création", body: "Rédaction, mise en page, sélection des visuels, paramétrage. Je travaille en autonomie avec quelques points de validation." },
  { n: "04", title: "Validation", body: "Une série d'allers-retours incluse, avec des retours concrets — pas une chasse au pixel sans fin." },
  { n: "05", title: "Mise en ligne ou transmission", body: "Je publie, ou je vous transmets le tout avec une mini-doc d'utilisation pour rester autonome ensuite." }];

  return (
    <section id="methode">
      <div className="wrap">
        <div className="section-head reveal">
          <div className="eyebrow"><span className="dot" />Méthode</div>
          <h2>Une méthode <em style={{ fontStyle: "italic", color: "var(--gold-deep)", fontWeight: 400 }}>simple.</em></h2>
        </div>

        <div className="process-list reveal d1">
          {steps.map((s) =>
          <div className="process-step" key={s.n}>
              <div className="pnum">{s.n}</div>
              <h3>{s.title}</h3>
              <p>{s.body}</p>
            </div>
          )}
        </div>

        <div className="process-trust reveal d2">
          <div className="ico" aria-hidden="true">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
              <rect x="3" y="11" width="18" height="11" rx="2" />
              <path d="M7 11V7a5 5 0 0 1 10 0v4" />
            </svg>
          </div>
          <div>
            <strong style={{ fontWeight: 600, color: "var(--ink)" }}>Aucun mot de passe partagé.</strong>{" "}
            Si un accès est nécessaire, il se fait par invitation temporaire ou rôle collaborateur.
          </div>
        </div>
      </div>
    </section>);

}

function About() {
  return (
    <section className="about" id="a-propos">
      <div className="wrap about-grid">
        <div className="portrait reveal">
          <img src="assets/portrait.png" alt="Daniel Blokbergen — portrait" />
          <div className="portrait-badge">Disponible · Paris</div>
          <div className="portrait-cap">Daniel Blokbergen</div>
        </div>
        <div className="about-copy reveal d1">
          <div className="eyebrow"><span className="dot" />À propos</div>
          <h2 style={{ marginTop: 18 }}>
            Daniel Blokbergen — <em>design, organisation et sens du client.</em>
          </h2>
          <p>Je viens du design industriel, de la gestion de projet et des opérations terrain. Je m'intéresse particulièrement à la valorisation des petites et moyennes entreprises locales, grâce aux dernières techniques de marketing de croissance et à un design centré sur l'humain et rendre leur présence en ligne plus claire et plus efficace.



          </p>
          <p>Mon approche est simple : comprendre le client final, organiser l'information, et augmenter la visibilité par des supports propres, utiles et faciles à utiliser.


          </p>

          <div className="about-meta">
            <div><span className="k">Basé à</span><span className="v">Paris</span></div>
            <div><span className="k">Disponible</span><span className="v">Missions ponctuelles</span></div>
            <div><span className="k">Langues</span><span className="v">FR · EN · IT · NL · ES </span></div>
          </div>
        </div>
      </div>
    </section>);

}

function Final() {
  return (
    <section className="final" id="contact">
      <div className="wrap reveal">
        <div className="eyebrow" style={{ color: "var(--gold-soft)" }}><span className="dot" />Et maintenant</div>
        <h2 style={{ marginTop: 18 }}>
          Votre présence en ligne <em>ne reflète plus</em> vraiment votre lieu&nbsp;?
        </h2>
        <p>
          Envoyez-moi votre site, Instagram ou fiche Google. Je vous dirai rapidement
          s'il y a quelque chose de concret à améliorer.
        </p>
        <div className="final-ctas">
          <a className="btn btn-primary" href="mailto:bonjour@dbdesign.pro">
            Demander un diagnostic
            <span className="arrow" aria-hidden="true">→</span>
          </a>
          <a className="btn btn-ghost" href="mailto:bonjour@dbdesign.pro">
            Me contacter
          </a>
        </div>
        <div className="final-meta">
          <span>Réponse sous 48 h ouvrées</span>
          <span>Premier échange offert · 20 min</span>
          <span>Paris &amp; visio</span>
        </div>
      </div>
    </section>);

}

function Footer() {
  return (
    <footer className="foot">
      <div className="wrap">
        <span>© 2026 DB Design &amp; Services · Daniel Blokbergen</span>
        <span style={{ display: "inline-flex", gap: 18 }}>
          <a href="mailto:bonjour@dbdesign.pro">bonjour@dbdesign.pro</a>
          <a href="#a-propos">À propos</a>
          <a href="#offres">Offres</a>
        </span>
      </div>
    </footer>);

}

// ─────────────────────────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useReveal();

  // Apply tweak values as CSS variables
  useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty("--gold", t.accent);
    // derive a soft + deep version of the accent
    root.style.setProperty("--gold-soft", mixWithWhite(t.accent, 0.35));
    root.style.setProperty("--gold-deep", mixWithBlack(t.accent, 0.28));
    root.style.setProperty("--bg", t.bgTone);
    root.style.setProperty("--bg-soft", t.softTone);
    root.style.setProperty("--serif", `"${t.headlineFont}", "EB Garamond", Georgia, serif`);
  }, [t.accent, t.bgTone, t.softTone, t.headlineFont]);

  return (
    <React.Fragment>
      <Nav />
      <Hero />
      <Problem />
      <Services />
      <Flow />
      <Portfolio />
      <Packages />
      <Process />
      <About />
      <Final />
      <Footer />

      <TweaksPanel>
        <TweakSection label="Couleur d'accent" />
        <TweakColor
          label="Accent"
          value={t.accent}
          options={ACCENT_OPTIONS}
          onChange={(v) => setTweak("accent", v)} />
        
        <TweakSection label="Tons de fond" />
        <TweakColor
          label="Palette"
          value={[t.bgTone, t.softTone]}
          options={BG_PALETTES}
          onChange={(v) => setTweak({ bgTone: v[0], softTone: v[1] })} />
        
        <TweakSection label="Typographie" />
        <TweakSelect
          label="Police titres"
          value={t.headlineFont}
          options={HEADLINE_FONTS}
          onChange={(v) => setTweak("headlineFont", v)} />
        
      </TweaksPanel>
    </React.Fragment>);

}

// Color helpers ───────────────────────────────────────────────────────────
function hexToRgb(h) {
  const s = h.replace("#", "");
  return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
}
function rgbToHex(r, g, b) {
  return "#" + [r, g, b].map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0")).join("");
}
function mixWithWhite(hex, amt) {
  const [r, g, b] = hexToRgb(hex);
  return rgbToHex(r + (255 - r) * amt, g + (255 - g) * amt, b + (255 - b) * amt);
}
function mixWithBlack(hex, amt) {
  const [r, g, b] = hexToRgb(hex);
  return rgbToHex(r * (1 - amt), g * (1 - amt), b * (1 - amt));
}

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