// Services (sticky chapter), Gallery (horizontal pinned), Proof

// Count up from 0 -> target once element is visible. Used in Services.
function useCountUp(target, { duration = 900, when = true } = {}) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    if (!when) return;
    let raf, start;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / duration);
      // easeOutCubic
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(eased * target));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [target, duration, when]);
  return val;
}

// ----- Services: sticky left column, scrubbing right-side media -----
function Services({ onInquire }) {
  const services = [
    {
      no: "01",
      name: "StoneGuard® Clear",
      sub: "Polished finish",
      desc: "A virtually invisible film that bonds to your stone, stain-proof, etch-proof, heat-resistant. Your marble looks identical. It just stops getting ruined.",
      bullets: ["Polished & glossy surfaces", "Stain Proof", "Etch Proof", "Lifetime Warranty"],
      img: "assets/work-clear-6.jpg",
      alt: "Polished Carrara marble island"
    },
    {
      no: "02",
      name: "StoneGuard® Satin",
      sub: "Honed finish",
      desc: "Engineered for honed stones and protects the full surface while preserving the exact tactile softness you chose your stone for.",
      bullets: ["Honed surfaces", "Matches matte finish perfectly", "Food-safe & non-yellowing", "Enhances depth and colors"],
      img: "assets/work-satin-2.png",
      alt: "Honed marble kitchen"
    },
  ];
  return (
    <section id="services" style={{ padding: "160px 0 140px", background: "var(--bone)", position: "relative" }}>
      <div className="container" style={{ position: "relative" }}>
        <Reveal>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 80, marginBottom: 120 }} className="services-head">
            <div><ServicesEyebrow /></div>
            <div>
              <h2 className="serif" style={{ fontSize: "clamp(40px, 5vw, 72px)", lineHeight: 1.02, letterSpacing: "-0.02em", maxWidth: 780 }}>
                Two finishes. One outcome: <em style={{ color: "var(--maroon)" }}>a countertop that stays like the day it was installed.</em>
              </h2>
            </div>
          </div>
        </Reveal>

        <ServicesCardGrid services={services} onInquire={onInquire} />
      </div>
      <style>{`
        @media (max-width: 860px){
          .services-head, .services-grid{ grid-template-columns: 1fr !important; gap: 40px !important; }
        }
      `}</style>
    </section>
  );
}

// --- Eyebrow with the counter that ticks 00 -> 02 as it enters ---
function ServicesEyebrow() {
  const [ref, shown] = useReveal();
  const n = useCountUp(2, { duration: 1800, when: shown });
  return (
    <div ref={ref}>
      <LineEyebrow>
        <span style={{ display: "inline-block", minWidth: "1.4em", fontVariantNumeric: "tabular-nums" }}>
          {String(n).padStart(2, "0")}
        </span>
        {" / Services"}
      </LineEyebrow>
    </div>
  );
}

// --- Grid wrapper that tracks which card is hovered and passes the state down. ---
function ServicesCardGrid({ services, onInquire }) {
  const [hover, setHover] = useState(null); // null | 0 | 1
  return (
    <div
      style={{
        display: "grid", gridTemplateColumns: "1fr 1fr", gap: 48,
        position: "relative",
        perspective: "1600px",
      }}
      className="services-grid"
      onMouseLeave={() => setHover(null)}
    >
      {services.map((s, i) => (
        <Reveal key={i} delay={i * 120}>
          <ServiceCard
            s={s}
            index={i}
            onInquire={onInquire}
            isHovered={hover === i}
            isDimmed={hover !== null && hover !== i}
            onHover={() => setHover(i)}
          />
        </Reveal>
      ))}
    </div>
  );
}

// --- Single card: image breathes in, "01/02" chip counts up,
//     3D push-forward on hover, sibling dims back. ---
function ServiceCard({ s, index, onInquire, isHovered, isDimmed, onHover }) {
  const [ref, shown] = useReveal();
  const targetNo = parseInt(s.no, 10);
  const n = useCountUp(targetNo, { duration: 1400 + index * 300, when: shown });
  return (
    <article
      ref={ref}
      onMouseEnter={onHover}
      style={{
        background: "var(--cream)",
        border: "1px solid var(--line)",
        height: "100%",
        display: "flex", flexDirection: "column",
        position: "relative",
        transformStyle: "preserve-3d",
        transform: isHovered
          ? "translate3d(0, -10px, 0) scale(1.025)"
          : isDimmed
            ? "translate3d(0, 4px, 0) scale(0.985)"
            : "translate3d(0, 0, 0) scale(1)",
        boxShadow: isHovered
          ? "0 40px 80px -30px rgba(20, 16, 12, 0.35), 0 12px 30px -15px rgba(20, 16, 12, 0.22)"
          : "0 0 0 rgba(0,0,0,0)",
        opacity: isDimmed ? 0.55 : 1,
        filter: isDimmed ? "saturate(0.85)" : "none",
        transition:
          "transform 700ms cubic-bezier(.2,.7,.2,1), box-shadow 700ms cubic-bezier(.2,.7,.2,1), opacity 600ms ease, filter 600ms ease",
        willChange: "transform",
        zIndex: isHovered ? 2 : 1,
      }}
    >
      <div style={{ overflow: "hidden", position: "relative" }}>
        <img src={s.img} alt={s.alt} style={{
          width: "100%", aspectRatio: "5/4", objectFit: "cover", display: "block",
          filter: shown ? "brightness(1) saturate(1)" : "brightness(0.55) saturate(0.4)",
          transform: shown
            ? (isHovered ? "scale(1.04)" : "scale(1)")
            : "scale(1.1)",
          transition: shown
            ? "transform 900ms cubic-bezier(.2,.7,.2,1), filter 2200ms cubic-bezier(.2,.7,.2,1)"
            : "filter 2200ms cubic-bezier(.2,.7,.2,1), transform 2400ms cubic-bezier(.2,.7,.2,1)",
          transitionDelay: shown ? "0ms" : `${300 + index * 180}ms`,
        }}/>
      </div>
      <div style={{ padding: "36px 36px 40px", display: "flex", flexDirection: "column", flex: 1 }}>
        <div className="mono" style={{ fontSize: 11, letterSpacing: "0.16em", color: "var(--mute)", marginBottom: 20, textTransform: "uppercase" }}>
          <span style={{ fontVariantNumeric: "tabular-nums", display: "inline-block", minWidth: "1.6em" }}>
            {String(n).padStart(2, "0")}
          </span>
          {` · ${s.sub}`}
        </div>
        <h3 className="serif" style={{ fontSize: 40, letterSpacing: "-0.02em", lineHeight: 1.05, marginBottom: 16 }}>
          {s.name}
        </h3>
        <p style={{ fontSize: 16, lineHeight: 1.6, color: "var(--ink-2)", marginBottom: 28 }}>
          {s.desc}
        </p>
        <ul style={{ listStyle: "none", marginBottom: 32, borderTop: "1px solid var(--line)" }}>
          {s.bullets.map((b, j) => (
            <li key={j} style={{
              padding: "14px 0",
              borderBottom: "1px solid var(--line)",
              display: "flex", alignItems: "center", gap: 14,
              fontSize: 14,
            }}>
              <svg width="12" height="12" viewBox="0 0 12 12"><path d="M2 6l3 3 5-7" stroke="var(--maroon)" strokeWidth="1.4" fill="none"/></svg>
              {b}
            </li>
          ))}
        </ul>
        <button onClick={onInquire} className="btn btn-ghost" style={{ width: "100%", justifyContent: "center", marginTop: "auto" }}>
          Get a quote for {s.name}
          <svg width="12" height="12" viewBox="0 0 12 12"><path d="M1 6h10m0 0L6 1m5 5L6 11" stroke="currentColor" strokeWidth="1.2"/></svg>
        </button>
      </div>
    </article>
  );
}

