/* global React, ReactDOM, TweaksPanel, useTweaks, TweakSection, TweakSelect, TweakText, TweakColor */

const { useEffect, useRef, useState } = React;

// ---------- Tweakable defaults (persisted via host) ----------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "fontPairing": "marcellus-worksans",
  "accentColor": "#B08A63",
  "heroVariant": "centered",
  "heroEyebrow": "Coastal Staging",
  "heroTitle": "Elevated Living.\nDesigned to Sell.",
  "heroSub": "Curated interiors for the coastal luxury market."
}/*EDITMODE-END*/;

const FONT_PAIRS = {
  "marcellus-worksans":  { display: "'Marcellus', serif",           body: "'Work Sans', sans-serif",  label: "Marcellus + Work Sans" },
  "cormorant-worksans":  { display: "'Cormorant Garamond', serif",  body: "'Work Sans', sans-serif",  label: "Cormorant + Work Sans" },
  "fraunces-inter":      { display: "'Fraunces', serif",            body: "'Inter', sans-serif",      label: "Fraunces + Inter" },
  "playfair-worksans":   { display: "'Playfair Display', serif",    body: "'Work Sans', sans-serif",  label: "Playfair + Work Sans" },
};

// ---------- Portfolio data ----------
const PROJECTS = [
  { id: "living",  title: "Ocean View Living", tag: "wide", img: "assets/portfolio-01-living.jpg",  label: "01 · Living" },
  { id: "kitchen", title: "Marble + Blue Island", tag: "tall", img: "assets/portfolio-02-kitchen.jpg", label: "02 · Kitchen" },
  { id: "bedroom", title: "Primary Bedroom", tag: "med", img: "assets/portfolio-03-bedroom.png",  label: "03 · Bedroom" },
  { id: "patio",   title: "Covered Patio", tag: "med", img: "assets/portfolio-04-patio.png",      label: "04 · Patio" },
  { id: "dining",  title: "Dining Room", tag: "med", img: "assets/portfolio-05-dining.png",       label: "05 · Dining" },
  { id: "canopy",  title: "Canopy Suite", tag: "half", img: "assets/portfolio-06-canopy.png",     label: "06 · Suite" },
  { id: "outdoor", title: "Oceanfront Terrace", tag: "half", img: "assets/portfolio-07-outdoor.png", label: "07 · Outdoor" },
];

// ---------- Reveal hook ----------
function useReveal(deps = []) {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal, .reveal-left, .reveal-right, .split-rise, .img-reveal, .sunset');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.15, rootMargin: '0px 0px -10% 0px' });
    els.forEach(el => io.observe(el));
    // Safety net: after 2.5s force any remaining .img-reveal elements into `.in`
    // so cover-wipe overlays never get stuck if the observer misses them.
    const t = setTimeout(() => {
      document.querySelectorAll('.img-reveal:not(.in)').forEach(el => el.classList.add('in'));
    }, 2500);
    return () => { io.disconnect(); clearTimeout(t); };
  }, deps);
}

// ---------- Scroll-linked image parallax ----------
function useImageParallax() {
  useEffect(() => {
    const tiles = Array.from(document.querySelectorAll('[data-parallax]'));
    if (!tiles.length) return;
    let raf = 0;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        const vh = window.innerHeight;
        tiles.forEach(t => {
          const rect = t.getBoundingClientRect();
          const center = rect.top + rect.height / 2;
          const progress = (center - vh / 2) / (vh * 0.8); // -1..1-ish
          const y = Math.max(-30, Math.min(30, -progress * 26));
          const inner = t.querySelector('.img');
          if (inner) inner.style.setProperty('--py', `${y}px`);
        });
        raf = 0;
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => { window.removeEventListener('scroll', onScroll); if (raf) cancelAnimationFrame(raf); };
  }, []);
}

