/* MotorInc — main app */
const { useState, useEffect, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#851d2c",
  "ink": "#262220",
  "grain": true,
  "marqueeSpeed": 38
}/*EDITMODE-END*/;

const SERVICES = [
  {
    n: "01",
    title: "Engine Rebuild",
    desc: "Full top-end and bottom-end rebuilds for Evolution, Twin Cam and Milwaukee-Eight motors. Stripped, measured, balanced and reassembled to spec — then run-in and verified on the bench.",
    tags: ["Evo", "Twin Cam", "M8"]
  },
  {
    n: "02",
    title: "Custom Builds & Mods",
    desc: "Bobbers, choppers, baggers and one-off performance customs. Structural modifications, custom frames, tanks and exhausts — from first sketch to first ignition.",
    tags: ["Bobber", "Chopper", "Fabrication"]
  },
  {
    n: "03",
    title: "Diagnostics & EFI Tuning",
    desc: "Diag4Bike-certified computer diagnostics, EFI remapping and fuel-map calibration. We dial in throttle response, AFR and stage upgrades so the bike runs clean and pulls hard.",
    tags: ["Diag4Bike", "EFI Remap", "Tuning"]
  },
  {
    n: "04",
    title: "Service & Maintenance",
    desc: "Scheduled servicing to keep the bike healthy — oil and primary changes, valve checks, belt and clutch inspection. Done properly and documented for resale.",
    tags: ["Oil & Fluids", "Valve Check", "Belt & Clutch"]
  },
  {
    n: "05",
    title: "Paint & Bodywork",
    desc: "Custom paint, candy coats, flake, pinstriping and hand-laid lettering. Tank dent repair and frame straightening done in-house, colour-matched to the build.",
    tags: ["Custom", "Pinstripe", "Candy"]
  },
  {
    n: "06",
    title: "Parts & After-Sales",
    desc: "OEM Harley-Davidson parts plus S&S, Vance & Hines, Öhlins and Performance Machine, imported direct from the US. Ongoing after-sales support to keep the build running.",
    tags: ["S&S", "V&H", "After-Sales"]
  }
];

const PROJECTS = [
  { code: "MI-001", year: "2025", name: "Black Lung", model: "Softail Night Train", size: "lg",
    blurb: "Matte black Softail, fully blacked-out. Twin Cam with S&S Stage I air cleaner, mini ape hangers, 40-spoke chrome front wheel, bobbed rear fender.", tag: "FEATURED",
    photos: [
      "assets/bikes/bike1/04.webp",
      "assets/bikes/bike1/01.webp",
      "assets/bikes/bike1/02.webp",
      "assets/bikes/bike1/03.webp",
      "assets/bikes/bike1/05.webp",
      "assets/bikes/bike1/06.webp",
      "assets/bikes/bike1/07.webp",
      "assets/bikes/bike1/08.webp"
    ] },
  { code: "MI-002", year: "2024", name: "Vulcan", model: "Custom Chopper — S&S 124\"", size: "md",
    blurb: "Long-rake custom chopper. Candy red with hand-laid silver ghost flames, fully chromed S&S V-twin, spike air cleaner, drag pipes, fat 240 rear on billet wheels.", tag: "CHOPPER",
    photos: [
      "assets/bikes/bike2/06.webp",
      "assets/bikes/bike2/01.webp",
      "assets/bikes/bike2/02.webp",
      "assets/bikes/bike2/03.webp",
      "assets/bikes/bike2/04.webp",
      "assets/bikes/bike2/05.webp",
      "assets/bikes/bike2/07.webp",
      "assets/bikes/bike2/08.webp",
      "assets/bikes/bike2/09.webp"
    ] },
  { code: "MI-003", year: "2024", name: "Apus", model: "Softail Custom", size: "sm",
    blurb: "Candy tangerine Softail with ghost flame graphics. 21\" fat-spoke front, blacked Twin Cam, 2-into-1 shorty drag pipe, bobbed rear, solo seat.", tag: "CUSTOM",
    photos: [
      "assets/bikes/bike3/06.webp",
      "assets/bikes/bike3/01.webp",
      "assets/bikes/bike3/02.webp",
      "assets/bikes/bike3/03.webp",
      "assets/bikes/bike3/04.webp",
      "assets/bikes/bike3/05.webp",
      "assets/bikes/bike3/07.webp"
    ] },
  { code: "MI-004", year: "2024", name: "Cardinal", model: "Softail Custom — FXSTC", size: "wide",
    blurb: "Old-school bobber on a Softail frame. Red and black scallop paint, ape hangers, diamond-stitched solo seat with red contrast, bobbed rear, dual-disc front.", tag: "BOBBER",
    photos: [
      "assets/bikes/bike4/03.webp",
      "assets/bikes/bike4/01.webp",
      "assets/bikes/bike4/02.webp",
      "assets/bikes/bike4/04.webp",
      "assets/bikes/bike4/05.webp"
    ] },
  { code: "MI-005", year: "2024", name: "Templierul", model: "Softail — Twin Cam 96", size: "wide",
    blurb: "Murdered-out Softail built around the Iron Cross theme — custom cast wheels, RSD turbine air cleaner, LED headlight, blacked everything. The only colour is the gold-leaf Harley script on the tank.", tag: "BLACKED-OUT",
    photos: [
      "assets/bikes/bike5/02.webp",
      "assets/bikes/bike5/01.webp",
      "assets/bikes/bike5/03.webp",
      "assets/bikes/bike5/04.webp",
      "assets/bikes/bike5/05.webp",
      "assets/bikes/bike5/06.webp"
    ] },
  { code: "MI-006", year: "2023", name: "Glonț", model: "Custom Chopper — S&S Super Stock 111\"", size: "md",
    blurb: "Frame-up long-rake chopper built in-house. Candy apple red, S&S Super Stock 111ci, open BDL belt primary, polished billet wheels, stretched gas tank.", tag: "CHOPPER",
    photos: [
      "assets/bikes/bike6/03.webp",
      "assets/bikes/bike6/01.webp",
      "assets/bikes/bike6/02.webp",
      "assets/bikes/bike6/04.webp",
      "assets/bikes/bike6/05.webp",
      "assets/bikes/bike6/06.webp",
      "assets/bikes/bike6/07.webp"
    ] },
  { code: "MI-007", year: "2023", name: "Rubin", model: "2001 FXSTI — Stage 3", size: "sm",
    blurb: "Frame-off rebuild of Johnny's '01 FXSTI — Stage 3. Stripped to the bones, everything new: Ultima fat-spoke rims on Avon Cobras, Cobra Bad Hombre exhaust, Arlen Ness mirrors, stretch fenders, Galfer rotors, custom candy paint, upholstery by Vanity Kustom.", tag: "REBUILT",
    photos: [
      "assets/bikes/bike7/02.webp",
      "assets/bikes/bike7/01.webp",
      "assets/bikes/bike7/03.webp"
    ] },
  { code: "MI-008", year: "2025", name: "Codru", model: "Sportster 1200 — Iron", size: "wide",
    blurb: "Custom candy-green metallic paint over the tank and fender, hand-laid 24k gold leaf Harley script. Stitched bobbed seat, blacked-out hardware.", tag: "CUSTOM",
    photos: [
      "assets/bikes/bike8/01.webp",
      "assets/bikes/bike8/02.webp",
      "assets/bikes/bike8/03.webp",
      "assets/bikes/bike8/04.webp",
      "assets/bikes/bike8/05.webp"
    ] }
];

