/* ============================================================
   FLOORING SITE — layout & logic only.
   Brand data lives in brand.js (loaded as window.BRAND before
   this file). Keep all business-specific copy out of here.
   ============================================================ */

/* ============================================================
   THEMES - three full palettes the components read from
   ============================================================ */

const THEMES = {
  light: {
    id: "light",
    bg: "#FAF6EE", // warm cream
    bgAlt: "#F1E9D6", // deeper cream
    surface: "#FFFFFF",
    surfaceAlt: "#FDF9F0",
    border: "#E2D8C2",
    borderStrong: "#C7B894",
    text: "#1F1B14", // warm near-black
    textMuted: "#6B6354",
    primary: "#1E3A5F", // navy
    primaryHover: "#152A47",
    onPrimary: "#FAF6EE",
    accent: "#C8552B", // warm orange
    accentHover: "#A8431F",
    onAccent: "#FFFFFF",
    star: "#D9A441",
    heroBg: "#1E3A5F",
    heroText: "#FAF6EE",
    heroSubtext: "#C9D2DD",
    footerBg: "#1A1D24",
    footerText: "#E5DDCB",
    footerMuted: "#8C857A",
    block: "#1E3A5F", // navy emphasis block
    onBlock: "#FAF6EE",
    chip: "#F1E9D6",
    onChip: "#5C4926",
    heroScale: 1
  },
  dark: {
    id: "dark",
    bg: "#0F1620",
    bgAlt: "#161E2A",
    surface: "#1A2230",
    surfaceAlt: "#1F2937",
    border: "#2A3645",
    borderStrong: "#3D4C61",
    text: "#F0E8D6",
    textMuted: "#9A9382",
    primary: "#E9B872", // warm amber
    primaryHover: "#F2C684",
    onPrimary: "#0F1620",
    accent: "#C8552B",
    accentHover: "#D9683E",
    onAccent: "#FFFFFF",
    star: "#E9B872",
    heroBg: "#0A111B",
    heroText: "#F0E8D6",
    heroSubtext: "#A39E92",
    footerBg: "#070B12",
    footerText: "#9A9382",
    footerMuted: "#5C5749",
    block: "#E9B872",
    onBlock: "#0F1620",
    chip: "#1F2937",
    onChip: "#E9B872",
    heroScale: 1
  },
  bold: {
    id: "bold",
    bg: "#FBF5E9",
    bgAlt: "#F4E8CC",
    surface: "#FFFFFF",
    surfaceAlt: "#FBF5E9",
    border: "#E2D8C2",
    borderStrong: "#1A1D24",
    text: "#1A1D24",
    textMuted: "#5C5751",
    primary: "#1A1D24", // near-black for confident type
    primaryHover: "#000000",
    onPrimary: "#FBF5E9",
    accent: "#E85A1A", // saturated orange
    accentHover: "#C24812",
    onAccent: "#FFFFFF",
    star: "#1A1D24",
    heroBg: "#F2EADB", // warm sand neutral
    heroText: "#1A1D24",
    heroSubtext: "#5C5751",
    footerBg: "#1A1D24",
    footerText: "#FBF5E9",
    footerMuted: "#8A8275",
    block: "#211C16", // dark neutral band (never orange bg)
    onBlock: "#FBF5E9",
    chip: "#1A1D24",
    onChip: "#FBF5E9",
    heroScale: 1.18 // bigger type
  }
};

const t = THEMES[BRAND.theme] || THEMES.light;

// Only surface the review COUNT when it's high enough to build trust.
// Below this, we still show the star rating but hide "· N reviews".
const SHOW_REVIEW_COUNT = (BRAND.reviewCount || 0) >= 15;

// Monogram for the no-logo nav badge: BRAND.monogram if set, else the first
// letter of each of the first two real words (only connectors/legal suffixes
// are skipped — descriptor words like "Flooring" still count, so
// "Generation Flooring" -> "GF", "American Custom Flooring" -> "AC").
function brandMonogram() {
  if (BRAND.monogram) return BRAND.monogram;
  const filler = new Set(["and", "co", "co.", "llc", "inc", "inc.", "the", "of", "&"]);
  const words = (BRAND.shortName || "").split(/\s+/)
    .filter((w) => w && !filler.has(w.toLowerCase().replace(/[^a-z.]/gi, "")));
  let initials = words.map((w) => w.replace(/[^A-Za-z]/g, "")[0] || "").join("").slice(0, 2);
  if (initials.length < 2 && words[0]) initials = words[0].replace(/[^A-Za-z]/g, "").slice(0, 2);
  return (initials || (BRAND.shortName || "•")[0]).toUpperCase();
}

/* ============================================================
   ICON - lucide wrapper. Reads from window.lucide.icons.
   ============================================================ */
function Icon({ name, size = 20, stroke, strokeWidth = 1.75, className = "", style = {} }) {
  const data = window.lucide && window.lucide.icons && window.lucide.icons[name] ||
  window.lucide && window.lucide.icons && window.lucide.icons.Circle;
  if (!data) {
    return <span className={className} style={{ display: "inline-block", width: size, height: size, ...style }} />;
  }
  const [, attrs, children] = data;
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width={size} height={size}
      viewBox={attrs.viewBox || "0 0 24 24"}
      fill={attrs.fill || "none"}
      stroke={stroke || "currentColor"}
      strokeWidth={strokeWidth}
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
      style={style}
      aria-hidden="true">
      
      {children.map(([tag, props], i) => React.createElement(tag, { key: i, ...props }))}
    </svg>);

}

/* ============================================================
   PHOTO - Unsplash with woven-texture fallback
   ============================================================ */
function Photo({ id, src: srcProp, alt, className = "", style = {}, label, dark = false, ...rest }) {
  const [failed, setFailed] = React.useState(!id && !srcProp);
  React.useEffect(() => { setFailed(!id && !srcProp); }, [id, srcProp]);
  const src = srcProp ? srcProp : id ? `https://images.unsplash.com/photo-${id}?w=1200&q=80&auto=format&fit=crop` : null;
  if (failed) {
    return (
      <div
        className={`${className} ${dark ? "photo-fallback-dark" : "photo-fallback"} flex items-end justify-start`}
        style={style}
        role="img"
        aria-label={alt}
        {...rest}>
        
        {label &&
        <span className="font-mono text-[11px] tracking-wide opacity-70 p-3 lowercase">
            {label}
          </span>
        }
      </div>);

  }
  return (
    <img
      src={src}
      alt={alt}
      onError={() => setFailed(true)}
      className={className}
      style={style}
      loading="lazy"
      {...rest} />);


}

/* ============================================================
   PHOTO MANIFEST - the single source of truth: photos/manifest.json.
   Drop an image into photos/<category>/ and add its filename to that
   category in manifest.json; it appears automatically. No code edits.
   ============================================================ */
let _photoManifest = null;
let _manifestPromise = null;
const _manifestSubs = new Set();
function loadPhotoManifest() {
  if (_photoManifest) return Promise.resolve(_photoManifest);
  if (_manifestPromise) return _manifestPromise;
  _manifestPromise = fetch("photos/manifest.json", { cache: "no-store" }).
  then((r) => r.ok ? r.json() : {}).
  then((m) => {_photoManifest = m || {};_manifestSubs.forEach((fn) => fn(_photoManifest));return _photoManifest;}).
  catch(() => {_photoManifest = {};return _photoManifest;});
  return _manifestPromise;
}
function usePhotoManifest() {
  const [m, setM] = React.useState(_photoManifest);
  React.useEffect(() => {
    if (_photoManifest) {setM(_photoManifest);return;}
    let alive = true;
    const fn = (mm) => {if (alive) setM(mm);};
    _manifestSubs.add(fn);
    loadPhotoManifest();
    return () => {alive = false;_manifestSubs.delete(fn);};
  }, []);
  return m;
}
function categoryPhotos(manifest, category) {
  if (!manifest || !category) return [];
  const c = manifest.categories && manifest.categories[category];
  const files = Array.isArray(c) ? c : c && c.photos || [];
  return (files || []).
  filter((f) => typeof f === "string" && f.trim()).
  map((f) => `photos/${category}/${encodeURIComponent(f.trim())}`);
}
function categoryLabel(manifest, category) {
  const c = manifest && manifest.categories && manifest.categories[category];
  return c && c.label || "";
}
function marqueePhotos(manifest) {
  if (!manifest) return [];
  const list = Array.isArray(manifest.marquee) ? manifest.marquee : [];
  return list.
  filter((f) => typeof f === "string" && f.trim()).
  map((f) => {
    const v = f.trim();
    return v.includes("/") ?
    "photos/" + v.split("/").map(encodeURIComponent).join("/") :
    "photos/marquee/" + encodeURIComponent(v);
  });
}

/* CATEGORYMEDIA - renders a service's photos as the shared carousel +
   full-screen lightbox. One photo shows static (still opens the lightbox);
   several auto-swipe. Pulls straight from the manifest. */
function CategoryMedia({ category, alt, className = "", radius = 18 }) {
  const manifest = usePhotoManifest();
  const photos = categoryPhotos(manifest, category);
  return (
    <ServiceCarousel
      photos={photos}
      alt={alt || categoryLabel(manifest, category)}
      className={className}
      radius={radius} />);

}

/* ============================================================
   SERVICECAROUSEL - a single pane that auto-swipes through a set
   of project photos and opens them in the lightbox on click.
   Used for flagship services that have a `slots` array of images.
   ============================================================ */
function useSwipeNav(ref, onStep) {
  const stepRef = React.useRef(onStep);
  stepRef.current = onStep;
  const swipedRef = React.useRef(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let accum = 0,lock = false,lockTimer = null;
    // Trackpad / mouse horizontal scroll (Mac two-finger). Natural direction:
    // scrolling left advances to the next (right-hand) photo.
    const onWheel = (e) => {
      if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return; // vertical -> let the page scroll
      e.preventDefault(); // also stops the browser back/forward swipe
      if (lock) return;
      accum += e.deltaX;
      if (Math.abs(accum) >= 40) {
        stepRef.current(accum > 0 ? 1 : -1);
        accum = 0;lock = true;
        clearTimeout(lockTimer);
        lockTimer = setTimeout(() => {lock = false;}, 450);
      }
    };
    // Touch swipe (mobile). Swipe left -> next, swipe right -> previous.
    let sx = 0,sy = 0,active = false;
    const onTouchStart = (e) => {const tp = e.touches[0];sx = tp.clientX;sy = tp.clientY;active = true;swipedRef.current = false;};
    const onTouchEnd = (e) => {
      if (!active) return;active = false;
      const tp = e.changedTouches[0];
      const dx = tp.clientX - sx,dy = tp.clientY - sy;
      if (Math.abs(dx) > 40 && Math.abs(dx) > Math.abs(dy)) {
        swipedRef.current = true;
        stepRef.current(dx < 0 ? 1 : -1);
        setTimeout(() => {swipedRef.current = false;}, 350);
      }
    };
    el.addEventListener("wheel", onWheel, { passive: false });
    el.addEventListener("touchstart", onTouchStart, { passive: true });
    el.addEventListener("touchend", onTouchEnd, { passive: true });
    return () => {
      el.removeEventListener("wheel", onWheel);
      el.removeEventListener("touchstart", onTouchStart);
      el.removeEventListener("touchend", onTouchEnd);
      clearTimeout(lockTimer);
    };
  }, [ref]);
  return swipedRef;
}
function ServiceCarousel({ photos, alt = "", className = "", radius = 18, interval = 4000 }) {
  const rootRef = React.useRef(null);
  const [index, setIndex] = React.useState(0);
  const [lightbox, setLightbox] = React.useState(null);
  const [paused, setPaused] = React.useState(false);
  // Self-healing: any image that fails to load (e.g. its file was deleted from
  // the folder) is dropped so it never shows as a blank slot - keeping the
  // visible photos tied to the files that actually exist.
  const [failed, setFailed] = React.useState(() => new Set());
  const visible = photos.filter((p) => !failed.has(p));
  const n = visible.length;
  const cur = n ? (index % n + n) % n : 0;
  const go = (i) => setIndex(n ? (i % n + n) % n : 0);
  const markFailed = (src) => setFailed((prev) => prev.has(src) ? prev : new Set(prev).add(src));
  const swipedRef = useSwipeNav(rootRef, (dir) => {if (n > 1) go(cur + dir);});

  React.useEffect(() => {
    if (paused || lightbox !== null || n < 2) return;
    const id = setInterval(() => setIndex((p) => (p + 1) % n), interval);
    return () => clearInterval(id);
  }, [paused, lightbox, n, interval]);

  // Keep the lightbox index valid as photos drop out.
  React.useEffect(() => {
    if (lightbox !== null && lightbox > n - 1) setLightbox(n ? n - 1 : null);
  }, [n, lightbox]);

  return (
    <React.Fragment>
      <div
        ref={rootRef}
        className={`svc-carousel ${className}`}
        style={{ borderRadius: radius, cursor: n ? "zoom-in" : "default" }}
        role="button"
        tabIndex={0}
        aria-label={`View ${alt} photos - opens full screen`}
        onMouseEnter={() => setPaused(true)}
        onMouseLeave={() => setPaused(false)}
        onClick={() => {if (swipedRef.current) return;if (n) setLightbox(cur);}}
        onKeyDown={(e) => {if (n && (e.key === "Enter" || e.key === " ")) {e.preventDefault();setLightbox(cur);}}}>
        <div className="svc-carousel-track">
          {visible.map((src, i) =>
          <div
            key={src}
            className="svc-carousel-slide"
            aria-hidden={i !== cur}
            style={{ opacity: i === cur ? 1 : 0 }}>
            
              <img src={src} alt={`${alt} ${i + 1}`} loading="lazy" draggable="false" onError={() => markFailed(src)} />
            </div>
          )}
        </div>
        {n === 0 &&
        <div className="svc-carousel-empty">
          <Icon name="Image" size={26} stroke={t.textMuted} />
          <span>Photos coming soon</span>
        </div>
        }
        {n > 0 &&
        <span className="svc-carousel-zoom" aria-hidden="true">
          <Icon name="Maximize2" size={16} />
        </span>
        }

        {n > 1 &&
        <React.Fragment>
            <button
            type="button"
            className="svc-carousel-arrow svc-carousel-prev"
            onClick={(e) => {e.stopPropagation();go(cur - 1);}}
            aria-label="Previous photo">
            
              <Icon name="ChevronLeft" size={20} />
            </button>
            <button
            type="button"
            className="svc-carousel-arrow svc-carousel-next"
            onClick={(e) => {e.stopPropagation();go(cur + 1);}}
            aria-label="Next photo">
            
              <Icon name="ChevronRight" size={20} />
            </button>
            <div className="svc-carousel-dots">
              {visible.map((_, i) =>
            <button
              type="button"
              key={i}
              className={`svc-carousel-dot ${i === cur ? "is-active" : ""}`}
              onClick={(e) => {e.stopPropagation();go(i);}}
              aria-label={`Go to photo ${i + 1}`}
              aria-current={i === cur} />
            )}
            </div>
          </React.Fragment>
        }
      </div>

      {lightbox !== null && n > 0 &&
      <Lightbox
        photos={visible}
        index={Math.min(lightbox, n - 1)}
        onClose={() => setLightbox(null)}
        onIndex={setLightbox} />
      }
    </React.Fragment>);

}
function Stars({ rating = 5, size = 14, color }) {
  return (
    <span className="inline-flex items-center gap-0.5" aria-label={`${rating} out of 5 stars`}>
      {[0, 1, 2, 3, 4].map((i) =>
      <svg key={i} width={size} height={size} viewBox="0 0 24 24" fill={i < Math.round(rating) ? color || t.star : "transparent"} stroke={color || t.star} strokeWidth="1.5">
          <path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z" />
        </svg>
      )}
    </span>);

}