// --- The bronze line that draws in: horizontal across top under the eyebrow,
//     then vertical between the two cards. Tied to section scroll progress. ---
function ServicesLineDraw() {
  const [ref, shown] = useReveal({ threshold: 0.2 });
  return (
    <div ref={ref} aria-hidden="true" style={{
      position: "absolute", inset: 0, pointerEvents: "none", zIndex: 0,
    }}>
      <svg
        width="100%" height="100%"
        preserveAspectRatio="none"
        viewBox="0 0 1000 1000"
        style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}
      >
        {/* Horizontal stitch — sits just above the cards row */}
        <line
          x1="0" y1="340" x2="1000" y2="340"
          stroke="var(--maroon)" strokeWidth="0.6"
          strokeDasharray="1000" strokeDashoffset={shown ? 0 : 1000}
          style={{ transition: "stroke-dashoffset 1800ms cubic-bezier(.2,.7,.2,1)" }}
          opacity="0.55"
        />
        {/* Vertical stitch — drops between the two cards */}
        <line
          x1="500" y1="340" x2="500" y2="960"
          stroke="var(--maroon)" strokeWidth="0.6"
          strokeDasharray="620" strokeDashoffset={shown ? 0 : 620}
          style={{ transition: "stroke-dashoffset 2400ms cubic-bezier(.2,.7,.2,1) 700ms" }}
          opacity="0.4"
        />
      </svg>
    </div>
  );
}