const FORSALE = [
  {
    id: "fs-hornet",
    name: "Hornet",
    model: "Softail Slim — Twin Cam 103",
    year: "2014",
    status: "Available",
    blurb: "One-off custom Softail finished in matte graphite with acid-green honeycomb graphics. Blacked-out 103ci Twin Cam, diamond-stitched seat and chrome mini-apes — sorted, serviced and ready to ride away.",
    photos: [
      "assets/forsale/hornet/01.jpg",
      "assets/forsale/hornet/02.jpg"
    ],
    video: "assets/forsale/hornet/reel.mp4",
    specs: [
      { label: "The build", items: [
        "Matte graphite + acid-green honeycomb livery",
        "Hand-painted Harley script & shield",
        "Diamond-stitched solo + pillion seat",
        "Colour-matched bobbed fenders"
      ] },
      { label: "Parts & mods", items: [
        "Chrome mini-ape bars on pullback risers",
        "Billet chrome tank console + cap",
        "Fat rear tyre on gloss-black spoked wheels",
        "Blacked-out 103\" Twin Cam, LED tail"
      ] },
      { label: "Included", items: [
        "Fresh full service",
        "New tyres, front & rear",
        "Documents & two keys"
      ] }
    ]
  }
];

const TEAM = [
  { initials: "RM", name: "Radu Mihai", role: "Founder · Master Tech", years: "18", badge: "FOUNDER",
    bio: "MMI Phoenix grad. 18 years on Harleys, 6 of them in California. Started Motor Inc. in '23 to bring it home." },
  { initials: "AC", name: "Andrei Cojocaru", role: "Lead Engine Builder", years: "12",
    bio: "Twin Cam and M8 specialist. If it's apart, he can put it back together better than it came." },
  { initials: "ES", name: "Elena Stoica", role: "Paint & Bodywork", years: "9",
    bio: "Trained in House of Kolor candy work. Hand-pinstriping, lettering, gold leaf. Steady hand, sharp eye." },
  { initials: "VP", name: "Vlad Petrescu", role: "Dyno & Tuning", years: "7",
    bio: "PowerVision and Dynojet certified. Treats every map like it's his own bike. Often, it is." }
];