/* ============================================================
   ROUTING - simple useState page switch + scroll restore
   ============================================================ */
const PageContext = React.createContext({ page: "home", setPage: () => {} });

function usePage() {return React.useContext(PageContext);}

// Cross-page deep-link target: set before switching to "services", consumed
// by the page-change effect in App so it scrolls to that service's anchor
// instead of resetting to the top.
let pendingScroll = null;
let pendingService = null;
function serviceAnchorId(title) {
  return "svc-" + title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
}
function goToService(setPage, title) {
  pendingService = title;
  setPage("book");
}

function PageLink({ to, children, className = "", style, onClick, ...rest }) {
  const { setPage } = usePage();
  return (
    <a
      href={`#${to}`}
      onClick={(e) => {e.preventDefault();setPage(to);window.scrollTo({ top: 0, behavior: "smooth" });onClick && onClick(e);}}
      className={className}
      style={style}
      {...rest}>
      
      {children}
    </a>);

}

/* ============================================================
   BUTTON PRIMITIVES - 3 consistent styles
   ============================================================ */
function PrimaryButton({ children, onClick, type = "button", className = "", as: As = "button", href, full = false }) {
  const Comp = As;
  const baseStyle = {
    backgroundColor: t.accent, color: t.onAccent,
    boxShadow: t.id === "dark" ? "0 1px 0 rgba(255,255,255,0.05) inset, 0 8px 24px -10px rgba(0,0,0,0.5)" : "0 1px 0 rgba(255,255,255,0.4) inset, 0 8px 22px -12px rgba(200,85,43,0.55)"
  };
  return (
    <Comp
      type={Comp === "button" ? type : undefined}
      href={href}
      onClick={onClick}
      className={`inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold text-[15px] tracking-tight transition-all hover:scale-[1.01] active:scale-[0.98] ${full ? "w-full" : ""} ${className}`}
      style={baseStyle}
      onMouseEnter={(e) => {e.currentTarget.style.backgroundColor = t.accentHover;}}
      onMouseLeave={(e) => {e.currentTarget.style.backgroundColor = t.accent;}}>
      
      {children}
    </Comp>);

}

function SecondaryButton({ children, onClick, type = "button", className = "", as: As = "button", href, full = false }) {
  const Comp = As;
  return (
    <Comp
      type={Comp === "button" ? type : undefined}
      href={href}
      onClick={onClick}
      className={`inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold text-[15px] tracking-tight border-2 transition-all hover:scale-[1.01] active:scale-[0.98] ${full ? "w-full" : ""} ${className}`}
      style={{ borderColor: t.primary, color: t.primary, backgroundColor: "transparent" }}
      onMouseEnter={(e) => {e.currentTarget.style.backgroundColor = t.primary;e.currentTarget.style.color = t.onPrimary;}}
      onMouseLeave={(e) => {e.currentTarget.style.backgroundColor = "transparent";e.currentTarget.style.color = t.primary;}}>
      
      {children}
    </Comp>);

}

function TertiaryButton({ children, onClick, className = "" }) {
  return (
    <button
      onClick={onClick}
      className={`tertiary-link inline-flex items-center gap-1.5 font-sans font-semibold text-[14px] ${className}`}
      style={{ color: t.accent }}>
      
      {children}
    </button>);

}

/* ============================================================
   HEADER + MOBILE NAV
   ============================================================ */
function Header() {
  const { page } = usePage();
  const [open, setOpen] = React.useState(false);
  const navItems = [
  { id: "home", label: "Home" },
  { id: "services", label: "Services" },
  { id: "about", label: "About" },
  { id: "book", label: "Inquire" }];


  return (
    <>
      <header
        className="sticky top-0 z-40 backdrop-blur-md border-b"
        style={{ backgroundColor: t.bgAlt + "EE", borderColor: t.border }}>
        
        <div className={`max-w-6xl mx-auto px-5 md:px-8 flex items-center justify-between ${BRAND.logo ? "h-[114px]" : "h-[74px]"}`}>
          <PageLink to="home" className="flex items-center gap-2.5 group">
            {BRAND.logo ?
            <img
              src={BRAND.logo}
              alt={BRAND.shortName}
              className="nav-logo h-[88px] w-auto block" /> :
            <React.Fragment>
              <span className="grid place-items-center rounded-lg font-serif font-bold flex-shrink-0"
                style={{ backgroundColor: t.accent, color: t.onAccent, width: 38, height: 38, fontSize: 19, lineHeight: 1 }}
                aria-hidden="true">
                {brandMonogram()}
              </span>
              <span className="font-serif font-bold leading-none tracking-tight whitespace-nowrap"
                style={{ color: t.text, fontSize: "clamp(17px, 1.9vw, 22px)" }}>
                {BRAND.shortName}
              </span>
            </React.Fragment>}

          </PageLink>

          {/* Desktop nav group - kept together and set apart from the wordmark */}
          <div className="hidden md:flex items-center gap-4">
            <nav className="flex items-center gap-0.5">
              {navItems.map((item) =>
              <PageLink
                key={item.id}
                to={item.id}
                data-active={page === item.id}
                className="nav-link px-3 py-2 rounded-md font-sans font-medium text-[15px]">

                  {item.label}
                </PageLink>
              )}
            </nav>
            <span className="h-6 w-px" style={{ backgroundColor: t.border }} aria-hidden="true" />
            <a
              href={`tel:${BRAND.phoneRaw}`}
              className="ul-link inline-flex items-center gap-2 font-sans font-semibold text-[15px]"
              style={{ color: t.text }}>

              <Icon name="Phone" size={16} stroke={t.accent} />
              {BRAND.phone}
            </a>
            <PageLink
              to="book"
              className="hero-btn hero-btn-primary inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-lg font-sans font-semibold text-[14.5px]"
              style={{ backgroundColor: t.accent, color: t.onAccent }}>

              Inquire now
            </PageLink>
          </div>

          <button
            onClick={() => setOpen(true)}
            className="icon-btn md:hidden p-2 rounded-md"
            style={{ color: t.text }}
            aria-label="Open menu">

            <Icon name="Menu" size={26} />
          </button>
        </div>
      </header>

      {/* Mobile drawer */}
      {open &&
      <div className="fixed inset-0 z-50 md:hidden">
          <div className="absolute inset-0" style={{ backgroundColor: "rgba(0,0,0,0.4)" }} onClick={() => setOpen(false)} />
          <div className="absolute right-0 top-0 bottom-0 w-[88%] max-w-sm shadow-2xl flex flex-col" style={{ backgroundColor: t.bg }}>
            <div className="flex items-center justify-between px-5 h-[68px] border-b" style={{ borderColor: t.border }}>
              <span className="font-serif font-bold text-[19px]" style={{ color: t.text }}>{BRAND.shortName}</span>
              <button onClick={() => setOpen(false)} className="icon-btn p-2 rounded-md" style={{ color: t.text }} aria-label="Close menu">
                <Icon name="X" size={24} />
              </button>
            </div>
            <nav className="flex flex-col p-5 gap-1">
              {navItems.map((item) =>
            <PageLink
              key={item.id}
              to={item.id}
              onClick={() => setOpen(false)}
              className="px-4 py-3.5 rounded-lg font-serif font-semibold text-[22px]"
              style={{
                color: page === item.id ? t.accent : t.text,
                backgroundColor: page === item.id ? t.bgAlt : "transparent"
              }}>
              
                  {item.label}
                </PageLink>
            )}
            </nav>
            <div className="mt-auto p-5 border-t space-y-3" style={{ borderColor: t.border }}>
              <a
              href={`tel:${BRAND.phoneRaw}`}
              onClick={() => setOpen(false)}
              className="tap-btn flex items-center justify-center gap-2.5 w-full py-4 rounded-lg font-sans font-bold text-[18px]"
              style={{ backgroundColor: t.primary, color: t.onPrimary }}>
              
                <Icon name="Phone" size={20} /> Call {BRAND.phone}
              </a>
              <PageLink to="book" onClick={() => setOpen(false)} className="block">
                <span
                className="hero-btn hero-btn-primary flex items-center justify-center gap-2 w-full py-4 rounded-lg font-sans font-bold text-[16px]"
                style={{ backgroundColor: t.accent, color: t.onAccent }}>
                
                  Inquire now
                </span>
              </PageLink>
              <p className="text-[12px] text-center" style={{ color: t.textMuted }}>
                {BRAND.promoLine}
              </p>
            </div>
          </div>
        </div>
      }
    </>);

}

/* ============================================================
   STICKY MOBILE BOTTOM BAR - #1 conversion driver
   ============================================================ */
function MobileBar() {
  return (
    <div
      className="md:hidden fixed bottom-0 left-0 right-0 z-30 grid grid-cols-2 border-t shadow-[0_-4px_20px_-8px_rgba(0,0,0,0.15)]"
      style={{ backgroundColor: t.surface, borderColor: t.border }}>
      
      <a
        href={`tel:${BRAND.phoneRaw}`}
        className="tap-btn flex items-center justify-center gap-2 py-3.5 font-sans font-bold text-[15px]"
        style={{ color: t.primary }}>
        
        <Icon name="Phone" size={18} /> Call
      </a>
      <PageLink to="book" className="tap-btn flex items-center justify-center gap-2 py-3.5 font-sans font-bold text-[15px]"
      style={{ backgroundColor: t.accent, color: t.onAccent }}>
        
        <Icon name="Ruler" size={18} /> Inquire
      </PageLink>
    </div>);

}

/* ============================================================
   FOOTER
   ============================================================ */