// ---------- Nav ----------
function Nav() {
  const [scrolled, setScrolled] = useState(false);
  const [open, setOpen] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 60);
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  // Lock body scroll when the mobile drawer is open
  useEffect(() => {
    document.body.style.overflow = open ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [open]);
  // Close on resize up to desktop, on Escape, or on hash/route change
  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    const onResize = () => { if (window.innerWidth > 900) setOpen(false); };
    const onHash = () => setOpen(false);
    window.addEventListener('keydown', onKey);
    window.addEventListener('resize', onResize);
    window.addEventListener('hashchange', onHash);
    return () => {
      window.removeEventListener('keydown', onKey);
      window.removeEventListener('resize', onResize);
      window.removeEventListener('hashchange', onHash);
    };
  }, []);
  const close = () => setOpen(false);
  return (
    <nav className={"nav" + (scrolled ? " scrolled" : "") + (open ? " open" : "")}>
      <a href="#top" className="brand brand-cinzel" onClick={close}>
        <span>Coastal Staging</span>
      </a>
      <button
        type="button"
        className={"nav-toggle" + (open ? " open" : "")}
        aria-label={open ? "Close menu" : "Open menu"}
        aria-expanded={open}
        aria-controls="mobile-menu"
        onClick={() => setOpen(o => !o)}
      >
        <span></span><span></span><span></span>
      </button>
      <div className="navlinks">
        <a href="#top" className="active">Home</a>
        <a href="#portfolio">Portfolio</a>
        <a href="services.html">Services</a>
        <a href="about.html">About</a>
        <a href="#process">Process</a>
        <a href="#contact">Contact</a>
      </div>
      <div id="mobile-menu" className={"mobile-menu" + (open ? " open" : "")} aria-hidden={!open}>
        <div className="mobile-menu-inner">
          <a href="#top" onPointerDown={close} onClick={close}>Home</a>
          <a href="#portfolio" onPointerDown={close} onClick={close}>Portfolio</a>
          <a href="services.html" onPointerDown={close} onClick={close}>Services</a>
          <a href="about.html" onPointerDown={close} onClick={close}>About</a>
          <a href="#process" onPointerDown={close} onClick={close}>Process</a>
          <a href="#contact" onPointerDown={close} onClick={close}>Contact</a>
          <div className="mobile-menu-foot">
            <a href="mailto:hello@coastalstaging.com">hello@coastalstaging.com</a>
            <span>Laguna Beach, CA</span>
          </div>
        </div>
      </div>
    </nav>
  );
}