function Nav() {
  const [scrolled, setScrolled] = useState(false);
  const [active, setActive] = useState("");
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 30);
    window.addEventListener('scroll', onScroll);
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  useEffect(() => {
    const ids = ["about", "services", "forsale", "projects", "contact"];
    const sections = ids
      .map(id => document.getElementById(id))
      .filter(Boolean);
    if (!sections.length) return;
    const pickActive = () => {
      // Active = the section whose top is closest to (but at/above) the
      // 30%-from-top probe line. Falls back to first section near the top
      // of the page, and clears past the last section.
      const probe = window.innerHeight * 0.3;
      let current = "";
      for (const s of sections) {
        const top = s.getBoundingClientRect().top;
        if (top - probe <= 0) current = s.id;
      }
      setActive(current);
    };
    pickActive();
    window.addEventListener('scroll', pickActive, { passive: true });
    window.addEventListener('resize', pickActive);
    return () => {
      window.removeEventListener('scroll', pickActive);
      window.removeEventListener('resize', pickActive);
    };
  }, []);
  const linkClass = (id) => active === id ? "is-active" : "";
  return (
    <nav className={`nav ${scrolled ? 'scrolled' : ''}`}>
      <a href="#top" className="nav__brand">
        <img src={(window.__resources && window.__resources.logo) || "assets/motorinc-logo.jpg"} alt="MotorInc" />
        <span>Motor<em>Inc</em>.</span>
      </a>
      <div className="nav__links">
        <a href="#about" className={linkClass("about")}>About Us</a>
        <a href="#services" className={linkClass("services")}>Services</a>
        <a href="#forsale" className={linkClass("forsale")}>For Sale</a>
        <a href="#projects" className={linkClass("projects")}>Projects</a>
        <a href="#contact" className={linkClass("contact")}>Contact</a>
      </div>
      <a href="#contact" className="nav__cta">Book a slot →</a>
    </nav>
  );
}