function Footer() {
  return (
    <footer className="pt-16 pb-24 md:pb-16" style={{ backgroundColor: t.footerBg, color: t.footerText }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8 grid grid-cols-1 md:grid-cols-12 gap-10">
        <div className="md:col-span-4 space-y-4">
          <div className="font-serif font-bold text-[24px] leading-tight" style={{ color: t.footerText }}>
            {BRAND.name}
          </div>
          <p className="text-[14.5px] leading-relaxed max-w-xs" style={{ color: t.footerMuted }}>
            {BRAND.tagline} Insured and answering the phone since {BRAND.foundedYear}.
          </p>
          <div className="flex items-center gap-2 text-[13px] font-mono" style={{ color: t.footerMuted }}>
            <Icon name="ShieldCheck" size={14} stroke={t.footerText} />
            <span>Insured & family-owned</span>
          </div>
        </div>

        <div className="md:col-span-2">
          <h5 className="font-sans font-bold text-[12px] tracking-[0.12em] uppercase mb-4" style={{ color: t.footerText }}>Services</h5>
          <ul className="space-y-2.5">
            {BRAND.services.slice(0, 5).map((s) =>
            <li key={s.title}>
                <PageLink to="services" className="ul-link text-[14px]" style={{ color: t.footerMuted }}>{s.title}</PageLink>
              </li>
            )}
          </ul>
        </div>

        <div className="md:col-span-3">
          <h5 className="font-sans font-bold text-[12px] tracking-[0.12em] uppercase mb-4" style={{ color: t.footerText }}>Service Areas</h5>
          <ul className="grid grid-cols-2 gap-x-3 gap-y-2.5">
            {BRAND.serviceAreas.map((a) =>
            <li key={a} className="text-[14px]" style={{ color: t.footerMuted }}>{a}</li>
            )}
          </ul>
        </div>

        <div className="md:col-span-3 space-y-3 text-[14px]">
          <h5 className="font-sans font-bold text-[12px] tracking-[0.12em] uppercase mb-4" style={{ color: t.footerText }}>Get in touch</h5>
          <a href={`tel:${BRAND.phoneRaw}`} className="ul-link flex items-center gap-2" style={{ color: t.footerText }}>
            <Icon name="Phone" size={14} stroke={t.footerMuted} /> {BRAND.phone}
          </a>
          {BRAND.email &&
          <a href={`mailto:${BRAND.email}`} className="ul-link flex items-center gap-2" style={{ color: t.footerMuted }}>
            <Icon name="Mail" size={14} /> {BRAND.email}
          </a>}
          <div className="flex items-start gap-2" style={{ color: t.footerMuted }}>
            <Icon name="MapPin" size={14} className="mt-0.5" />
            <span>{BRAND.address}</span>
          </div>
          {BRAND.hours ?
          <div className="flex items-start gap-2" style={{ color: t.footerMuted }}>
            <Icon name="Clock" size={14} className="mt-0.5" />
            <span>{BRAND.hours}</span>
          </div> :
          null}
        </div>
      </div>

      <div className="max-w-6xl mx-auto px-5 md:px-8 mt-12 pt-6 border-t flex flex-col md:flex-row gap-3 justify-between text-[12px]"
      style={{ borderColor: t.footerMuted + "33", color: t.footerMuted }}>
        <div>© {new Date().getFullYear()} {BRAND.name}. All rights reserved.</div>
        <div>{BRAND.builtBy}</div>
      </div>
    </footer>);

}

/* ============================================================
   SHARED - TrustStrip
   ============================================================ */
function TrustStrip() {
  return (
    <div className="border-y" style={{ borderColor: t.border, backgroundColor: t.bgAlt }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8 py-5 flex flex-wrap items-center justify-center gap-x-8 gap-y-3 text-[14px] font-medium" style={{ color: t.text }}>
        <div className="flex items-center gap-2.5">
          <Icon name="ShieldCheck" size={18} stroke={t.accent} />
          <span><strong className="font-bold">{BRAND.yearsInBusiness} years</strong> in the {BRAND.city} area</span>
        </div>
        <div className="hidden sm:block w-px h-5" style={{ backgroundColor: t.border }} />
        <div className="flex items-center gap-2.5">
          <Stars rating={BRAND.rating} size={14} />
          <span><strong className="font-bold">{BRAND.rating}</strong> Google rating{SHOW_REVIEW_COUNT ? ` · ${BRAND.reviewCount} reviews` : ""}</span>
        </div>
        <div className="hidden md:block w-px h-5" style={{ backgroundColor: t.border }} />
        <div className="flex items-center gap-2.5">
          <Icon name="Ruler" size={18} stroke={t.accent} />
          <span>{BRAND.promoLine}</span>
        </div>
      </div>
    </div>);

}

/* ============================================================
   HOME PAGE
   ============================================================ */
/* ============================================================
   LIGHTBOX - leaf through work photos (keyboard + arrows)
   ============================================================ */
function Lightbox({ photos, index, onClose, onIndex }) {
  const overlayRef = React.useRef(null);
  const go = (d) => onIndex((index + d + photos.length) % photos.length);
  const swipedRef = useSwipeNav(overlayRef, (dir) => go(dir));
  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape") onClose();else
      if (e.key === "ArrowRight") go(1);else
      if (e.key === "ArrowLeft") go(-1);
    };
    window.addEventListener("keydown", onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {window.removeEventListener("keydown", onKey);document.body.style.overflow = prev;};
  });
  return ReactDOM.createPortal(
    <div className="lightbox-overlay" ref={overlayRef} onClick={() => {if (!swipedRef.current) onClose();}} role="dialog" aria-modal="true" aria-label="Photo viewer">
      <button className="lightbox-close" onClick={onClose} aria-label="Close">
        <Icon name="X" size={22} />
      </button>
      <button className="lightbox-btn lightbox-prev" onClick={(e) => {e.stopPropagation();go(-1);}} aria-label="Previous photo">
        <Icon name="ChevronLeft" size={26} />
      </button>
      <div className="lightbox-stage" onClick={(e) => e.stopPropagation()}>
        <Photo
          key={index}
          src={photos[index]}
          alt={`Flooring work ${index + 1}`}
          className="lightbox-img"
          dark />
        
        <div className="font-mono text-[13px] tracking-wide" style={{ color: "rgba(255,255,255,0.7)" }}>
          {index + 1} / {photos.length}
        </div>
      </div>
      <button className="lightbox-btn lightbox-next" onClick={(e) => {e.stopPropagation();go(1);}} aria-label="Next photo">
        <Icon name="ChevronRight" size={26} />
      </button>
    </div>,
    document.body);

}