// ---------- Hero ----------
function Hero({ variant, eyebrow, title, subtitle }) {
  const mediaRef = useRef(null);
  const [hasImage, setHasImage] = useState(true); // optimistic: assume the image exists
  useEffect(() => {
    const el = mediaRef.current;
    if (!el) return;
    const url = "assets/hero.png";
    // Optimistically set the background-image immediately with cache-bust so the
    // browser always re-requests when the file changes.
    const bust = url + '?v=' + Date.now();
    el.style.backgroundImage = `url("${bust}")`;
    // Probe to decide whether to hide the placeholder label.
    const img = new Image();
    img.onload = () => {
      if (!mediaRef.current) return;
      mediaRef.current.classList.add('loaded');
      mediaRef.current.classList.remove('ph');
      mediaRef.current.classList.remove('hero-ph');
      mediaRef.current.removeAttribute('data-label');
      setHasImage(true);
    };
    img.onerror = () => {
      if (!mediaRef.current) return;
      mediaRef.current.style.backgroundImage = '';
      setHasImage(false);
    };
    img.src = bust;

    // Parallax
    const onScroll = () => {
      if (!mediaRef.current) return;
      const y = Math.min(window.scrollY, 900);
      mediaRef.current.style.transform = `translateY(${y * 0.3}px) scale(${1.05 + y * 0.0002})`;
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  const titleLines = (title || "").split("\n");

  return (
    <header className="hero" id="top" data-screen-label="Hero">
      <div
        ref={mediaRef}
        className="hero-media hero-ph ph"
        data-label="Drop hero.jpg in /assets — aspirational wide interior"
      />
      <div className={"hero-veil" + (hasImage ? "" : " hidden") + (variant === "wide" ? " warm" : "")} />

      <div className={"hero-content " + variant}>
        <div className="hero-eyebrow">{eyebrow}</div>
        <h1 className="hero-title">
          {titleLines.map((line, i) => (
            <span key={i} className="hero-title-line" style={{ display: "block", overflow: "hidden" }}>
              <span style={{ display: "inline-block" }}>{line}</span>
            </span>
          ))}
        </h1>
        <div className="hero-sub">{subtitle}</div>
        <div className="hero-cta">
          <a href="#contact" className="btn">Book a Walkthrough <span className="arrow"/></a>
        </div>
      </div>

      <a href="#portfolio" className="hero-scroll" aria-label="Scroll">
        <span>Scroll</span>
        <span className="line" />
      </a>
    </header>
  );
}

// ---------- Portfolio ----------
function Portfolio() {
  return (
    <section className="portfolio" id="portfolio" data-screen-label="Portfolio">
      <div className="wrap">
        <div className="section-head reveal">
          <span className="eyebrow">Selected Projects</span>
          <h2>A quiet discipline in every room.</h2>
          <p>Curated interiors for the coastal luxury market — designed to photograph beautifully and live honestly.</p>
        </div>

        <div className="grid-6">
          {PROJECTS.map((p, i) => (
            <PortfolioTile key={p.id} project={p} delay={i % 4} />
          ))}
        </div>

        <div className="portfolio-cta reveal">
          <a href="#contact" className="btn ghost">View Full Portfolio <span className="arrow"/></a>
        </div>
      </div>
    </section>
  );
}

function PortfolioTile({ project, delay }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const bust = project.img + '?v=' + Date.now();
    // Optimistically set background so browser fetches it directly.
    el.style.backgroundImage = `url("${bust}")`;
    const img = new Image();
    img.onload = () => {
      if (!ref.current) return;
      ref.current.classList.remove('ph');
      ref.current.removeAttribute('data-label');
    };
    img.onerror = () => {
      // keep placeholder
      if (!ref.current) return;
      ref.current.style.backgroundImage = '';
    };
    img.src = bust;
  }, [project.img]);
  return (
    <div className={`tile ${project.tag} img-reveal d${delay}`} data-parallax>
      <div
        ref={ref}
        className="img ph"
        data-label={project.label}
      />
      <div className="cap">{project.title}</div>
    </div>
  );
}

// ---------- Narrative ----------
function Narrative() {
  const photoRef = useRef(null);
  useEffect(() => {
    const el = photoRef.current;
    if (!el) return;
    const img = new Image();
    img.src = "assets/detail.png";
    img.onload = () => {
      el.style.backgroundImage = `url(${img.src})`;
      el.classList.remove('ph');
      el.removeAttribute('data-label');
    };
  }, []);

  return (
    <section className="narrative" id="story" data-screen-label="Narrative">
      <div className="cols">
        <div ref={photoRef} className="photo ph img-reveal reveal-left" data-label="detail shot" />
        <div className="copy reveal-right d1">
          <span className="eyebrow" style={{ marginBottom: 18, display: 'block' }}>The Difference</span>
          <h2>Every home tells a story.<br/>Ours helps it sell.</h2>
          <p>
            We combine thoughtful design, curated furnishings, and a working knowledge
            of the coastal luxury buyer to create spaces that feel both elevated and
            effortless — the kind of rooms that read instantly in photos and linger in person.
          </p>

          <div className="pillars">
            <div className="pillar">
              <div className="dot"><Icon name="palm"/></div>
              <div className="label">Designed for the<br/>coastal luxury market</div>
            </div>
            <div className="pillar">
              <div className="dot"><Icon name="chair"/></div>
              <div className="label">Curated materials<br/>and furnishings</div>
            </div>
            <div className="pillar">
              <div className="dot"><Icon name="vase"/></div>
              <div className="label">Elevated presentation<br/>strategy</div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function Icon({ name }) {
  const common = { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.2, strokeLinecap: "round", strokeLinejoin: "round" };
  if (name === "palm")  return <svg {...common}><path d="M12 22V11"/><path d="M12 11c0-4 3-7 8-7"/><path d="M12 11c0-4-3-7-8-7"/><path d="M12 11c3-2 7-2 10 0"/><path d="M12 11c-3-2-7-2-10 0"/></svg>;
  if (name === "chair") return <svg {...common}><path d="M6 10V6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4"/><path d="M4 14h16l-1 4H5z"/><path d="M7 18v3"/><path d="M17 18v3"/></svg>;
  if (name === "vase")  return <svg {...common}><path d="M9 3h6"/><path d="M10 3v3c0 1-2 2-2 5s2 6 4 6 4-3 4-6-2-4-2-5V3"/></svg>;
  return null;
}

// ---------- Brand mark moment ----------
function BrandMark() {
  return (
    <section className="brandmark" data-screen-label="Brand">
      <div className="brandmark-rule reveal" />
      <div className="brandmark-eyebrow reveal d1">The Coastal Staging Mark</div>
      <div className="brandmark-logo reveal d2">
        <img src="assets/logo-mark.png" alt="Coastal Staging" />
      </div>
      <div className="brandmark-tag reveal d3">
        <em>Elevated living.</em> Designed to sell.
      </div>
      <div className="brandmark-rule reveal d4" />
    </section>
  );
}

// ---------- Process ----------
function Process() {
  return (
    <section className="process" id="process" data-screen-label="Process">
      <div className="wrap">
        <div className="section-head reveal">
          <span className="eyebrow">Our Process</span>
          <h2>Three steps, quietly executed.</h2>
          <p>From first walkthrough to final install, every decision is made with the market-ready presentation in mind.</p>
        </div>

        <div className="process-grid">
          <div className="step reveal">
            <div className="num">01</div>
            <h3>Consultation</h3>
            <p>We walk the home, study the market, and identify the buyer. Every proposal is grounded in the property, not a template.</p>
          </div>
          <div className="step reveal d1">
            <div className="num">02</div>
            <h3>Design &amp; Curation</h3>
            <p>Furnishings, textiles, and art are selected to elevate the architecture — never compete with it. Restraint is the strategy.</p>
          </div>
          <div className="step reveal d2">
            <div className="num">03</div>
            <h3>Installation</h3>
            <p>A fully styled, camera-ready home delivered on schedule. We stay until the last book is placed and the light is right.</p>
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- Sunset banner ----------
function Sunset() {
  const mediaRef = useRef(null);
  useEffect(() => {
    const el = mediaRef.current;
    if (!el) return;
    const img = new Image();
    img.src = "assets/sunset.png";
    img.onload = () => {
      el.style.backgroundImage = `url(${img.src})`;
      el.classList.remove('ph');
      el.removeAttribute('data-label');
    };
    // gentle parallax
    const onScroll = () => {
      if (!el) return;
      const rect = el.parentElement.getBoundingClientRect();
      const progress = 1 - Math.max(0, Math.min(1, rect.top / window.innerHeight));
      el.style.transform = `translateY(${progress * -40}px) scale(1.08)`;
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  return (
    <section className="sunset" data-screen-label="Sunset">
      <div
        ref={mediaRef}
        className="sunset-media ph"
        data-label="sunset balcony"
        style={{ backgroundImage: "linear-gradient(135deg, #4A3A2E 0%, #C28A5F 50%, #6A4A38 100%)", transform: "scale(1.08)" }}
      />
      <div className="sunset-veil" />
      <div className="sunset-copy">
        <div className="lines">
          <div className="line-wrap l1"><span>Designed to capture attention.</span></div>
          <div className="line-wrap l2"><span><em>Curated to create desire.</em></span></div>
          <div className="line-wrap l3"><span>Positioned to sell.</span></div>
        </div>
      </div>
    </section>
  );
}

// ---------- Contact ----------
function Contact() {
  return (
    <section className="contact" id="contact" data-screen-label="Contact">
      <div className="wrap">
        <div className="contact-grid">
          <div className="reveal">
            <span className="eyebrow">Begin</span>
            <h2 style={{ marginTop: 16 }}>Book a Walkthrough.</h2>
            <p>Tell us about your property. We'll take care of the rest — from first impressions to final install.</p>
            <div style={{ marginTop: 36, borderTop: '1px solid var(--rule)', paddingTop: 24, color: 'var(--ink-soft)', fontSize: 14 }}>
              <div style={{ letterSpacing: '0.26em', fontSize: 10, textTransform: 'uppercase', color: 'var(--ink-mute)', marginBottom: 10 }}>Direct</div>
              <a href="mailto:info@coastalstaging.com">info@coastalstaging.com</a>
            </div>
          </div>

          <form className="form reveal d1" onSubmit={(e) => { e.preventDefault(); alert('Thank you — we\'ll be in touch shortly.'); }}>
            <div className="field">
              <label>Name</label>
              <input type="text" required />
            </div>
            <div className="field">
              <label>Email</label>
              <input type="email" required />
            </div>
            <div className="field col-2">
              <label>Property Address</label>
              <input type="text" />
            </div>
            <div className="field">
              <label>Property Value Range</label>
              <select>
                <option>Select a range</option>
                <option>Under $2M</option>
                <option>$2M – $5M</option>
                <option>$5M – $10M</option>
                <option>$10M+</option>
              </select>
            </div>
            <div className="field">
              <label>Timeline</label>
              <select>
                <option>Select a timeline</option>
                <option>Immediate</option>
                <option>Within 30 days</option>
                <option>60–90 days</option>
                <option>Exploring</option>
              </select>
            </div>
            <div className="field col-2">
              <label>Tell us about the home</label>
              <textarea />
            </div>
            <div className="col-2" style={{ marginTop: 12 }}>
              <button className="btn solid" type="submit">Send Message <span className="arrow"/></button>
            </div>
          </form>
        </div>
      </div>
    </section>
  );
}

// ---------- Footer ----------
function Footer() {
  return (
    <footer>
      <div className="foot-grid">
        <div className="foot-col">
          <div className="brand brand-cinzel" style={{ marginBottom: 16 }}>
            <span>Coastal Staging</span>
          </div>
          <p style={{ maxWidth: 280 }}>Elevated living. Designed to sell. Serving the California coast and select luxury markets.</p>
        </div>
        <div className="foot-col">
          <h4>Explore</h4>
          <a href="#top">Home</a>
          <a href="about.html">About</a>
          <a href="#portfolio">Portfolio</a>
          <a href="#process">Process</a>
        </div>
        <div className="foot-col">
          <h4>Services</h4>
          <a href="services.html#staging">Luxury Staging</a>
          <a href="services.html#design">Interior Design</a>
          <a href="services.html#consulting">Design Consultation</a>
          <a href="services.html#styling">Styling &amp; Install</a>
        </div>
        <div className="foot-col">
          <h4>Contact</h4>
          <a href="mailto:info@coastalstaging.com">info@coastalstaging.com</a>
          <p>Newport Beach, CA</p>
          <p>By appointment</p>
        </div>
      </div>
      <div className="foot-bottom">
        <span>© 2026 Coastal Staging</span>
        <span>Privacy · Terms</span>
      </div>
    </footer>
  );
}

// ---------- Tweaks ----------
function Tweaks({ t, setT }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Typography">
        <TweakSelect
          label="Font pairing"
          value={t.fontPairing}
          onChange={(v) => setT({ fontPairing: v })}
          options={Object.entries(FONT_PAIRS).map(([k, v]) => ({ value: k, label: v.label }))}
        />
      </TweakSection>

      <TweakSection title="Hero">
        <TweakSelect
          label="Layout variant"
          value={t.heroVariant}
          onChange={(v) => setT({ heroVariant: v })}
          options={[
            { value: "centered", label: "Centered (classic)" },
            { value: "split",    label: "Editorial split" },
            { value: "wide",     label: "Full-bleed wide" },
          ]}
        />
        <TweakText
          label="Eyebrow"
          value={t.heroEyebrow}
          onChange={(v) => setT({ heroEyebrow: v })}
        />
        <TweakText
          label="Headline (use \\n for line break)"
          value={t.heroTitle.replace(/\n/g, "\\n")}
          onChange={(v) => setT({ heroTitle: v.replace(/\\n/g, "\n") })}
        />
        <TweakText
          label="Subhead"
          value={t.heroSub}
          onChange={(v) => setT({ heroSub: v })}
        />
      </TweakSection>

      <TweakSection title="Brand">
        <TweakColor
          label="Accent"
          value={t.accentColor}
          onChange={(v) => setT({ accentColor: v })}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

// ---------- App ----------
function App() {
  const [t, setT] = useTweaks(TWEAK_DEFAULTS);
  useReveal([t.heroVariant]);
  useImageParallax();

  // Apply tweakable CSS vars
  useEffect(() => {
    const root = document.documentElement;
    const pair = FONT_PAIRS[t.fontPairing] || FONT_PAIRS["marcellus-worksans"];
    root.style.setProperty('--f-display', pair.display);
    root.style.setProperty('--f-body', pair.body);
    root.style.setProperty('--accent', t.accentColor);
    // derive a darker shade for hover
    root.style.setProperty('--accent-ink', shade(t.accentColor, -18));
  }, [t.fontPairing, t.accentColor]);

  return (
    <>
      <Nav />
      <Hero
        variant={t.heroVariant}
        eyebrow={t.heroEyebrow}
        title={t.heroTitle}
        subtitle={t.heroSub}
      />
      <Portfolio />
      <Narrative />
      <BrandMark />
      <Process />
      <Sunset />
      <Contact />
      <Footer />
      <Tweaks t={t} setT={setT} />
    </>
  );
}

// Simple hex shade helper
function shade(hex, pct) {
  const h = hex.replace('#', '');
  const r = parseInt(h.substring(0,2), 16);
  const g = parseInt(h.substring(2,4), 16);
  const b = parseInt(h.substring(4,6), 16);
  const amt = pct / 100;
  const adj = (c) => Math.max(0, Math.min(255, Math.round(c + (amt < 0 ? c : 255 - c) * amt)));
  const toHex = (c) => adj(c).toString(16).padStart(2, '0');
  return '#' + toHex(r) + toHex(g) + toHex(b);
}

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