// ----- Gallery: horizontal pinned scroll, ends on Eleonora testimonial panel -----
function Gallery() {
  // Uniform 3:4 portrait cards, sized off viewport HEIGHT so the photo is a
  // controlled share of the screen on every display. Width-driven sizing made
  // cards balloon on wide-but-short laptop screens (a 14" Mac is ~1512x800),
  // so we anchor to height (~70% of the viewport) and derive width from 3:4.
  const vwForSizing = typeof window !== "undefined" ? window.innerWidth : 1440;
  const vhForSizing = typeof window !== "undefined" ? window.innerHeight : 900;
  const galleryGap = 32;
  const cardAspectW = 3, cardAspectH = 4; // uniform portrait ratio for every card
  // Page padding for breathing room on the edges.
  const galleryPad = Math.max(48, vwForSizing * 0.04);
  // Height target keeps the photo from dominating short screens; the width cap
  // (no wider than ~1/2.6 of the row) keeps 2+ cards visible on wide monitors.
  const heightCardH = Math.round(vhForSizing * 0.70);
  const maxCardW = (vwForSizing - galleryPad * 2 - galleryGap * 2) / 2.6;
  const cardW = Math.round(Math.min(heightCardH * cardAspectW / cardAspectH, maxCardW));
  const cardH = Math.round(cardW * cardAspectH / cardAspectW);
  // Eleonora's portrait stays a 9:16 person-shot but matches the card HEIGHT
  // exactly (narrower column), so its top lines up with the gallery photos.
  const featPhotoW = Math.round(cardH * 9 / 16);

  const items = [
    { img: "assets/work-satin-1.png", label: "Penthouse · Manhattan", stone: "Honed black marble" },
    { img: "assets/hero-5313.jpg", label: "Coastal residence", stone: "Polished Calacatta" },
    { img: "assets/work-clear-1.jpg", label: "Open kitchen · New Jersey", stone: "Polished Carrara" },
    { img: "assets/work-clear-6.jpg", label: "Chandelier kitchen · Pennsylvania", stone: "Polished Carrara" },
    { img: "assets/work-black-kitchen.jpg", label: "Forest-view kitchen · New York", stone: "Honed marble" },
    { img: "assets/work-white-waterfall.jpg", label: "Waterfall island · New Jersey", stone: "Honed quartz" },
    { img: "assets/work-navy-original.jpg", label: "Navy kitchen · Brooklyn", stone: "Polished quartz" },
  ].map(it => ({ ...it, w: cardW }));
  // Eleonora final panel is a wider frame: portrait + full quote
  const finalPanelW = 1180; // portrait + copy panel
  const finalLeftMargin = 32; // match normal gap between gallery items
  const finalRightSpacer = typeof window !== "undefined" ? window.innerWidth * 0.35 : 560;
  const vw = typeof window !== "undefined" ? window.innerWidth : 1440;
  const introW = vw * 0.78;
  const totalW = introW + items.reduce((a, b) => a + b.w + 32, 0) + finalLeftMargin + finalPanelW + 80 + finalRightSpacer;
  const pinHeight = Math.max(200, (totalW / vw || 4) * 100);

  return (
    <section id="work" style={{ background: "var(--black)", color: "var(--bone)" }}>
      <PinnedHorizontal heightVh={Math.min(520, pinHeight + 140)}>
        {/* Intro panel — narrowed so the first photo peeks in from the right */}
        <div style={{
          flex: "0 0 auto", width: "78vw", height: "100%",
          padding: "0 72px",
          display: "flex", flexDirection: "column", justifyContent: "center",
        }} className="gallery-intro">
          <div className="mono" style={{ fontSize: 11, letterSpacing: "0.2em", textTransform: "uppercase", color: "rgba(245,242,237,0.55)", marginBottom: 28 }}>
            01 / Our Work
          </div>
          <h2 className="serif" style={{ fontSize: "clamp(56px, 8vw, 128px)", lineHeight: 0.94, letterSpacing: "-0.024em", maxWidth: 1100 }}>
            Stone we've<br/><em style={{ color: "var(--bronze)" }}>kept brand new.</em>
          </h2>
          <p style={{ fontSize: 17, lineHeight: 1.55, maxWidth: 480, color: "rgba(245,242,237,0.7)", marginTop: 40 }}>
            A quiet record of the homes we've worked in. Every surface here is still flawless, protected against stains, etches, and the everyday life of a home that gets used.
          </p>
          <div className="mono gallery-scroll-cue" style={{ marginTop: 40, fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "rgba(245,242,237,0.55)", display: "flex", alignItems: "center", gap: 14 }}>
            <span>Scroll</span>
            <span className="gallery-arrow" aria-hidden="true">
              <svg viewBox="0 0 60 10" preserveAspectRatio="none" style={{ width: "100%", height: 10, display: "block", overflow: "visible" }}>
                <line x1="0" y1="5" x2="54" y2="5" stroke="currentColor" strokeWidth="1" />
                <polyline points="50,1 54,5 50,9" stroke="currentColor" strokeWidth="1" fill="none" />
              </svg>
            </span>
          </div>
        </div>

        {items.map((it, i) => (
          <figure key={i} style={{
            flex: "0 0 auto",
            width: it.w, marginRight: galleryGap,
            display: "flex", flexDirection: "column",
          }}>
            <div style={{ width: "100%", aspectRatio: `${cardAspectW} / ${cardAspectH}`, overflow: "hidden", position: "relative", background: "#14110e" }}>
              <img src={it.img} alt={it.label} style={{
                width: "100%", height: "100%", objectFit: "cover", display: "block",
                filter: "brightness(0.95)",
              }}/>
            </div>
            <figcaption style={{ marginTop: 18, display: "flex", justifyContent: "space-between", alignItems: "baseline", flex: "0 0 auto" }}>
              <div>
                <div className="serif" style={{ fontSize: 20, letterSpacing: "-0.01em" }}>{it.stone}</div>
                <div className="mono" style={{ fontSize: 10, letterSpacing: "0.14em", color: "rgba(245,242,237,0.5)", textTransform: "uppercase", marginTop: 6 }}>{it.label}</div>
              </div>
              <div className="mono" style={{ fontSize: 11, color: "rgba(245,242,237,0.4)" }}>
                {String(i + 1).padStart(2, "0")}
              </div>
            </figcaption>
          </figure>
        ))}

        {/* Final panel: Eleonora featured testimonial — matches gallery figure height exactly */}
        <div style={{
          flex: "0 0 auto",
          width: finalPanelW, marginRight: 80, marginLeft: 0,
          display: "grid",
          gridTemplateColumns: `${featPhotoW}px 1fr`,
          gap: 56, alignItems: "center",
        }} className="gallery-feat">
          <div style={{ position: "relative", width: "100%", alignSelf: "start" }}>
            <div style={{ width: "100%", aspectRatio: "9 / 16", overflow: "hidden", position: "relative" }}>
              <img src="assets/eleonora-red.jpg" alt="Eleonora Srugo" style={{
                width: "100%", height: "100%", objectFit: "cover", display: "block",
              }}/>
              <div style={{
                position: "absolute", top: 20, left: 20,
                padding: "6px 10px",
                background: "rgba(10,9,8,0.7)", color: "var(--bone)",
                backdropFilter: "blur(6px)",
                fontFamily: "'JetBrains Mono', monospace", fontSize: 10,
                letterSpacing: "0.14em", textTransform: "uppercase",
                display: "flex", alignItems: "center", gap: 8,
              }}>
                <span style={{ width: 5, height: 5, background: "#E50914", borderRadius: 99 }}/>
                Netflix · Selling the City
              </div>
            </div>
            {/* Invisible caption spacer — mirrors the kitchen <figcaption> height so
                this column equals a gallery figure's height. The track centers every
                item, so matching heights keeps Eleonora's photo top aligned with the
                other photos instead of sitting lower. */}
            <div aria-hidden="true" style={{ marginTop: 18, visibility: "hidden" }}>
              <div className="serif" style={{ fontSize: 20, letterSpacing: "-0.01em" }}>Eleonora Srugo</div>
              <div className="mono" style={{ fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", marginTop: 6 }}>Featured client</div>
            </div>
          </div>
          <div style={{ maxWidth: 640, alignSelf: "center", paddingBottom: 52 }}>
            <div className="mono" style={{ fontSize: 11, letterSpacing: "0.2em", textTransform: "uppercase", color: "rgba(245,242,237,0.55)", marginBottom: 32 }}>
              Featured Client · In her words
            </div>
            <blockquote className="serif" style={{
              fontSize: "clamp(30px, 2.6vw, 42px)",
              lineHeight: 1.18,
              letterSpacing: "-0.015em",
              margin: 0,
              marginBottom: 44,
              color: "var(--bone)",
              textWrap: "pretty",
            }}>
              <span style={{ color: "#E8D4A8" }}>"</span>When my clients buy a $10M home, the last thing they want to worry about is a ring from a wine glass. M&amp;T is the only team I trust with stone at this level.<span style={{ color: "#E8D4A8" }}>"</span>
            </blockquote>
            <div style={{ display: "flex", alignItems: "center", gap: 20, flexWrap: "wrap", marginBottom: 56 }}>
              <div>
                <div className="serif" style={{ fontSize: 24, letterSpacing: "-0.01em", marginBottom: 4 }}>
                  Eleonora Srugo
                </div>
                <div className="mono" style={{ fontSize: 11, letterSpacing: "0.12em", color: "rgba(245,242,237,0.55)", textTransform: "uppercase" }}>
                  Top 10 Agent, Douglas Elliman
                </div>
              </div>
            </div>
            <a
              href="#"
              onClick={(e) => {
                e.preventDefault();
                window.dispatchEvent(new CustomEvent("watch-testimonial", { detail: { name: "Eleonora Srugo" } }));
              }}
              style={{
                display: "inline-flex",
                alignItems: "center",
                gap: 14,
                padding: "16px 24px 16px 20px",
                border: "1px solid rgba(232,212,168,0.45)",
                color: "var(--bone)",
                fontFamily: "'JetBrains Mono', monospace",
                fontSize: 11,
                letterSpacing: "0.22em",
                textTransform: "uppercase",
                textDecoration: "none",
                transition: "background .3s ease, border-color .3s ease, color .3s ease",
              }}
              onMouseEnter={e => {
                e.currentTarget.style.background = "#E8D4A8";
                e.currentTarget.style.borderColor = "#E8D4A8";
                e.currentTarget.style.color = "var(--black)";
              }}
              onMouseLeave={e => {
                e.currentTarget.style.background = "transparent";
                e.currentTarget.style.borderColor = "rgba(232,212,168,0.45)";
                e.currentTarget.style.color = "var(--bone)";
              }}
            >
              <span style={{
                width: 32, height: 32, borderRadius: "50%",
                border: "1px solid currentColor",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                flexShrink: 0,
              }}>
                <svg width="10" height="12" viewBox="0 0 10 12" fill="none" aria-hidden="true">
                  <path d="M0 0L10 6L0 12V0Z" fill="currentColor"/>
                </svg>
              </span>
              Watch her testimonial
            </a>
          </div>
        </div>

        {/* Spacer */}
        <div style={{ flex: "0 0 auto", width: "30vw" }}/>
      </PinnedHorizontal>
      <style>{`
        @keyframes gallery-arrow-stretch {
          0%, 100% { transform: scaleX(0.55); opacity: 0.6; }
          50%      { transform: scaleX(1);    opacity: 1; }
        }
        .gallery-arrow {
          display: inline-block;
          width: 54px;
          transform-origin: left center;
          animation: gallery-arrow-stretch 1.8s cubic-bezier(.65,.0,.35,1) infinite;
        }
        @media (max-width: 860px){
          .gallery-intro{ padding: 0 32px !important; width: 88vw !important; }
          .gallery-feat{ grid-template-columns: 1fr !important; gap: 32px !important; }
        }
      `}</style>
    </section>
  );
}

// ----- Proof: clean testimonial, drag-dial navigation -----
function Proof() {
  const reviews = [
    {
      quote: "I contacted both StoneGuard and a competitor's to protect our natural stone vanity tops in our 3 bathrooms and countertops and backsplash in our large kitchen. StoneGuard NYC reps, M&T Surface Protectors, were extremely timely with their response, professional, and thorough.",
      name: "Ned Boyd", role: "Homeowner · Westchester, NY",
      hasVideo: true,
    },
    {
      quote: "We have three young kids and white marble — a combination everyone warned us against. Michael and his team made it work. Six months in, not a single stain, and the countertops still look like the day they were installed. It genuinely changed how we live in our kitchen.",
      name: "Meera Patel", role: "Homeowner · Greenwich, CT",
      hasVideo: true,
    },
    {
      quote: "I would highly recommend M&T! They were extremely professional, thorough in their work, and very neat and organized. The quality of the surface protection exceeded our expectations — we were surprised to find that it actually enhanced the look of our stone even more than before.",
      name: "Fab", role: "Homeowner · 2 Reviews",
    },
    {
      quote: "I had the pleasure of having M&T Surface Protectors treat my marble center island today and I can't say enough about what an amazing job they did. They were on time, neat, kind, organized and very professional! They answered all of our questions.",
      name: "Yvonne Hardoon", role: "Homeowner · 4 Reviews · 2 Photos",
    },
    {
      quote: "I can't recommend Michael and his team enough. I'm about 2 months in to having them seal my kitchen counter, and I'm grateful to be stress free about it getting stained now. Also, it looks great — essentially invisible unless you really look.",
      name: "Jeremy Cohen", role: "Homeowner · Local Guide",
    },
    {
      quote: "Great company with excellent customer service. I have StoneGuard satin in my kitchen and it is excellent! It does exactly what it's supposed to do, protects my counter from stains and scratches! I can cook and use my counter worry free!",
      name: "Celeste C.", role: "Homeowner · 4 Reviews · 6 Photos",
    },
    {
      quote: "I'm really happy with the results of the work that M&T did in our kitchen. Professional, fast and honest! Would one hundred percent recommend them.",
      name: "Adela Mou", role: "Local Guide · 93 Reviews · 87 Photos",
    },
    {
      quote: "Excellent service and a top quality job. Our marble kitchen table required a lot of maintenance to maintain the shine and remove stains. The applied film is beautiful and is easy to maintain. The table looks better than new.",
      name: "Peter Weiss", role: "Local Guide · 15 Reviews · 5 Photos",
    },
    {
      quote: "Very professional, fairly priced, did a great job. Highly recommend.",
      name: "Vanessa DiFiglia", role: "Local Guide · 15 Reviews · 34 Photos",
    },
    {
      quote: "I recently purchased a home with white quartzite countertops and struggled to keep them stain-free. Michael was incredibly patient answering all my questions both before and after the install of the StoneGuard film.",
      name: "Irene D.", role: "Homeowner · New York",
    },
    {
      quote: "I had a great experience using M&T to help protect our very sensitive and etch/stain prone marble countertops by installing StoneGuard film with a professional and well-done installation. I worked with Michael from M&T throughout the process.",
      name: "Rommel Medina", role: "Homeowner · 6 Reviews · 2 Photos",
    },
    {
      quote: "M&T came to seal our new marble dining room table this morning. They were prompt, efficient and professional. They explained the entire process to us and walked us through how to care for our table once the protective sealant was on.",
      name: "Ashley Greenberg", role: "Homeowner · 2 Reviews · 1 Photo",
    },
    {
      quote: "Michael and TJ did a great job installing the StoneGuard surface protector on my kitchen island. I chose the glossy finish and am so glad I did. It really shines! So far, I love it. I've only had my Quartz countertops for 1 year.",
      name: "Marie", role: "Homeowner · 5 Reviews · 1 Photo",
    },
    {
      quote: "Fantastic job covering our coffee table with a natural stone top. Professional, accommodating, on time, and efficient. We're considering doing the kitchen quartz tables with them next.",
      name: "Mariam B.", role: "Homeowner · Bergen County, NJ",
    },
    {
      quote: "They came and did a great job covering the table. I can't see existing rings and can't even notice there's a covering. Highly recommend.",
      name: "Evan Cutler", role: "Homeowner · 6 Reviews",
    },
    {
      quote: "Michael did a great job installing the marble protector for our condo. The product is so nice, the marble countertops look even shinier after the installation. The value is great!",
      name: "Sun K.", role: "Homeowner · New York",
    },
    {
      quote: "Michael and CJ are incredibly professional and genuinely trustworthy. From start to finish, the experience was smooth and reassuring, and they clearly take pride in what they do. The product itself is excellent — high quality and exactly as promised.",
      name: "Salvatore D.", role: "Homeowner · Local Guide",
    },
    {
      quote: "Found them through social media. The team was very professional, very accommodating with scheduling. Did a fantastic job on a marble dining table and a kitchen island with waterfall sides. Highly recommended.",
      name: "Mike I.", role: "Homeowner · New York",
    },
    {
      quote: "Michael and CJ did a great job with protecting the counters. The product is great. It helps protect and keep the counters as new. They both are professionals and do a great job. Highly recommend!!",
      name: "Pawandeep Toor", role: "Homeowner · Local Guide",
    },
    {
      quote: "Excellent customer service and job done to my countertops. I recently remodeled my kitchen and installed new Quartzite countertops. I wanted to protect it, and was looking for a long-term solution that required minimum maintenance.",
      name: "Shah Nawaz C.", role: "Homeowner · Local Guide",
    },
  ];

  // --- Continuous position on a "dial." Each review occupies one unit. ---
  // pos = 0.0 means review 0 centered; pos = 1.0 means review 1 centered.
  // Fractional values are mid-drag.
  const [pos, setPos] = useState(0);
  const posRef = useRef(0);
  const draggingRef = useRef(false);
  const dragStartRef = useRef({ x: 0, pos: 0 });
  const snapRafRef = useRef(null);
  // Velocity tracking for inertia — store last few pointer samples
  const samplesRef = useRef([]);
  const PX_PER_UNIT = 180;

  const clamp = (v) => Math.max(0, Math.min(reviews.length - 1, v));

  const setPosBoth = (v) => {
    posRef.current = v;
    setPos(v);
  };

  // Decelerating inertia fling with spring bounce at the ends.
  // If the fling would exit [0, count-1], we bounce and damp instead of clamping flat.
  const flingAndSnap = (velocityUnitsPerMs) => {
    cancelAnimationFrame(snapRafRef.current);
    const friction = 0.992;        // longer free-spin coast
    const stopThreshold = 0.00004; // units/ms
    // Softer spring wall — less energy survives the hit so the return
    // is a gentle push-back rather than a quick snap.
    const bounceDamp = 0.32;
    const wallSpring = 0.006; // gentle pull toward the boundary while overshooting
    const maxBounces = 2;
    let v = velocityUnitsPerMs;
    let last = performance.now();
    let bounces = 0;

    const MAX_OVERSHOOT = 0.6; // generous cushion so the end-bar spring reads smoothly

    const step = (now) => {
      const dt = Math.min(40, now - last);
      last = now;
      let next = posRef.current + v * dt;
      // Soft spring: while past a boundary, apply a gentle pull-back force
      // on every frame. We also apply the spring if we're INSIDE the range
      // but already moving toward the valid region near an end — that way
      // the spring smoothly decays to rest instead of handing off to snapTo.
      const max = reviews.length - 1;
      if (next < 0) {
        v += wallSpring * (0 - next) * (dt / 16);
        v *= Math.pow(0.96, dt / 16);
        if (posRef.current >= 0 && next < 0) {
          const dir = Math.sign(v) || -1;
          v = dir * Math.min(Math.abs(v) * (bounceDamp + 0.4), 0.003);
          bounces += 1;
        }
        if (next < -MAX_OVERSHOOT) { next = -MAX_OVERSHOOT; v = Math.abs(v) * 0.5; }
      } else if (next > max) {
        v -= wallSpring * (next - max) * (dt / 16);
        v *= Math.pow(0.96, dt / 16);
        if (posRef.current <= max && next > max) {
          const dir = Math.sign(v) || 1;
          v = dir * Math.min(Math.abs(v) * (bounceDamp + 0.4), 0.003);
          bounces += 1;
        }
        if (next > max + MAX_OVERSHOOT) { next = max + MAX_OVERSHOOT; v = -Math.abs(v) * 0.5; }
      }
      setPosBoth(next);
      v *= Math.pow(friction, dt);

      // Decide whether to keep going. We keep integrating if:
      //  - there's meaningful velocity, OR
      //  - we're still outside the valid range (spring needs to pull us back)
      const outOfRange = next < 0 || next > max;
      if ((Math.abs(v) > stopThreshold || outOfRange) && bounces <= maxBounces) {
        snapRafRef.current = requestAnimationFrame(step);
      } else {
        // We're inside the range with negligible velocity.
        // Gently settle to the nearest integer WITHOUT a fresh easing curve —
        // use a critically-damped spring tween so there's no visible "kick".
        settleTo(Math.round(posRef.current));
      }
    };
    snapRafRef.current = requestAnimationFrame(step);
  };

  // Critically-damped settle — no oscillation. Uses a viscous pull that
  // decays smoothly to the target without overshoot or wobble.
  const settleTo = (target) => {
    cancelAnimationFrame(snapRafRef.current);
    let last = performance.now();
    const step = (now) => {
      const dt = Math.min(40, now - last);
      last = now;
      const diff = target - posRef.current;
      // Per-frame exponential decay toward target — critical damping, no overshoot.
      // Factor tuned so it covers most of the remaining distance in ~350ms.
      const next = posRef.current + diff * (1 - Math.pow(0.82, dt / 16));
      setPosBoth(next);
      if (Math.abs(target - next) > 0.002) {
        snapRafRef.current = requestAnimationFrame(step);
      } else {
        setPosBoth(target);
      }
    };
    snapRafRef.current = requestAnimationFrame(step);
  };

  const snapTo = (target) => {
    cancelAnimationFrame(snapRafRef.current);
    const start = posRef.current;
    const t0 = performance.now();
    // Duration scales with distance — short hops finish in ~180ms (no delay),
    // longer glides take proportionally more time but still feel responsive.
    const dist = Math.abs(target - start);
    const dur = Math.max(180, Math.min(520, 180 + dist * 140));
    const ease = (t) => 1 - Math.pow(1 - t, 4);
    const step = (now) => {
      const p = Math.min(1, (now - t0) / dur);
      const v = start + (target - start) * ease(p);
      setPosBoth(v);
      if (p < 1) snapRafRef.current = requestAnimationFrame(step);
    };
    snapRafRef.current = requestAnimationFrame(step);
  };

  const pushSample = (x) => {
    const now = performance.now();
    samplesRef.current.push({ x, t: now });
    // Keep only samples from the last 100ms
    samplesRef.current = samplesRef.current.filter(s => now - s.t < 100);
  };

  const getVelocityUnitsPerMs = () => {
    const s = samplesRef.current;
    if (s.length < 2) return 0;
    const first = s[0];
    const last = s[s.length - 1];
    const dt = last.t - first.t;
    if (dt < 8) return 0;
    const dx = last.x - first.x;
    // Drag RIGHT = negative pos (older reviews go left); velocity is -dx/dt converted to units/ms
    return -dx / dt / PX_PER_UNIT;
  };

  const onPointerDown = (e) => {
    e.currentTarget.setPointerCapture?.(e.pointerId);
    draggingRef.current = true;
    cancelAnimationFrame(snapRafRef.current);
    dragStartRef.current = { x: e.clientX, pos: posRef.current };
    samplesRef.current = [{ x: e.clientX, t: performance.now() }];
  };
  const onPointerMove = (e) => {
    if (!draggingRef.current) return;
    const dx = e.clientX - dragStartRef.current.x;
    // Soft over-travel: rubber-band past the edges by a damped half-unit so the
    // user feels resistance, and the spring bounce on release reads correctly.
    const raw = dragStartRef.current.pos - dx / PX_PER_UNIT;
    let next = raw;
    const min = 0, max = reviews.length - 1;
    if (raw < min) next = min - Math.min(0.5, (min - raw) * 0.35);
    else if (raw > max) next = max + Math.min(0.5, (raw - max) * 0.35);
    setPosBoth(next);
    pushSample(e.clientX);
  };
  const onPointerUp = (e) => {
    if (!draggingRef.current) return;
    draggingRef.current = false;
    e.currentTarget.releasePointerCapture?.(e.pointerId);
    const v = getVelocityUnitsPerMs();
    // Release-velocity drives the fling. Fast flick = long coast, even to the
    // end of the strip. Gentle release with no velocity = snap to whichever
    // tick you're closest to (half-tick threshold is automatic via Math.round).
    if (Math.abs(v) > 0.00015) {
      flingAndSnap(v);
    } else {
      snapTo(Math.round(posRef.current));
    }
  };

  // Scroll wheel — feeds the same fling physics as drag.
  // We track the last few wheel events to compute a velocity, update position
  // live, and when the wheel stops we hand off to flingAndSnap so it coasts
  // with friction and springs off the ends. Fast flick = long roll; gentle
  // nudge = short coast.
  const wheelSamplesRef = useRef([]);
  const onWheel = (e) => {
    const dominantDX = Math.abs(e.deltaX) > Math.abs(e.deltaY);
    const delta = dominantDX ? e.deltaX : e.deltaY;
    if (Math.abs(delta) < 2) return;
    e.preventDefault();
    cancelAnimationFrame(snapRafRef.current);

    const now = performance.now();
    // Live update: accumulate into pos, but DON'T clamp hard — allow a small
    // over-travel (±0.5) so the spring has room to pull back.
    const softMin = -0.5;
    const softMax = reviews.length - 1 + 0.5;
    const raw = posRef.current + delta / 260;
    const next = Math.max(softMin, Math.min(softMax, raw));
    setPosBoth(next);

    // Record a velocity sample (in units/ms)
    wheelSamplesRef.current.push({ pos: next, t: now });
    wheelSamplesRef.current = wheelSamplesRef.current.filter(s => now - s.t < 120);

    clearTimeout(onWheel._t);
    onWheel._t = setTimeout(() => {
      // Compute velocity from last wheel samples
      const samples = wheelSamplesRef.current;
      let v = 0;
      if (samples.length >= 2) {
        const first = samples[0];
        const last = samples[samples.length - 1];
        const dt = last.t - first.t;
        if (dt > 8) v = (last.pos - first.pos) / dt;
      }
      wheelSamplesRef.current = [];
      // If meaningful velocity, fling; otherwise just snap.
      if (Math.abs(v) > 0.0004) {
        flingAndSnap(v);
      } else {
        snapTo(Math.round(posRef.current));
      }
    }, 90);
  };

  // Active index — used for avatar/name display (rounded)
  const activeIdx = Math.round(pos);
  const r = reviews[activeIdx];

  return (
    <section id="reviews" style={{ padding: "160px 0 220px", background: "var(--bone)", overflow: "hidden" }}>
      <div className="container">
        <div style={{ display: "grid", gridTemplateColumns: "minmax(380px, 1fr) 1.8fr", gap: 80, alignItems: "start" }} className="proof-grid">
          <div>
            <LineEyebrow style={{ marginBottom: 28 }}>03 / In their words</LineEyebrow>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
              <Stars n={5} />
            </div>
            <div className="mono" style={{ fontSize: 11, letterSpacing: "0.16em", color: "var(--mute)", textTransform: "uppercase", lineHeight: 1.7 }}>
              5-Star Google<br/>
              5-Star Houzz
            </div>

            <div style={{ marginTop: 48 }}>
              <ProofDial
                pos={pos}
                count={reviews.length}
                onPointerDown={onPointerDown}
                onPointerMove={onPointerMove}
                onPointerUp={onPointerUp}
                onWheel={onWheel}
                onTickClick={(j) => {
                  settleTo(j);
                }}
                onPrev={() => {
                  const target = Math.max(0, activeIdx - 1);
                  if (target === activeIdx) {
                    // Already on first — do a little spring bump for feedback
                    flingAndSnap(-0.004);
                  } else {
                    settleTo(target);
                  }
                }}
                onNext={() => {
                  const target = Math.min(reviews.length - 1, activeIdx + 1);
                  if (target === activeIdx) {
                    flingAndSnap(0.004);
                  } else {
                    settleTo(target);
                  }
                }}
              />
            </div>
          </div>

          {/* Right column: the quote stack — clean crossfade, no blur */}
          <div style={{ position: "relative" }}>
            <div style={{
              position: "relative",
              minHeight: 360,
            }}>
              {reviews.map((rev, j) => {
                // Text follows the gear exactly — including spring overshoot.
                // Both elements bounce in the same direction at the same time.
                const offset = (j - pos); // 0 = centered
                const px = offset * 60;
                const d = Math.abs(offset);
                // Hard opacity falloff: only the near-centered card is visible.
                // Beyond ~0.5 units the neighbor is already invisible — no overlap, no ghost text.
                const opacity = d < 0.5 ? 1 - (d / 0.5) : 0;
                return (
                  <div key={j} style={{
                    position: "absolute",
                    top: 0, left: 0, right: 0,
                    transform: `translate3d(${px}px, 0, 0)`,
                    opacity,
                    pointerEvents: activeIdx === j ? "auto" : "none",
                    // Transform is driven frame-by-frame by the JS animation
                    // (fling/snap/drag) so there must be NO CSS transition on
                    // it — otherwise the text lags behind the gear. Only the
                    // fade is CSS-animated.
                    transition: "opacity 200ms ease",
                    willChange: "transform, opacity",
                  }}>
                    {/* Profile card — ABOVE the quote. Button pinned to the
                        quote's right edge (Option C) — both share maxWidth so
                        their right edges align exactly. */}
                    <div style={{
                      display: "flex", alignItems: "center", justifyContent: "space-between",
                      gap: 24, marginBottom: 28,
                      maxWidth: 760,
                    }}>
                      <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
                        <div style={{
                          width: 44, height: 44, borderRadius: 99,
                          background: "var(--bone-2)", display: "grid", placeItems: "center",
                          fontFamily: "'Instrument Serif', serif", fontSize: 18, color: "var(--ink-2)",
                          flexShrink: 0,
                        }}>{rev.name[0]}</div>
                        <div>
                          <div style={{ fontSize: 14, fontWeight: 500 }}>{rev.name}</div>
                          <div className="mono" style={{ fontSize: 11, color: "var(--mute)", letterSpacing: "0.12em", textTransform: "uppercase", marginTop: 2 }}>
                            {rev.role}
                          </div>
                        </div>
                      </div>
                      {rev.hasVideo && (
                        <a
                          href="#"
                          onClick={(e) => {
                            e.preventDefault();
                            window.dispatchEvent(new CustomEvent("watch-testimonial", { detail: { name: rev.name } }));
                          }}
                          style={{
                            display: "inline-flex",
                            alignItems: "center",
                            gap: 12,
                            padding: "10px 18px 10px 12px",
                            border: "1px solid color-mix(in oklab, var(--maroon) 55%, transparent)",
                            color: "var(--ink)",
                            fontFamily: "'JetBrains Mono', monospace",
                            fontSize: 10,
                            letterSpacing: "0.22em",
                            textTransform: "uppercase",
                            textDecoration: "none",
                            background: "transparent",
                            whiteSpace: "nowrap",
                            transition: "background .3s ease, border-color .3s ease, color .3s ease",
                          }}
                          onMouseEnter={(e) => {
                            e.currentTarget.style.background = "var(--maroon)";
                            e.currentTarget.style.borderColor = "var(--maroon)";
                            e.currentTarget.style.color = "var(--bone)";
                          }}
                          onMouseLeave={(e) => {
                            e.currentTarget.style.background = "transparent";
                            e.currentTarget.style.borderColor = "color-mix(in oklab, var(--maroon) 55%, transparent)";
                            e.currentTarget.style.color = "var(--ink)";
                          }}
                        >
                          <span style={{
                            width: 24, height: 24, borderRadius: "50%",
                            border: "1px solid currentColor",
                            display: "inline-flex", alignItems: "center", justifyContent: "center",
                            flexShrink: 0,
                          }}>
                            <svg width="7" height="9" viewBox="0 0 10 12" fill="none" aria-hidden="true">
                              <path d="M0 0L10 6L0 12V0Z" fill="currentColor"/>
                            </svg>
                          </span>
                          Watch Testimonial
                        </a>
                      )}
                    </div>

                    <blockquote className="serif" style={{
                      fontSize: "clamp(28px, 3.4vw, 48px)", lineHeight: 1.22, letterSpacing: "-0.02em",
                      margin: 0,
                      maxWidth: 760,
                    }}>
                      <span style={{ color: "var(--maroon)" }}>"</span>{rev.quote}<span style={{ color: "var(--maroon)" }}>"</span>
                    </blockquote>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      </div>
      <style>{`
        @media (max-width: 860px){ .proof-grid{ grid-template-columns: 1fr !important; gap: 40px !important; } }
      `}</style>
    </section>
  );
}

// --- The dial: a slim linear gauge set into a light bone-colored plate.
//     Editorial and instrumental, not industrial. Ticks curve via cylinder
//     perspective so the strip still reads as "rolling," just quieter. ---
function ProofDial({ pos, count, onPointerDown, onPointerMove, onPointerUp, onWheel, onTickClick, onPrev, onNext }) {
  const WIDTH = 340;
  const HEIGHT = 72;
  const CENTER = 60;
  const DEG_PER_REVIEW = 90;
  const DEG_PER_MINOR = 9;
  const VISIBLE_ARC = 92;

  const captionRef = useRef(null);
  const [captionWidth, setCaptionWidth] = useState(WIDTH);
  useEffect(() => {
    const el = captionRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      setCaptionWidth(el.getBoundingClientRect().width);
    });
    ro.observe(el);
    setCaptionWidth(el.getBoundingClientRect().width);
    return () => ro.disconnect();
  }, []);

  const wrapRef = useRef(null);
  useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const handler = (e) => onWheel(e);
    el.addEventListener("wheel", handler, { passive: false });
    return () => el.removeEventListener("wheel", handler);
  }, [onWheel]);

  const R = WIDTH * 0.58;
  const rotationDeg = pos * DEG_PER_REVIEW;

  const ticks = [];
  const minDeg = 0;
  const maxDeg = (count - 1) * DEG_PER_REVIEW;
  for (let deg = minDeg; deg <= maxDeg; deg += DEG_PER_MINOR) {
    const isMajor = deg % DEG_PER_REVIEW === 0;
    const reviewIdx = deg / DEG_PER_REVIEW;
    const inRange = reviewIdx >= 0 && reviewIdx <= count - 1 && Number.isInteger(reviewIdx);
    ticks.push({ deg, isMajor, inRange, reviewIdx });
  }

  return (
    <div style={{ userSelect: "none", width: "100%", maxWidth: WIDTH }}>
      {/* Bare gauge — no plate, sits directly on page background */}
      <div
        ref={wrapRef}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
        style={{
          position: "relative",
          width: "100%",
          height: HEIGHT,
          cursor: "grab",
          touchAction: "pan-y",
          overflow: "hidden",
        }}
        onMouseDown={(e) => { e.currentTarget.style.cursor = "grabbing"; }}
        onMouseUp={(e) => { e.currentTarget.style.cursor = "grab"; }}
        onMouseLeave={(e) => { e.currentTarget.style.cursor = "grab"; }}
      >
        {ticks.map(({ deg, isMajor, inRange, reviewIdx }) => {
          const angle = deg - rotationDeg;
          if (angle < -VISIBLE_ARC || angle > VISIBLE_ARC) return null;
          const rad = (angle * Math.PI) / 180;
          const x = CENTER + Math.sin(rad) * R;
          const depth = Math.cos(rad);
          if (depth < 0.05) return null;

          // Distance from the active (centered) position, in "review units"
          // Used to emphasize the currently-selected tick.
          const unitsFromActive = Math.abs(angle / DEG_PER_REVIEW);
          const isActive = isMajor && unitsFromActive < 0.5;

          // End caps: first and last major tick — tall structural bars.
          const isFirstEnd = isMajor && reviewIdx === 0;
          const isLastEnd = isMajor && reviewIdx === count - 1;
          const isEnd = isFirstEnd || isLastEnd;

          // Growth curve: ticks near the active position are tallest; they
          // shrink as they move away. Multiplied by `depth` for cylinder
          // perspective. Active major tick gets a small extra boost so it
          // reads as "you are here."
          const proximity = Math.max(0, 1 - unitsFromActive / 3); // 0..1 within 3 units
          const majorScale = 0.55 + 0.45 * proximity;  // 0.55..1.0
          const activeBoost = isActive ? 1.18 : 1;

          const h = (isEnd ? 56 : isMajor ? 36 * majorScale : 12 * (0.5 + 0.5 * proximity)) * depth * activeBoost;
          const w = (isEnd ? 2.2 : isMajor ? 1.2 : 0.8) * Math.max(0.5, depth);
          const isClickable = isMajor && inRange;
          const baseColor = isActive
            ? "var(--maroon)"
            : isEnd
              ? "var(--ink)"
              : inRange
                ? isMajor ? "var(--ink)" : "rgba(30,26,22,0.45)"
                : "rgba(30,26,22,0.12)";

          return (
            <div
              key={deg}
              onClick={isClickable ? (e) => { e.stopPropagation(); onTickClick(reviewIdx); } : undefined}
              style={{
                position: "absolute",
                left: x,
                top: "50%",
                transform: `translate(-50%, -50%)`,
                width: w,
                height: h,
                background: baseColor,
                opacity: Math.max(0.1, depth * depth),
                cursor: isClickable ? "pointer" : "inherit",
                pointerEvents: isClickable ? "auto" : "none",
                transition: "background 180ms ease",
              }}
            />
          );
        })}

        {/* Side fade — soft on both sides so ticks "roll in" from either direction */}
        <div style={{
          position: "absolute", inset: 0,
          pointerEvents: "none",
          background:
            "linear-gradient(90deg, rgba(245,242,237,0.9) 0%, rgba(245,242,237,0) 6%, rgba(245,242,237,0) 82%, var(--bone) 100%)",
        }}/>
      </div>

      {/* Progress track — matches the caption's exact width so it ends at the → arrow */}
      <div style={{
        marginTop: 18, width: captionWidth,
        height: 2, background: "rgba(30,26,22,0.08)", position: "relative",
      }}>
        <div style={{
          position: "absolute", top: 0, left: 0, height: "100%",
          width: `${(pos / Math.max(1, count - 1)) * 100}%`,
          background: "var(--maroon)",
          transition: "none",
        }}/>
      </div>

      <div ref={captionRef} className="mono" style={{
        fontSize: 10, letterSpacing: "0.22em", textTransform: "uppercase",
        color: "var(--mute)", marginTop: 14,
        display: "flex", alignItems: "center", justifyContent: "flex-start", gap: 10,
        width: "fit-content", maxWidth: WIDTH,
      }}>
        <button
          onClick={onPrev}
          aria-label="Previous review"
          style={{
            background: "transparent", border: 0, padding: "6px 8px 6px 0",
            cursor: "pointer", color: "inherit", display: "inline-flex", alignItems: "center",
            transition: "color 160ms ease",
          }}
          onMouseEnter={(e) => { e.currentTarget.style.color = "var(--ink)"; }}
          onMouseLeave={(e) => { e.currentTarget.style.color = "var(--mute)"; }}
        >
          <svg width="12" height="10" viewBox="0 0 12 10" fill="none">
            <path d="M0 5h11M0 5l4-4M0 5l4 4" stroke="currentColor" strokeWidth="1"/>
          </svg>
        </button>
        <span>Drag or scroll to browse</span>
        <button
          onClick={onNext}
          aria-label="Next review"
          style={{
            background: "transparent", border: 0, padding: "6px 0 6px 8px",
            cursor: "pointer", color: "inherit", display: "inline-flex", alignItems: "center",
            transition: "color 160ms ease",
          }}
          onMouseEnter={(e) => { e.currentTarget.style.color = "var(--ink)"; }}
          onMouseLeave={(e) => { e.currentTarget.style.color = "var(--mute)"; }}
        >
          <svg width="12" height="10" viewBox="0 0 12 10" fill="none">
            <path d="M1 5h11M12 5l-4-4M12 5l-4 4" stroke="currentColor" strokeWidth="1"/>
          </svg>
        </button>
      </div>
    </div>
  );
}

// ----- The System: dark background with floating light explainer card (Strata-style) -----
function System() {
  return (
    <section style={{
      position: "relative",
      background: "var(--black)",
      color: "var(--bone)",
      padding: "140px 0",
      overflow: "hidden",
    }}>
      <div style={{
        position: "absolute", inset: 0,
      }}>
        <img src="assets/work-satin-3.png" alt="" style={{
          width: "100%", height: "100%", objectFit: "cover",
          filter: "brightness(0.45) saturate(0.8)",
        }}/>
      </div>
      <div style={{ position: "absolute", inset: 0, background: "linear-gradient(90deg, rgba(10,9,8,0.6) 0%, rgba(10,9,8,0.2) 100%)" }}/>

      <div className="container" style={{ position: "relative", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 80, alignItems: "center" }}>
        <div className="system-card" style={{
          background: "var(--bone)",
          color: "var(--ink)",
          padding: "56px 48px",
          border: "1px solid var(--line)",
          boxShadow: "0 40px 80px -20px rgba(0,0,0,0.5)",
        }}>
          <Reveal>
            <LineEyebrow style={{ color: "var(--mute)", marginBottom: 28 }}>
              01 / The System
            </LineEyebrow>
            <h2 className="serif" style={{
              fontSize: "clamp(40px, 4.5vw, 64px)",
              lineHeight: 1.04,
              letterSpacing: "-0.022em",
              marginBottom: 24,
            }}>
              The StoneGuard® System.
            </h2>
            <p style={{ fontSize: 17, lineHeight: 1.6, color: "var(--ink-2)", marginBottom: 36 }}>
              An advanced, nearly invisible barrier engineered to preserve the beauty of natural stone. It bonds to the surface, takes the abuse that stone can't, and leaves your countertop looking identical to the day it was installed.
            </p>
            <ul style={{ listStyle: "none", borderTop: "1px solid var(--line)" }}>
              {[
                { t: "Nearly invisible", d: "You see stone, not a coating." },
                { t: "Stain & etch resistant", d: "Red wine, lemon, tomato. All safe." },
                { t: "Heat resistant", d: "Hot pans set down without fear." },
                { t: "Food safe & non yellowing", d: "Certified for kitchen use." },
              ].map((r, i) => (
                <li key={i} style={{
                  padding: "18px 0",
                  borderBottom: "1px solid var(--line)",
                  display: "grid", gridTemplateColumns: "1fr 1.4fr", gap: 20, alignItems: "baseline",
                }}>
                  <div className="mono" style={{ fontSize: 11, letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--ink)" }}>
                    {String(i + 1).padStart(2, "0")} · {r.t}
                  </div>
                  <div style={{ fontSize: 14, color: "var(--mute)" }}>{r.d}</div>
                </li>
              ))}
            </ul>
          </Reveal>
        </div>

        <div className="system-side">
          <Reveal delay={200}>
            <div className="serif" style={{ fontSize: "clamp(32px, 3.5vw, 52px)", lineHeight: 1.1, letterSpacing: "-0.02em", color: "var(--bone)", marginBottom: 28, maxWidth: 480 }}>
              The first line of defense<br/>
              <em style={{ color: "#E8D4A8" }}>between your stone and the life around it.</em>
            </div>
            <div className="mono" style={{ fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "rgba(245,242,237,0.55)" }}>
              Certified StoneGuard® Installer
            </div>
          </Reveal>
        </div>
      </div>

      <style>{`
        @media (max-width: 860px){
          .system-card{ padding: 40px 28px !important; }
          .container > div[style*="grid-template-columns: 1fr 1fr"]{ grid-template-columns: 1fr !important; gap: 40px !important; }
        }
      `}</style>
    </section>
  );
}

// ----- Applications: room type grid -----
function Applications() {
  const apps = [
    { name: "Kitchens", img: "assets/work-clear-1.jpg" },
    { name: "Master Baths", img: "assets/work-clear-2.jpg" },
    { name: "Dining Tables", img: "assets/work-clear-4.jpg" },
    { name: "Bars & Built-ins", img: "assets/work-clear-5.jpg" },
    { name: "Outdoor Kitchens", img: "assets/hero-5313.jpg" },
    { name: "Vanities & Tops", img: "assets/work-satin-3.png" },
  ];
  return (
    <section style={{ padding: "140px 0", background: "var(--bone)" }}>
      <div className="container">
        <Reveal>
          <div style={{ textAlign: "center", marginBottom: 80, maxWidth: 820, margin: "0 auto 80px" }}>
            <LineEyebrow style={{ color: "var(--mute)", justifyContent: "center", marginBottom: 24 }}>
              03 / Applications
            </LineEyebrow>
            <h2 className="serif" style={{ fontSize: "clamp(40px, 5vw, 72px)", lineHeight: 1.05, letterSpacing: "-0.022em" }}>
              Preserve the allure of natural stone<br/>
              <em style={{ color: "var(--maroon)" }}>in every room of the home.</em>
            </h2>
          </div>
        </Reveal>

        <div style={{
          display: "grid",
          gridTemplateColumns: "repeat(3, 1fr)",
          gap: 24,
        }} className="apps-grid">
          {apps.map((a, i) => (
            <Reveal key={i} delay={i * 80} y={16}>
              <figure style={{ position: "relative" }}>
                <div style={{ aspectRatio: "4/5", overflow: "hidden" }}>
                  <img src={a.img} alt={a.name} style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}/>
                </div>
                <figcaption style={{
                  marginTop: 16,
                  display: "flex", justifyContent: "space-between", alignItems: "baseline",
                }}>
                  <div className="serif" style={{ fontSize: 22, letterSpacing: "-0.01em" }}>{a.name}</div>
                  <div className="mono" style={{ fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--mute)" }}>
                    {String(i + 1).padStart(2, "0")}
                  </div>
                </figcaption>
              </figure>
            </Reveal>
          ))}
        </div>
      </div>
      <style>{`
        @media (max-width: 860px){
          .apps-grid{ grid-template-columns: repeat(2, 1fr) !important; }
        }
      `}</style>
    </section>
  );
}

Object.assign(window, { Services, Gallery, Proof, System, Applications });