function HomeHero() {
  const isBold = t.id === "bold";
  // Marquee photos come from the central manifest (photos/manifest.json -> "marquee").
  const manifest = usePhotoManifest();
  const photos = marqueePhotos(manifest);
  const [lightbox, setLightbox] = React.useState(null);
  const base = isBold ? t.heroBg : t.bg;
  const hexA = (hex, a) => {
    const h = hex.replace("#", "");
    const n = parseInt(h.length === 3 ? h.split("").map((c) => c + c).join("") : h, 16);
    return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${a})`;
  };
  return (
    <section className="hero-parallax-section" style={{ color: isBold ? t.heroText : t.text }}>
      <div className="hero-fixed-bg" aria-hidden="true">
        <div className="hero-fixed-img" />
        <div
          className="hero-fixed-scrim"
          style={{ background: `linear-gradient(180deg, ${hexA(base, 0.85)} 0%, ${hexA(base, 0.62)} 36%, ${hexA(base, 0.46)} 66%, ${hexA(base, 0.74)} 100%)` }} />
      </div>
      <div className="hero-parallax-content max-w-6xl mx-auto px-5 md:px-8 pt-14 md:pt-20 pb-14 md:pb-20">
        {/* Compact headline band */}
        <div className="max-w-3xl mb-10 md:mb-12 space-y-6">
          <div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-[12px] font-sans font-semibold tracking-wide uppercase"
          style={{ backgroundColor: isBold ? "rgba(26,29,36,0.06)" : t.chip, color: isBold ? t.text : t.onChip }}>
            <span className="w-1.5 h-1.5 rounded-full" style={{ backgroundColor: t.accent }} />
            Family-owned · {BRAND.city}, {BRAND.state} · Est. {BRAND.foundedYear}
          </div>
          <h1
            className="font-serif font-bold leading-[1.02] tracking-tight"
            style={{
              fontSize: `clamp(38px, ${6.4 * t.heroScale}vw, ${72 * t.heroScale}px)`,
              color: isBold ? t.heroText : t.text
            }}>
            
            Floors that still look right{" "}
            <span style={{ color: t.accent, fontStyle: "italic" }}>in twenty years.</span>
          </h1>
          <p className="font-sans text-[18px] md:text-[19px] leading-[1.65] max-w-xl"
          style={{ color: isBold ? t.heroSubtext : t.textMuted }}>
            {BRAND.heroSubtext}
          </p>
          <div className="flex flex-wrap gap-3 pt-1">
            <PageLink to="book">
              <span
                className="hero-btn hero-btn-primary inline-flex items-center justify-center gap-2 px-7 py-4 rounded-lg font-sans font-semibold text-[16px]"
                style={{ backgroundColor: t.accent, color: t.onAccent }}>
                
                Get a free estimate <Icon name="ArrowRight" size={18} />
              </span>
            </PageLink>
            <a
              href={`tel:${BRAND.phoneRaw}`}
              className="hero-btn hero-btn-secondary inline-flex items-center justify-center gap-2 px-7 py-4 rounded-lg font-sans font-semibold text-[16px] border-2"
              style={{
                borderColor: isBold ? t.heroText : t.primary,
                color: isBold ? t.heroText : t.primary,
                "--hero-btn-fill": isBold ? t.heroText : t.primary,
                "--hero-btn-text-on-fill": isBold ? t.heroBg : t.onPrimary
              }}>
              
              <Icon name="Phone" size={18} /> {BRAND.phone}
            </a>
          </div>
        </div>

        {/* Infinite work-photo marquee - the visual focus */}
        <div className="hero-marquee" style={{ height: "clamp(295px, 40vh, 430px)" }}>
          <div
            className="hero-marquee-track"
            style={{ animationDuration: `${Math.max(40, photos.length * 5)}s` }}>
            {[...photos, ...photos].map((src, i) =>
            <button
              type="button"
              className="hero-marquee-item"
              key={i}
              onClick={() => setLightbox(i % photos.length)}
              aria-label={`View flooring photo ${i % photos.length + 1}`}>
              
                <Photo
                src={src}
                alt={`Recent flooring work ${i % photos.length + 1}`}
                className="w-full h-full object-cover"
                dark={t.id === "dark"} />
              
              </button>
            )}
          </div>
        </div>
      </div>

      {lightbox !== null &&
      <Lightbox
        photos={photos}
        index={lightbox}
        onClose={() => setLightbox(null)}
        onIndex={setLightbox} />

      }
    </section>);

}

function ServicesGrid() {
  const { setPage } = usePage();
  return (
    <section className="py-20 md:py-24" style={{ backgroundColor: t.bg }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8">
        <div className="flex flex-col md:flex-row md:items-end justify-between gap-6 mb-12">
          <div className="max-w-xl">
            <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>What we do</div>
            <h2 className="font-serif font-bold text-[36px] md:text-[44px] leading-[1.1] tracking-tight" style={{ color: t.text }}>
              The work we're known for.
            </h2>
          </div>
          <p className="font-sans text-[16px] leading-[1.65] max-w-sm" style={{ color: t.textMuted }}>
            {BRAND.servicesIntro}
          </p>
        </div>

        {(() => {
          const flagship = BRAND.services.filter((s) => s.category);
          const extra = BRAND.services.filter((s) => !s.category);
          return (
            <>
              <div className="flex flex-wrap justify-center gap-4">
                {flagship.map((s, i) =>
                <div
                  key={s.title}
                  onClick={() => goToService(setPage, s.title)}
                  role="link"
                  tabIndex={0}
                  onKeyDown={(e) => {if (e.key === "Enter" || e.key === " ") {e.preventDefault();goToService(setPage, s.title);}}}
                  className="services-card group p-7 rounded-xl border transition-all cursor-pointer grow-0 basis-full sm:basis-[calc(50%_-_0.5rem)] lg:basis-[calc(33.333%_-_0.667rem)]"
                  style={{ backgroundColor: t.surface, borderColor: t.border }}>
                  
                    <div className="flex items-start justify-between mb-5">
                      <div
                      className="w-12 h-12 rounded-lg flex items-center justify-center"
                      style={{ backgroundColor: t.bgAlt, color: t.accent }}>
                      
                        <Icon name={s.icon} size={24} strokeWidth={1.75} />
                      </div>
                      <span className="font-mono text-[12px]" style={{ color: t.textMuted }}>{String(i + 1).padStart(2, "0")}</span>
                    </div>
                    <h3 className="font-serif font-bold text-[22px] leading-tight mb-2" style={{ color: t.text }}>{s.title}</h3>
                    <p className="font-sans text-[15px] leading-[1.65]" style={{ color: t.textMuted }}>{s.desc}</p>
                  </div>
                )}
              </div>

              {/* We also offer - skinny full-width rows for the remaining services */}
              <div className="mt-10 md:mt-12">
                <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-5" style={{ color: t.accent }}>We also offer</div>
                <div className="flex flex-col gap-3">
                  {extra.map((s) =>
                  <div
                    key={s.title}
                    onClick={() => goToService(setPage, s.title)}
                    role="link"
                    tabIndex={0}
                    onKeyDown={(e) => {if (e.key === "Enter" || e.key === " ") {e.preventDefault();goToService(setPage, s.title);}}}
                    className="services-row group flex items-center gap-4 md:gap-5 p-4 md:px-6 md:py-5 rounded-xl border transition-all cursor-pointer"
                    style={{ backgroundColor: t.surface, borderColor: t.border }}>
                    
                      <div
                      className="w-11 h-11 rounded-lg flex items-center justify-center flex-shrink-0"
                      style={{ backgroundColor: t.bgAlt, color: t.accent }}>
                      
                        <Icon name={s.icon} size={21} strokeWidth={1.75} />
                      </div>
                      <h4 className="font-serif font-bold text-[18px] md:text-[19px] leading-tight flex-shrink-0" style={{ color: t.text }}>{s.title}</h4>
                      <p className="hidden md:block font-sans text-[14px] leading-snug truncate flex-1" style={{ color: t.textMuted }}>
                        {s.includes.slice(0, 3).join("  ·  ")}
                      </p>
                      <Icon name="ArrowRight" size={18} stroke={t.textMuted} className="services-row-arrow ml-auto md:ml-0 flex-shrink-0" />
                    </div>
                  )}
                </div>
              </div>
            </>);
        })()}
      </div>
    </section>);

}

function WhyUs() {
  const reasons = [
  { icon: "Ruler", title: "A free in-home estimate.", body: "We visit your home, measure every room, present samples, and provide a free, flat written estimate tailored to your space - with no obligation." },
  { icon: "Receipt", title: "A quote before work begins.", body: "A flat price, in writing, before any work starts. What we quote is what you pay." },
  { icon: "Users", title: "One team, start to finish.", body: "No subcontractors. The installers who remove your existing floor are the ones who install the new one, and we stand behind that work." },
  { icon: "Wind", title: "Clean throughout.", body: "Dust barriers between rooms, floor protection over finished areas, and a full vacuum before we leave - on every project." }];

  return (
    <section className="py-20 md:py-24" style={{ backgroundColor: t.bgAlt }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8 grid md:grid-cols-12 gap-12">
        <div className="md:col-span-5">
          <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>Why us</div>
          <h2 className="font-serif font-bold text-[34px] md:text-[42px] leading-[1.1] tracking-tight mb-5" style={{ color: t.text }}>
            Four things we don't compromise on.
          </h2>
          <p className="font-sans text-[16px] leading-[1.7] mb-6" style={{ color: t.textMuted }}>
            We are not the lowest-priced option in the area, and we do not aim to be. We are the team to call when you want the work done once and done properly.
          </p>
          <PageLink to="about">
            <TertiaryButton>Read our story <Icon name="ArrowRight" size={14} /></TertiaryButton>
          </PageLink>
        </div>
        <div className="md:col-span-7 grid sm:grid-cols-2 gap-3">
          {reasons.map((r) =>
          <div key={r.title} className="p-6 rounded-xl" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
              <Icon name={r.icon} size={22} stroke={t.accent} className="mb-4" />
              <h4 className="font-serif font-bold text-[18px] mb-1.5" style={{ color: t.text }}>{r.title}</h4>
              <p className="font-sans text-[14.5px] leading-[1.6]" style={{ color: t.textMuted }}>{r.body}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}

const GOOGLE_REVIEW_URL = BRAND.googleReviewUrl ||
  ("https://www.google.com/maps/search/" + encodeURIComponent(`${BRAND.name} ${BRAND.city} ${BRAND.state}`));

function CustomerReviews() {
  const reviews = BRAND.testimonials.slice(0, 3).map((r) => ({ ...r, rating: 5 }));
  return (
    <section className="py-20 md:py-24" style={{ backgroundColor: t.bg }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8">
        <div className="text-center mb-12 md:mb-14">
          <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>
            What our customers say
          </div>
          <h2 className="font-serif font-bold text-[34px] md:text-[46px] leading-[1.08] tracking-tight" style={{ color: t.text }}>
            Reviewed by neighbors<br />across the {BRAND.city} area.
          </h2>
          <div className="flex items-center justify-center gap-2.5 mt-5">
            <Stars rating={5} size={18} color={t.accent} />
            <span className="font-sans font-semibold text-[15px]" style={{ color: t.textMuted }}>
              {SHOW_REVIEW_COUNT
              ? `${BRAND.rating} average across ${BRAND.reviewCount} Google reviews`
              : `Rated ${BRAND.rating} on Google`}
            </span>
          </div>
        </div>

        <div className={reviews.length >= 3 ? "grid md:grid-cols-3 gap-5" : "flex flex-col md:flex-row md:justify-center gap-5"}>
          {reviews.map((r) =>
          <figure
            key={r.name}
            className={`review-quote-card flex flex-col p-7 rounded-2xl h-full ${reviews.length < 3 ? "w-full md:flex-1 md:max-w-[400px]" : ""}`}
            style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
            
              <div className="flex items-center justify-between mb-5">
                <span
                className="grid place-items-center rounded-full font-sans font-bold text-[15px] h-9 w-9 flex-shrink-0"
                style={{ backgroundColor: t.bgAlt, color: t.accent, border: `1px solid ${t.border}` }}
                aria-hidden="true">{r.name.trim().charAt(0).toUpperCase()}


              </span>
                <Stars rating={5} size={16} color={t.accent} />
              </div>
              <blockquote className="font-sans text-[15.5px] leading-[1.65] flex-grow" style={{ color: t.text }}>
                {r.quote}
              </blockquote>
              <figcaption className="mt-6 pt-5" style={{ borderTop: `1px solid ${t.border}` }}>
                <div className="font-sans font-semibold text-[15px]" style={{ color: t.text }}>{r.name}</div>
                <div className="font-sans text-[13.5px] mt-0.5" style={{ color: t.textMuted }}>
                  {r.location ? `${r.location} · ${r.service}` : r.service}
                </div>
              </figcaption>
            </figure>
          )}
        </div>

        <p className="font-sans text-[13px] text-center mt-8" style={{ color: t.textMuted }}>

        </p>
      </div>
    </section>);
}

function Testimonials() {
  const isBold = t.id === "bold";
  return (
    <section className="py-20 md:py-28" style={{ backgroundColor: t.surface }}>
      <div className="max-w-4xl mx-auto px-5 md:px-8 text-center">
        <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-4" style={{ color: t.accent }}>
          Recent customer?
        </div>
        <h2 className="font-serif font-bold text-[34px] md:text-[48px] leading-[1.08] tracking-tight mb-5" style={{ color: t.text }}>
          We would appreciate<br />your review.
        </h2>
        <p className="font-sans text-[17px] md:text-[18px] leading-[1.65] max-w-xl mx-auto mb-8" style={{ color: t.textMuted }}>
          Referrals and online reviews are how a small business grows. If you were satisfied with our work, a brief review on Google helps other homeowners in the area find us.
        </p>

        <div className="flex justify-center mb-9">
          <span className="inline-flex items-center gap-1.5">
            {[0, 1, 2, 3, 4].map((i) =>
            <svg key={i} className="review-star" style={{ animationDelay: `${i * 90}ms` }} width={36} height={36} viewBox="0 0 24 24" fill={t.star} stroke={t.star} strokeWidth="1.5">
                <path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z" />
              </svg>
            )}
          </span>
        </div>

        <a
          href={GOOGLE_REVIEW_URL}
          target="_blank"
          rel="noopener noreferrer"
          className="hero-btn hero-btn-primary inline-flex items-center justify-center gap-2.5 px-8 py-4 rounded-lg font-sans font-semibold text-[16px]"
          style={{ backgroundColor: t.accent, color: t.onAccent }}>
          
          <Icon name="Star" size={18} /> Leave a review on Google
        </a>

        <p className="font-sans text-[13.5px] mt-5" style={{ color: t.textMuted }}>
          Opens Google in a new tab · About a minute
        </p>
      </div>
    </section>);

}

/* ============================================================
   MATERIALS GALLERY - replaces ServiceArea/Map for flooring
   Flooring buyers shop on visual outcome. This is the
   conversion section: before/after pairs + material chips.
   ============================================================ */
function MaterialsGallery() {
  // First service that has photos drives the showcase image — works for any service set.
  const cat = BRAND.services.find((s) => s.category) || {};
  return (
    <section className="py-20 md:py-24" style={{ backgroundColor: t.bgAlt }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8">
        <div className="grid md:grid-cols-12 gap-12 items-start">
          <div className="md:col-span-5">
            <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>Materials & samples</div>
            <h2 className="font-serif font-bold text-[34px] md:text-[42px] leading-[1.1] tracking-tight mb-5" style={{ color: t.text }}>
              We bring the showroom to you.
            </h2>
            <p className="font-sans text-[16px] leading-[1.7] mb-6" style={{ color: t.textMuted }}>
              Before any project begins, we visit you with samples, a tape measure, and a free, no-obligation estimate. There is no showroom process to navigate - only a clear assessment of what suits your space and your light.
            </p>
            <PageLink to="book">
              <span className="hero-btn hero-btn-primary inline-flex items-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold text-[15px]"
              style={{ backgroundColor: t.accent, color: t.onAccent }}>
                Get a free estimate <Icon name="ArrowRight" size={16} />
              </span>
            </PageLink>
          </div>

          <div className="md:col-span-7">
            <CategoryMedia
              category={cat.category}
              alt={cat.title}
              radius={18}
              className="w-full aspect-[4/3]" />
          </div>
        </div>
      </div>
    </section>);

}

function FinalCTA() {
  const isBold = t.id === "bold";
  return (
    <section className="py-20 md:py-24" style={{ backgroundColor: isBold ? t.block : t.primary, color: isBold ? t.onBlock : t.onPrimary }}>
      <div className="max-w-4xl mx-auto px-5 md:px-8 text-center space-y-7">
        <h2 className="font-serif font-bold leading-[1.05] tracking-tight" style={{ fontSize: "clamp(34px, 6vw, 56px)" }}>
          Ready to see what new floors<br />can do for your home?
        </h2>
        <p className="font-sans text-[17px] md:text-[18px] leading-[1.65] max-w-2xl mx-auto opacity-90">
          We bring samples and assess your space on site, then provide a free, flat written estimate. Inquire today with no obligation.
        </p>
        <div className="flex flex-wrap gap-3 justify-center pt-2">
          <PageLink to="book">
            <span className="hero-btn hero-btn-primary inline-flex items-center gap-2 px-7 py-4 rounded-lg font-sans font-semibold text-[16px]"
            style={{ backgroundColor: t.accent, color: t.onAccent }}>
              Get a free estimate <Icon name="ArrowRight" size={18} />
            </span>
          </PageLink>
          <a href={`tel:${BRAND.phoneRaw}`} className="hero-btn hero-btn-secondary inline-flex items-center gap-2 px-7 py-4 rounded-lg font-sans font-semibold text-[16px] border-2"
          style={{ borderColor: isBold ? t.onBlock : t.onPrimary, color: isBold ? t.onBlock : t.onPrimary, "--hero-btn-fill": isBold ? t.onBlock : t.onPrimary, "--hero-btn-text-on-fill": isBold ? t.block : t.primary }}>
            <Icon name="Phone" size={18} /> {BRAND.phone}
          </a>
        </div>
      </div>
    </section>);

}

/* ============================================================
   PROCESS - "What to expect" branded band
   ============================================================ */
function ProcessSteps() {
  const isBold = t.id === "bold";
  const bg = isBold ? t.block : t.primary;
  const fg = isBold ? t.onBlock : t.onPrimary;
  const fade = (a) => {
    const h = fg.replace("#", "");
    const n = parseInt(h.length === 3 ? h.split("").map((c) => c + c).join("") : h, 16);
    return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${a})`;
  };
  const steps = [
  { icon: "MessageCircle", title: "We listen", body: "From your first call, we listen to what you need and give honest, personalized advice \u2014 no pressure, no script." },
  { icon: "ClipboardList", title: "Free estimate", body: "We put together a clear, written budget \u2014 your free, no-obligation estimate \u2014 so you know exactly what to expect." },
  { icon: "CalendarCheck", title: "We schedule", body: "Together we coordinate an installation date that's convenient for you and your household." },
  { icon: "Hammer", title: "We install", body: "Our team handles the work with meticulous attention to detail, ensuring quality that lasts." },
  { icon: "ThumbsUp", title: "We follow up", body: "On completion we confirm you're happy with the result and show you how to keep it looking its best." }];

  return (
    <section className="py-20 md:py-28" style={{ backgroundColor: bg, color: fg }}>
      <div className="max-w-6xl mx-auto px-5 md:px-8">
        <div className="max-w-2xl mb-12 md:mb-16">
          <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>How it works</div>
          <h2 className="font-serif font-bold text-[34px] md:text-[46px] leading-[1.08] tracking-tight">
            What to expect<br />when you hire us.
          </h2>
        </div>
        <div className="grid sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-10">
          {steps.map((s, i) =>
          <div key={s.title}>
              <div className="flex items-center gap-3 mb-4">
                <span className="font-mono text-[13px]" style={{ color: t.accent }}>{String(i + 1).padStart(2, "0")}</span>
                <span className="h-px flex-1" style={{ backgroundColor: fade(0.18) }} />
              </div>
              <div className="w-12 h-12 rounded-xl flex items-center justify-center mb-4" style={{ backgroundColor: fade(0.1) }}>
                <Icon name={s.icon} size={24} stroke={t.accent} />
              </div>
              <h3 className="font-serif font-bold text-[20px] mb-2">{s.title}</h3>
              <p className="font-sans text-[14.5px] leading-[1.6]" style={{ color: fade(0.82) }}>{s.body}</p>
            </div>
          )}
        </div>
      </div>
    </section>);

}