function Hero() {
  const sparksRef = useRef(null);
  const ironRef = useRef(null);
  const titleRef = useRef(null);
  const reelRef = useRef(null);
  const videoRef = useRef(null);

  // Belt-and-braces mute: React's `muted` JSX attr is sometimes not reflected
  // onto the DOM property in time for autoplay, so set it imperatively.
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    v.muted = true;
    v.defaultMuted = true;
    v.volume = 0;
    const enforce = () => { v.muted = true; v.volume = 0; };
    v.addEventListener('volumechange', enforce);
    v.addEventListener('play', enforce);
    return () => {
      v.removeEventListener('volumechange', enforce);
      v.removeEventListener('play', enforce);
    };
  }, []);

  // Match shop-reel height to title height in desktop / wider configurations
  useEffect(() => {
    const titleEl = titleRef.current;
    const reelEl = reelRef.current;
    if (!titleEl || !reelEl) return;
    const sync = () => {
      if (window.matchMedia('(min-width: 981px)').matches) {
        reelEl.style.height = titleEl.offsetHeight + 'px';
      } else {
        reelEl.style.height = '';
      }
    };
    sync();
    const ro = new ResizeObserver(sync);
    ro.observe(titleEl);
    window.addEventListener('resize', sync);
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(sync);
    return () => { ro.disconnect(); window.removeEventListener('resize', sync); };
  }, []);

  useEffect(() => {
    const cnv = sparksRef.current;
    const ironEl = ironRef.current;
    if (!cnv || !ironEl) return;
    const ctx = cnv.getContext('2d');
    let raf, dpr = Math.min(window.devicePixelRatio || 1, 2);
    let w = 0, h = 0;
    let edgePoints = []; // sampled letter-edge points, canvas-local coords
    let wordLocal = { x: 0, y: 0, w: 0, h: 0 }; // word position inside canvas
    const sparks = [];
    const PAD = 60; // padding around the word for sparks to fly into

    function sampleLetters() {
      // Render "Iron." into an offscreen canvas at the same metrics, scan pixels
      const cs = getComputedStyle(ironEl);
      const fontSize = parseFloat(cs.fontSize);
      const fontFamily = cs.fontFamily;
      const fontWeight = cs.fontWeight;
      const text = (ironEl.textContent || 'Iron.').trim();

      const off = document.createElement('canvas');
      const wordW = wordLocal.w;
      const wordH = wordLocal.h;
      off.width = Math.max(1, Math.ceil(wordW));
      off.height = Math.max(1, Math.ceil(wordH));
      const octx = off.getContext('2d');
      octx.fillStyle = '#fff';
      octx.textBaseline = 'alphabetic';
      octx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
      // Bebas Neue baseline ~ 0.82 of em from top; just place near bottom
      octx.fillText(text, 0, wordH * 0.86);

      const data = octx.getImageData(0, 0, off.width, off.height).data;
      const pts = [];
      const step = 3;
      for (let y = 0; y < off.height; y += step) {
        for (let x = 0; x < off.width; x += step) {
          const i = (y * off.width + x) * 4 + 3;
          if (data[i] > 80) {
            // edge if a neighbor is empty
            const isEdge =
              (x + step >= off.width) ||
              (y + step >= off.height) ||
              data[(y * off.width + (x + step)) * 4 + 3] < 80 ||
              data[((y + step) * off.width + x) * 4 + 3] < 80 ||
              (x - step >= 0 && data[(y * off.width + (x - step)) * 4 + 3] < 80) ||
              (y - step >= 0 && data[((y - step) * off.width + x) * 4 + 3] < 80);
            if (isEdge) pts.push({ x, y });
          }
        }
      }
      edgePoints = pts;
    }

    function place() {
      const titleEl = ironEl.parentElement;
      const tRect = titleEl.getBoundingClientRect();
      const iRect = ironEl.getBoundingClientRect();
      // measure actual rendered text width (not the full row block)
      const inner = ironEl.querySelector('.inner') || ironEl;
      const innerRect = inner.getBoundingClientRect();
      const wordW = innerRect.width;
      const wordH = innerRect.height;
      const wordLeft = innerRect.left - tRect.left;
      const wordTop = innerRect.top - tRect.top;

      // canvas covers word + padding
      const canvasLeft = wordLeft - PAD;
      const canvasTop = wordTop - PAD;
      w = wordW + PAD * 2;
      h = wordH + PAD * 2;

      cnv.style.left = canvasLeft + 'px';
      cnv.style.top = canvasTop + 'px';
      cnv.style.width = w + 'px';
      cnv.style.height = h + 'px';
      cnv.width = w * dpr; cnv.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

      wordLocal = { x: PAD, y: PAD, w: wordW, h: wordH };
      sampleLetters();
    }

    // Wait for fonts so sampling matches what's rendered
    if (document.fonts && document.fonts.ready) {
      document.fonts.ready.then(place);
    } else {
      place();
    }
    place();
    const ro = new ResizeObserver(place);
    ro.observe(ironEl.parentElement);
    window.addEventListener('resize', place);

    function spawn(n) {
      if (!edgePoints.length) return;
      for (let i = 0; i < n; i++) {
        const p = edgePoints[(Math.random() * edgePoints.length) | 0];
        // canvas-local position of the edge sample
        const ox = wordLocal.x + p.x;
        const oy = wordLocal.y + p.y;
        // upward-biased fan with sideways spread (looks like grinder shower)
        const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI * 0.9;
        const speed = 1.4 + Math.random() * 4.5;
        sparks.push({
          x: ox, y: oy,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          life: 0,
          maxLife: 45 + Math.random() * 70,
          size: 0.7 + Math.random() * 1.4,
          hue: 18 + Math.random() * 30,
        });
      }
    }

    let active = true;
    let last = 0;
    function tick(t) {
      ctx.clearRect(0, 0, w, h);
      if (active && t - last > 40 + Math.random() * 80) {
        spawn(2 + Math.floor(Math.random() * 5));
        last = t;
      }
      ctx.globalCompositeOperation = 'lighter';
      for (let i = sparks.length - 1; i >= 0; i--) {
        const s = sparks[i];
        s.life++;
        s.x += s.vx; s.y += s.vy;
        s.vy += 0.07;
        s.vx *= 0.99; s.vy *= 0.99;
        const lt = s.life / s.maxLife;
        if (lt >= 1) { sparks.splice(i, 1); continue; }
        const a = (1 - lt) * 0.95;

        // glow
        ctx.beginPath();
        ctx.arc(s.x, s.y, s.size * 3.2, 0, Math.PI * 2);
        ctx.fillStyle = `hsla(${s.hue}, 100%, ${60 - lt * 30}%, ${a * 0.16})`;
        ctx.fill();

        // streak
        ctx.beginPath();
        ctx.moveTo(s.x, s.y);
        ctx.lineTo(s.x - s.vx * 1.6, s.y - s.vy * 1.6);
        ctx.strokeStyle = `hsla(${s.hue}, 100%, ${65 - lt * 30}%, ${a})`;
        ctx.lineWidth = s.size;
        ctx.lineCap = 'round';
        ctx.stroke();

        // hot core
        ctx.beginPath();
        ctx.arc(s.x, s.y, s.size, 0, Math.PI * 2);
        ctx.fillStyle = `hsla(50, 100%, ${85 - lt * 30}%, ${a})`;
        ctx.fill();
      }
      ctx.globalCompositeOperation = 'source-over';
      raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);

    const io = new IntersectionObserver(([e]) => { active = e.isIntersecting; });
    io.observe(cnv);

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      io.disconnect();
      window.removeEventListener('resize', place);
    };
  }, []);

  return (
    <section className="hero" id="top">

      <div className="wrap">
        <div className="hero__grid">
          <div className="hero__main">
            <div className="hero__eyebrow">
              <span className="dot"></span>
              <span>All-American Service & Repair · Est. 2023</span>
            </div>
            <h1 className="hero__title" ref={titleRef}>
              <span className="row"><span className="inner">American</span></span>
              <span className="row out" ref={ironRef}><span className="inner">Iron.</span></span>
              <span className="row shift"><span className="inner">Romanian</span></span>
              <span className="row red"><span className="inner">Hands.<span className="caret"></span></span></span>
              <span className="hero__title-spec s2" aria-hidden="true">Est. Cluj-Napoca · 2023</span>
            </h1>
            <p className="hero__sub">
              Harley-Davidson and American V-twin specialists. Engine rebuilds, custom builds, dyno tuning — done right, the first time, in Cluj-Napoca.
            </p>
            <div className="hero__ctas">
              <a className="btn btn--primary" href="#contact">Book service <span className="arrow">→</span></a>
              <a className="btn btn--ghost" href="#projects">See our builds</a>
            </div>

          </div>

          <aside className="hero__reel" aria-label="Shop reel" ref={reelRef}>
            <video
              ref={videoRef}
              className="hero__reel-video"
              autoPlay
              loop
              muted
              playsInline
              preload="auto"
              aria-hidden="true"
            >
              <source src="assets/motorinc-reel.av1.mp4" type="video/mp4; codecs=&quot;av01.0.04M.08&quot;" />
              <source src="assets/motorinc-reel.webm" type="video/webm" />
              <source src="assets/motorinc-reel.mp4" type="video/mp4" />
            </video>
            <div className="hero__reel-frame" aria-hidden="true"></div>
            <div className="hero__reel-tag">
              <span className="rec"></span>
              <span>LIVE · SHOP REEL</span>
            </div>
            <div className="hero__reel-meta" aria-hidden="true">
              <span>REC</span><span>CLUJ</span>
            </div>
          </aside>
        </div>
      </div>

      <div className="marquee">
        <div className="marquee__track" id="mq">
          {Array.from({length: 2}).map((_, i) => (
            <span key={i}>
              <em>Harley-Davidson</em> <span className="star">★</span>
              <em>Indian</em> <span className="star">★</span>
              <em>Victory</em> <span className="star">★</span>
              <em>Big Dog</em> <span className="star">★</span>
              <em>Boss Hoss</em> <span className="star">★</span>
            </span>
          ))}
        </div>
      </div>
    </section>
  );
}

