// femme-app.jsx — Daniéle laser landing, Femme-style layout
// All sections in one file (kept ≤500 lines).

const F_PALETTES = {
  // Brand palette sampled from danielelaserandaesthetics.com — bronze #826409, gold #E0AA3E,
  // warm sand #E7E3E0, olive-grey #8A8574 (logo field).
  daniele: { label: 'Daniéle — Bronze & Sand', swatch: ['#E7E3E0', '#36322D', '#826409'],
    vars: { '--bg': '#E7E3E0', '--bg-2': '#8A8574', '--ink': '#36322D', '--ink-soft': '#5d564e',
      '--accent': '#826409', '--accent-light': '#E0AA3E', '--btn-brown': '#826409',
      '--line': 'rgba(54,50,45,0.14)', '--line-strong': 'rgba(54,50,45,0.28)',
      '--paper': '#FFFFFF', '--shadow': '0 30px 60px -30px rgba(54,50,45,0.22)' } },
  cream: { label: 'Cream & Cocoa', swatch: ['#F5EFE6', '#3D2817', '#8B6B4F'],
    vars: { '--bg': '#F5EFE6', '--bg-2': '#ECE3D4', '--ink': '#3D2817', '--ink-soft': '#6B5440',
      '--accent': '#8B6B4F', '--line': 'rgba(61,40,23,0.14)', '--line-strong': 'rgba(61,40,23,0.28)',
      '--paper': '#FBF7EF', '--shadow': '0 30px 60px -30px rgba(61,40,23,0.25)' } },
  sand: { label: 'Sand & Olive', swatch: ['#F0EAE0', '#3F4429', '#7A7256'],
    vars: { '--bg': '#F0EAE0', '--bg-2': '#E3DBCC', '--ink': '#3F4429', '--ink-soft': '#6B6849',
      '--accent': '#7A7256', '--line': 'rgba(63,68,41,0.14)', '--line-strong': 'rgba(63,68,41,0.28)',
      '--paper': '#F7F2E9', '--shadow': '0 30px 60px -30px rgba(63,68,41,0.22)' } },
  blush: { label: 'Blush & Plum', swatch: ['#F4E8E5', '#3A1F2B', '#9A6B73'],
    vars: { '--bg': '#F4E8E5', '--bg-2': '#EAD8D2', '--ink': '#3A1F2B', '--ink-soft': '#6E5158',
      '--accent': '#9A6B73', '--line': 'rgba(58,31,43,0.14)', '--line-strong': 'rgba(58,31,43,0.26)',
      '--paper': '#FAF1EE', '--shadow': '0 30px 60px -30px rgba(58,31,43,0.22)' } },
  ivory: { label: 'Ivory & Ink', swatch: ['#F0EFEB', '#1B1B1A', '#5C5C58'],
    vars: { '--bg': '#F0EFEB', '--bg-2': '#E1DFD9', '--ink': '#1B1B1A', '--ink-soft': '#56564F',
      '--accent': '#5C5C58', '--line': 'rgba(27,27,26,0.12)', '--line-strong': 'rgba(27,27,26,0.25)',
      '--paper': '#F8F7F3', '--shadow': '0 30px 60px -30px rgba(27,27,26,0.2)' } }
};

const F_FONTS = {
  // Headings keep the template's Cormorant; body uses Montserrat from the client's
  // own site (danielelaserandaesthetics.com).
  daniele: { label: 'Cormorant + Montserrat',
    display: "'Cormorant Garamond', Georgia, serif", body: "'Montserrat', ui-sans-serif, system-ui, sans-serif" },
  cormorant: { label: 'Cormorant + Manrope',
    display: "'Cormorant Garamond', Georgia, serif", body: "'Manrope', ui-sans-serif, system-ui, sans-serif" },
  bodoni: { label: 'Bodoni + Outfit',
    display: "'Bodoni Moda', Georgia, serif", body: "'Outfit', ui-sans-serif, system-ui, sans-serif" },
  italiana: { label: 'Italiana + Jakarta',
    display: "'Italiana', Georgia, serif", body: "'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif" }
};

const F_TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "daniele",
  "fonts": "daniele"
} /*EDITMODE-END*/;

// ─────── Gift card bar (mirrors the top bar on danielelaserandaesthetics.com) ───────
// Gift cards are sold through the client's Boulevard booking system, same link as their site.
const F_GIFT_CARD_URL = 'https://blvd.me/aniele-laser-and-aesthetics/gift-cards';

function FGiftBar() {
  return (
    <div className="giftbar">
      <span className="giftbar-text">Gift yourself or anyone with a luxury experience.</span>
      <a
        href={F_GIFT_CARD_URL}
        className="giftbar-cta"
        target="_blank"
        rel="noopener noreferrer"
      >
        Get your gift card here
      </a>
    </div>);

}