function HomePage() {
  return (
    <>
      <HomeHero />
      <TrustStrip />
      <CustomerReviews />
      <Testimonials />
      <ServicesGrid />
      <WhyUs />
      <ProcessSteps />
      <MaterialsGallery />
      <FinalCTA />
    </>);

}

/* ============================================================
   SERVICES PAGE
   ============================================================ */
function ServicesPage() {
  const manifest = usePhotoManifest();
  return (
    <>
      <section className="py-20 md:py-24" style={{ backgroundColor: t.bg }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8 grid md:grid-cols-12 gap-10 items-end">
          <div className="md:col-span-8 space-y-5">
            <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase" style={{ color: t.accent }}>Services</div>
            <h1 className="font-serif font-bold leading-[1.05] tracking-tight" style={{ fontSize: "clamp(42px, 7vw, 72px)", color: t.text }}>
              Serving the {BRAND.city} area<br />
              <span style={{ color: t.accent, fontStyle: "italic" }}>since {BRAND.foundedYear}.</span>
            </h1>
          </div>
          <div className="md:col-span-4">
            <p className="font-sans text-[17px] leading-[1.7]" style={{ color: t.textMuted }}>
              {BRAND.servicesPageIntro}
            </p>
          </div>
        </div>
      </section>

      <TrustStrip />

      {/* Flagship services - the work we're known for, with photos */}
      {(() => {
        const flagship = BRAND.services.filter((s) => s.category);
        const extra = BRAND.services.filter((s) => !s.category);
        return (
          <>
            {flagship.map((s, idx) => {
              const flip = idx % 2 === 1;
              return (
                <section key={s.title} id={serviceAnchorId(s.title)} style={{ backgroundColor: idx % 2 === 0 ? t.bg : t.bgAlt, scrollMarginTop: "140px" }}>
                  <div className="max-w-6xl mx-auto px-5 md:px-8 py-16 md:py-24 grid md:grid-cols-12 gap-12 items-center">
                    <div className={`md:col-span-7 ${flip ? "md:order-2" : ""} space-y-6`}>
                      <div className="flex items-center gap-3">
                        <span className="font-mono text-[13px]" style={{ color: t.textMuted }}>{String(idx + 1).padStart(2, "0")} / {String(flagship.length).padStart(2, "0")}</span>
                        <span className="h-px flex-1 max-w-[60px]" style={{ backgroundColor: t.border }} />
                      </div>
                      <div className="flex items-center gap-4">
                        <div className="w-14 h-14 rounded-xl flex items-center justify-center" style={{ backgroundColor: t.accent, color: t.onAccent }}>
                          <Icon name={s.icon} size={28} />
                        </div>
                        <h2 className="font-serif font-bold text-[38px] md:text-[44px] leading-[1.05] tracking-tight" style={{ color: t.text }}>
                          {s.title}
                        </h2>
                      </div>
                      <p className="font-sans text-[17px] md:text-[18px] leading-[1.7] max-w-xl" style={{ color: t.textMuted }}>
                        {s.desc}
                      </p>
                      <ul className="grid sm:grid-cols-2 gap-x-6 gap-y-3 pt-2">
                        {s.includes.map((item) =>
                        <li key={item} className="flex items-start gap-2.5 font-sans text-[15px]" style={{ color: t.text }}>
                            <Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" />
                            <span>{item}</span>
                          </li>
                        )}
                      </ul>
                      <div className="pt-3 flex flex-wrap gap-3">
                        <PageLink to="book">
                          <span className="hero-btn hero-btn-primary inline-flex items-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold text-[15px]"
                          style={{ backgroundColor: t.accent, color: t.onAccent }}>
                            Get a free estimate <Icon name="ArrowRight" size={16} />
                          </span>
                        </PageLink>
                        <a href={`tel:${BRAND.phoneRaw}`} className="hero-btn hero-btn-secondary inline-flex items-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold text-[15px] border-2"
                        style={{ borderColor: t.primary, color: t.primary, "--hero-btn-fill": t.primary, "--hero-btn-text-on-fill": t.onPrimary }}>
                          <Icon name="Phone" size={16} /> Call instead
                        </a>
                      </div>
                    </div>
                    <div className={`md:col-span-5 ${flip ? "md:order-1" : ""}`}>
                      <CategoryMedia
                        category={s.category}
                        alt={s.title}
                        radius={18}
                        className="w-full aspect-[5/6]" />
                    </div>
                  </div>
                </section>);
            })}

            {/* We also do - additional services, no photo needed */}
            <section className="py-20 md:py-24" style={{ backgroundColor: t.bgAlt }}>
              <div className="max-w-6xl mx-auto px-5 md:px-8">
                <div className="max-w-2xl mb-12">
                  <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>Also available</div>
                  <h2 className="font-serif font-bold text-[34px] md:text-[44px] leading-[1.1] tracking-tight mb-4" style={{ color: t.text }}>
                    We finish the whole room.
                  </h2>
                  <p className="font-sans text-[16px] leading-[1.7]" style={{ color: t.textMuted }}>
                    Beyond the core work above, we handle the surrounding finishes so you only deal with one trusted team. Ask about any of these when you reach out.
                  </p>
                </div>
                <div className="flex flex-wrap justify-center gap-4">
                  {extra.map((s) =>
                  <PageLink key={s.title} id={serviceAnchorId(s.title)} to="book" className="block grow-0 basis-full sm:basis-[calc(50%_-_0.5rem)] lg:basis-[calc(33.333%_-_0.667rem)]" style={{ scrollMarginTop: "140px" }}>
                    <div className="group h-full p-6 rounded-xl border transition-all hover:-translate-y-0.5" style={{ backgroundColor: t.surface, borderColor: t.border }}>
                      <div className="w-11 h-11 rounded-lg flex items-center justify-center mb-4" style={{ backgroundColor: t.bgAlt, color: t.accent }}>
                        <Icon name={s.icon} size={22} />
                      </div>
                      <h3 className="font-serif font-bold text-[19px] leading-tight mb-2" style={{ color: t.text }}>{s.title}</h3>
                      <ul className="space-y-1.5">
                        {s.includes.slice(0, 3).map((item) =>
                        <li key={item} className="flex items-start gap-2 font-sans text-[13.5px]" style={{ color: t.textMuted }}>
                            <Icon name="Check" size={14} stroke={t.accent} className="mt-0.5 flex-shrink-0" />
                            <span>{item}</span>
                          </li>
                        )}
                      </ul>
                    </div>
                  </PageLink>
                  )}
                </div>
              </div>
            </section>
          </>);
      })()}

      {/* Recent work - drop your own photos */}
      <section className="py-16 md:py-20" style={{ backgroundColor: t.bg }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8">
          <div className="flex items-end justify-between mb-8">
            <h3 className="font-serif font-bold text-[26px] md:text-[32px] tracking-tight" style={{ color: t.text }}>Recent work</h3>
            <span className="font-mono text-[12px]" style={{ color: t.textMuted }}>{BRAND.city} area</span>
          </div>
          <div className="grid grid-cols-2 md:grid-cols-3 gap-3 md:gap-4">
            {marqueePhotos(manifest).slice(0, 6).map((src, i) =>
            <div key={src} className="w-full aspect-square overflow-hidden" style={{ borderRadius: 12, backgroundColor: t.surface }}>
                <img src={src} alt={`Recent work ${i + 1}`} loading="lazy" style={{ display: "block", width: "100%", height: "100%", objectFit: "cover" }} />
              </div>
            )}
          </div>
        </div>
      </section>

      <FinalCTA />
    </>);

}

/* ============================================================
   ABOUT PAGE
   ============================================================ */
function AboutPage() {
  // Photo for the story section: prefer a second service with photos for variety,
  // else the first — so it always resolves regardless of the service set.
  const flagshipCats = BRAND.services.filter((s) => s.category);
  const storyCat = flagshipCats[1] || flagshipCats[0] || {};
  const values = [
  { title: "Honesty.", body: "If your floors do not need replacing, we will say so. One client last spring believed her hardwood was beyond saving; we refinished it for roughly a third of the cost of replacement." },
  { title: "Quality materials.", body: "We install the same products in your home that we would select for our own - no bargain underlayment and no unbranded materials. We stand behind everything we specify." },
  { title: "Punctuality.", body: "When we schedule a Monday 8am start, we begin Monday at 8am. If anything changes, you will receive a phone call." }];


  return (
    <>
      <section className="py-20 md:py-28" style={{ backgroundColor: t.bg }}>
        <div className="max-w-5xl mx-auto px-5 md:px-8 text-center space-y-6">
          <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase" style={{ color: t.accent }}>About</div>
          <h1 className="font-serif font-bold leading-[1.02] tracking-tight" style={{ fontSize: "clamp(44px, 8vw, 84px)", color: t.text }}>
            A small team that<br />does precise work.
          </h1>
          <p className="font-sans text-[19px] md:text-[20px] leading-[1.6] max-w-2xl mx-auto" style={{ color: t.textMuted }}>
            Family-owned and based in the {BRAND.city} area since {BRAND.foundedYear}. The people who quote your floor are the same people who install it.
          </p>
        </div>
      </section>

      {/* Work photo + story */}
      <section className="pb-20 md:pb-28" style={{ backgroundColor: t.bg }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8 grid md:grid-cols-12 gap-12 items-start">
          <div className="md:col-span-5">
            <CategoryMedia
              category={storyCat.category}
              alt={storyCat.title}
              radius={18}
              className="w-full aspect-[4/5]" />
            
            <div className="mt-5 grid grid-cols-3 gap-3 font-mono text-[12px]" style={{ color: t.textMuted }}>
              <div className="p-3 rounded-md text-center" style={{ backgroundColor: t.bgAlt }}>
                <div className="font-serif font-bold text-[22px] mb-0.5" style={{ color: t.text }}>{BRAND.yearsInBusiness}</div>
                years
              </div>
              <div className="p-3 rounded-md text-center" style={{ backgroundColor: t.bgAlt }}>
                <div className="font-serif font-bold text-[22px] mb-0.5" style={{ color: t.text }}>{BRAND.rating}</div>
                avg ★
              </div>
              <div className="p-3 rounded-md text-center" style={{ backgroundColor: t.bgAlt }}>
                <div className="font-serif font-bold text-[22px] mb-0.5" style={{ color: t.text }}>{BRAND.city}</div>
                {BRAND.state}
              </div>
            </div>
          </div>

          <div className="md:col-span-7 font-serif text-[19px] md:text-[20px] leading-[1.65]" style={{ color: t.text }}>
            <p className="mb-6">
              {BRAND.ownerName} has been in the flooring and remodeling trade for over {BRAND.yearsInBusiness} years, and built {BRAND.name} on a simple idea: do the work right the first time, and treat every home like it matters. That hands-on experience stands behind every project we take on.
            </p>
            <p className="mb-6" style={{ color: t.textMuted }}>
              {BRAND.aboutSpecialty}
            </p>
            <p className="mb-6" style={{ color: t.textMuted }}>
              We operate differently. Our installers are not paid on commission. They work methodically, provide an honest assessment of which product will perform best in your space, and do not recommend a more expensive material when your floor does not require one. Every customer is held to the same standard, regardless of the size of the project.
            </p>
            <p style={{ color: t.textMuted }}>
              We are rarely the lowest quote you will receive. If your priority is work done correctly the first time, we would welcome the opportunity to discuss your project.
            </p>
          </div>
        </div>
      </section>

      {/* Values */}
      <section className="py-20 md:py-24" style={{ backgroundColor: t.bgAlt }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8">
          <div className="max-w-2xl mb-12">
            <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>What we believe</div>
            <h2 className="font-serif font-bold text-[34px] md:text-[44px] leading-[1.1] tracking-tight" style={{ color: t.text }}>
              Three things, plainly stated.
            </h2>
          </div>
          <div className="grid md:grid-cols-3 gap-5">
            {values.map((v, i) =>
            <div key={v.title} className="p-8 rounded-xl" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
                <div className="font-mono text-[13px] mb-4" style={{ color: t.accent }}>0{i + 1}</div>
                <h3 className="font-serif font-bold text-[24px] mb-3" style={{ color: t.text }}>{v.title}</h3>
                <p className="font-sans text-[15.5px] leading-[1.7]" style={{ color: t.textMuted }}>{v.body}</p>
              </div>
            )}
          </div>
        </div>
      </section>

      {/* Local vs corporate */}
      <section className="py-20 md:py-28" style={{ backgroundColor: t.bg }}>
        <div className="max-w-5xl mx-auto px-5 md:px-8">
          <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase mb-3" style={{ color: t.accent }}>Local vs. the national chains</div>
          <h2 className="font-serif font-bold text-[34px] md:text-[42px] leading-[1.1] tracking-tight mb-10" style={{ color: t.text }}>
            Why we don't operate like a chain.
          </h2>
          <div className="grid md:grid-cols-2 gap-px rounded-xl overflow-hidden border" style={{ backgroundColor: t.border, borderColor: t.border }}>
            <div className="p-7 md:p-9" style={{ backgroundColor: t.surface }}>
              <div className="font-mono text-[12px] uppercase tracking-wider mb-4" style={{ color: t.textMuted }}>The national chains</div>
              <ul className="space-y-3 font-sans text-[15px]" style={{ color: t.textMuted }}>
                <li className="flex gap-2.5"><Icon name="X" size={18} stroke={t.textMuted} className="mt-0.5 flex-shrink-0" /> Commission installers recommending upgrades you don't need</li>
                <li className="flex gap-2.5"><Icon name="X" size={18} stroke={t.textMuted} className="mt-0.5 flex-shrink-0" /> Subcontractors you've never met doing the actual work</li>
                <li className="flex gap-2.5"><Icon name="X" size={18} stroke={t.textMuted} className="mt-0.5 flex-shrink-0" /> Pushy upgrades layered onto every estimate</li>
                <li className="flex gap-2.5"><Icon name="X" size={18} stroke={t.textMuted} className="mt-0.5 flex-shrink-0" /> Phone trees, hold music, voicemail</li>
                <li className="flex gap-2.5"><Icon name="X" size={18} stroke={t.textMuted} className="mt-0.5 flex-shrink-0" /> "Sale pricing" that was never the real price</li>
              </ul>
            </div>
            <div className="p-7 md:p-9" style={{ backgroundColor: t.bgAlt }}>
              <div className="font-mono text-[12px] uppercase tracking-wider mb-4" style={{ color: t.accent }}>{BRAND.shortName}</div>
              <ul className="space-y-3 font-sans text-[15px]" style={{ color: t.text }}>
                <li className="flex gap-2.5"><Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" /> Hourly installers - no commission, no upselling.</li>
                <li className="flex gap-2.5"><Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" /> The same team from start to finish.</li>
                <li className="flex gap-2.5"><Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" /> A free in-home estimate on every project.</li>
                <li className="flex gap-2.5"><Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" /> A real person answers. No phone trees.</li>
                <li className="flex gap-2.5"><Icon name="Check" size={18} stroke={t.accent} className="mt-0.5 flex-shrink-0" /> Flat quote in writing before work begins.</li>
              </ul>
            </div>
          </div>
        </div>
      </section>

      <FinalCTA />
    </>);

}

/* ============================================================
   BOOK PAGE - 3-step form, real state, success state
   ============================================================ */
function BookPage() {
  const [submitted, setSubmitted] = React.useState(false);
  const [form, setForm] = React.useState(() => {
    const svc = pendingService || "";
    pendingService = null;
    return { name: "", phone: "", email: "", service: svc, details: "" };
  });
  const update = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const canSubmit = form.name && form.phone && form.service;

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!canSubmit) return;
    // When an email is configured, open the visitor's mail client pre-filled.
    // For demo sites with no email yet, just show the confirmation screen.
    if (BRAND.email) {
      const subject = encodeURIComponent(`Flooring Inquiry - ${form.service}`);
      const body = encodeURIComponent(
        `Name: ${form.name}\nPhone: ${form.phone}\nEmail: ${form.email || "-"}\nService: ${form.service}\n\nDetails:\n${form.details || "-"}`
      );
      window.location.href = `mailto:${BRAND.email}?subject=${subject}&body=${body}`;
    }
    setSubmitted(true);
  };

  if (submitted) {
    return (
      <section className="py-24 md:py-32" style={{ backgroundColor: t.bg }}>
        <div className="max-w-2xl mx-auto px-5 md:px-8 text-center">
          <div className="w-20 h-20 rounded-full mx-auto mb-6 flex items-center justify-center" style={{ backgroundColor: t.accent, color: t.onAccent }}>
            <Icon name="Mail" size={36} strokeWidth={2.5} />
          </div>
          <h1 className="font-serif font-bold text-[42px] md:text-[52px] leading-tight mb-4" style={{ color: t.text }}>
            Message sent.
          </h1>
          <p className="font-sans text-[18px] leading-[1.65] mb-8" style={{ color: t.textMuted }}>
            {BRAND.email
            ? `Your email client opened with the details filled in. Once you send it, ${BRAND.ownerName} will get back to you as soon as possible.`
            : `Thanks — we've got your details. ${BRAND.ownerName} will get back to you as soon as possible.`}
          </p>
          <div className="flex flex-wrap gap-3 justify-center">
            <a href={`tel:${BRAND.phoneRaw}`} className="hero-btn hero-btn-secondary inline-flex items-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold border-2"
            style={{ borderColor: t.primary, color: t.primary, "--hero-btn-fill": t.primary, "--hero-btn-text-on-fill": t.onPrimary }}>
              <Icon name="Phone" size={16} /> {BRAND.phone}
            </a>
            <button onClick={() => { setSubmitted(false); setForm({ name: "", phone: "", email: "", service: "", details: "" }); }}
            className="inline-flex items-center gap-2 px-6 py-3.5 rounded-lg font-sans font-semibold"
            style={{ color: t.textMuted }}>
              Send another
            </button>
          </div>
        </div>
      </section>);
  }

  return (
    <>
      <section className="pt-16 md:pt-20 pb-10" style={{ backgroundColor: t.bg }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8 grid md:grid-cols-12 gap-8 items-end">
          <div className="md:col-span-8 space-y-4">
            <div className="text-[12px] font-sans font-semibold tracking-[0.18em] uppercase" style={{ color: t.accent }}>Get in touch</div>
            <h1 className="font-serif font-bold leading-[1.05] tracking-tight" style={{ fontSize: "clamp(38px, 6vw, 60px)", color: t.text }}>
              Tell us about your project.
            </h1>
          </div>
          <div className="md:col-span-4">
            <p className="font-sans text-[15.5px] leading-[1.7]" style={{ color: t.textMuted }}>
              {BRAND.email
              ? `Fill in the form and hit send - it'll open your email app with everything pre-filled. ${BRAND.ownerName} will reply as soon as possible.`
              : `Fill in the form below and ${BRAND.ownerName} will get back to you as soon as possible.`}
            </p>
          </div>
        </div>
      </section>

      <section className="pb-24" style={{ backgroundColor: t.bg }}>
        <div className="max-w-6xl mx-auto px-5 md:px-8 grid md:grid-cols-12 gap-6">

          {/* Form */}
          <div className="md:col-span-8 p-6 md:p-10 rounded-2xl" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
            <form className="space-y-5" onSubmit={handleSubmit}>

              <div className="grid sm:grid-cols-2 gap-4">
                <Field label="Your name" required>
                  <input type="text" required value={form.name} onChange={(e) => update("name", e.target.value)} placeholder="Jane Doe"
                  className="w-full px-4 py-3.5 rounded-lg border-2 font-sans text-[15px] outline-none transition-all"
                  style={{ borderColor: t.border, backgroundColor: t.bg, color: t.text }}
                  onFocus={(e) => e.target.style.borderColor = t.accent}
                  onBlur={(e) => e.target.style.borderColor = t.border} />
                </Field>
                <Field label="Phone number" required>
                  <input type="tel" required value={form.phone} onChange={(e) => update("phone", e.target.value)} placeholder="(704) 555-0100"
                  className="w-full px-4 py-3.5 rounded-lg border-2 font-sans text-[15px] outline-none transition-all"
                  style={{ borderColor: t.border, backgroundColor: t.bg, color: t.text }}
                  onFocus={(e) => e.target.style.borderColor = t.accent}
                  onBlur={(e) => e.target.style.borderColor = t.border} />
                </Field>
              </div>

              <Field label="Your email">
                <input type="email" value={form.email} onChange={(e) => update("email", e.target.value)} placeholder="jane@example.com"
                className="w-full px-4 py-3.5 rounded-lg border-2 font-sans text-[15px] outline-none transition-all"
                style={{ borderColor: t.border, backgroundColor: t.bg, color: t.text }}
                onFocus={(e) => e.target.style.borderColor = t.accent}
                onBlur={(e) => e.target.style.borderColor = t.border} />
              </Field>

              <Field label="Service needed" required>
                <select required value={form.service} onChange={(e) => update("service", e.target.value)}
                className="w-full px-4 py-3.5 rounded-lg border-2 font-sans text-[15px] outline-none transition-all"
                style={{ borderColor: t.border, backgroundColor: t.bg, color: form.service ? t.text : t.textMuted }}
                onFocus={(e) => e.target.style.borderColor = t.accent}
                onBlur={(e) => e.target.style.borderColor = t.border}>
                  <option value="" disabled>Select a service…</option>
                  {BRAND.services.map((s) =>
                  <option key={s.title}>{s.title}</option>
                  )}
                  <option>Not sure yet</option>
                </select>
              </Field>

              <Field label="Details (optional)">
                <textarea value={form.details} onChange={(e) => update("details", e.target.value)}
                placeholder="Tell us about your space, rough square footage, timeline, or anything else that's helpful…"
                rows={5}
                className="w-full px-4 py-3.5 rounded-lg border-2 font-sans text-[15px] outline-none transition-all resize-none"
                style={{ borderColor: t.border, backgroundColor: t.bg, color: t.text }}
                onFocus={(e) => e.target.style.borderColor = t.accent}
                onBlur={(e) => e.target.style.borderColor = t.border} />
              </Field>

              <div className="pt-2 flex justify-end">
                <button type="submit" disabled={!canSubmit}
                className="hero-btn hero-btn-primary inline-flex items-center gap-2 px-7 py-3.5 rounded-lg font-sans font-bold text-[15px] disabled:opacity-40 disabled:cursor-not-allowed"
                style={{ backgroundColor: t.accent, color: t.onAccent }}>
                  Send message <Icon name="Send" size={17} />
                </button>
              </div>
            </form>
          </div>

          {/* Sidebar */}
          <aside className="md:col-span-4 space-y-4">
            <div className="p-6 rounded-2xl" style={{ backgroundColor: t.bgAlt, border: `1px solid ${t.border}` }}>
              <div className="font-mono text-[11px] uppercase tracking-wider mb-4" style={{ color: t.textMuted }}>Contact directly</div>
              <div className="space-y-3">
                <a href={`tel:${BRAND.phoneRaw}`} className="ul-link flex items-center gap-3 font-sans font-semibold text-[15px]" style={{ color: t.text }}>
                  <span className="w-9 h-9 rounded-lg flex items-center justify-center flex-shrink-0" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
                    <Icon name="Phone" size={16} stroke={t.accent} />
                  </span>
                  {BRAND.phone}
                </a>
                {BRAND.email &&
                <a href={`mailto:${BRAND.email}`} className="ul-link flex items-center gap-3 font-sans text-[14px]" style={{ color: t.textMuted }}>
                  <span className="w-9 h-9 rounded-lg flex items-center justify-center flex-shrink-0" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
                    <Icon name="Mail" size={16} stroke={t.accent} />
                  </span>
                  {BRAND.email}
                </a>}
              </div>
            </div>

            <div className="p-6 rounded-2xl" style={{ backgroundColor: t.bgAlt, border: `1px solid ${t.border}` }}>
              <div className="font-mono text-[11px] uppercase tracking-wider mb-4" style={{ color: t.textMuted }}>Service area</div>
              <p className="font-sans text-[14.5px] leading-[1.7]" style={{ color: t.textMuted }}>
                {BRAND.city} and the surrounding areas - including {BRAND.serviceAreas.slice(1).join(", ")}.
              </p>
            </div>

            <div className="p-6 rounded-2xl" style={{ backgroundColor: t.primary, color: t.onPrimary }}>
              <div className="flex items-center gap-2 mb-2.5">
                <Icon name="Layers" size={18} />
                <div className="font-sans font-bold text-[13px] uppercase tracking-wider">Not sure which material?</div>
              </div>
              <p className="font-sans text-[14px] leading-snug mb-4 opacity-90">
                Just call or mention it in the message. {BRAND.ownerName} will advise you on what holds up best in your space before you commit to anything.
              </p>
              <a href={`tel:${BRAND.phoneRaw}`} className="flex items-center justify-center gap-2 w-full py-3 rounded-lg font-sans font-bold text-[15px]"
              style={{ backgroundColor: t.onPrimary, color: t.primary }}>
                <Icon name="Phone" size={16} /> {BRAND.phone}
              </a>
            </div>

            <div className="p-6 rounded-2xl text-center" style={{ backgroundColor: t.surface, border: `1px solid ${t.border}` }}>
              <Stars rating={BRAND.rating} size={16} />
              <div className="font-serif font-bold text-[18px] mt-2.5" style={{ color: t.text }}>{BRAND.rating} out of 5</div>
              <div className="font-sans text-[13px]" style={{ color: t.textMuted }}>Average Google rating</div>
            </div>
          </aside>
        </div>
      </section>
    </>
  );
}

function Field({ label, required, children }) {
  return (
    <label className="block">
      <span className="block font-sans font-semibold text-[13px] uppercase tracking-wider mb-2" style={{ color: t.textMuted }}>
        {label}{required && <span style={{ color: t.accent }}> *</span>}
      </span>
      {children}
    </label>);

}

/* ============================================================
   APP ROOT
   ============================================================ */
function App() {
  const [page, setPage] = React.useState("home");

  // Page background lives on <html> (the canvas, painted behind everything)
  // so the fixed hero backdrop (z-index:-1) shows through the transparent
  // home hero, while every other section (opaque) scrolls up and covers it.
  // NOTE: it must be <html>, not <body> - an opaque <body> paints above
  // negative-z-index layers and would hide the backdrop.
  React.useEffect(() => {
    const el = document.documentElement;
    const prev = el.style.background;
    el.style.background = t.bg;
    return () => {el.style.background = prev;};
  }, []);

  // Re-render icon library after first mount (lucide loads async sometimes)
  const [, forceRender] = React.useState(0);
  React.useEffect(() => {
    if (!window.lucide) {
      const i = setInterval(() => {
        if (window.lucide) {forceRender((x) => x + 1);clearInterval(i);}
      }, 50);
      return () => clearInterval(i);
    }
  }, []);

  // Reset scroll on page change - unless a deep-link to a specific service
  // is pending, in which case lock onto that anchor as the page settles
  // (images/fonts can grow the doc after the first frame, so re-measure).
  React.useEffect(() => {
    if (pendingScroll) {
      const id = pendingScroll;
      pendingScroll = null;
      let n = 0;
      const settle = () => {
        const el = document.getElementById(id);
        if (el) {
          const target = Math.max(0, window.pageYOffset + el.getBoundingClientRect().top - 140);
          if (Math.abs(window.pageYOffset - target) > 2) window.scrollTo({ top: target });
        }
        if (n++ < 16) setTimeout(settle, 55);
      };
      settle();
    } else {
      window.scrollTo({ top: 0 });
    }
  }, [page]);

  /* ============================================================
     PREMIUM SCROLL ENGINE
     - Direction-aware reveals that REPLAY on re-entry (alive
       scrolling both up and down)
     - Continuous parallax drift on imagery
     - Scroll-progress bar + reactive sticky header
     ============================================================ */
  React.useEffect(() => {
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    const main = document.querySelector("main");
    if (!main) return;

    // ---- Build reveal targets: logical content blocks, with stagger ----
    const revealEls = [];
    main.querySelectorAll("section").forEach((section, si) => {
      section.querySelectorAll(":scope > div").forEach((wrap) => {
        Array.from(wrap.children).forEach((block, bi) => {
          // Skip elements that manage their own motion (e.g. the hero marquee)
          if (block.classList.contains("hero-marquee") || block.hasAttribute("data-no-sr")) return;
          const grid = block.matches(".grid, .flex-wrap") ?
          block :
          block.querySelector(":scope > .grid, :scope > .flex-wrap");
          const kids = grid ? Array.from(grid.children) : [];
          if (grid && kids.length > 1 && kids.length <= 12) {
            kids.forEach((kid, i) => {
              kid.classList.add("sr");
              kid.style.setProperty("--sr-delay", `${Math.min(i * 65, 480)}ms`);
              revealEls.push(kid);
            });
          } else {
            block.classList.add("sr");
            block.style.setProperty("--sr-delay", `${Math.min(bi * 60, 240)}ms`);
            revealEls.push(block);
          }
        });
      });
    });

    if (reduce) {
      // Respect reduced motion - show everything, no transforms
      revealEls.forEach((el) => el.classList.add("sr-in"));
      return;
    }

    // ---- Scroll direction tracking ----
    let dir = "down";
    let lastY = window.scrollY;

    // ---- Direction-aware reveal observer (replays on re-entry) ----
    const io = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        const el = entry.target;
        if (entry.isIntersecting) {
          el.dataset.srDir = dir;
          el.classList.add("sr-in");
        } else {
          // Only reset once it has cleared the viewport, so it can replay
          el.classList.remove("sr-in");
        }
      });
    }, { threshold: 0.08, rootMargin: "-6% 0px -10% 0px" });
    revealEls.forEach((el) => io.observe(el));

    // ---- Parallax + progress + header, driven by one rAF loop ----
    const pxEls = Array.from(main.querySelectorAll(".px-img"));
    const header = document.querySelector("header");
    let ticking = false;

    const frame = () => {
      ticking = false;
      const vh = window.innerHeight;

      // Parallax drift
      for (const el of pxEls) {
        const r = el.getBoundingClientRect();
        if (r.bottom < -240 || r.top > vh + 240) continue;
        const speed = parseFloat(el.dataset.speed || "20");
        const rel = (r.top + r.height / 2 - vh / 2) / vh; // ~ -0.6..0.6
        const y = (-rel * speed).toFixed(2);
        el.style.transform = `translate3d(0, ${y}px, 0) scale(1.16)`;
      }

      // Reactive header
      if (header) header.classList.toggle("is-scrolled", window.scrollY > 24);
    };

    const onScroll = () => {
      const y = window.scrollY;
      dir = y > lastY ? "down" : "up";
      lastY = y;
      if (!ticking) {ticking = true;requestAnimationFrame(frame);}
    };

    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    frame(); // initial paint

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

  return (
    <PageContext.Provider value={{ page, setPage }}>
      <div style={{ color: t.text, minHeight: "100vh" }}>
        <Header />
        <main>
          {page === "home" && <HomePage />}
          {page === "services" && <ServicesPage />}
          {page === "about" && <AboutPage />}
          {page === "book" && <BookPage />}
        </main>
        <Footer />
        <MobileBar />
      </div>
      <style>{`
        @keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
        .animate-fade { animation: fadeIn 0.4s cubic-bezier(0.2, 0.7, 0.2, 1); }

        /* ===== Premium scroll reveal - direction-aware, replays ===== */
        .sr {
          opacity: 0;
          transform: translateY(46px) scale(0.985);
          filter: blur(7px);
          transition: opacity 0.95s cubic-bezier(0.16, 0.84, 0.3, 1),
                      transform 1.05s cubic-bezier(0.16, 0.84, 0.3, 1),
                      filter 0.8s ease;
          transition-delay: var(--sr-delay, 0ms);
          will-change: opacity, transform, filter;
        }
        /* When entering while scrolling UP, the block descends from above */
        .sr[data-sr-dir="up"] {
          transform: translateY(-46px) scale(0.985);
        }
        .sr.sr-in {
          opacity: 1;
          transform: translateY(0) scale(1);
          filter: blur(0);
        }

        /* ===== Reactive sticky header ===== */
        header {
          transition: box-shadow 0.4s ease, background-color 0.4s ease, border-color 0.4s ease;
        }
        header.is-scrolled {
          box-shadow: 0 8px 30px -16px rgba(0,0,0,0.28);
        }

        /* ===== Parallax imagery ===== */
        .px-img {
          transform: scale(1.16);
          will-change: transform;
          backface-visibility: hidden;
        }

        /* ===== Hero fixed backdrop (never moves; lower sections scroll over it) ===== */
        .hero-parallax-section {
          position: relative;
          background: transparent;
        }
        .hero-fixed-bg {
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100vh;
          z-index: -1;
          pointer-events: none;
        }
        .hero-fixed-img {
          position: absolute;
          inset: 0;
          background: url("assets/hero-livingroom.jpeg") center center / cover no-repeat;
        }
        .hero-fixed-scrim {
          position: absolute;
          inset: 0;
        }
        .hero-parallax-content {
          position: relative;
          z-index: 1;
        }

        /* ===== Infinite hero photo marquee ===== */
        .hero-marquee {
          position: relative;
          width: 100vw;
          left: 50%;
          margin-left: -50vw;
          /* No overflow:hidden - the page clips horizontally and the mask
             fades the edges, so cards can bloom past the strip vertically. */
          -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 1.2%, #000 98.8%, transparent 100%);
                  mask-image: linear-gradient(90deg, transparent 0, #000 1.2%, #000 98.8%, transparent 100%);
        }
        .hero-marquee-track {
          display: flex;
          align-items: center;
          height: 100%;
          width: max-content;
          animation: heroMarquee 55s linear infinite;
        }
        .hero-marquee-item {
          flex: 0 0 auto;
          width: clamp(280px, 28vw, 400px);
          height: clamp(230px, 33vh, 360px);
          margin-right: 18px;
          border: none;
          padding: 0;
          border-radius: 16px;
          overflow: hidden;
          background: ${t.bgAlt};
          cursor: pointer;
          position: relative;
          transform-origin: center center;
          transition: transform 0.45s cubic-bezier(0.2, 0.75, 0.2, 1),
                      box-shadow 0.45s ease;
          will-change: transform;
        }
        .hero-marquee-item:hover {
          transform: scale(1.14);
          z-index: 3;
        }
        /* Keep the bloom on the card only - image doesn't double-zoom */
        .hero-marquee-item:hover img { transform: none; }
        /* -50% lands exactly on the duplicated set (equal margins → seamless) */
        @keyframes heroMarquee {
          from { transform: translate3d(0, 0, 0); }
          to   { transform: translate3d(-50%, 0, 0); }
        }
        @media (prefers-reduced-motion: reduce) {
          .hero-marquee-track { animation: none; }
        }

        /* ===== Service photo carousel ===== */
        .svc-carousel {
          position: relative;
          overflow: hidden;
          background: ${t.surface};
          box-shadow: 0 24px 60px -32px rgba(0,0,0,0.45);
        }
        .svc-carousel-track { position: absolute; inset: 0; }
        .svc-carousel-slide {
          position: absolute;
          inset: 0;
          pointer-events: none;
          transition: opacity 0.7s ease;
        }
        .svc-carousel-slide img {
          width: 100%;
          height: 100%;
          object-fit: cover;
          display: block;
        }
        .svc-carousel-zoom {
          position: absolute;
          top: 14px;
          right: 14px;
          width: 38px;
          height: 38px;
          display: flex;
          align-items: center;
          justify-content: center;
          border-radius: 10px;
          background: rgba(20,20,22,0.42);
          color: #fff;
          backdrop-filter: blur(6px);
          opacity: 0;
          transform: translateY(-3px);
          transition: opacity 0.25s ease, transform 0.25s ease;
        }
        .svc-carousel:hover .svc-carousel-zoom { opacity: 1; transform: none; }
        .svc-carousel-empty {
          position: absolute;
          inset: 0;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          gap: 10px;
          font-family: 'Manrope', system-ui, sans-serif;
          font-size: 14px;
          letter-spacing: 0.01em;
          color: ${t.textMuted};
          background: ${t.bgAlt};
        }
        .svc-carousel-arrow {
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          width: 40px;
          height: 40px;
          display: flex;
          align-items: center;
          justify-content: center;
          border: none;
          border-radius: 999px;
          background: rgba(20,20,22,0.4);
          color: #fff;
          cursor: pointer;
          backdrop-filter: blur(6px);
          opacity: 0;
          transition: opacity 0.25s ease, background 0.2s ease;
          z-index: 2;
        }
        .svc-carousel:hover .svc-carousel-arrow { opacity: 1; }
        .svc-carousel-arrow:hover { background: rgba(20,20,22,0.62); }
        .svc-carousel-arrow:active { transform: translateY(-50%) scale(0.92); }
        .svc-carousel-prev { left: 12px; }
        .svc-carousel-next { right: 12px; }
        .svc-carousel-dots {
          position: absolute;
          left: 0;
          right: 0;
          bottom: 14px;
          display: flex;
          justify-content: center;
          gap: 8px;
          z-index: 2;
        }
        .svc-carousel-dot {
          width: 8px;
          height: 8px;
          padding: 0;
          border: none;
          border-radius: 999px;
          background: rgba(255,255,255,0.55);
          box-shadow: 0 1px 3px rgba(0,0,0,0.35);
          cursor: pointer;
          transition: width 0.3s ease, background 0.3s ease;
        }
        .svc-carousel-dot.is-active {
          width: 22px;
          background: #fff;
        }
        @media (hover: none) {
          .svc-carousel-arrow, .svc-carousel-zoom { opacity: 1; }
        }

        /* ===== Lightbox ===== */
        .lightbox-overlay {
          position: fixed;
          inset: 0;
          z-index: 100;
          display: flex;
          align-items: center;
          justify-content: center;
          background: rgba(8, 8, 10, 0.9);
          backdrop-filter: blur(6px);
          -webkit-backdrop-filter: blur(6px);
          animation: lbFade 0.3s ease both;
          padding: clamp(12px, 3vw, 40px);
        }
        @keyframes lbFade { from { opacity: 0; } to { opacity: 1; } }
        .lightbox-stage {
          position: relative;
          max-width: 96vw;
          width: auto;
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 16px;
          animation: lbPop 0.4s cubic-bezier(0.16, 0.84, 0.3, 1) both;
        }
        @keyframes lbPop { from { opacity: 0; transform: scale(0.96) translateY(10px); } to { opacity: 1; transform: none; } }
        .lightbox-img {
          width: auto;
          max-width: 94vw;
          max-height: 90vh;
          object-fit: contain;
          border-radius: 14px;
          box-shadow: 0 30px 80px -30px rgba(0,0,0,0.8);
        }
        .lightbox-btn {
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          width: 52px;
          height: 52px;
          border-radius: 999px;
          border: none;
          display: flex;
          align-items: center;
          justify-content: center;
          background: rgba(255,255,255,0.12);
          color: #fff;
          cursor: pointer;
          transition: background 0.2s ease, transform 0.2s ease;
          z-index: 2;
        }
        .lightbox-btn:hover { background: rgba(255,255,255,0.24); }
        .lightbox-btn:active { transform: translateY(-50%) scale(0.92); }
        .lightbox-prev { left: clamp(8px, 3vw, 28px); }
        .lightbox-next { right: clamp(8px, 3vw, 28px); }
        .lightbox-close {
          position: fixed;
          top: 22px;
          right: 24px;
          width: 46px;
          height: 46px;
          border-radius: 999px;
          border: none;
          display: flex;
          align-items: center;
          justify-content: center;
          background: rgba(255,255,255,0.12);
          color: #fff;
          cursor: pointer;
          transition: background 0.2s ease;
          z-index: 3;
        }
        .lightbox-close:hover { background: rgba(255,255,255,0.24); }

        /* ===== Review stars pop ===== */
        @keyframes starPop {
          0%   { transform: scale(0) rotate(-30deg); opacity: 0; }
          60%  { transform: scale(1.18) rotate(4deg); opacity: 1; }
          100% { transform: scale(1) rotate(0); opacity: 1; }
        }
        .review-star {
          animation: starPop 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) both;
          filter: drop-shadow(0 2px 4px rgba(0,0,0,0.08));
        }

        /* ===== Subtle hover animations ===== */

        /* Service cards (use .group) - lift + soft shadow */
        .group {
          transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1),
                      box-shadow 0.4s ease,
                      border-color 0.4s ease;
        }
        .group:hover {
          box-shadow: 0 14px 32px -16px rgba(0,0,0,0.22),
                      0 2px 6px rgba(0,0,0,0.05);
        }

        /* Photos in cards - gentle zoom (parallax images opt out) */
        img:not(.px-img) {
          transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1),
                      filter 0.4s ease;
          will-change: transform;
        }
        img:not(.px-img):hover { transform: scale(1.025); }
        .nav-logo, .nav-logo:hover, .group:hover .nav-logo { transform: none !important; }

        /* Header nav - animated underline grow */
        header nav a {
          position: relative;
        }
        header nav a::after {
          content: '';
          position: absolute;
          left: 16px;
          right: 16px;
          bottom: 6px;
          height: 1.5px;
          background: currentColor;
          transform: scaleX(0);
          transform-origin: left center;
          transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.2, 1);
          opacity: 0.55;
          pointer-events: none;
        }
        header nav a:hover::after { transform: scaleX(1); }

        /* Footer links - slight slide right on hover */
        footer a {
          transition: color 0.2s ease, transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.2s ease;
        }
        footer ul a:hover { transform: translateX(3px); opacity: 1; }

        /* Material chips in gallery - subtle lift */
        span.rounded-full {
          transition: transform 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
        }

        /* Stat boxes (years / NC / avg ★) - subtle scale */
        .grid > .p-3.rounded-md {
          transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
        }
        .grid > .p-3.rounded-md:hover {
          transform: translateY(-2px);
        }

        /* ===== Hero buttons - bigger pop ===== */
        .hero-btn {
          position: relative;
          overflow: hidden;
          isolation: isolate;
          transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1),
                      box-shadow 0.35s ease,
                      background-color 0.3s ease,
                      color 0.3s ease,
                      border-color 0.3s ease;
        }
        .hero-btn svg {
          transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
        }
        .hero-btn:hover {
          transform: translateY(-2px) scale(1.015);
        }
        .hero-btn:active {
          transform: translateY(0);
          transition-duration: 0.08s;
        }

        /* Shine sweep for both */
        .hero-btn::before {
          content: '';
          position: absolute;
          inset: 0;
          background: linear-gradient(115deg,
            transparent 30%,
            rgba(255,255,255,0.28) 50%,
            transparent 70%);
          transform: translateX(-110%);
          transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
          pointer-events: none;
          z-index: 1;
        }
        .hero-btn:hover::before { transform: translateX(110%); }
        .hero-btn > * { position: relative; z-index: 2; }

        /* Primary: glow + arrow nudge */
        .hero-btn-primary {
          box-shadow: 0 8px 22px -12px rgba(200,85,43,0.55),
                      0 1px 0 rgba(255,255,255,0.35) inset;
        }
        .hero-btn-primary:hover {
          box-shadow: 0 18px 36px -14px rgba(200,85,43,0.6),
                      0 1px 0 rgba(255,255,255,0.45) inset;
        }
        .hero-btn-primary:hover svg:last-child {
          transform: translateX(4px);
        }

        /* Secondary: fills on hover with brand color */
        .hero-btn-secondary {
          background-color: transparent;
        }
        .hero-btn-secondary:hover {
          background-color: var(--hero-btn-fill);
          color: var(--hero-btn-text-on-fill) !important;
          box-shadow: 0 14px 28px -16px rgba(0,0,0,0.35);
        }
        .hero-btn-secondary:hover svg:first-child {
          transform: rotate(-12deg) scale(1.08);
        }

        /* ===== Nav links - growing underline + color shift ===== */
        .nav-link {
          position: relative;
          color: ${t.text};
          transition: color 0.25s ease, background-color 0.25s ease;
        }
        .nav-link::after {
          content: '';
          position: absolute;
          left: 16px; right: 16px; bottom: 5px;
          height: 2px; border-radius: 2px;
          background: ${t.accent};
          transform: scaleX(0);
          transform-origin: left center;
          transition: transform 0.34s cubic-bezier(0.2,0.7,0.2,1);
        }
        .nav-link:hover { color: ${t.accent}; }
        .nav-link:hover::after,
        .nav-link[data-active="true"]::after { transform: scaleX(1); }
        .nav-link[data-active="true"] { color: ${t.accent}; }

        /* ===== Inline links - underline grows from left ===== */
        .ul-link {
          background-image: linear-gradient(currentColor, currentColor);
          background-size: 0% 1.5px;
          background-repeat: no-repeat;
          background-position: left 100%;
          padding-bottom: 2px;
          transition: background-size 0.35s cubic-bezier(0.2,0.7,0.2,1), color 0.25s ease;
        }
        .ul-link:hover { background-size: 100% 1.5px; }
        .ul-link svg { transition: transform 0.3s cubic-bezier(0.2,0.7,0.2,1); }

        /* ===== Tertiary link - arrow nudge + color deepen ===== */
        .tertiary-link { transition: color 0.25s ease; }
        .tertiary-link svg { transition: transform 0.3s cubic-bezier(0.2,0.7,0.2,1); }
        .tertiary-link:hover { color: ${t.accentHover}; }
        .tertiary-link:hover svg:last-child { transform: translateX(4px); }
        .tertiary-link:hover svg:first-child { transform: translateX(-2px); }

        /* ===== Logo badge - playful lift on group hover ===== */
        .logo-badge {
          transition: transform 0.4s cubic-bezier(0.2,0.7,0.2,1), box-shadow 0.4s ease;
        }
        .group:hover .logo-badge {
          transform: translateY(-1px) rotate(-5deg) scale(1.06);
          box-shadow: 0 9px 20px -8px rgba(232,90,26,0.6);
        }

        /* ===== Tap feedback (mobile bar / icon buttons) ===== */
        .tap-btn {
          transition: transform 0.18s ease, filter 0.25s ease, background-color 0.25s ease;
        }
        @media (hover:hover) { .tap-btn:hover { filter: brightness(1.07); } }
        .tap-btn:active { transform: scale(0.95); }

        /* ===== Icon button (menu, close) - subtle ring ===== */
        .icon-btn {
          transition: transform 0.25s cubic-bezier(0.2,0.7,0.2,1), background-color 0.25s ease, color 0.25s ease;
        }
        .icon-btn:hover {
          background-color: ${t.accent}1A;
          color: ${t.accent};
          transform: scale(1.08);
        }
        .icon-btn:active { transform: scale(0.92); }

        /* ===== Review quote cards ===== */
        .services-card {
          transition: transform 0.25s cubic-bezier(0.2,0.7,0.2,1), border-color 0.25s ease;
        }
        .services-card:hover {
          transform: translateY(-2px);
          border-color: ${t.accent} !important;
        }
        .services-row {
          transition: transform 0.25s cubic-bezier(0.2,0.7,0.2,1), border-color 0.25s ease;
        }
        .services-row:hover {
          transform: translateY(-2px);
          border-color: ${t.accent} !important;
        }
        .services-row-arrow {
          opacity: 0.5;
          transition: transform 0.25s ease, opacity 0.25s ease;
        }
        .services-row:hover .services-row-arrow {
          opacity: 1;
          transform: translateX(4px);
        }
        .review-quote-card {
          transition: transform 0.3s cubic-bezier(0.2,0.7,0.2,1), border-color 0.3s ease;
        }
        .review-quote-card:hover {
          transform: translateY(-3px);
          border-color: ${t.accent} !important;
        }

        @media (prefers-reduced-motion: reduce) {
          .hero-btn:hover { transform: none; }
          .hero-btn::before { display: none; }
          .hero-btn-primary:hover svg:last-child,
          .hero-btn-secondary:hover svg:first-child { transform: none; }
        }

        /* Honor reduced motion preferences */
        @media (prefers-reduced-motion: reduce) {
          *, *::before, *::after {
            transition-duration: 0.01ms !important;
            animation-duration: 0.01ms !important;
          }
          img:hover { transform: none; }
        }
      `}</style>
    </PageContext.Provider>);

}

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