function SectionHead({ num, title, accent, meta }) {
  return (
    <div className="section-head">
      <h2 className="section-head__title">
        {title} <em>{accent}</em>
      </h2>
      <div className="section-head__meta" dangerouslySetInnerHTML={{__html: meta}} />
    </div>
  );
}

function Services() {
  return (
    <section className="services" id="services">
      <div className="wrap">
        <SectionHead num="§ 02 / SERVICES" title="What we" accent="do." meta="Six core services" />
        <div className="services__grid">
          {SERVICES.map(s => (
            <div className="svc" key={s.n}>
              <div className="svc__bar"></div>
              <div>
                <h3 className="svc__title">{s.title}</h3>
                <p className="svc__desc">{s.desc}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function BikeGallery({ photos, code, name, onOpen }) {
  const trackRef = useRef(null);
  const [idx, setIdx] = useState(0);
  const [canPrev, setCanPrev] = useState(false);
  const [canNext, setCanNext] = useState(true);

  useEffect(() => {
    const el = trackRef.current;
    if (!el) return;
    const onScroll = () => {
      const w = el.clientWidth;
      const i = Math.round(el.scrollLeft / w);
      setIdx(Math.max(0, Math.min(photos.length - 1, i)));
      setCanPrev(el.scrollLeft > 4);
      setCanNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
    };
    onScroll();
    el.addEventListener('scroll', onScroll, { passive: true });
    const ro = new ResizeObserver(onScroll);
    ro.observe(el);
    return () => { el.removeEventListener('scroll', onScroll); ro.disconnect(); };
  }, [photos.length]);

  const scrollBy = (dir) => {
    const el = trackRef.current;
    if (!el) return;
    el.scrollBy({ left: dir * el.clientWidth, behavior: 'smooth' });
  };

  return (
    <div className="gal">
      <div className="gal__track" ref={trackRef}>
        {photos.map((src, i) => (
          <button
            type="button"
            className="gal__slide"
            key={src}
            onClick={() => onOpen(i)}
            aria-label={`Open photo ${i + 1} of ${photos.length} — ${name}`}
          >
            <img src={src} alt={`${name} — ${i + 1}`} loading="lazy" draggable="false" />
          </button>
        ))}
      </div>

      <button
        type="button"
        className="gal__nav gal__nav--prev"
        onClick={(e) => { e.stopPropagation(); scrollBy(-1); }}
        disabled={!canPrev}
        aria-label="Previous photo"
      >←</button>
      <button
        type="button"
        className="gal__nav gal__nav--next"
        onClick={(e) => { e.stopPropagation(); scrollBy(1); }}
        disabled={!canNext}
        aria-label="Next photo"
      >→</button>

      <div className="gal__count" aria-hidden="true">
        <span>{String(idx + 1).padStart(2, '0')}</span>
        <span className="gal__count-sep">/</span>
        <span>{String(photos.length).padStart(2, '0')}</span>
      </div>
    </div>
  );
}

function Lightbox({ open, photos, startIdx, caption, onClose }) {
  const [idx, setIdx] = useState(startIdx);

  useEffect(() => { if (open) setIdx(startIdx); }, [open, startIdx]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === 'Escape') onClose();
      else if (e.key === 'ArrowRight') setIdx(i => Math.min(photos.length - 1, i + 1));
      else if (e.key === 'ArrowLeft') setIdx(i => Math.max(0, i - 1));
    };
    window.addEventListener('keydown', onKey);
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = prevOverflow;
    };
  }, [open, photos.length, onClose]);

  if (!open) return null;

  return (
    <div className="lb" onClick={onClose} role="dialog" aria-modal="true" aria-label="Photo viewer">
      <div className="lb__stage" onClick={(e) => e.stopPropagation()}>
        <img className="lb__img" src={photos[idx]} alt="" />
      </div>

      <button type="button" className="lb__close" onClick={onClose} aria-label="Close">×</button>

      {idx > 0 && (
        <button
          type="button"
          className="lb__nav lb__nav--prev"
          onClick={(e) => { e.stopPropagation(); setIdx(i => Math.max(0, i - 1)); }}
          aria-label="Previous"
        >←</button>
      )}
      {idx < photos.length - 1 && (
        <button
          type="button"
          className="lb__nav lb__nav--next"
          onClick={(e) => { e.stopPropagation(); setIdx(i => Math.min(photos.length - 1, i + 1)); }}
          aria-label="Next"
        >→</button>
      )}

      <div className="lb__meta" onClick={(e) => e.stopPropagation()}>
        <div className="lb__caption">{caption}</div>
        <div className="lb__count">
          {String(idx + 1).padStart(2, '0')}
          <span className="lb__count-sep"> / </span>
          {String(photos.length).padStart(2, '0')}
        </div>
      </div>
    </div>
  );
}

function Projects() {
  const [lb, setLb] = useState({ open: false, photos: [], startIdx: 0, caption: '' });
  const closeLb = () => setLb(l => ({ ...l, open: false }));

  return (
    <section className="projects" id="projects">
      <div className="wrap">
        <SectionHead num="§ 03 / WORK" title="Selected" accent="builds." meta={`2023 — ${new Date().getFullYear()}<br/>27 customs · countless rebuilds`} />
        <div className="proj-grid" style={{marginTop: 50}}>
          {PROJECTS.map(p => (
            <article className={`proj size-${p.size}`} key={p.code}>
              <div className="proj__media">
                <BikeGallery
                  photos={p.photos}
                  code={p.code}
                  name={p.name}
                  onOpen={(i) => setLb({ open: true, photos: p.photos, startIdx: i, caption: `${p.code} · ${p.name} — ${p.model}` })}
                />
              </div>
              <div className="proj__body">
                <div className="proj__head">
                  <h3 className="proj__name">{p.name}</h3>
                  <span className="badge">{p.tag}</span>
                </div>
                <p className="proj__blurb"><b style={{color:'var(--ink)', fontFamily:'var(--f-mono)', fontSize:11, letterSpacing:'0.12em', textTransform:'uppercase'}}>{p.model}</b><br/>{p.blurb}</p>
              </div>
            </article>
          ))}
        </div>
      </div>
      <Lightbox open={lb.open} photos={lb.photos} startIdx={lb.startIdx} caption={lb.caption} onClose={closeLb} />
    </section>
  );
}

function VideoModal({ open, src, onClose }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = prevOverflow;
    };
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="vlb" onClick={onClose}>
      <button className="vlb__close" aria-label="Close video" onClick={onClose}>×</button>
      <div className="vlb__inner" onClick={(e) => e.stopPropagation()}>
        <video src={src} controls autoPlay playsInline></video>
      </div>
    </div>
  );
}