// ─────── Nav ───────
function FNav() {
  React.useEffect(() => {
    const onScroll = () => document.querySelector('.nav')?.classList.toggle('scrolled', window.scrollY > 24);
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  const [menuOpen, setMenuOpen] = React.useState(false);
  React.useEffect(() => {
    document.body.style.overflow = menuOpen ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [menuOpen]);
  const links = [
    { href: 'index.html', label: 'Home' },
    { href: 'about-us.html', label: 'About Us' },
    { href: 'laser-hair-removal.html', label: 'Laser Hair Removal' },
    { href: 'aesthetic-treatments.html', label: 'Aesthetic Treatments' },
    { href: 'contact-us.html', label: 'Contact Us' },
    { href: F_GIFT_CARD_URL, label: 'Gift Cards', external: true },
  ];
  const ext = (l) => (l.external ? { target: '_blank', rel: 'noopener' } : {});
  // Highlight the page we're on. Cloudflare serves both /about-us and /about-us.html,
  // and home is '/', so compare on a normalized slug (filename without .html; '' → index).
  const slugOf = (href) => ((href.split(/[?#]/)[0].split('/').pop() || 'index').replace(/\.html$/, '') || 'index');
  const currentSlug = slugOf(window.location.pathname);
  const isActive = (l) => !l.external && slugOf(l.href) === currentSlug;
  return (
    <>
    <nav className="nav">
      <a href="index.html" className="logo" aria-label="Daniéle Laser + Aesthetics — home">
        <img src="images/daniele/footer-logo-new.png" alt="Daniéle Laser + Aesthetics" />
      </a>
      <ul className="nav-menu">
        {links.map((l) => (
          <li key={l.href} className="nav-item"><a href={l.href} {...ext(l)} className={isActive(l) ? 'active' : undefined} aria-current={isActive(l) ? 'page' : undefined}>{l.label}</a></li>
        ))}
      </ul>
      <div className="nav-right">
        <a href="#book" className="nav-cta" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book &amp; Glow</a>
        <button
          type="button"
          className={`nav-burger ${menuOpen ? 'on' : ''}`}
          aria-label="Menu"
          aria-expanded={menuOpen}
          onClick={() => setMenuOpen(o => !o)}
        >
          <span></span><span></span>
        </button>
      </div>
      <div className={`nav-drawer ${menuOpen ? 'on' : ''}`} onClick={() => setMenuOpen(false)}>
        <div className="nav-drawer-panel" onClick={(e) => e.stopPropagation()}>
          <button type="button" className="nav-drawer-close" aria-label="Close menu" onClick={() => setMenuOpen(false)}>×</button>
          <ul>
            {links.map((l) => (
              <li key={l.href}><a href={l.href} {...ext(l)} className={isActive(l) ? 'active' : undefined} aria-current={isActive(l) ? 'page' : undefined} onClick={() => setMenuOpen(false)}>{l.label}</a></li>
            ))}
          </ul>
          <a href="#book" className="btn nav-drawer-cta" onClick={(e) => { e.preventDefault(); setMenuOpen(false); openBooking(); }}>Book &amp; Glow</a>
        </div>
      </div>
    </nav>
    <FBookingHost />
    </>);

}

// ─────── Rotating circle button (Femme signature) ───────
function RotateButton({ children, label = 'Book · Today · Now · ', href = '#contact' }) {
  const ref = useMagnet(0.15);
  return (
    <a href={href} className="btn-rotate">
      <span ref={ref} className="ring">
        <IconArrowUpRight size={20} sw={1.5} />
        <svg className="rotating-text" viewBox="0 0 60 60">
          <defs>
            <path id="rt-circle" d="M 30,30 m -22,0 a 22,22 0 1,1 44,0 a 22,22 0 1,1 -44,0" />
          </defs>
          <text>
            <textPath href="#rt-circle">{label.repeat(3)}</textPath>
          </text>
        </svg>
      </span>
      {children}
    </a>);

}

// ─────── HERO (Femme-style with marquee top, welcome bottom-left, pill grid bottom-right) ───────
function FHero() {
  return (
    <section className="hero">
      <div className="hero-marquee" aria-hidden="true">
        <div className="hero-marquee-track">
          {Array.from({ length: 8 }).map((_, i) =>
          <span key={i} className="hero-marquee-item">
              {['Laser hair removal', 'Smoother skin'][i % 2]} <span className="dot">✦</span>{" "}
            </span>
          )}
        </div>
      </div>
      <div className="hero-bg">
        <HeroSlider />
      </div>
      <div className="hero-bottom">
        <div className="hero-welcome">
          <span className="hero-welcome-eyebrow">— Welcome to Daniéle:</span>
          <p className="hero-welcome-body">
            Luxury laser hair removal on the newest Candela GentleMax Pro — safe and effective for every skin tone, delivered by licensed specialists who never rush your hour.
          </p>
        </div>
        <div className="hero-pills">
          <a href="#faq" className="hero-pill">Expert advice</a>
          <a href="#results" className="hero-pill">Gallery</a>
          <a href="#calculator" className="hero-pill">Pricing</a>
          <a href="#testimonials" className="hero-pill">Reviews</a>
          <a href="#services" className="hero-pill">Services</a>
          <a href="#contact" className="hero-pill">Support</a>
        </div>
      </div>
    </section>);

}

// ─────── Hero auto-cross-fade slider ───────
function HeroSlider() {
  const slides = [
    'images/daniele/aesthetic-banner.png',
    'images/daniele/hero-banner.jpg',
  ];
  const [active, setActive] = React.useState(0);
  React.useEffect(() => {
    if (slides.length < 2) return;
    const id = setInterval(() => setActive(a => (a + 1) % slides.length), 8000);
    return () => clearInterval(id);
  }, []);
  return (
    <div className="hero-slider">
      {slides.map((src, i) => (
        <img
          key={src}
          src={src}
          alt=""
          className={"hero-slide" + (i === active ? " on" : "")}
          aria-hidden={i === active ? "false" : "true"}
        />
      ))}
    </div>
  );
}

// ─────── Statement (centered sticky heading + chaotic floating cards) ───────
function FStatement() {
  const benefits = [
  { n: '01', t: 'Lasting smoothness', body: '80–95% reduction after a six-session course.',
    meta: 'Up to 95%', icon: IconSparkle,
    pos: { top: '3%', left: '0%' }, parallax: 0.06, rotate: -5, fromX: -40, fromY: 80 },
  { n: '02', t: 'Kinder to your skin', body: 'No ingrown hairs, no nicks, no razor rash.',
    meta: 'Zero ingrowns', icon: IconLeaf,
    pos: { top: '12%', right: '10%' }, parallax: -0.08, rotate: 6, fromX: 40, fromY: 80 },
  { n: '03', t: 'Every skin tone', body: 'Alexandrite and Nd:YAG in one system — we tune the wavelength to your skin and hair.',
    meta: 'Alex + Nd:YAG', icon: IconCompass,
    pos: { top: '36%', left: '12%' }, parallax: 0.09, rotate: 4, fromX: -30, fromY: 100 },
  { n: '04', t: 'Dynamic cooling', body: 'The GentleMax Pro cools your skin with every pulse, so sensitive areas stay comfortable.',
    meta: 'Cooling built in', icon: IconDrop,
    pos: { top: '50%', right: '0%' }, parallax: -0.07, rotate: -3, fromX: 50, fromY: 90 },
  { n: '05', t: 'Never one-size-fits-all', body: 'Thorough consultation, patch testing where needed, progress monitored every visit.',
    meta: 'Made for you', icon: IconClock,
    pos: { top: '72%', left: '1%' }, parallax: 0.05, rotate: -4, fromX: -20, fromY: 110 },
  { n: '06', t: 'Licensed specialists', body: 'Certified laser specialists with extensive experience across every skin tone.',
    meta: 'Senior-level team', icon: IconShield,
    pos: { top: '84%', right: '11%' }, parallax: -0.06, rotate: 5, fromX: 30, fromY: 80 }];

  return (
    <section id="statement" className="statement">
      <div className="statement-cards-fall">
        {benefits.map((b, i) => <BenefitCard key={b.n} {...b} index={i} />)}
      </div>
      <div className="statement-middle">
        <div className="statement-sticky">
          <span className="eyebrow">The Daniéle promise</span>
          <h2 className="h-display">
            Laser care, quietly <span className="ny">calibrated</span> to your unique skin and the rhythm of life you'd rather be living.
          </h2>
          <div className="statement-thumbs">
            <div className="statement-thumb-fan">
              <div className="statement-thumb"><img src="images/daniele/laser-img.png" alt="" /></div>
              <div className="statement-thumb"><img src="images/daniele/bikini.jpg" alt="" /></div>
              <div className="statement-thumb"><img src="images/daniele/laser-treatment.jpg" alt="" /></div>
            </div>
            <span className="statement-thumb-count"><strong>20,000+</strong> treatments performed</span>
          </div>
        </div>
      </div>
    </section>);

}

function BenefitCard({ n, t, body, meta, icon: Icon, index, parallax, rotate, fromX, fromY, pos }) {
  const [inRef, inView] = useInView({ threshold: 0.15 });
  const parRef = useParallax(parallax);
  const setRef = (el) => {inRef.current = el;parRef.current = el;};
  return (
    <div ref={setRef} className="benefit-wrap" style={pos}>
      <article
        className={`benefit ${inView ? 'in' : ''}`}
        style={{
          '--enter-rot': `${rotate}deg`,
          '--enter-x': `${fromX}px`,
          '--enter-y': `${fromY}px`
        }}>
        
        <div className="benefit-inner">
          <span className="benefit-icon" aria-hidden="true"><Icon size={20} sw={1.4} /></span>
          <h3 className="benefit-t h-display">{t}</h3>
          <p className="benefit-body">{body}</p>
          <span className="benefit-meta">{meta}</span>
        </div>
      </article>
    </div>);

}

// ─────── Tabbed services ───────
const F_SERVICES = [
{ n: '01', t: 'Face Laser', body: "Upper lip, chin, jawline, full face. Quiet sessions on a 4–6 week rhythm, calibrated to your skin tone each visit.",
  img: 'images/daniele/services-bg-1.png', price: 35 },
{ n: '02', t: 'Body Smooth', body: "Underarms, arms, legs — our most-requested course. Six sessions delivers 80–95% permanent reduction.",
  img: 'images/daniele/laser-img.png', price: 65 },
{ n: '03', t: 'Bikini & Brazilian', body: "Discreet, considered care with cooling on every pulse. One of the most popular areas we treat.",
  img: 'images/daniele/bikini.jpg', price: 85 },
{ n: '04', t: 'Concierge Full-Body', body: "Whole-body course across the year, with concierge scheduling, dedicated practitioner, and complimentary aftercare.",
  img: 'images/daniele/hero-banner.jpg', price: 380 }];


function FServices() {
  const [tab, setTab] = React.useState(0);
  return (
    <section id="services" className="services">
      <div className="container">
        <div className="services-head">
          <div>
            <span className="eyebrow">Laser services</span>
            <h2 className="h-display">
              Four <span className="i">considered</span> ways to begin a course.
            </h2>
          </div>
          <a href="contact-us.html" className="btn" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book a service</a>
        </div>
        <div className="services-row">
          <div className="services-tabs">
            {F_SERVICES.map((s, i) =>
            <div key={i} className={`tab ${tab === i ? 'on' : ''}`} onClick={() => setTab(i)}>
                <div className="tab-n">{s.n}</div>
                <div className="tab-main">
                  <div className="tab-title h-display">{s.t}</div>
                  <div className="tab-body">{s.body}</div>
                </div>
                <div className="tab-arrow"><IconArrowUpRight size={16} sw={1.5} /></div>
                <div className="tab-img">
                  <img src={s.img} alt={`${s.t} — laser hair removal at Daniéle`} loading="lazy" />
                  <span className="price-tag"><small>from</small>${s.price}</span>
                </div>
              </div>
            )}
          </div>
          <div className="services-img">
            {F_SERVICES.map((s, i) =>
            <div key={i} className={`services-img-card ${tab === i ? 'on' : ''}`}>
                <img src={s.img} alt={`${s.t} — laser hair removal at Daniéle`} />
                <span className="price-tag"><small>from</small>${s.price}</span>
              </div>
            )}
          </div>
        </div>
      </div>
    </section>);

}

// ─────── Word marquee (Femme signature) ───────
function FWordMarquee({ tone }) {
  const words = ['Quietly', 'Smooth', 'Confident', 'Refined', 'Magnetic', 'Effortless'];
  const dup = [...words, ...words];
  return (
    <div className={`word-marquee${tone ? ` word-marquee--${tone}` : ''}`}>
      <div className="word-marquee-track">
        {dup.map((w, i) =>
        <span key={i} className="word-marquee-item">{w}</span>
        )}
      </div>
    </div>);

}

// ─────── Service cards ───────
// ─────── Build your course (calculator) ───────
// Each package covers up to F_MAX_PER_TIER areas from a single tier at a flat price.
// Selecting areas across tiers stacks one package per tier.
const F_TIERS = [
  { id: 'small',  label: 'Small',   price: 299 },
  { id: 'medium', label: 'Medium',  price: 499 },
  { id: 'large',  label: 'Large',   price: 599 },
  { id: 'xlarge', label: 'X-Large', price: 699 },
];
const F_MAX_PER_TIER = 6;
// Mix + match: any areas from any category, priced by how many you pick (client, 2026-07-17).
const F_MIX = [
  { count: 2, price: 699 },
  { count: 3, price: 799 },
  { count: 4, price: 899 },
];
const F_MIX_MIN = F_MIX[0].count;
const F_MIX_MAX = F_MIX[F_MIX.length - 1].count;
const F_AREAS = [
  { id: 'areolas',      name: 'Areolas',        tier: 'small' },
  { id: 'butt-strip',   name: 'Buttocks strip', tier: 'small' },
  { id: 'chin',         name: 'Chin',           tier: 'small' },
  { id: 'ears',         name: 'Ears',           tier: 'small' },
  { id: 'eyebrows',     name: 'Eyebrows',       tier: 'small' },
  { id: 'feet',         name: 'Feet',           tier: 'small' },
  { id: 'hairline',     name: 'Hairline',       tier: 'small' },
  { id: 'hands',        name: 'Hands',          tier: 'small' },
  { id: 'happy-trail',  name: 'Happy trail',    tier: 'small' },
  { id: 'jawline',      name: 'Jawline',        tier: 'small' },
  { id: 'nose',         name: 'Nose',           tier: 'small' },
  { id: 'sideburns',    name: 'Sideburns',      tier: 'small' },
  { id: 'upper-lip',    name: 'Upper lip',      tier: 'small' },

  { id: 'buttocks',     name: 'Buttocks',       tier: 'medium' },
  { id: 'chest',        name: 'Chest',          tier: 'medium' },
  { id: 'face',         name: 'Face',           tier: 'medium' },
  { id: 'underarms',    name: 'Underarms',      tier: 'medium' },
  { id: 'inner-thighs', name: 'Inner thighs',   tier: 'medium' },

  { id: 'head',         name: 'Head',           tier: 'large' },
  { id: 'lower-legs',   name: 'Lower legs',     tier: 'large' },
  { id: 'upper-legs',   name: 'Upper legs',     tier: 'large' },
  { id: 'brazilian',    name: 'Brazilian',      tier: 'large' },
  { id: 'shoulders',    name: 'Shoulders',      tier: 'large' },
  { id: 'lower-arms',   name: 'Lower arms',     tier: 'large' },
  { id: 'upper-arms',   name: 'Upper arms',     tier: 'large' },
  { id: 'abs',          name: 'Abs',            tier: 'large' },
  { id: 'half-back',    name: 'Half back',      tier: 'large' },
  { id: 'full-face',    name: 'Full face',      tier: 'large' },
  { id: 'lower-back',   name: 'Lower back',     tier: 'large' },
  { id: 'upper-back',   name: 'Upper back',     tier: 'large' },
  { id: 'half-abdomen', name: 'Half abdomen',   tier: 'large' },

  { id: 'full-legs',    name: 'Full legs',      tier: 'xlarge' },
  { id: 'full-back',    name: 'Full back',      tier: 'xlarge' },
  { id: 'full-abdomen', name: 'Full abdomen',   tier: 'xlarge' },
  { id: 'full-chest',   name: 'Full chest',     tier: 'xlarge' },
  { id: 'full-arms',    name: 'Full arms',      tier: 'xlarge' },
];
// Locations, phone, hours and map embed all taken from danielelaserandaesthetics.com/contact-us
const F_LOCATIONS = [
  { id: 'friendswood', name: 'Friendswood',
    address: '1769 S. Friendswood Dr. Suite 113, Friendswood, TX 77546',
    email: 'corporate@danielefriendswood.com',
    hours: 'Mon–Fri 10–7 · Sat 10–5 · Sun closed',
    mapUrl: 'https://maps.app.goo.gl/AWyeh7J67v6qRwMY8' },
  // Second studio in Cypress, TX — opens Aug 12. `opening` renders a badge everywhere the location is listed.
  { id: 'cypress', name: 'Cypress',
    address: '20049 House Hahl Rd. Suite 113, Cypress, TX 77433',
    email: 'corporate@danielecypress.com',
    hours: 'Wed–Fri 10–7 · Sat 10–5 · Sun closed',
    opening: 'Opens Aug 12',
    mapUrl: 'https://www.google.com/maps/search/?api=1&query=20049+House+Hahl+Rd+Suite+113+Cypress+TX+77433' },
];
const F_PHONE = '(281) 612-2073';
const F_INSTAGRAM = 'https://www.instagram.com/danielelaserandaesthetics/';
const F_FACEBOOK = 'https://www.facebook.com/profile.php?id=61561791801373';
const F_MAP_EMBED = 'https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d3472.3198881230796!2d-95.1879451!3d29.5070337!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x86409ad58cd67a63%3A0xe976b01a950a7fcd!2s1769%20S%20Friendswood%20Dr%2C%20Friendswood%2C%20TX%2077546%2C%20USA!5e0!3m2!1sen!2sin!4v1719391444880!5m2!1sen!2sin';

// ─────── Form delivery ───────
// Real server-side email via Web3Forms (free, works on a static site — no backend).
// Each studio has its OWN access key so the request lands in that location's inbox,
// routed by the customer's location choice. To activate: go to https://web3forms.com,
// enter corporate@danielefriendswood.com to get one key and corporate@danielecypress.com
// to get another, then paste them below. Until the keys are set the forms fall back to a
// mailto so nothing is broken.
const F_WEB3_KEYS = {
  friendswood: 'ca93e4ae-5742-4a15-8e77-e483bccefb68',
  cypress: 'ede1f728-b79b-487c-891f-ced35e1fb893',
};

async function deliverBooking({ locationId, name, email, phone, subject, message }) {
  const loc = F_LOCATIONS.find(l => l.id === locationId) || F_LOCATIONS[0];
  const key = F_WEB3_KEYS[loc.id];
  if (key && !key.startsWith('YOUR_')) {
    const res = await fetch('https://api.web3forms.com/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
      body: JSON.stringify({
        access_key: key,
        subject,
        from_name: 'Daniéle Website',
        replyto: email || '',
        name: name || '',
        email: email || '',
        phone: phone || '',
        message,
      }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok || !data.success) throw new Error(data.message || 'Submission failed');
    return 'sent';
  }
  // Fallback until the Web3Forms keys are in place — opens the user's mail client.
  window.location.href = `mailto:${loc.email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(message)}`;
  return 'mailto';
}

function FBookingModal({ onClose, quote }) {
  const [sent, setSent] = React.useState(false);
  const [error, setError] = React.useState(false);
  const [location, setLocation] = React.useState(F_LOCATIONS[0].id);
  const [service, setService] = React.useState('consult');
  const [form, setForm] = React.useState({ name: '', email: '', phone: '', date: '', notes: '' });
  const items = quote ? quote.items : [];
  const lines = quote ? quote.lines : [];
  const total = quote ? quote.price : 0;
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
  }, []);
  const set = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  // Route the booking to the chosen location's own inbox via Web3Forms (mailto fallback).
  const submit = async (e) => {
    e.preventDefault();
    const loc = F_LOCATIONS.find(l => l.id === location);
    const areaLines = lines.map(l => `  • ${l.name} — ${l.tierLabel} package (6 sessions), $${l.price}`).join('\n');
    const body = [
      `${quote ? 'New course reservation' : 'New booking request'} — ${loc.name}`,
      '',
      `Name:  ${form.name}`,
      `Email: ${form.email}`,
      `Phone: ${form.phone || '—'}`,
      `Preferred date: ${form.date || '—'}`,
      '',
      quote ? 'Selected areas:' : 'Requested:',
      quote
        ? (areaLines || '  —')
        : `  • ${service === 'consult' ? 'Free consultation' : service}`,
      '',
      quote
        ? (quote.kind === 'mix'
            ? `Pricing: Mix + match, any ${items.length} areas — $${total} (saves $${quote.saving})`
            : `Estimated total: $${total}`)
        : 'No course selected yet — happy to advise at the consultation.',
      '',
      form.notes ? `Notes: ${form.notes}` : '',
    ].join('\n');
    const subject = quote ? `Course reservation — ${loc.name}` : `Booking request — ${loc.name}`;
    try {
      await deliverBooking({ locationId: loc.id, name: form.name, email: form.email, phone: form.phone, subject, message: body });
      setSent(true);
    } catch (err) {
      setError(true);
    }
  };

  const loc = F_LOCATIONS.find(l => l.id === location);
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal modal--split" role="dialog" aria-modal="true" onClick={(e) => e.stopPropagation()}>
        <button type="button" className="modal-close" onClick={onClose} aria-label="Close">×</button>
        <div className="modal-media" aria-hidden="true"><img src="images/daniele/bikini.jpg" alt="" /></div>
        <div className="modal-inner">
        {sent ? (
          <div className="modal-done">
            <span className="eyebrow">Reservation sent</span>
            <h3 className="modal-h">On its way to <span className="i">{loc.name}.</span></h3>
            <p className="modal-done-p">Your request has been addressed to our {loc.name} studio ({loc.email}). A Daniéle practitioner will confirm your consultation and course, usually within the hour.</p>
            <button type="button" className="btn" onClick={onClose}>Close</button>
          </div>
        ) : (
          <>
            <span className="eyebrow">{quote ? 'Reserve your course' : 'Book your visit'}</span>
            <h3 className="modal-h">Book my <span className="i">{quote ? 'course.' : 'visit.'}</span></h3>
            {quote ? (
              <div className="modal-summary">
                <div className="modal-summary-row"><span>Areas</span><span>{items.map(a => a.name).join(', ') || '—'}</span></div>
                <div className="modal-summary-row"><span>{quote.kind === 'mix' ? 'Mix + match' : 'Packages'}</span><span>{quote.label}</span></div>
                <div className="modal-summary-row modal-summary-total"><span>Estimated total</span><span>${total.toLocaleString()}</span></div>
              </div>
            ) : (
              <label className="modal-field modal-service">
                <span>What would you like to book?</span>
                <select value={service} onChange={(e) => setService(e.target.value)}>
                  <option value="consult">A free consultation</option>
                  {F_SERVICES.map(s => <option key={s.t} value={s.t}>{s.t}</option>)}
                </select>
              </label>
            )}
            <form className="modal-form" onSubmit={submit}>
              <label className="modal-field"><span>Full name</span><input type="text" required placeholder="Your name" value={form.name} onChange={set('name')} /></label>
              <label className="modal-field"><span>Email</span><input type="email" required placeholder="your@email.com" value={form.email} onChange={set('email')} /></label>
              <label className="modal-field"><span>Phone</span><input type="tel" placeholder="(___) ___-____" value={form.phone} onChange={set('phone')} /></label>
              <label className="modal-field">
                <span>Location</span>
                <select required value={location} onChange={(e) => setLocation(e.target.value)}>
                  {F_LOCATIONS.map(l => <option key={l.id} value={l.id}>{l.name}{l.opening ? ` (${l.opening})` : ''}</option>)}
                </select>
              </label>
              <label className="modal-field"><span>Preferred date</span><input type="date" className="date-input" min={new Date().toISOString().split('T')[0]} value={form.date} onChange={set('date')} /></label>
              <label className="modal-field modal-field--full"><span>Anything we should know?</span><textarea rows="2" placeholder="Optional — sensitivities, questions, timing" value={form.notes} onChange={set('notes')}></textarea></label>
              <button type="submit" className="btn modal-submit">Send to {loc.name}</button>
              {error && <p className="modal-error" role="alert">Something went wrong sending your request. Please call us at {F_PHONE} or try again.</p>}
            </form>
          </>
        )}
        </div>
      </div>
    </div>
  );
}

// ─────── Global booking popup ───────
// Any CTA on any page calls openBooking(quote?) to open the shared booking form. A single
// FBookingHost (mounted once inside FNav, which every page renders) listens for the event,
// so every "Book a consultation" button opens the popup form instead of navigating away.
// quote is optional — the pricing builder passes its selection; everyone else passes none.
function openBooking(quote) {
  window.dispatchEvent(new CustomEvent('daniele:book', { detail: { quote: quote || null } }));
}

function FBookingHost() {
  const [state, setState] = React.useState({ open: false, quote: null });
  React.useEffect(() => {
    const onOpen = (e) => setState({ open: true, quote: (e.detail && e.detail.quote) || null });
    window.addEventListener('daniele:book', onOpen);
    return () => window.removeEventListener('daniele:book', onOpen);
  }, []);
  if (!state.open) return null;
  return <FBookingModal quote={state.quote} onClose={() => setState({ open: false, quote: null })} />;
}

const F_TIER_PRICE = F_TIERS.reduce((m, t) => { m[t.id] = t; return m; }, {});

// Correct model (confirmed by the client + their own "$199 for a package of 6" graphic):
// each AREA is its own package of 6 sessions, priced by that area's size tier. Buying
// several areas normally sums those package prices — UNLESS mix + match (a flat price by
// area count, any category) is cheaper, in which case the studio charges that. We quote
// the lower of the two so we never overcharge.
function quoteFor(selected) {
  const items = F_AREAS.filter(a => selected.includes(a.id));
  if (!items.length) return null;

  const lines = items.map(a => ({ ...a, price: F_TIER_PRICE[a.tier].price, tierLabel: F_TIER_PRICE[a.tier].label }));
  const areaSum = lines.reduce((sum, l) => sum + l.price, 0);

  const mix = F_MIX.find(m => m.count === items.length) || null;

  if (mix && mix.price < areaSum) {
    return {
      kind: 'mix', price: mix.price, items, lines,
      saving: areaSum - mix.price,
      label: `Mix + match · any ${items.length} areas`,
    };
  }
  return {
    kind: 'areas', price: areaSum, items, lines, saving: 0,
    label: items.length === 1 ? `${lines[0].tierLabel} package` : `${items.length} packages`,
  };
}

// ══════════════════════════════════════════════════════════════════════════
//  PRICING — interactive builder. Each area is a 6-session package priced by
//  size; mix + match discounts by count; booking routes to the location email.
// ══════════════════════════════════════════════════════════════════════════

function FPricingBuilder() {
  const [selected, setSelected] = React.useState(['underarms']);
  const [activeTier, setActiveTier] = React.useState('medium');

  const toggle = (id) => setSelected(s =>
    s.includes(id) ? s.filter(x => x !== id) : [...s, id]);

  const countInTier = (tierId) => F_AREAS.filter(a => a.tier === tierId && selected.includes(a.id)).length;
  const quote = quoteFor(selected);
  const items = quote ? quote.items : [];
  const total = quote ? quote.price : 0;
  const animatedTotal = useSmoothNumber(total, 450);
  const canBook = items.length > 0;

  return (
    <section id="calculator" className="calc">
      <div className="container">
        <div className="calc-head">
          <div>
            <span className="eyebrow">Build your course</span>
            <h2 className="h-display">
              Build your <span className="i">package.</span>
            </h2>
          </div>
          <p className="calc-blurb">
            Every area is a package of six sessions, priced by size. Pick the areas you'd like — we always quote you the lowest price your selection qualifies for, mix + match included.
          </p>
        </div>

        <div className="pcards-grid calc-tiercards">
          {F_TIERS.map(t => {
            const cnt = countInTier(t.id);
            return (
              <button key={t.id} type="button"
                className={`pcard ${activeTier === t.id ? 'active' : ''}`}
                onClick={() => setActiveTier(t.id)}>
                <div className="pcard-head-l">
                  <span className="pcard-size">{t.label}</span>
                  <span className="pcard-sessions">6 sessions · one area</span>
                </div>
                <span className="pcard-price">${t.price}</span>
                {cnt > 0 && <span className="pcard-count">{cnt}</span>}
              </button>
            );
          })}
        </div>

        <div className="calc-panel">
          <div className="calc-section-head">
            <div className="calc-section-l">— {F_TIERS.find(t => t.id === activeTier).label} areas</div>
            <span className="calc-section-note">
              ${F_TIERS.find(t => t.id === activeTier).price} each · six sessions per area
            </span>
          </div>

          <div className="calc-pills">
            {F_AREAS.filter(a => a.tier === activeTier).map(a => {
              const on = selected.includes(a.id);
              return (
                <button key={a.id} type="button"
                  className={`calc-pill ${on ? 'on' : ''}`}
                  onClick={() => toggle(a.id)} aria-pressed={on}>
                  <span className="calc-pill-name">{a.name}</span>
                </button>
              );
            })}
          </div>

          <div className="calc-footer">
            <div className="calc-breakdown">
              {items.length === 0 ? (
                <p className="calc-empty">
                  We only sell packages, never single sessions — the price you see is the price you pay, confirmed at your free consultation. Pick an area to begin.
                </p>
              ) : (
                <>
                  <div className="calc-breakdown-head">
                    <span className="calc-breakdown-l">Your selection</span>
                    <button type="button" className="calc-clear calc-clear--sm" onClick={() => setSelected([])}>Clear all</button>
                  </div>
                  <ul className="calc-items">
                    {quote.lines.map(l => (
                      <li key={l.id}>
                        <span>{l.name}</span>
                        <span className="calc-item-meta">
                          {l.tierLabel} · 6 sessions · ${l.price}
                          <button type="button" className="calc-item-del" aria-label={`Remove ${l.name}`}
                            onClick={() => toggle(l.id)}>
                            <IconTrash size={15} />
                          </button>
                        </span>
                      </li>
                    ))}
                  </ul>
                </>
              )}
            </div>

            <div className="calc-checkout">
              <div className="calc-total">
                <div>
                  <span className="calc-total-l">Your price</span>
                  <span className="calc-total-sub">
                    {quote ? (quote.kind === 'mix' ? quote.label : `${items.length} ${items.length === 1 ? 'area' : 'areas'} · ${quote.label}`) : 'Nothing selected yet'}
                  </span>
                </div>
                <div className="calc-total-n">${animatedTotal.toLocaleString()}</div>
              </div>
              {quote && quote.saving > 0 && (
                <p className="calc-saving">Mix + match saves you ${quote.saving.toLocaleString()} versus booking these areas separately.</p>
              )}
              <button type="button" className={`btn calc-cta ${canBook ? '' : 'disabled'}`}
                onClick={() => canBook && openBooking(quote)}>
                {canBook ? 'Book my package' : 'Pick an area to begin'}
              </button>
            </div>
          </div>

          <div className="pcards-mix">
            <span className="mixnote-l">Mix + match, any areas</span>
            {F_MIX.map(m => (
              <div key={m.count} className="pcards-mix-tier">
                <span>{m.count} areas</span><strong>${m.price}</strong>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

function FCalculator() {
  return <FPricingBuilder />;
}

// ─────── Why us with stats ───────
function FWhy() {
  const videoRef = React.useRef(null);
  // Subtle background-photo parallax on scroll (sets --parallax on the section).
  const whyRef = useParallax(0.06);

  // React can render <video muted> without the property being set in time, and an
  // unmuted autoplay is blocked outright. Force it, then start playback ourselves.
  React.useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    v.muted = true;
    v.defaultMuted = true;
    const p = v.play();
    if (p && typeof p.catch === 'function') p.catch(() => {});
  }, []);

  return (
    <section id="why" className="why" ref={whyRef}>
      <div className="container">
        <div className="why-head">
          <span className="eyebrow">Smooth. Confident. You.</span>
          <h2 className="why-h h-display">
            Why choose <span className="i">Daniéle?</span>
          </h2>
        </div>

        <div className="why-bottom">
          <div className="why-mission">
            <p className="why-lead">
              Luxury laser hair removal, <span className="i">tailored to every skin tone and hair type</span> — for women and men alike.
            </p>
            <p>
              We use the newest <strong>Candela GentleMax Pro</strong> — Alexandrite and Nd:YAG in
              one system, the gold standard for safe, virtually painless results on every skin tone
              and hair type. From the moment you walk in, you're cared for by senior, licensed
              specialists.
            </p>
            <a href="contact-us.html" className="btn" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book a free consultation</a>
          </div>
          <div className="why-images">
            <div className="img img--video">
              {/* Client's own Instagram clip — a real client walking through her appointment.
                  Autoplays muted (the only way browsers allow autoplay); controls stay so the
                  voiceover, which is the actual review, can be turned on. */}
              <video
                ref={videoRef}
                src="images/daniele/client-review.mp4"
                poster="images/daniele/client-review-poster.jpg"
                controls
                autoPlay
                loop
                muted
                playsInline
                preload="metadata"
                aria-label="A client's walkthrough of her laser hair removal appointment at Daniéle"
              ></video>
              <span className="img-caption">Hair removal at Daniéle</span>
            </div>
            <div className="img img--still">
              <img src="images/daniele/reception.jpg" alt="Inside a Daniéle studio — reception and product wall" loading="lazy" />
              <span className="img-caption">Inside our studio</span>
            </div>
          </div>
        </div>

        {/* Real figures supplied by the client (2026-07-17): 2 years open, 20,000+ treatments,
            thousands of happy clients, 2 studio locations. */}
        <div className="why-stats">
          <CountStatF target={20000} suffix="+" label="Treatments performed" icon={IconSparkle} />
          <CountStatF target={2000} suffix="+" label="Happy clients" icon={IconStar} />
          <CountStatF target={2} suffix="" label="Studio locations" icon={IconPin} />
          <CountStatF target={2} suffix="" label="Years of care" icon={IconClock} />
        </div>
      </div>
    </section>);

}

function CountStatF({ target, suffix, label, icon: Icon }) {
  const [ref, inView] = useInView({ threshold: 0.3 });
  const v = useCountUp(target, { trigger: inView, duration: 1600 });
  return (
    <div className="why-stat" ref={ref}>
      <div className="why-stat-body">
        <div className="why-stat-n">{v.toLocaleString()}{suffix}</div>
        <div className="why-stat-l">{label}</div>
      </div>
    </div>);

}

// ─────── Video promo banner ───────
function FVideoBanner() {
  return (
    <section className="video-banner">
      <div className="video-card">
        <img src="images/daniele/faq-room.jpg" alt="Inside a Daniéle treatment room" />
        <div className="video-card-content">
          <div className="video-card-top">
            <span className="eyebrow">A studio note</span>
          </div>
          <div className="video-card-bottom">
            <h3 className="video-card-h">
              The first consultation is always <span style={{ fontStyle: 'italic' }}>free.</span>
            </h3>
            <p className="video-card-sub">We'll assess your skin, map your course, and answer everything — with no pressure to book.</p>
            <a href="contact-us.html" className="btn video-card-cta" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book a free consultation</a>
          </div>
        </div>
      </div>
    </section>);
}

// ─────── Journal ───────
function FJournal() {
  const posts = [
  { cat: 'Skin science', title: 'How laser actually targets the follicle — and why it takes six sessions.',
    author: 'Camille Reyes', year: 2026,
    img: 'images/daniele/rejuvenation.jpg' },
  { cat: 'Treatment guide', title: 'A quiet primer on preparing your skin for a course of laser care.',
    author: 'Inès Laurent', year: 2026,
    img: 'images/daniele/about-img-1.png' }];

  return (
    <section id="journal" className="journal">
      <div className="container">
        <div className="journal-head">
          <div>
            <span className="eyebrow">From the journal</span>
            <h2 className="h-display">
              Unlock the secrets to <span className="i">timeless</span> smooth skin.
            </h2>
          </div>
          <a href="#" className="btn">Read all journal</a>
        </div>
        <div className="journal-grid">
          {posts.map((p, i) =>
          <a className="journal-card" key={i} href="#">
              <div className="journal-img"><img src={p.img} alt={p.title} /></div>
              <div className="journal-body">
                <div>
                  <span className="journal-cat"><IconAsterisk size={9} sw={1.4} /> {p.cat}</span>
                  <h3 className="journal-title" style={{ marginTop: 12 }}>{p.title}</h3>
                </div>
                <div className="journal-meta">
                  <span>By <em style={{ fontStyle: 'italic' }}>{p.author}</em></span>
                  <span>{p.year}</span>
                </div>
              </div>
            </a>
          )}
        </div>
      </div>
    </section>);

}

// ─────── Testimonials slider (3-up) ───────
function FTestimonials() {
  // Real reviews from the studio's own booking system. Client and technician names are
  // withheld — each is credited only by the service performed and the month. Text is
  // verbatim aside from removing staff first names at the studio's request.
  const tests = [
  { q: "My technician was super sweet and knowledgeable! This was my first time doing laser hair removal. She made me feel comfortable the whole time. 10/10 would recommend. (:",
    service: "Full Body Laser Hair Removal", date: "March 2026" },
  { q: "My technician was very welcoming and made me feel at ease. She provided helpful tips for after care too.",
    service: "Full Legs Laser Hair Removal", date: "January 2026" },
  { q: "Best customer service and amazing attitude and grace. My technician is just wonderful and amazing.",
    service: "Lower Legs Laser Hair Removal", date: "November 2025" },
  { q: "The facility was beautiful and my technician was amazing.",
    service: "Advanced Facial Tightening", date: "September 2025" },
  { q: "My technician was excellent. Looking forward towards my next visit.",
    service: "Brazilian Laser Hair Removal", date: "August 2025" },
  { q: "Technician was very helpful.",
    service: "Brazilian Laser Hair Removal", date: "July 2025" },
  { q: "My technician was amazing.",
    service: "Full Body Laser Hair Removal", date: "May 2025" }];

  const trackRef = React.useRef(null);
  const [page, setPage] = React.useState(0);
  const [pageCount, setPageCount] = React.useState(1);

  const recompute = React.useCallback(() => {
    const el = trackRef.current;
    if (!el) return;
    const card = el.querySelector('.test-card');
    if (!card) return;
    const styles = getComputedStyle(el);
    const gap = parseFloat(styles.columnGap || styles.gap || 0);
    const padL = parseFloat(styles.paddingLeft) || 0;
    const padR = parseFloat(styles.paddingRight) || 0;
    const cardW = card.getBoundingClientRect().width;
    const step = cardW + gap;
    const visibleArea = Math.max(0, el.clientWidth - padL - padR);
    const visible = Math.max(1, Math.round(visibleArea / step));
    const pages = Math.max(1, tests.length - visible + 1);
    setPageCount(pages);
    const current = Math.min(pages - 1, Math.round(el.scrollLeft / step));
    setPage(current);
  }, [tests.length]);

  React.useEffect(() => {
    recompute();
    const el = trackRef.current;
    if (!el) return;
    const onScroll = () => recompute();
    el.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', recompute);
    return () => {
      el.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', recompute);
    };
  }, [recompute]);

  const goBy = (dir) => {
    const el = trackRef.current;
    if (!el) return;
    const card = el.querySelector('.test-card');
    if (!card) return;
    const gap = parseFloat(getComputedStyle(el).columnGap || 0);
    const step = card.getBoundingClientRect().width + gap;
    el.scrollBy({ left: dir * step, behavior: 'smooth' });
  };
  const goTo = (p) => {
    const el = trackRef.current;
    if (!el) return;
    const card = el.querySelector('.test-card');
    if (!card) return;
    const gap = parseFloat(getComputedStyle(el).columnGap || 0);
    const step = card.getBoundingClientRect().width + gap;
    el.scrollTo({ left: p * step, behavior: 'smooth' });
  };

  return (
    <section id="testimonials" className="testimonials">
      <div className="container">
        <div className="test-head">
          <div className="test-head-left">
            <span className="eyebrow">4.8★ from 170+ Google reviews</span>
            <h2 className="h-display">What our <span className="i">clients</span> say.</h2>
          </div>
          <div className="test-head-right">
            <div className="test-counter">
              <span className="test-counter-now">{String(page + 1).padStart(2, '0')}</span>
              <span className="test-counter-sep">/</span>
              <span className="test-counter-total">{String(pageCount).padStart(2, '0')}</span>
            </div>
            <div className="test-nav">
              <button className="test-arrow" aria-label="Previous" onClick={() => goBy(-1)} disabled={page === 0}>
                <IconArrowUpRight size={18} sw={1.4} style={{ transform: 'rotate(-135deg)' }} />
              </button>
              <button className="test-arrow" aria-label="Next" onClick={() => goBy(1)} disabled={page >= pageCount - 1}>
                <IconArrowUpRight size={18} sw={1.4} style={{ transform: 'rotate(45deg)' }} />
              </button>
            </div>
          </div>
        </div>

        <div className="test-track" ref={trackRef}>
          {tests.map((t, k) =>
          <article key={k} className="test-card">
              <div className="test-cardtop">
                <span className="test-mark" aria-hidden="true">"</span>
                <div className="test-stars" aria-label="5 out of 5 stars">
                  {[0, 1, 2, 3, 4].map((s) => <IconStar key={s} size={17} sw={0} style={{ fill: 'currentColor' }} />)}
                </div>
              </div>
              <p className="test-q">{t.q}</p>
              <div className="test-foot">
                <div className="test-avatar">
                  <img src="images/daniele/footer-logo-new.png" alt="" loading="lazy" />
                </div>
                <div className="test-who">
                  <div className="test-name">{t.service}</div>
                  <div className="test-role">{t.date}</div>
                </div>
              </div>
            </article>
          )}
        </div>

        <div className="test-dots" role="tablist">
          {Array.from({ length: pageCount }).map((_, k) =>
          <button key={k} className={`test-dot ${k === page ? 'on' : ''}`}
          onClick={() => goTo(k)} aria-label={`Go to slide ${k + 1}`} />
          )}
        </div>
      </div>
    </section>);

}

// ─────── Social / Follow us ───────
function FSocial() {
  // The studio's own Instagram content — candid treatment moments mixed with posts.
  const tiles = [
  { src: 'images/daniele/ig-back-laser.jpg', shape: 'rounded' },
  { src: 'images/daniele/laser-treatment.jpg', shape: 'arch' },
  { src: 'images/daniele/ig-room.jpg', shape: 'rounded' },
  { src: 'images/daniele/ig-leg-pro.jpg', shape: 'arch' },
  { src: 'images/daniele/ig-lounge.jpg', shape: 'rounded' }];

  return (
    <section className="social">
      <div className="social-top">
        <div className="social-top-inner">
          <span className="social-eyebrow">— Follow us</span>
          <ul className="social-links">
            <li><a href={F_INSTAGRAM} target="_blank" rel="noopener" aria-label="Daniéle on Instagram">Instagram</a></li>
            <li><a href={F_FACEBOOK} target="_blank" rel="noopener" aria-label="Daniéle on Facebook">Facebook</a></li>
          </ul>
        </div>
      </div>
      <div className="social-strip">
        <div className="social-tiles">
          {tiles.map((t, i) =>
          <a key={i} className={`social-tile social-tile--${t.shape}`} href={F_INSTAGRAM} target="_blank" rel="noopener" aria-label="View Daniéle on Instagram">
              <img src={t.src} alt="" loading="lazy" />
            </a>
          )}
        </div>
      </div>
      <div className="social-bottom">
        {/* Client's own studio: reception wordmark left, their wall quote right.
            Both are cropped low so their lettering sits below our headline, not under it. */}
        <div className="social-bottom-bg" aria-hidden="true">
          {/* Each half clips its own photo: the reception shot is rotated to level its
              wall sign, and without a clipping box that rotation spills across the seam. */}
          <div className="social-bottom-half">
            <img src="images/daniele/studio-reception.jpg" alt="Reception area at a Daniéle Laser + Aesthetics studio in Texas" loading="lazy" />
          </div>
          <div className="social-bottom-half">
            <img src="images/daniele/studio-wall.jpg" alt="Product and treatment wall inside a Daniéle Laser + Aesthetics studio" loading="lazy" />
          </div>
        </div>
        <div className="social-bottom-inner">
          {/* No headline of our own here: both photos are the studio's own lettered walls,
              and anything we set over them competes rather than reads. */}
          <div className="social-foot">
            <p className="social-blurb">
              Book a free consultation and begin your course. Fewer hairs every session — no razors, no waxing, no ingrowns.
            </p>
            <div className="social-phones">
              <a className="social-phone" href="tel:+12816122073">{F_PHONE}</a>
              <span className="social-phone-sep" aria-hidden="true"></span>
              <a className="social-phone" href="contact-us.html" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book a consultation</a>
            </div>
          </div>
        </div>
      </div>
    </section>);

}

// ─────── Before / After comparison slider ───────
function FBeforeAfter() {
  const [pos, setPos] = React.useState(50);
  const ref = React.useRef(null);
  const dragRef = React.useRef(false);

  const setFromX = (clientX) => {
    const r = ref.current.getBoundingClientRect();
    const next = Math.max(0, Math.min(100, ((clientX - r.left) / r.width) * 100));
    setPos(next);
  };
  const onDown = (e) => {
    dragRef.current = true;
    setFromX(e.touches ? e.touches[0].clientX : e.clientX);
    e.preventDefault();
  };
  const onMove = (e) => {
    if (!dragRef.current) return;
    setFromX(e.touches ? e.touches[0].clientX : e.clientX);
  };
  const onUp = () => { dragRef.current = false; };

  React.useEffect(() => {
    window.addEventListener('mousemove', onMove);
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchend', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchend', onUp);
    };
  }, []);

  return (
    <section id="results" className="results">
      <div className="container">
        <div className="results-head">
          <div>
            <span className="eyebrow">Real client results</span>
            <h2 className="h-display">
              Smoother skin, <span className="i">session by session.</span>
            </h2>
          </div>
          <p className="results-blurb">
            Drag the divider to compare. These photos show a typical underarm course at week 0 and week 24 — six sessions on a five-week rhythm.
          </p>
        </div>

        <div className="ba" ref={ref} onMouseDown={onDown} onTouchStart={onDown}>
          <img className="ba-img ba-img--before"
            src="images/o/ba-before.jpg" alt="Before treatment" />
          {/* Before label sits on the base layer, under the after overlay, so the
              after image covers (clips) it once the divider slides past it. */}
          <span className="ba-label ba-label--before" style={{ opacity: pos > 20 ? 1 : 0 }}>Before · Week 0</span>
          <div className="ba-after-wrap" style={{ clipPath: `inset(0 0 0 ${pos}%)` }}>
            <img className="ba-img ba-img--after"
              src="images/o/ba-after.jpg" alt="After 6 sessions" />
            {/* After label lives inside the clipped layer, so it's cut at the divider
                and never crosses onto the before side. */}
            <span className="ba-label ba-label--after" style={{ opacity: pos < 80 ? 1 : 0 }}>After · Week 24</span>
          </div>
          <div className="ba-divider" style={{ left: `${pos}%` }}>
            <button className="ba-handle" aria-label="Drag to compare">
              <IconArrowUpRight size={14} sw={1.5} style={{transform:'rotate(-135deg)'}} />
              <IconArrowUpRight size={14} sw={1.5} style={{transform:'rotate(45deg)'}} />
            </button>
          </div>
        </div>

        <div className="results-stats">
          <div className="results-stat">
            <span className="results-stat-n">20,000<sup>+</sup></span>
            <span className="results-stat-l">Treatments performed</span>
          </div>
          <div className="results-stat">
            <span className="results-stat-n">6</span>
            <span className="results-stat-l">Sessions in a full course</span>
          </div>
          <div className="results-stat">
            <span className="results-stat-n">4–6<sup>w</sup></span>
            <span className="results-stat-l">Between visits</span>
          </div>
          <div className="results-stat">
            <span className="results-stat-n">2</span>
            <span className="results-stat-l">Texas studios</span>
          </div>
        </div>
      </div>
    </section>
  );
}

// ─────── FAQ (accordion) ───────
function FFAQ() {
  const faqs = [
    { q: 'How many sessions will I need?',
      a: 'Most clients see 80–95% reduction after six sessions on a 4–6 week rhythm. Areas with denser, darker hair often need eight to ten visits — we map your course at the first consultation.' },
    { q: 'Does laser hair removal hurt?',
      a: 'The Candela GentleMax Pro cools your skin with every pulse, so most clients describe it as the gentle snap of a warm rubber band — and barely notice it at all by the third session.' },
    { q: 'Is laser safe for my skin tone?',
      a: 'Yes. The GentleMax Pro carries both Alexandrite and Nd:YAG wavelengths, which lets us treat every skin tone safely — our specialists have extensive experience across all of them. We patch test whenever it is needed and tune the settings to your skin at every visit.' },
    { q: 'How should I prepare for a session?',
      a: 'Shave the area 24 hours before. Avoid sun, retinol and self-tanners for two weeks prior. Arrive freshly cleansed — no oils, lotions, deodorant or makeup on the treatment area.' },
    { q: 'What does aftercare look like?',
      a: 'Aloe gel and avoiding hot showers or workouts for 48 hours. SPF 50 on the area for two weeks. We send you a tailored aftercare guide by email within an hour of every session.' },
    { q: 'Can I shave between sessions?',
      a: 'Yes — shaving is encouraged and required. Avoid waxing, threading, or plucking between visits, since those remove the follicle the laser needs to target.' },
  ];
  const [open, setOpen] = React.useState(-1);
  return (
    <section id="faq" className="faq">
      <div className="container">
        <div className="faq-head">
          <div>
            <span className="eyebrow">Frequently asked</span>
            <h2 className="h-display">
              The <span className="i">quiet answers</span> to the questions clients ask most.
            </h2>
          </div>
          <a href="contact-us.html" className="btn">Ask us anything</a>
        </div>
        <div className="faq-grid">
        <ul className="faq-list">
          {faqs.map((f, i) => (
            <li key={i} className={`faq-item ${open === i ? 'on' : ''}`}>
              <button className="faq-q" aria-expanded={open === i} onClick={() => setOpen(open === i ? -1 : i)}>
                <span className="faq-n">{String(i + 1).padStart(2, '0')}</span>
                <span className="faq-qt">{f.q}</span>
                <span className="faq-toggle" aria-hidden="true">
                  <IconArrowUpRight size={14} sw={1.6} />
                </span>
              </button>
              <div className="faq-a-wrap">
                <div className="faq-a-inner">
                  <p className="faq-a">{f.a}</p>
                </div>
              </div>
            </li>
          ))}
        </ul>
        <aside className="faq-media">
          <img src="images/daniele/treatment-room.jpg" alt="A Daniéle treatment room with the Candela GentleMax Pro laser" loading="lazy" />
        </aside>
        </div>
      </div>
    </section>
  );
}

// ─────── Booking form (before footer) ───────
const F_SERVICE_LABELS = { face: 'Face Laser', body: 'Body Smooth', bikini: 'Bikini & Brazilian', concierge: 'Concierge Full-Body', unsure: "I'd like to be advised" };

function FCTA() {
  const [form, setForm] = React.useState({ name: '', email: '', phone: '', service: '', location: F_LOCATIONS[0].id, date: '', notes: '' });
  const [sent, setSent] = React.useState(false);
  const [error, setError] = React.useState(false);
  const upd = (k) => (e) => setForm({ ...form, [k]: e.target.value });
  // Route to the chosen studio's own inbox — same location-based routing as the booking popup.
  const onSubmit = async (e) => {
    e.preventDefault();
    const loc = F_LOCATIONS.find(l => l.id === form.location) || F_LOCATIONS[0];
    const body = [
      `New consultation request — ${loc.name}`, '',
      `Name:  ${form.name}`,
      `Email: ${form.email}`,
      `Phone: ${form.phone || '—'}`,
      `Service: ${F_SERVICE_LABELS[form.service] || 'To be advised'}`,
      `Preferred date: ${form.date || '—'}`,
      form.notes ? `\nNotes: ${form.notes}` : '',
    ].join('\n');
    const subject = `Consultation request — ${loc.name}`;
    setError(false);
    try {
      await deliverBooking({ locationId: loc.id, name: form.name, email: form.email, phone: form.phone, subject, message: body });
      setSent(true);
    } catch (err) {
      setError(true);
    }
  };
  return (
    <section className="cta" id="book">
      <div className="cta-inner">
        <div className="cta-map">
          <iframe
            src={F_MAP_EMBED}
            title="Daniéle Laser + Aesthetics — Friendswood location on Google Maps"
            loading="lazy"
            referrerPolicy="no-referrer-when-downgrade"
            allowFullScreen
          ></iframe>
          <div className="cta-map-panel">
            {F_LOCATIONS.map(l => (
              <div key={l.id} className="cta-map-loc">
                <span className="cta-map-loc-n">
                  {l.name}
                  {l.opening && <em className="cta-map-soon">{l.opening}</em>}
                </span>
                <a className="cta-map-addr" href={l.mapUrl} target="_blank" rel="noopener noreferrer">
                  {l.address}
                </a>
                <span className="cta-map-hours-v">{l.hours}</span>
              </div>
            ))}
          </div>
        </div>
        <form className="cta-form" onSubmit={onSubmit}>
          <div className="cta-form-head">
            <span className="eyebrow">Book a consultation</span>
            <h2 className="h-display">
              Reserve your <span className="i">first visit.</span>
            </h2>
            <p className="cta-form-blurb">
              Tell us a little about yourself and the area you'd like to treat. We'll be in touch within two hours to suggest a quiet slot.
            </p>
          </div>

          <div className="cta-form-grid">
            <label className="field">
              <span>Full name</span>
              <input type="text" value={form.name} onChange={upd('name')} placeholder="Inès Laurent" required />
            </label>
            <label className="field">
              <span>Email</span>
              <input type="email" value={form.email} onChange={upd('email')} placeholder="ines@example.com" required />
            </label>
            <label className="field">
              <span>Phone</span>
              <input type="tel" value={form.phone} onChange={upd('phone')} placeholder="(281) 000-0000" />
            </label>
            <label className="field">
              <span>Service</span>
              <div className="field-select">
                <select value={form.service} onChange={upd('service')} required>
                  <option value="">Choose a service…</option>
                  <option value="face">Face Laser</option>
                  <option value="body">Body Smooth</option>
                  <option value="bikini">Bikini & Brazilian</option>
                  <option value="concierge">Concierge Full-Body</option>
                  <option value="unsure">I'd like to be advised</option>
                </select>
                <IconArrowUpRight size={14} sw={1.5} style={{ transform: 'rotate(135deg)' }} />
              </div>
            </label>
            <label className="field field--full">
              <span>Studio</span>
              <div className="field-select">
                <select value={form.location} onChange={upd('location')} required>
                  {F_LOCATIONS.map(l => <option key={l.id} value={l.id}>{l.name}{l.opening ? ` (${l.opening})` : ''}</option>)}
                </select>
                <IconArrowUpRight size={14} sw={1.5} style={{ transform: 'rotate(135deg)' }} />
              </div>
            </label>
            <label className="field field--full">
              <span>Preferred date</span>
              <input type="date" className="date-input" value={form.date} min={new Date().toISOString().split('T')[0]} onChange={upd('date')} />
            </label>
            <label className="field field--full">
              <span>A note for your practitioner <em>(optional)</em></span>
              <textarea rows={3} value={form.notes} onChange={upd('notes')} placeholder="Anything you'd like us to know in advance — skin sensitivities, previous treatments, time-of-day preference." />
            </label>
          </div>

          <div className="cta-form-foot">
            <label className="cta-form-consent">
              <input type="checkbox" defaultChecked />
              <span>I agree to receive a reply by email or phone.</span>
            </label>
            <button type="submit" className="btn cta-form-submit">Send &amp; book</button>
          </div>
          {sent && (
            <p className="cta-form-sent" role="status">
              Thank you — your request is on its way to our {F_LOCATIONS.find(l => l.id === form.location)?.name} studio. We'll reply within two hours.
            </p>
          )}
          {error && (
            <p className="cta-form-sent cta-form-error" role="alert">
              Something went wrong sending your request. Please call us at {F_PHONE} or try again.
            </p>
          )}
        </form>
      </div>
    </section>);

}

// ─────── Footer ───────
function FFooter() {
  const [email, setEmail] = React.useState('');
  const onSubmit = (e) => {e.preventDefault();setEmail('');};
  const year = new Date().getFullYear();
  return (
    <footer id="contact">
      <div className="footer-cta">
        <div className="container">
          <div className="footer-cta-row">
            <div>
              <span className="footer-eyebrow">— Let's begin</span>
              <h2 className="footer-h h-display">
                Ready for a quieter, smoother <span className="i">you?</span>
              </h2>
            </div>
            <a href="contact-us.html" className="btn footer-cta-btn" onClick={(e) => { e.preventDefault(); openBooking(); }}>Book a consultation</a>
          </div>
        </div>
      </div>

      <div className="container">
        <div className="footer-mid">
          <div className="footer-col footer-col--brand">
            <span className="footer-logo">
              <img src="images/daniele/footer-logo-new.png" alt="Daniéle Laser + Aesthetics" />
            </span>
            <p className="footer-brand-blurb">
              Luxury laser hair removal on the newest Candela GentleMax Pro. Licensed specialists, two Texas studios, over 20,000 treatments performed.
            </p>
            <a className="footer-phone" href="tel:+12816122073">{F_PHONE}</a>
            <div className="footer-social">
              <a href={F_INSTAGRAM} target="_blank" rel="noopener noreferrer">Instagram</a>
              <a href={F_FACEBOOK} target="_blank" rel="noopener noreferrer">Facebook</a>
            </div>
          </div>

          <div className="footer-col">
            <h5>Friendswood</h5>
            <div className="footer-loc-item">
              <span className="footer-loc-addr">1769 S. Friendswood Dr. Suite 113<br />Friendswood, TX 77546</span>
              <span className="footer-loc-addr">Mon–Fri 10–7 · Sat 10–5 · Sun closed</span>
              <a className="footer-loc-mail" href="mailto:corporate@danielefriendswood.com">corporate@danielefriendswood.com</a>
              <a className="footer-loc-link" href={F_LOCATIONS[0].mapUrl} target="_blank" rel="noopener noreferrer">
                Get directions <IconArrowUpRight size={11} sw={1.6} />
              </a>
            </div>
          </div>

          <div className="footer-col">
            <h5>Cypress <span className="footer-loc-soon">Opens Aug 12</span></h5>
            <div className="footer-loc-item">
              <span className="footer-loc-addr">20049 House Hahl Rd. Suite 113<br />Cypress, TX 77433</span>
              <span className="footer-loc-addr">Wed–Fri 10–7 · Sat 10–5 · Sun closed</span>
              <a className="footer-loc-mail" href="mailto:corporate@danielecypress.com">corporate@danielecypress.com</a>
              <a className="footer-loc-link" href={F_LOCATIONS[1].mapUrl} target="_blank" rel="noopener noreferrer">
                Get directions <IconArrowUpRight size={11} sw={1.6} />
              </a>
            </div>
          </div>

          <div className="footer-col">
            <h5>Sitemap</h5>
            <ul>
              <li><a href="index.html">Home</a></li>
              <li><a href="about-us.html">About Us</a></li>
              <li><a href="laser-hair-removal.html">Laser Hair Removal</a></li>
              <li><a href="aesthetic-treatments.html">Aesthetic Treatments</a></li>
              <li><a href="contact-us.html">Contact Us</a></li>
            </ul>
            <a className="footer-loc-link" href={F_GIFT_CARD_URL} target="_blank" rel="noopener noreferrer">
              Gift cards <IconArrowUpRight size={11} sw={1.6} />
            </a>
          </div>
        </div>

        <div className="footer-bottom">
          <span>© {year} daniéle laser + aesthetics · All rights reserved.</span>
          <span className="footer-legal">
            <a href="privacy-policy.html">Privacy</a>
            <a href="cancellation-refund-policy.html">Cancellation &amp; refunds</a>
            <a href="customer-care-policy.html">Customer care</a>
          </span>
          <span className="footer-made">Friendswood &amp; Cypress, Texas</span>
        </div>
      </div>
    </footer>);

}

// ─────── Immersive cinematic interlude (signature moment) ───────
function FImmersive() {
  const secRef = React.useRef(null);
  const mediaRef = React.useRef(null);
  const [entered, setEntered] = React.useState(false);

  React.useEffect(() => {
    const sec = secRef.current;
    const media = mediaRef.current;
    if (!sec || !media) return;
    let raf;
    let done = false;
    const apply = () => {
      const r = sec.getBoundingClientRect();
      const vh = window.innerHeight;
      const prog = (vh - r.top) / (vh + r.height); // 0..1 as it crosses the viewport
      const y = (Math.min(1, Math.max(0, prog)) - 0.5) * 34; // -17% … +17% drift
      media.style.transform = "translate3d(0, " + y + "%, 0)";
      if (!done && r.top < vh * 0.8) { done = true; setEntered(true); }
    };
    const onScroll = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(apply); };
    window.addEventListener("scroll", onScroll, { passive: true });
    apply();

    return () => {
      window.removeEventListener("scroll", onScroll);
      cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <section ref={secRef} className={"immersive" + (entered ? " in" : "")} aria-label="Considered light">
      <div ref={mediaRef} className="immersive-media">
        <img src="images/daniele/laser-img.png" alt="Laser hair removal on the Candela GentleMax Pro at Daniéle Laser + Aesthetics" />
      </div>
      <div className="immersive-scrim" aria-hidden="true"></div>
      <div className="immersive-content">
        <span className="immersive-eyebrow"><span>— The Daniéle hour</span></span>
        <h2 className="immersive-h">
          <span className="immersive-line"><span>Where precision</span></span>
          <span className="immersive-line"><span>becomes <em className="i">calm.</em></span></span>
        </h2>
        <p className="immersive-caption">An unhurried hour, considered light, and skin that quietly remembers the difference.</p>
        <a href="#calculator" className="immersive-cta">Build your course</a>
      </div>
    </section>
  );
}

function useScrollReveal() {
  React.useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const sel = ".services-head, .calc-head, .why-head, .faq-head, .reviews-head, .results-head, .cta-form-head, .section-head" +
      // Sub-page content blocks (laser / aesthetic / about / contact) — these
      // classes only exist on the standalone pages, so the home App is unaffected.
      ", .laser-intro-l, .laser-intro-media, .aesthetic-card, .zone-row, .zones-mix, .zones-cta" +
      ", .exp-step, .about-intro-r, .about-intro-media, .about-feats, .contact-panel, .legal-inner";
    const els = Array.prototype.slice.call(document.querySelectorAll(sel));
    document.documentElement.classList.add("reveal-on");
    els.forEach(function (el) { el.classList.add("rv"); });
    const io = new IntersectionObserver(function (entries) {
      entries.forEach(function (e) {
        if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); }
      });
    }, { threshold: 0.18, rootMargin: "0px 0px -8% 0px" });
    els.forEach(function (el) { io.observe(el); });

    // Scroll/resize fallback: IntersectionObserver is throttled in some contexts
    // (backgrounded tabs, occasional iOS bfcache restores). Since every element
    // here starts at opacity:0, a missed IO would leave content invisible — the
    // geometry check on scroll guarantees it always reveals.
    const revealIfVisible = function () {
      const vh = window.innerHeight || document.documentElement.clientHeight;
      els.forEach(function (el) {
        if (el.classList.contains("in")) return;
        const r = el.getBoundingClientRect();
        if (r.top < vh * 0.92 && r.bottom > 0) { el.classList.add("in"); io.unobserve(el); }
      });
    };
    window.addEventListener("scroll", revealIfVisible, { passive: true });
    window.addEventListener("resize", revealIfVisible);
    revealIfVisible();

    return () => {
      io.disconnect();
      window.removeEventListener("scroll", revealIfVisible);
      window.removeEventListener("resize", revealIfVisible);
    };
  }, []);
}

// Shared page chrome for the standalone sub-pages (pages.jsx): applies the default
// palette/font CSS vars and wires the same scroll-reveal the home App uses. The home
// page keeps its own tweakable version inside FApp; sub-pages just use the defaults.
function usePageChrome() {
  useScrollReveal();
  React.useEffect(() => {
    const root = document.documentElement;
    const p = F_PALETTES[F_TWEAK_DEFAULTS.palette] || F_PALETTES.cream;
    Object.entries(p.vars).forEach(([k, v]) => root.style.setProperty(k, v));
    const f = F_FONTS[F_TWEAK_DEFAULTS.fonts] || F_FONTS.cormorant;
    root.style.setProperty('--font-display', f.display);
    root.style.setProperty('--font-body', f.body);
  }, []);
}

// ─────── App root ───────
function FApp() {
  const [t, setTweak] = useTweaks(F_TWEAK_DEFAULTS);
  useScrollReveal();
  React.useEffect(() => {
    const root = document.documentElement;
    const p = F_PALETTES[t.palette] || F_PALETTES.cream;
    Object.entries(p.vars).forEach(([k, v]) => root.style.setProperty(k, v));
    const f = F_FONTS[t.fonts] || F_FONTS.cormorant;
    root.style.setProperty('--font-display', f.display);
    root.style.setProperty('--font-body', f.body);
  }, [t.palette, t.fonts]);

  return (
    <>
      <ScrollProgress />
      <FGiftBar />
      <FNav />
      <FHero />
      <FStatement />
      <FServices />
      <FWordMarquee />
      <FImmersive />
      <FCalculator />
      <FWhy />
      <FBeforeAfter />
      <FWordMarquee tone="bronze" />
      <FFAQ />
      <FVideoBanner />
      <FTestimonials />
      <FSocial />
      <FWordMarquee tone="bronze" />
      <FCTA />
      <FFooter />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Color palette" />
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
          {Object.entries(F_PALETTES).map(([k, p]) =>
          <button key={k} onClick={() => setTweak('palette', k)}
          style={{ display: 'flex', flexDirection: 'column', gap: 6, padding: 8,
            border: '1px solid ' + (t.palette === k ? 'rgba(41,38,27,0.7)' : 'rgba(0,0,0,0.1)'),
            borderRadius: 8, background: t.palette === k ? 'rgba(0,0,0,0.04)' : 'transparent',
            cursor: 'pointer', textAlign: 'left', font: 'inherit', color: 'inherit' }}>
              <div style={{ display: 'flex', gap: 3, height: 22 }}>
                {p.swatch.map((c, i) =>
              <div key={i} style={{ flex: 1, background: c, borderRadius: 3, border: '0.5px solid rgba(0,0,0,0.08)' }}></div>
              )}
              </div>
              <span style={{ fontSize: 10, color: 'rgba(41,38,27,0.7)' }}>{p.label}</span>
            </button>
          )}
        </div>
        <TweakSection label="Type pair" />
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {Object.entries(F_FONTS).map(([k, f]) =>
          <button key={k} onClick={() => setTweak('fonts', k)}
          style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', padding: '10px 12px',
            borderRadius: 8, border: '1px solid ' + (t.fonts === k ? 'rgba(41,38,27,0.7)' : 'rgba(0,0,0,0.1)'),
            background: t.fonts === k ? 'rgba(0,0,0,0.04)' : 'transparent', cursor: 'pointer',
            textAlign: 'left', font: 'inherit', color: 'inherit', width: '100%' }}>
              <span style={{ fontFamily: f.display, fontSize: 24, lineHeight: 1, fontStyle: 'italic' }}>Smooth.</span>
              <span style={{ fontFamily: f.body, fontSize: 10, color: 'rgba(41,38,27,0.6)', marginTop: 4, letterSpacing: '0.04em' }}>{f.label}</span>
            </button>
          )}
        </div>
      </TweaksPanel>
    </>);

}

// Multi-page site: each HTML sets #root[data-page]. The home page ('home' or no
// attribute) renders the full FApp here; the sub-pages are rendered by pages.jsx,
// which no-ops on 'home'. Both scripts load on every page, so this guard keeps them
// from fighting over #root.
(function () {
  const rootEl = document.getElementById('root');
  const page = (rootEl && rootEl.dataset.page) || 'home';
  if (page === 'home') {
    ReactDOM.createRoot(rootEl).render(<FApp />);
    // Arriving with a hash (e.g. from a sub-page footer link -> index.html#services):
    // the target section only exists after the app renders, so the browser's native
    // hash scroll misses it. Retry until the anchor mounts, then scroll to it.
    if (window.location.hash && window.location.hash.length > 1) {
      const id = decodeURIComponent(window.location.hash.slice(1));
      let tries = 0;
      const tryScroll = () => {
        const el = document.getElementById(id);
        if (el) { el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
        else if (tries++ < 40) { setTimeout(tryScroll, 100); }
      };
      setTimeout(tryScroll, 150);
    }
  }
})();