function ForSale() {
  const [lb, setLb] = useState({ open: false, photos: [], startIdx: 0, caption: '' });
  const [vid, setVid] = useState({ open: false, src: '' });
  const closeLb = () => setLb(l => ({ ...l, open: false }));

  return (
    <section className="forsale" id="forsale">
      <div className="wrap">
        <SectionHead title="Bikes" accent="For Sale." meta="In the showroom now" />
        <div className="forsale__list">
          {FORSALE.map(b => (
            <article className="fs-row" key={b.id}>
              <div className="fs-row__media">
                <BikeGallery
                  photos={b.photos}
                  code={b.id}
                  name={b.name}
                  onOpen={(i) => setLb({ open: true, photos: b.photos, startIdx: i, caption: `${b.name} — ${b.model}` })}
                />
                {b.video && (
                  <button
                    type="button"
                    className="fs-videobtn"
                    onClick={() => setVid({ open: true, src: b.video })}
                  >
                    <span className="fs-videobtn__play">▶</span> Watch video
                  </button>
                )}
              </div>
              <div className="fs-row__body">
                <div className="fs-row__head">
                  <span className="fs-row__status">{b.status}</span>
                  <h3 className="fs-row__name">{b.name}</h3>
                  <p className="fs-row__model">{b.model} · {b.year}</p>
                </div>
                <p className="fs-row__blurb">{b.blurb}</p>
                <div className="fs-specs">
                  {b.specs.map(g => (
                    <div className="fs-spec" key={g.label}>
                      <h4>{g.label}</h4>
                      <ul>
                        {g.items.map(it => <li key={it}>{it}</li>)}
                      </ul>
                    </div>
                  ))}
                </div>
                <div className="fs-row__actions">
                  <a className="btn btn--primary" href="tel:+40747428621">Call Us</a>
                  {b.video && (
                    <button type="button" className="btn btn--ghost" onClick={() => setVid({ open: true, src: b.video })}>
                      <span className="arrow">▶</span> Video
                    </button>
                  )}
                </div>
              </div>
            </article>
          ))}
        </div>
      </div>
      <Lightbox open={lb.open} photos={lb.photos} startIdx={lb.startIdx} caption={lb.caption} onClose={closeLb} />
      <VideoModal open={vid.open} src={vid.src} onClose={() => setVid({ open: false, src: '' })} />
    </section>
  );
}

function About() {
  const floorRef = useRef(null);
  const [inView, setInView] = useState(false);

  useEffect(() => {
    const el = floorRef.current;
    if (!el) return;
    // Respect reduced motion: skip the animation entirely
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      setInView(true);
      return;
    }
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        setInView(true);
        io.disconnect();
      }
    }, { threshold: 0.25 });
    io.observe(el);
    return () => io.disconnect();
  }, []);

  return (
    <section className="about" id="about">
      <div className="wrap">
        <SectionHead num="§ 01 / SHOP" title="About" accent="us." meta="Cluj-Napoca, since 2023<br/>One garage, no compromises" />

        <figure
          className={`shop-floor${inView ? ' is-in-view' : ''}`}
          ref={floorRef}
          role="img"
          aria-label="The Motor Inc. shop floor in Apahida — Harleys lined up, painted Motor Inc. Service & Repair Garage sign at the back"
        >
          <div className="shop-floor__split" aria-hidden="true">
            <div className="shop-floor__half shop-floor__half--left"></div>
            <div className="shop-floor__half shop-floor__half--right"></div>
          </div>
          <span className="shop-floor__tick" aria-hidden="true"></span>
          <figcaption className="shop-floor__cap" aria-hidden="true">
            <span>///</span>
            <span>THE FLOOR</span>
            <span className="shop-floor__cap-dot">·</span>
            <span>APAHIDA</span>
            <span className="shop-floor__cap-dot">·</span>
            <span>2026</span>
          </figcaption>
          <span className="shop-floor__coord" aria-hidden="true">46.8292° N · 23.7438° E</span>
        </figure>

        <div className="about__intro">
          <h3 className="about__lead">
            We grew up on <em>American iron.</em> Now we keep it running on Romanian roads.
          </h3>
          <div className="about__copy">
            <p>Motor Inc. opened its doors in Cluj-Napoca in 2023, but our hands are older than that. Between us we've spent years in California shops, on the Sturgis salt, and bent over Twin Cams in barns from Cluj to Constanța. We work on Harleys and American V-twins — and only that — so every bike leaves running better than it came in, logbook in hand.</p>
          </div>
        </div>
        {/* Team / individuals section temporarily hidden
        <div className="team">
          {TEAM.map((m, i) => (
            <div className="member" key={m.name}>
              <div className="member__years">{String(i+1).padStart(2,'0')}</div>
              <div className="member__photo">
                {m.badge && <span className="badge">{m.badge}</span>}
                <span className="ph">{m.initials}</span>
              </div>
              <h4 className="member__name">{m.name}</h4>
              <div className="member__role">{m.role} · {m.years} yrs</div>
              <p className="member__bio">{m.bio}</p>
            </div>
          ))}
        </div>
        */}
      </div>
    </section>
  );
}

function Contact() {
  return (
    <section className="contact" id="contact">
      <div className="wrap">
        <SectionHead num="§ 04 / VISIT" title="Pull up to the" accent="shop." meta="Tue — Fri · 10—18<br/>Sat by appointment" />
        <div className="contact__grid">
          <div className="contact__info">
            <div className="info-block">
              <h4>Address</h4>
              <a
                className="address-link"
                href="https://www.google.com/maps/place/MOTOR+Inc/@46.8291979,23.7437639,17z/data=!4m6!3m5!1s0x47490fd97e8c8e93:0x7b3981e7a06daca7!8m2!3d46.8291979!4d23.7437639!16s%2Fg%2F11tsp3f8yn"
                target="_blank"
                rel="noopener"
              >Str. Libertății nr. 347<br/>(Intrarea Câmpenești)<br/>Apahida, Cluj, Romania</a>
              <p className="small">Free parking on-site · Drop-off bay around back</p>
            </div>
            <div className="info-block">
              <h4>Phone</h4>
              <a href="tel:+40747428621">+40 747 428 621</a>
            </div>
            <div className="info-block info-block--whatsapp">
              <h4>WhatsApp <span className="info-block__pill">FASTEST</span></h4>
              <a className="wa-cta" href="https://wa.me/40747428621" target="_blank" rel="noopener">
                <span className="wa-cta__icon" aria-hidden="true">
                  <svg viewBox="0 0 24 24"><path d="M17.5 14.4c-.3-.1-1.7-.8-2-.9-.3-.1-.5-.2-.7.2-.2.3-.8.9-.9 1.1-.2.2-.3.2-.6.1-1.6-.8-2.6-1.4-3.7-3.2-.3-.5.3-.5.8-1.5.1-.2 0-.4 0-.5l-.9-2.2c-.2-.6-.5-.5-.7-.5h-.6c-.2 0-.5.1-.8.4-.3.3-1 1-1 2.4s1 2.8 1.2 3c.1.2 2 3.1 4.9 4.4 1.8.8 2.5.9 3.4.7.5-.1 1.7-.7 1.9-1.3.2-.7.2-1.2.2-1.3-.1-.1-.3-.2-.6-.3zM12 2C6.5 2 2 6.5 2 12c0 1.9.5 3.6 1.4 5.1L2 22l5-1.4c1.4.8 3.1 1.3 5 1.3 5.5 0 10-4.5 10-10S17.5 2 12 2zm0 18c-1.7 0-3.3-.5-4.7-1.3l-.3-.2-3 .8.8-2.9-.2-.3C3.5 14.7 3 13.4 3 12 3 7 7 3 12 3s9 4 9 9-4 9-9 9z"/></svg>
                </span>
                <span className="wa-cta__body">
                  <strong>Open chat</strong>
                  <span className="wa-cta__sub">Send photos · quote within 24h</span>
                </span>
                <span className="wa-cta__arrow" aria-hidden="true">→</span>
              </a>
            </div>
            <div className="info-block">
              <h4>Follow</h4>
              <div className="socials">
                <a className="social" href="https://www.facebook.com/profile.php?id=100067445875017" target="_blank" rel="noopener" aria-label="Facebook">
                  <svg viewBox="0 0 24 24"><path d="M22 12a10 10 0 1 0-11.6 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.7l-.4 2.9h-2.3v7A10 10 0 0 0 22 12z"/></svg>
                  Facebook
                </a>
                <a className="social" href="https://www.instagram.com/motor.inc.garage/" target="_blank" rel="noopener" aria-label="Instagram">
                  <svg viewBox="0 0 24 24"><path d="M12 2.2c3.2 0 3.6 0 4.8.1 1.2 0 1.8.3 2.3.4.5.2 1 .5 1.4 1 .4.4.7.8.9 1.4.2.5.4 1.1.4 2.3.1 1.2.1 1.6.1 4.8s0 3.6-.1 4.8c0 1.2-.3 1.8-.4 2.3-.2.5-.5 1-1 1.4-.4.4-.8.7-1.4.9-.5.2-1.1.4-2.3.4-1.2.1-1.6.1-4.8.1s-3.6 0-4.8-.1c-1.2 0-1.8-.3-2.3-.4-.5-.2-1-.5-1.4-1-.4-.4-.7-.8-.9-1.4-.2-.5-.4-1.1-.4-2.3C2.2 15.6 2.2 15.2 2.2 12s0-3.6.1-4.8c0-1.2.3-1.8.4-2.3.2-.5.5-1 1-1.4.4-.4.8-.7 1.4-.9.5-.2 1.1-.4 2.3-.4C8.4 2.2 8.8 2.2 12 2.2zm0 2.2c-3.1 0-3.5 0-4.7.1-1.1 0-1.7.3-2.1.4-.5.2-.9.4-1.3.8-.4.4-.6.8-.8 1.3-.1.4-.3 1-.4 2.1C2.6 8.5 2.6 8.9 2.6 12s0 3.5.1 4.7c0 1.1.3 1.7.4 2.1.2.5.4.9.8 1.3.4.4.8.6 1.3.8.4.1 1 .3 2.1.4 1.2.1 1.6.1 4.7.1s3.5 0 4.7-.1c1.1 0 1.7-.3 2.1-.4.5-.2.9-.4 1.3-.8.4-.4.6-.8.8-1.3.1-.4.3-1 .4-2.1.1-1.2.1-1.6.1-4.7s0-3.5-.1-4.7c0-1.1-.3-1.7-.4-2.1-.2-.5-.4-.9-.8-1.3-.4-.4-.8-.6-1.3-.8-.4-.1-1-.3-2.1-.4C15.5 4.4 15.1 4.4 12 4.4zm0 3.4a4.2 4.2 0 1 1 0 8.4 4.2 4.2 0 0 1 0-8.4zm0 6.9a2.7 2.7 0 1 0 0-5.4 2.7 2.7 0 0 0 0 5.4zm5.4-7.1a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/></svg>
                  Instagram
                </a>
                <a className="social" href="https://www.tiktok.com/@motor.inc.garage" target="_blank" rel="noopener" aria-label="TikTok">
                  <svg viewBox="0 0 24 24"><path d="M19.6 6.7a5.6 5.6 0 0 1-3.2-1V15a5.5 5.5 0 1 1-5.5-5.5h.7v2.7a2.8 2.8 0 1 0 2 2.7V2h2.7a3.6 3.6 0 0 0 3.3 3.2v2.5z"/></svg>
                  TikTok
                </a>
              </div>
            </div>
          </div>
          <div className="contact__map">
            <iframe
              src="https://maps.google.com/maps?q=MOTOR%20Inc%2C%20Strada%20C%C3%A2mpene%C8%99ti%2C%20Apahida&z=16&output=embed"
              loading="lazy"
              referrerPolicy="no-referrer-when-downgrade"
              title="MotorInc location"></iframe>
          </div>
        </div>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div className="wrap" style={{display:'grid', gridTemplateColumns:'auto 1fr auto', gap:30, alignItems:'center'}}>
        <div className="footer__brand">
          <img src={(window.__resources && window.__resources.logo) || "assets/motorinc-logo.jpg"} alt="" />
          <span>© 2026 Motor Inc. SRL</span>
        </div>
        <div className="footer__center">All American · Service & Repair · Est. '23</div>
        <div className="footer__right">Built in Cluj-Napoca, RO</div>
      </div>
    </footer>
  );
}

function Tweaks() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useEffect(() => {
    document.documentElement.style.setProperty('--accent', t.accent);
    document.documentElement.style.setProperty('--ink', t.ink);
    document.body.classList.toggle('grain', !!t.grain);
    const mq = document.getElementById('mq');
    if (mq) mq.style.animationDuration = `${t.marqueeSpeed}s`;
  }, [t]);

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Accent">
        <TweakColor
          label="Brand color"
          value={t.accent}
          onChange={v => setTweak('accent', v)}
          options={['#851d2c', '#2db5e8', '#f59e0b', '#22c55e', '#16140f']}
        />
        <TweakColor
          label="Headline ink"
          value={t.ink}
          onChange={v => setTweak('ink', v)}
          options={['#16140f', '#262220', '#37322c', '#4a443c']}
        />
      </TweakSection>
      <TweakSection title="Atmosphere">
        <TweakToggle label="Film grain" value={t.grain} onChange={v => setTweak('grain', v)} />
        <TweakSlider label="Marquee speed" min={15} max={80} step={1} value={t.marqueeSpeed} onChange={v => setTweak('marqueeSpeed', v)} suffix="s" />
      </TweakSection>
    </TweaksPanel>
  );
}

function App() {
  return (
    <>
      <Nav />
      <Hero />
      <About />
      <Services />
      <ForSale />
      <Projects />
      <Contact />
      <Footer />
      <Tweaks />
    </>
  );
}

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